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,
|
inventory::Inventory,
|
||||||
modules::{
|
modules::{
|
||||||
cert_manager::{
|
cert_manager::{
|
||||||
capability::CertificateManagementConfig, score_k8s::CertificateManagementScore,
|
capability::CertificateManagementConfig, score_create_cert::CertificateCreationScore,
|
||||||
|
score_create_issuer::CertificateIssuerScore,
|
||||||
|
score_operator::CertificateManagementScore,
|
||||||
},
|
},
|
||||||
postgresql::{PostgreSQLScore, capability::PostgreSQLConfig},
|
postgresql::{PostgreSQLScore, capability::PostgreSQLConfig},
|
||||||
},
|
},
|
||||||
@@ -11,20 +13,32 @@ use harmony::{
|
|||||||
|
|
||||||
#[tokio::main]
|
#[tokio::main]
|
||||||
async fn 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 {
|
let cert_manager = CertificateManagementScore {
|
||||||
config: CertificateManagementConfig {
|
config: config.clone(),
|
||||||
name: todo!(),
|
};
|
||||||
namespace: todo!(),
|
|
||||||
acme_issuer: todo!(),
|
let issuer = CertificateIssuerScore {
|
||||||
ca_issuer: todo!(),
|
config: config.clone(),
|
||||||
self_signed: todo!(),
|
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(
|
harmony_cli::run(
|
||||||
Inventory::autoload(),
|
Inventory::autoload(),
|
||||||
K8sAnywhereTopology::from_env(),
|
K8sAnywhereTopology::from_env(),
|
||||||
vec![Box::new(cert_manager)],
|
vec![Box::new(cert_manager), Box::new(issuer), Box::new(cert)],
|
||||||
None,
|
None,
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
|
|||||||
@@ -230,14 +230,26 @@ impl K8sClient {
|
|||||||
namespace: Option<&str>,
|
namespace: Option<&str>,
|
||||||
gvk: &GroupVersionKind,
|
gvk: &GroupVersionKind,
|
||||||
) -> Result<DynamicObject, Error> {
|
) -> Result<DynamicObject, Error> {
|
||||||
let gvk = ApiResource::from_gvk(gvk);
|
let api_resource = 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)
|
|
||||||
};
|
|
||||||
|
|
||||||
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(
|
pub async fn get_secret_json_value(
|
||||||
|
|||||||
@@ -366,10 +366,7 @@ impl Serialize for K8sAnywhereTopology {
|
|||||||
|
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
impl CertificateManagement for K8sAnywhereTopology {
|
impl CertificateManagement for K8sAnywhereTopology {
|
||||||
async fn install(
|
async fn install(&self) -> Result<PreparationOutcome, PreparationError> {
|
||||||
&self,
|
|
||||||
config: &CertificateManagementConfig,
|
|
||||||
) -> Result<PreparationOutcome, PreparationError> {
|
|
||||||
let cert_management_operator = CertManagerOperatorScore::default();
|
let cert_management_operator = CertManagerOperatorScore::default();
|
||||||
|
|
||||||
cert_management_operator
|
cert_management_operator
|
||||||
@@ -385,11 +382,33 @@ impl CertificateManagement for K8sAnywhereTopology {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn ensure_ready(
|
async fn ensure_certificate_management_ready(
|
||||||
&self,
|
&self,
|
||||||
config: &CertificateManagementConfig,
|
config: &CertificateManagementConfig,
|
||||||
) -> Result<PreparationOutcome, PreparationError> {
|
) -> 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(
|
async fn create_issuer(
|
||||||
@@ -398,6 +417,7 @@ impl CertificateManagement for K8sAnywhereTopology {
|
|||||||
config: &CertificateManagementConfig,
|
config: &CertificateManagementConfig,
|
||||||
) -> Result<PreparationOutcome, PreparationError> {
|
) -> Result<PreparationOutcome, PreparationError> {
|
||||||
let issuer_score = IssuerScore {
|
let issuer_score = IssuerScore {
|
||||||
|
issuer_name: issuer_name.clone(),
|
||||||
config: config.clone(),
|
config: config.clone(),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -11,10 +11,9 @@ use crate::{
|
|||||||
pub trait CertificateManagement: Send + Sync {
|
pub trait CertificateManagement: Send + Sync {
|
||||||
async fn install(
|
async fn install(
|
||||||
&self,
|
&self,
|
||||||
config: &CertificateManagementConfig,
|
|
||||||
) -> Result<PreparationOutcome, PreparationError>;
|
) -> Result<PreparationOutcome, PreparationError>;
|
||||||
|
|
||||||
async fn ensure_ready(
|
async fn ensure_certificate_management_ready(
|
||||||
&self,
|
&self,
|
||||||
config: &CertificateManagementConfig,
|
config: &CertificateManagementConfig,
|
||||||
) -> Result<PreparationOutcome, PreparationError>;
|
) -> Result<PreparationOutcome, PreparationError>;
|
||||||
@@ -35,7 +34,6 @@ pub trait CertificateManagement: Send + Sync {
|
|||||||
|
|
||||||
#[derive(Debug, Clone, Serialize)]
|
#[derive(Debug, Clone, Serialize)]
|
||||||
pub struct CertificateManagementConfig {
|
pub struct CertificateManagementConfig {
|
||||||
pub name: String,
|
|
||||||
pub namespace: Option<String>,
|
pub namespace: Option<String>,
|
||||||
pub acme_issuer: Option<AcmeIssuer>,
|
pub acme_issuer: Option<AcmeIssuer>,
|
||||||
pub ca_issuer: Option<CaIssuer>,
|
pub ca_issuer: Option<CaIssuer>,
|
||||||
|
|||||||
@@ -40,6 +40,7 @@ impl<T: Topology + K8sclient> Score<T> for CertificateScore {
|
|||||||
kind: Some("Issuer".into()),
|
kind: Some("Issuer".into()),
|
||||||
group: Some("cert-manager.io".into()),
|
group: Some("cert-manager.io".into()),
|
||||||
},
|
},
|
||||||
|
dns_names: Some(vec!["test.example.local".to_string()]),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ use crate::{
|
|||||||
|
|
||||||
#[derive(Debug, Clone, Serialize)]
|
#[derive(Debug, Clone, Serialize)]
|
||||||
pub struct IssuerScore {
|
pub struct IssuerScore {
|
||||||
|
pub issuer_name: String,
|
||||||
pub config: CertificateManagementConfig,
|
pub config: CertificateManagementConfig,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -29,7 +30,7 @@ impl<T: Topology + K8sclient> Score<T> for IssuerScore {
|
|||||||
|
|
||||||
fn create_interpret(&self) -> Box<dyn Interpret<T>> {
|
fn create_interpret(&self) -> Box<dyn Interpret<T>> {
|
||||||
let metadata = ObjectMeta {
|
let metadata = ObjectMeta {
|
||||||
name: Some(format!("{}-issuer", self.config.namespace.clone().unwrap())),
|
name: Some(self.issuer_name.clone()),
|
||||||
namespace: self.config.namespace.clone(),
|
namespace: self.config.namespace.clone(),
|
||||||
..ObjectMeta::default()
|
..ObjectMeta::default()
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -3,5 +3,7 @@ pub mod cluster_issuer;
|
|||||||
pub mod crd;
|
pub mod crd;
|
||||||
mod helm;
|
mod helm;
|
||||||
pub mod operator;
|
pub mod operator;
|
||||||
pub mod score_k8s;
|
pub mod score_operator;
|
||||||
|
pub mod score_create_cert;
|
||||||
|
pub mod score_create_issuer;
|
||||||
pub use helm::*;
|
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,
|
inventory: &Inventory,
|
||||||
topology: &T,
|
topology: &T,
|
||||||
) -> Result<Outcome, InterpretError> {
|
) -> Result<Outcome, InterpretError> {
|
||||||
let cert_management = topology
|
|
||||||
.install(&self.config)
|
topology
|
||||||
|
.ensure_certificate_management_ready(&self.config)
|
||||||
.await
|
.await
|
||||||
.map_err(|e| InterpretError::new(e.to_string()))?;
|
.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 {
|
fn get_name(&self) -> InterpretName {
|
||||||
Reference in New Issue
Block a user