Structure the Harmony core to rely on a DAG for declaring & executing Scores
This commit is contained in:
13
examples/harmony/Cargo.toml
Normal file
13
examples/harmony/Cargo.toml
Normal file
@@ -0,0 +1,13 @@
|
||||
[package]
|
||||
name = "example-harmony"
|
||||
version = "0.1.0"
|
||||
edition = "2024"
|
||||
|
||||
[dependencies]
|
||||
async-trait = "0.1.89"
|
||||
harmony-core = { version = "0.1.0", path = "../../harmony-core" }
|
||||
harmony-derive = { version = "0.1.0", path = "../../harmony-derive" }
|
||||
inquire = "0.7.5"
|
||||
serde = { version = "1.0.219", features = ["derive"] }
|
||||
serde_json = "1.0.143"
|
||||
tokio = "1.47.1"
|
||||
801
examples/harmony/src/main.rs
Normal file
801
examples/harmony/src/main.rs
Normal file
@@ -0,0 +1,801 @@
|
||||
use std::fmt::Display;
|
||||
|
||||
use async_trait::async_trait;
|
||||
use harmony_core::{
|
||||
Dependency, ExecutionContext, Id, Interpret, InterpretError, InterpretOutcome, Inventory,
|
||||
LinkedValue, Maestro, Score, Topology, dependency,
|
||||
};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
trait Ingress {
|
||||
fn get_domain(&self, service: &str) -> String;
|
||||
}
|
||||
|
||||
trait DhcpServer {
|
||||
fn get_gateway_ip(&self) -> String;
|
||||
}
|
||||
|
||||
trait LoadBalancer {
|
||||
fn get_domain_name(&self) -> String;
|
||||
fn get_load_balancer_ip(&self) -> String;
|
||||
}
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
pub struct HaClusterTopology;
|
||||
|
||||
impl Topology for HaClusterTopology {
|
||||
fn name(&self) -> &str {
|
||||
"HaCluster"
|
||||
}
|
||||
}
|
||||
|
||||
impl Ingress for HaClusterTopology {
|
||||
fn get_domain(&self, service: &str) -> String {
|
||||
format!("https://{service}.domain.com")
|
||||
}
|
||||
}
|
||||
|
||||
impl DhcpServer for HaClusterTopology {
|
||||
fn get_gateway_ip(&self) -> String {
|
||||
"1.1.1.1".into()
|
||||
}
|
||||
}
|
||||
|
||||
impl LoadBalancer for HaClusterTopology {
|
||||
fn get_domain_name(&self) -> String {
|
||||
"domain.com".into()
|
||||
}
|
||||
|
||||
fn get_load_balancer_ip(&self) -> String {
|
||||
"192.168.1.1".into()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct IngressScore {
|
||||
service: String,
|
||||
}
|
||||
|
||||
impl Display for IngressScore {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.write_str(&format!("IngressScore[{}]", self.service))
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Topology + Ingress> Score<T> for IngressScore {
|
||||
fn id(&self) -> Id {
|
||||
Id(format!("ingress-{}", self.service))
|
||||
}
|
||||
|
||||
fn name(&self) -> String {
|
||||
format!("IngressScore[{}]", self.service)
|
||||
}
|
||||
|
||||
fn depends_on(&self) -> Vec<Dependency<T>> {
|
||||
vec![]
|
||||
}
|
||||
|
||||
fn create_interpret(&self) -> Box<dyn Interpret<T>> {
|
||||
Box::new(IngressInterpret {
|
||||
score: self.clone(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct IngressInterpret {
|
||||
score: IngressScore,
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl<T: Topology + Ingress> Interpret<T> for IngressInterpret {
|
||||
async fn execute(
|
||||
&self,
|
||||
_inventory: &Inventory,
|
||||
topology: &T,
|
||||
context: ExecutionContext,
|
||||
) -> Result<InterpretOutcome, InterpretError> {
|
||||
let domain = topology.get_domain(&self.score.service);
|
||||
context.insert(Id("domain".into()), &domain);
|
||||
|
||||
println!("Ingress domain: {domain}");
|
||||
|
||||
Ok(InterpretOutcome {})
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
struct ApplicationScore {
|
||||
name: String,
|
||||
domain: LinkedValue<String>,
|
||||
}
|
||||
|
||||
impl Display for ApplicationScore {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.write_str(&format!("ApplicationScore[{}]", self.name))
|
||||
}
|
||||
}
|
||||
|
||||
impl ApplicationScore {
|
||||
fn new(name: String) -> Self {
|
||||
Self {
|
||||
name: name.clone(),
|
||||
domain: LinkedValue::ContextKey(Id("ingress.domain".into())),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Topology + Ingress> Score<T> for ApplicationScore {
|
||||
fn id(&self) -> Id {
|
||||
Id(format!("application-{}", self.name))
|
||||
}
|
||||
|
||||
fn name(&self) -> String {
|
||||
format!("ApplicationScore[{}]", self.name)
|
||||
}
|
||||
|
||||
fn depends_on(&self) -> Vec<Dependency<T>> {
|
||||
vec![dependency!(
|
||||
Id("ingress".into()),
|
||||
IngressScore {
|
||||
service: self.name.clone()
|
||||
}
|
||||
)]
|
||||
}
|
||||
|
||||
fn create_interpret(&self) -> Box<dyn Interpret<T>> {
|
||||
Box::new(ApplicationInterpret {
|
||||
score: self.clone(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct ApplicationInterpret {
|
||||
score: ApplicationScore,
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl<T: Topology + Ingress> Interpret<T> for ApplicationInterpret {
|
||||
async fn execute(
|
||||
&self,
|
||||
_inventory: &Inventory,
|
||||
_topology: &T,
|
||||
context: ExecutionContext,
|
||||
) -> Result<InterpretOutcome, InterpretError> {
|
||||
let domain = self.score.domain.resolve(&context)?;
|
||||
|
||||
println!("{}: {}", self.score.name, domain);
|
||||
|
||||
Ok(InterpretOutcome {})
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
struct DhcpServerScore {}
|
||||
|
||||
impl Display for DhcpServerScore {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.write_str("DhcpServerScore")
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Topology + DhcpServer> Score<T> for DhcpServerScore {
|
||||
fn id(&self) -> Id {
|
||||
Id("dhcp-server".into())
|
||||
}
|
||||
|
||||
fn name(&self) -> String {
|
||||
"DhcpServerScore".into()
|
||||
}
|
||||
|
||||
fn depends_on(&self) -> Vec<Dependency<T>> {
|
||||
vec![]
|
||||
}
|
||||
|
||||
fn create_interpret(&self) -> Box<dyn Interpret<T>> {
|
||||
Box::new(DhcpServerInterpret {})
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct DhcpServerInterpret {}
|
||||
|
||||
#[async_trait]
|
||||
impl<T: Topology + DhcpServer> Interpret<T> for DhcpServerInterpret {
|
||||
async fn execute(
|
||||
&self,
|
||||
_inventory: &Inventory,
|
||||
topology: &T,
|
||||
context: ExecutionContext,
|
||||
) -> Result<InterpretOutcome, InterpretError> {
|
||||
let gateway_ip = topology.get_gateway_ip();
|
||||
context.insert(Id("gateway-ip".into()), gateway_ip);
|
||||
|
||||
Ok(InterpretOutcome {})
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
struct DhcpScore {
|
||||
host_binding: Vec<String>,
|
||||
domain: Option<String>,
|
||||
next_server: LinkedValue<String>,
|
||||
}
|
||||
|
||||
impl DhcpScore {
|
||||
fn new(host_binding: Vec<String>, domain: Option<String>, next_server: Option<String>) -> Self {
|
||||
Self {
|
||||
host_binding,
|
||||
domain,
|
||||
next_server: match next_server {
|
||||
Some(next_server) => LinkedValue::Value(next_server),
|
||||
None => LinkedValue::ContextKey(Id("dhcp-server.gateway-ip".into())),
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for DhcpScore {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.write_str("DhcpScore")
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Topology + DhcpServer> Score<T> for DhcpScore {
|
||||
fn id(&self) -> Id {
|
||||
Id("dhcp".into())
|
||||
}
|
||||
|
||||
fn name(&self) -> String {
|
||||
"DhcpScore".into()
|
||||
}
|
||||
|
||||
fn depends_on(&self) -> Vec<Dependency<T>> {
|
||||
let mut dependencies: Vec<Dependency<T>> = vec![];
|
||||
|
||||
if let LinkedValue::ContextKey(_) = &self.next_server {
|
||||
dependencies.push(dependency!(Id("dhcp-server".into()), DhcpServerScore {}));
|
||||
}
|
||||
|
||||
dependencies
|
||||
}
|
||||
|
||||
fn create_interpret(&self) -> Box<dyn Interpret<T>> {
|
||||
Box::new(DhcpInterpret {
|
||||
score: self.clone(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct DhcpInterpret {
|
||||
score: DhcpScore,
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl<T: Topology> Interpret<T> for DhcpInterpret {
|
||||
async fn execute(
|
||||
&self,
|
||||
_inventory: &Inventory,
|
||||
_topology: &T,
|
||||
context: ExecutionContext,
|
||||
) -> Result<InterpretOutcome, InterpretError> {
|
||||
let next_server = self.score.next_server.resolve(&context)?;
|
||||
println!(
|
||||
"Configuring DHCP [\n - next_server: {:?}\n - host_binding: {:?}\n - domain: {:?}\n]",
|
||||
next_server, self.score.host_binding, self.score.domain
|
||||
);
|
||||
Ok(InterpretOutcome {})
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
struct OkdIpxeScore {
|
||||
kickstart_filename: String,
|
||||
harmony_inventory_agent: String,
|
||||
}
|
||||
|
||||
impl Display for OkdIpxeScore {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.write_str(&format!("OkdIpxeScore[{}]", self.kickstart_filename))
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Topology + DhcpServer> Score<T> for OkdIpxeScore {
|
||||
fn id(&self) -> Id {
|
||||
Id("okd-ipxe".into())
|
||||
}
|
||||
|
||||
fn name(&self) -> String {
|
||||
format!("OkdIpxeScore[{}]", self.kickstart_filename)
|
||||
}
|
||||
|
||||
fn depends_on(&self) -> Vec<Dependency<T>> {
|
||||
vec![
|
||||
dependency!(Id("dhcp".into()), DhcpScore::new(vec![], None, None)),
|
||||
dependency!(
|
||||
Id("tftp".into()),
|
||||
TftpScore {
|
||||
files_to_serve: "./data/pxe/okd/tftpboot/".into(),
|
||||
}
|
||||
),
|
||||
]
|
||||
}
|
||||
|
||||
fn create_interpret(&self) -> Box<dyn Interpret<T>> {
|
||||
Box::new(OkdIpxeInterpret {})
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct OkdIpxeInterpret {}
|
||||
|
||||
#[async_trait]
|
||||
impl<T: Topology> Interpret<T> for OkdIpxeInterpret {
|
||||
async fn execute(
|
||||
&self,
|
||||
_inventory: &Inventory,
|
||||
_topology: &T,
|
||||
_context: ExecutionContext,
|
||||
) -> Result<InterpretOutcome, InterpretError> {
|
||||
Ok(InterpretOutcome {})
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
struct TftpScore {
|
||||
files_to_serve: String,
|
||||
}
|
||||
|
||||
impl Display for TftpScore {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.write_str(&format!("TftpScore[{}]", self.files_to_serve))
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Topology> Score<T> for TftpScore {
|
||||
fn id(&self) -> Id {
|
||||
Id("TftpScore".into())
|
||||
}
|
||||
|
||||
fn name(&self) -> String {
|
||||
"TftpScore".into()
|
||||
}
|
||||
|
||||
fn depends_on(&self) -> Vec<Dependency<T>> {
|
||||
vec![]
|
||||
}
|
||||
|
||||
fn create_interpret(&self) -> Box<dyn Interpret<T>> {
|
||||
Box::new(TftpInterpret {})
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct TftpInterpret {}
|
||||
|
||||
#[async_trait]
|
||||
impl<T: Topology> Interpret<T> for TftpInterpret {
|
||||
async fn execute(
|
||||
&self,
|
||||
_inventory: &Inventory,
|
||||
_topology: &T,
|
||||
_context: ExecutionContext,
|
||||
) -> Result<InterpretOutcome, InterpretError> {
|
||||
Ok(InterpretOutcome {})
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
struct OkdInstallationScore {}
|
||||
|
||||
impl Display for OkdInstallationScore {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.write_str("OkdInstallationScore")
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Topology + LoadBalancer> Score<T> for OkdInstallationScore {
|
||||
fn id(&self) -> Id {
|
||||
Id("okd-installation".into())
|
||||
}
|
||||
|
||||
fn name(&self) -> String {
|
||||
"OkdInstallationScore".into()
|
||||
}
|
||||
|
||||
fn depends_on(&self) -> Vec<Dependency<T>> {
|
||||
vec![
|
||||
dependency!(Id("prepare".into()), OkdInstallationPrepareScore::new()),
|
||||
dependency!(Id("bootstrap".into()), OkdInstallationBootstrapScore {}),
|
||||
]
|
||||
}
|
||||
|
||||
fn create_interpret(&self) -> Box<dyn Interpret<T>> {
|
||||
Box::new(OkdInstallationInterpret {})
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct OkdInstallationInterpret {}
|
||||
|
||||
#[async_trait]
|
||||
impl<T: Topology + LoadBalancer> Interpret<T> for OkdInstallationInterpret {
|
||||
async fn execute(
|
||||
&self,
|
||||
_inventory: &Inventory,
|
||||
_topology: &T,
|
||||
_context: ExecutionContext,
|
||||
) -> Result<InterpretOutcome, InterpretError> {
|
||||
Ok(InterpretOutcome {})
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
struct PhysicalHost {
|
||||
id: Id,
|
||||
category: HostCategory,
|
||||
}
|
||||
|
||||
impl Display for PhysicalHost {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.write_str(&format!("Host[{}, {:?}]", self.id, self.category))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
enum HostRole {
|
||||
Bootstrap,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
enum HostCategory {
|
||||
Server,
|
||||
Firewall,
|
||||
Switch,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
struct OkdInstallationPrepareScore {
|
||||
bootstrap_host: LinkedValue<PhysicalHost>,
|
||||
}
|
||||
|
||||
impl OkdInstallationPrepareScore {
|
||||
fn new() -> Self {
|
||||
Self {
|
||||
bootstrap_host: LinkedValue::ContextKey(Id("discover-host.host".into())),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for OkdInstallationPrepareScore {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.write_str("OkdInstallationPrepareScore")
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Topology + LoadBalancer> Score<T> for OkdInstallationPrepareScore {
|
||||
fn id(&self) -> Id {
|
||||
Id("okd-installation-prepare".into())
|
||||
}
|
||||
|
||||
fn name(&self) -> String {
|
||||
"OkdInstallationPrepareScore".into()
|
||||
}
|
||||
|
||||
fn depends_on(&self) -> Vec<Dependency<T>> {
|
||||
vec![
|
||||
dependency!(Id("opnsense-hosts".into()), OPNsenseHostsScore {}),
|
||||
dependency!(
|
||||
Id("discover-host".into()),
|
||||
DiscoverHostForRoleScore::new(HostRole::Bootstrap)
|
||||
),
|
||||
]
|
||||
}
|
||||
|
||||
fn create_interpret(&self) -> Box<dyn Interpret<T>> {
|
||||
Box::new(OkdInstallationPrepareInterpret {
|
||||
score: self.clone(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct OkdInstallationPrepareInterpret {
|
||||
score: OkdInstallationPrepareScore,
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl<T: Topology + LoadBalancer> Interpret<T> for OkdInstallationPrepareInterpret {
|
||||
async fn execute(
|
||||
&self,
|
||||
_inventory: &Inventory,
|
||||
_topology: &T,
|
||||
context: ExecutionContext,
|
||||
) -> Result<InterpretOutcome, InterpretError> {
|
||||
let bootstrap_host = self.score.bootstrap_host.resolve(&context)?;
|
||||
println!("Bootstrap host: {}", bootstrap_host);
|
||||
Ok(InterpretOutcome {})
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
struct DiscoverHostForRoleScore {
|
||||
role: HostRole,
|
||||
hosts: LinkedValue<Vec<PhysicalHost>>,
|
||||
}
|
||||
|
||||
impl DiscoverHostForRoleScore {
|
||||
fn new(role: HostRole) -> Self {
|
||||
Self {
|
||||
role,
|
||||
hosts: LinkedValue::ContextKey(Id("available-hosts.hosts".into())),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for DiscoverHostForRoleScore {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.write_str(&format!("DiscoverHostForRoleScore[{:?}]", self.role))
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Topology> Score<T> for DiscoverHostForRoleScore {
|
||||
fn id(&self) -> Id {
|
||||
Id(format!("discover-host-{:?}", self.role))
|
||||
}
|
||||
|
||||
fn name(&self) -> String {
|
||||
format!("DiscoverHostForRoleScore[{:?}]", self.role)
|
||||
}
|
||||
|
||||
fn depends_on(&self) -> Vec<Dependency<T>> {
|
||||
vec![dependency!(
|
||||
Id("available-hosts".into()),
|
||||
DiscoverAvailableHostsScore {}
|
||||
)]
|
||||
}
|
||||
|
||||
fn create_interpret(&self) -> Box<dyn Interpret<T>> {
|
||||
Box::new(DiscoverHostForRoleInterpret {
|
||||
score: self.clone(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct DiscoverHostForRoleInterpret {
|
||||
score: DiscoverHostForRoleScore,
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl<T: Topology> Interpret<T> for DiscoverHostForRoleInterpret {
|
||||
async fn execute(
|
||||
&self,
|
||||
_inventory: &Inventory,
|
||||
_topology: &T,
|
||||
context: ExecutionContext,
|
||||
) -> Result<InterpretOutcome, InterpretError> {
|
||||
let hosts = self.score.hosts.resolve(&context)?;
|
||||
let host = hosts.first().unwrap();
|
||||
context.insert(Id("host".into()), host);
|
||||
Ok(InterpretOutcome {})
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
struct DiscoverAvailableHostsScore {}
|
||||
|
||||
impl Display for DiscoverAvailableHostsScore {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.write_str("DiscoverAvailableHostsScore")
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Topology> Score<T> for DiscoverAvailableHostsScore {
|
||||
fn id(&self) -> Id {
|
||||
Id("discover-available-hosts".into())
|
||||
}
|
||||
|
||||
fn name(&self) -> String {
|
||||
"DiscoverAvailableHostsScore".into()
|
||||
}
|
||||
|
||||
fn depends_on(&self) -> Vec<Dependency<T>> {
|
||||
vec![]
|
||||
}
|
||||
|
||||
fn create_interpret(&self) -> Box<dyn Interpret<T>> {
|
||||
Box::new(DiscoverAvailableHostsInterpret {})
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct DiscoverAvailableHostsInterpret {}
|
||||
|
||||
#[async_trait]
|
||||
impl<T: Topology> Interpret<T> for DiscoverAvailableHostsInterpret {
|
||||
async fn execute(
|
||||
&self,
|
||||
_inventory: &Inventory,
|
||||
_topology: &T,
|
||||
context: ExecutionContext,
|
||||
) -> Result<InterpretOutcome, InterpretError> {
|
||||
context.insert(
|
||||
Id("hosts".into()),
|
||||
vec![PhysicalHost {
|
||||
id: Id("host-1".into()),
|
||||
category: HostCategory::Server,
|
||||
}],
|
||||
);
|
||||
Ok(InterpretOutcome {})
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
struct OPNsenseHostsScore {}
|
||||
|
||||
impl Display for OPNsenseHostsScore {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.write_str("OPNsenseHostsScore")
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Topology + LoadBalancer> Score<T> for OPNsenseHostsScore {
|
||||
fn id(&self) -> Id {
|
||||
Id("opnsense-hosts".into())
|
||||
}
|
||||
|
||||
fn name(&self) -> String {
|
||||
"OPNsenseHostsScore".into()
|
||||
}
|
||||
|
||||
fn depends_on(&self) -> Vec<Dependency<T>> {
|
||||
vec![]
|
||||
}
|
||||
|
||||
fn create_interpret(&self) -> Box<dyn Interpret<T>> {
|
||||
Box::new(OPNsenseHostsInterpret {})
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct OPNsenseHostsInterpret {}
|
||||
|
||||
#[async_trait]
|
||||
impl<T: Topology + LoadBalancer> Interpret<T> for OPNsenseHostsInterpret {
|
||||
async fn execute(
|
||||
&self,
|
||||
_inventory: &Inventory,
|
||||
topology: &T,
|
||||
_context: ExecutionContext,
|
||||
) -> Result<InterpretOutcome, InterpretError> {
|
||||
let cluster_domain = &topology.get_domain_name();
|
||||
let load_balancer_ip = &topology.get_load_balancer_ip();
|
||||
|
||||
inquire::Confirm::new(&format!(
|
||||
"Set hostnames manually in your opnsense dnsmasq config :
|
||||
*.apps.{cluster_domain} -> {load_balancer_ip}
|
||||
api.{cluster_domain} -> {load_balancer_ip}
|
||||
api-int.{cluster_domain} -> {load_balancer_ip}
|
||||
|
||||
When you can dig them, confirm to continue.
|
||||
"
|
||||
))
|
||||
.prompt()
|
||||
.expect("Prompt error");
|
||||
|
||||
Ok(InterpretOutcome {})
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
struct OkdInstallationBootstrapScore {}
|
||||
|
||||
impl Display for OkdInstallationBootstrapScore {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.write_str("OkdInstallationBootstrapScore")
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Topology> Score<T> for OkdInstallationBootstrapScore {
|
||||
fn id(&self) -> Id {
|
||||
Id("okd-installation-bootstrap".into())
|
||||
}
|
||||
|
||||
fn name(&self) -> String {
|
||||
"OkdInstallationBootstrapScore".into()
|
||||
}
|
||||
|
||||
fn depends_on(&self) -> Vec<Dependency<T>> {
|
||||
vec![]
|
||||
}
|
||||
|
||||
fn create_interpret(&self) -> Box<dyn Interpret<T>> {
|
||||
Box::new(OkdInstallationBootstrapInterpret {})
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct OkdInstallationBootstrapInterpret {}
|
||||
|
||||
#[async_trait]
|
||||
impl<T: Topology> Interpret<T> for OkdInstallationBootstrapInterpret {
|
||||
async fn execute(
|
||||
&self,
|
||||
_inventory: &Inventory,
|
||||
_topology: &T,
|
||||
_context: ExecutionContext,
|
||||
) -> Result<InterpretOutcome, InterpretError> {
|
||||
Ok(InterpretOutcome {})
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
struct ProvisionHighAvailabilityClusterScore {}
|
||||
|
||||
impl Display for ProvisionHighAvailabilityClusterScore {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.write_str("ProvisionHighAvailabilityClusterScore")
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Topology + DhcpServer + LoadBalancer> Score<T> for ProvisionHighAvailabilityClusterScore {
|
||||
fn id(&self) -> Id {
|
||||
Id("provision-high-availability-cluster".into())
|
||||
}
|
||||
|
||||
fn name(&self) -> String {
|
||||
"ProvisionHighAvailabilityClusterScore".into()
|
||||
}
|
||||
|
||||
fn depends_on(&self) -> Vec<Dependency<T>> {
|
||||
vec![
|
||||
dependency!(
|
||||
Id("okd-ipxe".into()),
|
||||
OkdIpxeScore {
|
||||
kickstart_filename: "inventory.kickstart".into(),
|
||||
harmony_inventory_agent: "harmony_inventory_agent".into(),
|
||||
}
|
||||
),
|
||||
dependency!(Id("okd-installation".into()), OkdInstallationScore {}),
|
||||
]
|
||||
}
|
||||
|
||||
fn create_interpret(&self) -> Box<dyn Interpret<T>> {
|
||||
Box::new(ProvisionHighAvailabilityClusterInterpret {})
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct ProvisionHighAvailabilityClusterInterpret {}
|
||||
|
||||
#[async_trait]
|
||||
impl<T: Topology> Interpret<T> for ProvisionHighAvailabilityClusterInterpret {
|
||||
async fn execute(
|
||||
&self,
|
||||
_inventory: &Inventory,
|
||||
_topology: &T,
|
||||
_context: ExecutionContext,
|
||||
) -> Result<InterpretOutcome, InterpretError> {
|
||||
Ok(InterpretOutcome {})
|
||||
}
|
||||
}
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() -> Result<(), InterpretError> {
|
||||
let inventory = Inventory::autoload();
|
||||
let topology = HaClusterTopology;
|
||||
|
||||
let maestro = Maestro::init(
|
||||
inventory,
|
||||
topology,
|
||||
vec![Box::new(ProvisionHighAvailabilityClusterScore {})],
|
||||
);
|
||||
|
||||
let _ = maestro.plan();
|
||||
maestro.execute().await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
Reference in New Issue
Block a user