From 8ae0d6b54811d1db7ea68744f2b0572ca2a3ce2d Mon Sep 17 00:00:00 2001 From: Jean-Gabriel Gill-Couture Date: Tue, 1 Jul 2025 22:44:44 -0400 Subject: [PATCH 1/5] feat: Application Interpret still WIP but now call ensure_installed on features, also introduced a rust app example, completed work on clone_box behavior --- Cargo.lock | 14 ++++++++ examples/rust/Cargo.toml | 14 ++++++++ examples/rust/src/main.rs | 20 +++++++++++ examples/tui/Cargo.toml | 2 +- harmony/src/domain/topology/ha_cluster.rs | 2 +- .../features/continuous_delivery.rs | 2 +- .../modules/application/features/endpoint.rs | 2 +- .../application/features/monitoring.rs | 2 +- harmony/src/modules/application/mod.rs | 33 ++++++++++++++++--- harmony/src/modules/application/rust.rs | 6 ++-- 10 files changed, 86 insertions(+), 11 deletions(-) create mode 100644 examples/rust/Cargo.toml create mode 100644 examples/rust/src/main.rs diff --git a/Cargo.lock b/Cargo.lock index 2769781..cea53ec 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1194,6 +1194,20 @@ dependencies = [ "url", ] +[[package]] +name = "example-rust" +version = "0.1.0" +dependencies = [ + "env_logger", + "harmony", + "harmony_cli", + "harmony_macros", + "harmony_types", + "log", + "tokio", + "url", +] + [[package]] name = "example-tenant" version = "0.1.0" diff --git a/examples/rust/Cargo.toml b/examples/rust/Cargo.toml new file mode 100644 index 0000000..9fcfb2f --- /dev/null +++ b/examples/rust/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "example-rust" +version = "0.1.0" +edition = "2024" + +[dependencies] +harmony = { path = "../../harmony" } +harmony_cli = { path = "../../harmony_cli" } +harmony_types = { path = "../../harmony_types" } +harmony_macros = { path = "../../harmony_macros" } +tokio = { workspace = true } +log = { workspace = true } +env_logger = { workspace = true } +url = { workspace = true } diff --git a/examples/rust/src/main.rs b/examples/rust/src/main.rs new file mode 100644 index 0000000..28cd6f1 --- /dev/null +++ b/examples/rust/src/main.rs @@ -0,0 +1,20 @@ +use harmony::{ + inventory::Inventory, + maestro::Maestro, + modules::application::{RustWebappScore, features::ContinuousDelivery}, + topology::{K8sAnywhereTopology, Url}, +}; + +#[tokio::main] +async fn main() { + let app = RustWebappScore { + name: "Example Rust Webapp".to_string(), + domain: Url::Url(url::Url::parse("https://rustapp.harmony.example.com").unwrap()), + features: vec![Box::new(ContinuousDelivery {})], + }; + + let topology = K8sAnywhereTopology::from_env(); + let mut maestro = Maestro::new(Inventory::autoload(), topology); + maestro.register_all(vec![Box::new(app)]); + harmony_cli::init(maestro, None).await.unwrap(); +} diff --git a/examples/tui/Cargo.toml b/examples/tui/Cargo.toml index d9390ca..9e5dc2a 100644 --- a/examples/tui/Cargo.toml +++ b/examples/tui/Cargo.toml @@ -10,9 +10,9 @@ publish = false harmony = { path = "../../harmony" } harmony_tui = { path = "../../harmony_tui" } harmony_types = { path = "../../harmony_types" } +harmony_macros = { path = "../../harmony_macros" } cidr = { workspace = true } tokio = { workspace = true } -harmony_macros = { path = "../../harmony_macros" } log = { workspace = true } env_logger = { workspace = true } url = { workspace = true } diff --git a/harmony/src/domain/topology/ha_cluster.rs b/harmony/src/domain/topology/ha_cluster.rs index 6ee1844..a114e18 100644 --- a/harmony/src/domain/topology/ha_cluster.rs +++ b/harmony/src/domain/topology/ha_cluster.rs @@ -46,7 +46,7 @@ pub struct HAClusterTopology { #[async_trait] impl Topology for HAClusterTopology { fn name(&self) -> &str { - todo!() + "HAClusterTopology" } async fn ensure_ready(&self) -> Result { todo!( diff --git a/harmony/src/modules/application/features/continuous_delivery.rs b/harmony/src/modules/application/features/continuous_delivery.rs index 3530142..14ce255 100644 --- a/harmony/src/modules/application/features/continuous_delivery.rs +++ b/harmony/src/modules/application/features/continuous_delivery.rs @@ -30,7 +30,7 @@ use crate::{modules::application::ApplicationFeature, topology::Topology}; /// - Harbor as artifact registru /// - ArgoCD to install/upgrade/rollback/inspect k8s resources /// - Kubernetes for runtime orchestration -#[derive(Debug, Default)] +#[derive(Debug, Default, Clone)] pub struct ContinuousDelivery {} #[async_trait] diff --git a/harmony/src/modules/application/features/endpoint.rs b/harmony/src/modules/application/features/endpoint.rs index f4940ed..83cc215 100644 --- a/harmony/src/modules/application/features/endpoint.rs +++ b/harmony/src/modules/application/features/endpoint.rs @@ -6,7 +6,7 @@ use crate::{ topology::{K8sclient, Topology}, }; -#[derive(Debug)] +#[derive(Debug, Clone)] pub struct PublicEndpoint { application_port: u16, } diff --git a/harmony/src/modules/application/features/monitoring.rs b/harmony/src/modules/application/features/monitoring.rs index 91ad72d..a343e44 100644 --- a/harmony/src/modules/application/features/monitoring.rs +++ b/harmony/src/modules/application/features/monitoring.rs @@ -6,7 +6,7 @@ use crate::{ topology::{HelmCommand, Topology}, }; -#[derive(Debug, Default)] +#[derive(Debug, Default, Clone)] pub struct Monitoring {} #[async_trait] diff --git a/harmony/src/modules/application/mod.rs b/harmony/src/modules/application/mod.rs index 2a3ee24..ddbfe49 100644 --- a/harmony/src/modules/application/mod.rs +++ b/harmony/src/modules/application/mod.rs @@ -22,9 +22,19 @@ impl Interpret for ApplicationInterpret { async fn execute( &self, _inventory: &Inventory, - _topology: &T, + topology: &T, ) -> Result { - todo!() + for feature in self.features.iter() { + let _ = match feature.ensure_installed(topology).await { + Ok(()) => (), + Err(msg) => { + return Err(InterpretError::new(format!( + "Application Interpret failed to install feature : {msg}" + ))); + } + }; + } + todo!("Do I need to do anything more than this here??") } fn get_name(&self) -> InterpretName { @@ -47,10 +57,25 @@ impl Interpret for ApplicationInterpret { /// An ApplicationFeature provided by harmony, such as Backups, Monitoring, MultisiteAvailability, /// ContinuousIntegration, ContinuousDelivery #[async_trait] -pub trait ApplicationFeature: std::fmt::Debug + Send + Sync { +pub trait ApplicationFeature: + std::fmt::Debug + Send + Sync + ApplicationFeatureClone +{ async fn ensure_installed(&self, topology: &T) -> Result<(), String>; } +trait ApplicationFeatureClone { + fn clone_box(&self) -> Box>; +} + +impl ApplicationFeatureClone for A +where + A: ApplicationFeature + Clone + 'static, +{ + fn clone_box(&self) -> Box> { + Box::new(self.clone()) + } +} + impl Serialize for Box> { fn serialize(&self, serializer: S) -> Result where @@ -62,6 +87,6 @@ impl Serialize for Box> { impl Clone for Box> { fn clone(&self) -> Self { - todo!() + self.clone_box() } } diff --git a/harmony/src/modules/application/rust.rs b/harmony/src/modules/application/rust.rs index 0ef41b3..231b821 100644 --- a/harmony/src/modules/application/rust.rs +++ b/harmony/src/modules/application/rust.rs @@ -5,7 +5,7 @@ use crate::{ topology::{Topology, Url}, }; -use super::{ApplicationFeature, ApplicationInterpret}; +use super::{ApplicationFeature, ApplicationInterpret, features::ContinuousDelivery}; #[derive(Debug, Serialize, Clone)] pub struct RustWebappScore { @@ -16,7 +16,9 @@ pub struct RustWebappScore { impl Score for RustWebappScore { fn create_interpret(&self) -> Box> { - Box::new(ApplicationInterpret { features: todo!() }) + Box::new(ApplicationInterpret { + features: self.features.clone(), + }) } fn name(&self) -> String { From c74c51090a550567bfbd8b8b7ed3459eef28a1ac Mon Sep 17 00:00:00 2001 From: Jean-Gabriel Gill-Couture Date: Wed, 2 Jul 2025 07:53:14 -0400 Subject: [PATCH 2/5] feat: Introduce Application trait, not too sure how it will evolve but it makes sense, at the very least to identify the Application, also some minor refactoring --- .../features/continuous_delivery.rs | 3 + .../modules/application/features/endpoint.rs | 3 + .../application/features/monitoring.rs | 3 + harmony/src/modules/application/mod.rs | 59 +++++++------------ harmony/src/modules/application/rust.rs | 16 ++++- 5 files changed, 45 insertions(+), 39 deletions(-) diff --git a/harmony/src/modules/application/features/continuous_delivery.rs b/harmony/src/modules/application/features/continuous_delivery.rs index 14ce255..cbfdbe7 100644 --- a/harmony/src/modules/application/features/continuous_delivery.rs +++ b/harmony/src/modules/application/features/continuous_delivery.rs @@ -39,4 +39,7 @@ impl ApplicationFeature for ContinuousDelivery { info!("Installing ContinuousDelivery feature"); todo!() } + fn name(&self) -> String { + "ContinuousDelivery".to_string() + } } diff --git a/harmony/src/modules/application/features/endpoint.rs b/harmony/src/modules/application/features/endpoint.rs index 83cc215..042f0dd 100644 --- a/harmony/src/modules/application/features/endpoint.rs +++ b/harmony/src/modules/application/features/endpoint.rs @@ -36,4 +36,7 @@ impl ApplicationFeature for PublicEndpoint ); todo!() } + fn name(&self) -> String { + "PublicEndpoint".to_string() + } } diff --git a/harmony/src/modules/application/features/monitoring.rs b/harmony/src/modules/application/features/monitoring.rs index a343e44..33717a4 100644 --- a/harmony/src/modules/application/features/monitoring.rs +++ b/harmony/src/modules/application/features/monitoring.rs @@ -15,4 +15,7 @@ impl ApplicationFeature for Monitoring { info!("Ensuring monitoring is available for application"); todo!("create and execute k8s prometheus score, depends on Will's work") } + fn name(&self) -> String { + "Monitoring".to_string() + } } diff --git a/harmony/src/modules/application/mod.rs b/harmony/src/modules/application/mod.rs index ddbfe49..663835f 100644 --- a/harmony/src/modules/application/mod.rs +++ b/harmony/src/modules/application/mod.rs @@ -1,9 +1,11 @@ +mod feature; pub mod features; mod rust; +pub use feature::*; +use log::info; pub use rust::*; use async_trait::async_trait; -use serde::Serialize; use crate::{ data::{Id, Version}, @@ -12,9 +14,14 @@ use crate::{ topology::Topology, }; +pub trait Application: std::fmt::Debug + Send + Sync { + fn name(&self) -> String; +} + #[derive(Debug)] pub struct ApplicationInterpret { features: Vec>>, + application: Box, } #[async_trait] @@ -24,7 +31,20 @@ impl Interpret for ApplicationInterpret { _inventory: &Inventory, topology: &T, ) -> Result { + let app_name = self.application.name(); + info!( + "Preparing features {} for application {app_name}", + self.features + .iter() + .map(|f| f.name()) + .collect::>() + .join(", ") + ); for feature in self.features.iter() { + info!( + "Installing feature {} for application {app_name}", + feature.name() + ); let _ = match feature.ensure_installed(topology).await { Ok(()) => (), Err(msg) => { @@ -53,40 +73,3 @@ impl Interpret for ApplicationInterpret { todo!() } } - -/// An ApplicationFeature provided by harmony, such as Backups, Monitoring, MultisiteAvailability, -/// ContinuousIntegration, ContinuousDelivery -#[async_trait] -pub trait ApplicationFeature: - std::fmt::Debug + Send + Sync + ApplicationFeatureClone -{ - async fn ensure_installed(&self, topology: &T) -> Result<(), String>; -} - -trait ApplicationFeatureClone { - fn clone_box(&self) -> Box>; -} - -impl ApplicationFeatureClone for A -where - A: ApplicationFeature + Clone + 'static, -{ - fn clone_box(&self) -> Box> { - Box::new(self.clone()) - } -} - -impl Serialize for Box> { - fn serialize(&self, serializer: S) -> Result - where - S: serde::Serializer, - { - todo!() - } -} - -impl Clone for Box> { - fn clone(&self) -> Self { - self.clone_box() - } -} diff --git a/harmony/src/modules/application/rust.rs b/harmony/src/modules/application/rust.rs index 231b821..43a4907 100644 --- a/harmony/src/modules/application/rust.rs +++ b/harmony/src/modules/application/rust.rs @@ -5,7 +5,7 @@ use crate::{ topology::{Topology, Url}, }; -use super::{ApplicationFeature, ApplicationInterpret, features::ContinuousDelivery}; +use super::{Application, ApplicationFeature, ApplicationInterpret}; #[derive(Debug, Serialize, Clone)] pub struct RustWebappScore { @@ -18,6 +18,9 @@ impl Score for R fn create_interpret(&self) -> Box> { Box::new(ApplicationInterpret { features: self.features.clone(), + application: Box::new(RustWebapp { + name: self.name.clone(), + }), }) } @@ -25,3 +28,14 @@ impl Score for R format!("{}-RustWebapp", self.name) } } + +#[derive(Debug)] +struct RustWebapp { + name: String, +} + +impl Application for RustWebapp { + fn name(&self) -> String { + self.name.clone() + } +} From 6e884cff3a862c675032a356635277b2c4476ec9 Mon Sep 17 00:00:00 2001 From: Jean-Gabriel Gill-Couture Date: Wed, 2 Jul 2025 11:14:24 -0400 Subject: [PATCH 3/5] feat: Start default implementation to ArgoCD for ContinuousDelivery feature --- harmony/src/domain/interpret/mod.rs | 2 + harmony/src/domain/inventory/mod.rs | 11 +++++ .../features/continuous_delivery.rs | 47 +++++++++++++++++-- harmony/src/modules/application/mod.rs | 11 +++-- 4 files changed, 63 insertions(+), 8 deletions(-) diff --git a/harmony/src/domain/interpret/mod.rs b/harmony/src/domain/interpret/mod.rs index 5e928cb..9a0c26b 100644 --- a/harmony/src/domain/interpret/mod.rs +++ b/harmony/src/domain/interpret/mod.rs @@ -21,6 +21,7 @@ pub enum InterpretName { OPNSense, K3dInstallation, TenantInterpret, + Application, } impl std::fmt::Display for InterpretName { @@ -37,6 +38,7 @@ impl std::fmt::Display for InterpretName { InterpretName::OPNSense => f.write_str("OPNSense"), InterpretName::K3dInstallation => f.write_str("K3dInstallation"), InterpretName::TenantInterpret => f.write_str("Tenant"), + InterpretName::Application => f.write_str("Application"), } } } diff --git a/harmony/src/domain/inventory/mod.rs b/harmony/src/domain/inventory/mod.rs index d566f18..851a150 100644 --- a/harmony/src/domain/inventory/mod.rs +++ b/harmony/src/domain/inventory/mod.rs @@ -34,6 +34,17 @@ pub struct Inventory { } impl Inventory { + pub fn empty() -> Self { + Self { + location: Location::new("Empty".to_string(), "location".to_string()), + switch: vec![], + firewall: vec![], + worker_host: vec![], + storage_host: vec![], + control_plane_host: vec![], + } + } + pub fn autoload() -> Self { Self { location: Location::test_building(), diff --git a/harmony/src/modules/application/features/continuous_delivery.rs b/harmony/src/modules/application/features/continuous_delivery.rs index cbfdbe7..e7dd968 100644 --- a/harmony/src/modules/application/features/continuous_delivery.rs +++ b/harmony/src/modules/application/features/continuous_delivery.rs @@ -1,7 +1,14 @@ use async_trait::async_trait; use log::info; +use serde_json::Value; -use crate::{modules::application::ApplicationFeature, topology::Topology}; +use crate::{ + data::Version, + inventory::Inventory, + modules::{application::ApplicationFeature, helm::chart::HelmChartScore}, + score::Score, + topology::{HelmCommand, Topology, Url}, +}; /// ContinuousDelivery in Harmony provides this functionality : /// @@ -34,12 +41,44 @@ use crate::{modules::application::ApplicationFeature, topology::Topology}; pub struct ContinuousDelivery {} #[async_trait] -impl ApplicationFeature for ContinuousDelivery { - async fn ensure_installed(&self, _topology: &T) -> Result<(), String> { +impl ApplicationFeature for ContinuousDelivery { + async fn ensure_installed(&self, topology: &T) -> Result<(), String> { info!("Installing ContinuousDelivery feature"); - todo!() + let cd_server = HelmChartScore { + namespace: todo!( + "ArgoCD Helm chart with proper understanding of Tenant, see how Will did it for Monitoring for now" + ), + release_name: todo!("argocd helm chart whatever"), + chart_name: todo!(), + chart_version: todo!(), + values_overrides: todo!(), + values_yaml: todo!(), + create_namespace: todo!(), + install_only: todo!(), + repository: todo!(), + }; + let interpret = cd_server.create_interpret(); + interpret.execute(&Inventory::empty(), topology); + + todo!("1. Create ArgoCD score that installs argo using helm chart, see if Taha's already done it + 2. Package app (docker image, helm chart) + 3. Push to registry if staging or prod + 4. Poke Argo + 5. Ensure app is up") } fn name(&self) -> String { "ContinuousDelivery".to_string() } } + +/// For now this is entirely bound to K8s / ArgoCD, will have to be revisited when we support +/// more CD systems +pub struct CDApplicationConfig { + version: Version, + helm_chart_url: Url, + values_overrides: Value, +} + +pub trait ContinuousDeliveryApplication { + fn get_config(&self) -> CDApplicationConfig; +} diff --git a/harmony/src/modules/application/mod.rs b/harmony/src/modules/application/mod.rs index 663835f..92669c0 100644 --- a/harmony/src/modules/application/mod.rs +++ b/harmony/src/modules/application/mod.rs @@ -33,7 +33,8 @@ impl Interpret for ApplicationInterpret { ) -> Result { let app_name = self.application.name(); info!( - "Preparing features {} for application {app_name}", + "Preparing {} features [{}] for application {app_name}", + self.features.len(), self.features .iter() .map(|f| f.name()) @@ -54,15 +55,17 @@ impl Interpret for ApplicationInterpret { } }; } - todo!("Do I need to do anything more than this here??") + todo!( + "Do I need to do anything more than this here?? I feel like the Application trait itself should expose something like ensure_ready but its becoming redundant. We'll see as this evolves." + ) } fn get_name(&self) -> InterpretName { - todo!() + InterpretName::Application } fn get_version(&self) -> Version { - todo!() + Version::from("1.0.0").unwrap() } fn get_status(&self) -> InterpretStatus { From ab69a2c264805956f86f687b7eb8e75444dc318e Mon Sep 17 00:00:00 2001 From: taha Date: Wed, 2 Jul 2025 15:29:16 +0000 Subject: [PATCH 4/5] feat: add service monitors support to prom (#66) Co-authored-by: tahahawa Reviewed-on: https://git.nationtech.io/NationTech/harmony/pulls/66 Co-authored-by: taha Co-committed-by: taha --- Cargo.lock | 1 + examples/monitoring/Cargo.toml | 1 + examples/monitoring/src/main.rs | 23 ++ .../monitoring/kube_prometheus/helm/config.rs | 2 + .../helm/kube_prometheus_helm_chart.rs | 21 +- .../helm_prometheus_alert_score.rs | 11 +- .../monitoring/kube_prometheus/types.rs | 199 ++++++++++++++++++ 7 files changed, 252 insertions(+), 6 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index cea53ec..7d58b9f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1160,6 +1160,7 @@ version = "0.1.0" dependencies = [ "harmony", "harmony_cli", + "harmony_macros", "tokio", "url", ] diff --git a/examples/monitoring/Cargo.toml b/examples/monitoring/Cargo.toml index d188b78..1c35330 100644 --- a/examples/monitoring/Cargo.toml +++ b/examples/monitoring/Cargo.toml @@ -8,5 +8,6 @@ license.workspace = true [dependencies] harmony = { version = "0.1.0", path = "../../harmony" } harmony_cli = { version = "0.1.0", path = "../../harmony_cli" } +harmony_macros = { version = "0.1.0", path = "../../harmony_macros" } tokio.workspace = true url.workspace = true diff --git a/examples/monitoring/src/main.rs b/examples/monitoring/src/main.rs index c2522f3..da9c1c1 100644 --- a/examples/monitoring/src/main.rs +++ b/examples/monitoring/src/main.rs @@ -1,3 +1,5 @@ +use std::collections::HashMap; + use harmony::{ inventory::Inventory, maestro::Maestro, @@ -41,9 +43,30 @@ async fn main() { ], ); + let service_monitor_endpoint = ServiceMonitorEndpoint { + port: Some("80".to_string()), + path: "/metrics".to_string(), + scheme: HTTPScheme::HTTP, + ..Default::default() + }; + + let service_monitor = ServiceMonitor { + name: "test-service-monitor".to_string(), + selector: Selector { + match_labels: HashMap::new(), + match_expressions: vec![MatchExpression { + key: "test".to_string(), + operator: Operator::In, + values: vec!["test-service".to_string()], + }], + }, + endpoints: vec![service_monitor_endpoint], + ..Default::default() + }; let alerting_score = HelmPrometheusAlertingScore { receivers: vec![Box::new(discord_receiver)], rules: vec![Box::new(additional_rules), Box::new(additional_rules2)], + service_monitors: vec![service_monitor], }; let mut maestro = Maestro::::initialize( Inventory::autoload(), diff --git a/harmony/src/modules/monitoring/kube_prometheus/helm/config.rs b/harmony/src/modules/monitoring/kube_prometheus/helm/config.rs index ecbf8d8..723e7b9 100644 --- a/harmony/src/modules/monitoring/kube_prometheus/helm/config.rs +++ b/harmony/src/modules/monitoring/kube_prometheus/helm/config.rs @@ -26,6 +26,7 @@ pub struct KubePrometheusConfig { pub prometheus_operator: bool, pub alert_receiver_configs: Vec, pub alert_rules: Vec, + pub additional_service_monitors: Vec, } impl KubePrometheusConfig { pub fn new() -> Self { @@ -49,6 +50,7 @@ impl KubePrometheusConfig { kube_scheduler: false, alert_receiver_configs: vec![], alert_rules: vec![], + additional_service_monitors: vec![], } } } diff --git a/harmony/src/modules/monitoring/kube_prometheus/helm/kube_prometheus_helm_chart.rs b/harmony/src/modules/monitoring/kube_prometheus/helm/kube_prometheus_helm_chart.rs index 843a677..8b86b88 100644 --- a/harmony/src/modules/monitoring/kube_prometheus/helm/kube_prometheus_helm_chart.rs +++ b/harmony/src/modules/monitoring/kube_prometheus/helm/kube_prometheus_helm_chart.rs @@ -12,7 +12,7 @@ use crate::modules::{ helm::chart::HelmChartScore, monitoring::kube_prometheus::types::{ AlertGroup, AlertManager, AlertManagerAdditionalPromRules, AlertManagerConfig, - AlertManagerRoute, AlertManagerValues, + AlertManagerRoute, AlertManagerValues, PrometheusConfig, }, }; @@ -101,11 +101,26 @@ nodeExporter: enabled: {node_exporter} prometheusOperator: enabled: {prometheus_operator} -prometheus: - enabled: {prometheus} + "#, ); + let prometheus_config = + crate::modules::monitoring::kube_prometheus::types::PrometheusConfigValues { + prometheus: PrometheusConfig { + prometheus: bool::from_str(prometheus.as_str()).expect("couldn't parse bool"), + additional_service_monitors: config.additional_service_monitors.clone(), + }, + }; + let prometheus_config_yaml = + serde_yaml::to_string(&prometheus_config).expect("Failed to serialize YAML"); + + debug!( + "serialized prometheus config: \n {:#}", + prometheus_config_yaml + ); + values.push_str(&prometheus_config_yaml); + // add required null receiver for prometheus alert manager let mut null_receiver = Mapping::new(); null_receiver.insert( diff --git a/harmony/src/modules/monitoring/kube_prometheus/helm_prometheus_alert_score.rs b/harmony/src/modules/monitoring/kube_prometheus/helm_prometheus_alert_score.rs index 8844309..954f6b9 100644 --- a/harmony/src/modules/monitoring/kube_prometheus/helm_prometheus_alert_score.rs +++ b/harmony/src/modules/monitoring/kube_prometheus/helm_prometheus_alert_score.rs @@ -4,6 +4,7 @@ use serde::Serialize; use super::{helm::config::KubePrometheusConfig, prometheus::Prometheus}; use crate::{ + modules::monitoring::kube_prometheus::types::ServiceMonitor, score::Score, topology::{ HelmCommand, Topology, @@ -15,14 +16,18 @@ use crate::{ pub struct HelmPrometheusAlertingScore { pub receivers: Vec>>, pub rules: Vec>>, + pub service_monitors: Vec, } impl Score for HelmPrometheusAlertingScore { fn create_interpret(&self) -> Box> { + let config = Arc::new(Mutex::new(KubePrometheusConfig::new())); + config + .try_lock() + .expect("couldn't lock config") + .additional_service_monitors = self.service_monitors.clone(); Box::new(AlertingInterpret { - sender: Prometheus { - config: Arc::new(Mutex::new(KubePrometheusConfig::new())), - }, + sender: Prometheus { config }, receivers: self.receivers.clone(), rules: self.rules.clone(), }) diff --git a/harmony/src/modules/monitoring/kube_prometheus/types.rs b/harmony/src/modules/monitoring/kube_prometheus/types.rs index 878d527..f3d1e95 100644 --- a/harmony/src/modules/monitoring/kube_prometheus/types.rs +++ b/harmony/src/modules/monitoring/kube_prometheus/types.rs @@ -53,3 +53,202 @@ pub struct AlertManagerAdditionalPromRules { pub struct AlertGroup { pub groups: Vec, } + +#[derive(Debug, Clone, Serialize)] +pub enum HTTPScheme { + #[serde(rename = "http")] + HTTP, + #[serde(rename = "https")] + HTTPS, +} + +#[derive(Debug, Clone, Serialize)] +pub enum Operator { + In, + NotIn, + Exists, + DoesNotExist, +} + +#[derive(Debug, Clone, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct PrometheusConfigValues { + pub prometheus: PrometheusConfig, +} + +#[derive(Debug, Clone, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct PrometheusConfig { + pub prometheus: bool, + pub additional_service_monitors: Vec, +} + +#[derive(Debug, Clone, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct ServiceMonitorTLSConfig { + // ## Path to the CA file + // ## + pub ca_file: Option, + + // ## Path to client certificate file + // ## + pub cert_file: Option, + + // ## Skip certificate verification + // ## + pub insecure_skip_verify: Option, + + // ## Path to client key file + // ## + pub key_file: Option, + + // ## Server name used to verify host name + // ## + pub server_name: Option, +} + +#[derive(Debug, Clone, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct ServiceMonitorEndpoint { + // ## Name of the endpoint's service port + // ## Mutually exclusive with targetPort + pub port: Option, + + // ## Name or number of the endpoint's target port + // ## Mutually exclusive with port + pub target_port: Option, + + // ## File containing bearer token to be used when scraping targets + // ## + pub bearer_token_file: Option, + + // ## Interval at which metrics should be scraped + // ## + pub interval: Option, + + // ## HTTP path to scrape for metrics + // ## + pub path: String, + + // ## HTTP scheme to use for scraping + // ## + pub scheme: HTTPScheme, + + // ## TLS configuration to use when scraping the endpoint + // ## + pub tls_config: Option, + + // ## MetricRelabelConfigs to apply to samples after scraping, but before ingestion. + // ## ref: https://github.com/prometheus-operator/prometheus-operator/blob/main/Documentation/api-reference/api.md#relabelconfig + // ## + // # - action: keep + // # regex: 'kube_(daemonset|deployment|pod|namespace|node|statefulset).+' + // # sourceLabels: [__name__] + pub metric_relabelings: Vec, + + // ## RelabelConfigs to apply to samples before scraping + // ## ref: https://github.com/prometheus-operator/prometheus-operator/blob/main/Documentation/api-reference/api.md#relabelconfig + // ## + // # - sourceLabels: [__meta_kubernetes_pod_node_name] + // # separator: ; + // # regex: ^(.*)$ + // # targetLabel: nodename + // # replacement: $1 + // # action: replace + pub relabelings: Vec, +} + +#[derive(Debug, Clone, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct MatchExpression { + pub key: String, + pub operator: Operator, + pub values: Vec, +} + +#[derive(Debug, Clone, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct Selector { + // # label selector for services + pub match_labels: HashMap, + pub match_expressions: Vec, +} + +#[derive(Debug, Clone, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct ServiceMonitor { + pub name: String, + + // # Additional labels to set used for the ServiceMonitorSelector. Together with standard labels from the chart + pub additional_labels: Option, + + // # Service label for use in assembling a job name of the form