From f37a8e373aa602d43971a10a3815c75351ec336d Mon Sep 17 00:00:00 2001 From: wjro Date: Thu, 22 Jan 2026 15:56:17 -0500 Subject: [PATCH 1/2] fix: modified cert-manager ensure ready to check for existence of pods with labels matching cert-manager in kubernetes env. replaced deprecated olm subscription based install of cert-manager for supported helm-chart --- harmony/src/domain/topology/k8s.rs | 22 +++++++ .../topology/k8s_anywhere/k8s_anywhere.rs | 26 ++++---- harmony/src/modules/cert_manager/operator.rs | 66 +++++++++++++------ 3 files changed, 82 insertions(+), 32 deletions(-) diff --git a/harmony/src/domain/topology/k8s.rs b/harmony/src/domain/topology/k8s.rs index ef34f3cf..45e69e5e 100644 --- a/harmony/src/domain/topology/k8s.rs +++ b/harmony/src/domain/topology/k8s.rs @@ -925,6 +925,28 @@ impl K8sClient { api.get_opt(name).await } + pub async fn list_all_with_labels(&self, labels: &str) -> Result, Error> + where + K: Resource + Clone + std::fmt::Debug + DeserializeOwned, + ::DynamicType: Default, + { + let api: Api = Api::all(self.client.clone()); + + let lp = ListParams::default().labels(labels); + Ok(api.list(&lp).await?.items) + } + + /// Gets all resources of type K accross all namespaces + pub async fn get_all_resource(&self) -> Result, Error> + where + K: Resource + Clone + std::fmt::Debug + DeserializeOwned, + ::Scope: ApplyStrategy, + ::DynamicType: Default, + { + let api: Api = Api::all(self.client.clone()); + Ok(api.list(&Default::default()).await?.items) + } + /// Lists all resources of a specific type `K`. /// /// This function uses the `ApplyStrategy` trait to correctly determine diff --git a/harmony/src/domain/topology/k8s_anywhere/k8s_anywhere.rs b/harmony/src/domain/topology/k8s_anywhere/k8s_anywhere.rs index fe232552..a3d18b46 100644 --- a/harmony/src/domain/topology/k8s_anywhere/k8s_anywhere.rs +++ b/harmony/src/domain/topology/k8s_anywhere/k8s_anywhere.rs @@ -4,7 +4,7 @@ use async_trait::async_trait; use base64::{Engine, engine::general_purpose}; use harmony_types::rfc1123::Rfc1123Name; use k8s_openapi::api::{ - core::v1::Secret, + core::v1::{Pod, Secret}, rbac::v1::{ClusterRoleBinding, RoleRef, Subject}, }; use kube::api::{DynamicObject, GroupVersionKind, ObjectMeta}; @@ -376,7 +376,6 @@ impl Serialize for K8sAnywhereTopology { impl CertificateManagement for K8sAnywhereTopology { async fn install(&self) -> Result { let cert_management_operator = CertManagerOperatorScore::default(); - cert_management_operator .interpret(&Inventory::empty(), self) .await @@ -390,17 +389,20 @@ impl CertificateManagement for K8sAnywhereTopology { async fn ensure_ready(&self) -> Result { let k8s_client = self.k8s_client().await.unwrap(); - - match k8s_client - .get_resource::("cert-manager", Some("openshift-operators")) + let pods = k8s_client + .list_all_with_labels::( + "app.kubernetes.io/component=controller,\ + app.kubernetes.io/name=cert-manager", + ) .await - .map_err(|e| ExecutorError::UnexpectedError(format!("{}", e)))? - { - Some(subscription) => { - trace!("subscription {:#?}", subscription,); - Ok(Outcome::success(format!("Certificate Management Ready",))) - } - None => self.install().await, + .map_err(|e| ExecutorError::UnexpectedError(format!("{}", e)))?; + + if pods.is_empty() { + trace!("cert-manager not installed (no controller pods found)"); + self.install().await + } else { + trace!("cert-manager controller pods found: {:#?}", pods); + Ok(Outcome::success("Certificate Management Ready".to_string())) } } diff --git a/harmony/src/modules/cert_manager/operator.rs b/harmony/src/modules/cert_manager/operator.rs index e4112db2..34807dea 100644 --- a/harmony/src/modules/cert_manager/operator.rs +++ b/harmony/src/modules/cert_manager/operator.rs @@ -1,14 +1,20 @@ +use std::{collections::HashMap, str::FromStr}; + use kube::api::ObjectMeta; +use non_blank_string_rs::NonBlankString; use serde::Serialize; use crate::{ interpret::Interpret, - modules::k8s::{ - apps::crd::{Subscription, SubscriptionSpec}, - resource::K8sResourceScore, + modules::{ + helm::chart::HelmChartScore, + k8s::{ + apps::crd::{Subscription, SubscriptionSpec}, + resource::K8sResourceScore, + }, }, score::Score, - topology::{K8sclient, Topology, k8s::K8sClient}, + topology::{HelmCommand, K8sclient, Topology, k8s::K8sClient}, }; /// Install the Cert-Manager Operator via RedHat Community Operators registry.redhat.io/redhat/community-operator-index:v4.19 @@ -35,30 +41,50 @@ impl Default for CertManagerOperatorScore { } } -impl Score for CertManagerOperatorScore { +impl Score for CertManagerOperatorScore { fn name(&self) -> String { "CertManagerOperatorScore".to_string() } fn create_interpret(&self) -> Box> { - let metadata = ObjectMeta { - name: Some("cert-manager".to_string()), - namespace: Some(self.namespace.clone()), - ..ObjectMeta::default() + let cert_manager_score = HelmChartScore { + namespace: Some(NonBlankString::from_str(&self.namespace.as_str()).unwrap()), + release_name: NonBlankString::from_str("cert-manager").unwrap(), + chart_name: NonBlankString::from_str("oci://quay.io/jetstack/charts/cert-manager") + .unwrap(), + chart_version: None, + values_overrides: Some(HashMap::from([( + NonBlankString::from_str("installCRDs").unwrap(), + "true".to_string(), + )])), + values_yaml: None, + create_namespace: true, + install_only: true, + repository: None, }; - let spec = SubscriptionSpec { - channel: Some(self.channel.clone()), - config: None, - install_plan_approval: Some(self.install_plan_approval.clone()), - name: "cert-manager".to_string(), - source: self.source.clone(), - source_namespace: self.source_namespace.clone(), - starting_csv: None, - }; + let cert_score = cert_manager_score.create_interpret(); - let subscription = Subscription { metadata, spec }; + cert_score - K8sResourceScore::single(subscription, Some(self.namespace.clone())).create_interpret() + // let metadata = ObjectMeta { + // name: Some("cert-manager".to_string()), + // namespace: Some(self.namespace.clone()), + // ..ObjectMeta::default() + // }; + // + // let spec = SubscriptionSpec { + // channel: Some(self.channel.clone()), + // config: None, + // install_plan_approval: Some(self.install_plan_approval.clone()), + // name: "cert-manager".to_string(), + // source: self.source.clone(), + // source_namespace: self.source_namespace.clone(), + // starting_csv: None, + // }; + // + // let subscription = Subscription { metadata, spec }; + // + // K8sResourceScore::single(subscription, Some(self.namespace.clone())).create_interpret() } } -- 2.39.5 From d0cd21c322498b2bb00d34bc9bbbffe3abc20380 Mon Sep 17 00:00:00 2001 From: wjro Date: Fri, 23 Jan 2026 11:26:35 -0500 Subject: [PATCH 2/2] fix: improved logging and function names for clarity --- harmony/src/domain/topology/k8s.rs | 5 ++- .../topology/k8s_anywhere/k8s_anywhere.rs | 10 +++--- harmony/src/modules/cert_manager/operator.rs | 35 +++---------------- 3 files changed, 10 insertions(+), 40 deletions(-) diff --git a/harmony/src/domain/topology/k8s.rs b/harmony/src/domain/topology/k8s.rs index 45e69e5e..f4595ee4 100644 --- a/harmony/src/domain/topology/k8s.rs +++ b/harmony/src/domain/topology/k8s.rs @@ -925,7 +925,7 @@ impl K8sClient { api.get_opt(name).await } - pub async fn list_all_with_labels(&self, labels: &str) -> Result, Error> + pub async fn list_all_resources_with_labels(&self, labels: &str) -> Result, Error> where K: Resource + Clone + std::fmt::Debug + DeserializeOwned, ::DynamicType: Default, @@ -936,8 +936,7 @@ impl K8sClient { Ok(api.list(&lp).await?.items) } - /// Gets all resources of type K accross all namespaces - pub async fn get_all_resource(&self) -> Result, Error> + pub async fn get_all_resource_in_all_namespace(&self) -> Result, Error> where K: Resource + Clone + std::fmt::Debug + DeserializeOwned, ::Scope: ApplyStrategy, diff --git a/harmony/src/domain/topology/k8s_anywhere/k8s_anywhere.rs b/harmony/src/domain/topology/k8s_anywhere/k8s_anywhere.rs index a3d18b46..e887f7b6 100644 --- a/harmony/src/domain/topology/k8s_anywhere/k8s_anywhere.rs +++ b/harmony/src/domain/topology/k8s_anywhere/k8s_anywhere.rs @@ -28,10 +28,7 @@ use crate::{ score_cert_management::CertificateManagementScore, }, k3d::K3DInstallationScore, - k8s::{ - apps::crd::Subscription, - ingress::{K8sIngressScore, PathType}, - }, + k8s::ingress::{K8sIngressScore, PathType}, monitoring::{ grafana::{grafana::Grafana, helm::helm_grafana::grafana_helm_chart_score}, kube_prometheus::crd::{ @@ -390,7 +387,7 @@ impl CertificateManagement for K8sAnywhereTopology { async fn ensure_ready(&self) -> Result { let k8s_client = self.k8s_client().await.unwrap(); let pods = k8s_client - .list_all_with_labels::( + .list_all_resources_with_labels::( "app.kubernetes.io/component=controller,\ app.kubernetes.io/name=cert-manager", ) @@ -398,10 +395,11 @@ impl CertificateManagement for K8sAnywhereTopology { .map_err(|e| ExecutorError::UnexpectedError(format!("{}", e)))?; if pods.is_empty() { - trace!("cert-manager not installed (no controller pods found)"); + info!("cert-manager not installed (no controller pods found)"); self.install().await } else { trace!("cert-manager controller pods found: {:#?}", pods); + info!("cert-manager controller pods found"); Ok(Outcome::success("Certificate Management Ready".to_string())) } } diff --git a/harmony/src/modules/cert_manager/operator.rs b/harmony/src/modules/cert_manager/operator.rs index 34807dea..f6e9c22f 100644 --- a/harmony/src/modules/cert_manager/operator.rs +++ b/harmony/src/modules/cert_manager/operator.rs @@ -1,24 +1,17 @@ use std::{collections::HashMap, str::FromStr}; -use kube::api::ObjectMeta; use non_blank_string_rs::NonBlankString; use serde::Serialize; use crate::{ interpret::Interpret, - modules::{ - helm::chart::HelmChartScore, - k8s::{ - apps::crd::{Subscription, SubscriptionSpec}, - resource::K8sResourceScore, - }, - }, + modules::helm::chart::HelmChartScore, score::Score, - topology::{HelmCommand, K8sclient, Topology, k8s::K8sClient}, + topology::{HelmCommand, K8sclient, Topology}, }; -/// Install the Cert-Manager Operator via RedHat Community Operators registry.redhat.io/redhat/community-operator-index:v4.19 -/// This Score creates a Subscription CR in the specified namespace +/// Install the Cert-Manager Operator via helm chart +/// This Score installs the cert-manager CRs in the specified namespace #[derive(Debug, Clone, Serialize)] pub struct CertManagerOperatorScore { @@ -66,25 +59,5 @@ impl Score for CertManagerOp let cert_score = cert_manager_score.create_interpret(); cert_score - - // let metadata = ObjectMeta { - // name: Some("cert-manager".to_string()), - // namespace: Some(self.namespace.clone()), - // ..ObjectMeta::default() - // }; - // - // let spec = SubscriptionSpec { - // channel: Some(self.channel.clone()), - // config: None, - // install_plan_approval: Some(self.install_plan_approval.clone()), - // name: "cert-manager".to_string(), - // source: self.source.clone(), - // source_namespace: self.source_namespace.clone(), - // starting_csv: None, - // }; - // - // let subscription = Subscription { metadata, spec }; - // - // K8sResourceScore::single(subscription, Some(self.namespace.clone())).create_interpret() } } -- 2.39.5