fix: modified trait to use other return types, modified trait function name to be ensure ready, use rust CRD definitions rather than constructing gvk for certificateManagement trait function in k8sanywhere
This commit is contained in:
@@ -1,12 +1,8 @@
|
|||||||
use harmony::{
|
use harmony::{
|
||||||
inventory::Inventory,
|
inventory::Inventory,
|
||||||
modules::{
|
modules::cert_manager::{
|
||||||
cert_manager::{
|
capability::CertificateManagementConfig, score_create_cert::CertificateCreationScore,
|
||||||
capability::CertificateManagementConfig, score_create_cert::CertificateCreationScore,
|
score_create_issuer::CertificateIssuerScore, score_operator::CertificateManagementScore,
|
||||||
score_create_issuer::CertificateIssuerScore,
|
|
||||||
score_operator::CertificateManagementScore,
|
|
||||||
},
|
|
||||||
postgresql::{PostgreSQLScore, capability::PostgreSQLConfig},
|
|
||||||
},
|
},
|
||||||
topology::K8sAnywhereTopology,
|
topology::K8sAnywhereTopology,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -14,16 +14,24 @@ use tokio::sync::OnceCell;
|
|||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
executors::ExecutorError,
|
executors::ExecutorError,
|
||||||
interpret::InterpretStatus,
|
interpret::{InterpretStatus, Outcome},
|
||||||
inventory::Inventory,
|
inventory::Inventory,
|
||||||
modules::{
|
modules::{
|
||||||
cert_manager::{
|
cert_manager::{
|
||||||
capability::{CertificateManagement, CertificateManagementConfig},
|
capability::{CertificateManagement, CertificateManagementConfig},
|
||||||
crd::{score_certificate::CertificateScore, score_issuer::IssuerScore},
|
crd::{
|
||||||
|
certificate::Certificate,
|
||||||
|
issuer::{Issuer, IssuerSpec},
|
||||||
|
score_certificate::CertificateScore,
|
||||||
|
score_issuer::IssuerScore,
|
||||||
|
},
|
||||||
operator::CertManagerOperatorScore,
|
operator::CertManagerOperatorScore,
|
||||||
},
|
},
|
||||||
k3d::K3DInstallationScore,
|
k3d::K3DInstallationScore,
|
||||||
k8s::ingress::{K8sIngressScore, PathType},
|
k8s::{
|
||||||
|
apps::crd::Subscription,
|
||||||
|
ingress::{K8sIngressScore, PathType},
|
||||||
|
},
|
||||||
monitoring::{
|
monitoring::{
|
||||||
grafana::{grafana::Grafana, helm::helm_grafana::grafana_helm_chart_score},
|
grafana::{grafana::Grafana, helm::helm_grafana::grafana_helm_chart_score},
|
||||||
kube_prometheus::crd::{
|
kube_prometheus::crd::{
|
||||||
@@ -366,44 +374,36 @@ impl Serialize for K8sAnywhereTopology {
|
|||||||
|
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
impl CertificateManagement for K8sAnywhereTopology {
|
impl CertificateManagement for K8sAnywhereTopology {
|
||||||
async fn install(&self) -> Result<PreparationOutcome, PreparationError> {
|
async fn install(&self) -> Result<Outcome, ExecutorError> {
|
||||||
let cert_management_operator = CertManagerOperatorScore::default();
|
let cert_management_operator = CertManagerOperatorScore::default();
|
||||||
|
|
||||||
cert_management_operator
|
cert_management_operator
|
||||||
.interpret(&Inventory::empty(), self)
|
.interpret(&Inventory::empty(), self)
|
||||||
.await
|
.await
|
||||||
.map_err(|e| PreparationError { msg: e.to_string() })?;
|
.map_err(|e| ExecutorError::UnexpectedError(e.to_string()))?;
|
||||||
|
|
||||||
Ok(PreparationOutcome::Success {
|
Ok(Outcome::success(format!(
|
||||||
details: format!(
|
"Installed cert-manager into ns: {}",
|
||||||
"Installed cert-manager into ns: {}",
|
cert_management_operator.namespace
|
||||||
cert_management_operator.namespace
|
)))
|
||||||
),
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn ensure_certificate_management_ready(
|
async fn ensure_ready(
|
||||||
&self,
|
&self,
|
||||||
config: &CertificateManagementConfig,
|
config: &CertificateManagementConfig,
|
||||||
) -> Result<PreparationOutcome, PreparationError> {
|
) -> Result<Outcome, ExecutorError> {
|
||||||
let k8s_client = self.k8s_client().await.unwrap();
|
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
|
match k8s_client
|
||||||
.get_resource_json_value("cert-manager.openshift-operators", None, &gvk)
|
.get_resource::<Subscription>("cert-manager", Some("openshift-operators"))
|
||||||
.await
|
.await
|
||||||
|
.map_err(|e| ExecutorError::UnexpectedError(format!("{}", e)))?
|
||||||
{
|
{
|
||||||
Ok(_ready) => Ok(PreparationOutcome::Success {
|
Some(subscription) => {
|
||||||
details: "Certificate Management Ready".to_string(),
|
trace!("subscription {:#?}", subscription,);
|
||||||
}),
|
Ok(Outcome::success(format!("Certificate Management Ready",)))
|
||||||
Err(e) => {
|
|
||||||
debug!("{} operator not found", e.to_string());
|
|
||||||
self.install().await
|
|
||||||
}
|
}
|
||||||
|
None => self.install().await,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -411,7 +411,7 @@ impl CertificateManagement for K8sAnywhereTopology {
|
|||||||
&self,
|
&self,
|
||||||
issuer_name: String,
|
issuer_name: String,
|
||||||
config: &CertificateManagementConfig,
|
config: &CertificateManagementConfig,
|
||||||
) -> Result<PreparationOutcome, PreparationError> {
|
) -> Result<Outcome, ExecutorError> {
|
||||||
let issuer_score = IssuerScore {
|
let issuer_score = IssuerScore {
|
||||||
issuer_name: issuer_name.clone(),
|
issuer_name: issuer_name.clone(),
|
||||||
config: config.clone(),
|
config: config.clone(),
|
||||||
@@ -420,11 +420,12 @@ impl CertificateManagement for K8sAnywhereTopology {
|
|||||||
issuer_score
|
issuer_score
|
||||||
.interpret(&Inventory::empty(), self)
|
.interpret(&Inventory::empty(), self)
|
||||||
.await
|
.await
|
||||||
.map_err(|e| PreparationError { msg: e.to_string() })?;
|
.map_err(|e| ExecutorError::UnexpectedError(e.to_string()))?;
|
||||||
|
|
||||||
Ok(PreparationOutcome::Success {
|
Ok(Outcome::success(format!(
|
||||||
details: format!("issuer of kind {} is ready", issuer_name),
|
"issuer of kind {} is ready",
|
||||||
})
|
issuer_name
|
||||||
|
)))
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn create_certificate(
|
async fn create_certificate(
|
||||||
@@ -432,7 +433,7 @@ impl CertificateManagement for K8sAnywhereTopology {
|
|||||||
cert_name: String,
|
cert_name: String,
|
||||||
issuer_name: String,
|
issuer_name: String,
|
||||||
config: &CertificateManagementConfig,
|
config: &CertificateManagementConfig,
|
||||||
) -> Result<PreparationOutcome, PreparationError> {
|
) -> Result<Outcome, ExecutorError> {
|
||||||
self.certificate_issuer_ready(
|
self.certificate_issuer_ready(
|
||||||
issuer_name.clone(),
|
issuer_name.clone(),
|
||||||
self.k8s_client().await.unwrap(),
|
self.k8s_client().await.unwrap(),
|
||||||
@@ -447,69 +448,66 @@ impl CertificateManagement for K8sAnywhereTopology {
|
|||||||
};
|
};
|
||||||
cert.interpret(&Inventory::empty(), self)
|
cert.interpret(&Inventory::empty(), self)
|
||||||
.await
|
.await
|
||||||
.map_err(|e| PreparationError { msg: e.to_string() })?;
|
.map_err(|e| ExecutorError::UnexpectedError(e.to_string()))?;
|
||||||
|
|
||||||
Ok(PreparationOutcome::Success {
|
Ok(Outcome::success(format!(
|
||||||
details: format!("Created cert into ns: {:#?}", config.namespace.clone()),
|
"Created cert into ns: {:#?}",
|
||||||
})
|
config.namespace.clone()
|
||||||
|
)))
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn get_ca_certificate(
|
async fn get_ca_certificate(
|
||||||
&self,
|
&self,
|
||||||
cert_name: String,
|
cert_name: String,
|
||||||
config: &CertificateManagementConfig,
|
config: &CertificateManagementConfig,
|
||||||
) -> Result<String, PreparationError> {
|
) -> Result<String, ExecutorError> {
|
||||||
let namespace = config.namespace.clone().unwrap();
|
let namespace = config.namespace.clone().unwrap();
|
||||||
let certificate_gvk = GroupVersionKind {
|
|
||||||
group: "cert-manager.io".to_string(),
|
|
||||||
version: "v1".to_string(),
|
|
||||||
kind: "Certificate".to_string(),
|
|
||||||
};
|
|
||||||
let client = self.k8s_client().await.unwrap();
|
let client = self.k8s_client().await.unwrap();
|
||||||
let certificate_data = client
|
|
||||||
.get_resource_json_value(&cert_name, Some(&namespace), &certificate_gvk)
|
|
||||||
.await?
|
|
||||||
.data;
|
|
||||||
|
|
||||||
trace!("Certificate Data {:#?}", certificate_data);
|
if let Some(certificate) = client
|
||||||
|
.get_resource::<Certificate>(&cert_name, Some(&namespace))
|
||||||
|
.await
|
||||||
|
.map_err(|e| ExecutorError::UnexpectedError(format!("{}", e)))?
|
||||||
|
{
|
||||||
|
let secret_name = certificate.spec.secret_name.clone();
|
||||||
|
|
||||||
let secret_name = certificate_data
|
trace!("Secret Name {:#?}", secret_name);
|
||||||
.get("spec")
|
if let Some(secret) = client
|
||||||
.ok_or_else(|| PreparationError {
|
.get_resource::<Secret>(&secret_name, Some(&namespace))
|
||||||
msg: format!("failed to get spec from Certificate {}", cert_name),
|
.await
|
||||||
})?
|
.map_err(|e| {
|
||||||
.get("secretName")
|
ExecutorError::UnexpectedError(format!(
|
||||||
.ok_or_else(|| PreparationError {
|
"secret {} not found in namespace {}: {}",
|
||||||
msg: format!("failed to get secretName from Certificate {}", cert_name),
|
secret_name, namespace, e
|
||||||
})?;
|
))
|
||||||
|
})?
|
||||||
|
{
|
||||||
|
let ca_cert = secret
|
||||||
|
.data
|
||||||
|
.as_ref()
|
||||||
|
.and_then(|d| d.get("ca.crt"))
|
||||||
|
.ok_or_else(|| {
|
||||||
|
ExecutorError::UnexpectedError("Secret missing key 'ca.crt'".into())
|
||||||
|
})?;
|
||||||
|
|
||||||
trace!("Secret Name {:#?}", secret_name);
|
let ca_cert = String::from_utf8(ca_cert.0.clone()).map_err(|_| {
|
||||||
|
ExecutorError::UnexpectedError("ca.crt is not valid UTF-8".into())
|
||||||
|
})?;
|
||||||
|
|
||||||
let secret_name: String = serde_json::from_value(secret_name.clone())
|
return Ok(ca_cert);
|
||||||
.map_err(|e| PreparationError { msg: e.to_string() })?;
|
} else {
|
||||||
|
Err(ExecutorError::UnexpectedError(format!(
|
||||||
let secret = client
|
"Error getting secret associated with cert_name: {}",
|
||||||
.get_secret_json_value(&secret_name, Some(&namespace))
|
cert_name
|
||||||
.await?
|
)))
|
||||||
.data;
|
}
|
||||||
|
} else {
|
||||||
let ca_cert = secret
|
return Err(ExecutorError::UnexpectedError(format!(
|
||||||
.get("data")
|
"Certificate {} not found in namespace {}",
|
||||||
.ok_or_else(|| PreparationError {
|
cert_name, namespace
|
||||||
msg: format!("failed to get data from secret {}", secret_name),
|
)));
|
||||||
})?
|
}
|
||||||
.get("ca.crt")
|
|
||||||
.ok_or_else(|| PreparationError {
|
|
||||||
msg: format!("failed to get ca.crt from secret {}", secret_name),
|
|
||||||
})?;
|
|
||||||
|
|
||||||
trace!("ca.crt {:#?}", ca_cert.clone());
|
|
||||||
|
|
||||||
let ca_cert: String = serde_json::from_value(ca_cert.clone())
|
|
||||||
.map_err(|e| PreparationError { msg: e.to_string() })?;
|
|
||||||
|
|
||||||
trace!("ca.crt string {:#?}", ca_cert.clone());
|
|
||||||
Ok(ca_cert)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -537,27 +535,30 @@ impl K8sAnywhereTopology {
|
|||||||
issuer_name: String,
|
issuer_name: String,
|
||||||
k8s_client: Arc<K8sClient>,
|
k8s_client: Arc<K8sClient>,
|
||||||
config: &CertificateManagementConfig,
|
config: &CertificateManagementConfig,
|
||||||
) -> Result<PreparationOutcome, PreparationError> {
|
) -> Result<Outcome, ExecutorError> {
|
||||||
let ns = config.namespace.clone().ok_or_else(|| PreparationError {
|
let ns = config
|
||||||
msg: "namespace is required".to_string(),
|
.namespace
|
||||||
})?;
|
.clone()
|
||||||
|
.ok_or_else(|| ExecutorError::UnexpectedError("namespace is required".to_string()))?;
|
||||||
let gvk = GroupVersionKind {
|
|
||||||
group: "cert-manager.io".to_string(),
|
|
||||||
version: "v1".to_string(),
|
|
||||||
kind: "Issuer".to_string(),
|
|
||||||
};
|
|
||||||
|
|
||||||
match k8s_client
|
match k8s_client
|
||||||
.get_resource_json_value(&issuer_name, Some(&ns), &gvk)
|
.get_resource::<Issuer>(&issuer_name, Some(&ns))
|
||||||
.await
|
.await
|
||||||
{
|
{
|
||||||
Ok(_cert_issuer) => Ok(PreparationOutcome::Success {
|
Ok(Some(_cert_issuer)) => Ok(Outcome::success(format!(
|
||||||
details: format!("issuer of kind {} is ready", issuer_name),
|
"issuer of kind {} is ready",
|
||||||
}),
|
issuer_name
|
||||||
Err(e) => Err(PreparationError {
|
))),
|
||||||
msg: format!("{} issuer {} not present", e.to_string(), issuer_name),
|
|
||||||
}),
|
Ok(None) => Err(ExecutorError::UnexpectedError(format!(
|
||||||
|
"Issuer {} not present in namespace {}",
|
||||||
|
issuer_name, ns
|
||||||
|
))),
|
||||||
|
|
||||||
|
Err(e) => Err(ExecutorError::UnexpectedError(format!(
|
||||||
|
"Failed to fetch Issuer {}: {}",
|
||||||
|
issuer_name, e
|
||||||
|
))),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,38 +2,39 @@ use async_trait::async_trait;
|
|||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
executors::ExecutorError,
|
||||||
|
interpret::Outcome,
|
||||||
modules::cert_manager::crd::{AcmeIssuer, CaIssuer},
|
modules::cert_manager::crd::{AcmeIssuer, CaIssuer},
|
||||||
topology::{PreparationError, PreparationOutcome},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
///TODO rust doc explaining issuer, certificate etc
|
///TODO rust doc explaining issuer, certificate etc
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
pub trait CertificateManagement: Send + Sync {
|
pub trait CertificateManagement: Send + Sync {
|
||||||
async fn install(&self) -> Result<PreparationOutcome, PreparationError>;
|
async fn install(&self) -> Result<Outcome, ExecutorError>;
|
||||||
|
|
||||||
async fn ensure_certificate_management_ready(
|
async fn ensure_ready(
|
||||||
&self,
|
&self,
|
||||||
config: &CertificateManagementConfig,
|
config: &CertificateManagementConfig,
|
||||||
) -> Result<PreparationOutcome, PreparationError>;
|
) -> Result<Outcome, ExecutorError>;
|
||||||
|
|
||||||
async fn create_issuer(
|
async fn create_issuer(
|
||||||
&self,
|
&self,
|
||||||
issuer_name: String,
|
issuer_name: String,
|
||||||
config: &CertificateManagementConfig,
|
config: &CertificateManagementConfig,
|
||||||
) -> Result<PreparationOutcome, PreparationError>;
|
) -> Result<Outcome, ExecutorError>;
|
||||||
|
|
||||||
async fn create_certificate(
|
async fn create_certificate(
|
||||||
&self,
|
&self,
|
||||||
cert_name: String,
|
cert_name: String,
|
||||||
issuer_name: String,
|
issuer_name: String,
|
||||||
config: &CertificateManagementConfig,
|
config: &CertificateManagementConfig,
|
||||||
) -> Result<PreparationOutcome, PreparationError>;
|
) -> Result<Outcome, ExecutorError>;
|
||||||
|
|
||||||
async fn get_ca_certificate(
|
async fn get_ca_certificate(
|
||||||
&self,
|
&self,
|
||||||
cert_name: String,
|
cert_name: String,
|
||||||
config: &CertificateManagementConfig,
|
config: &CertificateManagementConfig,
|
||||||
) -> Result<String, PreparationError>;
|
) -> Result<String, ExecutorError>;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize)]
|
#[derive(Debug, Clone, Serialize)]
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
use harmony_types::id::Id;
|
use harmony_types::id::Id;
|
||||||
|
use log::trace;
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
@@ -55,6 +56,11 @@ impl<T: Topology + CertificateManagement> Interpret<T> for CertificateCreationIn
|
|||||||
.await
|
.await
|
||||||
.map_err(|e| InterpretError::new(e.to_string()))?;
|
.map_err(|e| InterpretError::new(e.to_string()))?;
|
||||||
|
|
||||||
|
let ca_cert = topology
|
||||||
|
.get_ca_certificate("test-self-signed-cert".to_string(), &self.config)
|
||||||
|
.await?;
|
||||||
|
trace!("cacert: {}", ca_cert);
|
||||||
|
|
||||||
Ok(Outcome::success(format!("Installed CertificateManagement")))
|
Ok(Outcome::success(format!("Installed CertificateManagement")))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -40,8 +40,7 @@ impl<T: Topology + CertificateManagement> Interpret<T> for CertificateManagement
|
|||||||
inventory: &Inventory,
|
inventory: &Inventory,
|
||||||
topology: &T,
|
topology: &T,
|
||||||
) -> Result<Outcome, InterpretError> {
|
) -> Result<Outcome, InterpretError> {
|
||||||
topology
|
let _cert_management = &CertificateManagement::ensure_ready(topology, &self.config)
|
||||||
.ensure_certificate_management_ready(&self.config)
|
|
||||||
.await
|
.await
|
||||||
.map_err(|e| InterpretError::new(e.to_string()))?;
|
.map_err(|e| InterpretError::new(e.to_string()))?;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user