diff --git a/examples/cert_manager/src/main.rs b/examples/cert_manager/src/main.rs index ee0a203..df6484e 100644 --- a/examples/cert_manager/src/main.rs +++ b/examples/cert_manager/src/main.rs @@ -12,7 +12,13 @@ use harmony::{ #[tokio::main] async fn main() { let cert_manager = CertificateManagementScore { - config: CertificateManagementConfig {}, + config: CertificateManagementConfig { + name: todo!(), + namespace: todo!(), + acme_issuer: todo!(), + ca_issuer: todo!(), + self_signed: todo!(), + }, }; harmony_cli::run( diff --git a/harmony/src/domain/topology/k8s_anywhere/k8s_anywhere.rs b/harmony/src/domain/topology/k8s_anywhere/k8s_anywhere.rs index c259eff..ca99847 100644 --- a/harmony/src/domain/topology/k8s_anywhere/k8s_anywhere.rs +++ b/harmony/src/domain/topology/k8s_anywhere/k8s_anywhere.rs @@ -18,7 +18,8 @@ use crate::{ inventory::Inventory, modules::{ cert_manager::{ - capability::{CertificateManagement, CertificateManagementConfig}, + capability::{CertificateManagement, CertificateManagementConfig, Issuer}, + crd::{score_certificate::CertificateScore, score_issuer::IssuerScore}, operator::CertManagerOperatorScore, }, k3d::K3DInstallationScore, @@ -382,6 +383,38 @@ impl CertificateManagement for K8sAnywhereTopology { ), }) } + + async fn ensure_ready( + &self, + config: &CertificateManagementConfig, + ) -> Result { + self.certificate_issuer_ready(Issuer::Issuer, config) + .await?; + Ok(PreparationOutcome::Success { + details: "issuer ready".to_string(), + }) + } + + async fn create_certificate( + &self, + cert_name: String, + config: &CertificateManagementConfig, + ) -> Result { + let cert = CertificateScore { + name: cert_name, + config: config.clone(), + }; + cert.interpret(&Inventory::empty(), self) + .await + .map_err(|e| PreparationError { msg: e.to_string() })?; + + Ok(PreparationOutcome::Success { + details: format!( + "Created cert into ns: {:#?}", + config.namespace.clone() + ), + }) + } } impl K8sAnywhereTopology { @@ -935,6 +968,29 @@ impl K8sAnywhereTopology { ), }) } + + async fn certificate_issuer_ready( + &self, + issuer: Issuer, + config: &CertificateManagementConfig, + ) -> Result { + match issuer { + Issuer::ClusterIssuer => todo!(), + + Issuer::Issuer => { + let issuer_score = IssuerScore { + config: config.clone(), + }; + issuer_score + .interpret(&Inventory::empty(), self) + .await + .map_err(|e| PreparationError { msg: e.to_string() })?; + Ok(PreparationOutcome::Success { + details: format!("issuer of kind {} is ready", issuer.to_string()), + }) + } + } + } } #[derive(Clone, Debug)] diff --git a/harmony/src/modules/cert_manager/capability.rs b/harmony/src/modules/cert_manager/capability.rs index fffe537..bd0c921 100644 --- a/harmony/src/modules/cert_manager/capability.rs +++ b/harmony/src/modules/cert_manager/capability.rs @@ -1,10 +1,7 @@ use async_trait::async_trait; use serde::Serialize; -use crate::{ - interpret::Outcome, - topology::{PreparationError, PreparationOutcome}, -}; +use crate::{modules::cert_manager::crd::{AcmeIssuer, CaIssuer}, topology::{PreparationError, PreparationOutcome}}; #[async_trait] pub trait CertificateManagement: Send + Sync { @@ -12,7 +9,40 @@ pub trait CertificateManagement: Send + Sync { &self, config: &CertificateManagementConfig, ) -> Result; + + async fn ensure_ready( + &self, + config: &CertificateManagementConfig, + ) -> Result; + + async fn create_certificate( + &self, + cert_name: String, + config: &CertificateManagementConfig, + ) -> Result; } #[derive(Debug, Clone, Serialize)] -pub struct CertificateManagementConfig {} +pub struct CertificateManagementConfig { + pub name: String, + pub namespace: Option, + pub acme_issuer: Option, + pub ca_issuer: Option, + pub self_signed: bool, +} + +#[derive(Serialize)] +pub enum Issuer { + ClusterIssuer, + Issuer, +} + +impl std::fmt::Display for Issuer { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Issuer::Issuer => f.write_str("Issuer"), + Issuer::ClusterIssuer => f.write_str("ClusterIssuer"), + } + } +} + diff --git a/harmony/src/modules/cert_manager/crd/mod.rs b/harmony/src/modules/cert_manager/crd/mod.rs index c9050b7..70ea469 100644 --- a/harmony/src/modules/cert_manager/crd/mod.rs +++ b/harmony/src/modules/cert_manager/crd/mod.rs @@ -4,6 +4,9 @@ use serde::{Deserialize, Serialize}; pub mod certificate; pub mod issuer; pub mod cluster_issuer; +//pub mod score_cluster_issuer; +pub mod score_issuer; +pub mod score_certificate; #[derive(Deserialize, Serialize, Clone, Debug)] #[serde(rename_all = "camelCase")] diff --git a/harmony/src/modules/cert_manager/crd/score_certificate.rs b/harmony/src/modules/cert_manager/crd/score_certificate.rs new file mode 100644 index 0000000..53c2a34 --- /dev/null +++ b/harmony/src/modules/cert_manager/crd/score_certificate.rs @@ -0,0 +1,47 @@ +use kube::api::ObjectMeta; +use serde::Serialize; + +use crate::{ + interpret::Interpret, + modules::{ + cert_manager::{ + capability::CertificateManagementConfig, + crd::certificate::{Certificate, CertificateSpec, IssuerRef}, + }, + k8s::resource::K8sResourceScore, + }, + score::Score, + topology::{K8sclient, Topology}, +}; + +#[derive(Debug, Clone, Serialize)] +pub struct CertificateScore { + pub name: String, + pub config: CertificateManagementConfig, +} + +impl Score for CertificateScore { + fn name(&self) -> String { + "CertificateScore".to_string() + } + + fn create_interpret(&self) -> Box> { + let cert = Certificate { + metadata: ObjectMeta { + name: Some(self.name.clone()), + namespace: self.config.namespace.clone(), + ..Default::default() + }, + spec: CertificateSpec { + secret_name: format!("{}-tls", self.name.clone()), + issuer_ref: IssuerRef { + name: self.config.name.clone(), + kind: Some("Issuer".into()), + group: Some("cert-manager.io".into()), + }, + ..Default::default() + }, + }; + K8sResourceScore::single(cert, self.config.namespace.clone()).create_interpret() + } +} diff --git a/harmony/src/modules/cert_manager/crd/score_cluster_issuer.rs b/harmony/src/modules/cert_manager/crd/score_cluster_issuer.rs new file mode 100644 index 0000000..5437fc7 --- /dev/null +++ b/harmony/src/modules/cert_manager/crd/score_cluster_issuer.rs @@ -0,0 +1,51 @@ +use kube::api::ObjectMeta; +use serde::Serialize; + +use crate::{ + interpret::Interpret, + modules::{ + cert_manager::crd::{ + AcmeIssuer, CaIssuer, SelfSignedIssuer, + cluster_issuer::{ClusterIssuer, ClusterIssuerSpec}, + }, + k8s::resource::K8sResourceScore, + }, + score::Score, + topology::{K8sclient, Topology}, +}; + +#[derive(Debug, Clone, Serialize)] +pub struct ClusterIssuerScore { + name: String, + acme_issuer: Option, + ca_issuer: Option, + self_signed: bool, +} + +impl Score for ClusterIssuerScore { + fn name(&self) -> String { + "ClusterIssuerScore".to_string() + } + + fn create_interpret(&self) -> Box> { + let metadata = ObjectMeta { + name: Some(self.name.clone()), + namespace: None, + ..ObjectMeta::default() + }; + + let spec = ClusterIssuerSpec { + acme: self.acme_issuer.clone(), + ca: self.ca_issuer.clone(), + self_signed: if self.self_signed { + Some(SelfSignedIssuer::default()) + } else { + None + }, + }; + + let cluster_issuer = ClusterIssuer { metadata, spec }; + + K8sResourceScore::single(cluster_issuer, None).create_interpret() + } +} diff --git a/harmony/src/modules/cert_manager/crd/score_issuer.rs b/harmony/src/modules/cert_manager/crd/score_issuer.rs new file mode 100644 index 0000000..05af62d --- /dev/null +++ b/harmony/src/modules/cert_manager/crd/score_issuer.rs @@ -0,0 +1,48 @@ +use kube::api::ObjectMeta; +use serde::Serialize; + +use crate::{ + interpret::Interpret, + modules::{ + cert_manager::{capability::CertificateManagementConfig, crd::{ + AcmeIssuer, CaIssuer, SelfSignedIssuer, + issuer::{Issuer, IssuerSpec}, + }}, + k8s::resource::K8sResourceScore, + }, + score::Score, + topology::{K8sclient, Topology}, +}; + +#[derive(Debug, Clone, Serialize)] +pub struct IssuerScore { + pub config: CertificateManagementConfig, +} + +impl Score for IssuerScore { + fn name(&self) -> String { + "IssuerScore".to_string() + } + + fn create_interpret(&self) -> Box> { + let metadata = ObjectMeta { + name: Some(self.config.name.clone()), + namespace: self.config.namespace.clone(), + ..ObjectMeta::default() + }; + + let spec = IssuerSpec { + acme: self.config.acme_issuer.clone(), + ca: self.config.ca_issuer.clone(), + self_signed: if self.config.self_signed { + Some(SelfSignedIssuer::default()) + } else { + None + }, + }; + + let issuer = Issuer { metadata, spec }; + + K8sResourceScore::single(issuer, self.config.namespace.clone()).create_interpret() + } +}