1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
use crate::{apis::coredb_types::CoreDB, Context, Error};
use k8s_openapi::api::core::v1::ConfigMap;
use kube::{
    api::{Api, ObjectMeta, Patch, PatchParams},
    runtime::controller::Action,
    Client, ResourceExt,
};
use std::{collections::BTreeMap, sync::Arc};

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<Context>,
) -> 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<ConfigMap> =
        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,
    namespace: &str,
    cm_name: &str,
    data: BTreeMap<String, String>,
) -> Result<(), Error> {
    let mut labels: BTreeMap<String, String> = BTreeMap::new();
    labels.insert("cnpg.io/reload".to_owned(), "true".to_owned());
    let cm_api: Api<ConfigMap> = Api::namespaced(client, namespace);
    let cm = ConfigMap {
        metadata: ObjectMeta {
            name: Some(cm_name.to_string()),
            labels: Some(labels),
            ..Default::default()
        },
        data: Some(data),
        ..Default::default()
    };

    let patch_params = PatchParams::apply("cntrlr");
    let patch = Patch::Apply(&cm);

    match cm_api.patch(cm_name, &patch_params, &patch).await {
        Ok(o) => {
            debug!("Set configmap: {}", o.metadata.name.unwrap());
        }
        Err(e) => {
            error!("Failed to set configmap: {}", e);
        }
    };
    Ok(())
}