From 80bdd0ee8ac57f24496642b3f519d90e4e7f458f Mon Sep 17 00:00:00 2001 From: Jean-Gabriel Gill-Couture Date: Thu, 24 Apr 2025 12:58:41 -0400 Subject: [PATCH] feat: introduce Maestro::initialize function that creates the maestro instance and ensure_ready the topology as well. Also refactor all relevant examples to use this new initialize function --- Cargo.lock | 1 + examples/cli/src/main.rs | 6 ++-- examples/kube-rs/Cargo.toml | 1 + examples/kube-rs/src/main.rs | 12 ++++++++ examples/nanodc/src/main.rs | 2 +- examples/opnsense/src/main.rs | 2 +- examples/tui/src/main.rs | 7 ++--- harmony/src/domain/maestro/mod.rs | 6 ++++ harmony/src/domain/topology/ha_cluster.rs | 16 +++++++++- harmony/src/domain/topology/k8s_anywhere.rs | 2 +- harmony/src/infra/opnsense/load_balancer.rs | 34 +++++++++------------ 11 files changed, 58 insertions(+), 31 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e4688ec..f58898d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -961,6 +961,7 @@ dependencies = [ "harmony", "harmony_macros", "http 1.3.1", + "inquire", "k8s-openapi", "kube", "log", diff --git a/examples/cli/src/main.rs b/examples/cli/src/main.rs index 256d055..58674ff 100644 --- a/examples/cli/src/main.rs +++ b/examples/cli/src/main.rs @@ -2,14 +2,14 @@ use harmony::{ inventory::Inventory, maestro::Maestro, modules::dummy::{ErrorScore, PanicScore, SuccessScore}, - topology::HAClusterTopology, + topology::LocalhostTopology, }; #[tokio::main] async fn main() { let inventory = Inventory::autoload(); - let topology = HAClusterTopology::autoload(); - let mut maestro = Maestro::new(inventory, topology); + let topology = LocalhostTopology::new(); + let mut maestro = Maestro::initialize(inventory, topology).await.unwrap(); maestro.register_all(vec![ Box::new(SuccessScore {}), diff --git a/examples/kube-rs/Cargo.toml b/examples/kube-rs/Cargo.toml index a4d7651..34fc64c 100644 --- a/examples/kube-rs/Cargo.toml +++ b/examples/kube-rs/Cargo.toml @@ -18,3 +18,4 @@ kube = "0.98.0" k8s-openapi = { version = "0.24.0", features = [ "v1_30" ] } http = "1.2.0" serde_yaml = "0.9.34" +inquire.workspace = true diff --git a/examples/kube-rs/src/main.rs b/examples/kube-rs/src/main.rs index 7f228e7..d7d941f 100644 --- a/examples/kube-rs/src/main.rs +++ b/examples/kube-rs/src/main.rs @@ -1,6 +1,7 @@ use std::collections::BTreeMap; use harmony_macros::yaml; +use inquire::Confirm; use k8s_openapi::{ api::{ apps::v1::{Deployment, DeploymentSpec}, @@ -15,6 +16,17 @@ use kube::{ #[tokio::main] async fn main() { + let confirmation = Confirm::new( + "This will install various ressources to your default kubernetes cluster. Are you sure?", + ) + .with_default(false) + .prompt() + .expect("Unexpected prompt error"); + + if !confirmation { + return; + } + let client = Client::try_default() .await .expect("Should instanciate client from defaults"); diff --git a/examples/nanodc/src/main.rs b/examples/nanodc/src/main.rs index 5c8c179..27e6849 100644 --- a/examples/nanodc/src/main.rs +++ b/examples/nanodc/src/main.rs @@ -9,7 +9,7 @@ use harmony::{ async fn main() { let inventory = Inventory::autoload(); let topology = HAClusterTopology::autoload(); - let mut maestro = Maestro::new(inventory, topology); + let mut maestro = Maestro::initialize(inventory, topology).await.unwrap(); maestro.register_all(vec![ // ADD scores : diff --git a/examples/opnsense/src/main.rs b/examples/opnsense/src/main.rs index ddf781d..8e01dc0 100644 --- a/examples/opnsense/src/main.rs +++ b/examples/opnsense/src/main.rs @@ -84,7 +84,7 @@ async fn main() { let http_score = HttpScore::new(Url::LocalFolder( "./data/watchguard/pxe-http-files".to_string(), )); - let mut maestro = Maestro::new(inventory, topology); + let mut maestro = Maestro::initialize(inventory, topology).await.unwrap(); maestro.register_all(vec![ Box::new(dns_score), Box::new(dhcp_score), diff --git a/examples/tui/src/main.rs b/examples/tui/src/main.rs index e107d96..39d5039 100644 --- a/examples/tui/src/main.rs +++ b/examples/tui/src/main.rs @@ -9,8 +9,7 @@ use harmony::{ load_balancer::LoadBalancerScore, }, topology::{ - BackendServer, HAClusterTopology, HealthCheck, HttpMethod, HttpStatusCode, - LoadBalancerService, + BackendServer, DummyInfra, HealthCheck, HttpMethod, HttpStatusCode, LoadBalancerService, }, }; use harmony_macros::ipv4; @@ -18,8 +17,8 @@ use harmony_macros::ipv4; #[tokio::main] async fn main() { let inventory = Inventory::autoload(); - let topology = HAClusterTopology::autoload(); - let mut maestro = Maestro::new(inventory, topology); + let topology = DummyInfra {}; + let mut maestro = Maestro::initialize(inventory, topology).await.unwrap(); maestro.register_all(vec![ Box::new(SuccessScore {}), diff --git a/harmony/src/domain/maestro/mod.rs b/harmony/src/domain/maestro/mod.rs index 2bea72d..27932d2 100644 --- a/harmony/src/domain/maestro/mod.rs +++ b/harmony/src/domain/maestro/mod.rs @@ -28,6 +28,12 @@ impl Maestro { } } + pub async fn initialize(inventory: Inventory, topology: T) -> Result { + let instance = Self::new(inventory, topology); + instance.prepare_topology().await?; + Ok(instance) + } + /// Ensures the associated Topology is ready for operations. /// Delegates the readiness check and potential setup actions to the Topology. pub async fn prepare_topology(&self) -> Result { diff --git a/harmony/src/domain/topology/ha_cluster.rs b/harmony/src/domain/topology/ha_cluster.rs index a9bde4c..766c93c 100644 --- a/harmony/src/domain/topology/ha_cluster.rs +++ b/harmony/src/domain/topology/ha_cluster.rs @@ -1,6 +1,7 @@ use async_trait::async_trait; use harmony_macros::ip; use harmony_types::net::MacAddress; +use log::info; use crate::executors::ExecutorError; use crate::interpret::InterpretError; @@ -223,7 +224,20 @@ impl HttpServer for HAClusterTopology { } #[derive(Debug)] -struct DummyInfra; +pub struct DummyInfra; + +#[async_trait] +impl Topology for DummyInfra { + fn name(&self) -> &str { + todo!() + } + + async fn ensure_ready(&self) -> Result { + let dummy_msg = "This is a dummy infrastructure that does nothing"; + info!("{dummy_msg}"); + Ok(Outcome::success(dummy_msg.to_string())) + } +} const UNIMPLEMENTED_DUMMY_INFRA: &str = "This is a dummy infrastructure, no operation is supported"; diff --git a/harmony/src/domain/topology/k8s_anywhere.rs b/harmony/src/domain/topology/k8s_anywhere.rs index c8912d7..79beca5 100644 --- a/harmony/src/domain/topology/k8s_anywhere.rs +++ b/harmony/src/domain/topology/k8s_anywhere.rs @@ -62,7 +62,7 @@ impl K8sAnywhereTopology { } async fn try_install_k3d(&self) -> Result { - let maestro = Maestro::new(Inventory::autoload(), LocalhostTopology::new()); + let maestro = Maestro::initialize(Inventory::autoload(), LocalhostTopology::new()).await?; let k3d_score = K3DInstallationScore::new(); maestro.interpret(Box::new(k3d_score)).await?; todo!( diff --git a/harmony/src/infra/opnsense/load_balancer.rs b/harmony/src/infra/opnsense/load_balancer.rs index cae414a..dd32a03 100644 --- a/harmony/src/infra/opnsense/load_balancer.rs +++ b/harmony/src/infra/opnsense/load_balancer.rs @@ -370,13 +370,10 @@ mod tests { let result = get_servers_for_backend(&backend, &haproxy); // Check the result - assert_eq!( - result, - vec![BackendServer { - address: "192.168.1.1".to_string(), - port: 80, - },] - ); + assert_eq!(result, vec![BackendServer { + address: "192.168.1.1".to_string(), + port: 80, + },]); } #[test] fn test_get_servers_for_backend_no_linked_servers() { @@ -433,18 +430,15 @@ mod tests { // Call the function let result = get_servers_for_backend(&backend, &haproxy); // Check the result - assert_eq!( - result, - vec![ - BackendServer { - address: "some-hostname.test.mcd".to_string(), - port: 80, - }, - BackendServer { - address: "192.168.1.2".to_string(), - port: 8080, - }, - ] - ); + assert_eq!(result, vec![ + BackendServer { + address: "some-hostname.test.mcd".to_string(), + port: 80, + }, + BackendServer { + address: "192.168.1.2".to_string(), + port: 8080, + }, + ]); } }