diff --git a/harmony/src/domain/topology/k8s_anywhere.rs b/harmony/src/domain/topology/k8s_anywhere.rs index e6c37ea..6dfb1a8 100644 --- a/harmony/src/domain/topology/k8s_anywhere.rs +++ b/harmony/src/domain/topology/k8s_anywhere.rs @@ -12,14 +12,17 @@ use crate::{ inventory::Inventory, modules::{ k3d::K3DInstallationScore, - monitoring::kube_prometheus::crd::{ - crd_alertmanager_config::CRDPrometheus, - prometheus_operator::prometheus_operator_helm_chart_score, - rhob_alertmanager_config::RHOBObservability, + monitoring::{ + grafana::{grafana::Grafana, helm::helm_grafana::grafana_helm_chart_score}, + kube_prometheus::crd::{ + crd_alertmanager_config::CRDPrometheus, + prometheus_operator::prometheus_operator_helm_chart_score, + rhob_alertmanager_config::RHOBObservability, service_monitor::ServiceMonitor, + }, }, prometheus::{ k8s_prometheus_alerting_score::K8sPrometheusCRDAlertingScore, - prometheus::PrometheusApplicationMonitoring, rhob_alerting_score::RHOBAlertingScore, + prometheus::PrometheusMonitoring, rhob_alerting_score::RHOBAlertingScore, }, }, score::Score, @@ -86,7 +89,43 @@ impl K8sclient for K8sAnywhereTopology { } #[async_trait] -impl PrometheusApplicationMonitoring for K8sAnywhereTopology { +impl Grafana for K8sAnywhereTopology { + async fn ensure_grafana_operator_ready( + &self, + inventory: &Inventory, + ) -> Result { + let client = self.k8s_client().await.unwrap(); + let grafana_gvk = GroupVersionKind { + group: "grafana.integreatly.org".to_string(), + version: "v1beta1".to_string(), + kind: "Grafana".to_string(), + }; + let name = "grafanas.grafana.integreatly.org"; + let ns = "grafana"; + + let grafana_crd = client + .get_resource_json_value(name, Some(ns), &grafana_gvk) + .await; + match grafana_crd { + Ok(_) => { + return Ok(PreparationOutcome::Success { + details: "Found grafana CRDs in cluster".to_string(), + }); + } + Err(_) => { + return self + .install_grafana_operator(inventory, Some("grafana")) + .await; + } + }; + } + async fn install_grafana(&self) -> Result { + todo!() + } +} + +#[async_trait] +impl PrometheusMonitoring for K8sAnywhereTopology { async fn install_prometheus( &self, sender: &CRDPrometheus, @@ -101,7 +140,11 @@ impl PrometheusApplicationMonitoring for K8sAnywhereTopology { } let result = self - .get_k8s_prometheus_application_score(sender.clone(), receivers) + .get_k8s_prometheus_application_score( + sender.clone(), + receivers, + Some(sender.service_monitor.clone()), + ) .await .interpret(inventory, self) .await; @@ -117,10 +160,24 @@ impl PrometheusApplicationMonitoring for K8sAnywhereTopology { Err(err) => Err(PreparationError::new(err.to_string())), } } + async fn ensure_prometheus_operator( + &self, + sender: &CRDPrometheus, + inventory: &Inventory, + ) -> Result { + let po_result = self.ensure_prometheus_operator(sender).await?; + + if po_result == PreparationOutcome::Noop { + debug!("Skipping Prometheus CR installation due to missing operator."); + return Ok(po_result); + } else { + todo!() + } + } } #[async_trait] -impl PrometheusApplicationMonitoring for K8sAnywhereTopology { +impl PrometheusMonitoring for K8sAnywhereTopology { async fn install_prometheus( &self, sender: &RHOBObservability, @@ -154,6 +211,13 @@ impl PrometheusApplicationMonitoring for K8sAnywhereTopology Err(err) => Err(PreparationError::new(err.to_string())), } } + async fn ensure_prometheus_operator( + &self, + sender: &RHOBObservability, + inventory: &Inventory, + ) -> Result { + todo!() + } } impl Serialize for K8sAnywhereTopology { @@ -253,12 +317,22 @@ impl K8sAnywhereTopology { &self, sender: CRDPrometheus, receivers: Option>>>, + service_monitors: Option>, ) -> K8sPrometheusCRDAlertingScore { - K8sPrometheusCRDAlertingScore { - sender, - receivers: receivers.unwrap_or_default(), - service_monitors: vec![], - prometheus_rules: vec![], + if let Some(sm) = service_monitors { + return K8sPrometheusCRDAlertingScore { + sender, + receivers: receivers.unwrap_or_default(), + service_monitors: sm, + prometheus_rules: vec![], + }; + } else { + return K8sPrometheusCRDAlertingScore { + sender, + receivers: receivers.unwrap_or_default(), + service_monitors: vec![], + prometheus_rules: vec![], + }; } } @@ -527,6 +601,22 @@ impl K8sAnywhereTopology { details: "prometheus operator present in cluster".into(), }) } + + async fn install_grafana_operator( + &self, + inventory: &Inventory, + ns: Option<&str>, + ) -> Result { + let _grafana_operator_score = grafana_helm_chart_score(ns.unwrap(), true) + .interpret(inventory, self) + .await; + Ok(PreparationOutcome::Success { + details: format!( + "Successfully installed grafana operator in ns {}", + ns.unwrap() + ), + }) + } } #[derive(Clone, Debug)] diff --git a/harmony/src/modules/application/features/monitoring.rs b/harmony/src/modules/application/features/monitoring.rs index 1a60d00..0fd155d 100644 --- a/harmony/src/modules/application/features/monitoring.rs +++ b/harmony/src/modules/application/features/monitoring.rs @@ -14,7 +14,7 @@ use crate::{ topology::{HelmCommand, K8sclient, Topology, tenant::TenantManager}, }; use crate::{ - modules::prometheus::prometheus::PrometheusApplicationMonitoring, + modules::prometheus::prometheus::PrometheusMonitoring, topology::oberservability::monitoring::AlertReceiver, }; use async_trait::async_trait; @@ -40,7 +40,7 @@ impl< + TenantManager + K8sclient + MultiTargetTopology - + PrometheusApplicationMonitoring + + PrometheusMonitoring + Ingress + std::fmt::Debug, > ApplicationFeature for Monitoring @@ -61,6 +61,7 @@ impl< sender: CRDPrometheus { namespace: namespace.clone(), client: topology.k8s_client().await.unwrap(), + service_monitor: vec![], }, application: self.application.clone(), receivers: self.alert_receiver.clone(), diff --git a/harmony/src/modules/application/features/rhob_monitoring.rs b/harmony/src/modules/application/features/rhob_monitoring.rs index d87ef61..876dba9 100644 --- a/harmony/src/modules/application/features/rhob_monitoring.rs +++ b/harmony/src/modules/application/features/rhob_monitoring.rs @@ -18,7 +18,7 @@ use crate::{ topology::{HelmCommand, K8sclient, Topology, tenant::TenantManager}, }; use crate::{ - modules::prometheus::prometheus::PrometheusApplicationMonitoring, + modules::prometheus::prometheus::PrometheusMonitoring, topology::oberservability::monitoring::AlertReceiver, }; use async_trait::async_trait; @@ -42,7 +42,7 @@ impl< + MultiTargetTopology + Ingress + std::fmt::Debug - + PrometheusApplicationMonitoring, + + PrometheusMonitoring, > ApplicationFeature for Monitoring { async fn ensure_installed( diff --git a/harmony/src/modules/monitoring/application_monitoring/application_monitoring_score.rs b/harmony/src/modules/monitoring/application_monitoring/application_monitoring_score.rs index 8246d15..2780edd 100644 --- a/harmony/src/modules/monitoring/application_monitoring/application_monitoring_score.rs +++ b/harmony/src/modules/monitoring/application_monitoring/application_monitoring_score.rs @@ -10,7 +10,7 @@ use crate::{ modules::{ application::Application, monitoring::kube_prometheus::crd::crd_alertmanager_config::CRDPrometheus, - prometheus::prometheus::PrometheusApplicationMonitoring, + prometheus::prometheus::PrometheusMonitoring, }, score::Score, topology::{PreparationOutcome, Topology, oberservability::monitoring::AlertReceiver}, @@ -24,9 +24,7 @@ pub struct ApplicationMonitoringScore { pub receivers: Vec>>, } -impl> Score - for ApplicationMonitoringScore -{ +impl> Score for ApplicationMonitoringScore { fn create_interpret(&self) -> Box> { Box::new(ApplicationMonitoringInterpret { score: self.clone(), @@ -47,7 +45,7 @@ pub struct ApplicationMonitoringInterpret { } #[async_trait] -impl> Interpret +impl> Interpret for ApplicationMonitoringInterpret { async fn execute( diff --git a/harmony/src/modules/monitoring/application_monitoring/rhobs_application_monitoring_score.rs b/harmony/src/modules/monitoring/application_monitoring/rhobs_application_monitoring_score.rs index 5f5127f..6f45c88 100644 --- a/harmony/src/modules/monitoring/application_monitoring/rhobs_application_monitoring_score.rs +++ b/harmony/src/modules/monitoring/application_monitoring/rhobs_application_monitoring_score.rs @@ -12,7 +12,7 @@ use crate::{ monitoring::kube_prometheus::crd::{ crd_alertmanager_config::CRDPrometheus, rhob_alertmanager_config::RHOBObservability, }, - prometheus::prometheus::PrometheusApplicationMonitoring, + prometheus::prometheus::PrometheusMonitoring, }, score::Score, topology::{PreparationOutcome, Topology, oberservability::monitoring::AlertReceiver}, @@ -26,7 +26,7 @@ pub struct ApplicationRHOBMonitoringScore { pub receivers: Vec>>, } -impl> Score +impl> Score for ApplicationRHOBMonitoringScore { fn create_interpret(&self) -> Box> { @@ -49,7 +49,7 @@ pub struct ApplicationRHOBMonitoringInterpret { } #[async_trait] -impl> Interpret +impl> Interpret for ApplicationRHOBMonitoringInterpret { async fn execute( diff --git a/harmony/src/modules/monitoring/grafana/grafana.rs b/harmony/src/modules/monitoring/grafana/grafana.rs new file mode 100644 index 0000000..411d7a6 --- /dev/null +++ b/harmony/src/modules/monitoring/grafana/grafana.rs @@ -0,0 +1,15 @@ +use async_trait::async_trait; + +use crate::{ + inventory::Inventory, + topology::{PreparationError, PreparationOutcome}, +}; + +#[async_trait] +pub trait Grafana { + async fn ensure_grafana_operator_ready( + &self, + inventory: &Inventory, + ) -> Result; + async fn install_grafana(&self) -> Result; +} diff --git a/harmony/src/modules/monitoring/grafana/helm/helm_grafana.rs b/harmony/src/modules/monitoring/grafana/helm/helm_grafana.rs index 3af6550..094beca 100644 --- a/harmony/src/modules/monitoring/grafana/helm/helm_grafana.rs +++ b/harmony/src/modules/monitoring/grafana/helm/helm_grafana.rs @@ -1,25 +1,22 @@ use non_blank_string_rs::NonBlankString; -use std::str::FromStr; +use std::{collections::HashMap, str::FromStr}; use crate::modules::helm::chart::HelmChartScore; -pub fn grafana_helm_chart_score(ns: &str) -> HelmChartScore { - let values = r#" -rbac: - namespaced: true -sidecar: - dashboards: - enabled: true - "# - .to_string(); - +pub fn grafana_helm_chart_score(ns: &str, scope: bool) -> HelmChartScore { + let mut values_overrides = HashMap::new(); + values_overrides.insert( + NonBlankString::from_str("namespaceScope").unwrap(), + scope.to_string(), + ); HelmChartScore { namespace: Some(NonBlankString::from_str(ns).unwrap()), release_name: NonBlankString::from_str("grafana").unwrap(), - chart_name: NonBlankString::from_str("oci://ghcr.io/grafana/helm-charts/grafana").unwrap(), + chart_name: NonBlankString::from_str("oci://ghcr.io/grafana/helm-charts/grafana-operator") + .unwrap(), chart_version: None, - values_overrides: None, - values_yaml: Some(values.to_string()), + values_overrides: Some(values_overrides), + values_yaml: None, create_namespace: true, install_only: true, repository: None, diff --git a/harmony/src/modules/monitoring/grafana/mod.rs b/harmony/src/modules/monitoring/grafana/mod.rs index c821bcb..8dccab1 100644 --- a/harmony/src/modules/monitoring/grafana/mod.rs +++ b/harmony/src/modules/monitoring/grafana/mod.rs @@ -1 +1,2 @@ +pub mod grafana; pub mod helm; diff --git a/harmony/src/modules/monitoring/kube_prometheus/crd/crd_alertmanager_config.rs b/harmony/src/modules/monitoring/kube_prometheus/crd/crd_alertmanager_config.rs index 2165a4a..0ac8fc7 100644 --- a/harmony/src/modules/monitoring/kube_prometheus/crd/crd_alertmanager_config.rs +++ b/harmony/src/modules/monitoring/kube_prometheus/crd/crd_alertmanager_config.rs @@ -1,12 +1,25 @@ use std::sync::Arc; +use async_trait::async_trait; use kube::CustomResource; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; -use crate::topology::{ - k8s::K8sClient, - oberservability::monitoring::{AlertReceiver, AlertSender}, +use crate::{ + interpret::{InterpretError, Outcome}, + inventory::Inventory, + modules::{ + monitoring::{ + grafana::grafana::Grafana, kube_prometheus::crd::service_monitor::ServiceMonitor, + }, + prometheus::prometheus::PrometheusMonitoring, + }, + topology::{ + K8sclient, Topology, + installable::Installable, + k8s::K8sClient, + oberservability::monitoring::{AlertReceiver, AlertSender}, + }, }; #[derive(CustomResource, Serialize, Deserialize, Debug, Clone, JsonSchema)] @@ -26,6 +39,7 @@ pub struct AlertmanagerConfigSpec { pub struct CRDPrometheus { pub namespace: String, pub client: Arc, + pub service_monitor: Vec, } impl AlertSender for CRDPrometheus { @@ -48,3 +62,24 @@ impl Serialize for Box> { todo!() } } + +#[async_trait] +impl + Grafana> Installable + for CRDPrometheus +{ + async fn configure(&self, inventory: &Inventory, topology: &T) -> Result<(), InterpretError> { + topology.ensure_grafana_operator_ready(inventory).await?; + topology.ensure_prometheus_operator(self, inventory).await?; + Ok(()) + } + + async fn ensure_installed( + &self, + inventory: &Inventory, + topology: &T, + ) -> Result<(), InterpretError> { + topology.install_grafana().await?; + topology.install_prometheus(&self, inventory, None).await?; + Ok(()) + } +} diff --git a/harmony/src/modules/monitoring/prometheus/prometheus.rs b/harmony/src/modules/monitoring/prometheus/prometheus.rs index a207d5a..2fe0d06 100644 --- a/harmony/src/modules/monitoring/prometheus/prometheus.rs +++ b/harmony/src/modules/monitoring/prometheus/prometheus.rs @@ -114,7 +114,7 @@ impl Prometheus { }; if let Some(ns) = namespace.as_deref() { - grafana_helm_chart_score(ns) + grafana_helm_chart_score(ns, false) .interpret(inventory, topology) .await } else { diff --git a/harmony/src/modules/prometheus/k8s_prometheus_alerting_score.rs b/harmony/src/modules/prometheus/k8s_prometheus_alerting_score.rs index 24ca918..2cb4ffb 100644 --- a/harmony/src/modules/prometheus/k8s_prometheus_alerting_score.rs +++ b/harmony/src/modules/prometheus/k8s_prometheus_alerting_score.rs @@ -39,7 +39,7 @@ use crate::{ }; use harmony_types::id::Id; -use super::prometheus::PrometheusApplicationMonitoring; +use super::prometheus::PrometheusMonitoring; #[derive(Clone, Debug, Serialize)] pub struct K8sPrometheusCRDAlertingScore { @@ -49,7 +49,7 @@ pub struct K8sPrometheusCRDAlertingScore { pub prometheus_rules: Vec, } -impl> Score +impl> Score for K8sPrometheusCRDAlertingScore { fn create_interpret(&self) -> Box> { @@ -75,7 +75,7 @@ pub struct K8sPrometheusCRDAlertingInterpret { } #[async_trait] -impl> Interpret +impl> Interpret for K8sPrometheusCRDAlertingInterpret { async fn execute( diff --git a/harmony/src/modules/prometheus/prometheus.rs b/harmony/src/modules/prometheus/prometheus.rs index d3940c7..efb89da 100644 --- a/harmony/src/modules/prometheus/prometheus.rs +++ b/harmony/src/modules/prometheus/prometheus.rs @@ -9,11 +9,17 @@ use crate::{ }; #[async_trait] -pub trait PrometheusApplicationMonitoring { +pub trait PrometheusMonitoring { async fn install_prometheus( &self, sender: &S, inventory: &Inventory, receivers: Option>>>, ) -> Result; + + async fn ensure_prometheus_operator( + &self, + sender: &S, + inventory: &Inventory, + ) -> Result; } diff --git a/harmony/src/modules/prometheus/rhob_alerting_score.rs b/harmony/src/modules/prometheus/rhob_alerting_score.rs index 95908d5..644e6f9 100644 --- a/harmony/src/modules/prometheus/rhob_alerting_score.rs +++ b/harmony/src/modules/prometheus/rhob_alerting_score.rs @@ -38,7 +38,7 @@ use crate::{ }; use harmony_types::id::Id; -use super::prometheus::PrometheusApplicationMonitoring; +use super::prometheus::PrometheusMonitoring; #[derive(Clone, Debug, Serialize)] pub struct RHOBAlertingScore { @@ -48,8 +48,8 @@ pub struct RHOBAlertingScore { pub prometheus_rules: Vec, } -impl> - Score for RHOBAlertingScore +impl> Score + for RHOBAlertingScore { fn create_interpret(&self) -> Box> { Box::new(RHOBAlertingInterpret { @@ -74,8 +74,8 @@ pub struct RHOBAlertingInterpret { } #[async_trait] -impl> - Interpret for RHOBAlertingInterpret +impl> Interpret + for RHOBAlertingInterpret { async fn execute( &self,