diff --git a/harmony/src/domain/topology/k8s.rs b/harmony/src/domain/topology/k8s.rs index ef34f3cf..f4595ee4 100644 --- a/harmony/src/domain/topology/k8s.rs +++ b/harmony/src/domain/topology/k8s.rs @@ -925,6 +925,27 @@ impl K8sClient { api.get_opt(name).await } + pub async fn list_all_resources_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) + } + + pub async fn get_all_resource_in_all_namespace(&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..e887f7b6 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}; @@ -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::{ @@ -376,7 +373,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 +386,21 @@ 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_resources_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() { + 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 e4112db2..f6e9c22f 100644 --- a/harmony/src/modules/cert_manager/operator.rs +++ b/harmony/src/modules/cert_manager/operator.rs @@ -1,18 +1,17 @@ -use kube::api::ObjectMeta; +use std::{collections::HashMap, str::FromStr}; + +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, score::Score, - topology::{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 { @@ -35,30 +34,30 @@ 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 }; - - K8sResourceScore::single(subscription, Some(self.namespace.clone())).create_interpret() + cert_score } }