feat: added working examples to add self signed issuer and self signed certificate. modified get_resource_json_value to be able to get cluster scoped operators
This commit is contained in:
@@ -2,7 +2,9 @@ use harmony::{
|
||||
inventory::Inventory,
|
||||
modules::{
|
||||
cert_manager::{
|
||||
capability::CertificateManagementConfig, score_k8s::CertificateManagementScore,
|
||||
capability::CertificateManagementConfig, score_create_cert::CertificateCreationScore,
|
||||
score_create_issuer::CertificateIssuerScore,
|
||||
score_operator::CertificateManagementScore,
|
||||
},
|
||||
postgresql::{PostgreSQLScore, capability::PostgreSQLConfig},
|
||||
},
|
||||
@@ -11,20 +13,32 @@ use harmony::{
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() {
|
||||
let config = CertificateManagementConfig {
|
||||
namespace: Some("test".to_string()),
|
||||
acme_issuer: None,
|
||||
ca_issuer: None,
|
||||
self_signed: true,
|
||||
};
|
||||
|
||||
let cert_manager = CertificateManagementScore {
|
||||
config: CertificateManagementConfig {
|
||||
name: todo!(),
|
||||
namespace: todo!(),
|
||||
acme_issuer: todo!(),
|
||||
ca_issuer: todo!(),
|
||||
self_signed: todo!(),
|
||||
},
|
||||
config: config.clone(),
|
||||
};
|
||||
|
||||
let issuer = CertificateIssuerScore {
|
||||
config: config.clone(),
|
||||
issuer_name: "test-self-signed-issuer".to_string(),
|
||||
};
|
||||
|
||||
let cert = CertificateCreationScore {
|
||||
config: config.clone(),
|
||||
cert_name: "test-self-signed-cert".to_string(),
|
||||
issuer_name: "test-self-signed-issuer".to_string(),
|
||||
};
|
||||
|
||||
harmony_cli::run(
|
||||
Inventory::autoload(),
|
||||
K8sAnywhereTopology::from_env(),
|
||||
vec![Box::new(cert_manager)],
|
||||
vec![Box::new(cert_manager), Box::new(issuer), Box::new(cert)],
|
||||
None,
|
||||
)
|
||||
.await
|
||||
|
||||
@@ -230,14 +230,26 @@ impl K8sClient {
|
||||
namespace: Option<&str>,
|
||||
gvk: &GroupVersionKind,
|
||||
) -> Result<DynamicObject, Error> {
|
||||
let gvk = ApiResource::from_gvk(gvk);
|
||||
let resource: Api<DynamicObject> = if let Some(ns) = namespace {
|
||||
Api::namespaced_with(self.client.clone(), ns, &gvk)
|
||||
} else {
|
||||
Api::default_namespaced_with(self.client.clone(), &gvk)
|
||||
};
|
||||
let api_resource = ApiResource::from_gvk(gvk);
|
||||
|
||||
resource.get(name).await
|
||||
// 1. Try namespaced first (if a namespace was provided)
|
||||
if let Some(ns) = namespace {
|
||||
let api: Api<DynamicObject> =
|
||||
Api::namespaced_with(self.client.clone(), ns, &api_resource);
|
||||
|
||||
match api.get(name).await {
|
||||
Ok(obj) => return Ok(obj),
|
||||
Err(Error::Api(ae)) if ae.code == 404 => {
|
||||
// fall through and try cluster-scoped
|
||||
}
|
||||
Err(e) => return Err(e),
|
||||
}
|
||||
}
|
||||
|
||||
// 2. Fallback to cluster-scoped
|
||||
let api: Api<DynamicObject> = Api::all_with(self.client.clone(), &api_resource);
|
||||
|
||||
api.get(name).await
|
||||
}
|
||||
|
||||
pub async fn get_secret_json_value(
|
||||
|
||||
@@ -366,10 +366,7 @@ impl Serialize for K8sAnywhereTopology {
|
||||
|
||||
#[async_trait]
|
||||
impl CertificateManagement for K8sAnywhereTopology {
|
||||
async fn install(
|
||||
&self,
|
||||
config: &CertificateManagementConfig,
|
||||
) -> Result<PreparationOutcome, PreparationError> {
|
||||
async fn install(&self) -> Result<PreparationOutcome, PreparationError> {
|
||||
let cert_management_operator = CertManagerOperatorScore::default();
|
||||
|
||||
cert_management_operator
|
||||
@@ -385,11 +382,33 @@ impl CertificateManagement for K8sAnywhereTopology {
|
||||
})
|
||||
}
|
||||
|
||||
async fn ensure_ready(
|
||||
async fn ensure_certificate_management_ready(
|
||||
&self,
|
||||
config: &CertificateManagementConfig,
|
||||
) -> Result<PreparationOutcome, PreparationError> {
|
||||
todo!()
|
||||
let k8s_client = self.k8s_client().await.unwrap();
|
||||
let gvk = GroupVersionKind {
|
||||
group: "operators.coreos.com".to_string(),
|
||||
version: "v1".to_string(),
|
||||
kind: "Operator".to_string(),
|
||||
};
|
||||
//TODO make this generic across k8s distributions using k8s family
|
||||
match k8s_client
|
||||
.get_resource_json_value(
|
||||
"cert-manager.openshift-operators",
|
||||
None,
|
||||
&gvk,
|
||||
)
|
||||
.await
|
||||
{
|
||||
Ok(_ready) => Ok(PreparationOutcome::Success {
|
||||
details: "Certificate Management Ready".to_string(),
|
||||
}),
|
||||
Err(e) => {
|
||||
debug!("{} operator not found", e.to_string());
|
||||
self.install().await
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async fn create_issuer(
|
||||
@@ -398,6 +417,7 @@ impl CertificateManagement for K8sAnywhereTopology {
|
||||
config: &CertificateManagementConfig,
|
||||
) -> Result<PreparationOutcome, PreparationError> {
|
||||
let issuer_score = IssuerScore {
|
||||
issuer_name: issuer_name.clone(),
|
||||
config: config.clone(),
|
||||
};
|
||||
|
||||
|
||||
@@ -11,10 +11,9 @@ use crate::{
|
||||
pub trait CertificateManagement: Send + Sync {
|
||||
async fn install(
|
||||
&self,
|
||||
config: &CertificateManagementConfig,
|
||||
) -> Result<PreparationOutcome, PreparationError>;
|
||||
|
||||
async fn ensure_ready(
|
||||
async fn ensure_certificate_management_ready(
|
||||
&self,
|
||||
config: &CertificateManagementConfig,
|
||||
) -> Result<PreparationOutcome, PreparationError>;
|
||||
@@ -35,7 +34,6 @@ pub trait CertificateManagement: Send + Sync {
|
||||
|
||||
#[derive(Debug, Clone, Serialize)]
|
||||
pub struct CertificateManagementConfig {
|
||||
pub name: String,
|
||||
pub namespace: Option<String>,
|
||||
pub acme_issuer: Option<AcmeIssuer>,
|
||||
pub ca_issuer: Option<CaIssuer>,
|
||||
|
||||
@@ -40,6 +40,7 @@ impl<T: Topology + K8sclient> Score<T> for CertificateScore {
|
||||
kind: Some("Issuer".into()),
|
||||
group: Some("cert-manager.io".into()),
|
||||
},
|
||||
dns_names: Some(vec!["test.example.local".to_string()]),
|
||||
..Default::default()
|
||||
},
|
||||
};
|
||||
|
||||
@@ -19,6 +19,7 @@ use crate::{
|
||||
|
||||
#[derive(Debug, Clone, Serialize)]
|
||||
pub struct IssuerScore {
|
||||
pub issuer_name: String,
|
||||
pub config: CertificateManagementConfig,
|
||||
}
|
||||
|
||||
@@ -29,7 +30,7 @@ impl<T: Topology + K8sclient> Score<T> for IssuerScore {
|
||||
|
||||
fn create_interpret(&self) -> Box<dyn Interpret<T>> {
|
||||
let metadata = ObjectMeta {
|
||||
name: Some(format!("{}-issuer", self.config.namespace.clone().unwrap())),
|
||||
name: Some(self.issuer_name.clone()),
|
||||
namespace: self.config.namespace.clone(),
|
||||
..ObjectMeta::default()
|
||||
};
|
||||
|
||||
@@ -3,5 +3,7 @@ pub mod cluster_issuer;
|
||||
pub mod crd;
|
||||
mod helm;
|
||||
pub mod operator;
|
||||
pub mod score_k8s;
|
||||
pub mod score_operator;
|
||||
pub mod score_create_cert;
|
||||
pub mod score_create_issuer;
|
||||
pub use helm::*;
|
||||
|
||||
72
harmony/src/modules/cert_manager/score_create_cert.rs
Normal file
72
harmony/src/modules/cert_manager/score_create_cert.rs
Normal file
@@ -0,0 +1,72 @@
|
||||
use async_trait::async_trait;
|
||||
use harmony_types::id::Id;
|
||||
use serde::Serialize;
|
||||
|
||||
use crate::{
|
||||
data::Version,
|
||||
interpret::{Interpret, InterpretError, InterpretName, InterpretStatus, Outcome},
|
||||
inventory::Inventory,
|
||||
modules::cert_manager::capability::{CertificateManagement, CertificateManagementConfig},
|
||||
score::Score,
|
||||
topology::Topology,
|
||||
};
|
||||
|
||||
#[derive(Debug, Clone, Serialize)]
|
||||
pub struct CertificateCreationScore {
|
||||
pub cert_name: String,
|
||||
pub issuer_name: String,
|
||||
pub config: CertificateManagementConfig,
|
||||
}
|
||||
|
||||
impl<T: Topology + CertificateManagement> Score<T> for CertificateCreationScore {
|
||||
fn name(&self) -> String {
|
||||
"CertificateCreationScore".to_string()
|
||||
}
|
||||
|
||||
fn create_interpret(&self) -> Box<dyn Interpret<T>> {
|
||||
Box::new(CertificateCreationInterpret {
|
||||
cert_name: self.cert_name.clone(),
|
||||
issuer_name: self.issuer_name.clone(),
|
||||
config: self.config.clone(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct CertificateCreationInterpret {
|
||||
cert_name: String,
|
||||
issuer_name: String,
|
||||
config: CertificateManagementConfig,
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl<T: Topology + CertificateManagement> Interpret<T> for CertificateCreationInterpret {
|
||||
async fn execute(
|
||||
&self,
|
||||
inventory: &Inventory,
|
||||
topology: &T,
|
||||
) -> Result<Outcome, InterpretError> {
|
||||
let _certificate = topology
|
||||
.create_certificate(self.cert_name.clone(), self.issuer_name.clone(), &self.config)
|
||||
.await
|
||||
.map_err(|e| InterpretError::new(e.to_string()))?;
|
||||
|
||||
Ok(Outcome::success(format!("Installed CertificateManagement")))
|
||||
}
|
||||
|
||||
fn get_name(&self) -> InterpretName {
|
||||
InterpretName::Custom("CertificateManagementInterpret")
|
||||
}
|
||||
|
||||
fn get_version(&self) -> Version {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn get_status(&self) -> InterpretStatus {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn get_children(&self) -> Vec<Id> {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
66
harmony/src/modules/cert_manager/score_create_issuer.rs
Normal file
66
harmony/src/modules/cert_manager/score_create_issuer.rs
Normal file
@@ -0,0 +1,66 @@
|
||||
use async_trait::async_trait;
|
||||
use harmony_types::id::Id;
|
||||
use log::debug;
|
||||
use serde::Serialize;
|
||||
|
||||
use crate::{data::Version, interpret::{Interpret, InterpretError, InterpretName, InterpretStatus, Outcome}, inventory::Inventory, modules::cert_manager::capability::{CertificateManagement, CertificateManagementConfig}, score::Score, topology::Topology};
|
||||
|
||||
|
||||
|
||||
#[derive(Debug, Clone, Serialize)]
|
||||
pub struct CertificateIssuerScore {
|
||||
pub issuer_name: String,
|
||||
pub config: CertificateManagementConfig,
|
||||
}
|
||||
|
||||
impl<T: Topology + CertificateManagement> Score<T> for CertificateIssuerScore {
|
||||
fn name(&self) -> String {
|
||||
"CertificateIssuerScore".to_string()
|
||||
}
|
||||
|
||||
fn create_interpret(&self) -> Box<dyn Interpret<T>> {
|
||||
Box::new(CertificateIssuerInterpret {
|
||||
config: self.config.clone(),
|
||||
issuer_name: self.issuer_name.clone(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct CertificateIssuerInterpret {
|
||||
config: CertificateManagementConfig,
|
||||
issuer_name: String,
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl<T: Topology + CertificateManagement> Interpret<T> for CertificateIssuerInterpret {
|
||||
async fn execute(
|
||||
&self,
|
||||
inventory: &Inventory,
|
||||
topology: &T,
|
||||
) -> Result<Outcome, InterpretError> {
|
||||
debug!("issuer name: {}", self.issuer_name.clone());
|
||||
let _cert_issuer = topology
|
||||
.create_issuer(self.issuer_name.clone(), &self.config)
|
||||
.await
|
||||
.map_err(|e| InterpretError::new(e.to_string()))?;
|
||||
|
||||
Ok(Outcome::success(format!("Installed CertificateManagement")))
|
||||
}
|
||||
|
||||
fn get_name(&self) -> InterpretName {
|
||||
InterpretName::Custom("CertificateManagementInterpret")
|
||||
}
|
||||
|
||||
fn get_version(&self) -> Version {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn get_status(&self) -> InterpretStatus {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn get_children(&self) -> Vec<Id> {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
@@ -40,12 +40,13 @@ impl<T: Topology + CertificateManagement> Interpret<T> for CertificateManagement
|
||||
inventory: &Inventory,
|
||||
topology: &T,
|
||||
) -> Result<Outcome, InterpretError> {
|
||||
let cert_management = topology
|
||||
.install(&self.config)
|
||||
|
||||
topology
|
||||
.ensure_certificate_management_ready(&self.config)
|
||||
.await
|
||||
.map_err(|e| InterpretError::new(e.to_string()))?;
|
||||
|
||||
Ok(Outcome::success(format!("Installed CertificateManagement")))
|
||||
Ok(Outcome::success(format!("CertificateManagement is ready")))
|
||||
}
|
||||
|
||||
fn get_name(&self) -> InterpretName {
|
||||
Reference in New Issue
Block a user