diff --git a/Cargo.lock b/Cargo.lock index 8020fb8..e4688ec 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1343,12 +1343,14 @@ dependencies = [ "env_logger", "harmony_macros", "harmony_types", + "helm-wrapper-rs", "http 1.3.1", "inquire", "k8s-openapi", "kube", "libredfish", "log", + "non-blank-string-rs", "opnsense-config", "opnsense-config-xml", "reqwest 0.11.27", @@ -1453,6 +1455,19 @@ version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" +[[package]] +name = "helm-wrapper-rs" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc9253a7bbf4ba8ff6052d5ab7ddc6e2ca17cd8481d15636fb9f64611653880c" +dependencies = [ + "log", + "non-blank-string-rs", + "serde", + "serde_json", + "thiserror 1.0.69", +] + [[package]] name = "hermit-abi" version = "0.3.9" @@ -2328,6 +2343,15 @@ dependencies = [ "unicode-segmentation", ] +[[package]] +name = "non-blank-string-rs" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a05a02248b2e70f1943a59af287a28df78ef9adfc72ee5dc443381d3a1a1a5c" +dependencies = [ + "serde", +] + [[package]] name = "num-bigint" version = "0.4.6" diff --git a/examples/cli/src/main.rs b/examples/cli/src/main.rs index 8689b02..256d055 100644 --- a/examples/cli/src/main.rs +++ b/examples/cli/src/main.rs @@ -18,21 +18,3 @@ async fn main() { ]); harmony_cli::init(maestro, None).await.unwrap(); } - -use assert_cmd::Command; - -#[test] -fn test_example_success() { - let mut cmd = Command::cargo_bin("example-cli").unwrap(); - let assert = cmd.args(&["--yes", "--filter", "SuccessScore"]).assert(); - - assert.success(); -} - -#[test] -fn test_example_fail() { - let mut cmd_fail = Command::cargo_bin("example-cli").unwrap(); - let assert_fail = cmd_fail.args(&["--yes", "--filter", "ErrorScore"]).assert(); - - assert_fail.failure(); -} diff --git a/harmony/Cargo.toml b/harmony/Cargo.toml index a5d53d1..aae188d 100644 --- a/harmony/Cargo.toml +++ b/harmony/Cargo.toml @@ -7,7 +7,7 @@ license.workspace = true [dependencies] libredfish = "0.1.1" -reqwest = {version = "0.11", features = ["blocking", "json"] } +reqwest = { version = "0.11", features = ["blocking", "json"] } russh = "0.45.0" rust-ipmi = "0.1.1" semver = "1.0.23" @@ -31,3 +31,5 @@ serde_yaml = { workspace = true } http = { workspace = true } serde-value = { workspace = true } inquire.workspace = true +helm-wrapper-rs = "0.4.0" +non-blank-string-rs = "1.0.4" diff --git a/harmony/src/domain/topology/helm_command.rs b/harmony/src/domain/topology/helm_command.rs new file mode 100644 index 0000000..f3dd697 --- /dev/null +++ b/harmony/src/domain/topology/helm_command.rs @@ -0,0 +1 @@ +pub trait HelmCommand {} diff --git a/harmony/src/domain/topology/mod.rs b/harmony/src/domain/topology/mod.rs index e792227..3d773ff 100644 --- a/harmony/src/domain/topology/mod.rs +++ b/harmony/src/domain/topology/mod.rs @@ -20,6 +20,9 @@ pub use network::*; use serde::Serialize; pub use tftp::*; +mod helm_command; +pub use helm_command::*; + use std::net::IpAddr; use super::interpret::{InterpretError, Outcome}; diff --git a/harmony/src/infra/opnsense/load_balancer.rs b/harmony/src/infra/opnsense/load_balancer.rs index dd32a03..cae414a 100644 --- a/harmony/src/infra/opnsense/load_balancer.rs +++ b/harmony/src/infra/opnsense/load_balancer.rs @@ -370,10 +370,13 @@ 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() { @@ -430,15 +433,18 @@ 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, + }, + ] + ); } } diff --git a/harmony/src/modules/helm/chart.rs b/harmony/src/modules/helm/chart.rs new file mode 100644 index 0000000..c4dad5e --- /dev/null +++ b/harmony/src/modules/helm/chart.rs @@ -0,0 +1,96 @@ +use crate::data::{Id, Version}; +use crate::interpret::{Interpret, InterpretError, InterpretName, InterpretStatus, Outcome}; +use crate::inventory::Inventory; +use crate::score::Score; +use crate::topology::{HelmCommand, Topology}; +use async_trait::async_trait; +use helm_wrapper_rs; +use helm_wrapper_rs::blocking::{DefaultHelmExecutor, HelmExecutor}; +use non_blank_string_rs::NonBlankString; +use serde::Serialize; +use serde::de::DeserializeOwned; +use std::collections::HashMap; +use std::path::PathBuf; + +#[derive(Debug, Clone, Serialize)] +pub struct HelmChartScore { + pub namespace: Option, + pub release_name: NonBlankString, + pub chart_name: NonBlankString, + pub chart_version: NonBlankString, + pub values_overrides: Option>, +} + +impl Score for HelmChartScore { + fn create_interpret(&self) -> Box> { + todo!() + } + + fn name(&self) -> String { + "HelmChartScore".to_string() + } +} + +#[derive(Debug, Serialize)] +pub struct HelmChartInterpret { + pub score: HelmChartScore, +} + +#[async_trait] +impl Interpret for HelmChartInterpret { + async fn execute( + &self, + _inventory: &Inventory, + _topology: &T, + ) -> Result { + let ns = self + .score + .namespace + .as_ref() + .unwrap_or(todo!("Get namespace from active kubernetes cluster")); + let helm_executor = DefaultHelmExecutor::new(); + let res = helm_executor.install_or_upgrade( + ns, + &self.score.release_name, + &self.score.chart_name, + Some(&self.score.chart_version), + self.score.values_overrides.as_ref(), + None, + None, + ); + let status = match res { + Ok(status) => status, + Err(err) => return Err(InterpretError::new(err.to_string())), + }; + + match status { + helm_wrapper_rs::HelmDeployStatus::Deployed => Ok(Outcome::new( + InterpretStatus::SUCCESS, + "Helm Chart deployed".to_string(), + )), + helm_wrapper_rs::HelmDeployStatus::PendingInstall => Ok(Outcome::new( + InterpretStatus::RUNNING, + "Helm Chart Pending install".to_string(), + )), + helm_wrapper_rs::HelmDeployStatus::PendingUpgrade => Ok(Outcome::new( + InterpretStatus::RUNNING, + "Helm Chart pending upgrade".to_string(), + )), + helm_wrapper_rs::HelmDeployStatus::Failed => Err(InterpretError::new( + "Failed to install helm chart".to_string(), + )), + } + } + fn get_name(&self) -> InterpretName { + todo!() + } + fn get_version(&self) -> Version { + todo!() + } + fn get_status(&self) -> InterpretStatus { + todo!() + } + fn get_children(&self) -> Vec { + todo!() + } +} diff --git a/harmony/src/modules/helm/mod.rs b/harmony/src/modules/helm/mod.rs new file mode 100644 index 0000000..831fbe5 --- /dev/null +++ b/harmony/src/modules/helm/mod.rs @@ -0,0 +1 @@ +pub mod chart; diff --git a/harmony/src/modules/mod.rs b/harmony/src/modules/mod.rs index 19d88d7..a578ada 100644 --- a/harmony/src/modules/mod.rs +++ b/harmony/src/modules/mod.rs @@ -1,6 +1,7 @@ pub mod dhcp; pub mod dns; pub mod dummy; +pub mod helm; pub mod http; pub mod k3d; pub mod k8s;