diff --git a/tembo-operator/src/cloudnativepg/cnpg.rs b/tembo-operator/src/cloudnativepg/cnpg.rs index 2d00d95d0..e794d2e5b 100644 --- a/tembo-operator/src/cloudnativepg/cnpg.rs +++ b/tembo-operator/src/cloudnativepg/cnpg.rs @@ -39,6 +39,7 @@ use crate::{ }, }, config::Config, + configmap::custom_metrics_configmap_settings, defaults::{default_image, default_llm_image}, errors::ValueError, is_postgres_ready, patch_cdb_status_merge, @@ -581,6 +582,18 @@ pub fn cnpg_cluster_from_cdb( }; let certificates = create_cluster_certificates(cdb); + let mut metrics = vec![ClusterMonitoringCustomQueriesConfigMap { + key: "queries".to_string(), + name: "cnpg-default-monitoring".to_string(), + }]; + + if custom_metrics_configmap_settings().is_some() { + let configmap_name = format!("{}-custom", cdb.name_any()); + metrics.push(ClusterMonitoringCustomQueriesConfigMap { + key: "custom-queries".to_string(), + name: configmap_name, + }) + } Cluster { metadata: ObjectMeta { @@ -611,10 +624,7 @@ pub fn cnpg_cluster_from_cdb( max_sync_replicas: Some(0), min_sync_replicas: Some(0), monitoring: Some(ClusterMonitoring { - custom_queries_config_map: Some(vec![ClusterMonitoringCustomQueriesConfigMap { - key: "queries".to_string(), - name: "cnpg-default-monitoring".to_string(), - }]), + custom_queries_config_map: Some(metrics), disable_default_queries: Some(false), enable_pod_monitor: Some(true), ..ClusterMonitoring::default() @@ -843,6 +853,7 @@ fn update_restarted_at(cdb: &CoreDB, maybe_cluster: Option<&Cluster>, new_spec: restart_annotation_updated } + #[instrument(skip(cdb, ctx) fields(trace_id, instance_name = %cdb.name_any()))] pub async fn reconcile_cnpg(cdb: &CoreDB, ctx: Arc) -> Result<(), Action> { let pods_to_fence = pods_to_fence(cdb, ctx.clone()).await?; diff --git a/tembo-operator/src/configmap.rs b/tembo-operator/src/configmap.rs index ca33a60ed..eb61060f6 100644 --- a/tembo-operator/src/configmap.rs +++ b/tembo-operator/src/configmap.rs @@ -1,12 +1,70 @@ -use crate::Error; +use crate::{apis::coredb_types::CoreDB, Context, Error}; use k8s_openapi::api::core::v1::ConfigMap; use kube::{ api::{Api, ObjectMeta, Patch, PatchParams}, - Client, + runtime::controller::Action, + Client, ResourceExt, }; -use std::collections::BTreeMap; +use std::{collections::BTreeMap, sync::Arc}; -use tracing::{debug, error}; +use tracing::{debug, error, instrument}; + +#[instrument(skip(cdb, ctx) fields(trace_id, instance_name = %cdb.name_any()))] +pub async fn reconcile_generic_metrics_configmap(cdb: &CoreDB, ctx: Arc) -> Result<(), Action> { + let (custom_metrics_namespace, custom_metrics_name) = match custom_metrics_configmap_settings() { + Some(value) => value, + _ => return Ok(()), + }; + + let namespace = cdb.namespace().unwrap(); + let client = ctx.client.clone(); + let configmap_api_dataplane_namespace: Api = + Api::namespaced(client.clone(), &custom_metrics_namespace); + + let configmap_name = format!("{}-custom", cdb.name_any()); + + match configmap_api_dataplane_namespace.get(&custom_metrics_name).await { + Ok(original_configmap) => { + let data = original_configmap.data.clone().unwrap_or_default(); + match apply_configmap(client, &namespace, &configmap_name, data).await { + Ok(_) => { + debug!("ConfigMap data applied successfully to namespace '{}'", namespace); + } + Err(e) => { + error!("Failed to apply ConfigMap in namespace '{}': {:?}", namespace, e); + return Err(Action::requeue(std::time::Duration::from_secs(300))); + } + } + } + Err(e) => { + println!( + "Failed to get ConfigMap from '{}' namespace: {:?}", + &custom_metrics_namespace, e + ); + return Err(Action::requeue(std::time::Duration::from_secs(300))); + } + } + + Ok(()) +} + +pub fn custom_metrics_configmap_settings() -> Option<(String, String)> { + let custom_metrics_namespace = match std::env::var("CUSTOM_METRICS_CONFIGMAP_NAMESPACE") { + Ok(namespace) => namespace, + Err(_) => { + debug!("CUSTOM_METRICS_CONFIGMAP_NAMESPACE not set, skipping adding custom metrics"); + return None; + } + }; + let custom_metrics_name = match std::env::var("CUSTOM_METRICS_CONFIGMAP_NAME") { + Ok(name) => name, + Err(_) => { + debug!("CUSTOM_METRICS_CONFIGMAP_NAME not set, skipping adding custom metrics"); + return None; + } + }; + Some((custom_metrics_namespace, custom_metrics_name)) +} pub async fn apply_configmap( client: Client, diff --git a/tembo-operator/src/controller.rs b/tembo-operator/src/controller.rs index 8893d9fe4..42828ac0e 100644 --- a/tembo-operator/src/controller.rs +++ b/tembo-operator/src/controller.rs @@ -39,6 +39,7 @@ use kube::{ use crate::{ apis::postgres_parameters::PgConfig, + configmap::reconcile_generic_metrics_configmap, extensions::{database_queries::list_config_params, reconcile_extensions}, ingress::{reconcile_extra_postgres_ing_route_tcp, reconcile_ip_allowlist_middleware}, network_policies::reconcile_network_policies, @@ -262,7 +263,9 @@ impl CoreDB { Action::requeue(Duration::from_secs(300)) })?; - // Deploy cluster + + reconcile_generic_metrics_configmap(self, ctx.clone()).await?; + reconcile_cnpg(self, ctx.clone()).await?; if cfg.enable_backup { reconcile_cnpg_scheduled_backup(self, ctx.clone()).await?;