forked from NationTech/harmony
		
	feat(cert-manager): add cluster issuer to okd cluster score (#157)
added score to install okd cluster issuer Reviewed-on: https://git.nationtech.io/NationTech/harmony/pulls/157
This commit is contained in:
		
							parent
							
								
									14d1823d15
								
							
						
					
					
						commit
						987f195e2f
					
				
							
								
								
									
										209
									
								
								harmony/src/modules/cert_manager/cluster_issuer.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										209
									
								
								harmony/src/modules/cert_manager/cluster_issuer.rs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,209 @@ | ||||
| use std::sync::Arc; | ||||
| 
 | ||||
| use async_trait::async_trait; | ||||
| use harmony_types::id::Id; | ||||
| use kube::{CustomResource, api::ObjectMeta}; | ||||
| use schemars::JsonSchema; | ||||
| use serde::{Deserialize, Serialize}; | ||||
| 
 | ||||
| use crate::{ | ||||
|     data::Version, | ||||
|     interpret::{Interpret, InterpretError, InterpretName, InterpretStatus, Outcome}, | ||||
|     inventory::Inventory, | ||||
|     score::Score, | ||||
|     topology::{K8sclient, Topology, k8s::K8sClient}, | ||||
| }; | ||||
| 
 | ||||
| #[derive(Clone, Debug, Serialize)] | ||||
| pub struct ClusterIssuerScore { | ||||
|     email: String, | ||||
|     server: String, | ||||
|     issuer_name: String, | ||||
|     namespace: String, | ||||
| } | ||||
| 
 | ||||
| impl<T: Topology + K8sclient> Score<T> for ClusterIssuerScore { | ||||
|     fn name(&self) -> String { | ||||
|         "ClusterIssuerScore".to_string() | ||||
|     } | ||||
| 
 | ||||
|     #[doc(hidden)] | ||||
|     fn create_interpret(&self) -> Box<dyn Interpret<T>> { | ||||
|         Box::new(ClusterIssuerInterpret { | ||||
|             score: self.clone(), | ||||
|         }) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| #[derive(Debug, Clone)] | ||||
| pub struct ClusterIssuerInterpret { | ||||
|     score: ClusterIssuerScore, | ||||
| } | ||||
| 
 | ||||
| #[async_trait] | ||||
| impl<T: Topology + K8sclient> Interpret<T> for ClusterIssuerInterpret { | ||||
|     async fn execute( | ||||
|         &self, | ||||
|         _inventory: &Inventory, | ||||
|         topology: &T, | ||||
|     ) -> Result<Outcome, InterpretError> { | ||||
|         self.apply_cluster_issuer(topology.k8s_client().await.unwrap()) | ||||
|             .await | ||||
|     } | ||||
| 
 | ||||
|     fn get_name(&self) -> InterpretName { | ||||
|         InterpretName::Custom("ClusterIssuer") | ||||
|     } | ||||
| 
 | ||||
|     fn get_version(&self) -> Version { | ||||
|         todo!() | ||||
|     } | ||||
| 
 | ||||
|     fn get_status(&self) -> InterpretStatus { | ||||
|         todo!() | ||||
|     } | ||||
| 
 | ||||
|     fn get_children(&self) -> Vec<Id> { | ||||
|         todo!() | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl ClusterIssuerInterpret { | ||||
|     async fn validate_cert_manager( | ||||
|         &self, | ||||
|         client: &Arc<K8sClient>, | ||||
|     ) -> Result<Outcome, InterpretError> { | ||||
|         let cert_manager = "cert-manager".to_string(); | ||||
|         let operator_namespace = "openshift-operators".to_string(); | ||||
|         match client | ||||
|             .get_deployment(&cert_manager, Some(&operator_namespace)) | ||||
|             .await | ||||
|         { | ||||
|             Ok(Some(deployment)) => { | ||||
|                 if let Some(status) = deployment.status { | ||||
|                     let ready_count = status.ready_replicas.unwrap_or(0); | ||||
|                     if ready_count >= 1 { | ||||
|                         return Ok(Outcome::success(format!( | ||||
|                             "'{}' is ready with {} replica(s).", | ||||
|                             &cert_manager, ready_count | ||||
|                         ))); | ||||
|                     } else { | ||||
|                         return Err(InterpretError::new( | ||||
|                             "cert-manager operator not ready in cluster".to_string(), | ||||
|                         )); | ||||
|                     } | ||||
|                 } else { | ||||
|                     Err(InterpretError::new(format!( | ||||
|                         "failed to get deployment status {} in ns {}", | ||||
|                         &cert_manager, &operator_namespace | ||||
|                     ))) | ||||
|                 } | ||||
|             } | ||||
|             Ok(None) => Err(InterpretError::new(format!( | ||||
|                 "Deployment '{}' not found in namespace '{}'.", | ||||
|                 &cert_manager, &operator_namespace | ||||
|             ))), | ||||
|             Err(e) => Err(InterpretError::new(format!( | ||||
|                 "Failed to query for deployment '{}': {}", | ||||
|                 &cert_manager, e | ||||
|             ))), | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     fn build_cluster_issuer(&self) -> Result<ClusterIssuer, InterpretError> { | ||||
|         let issuer_name = &self.score.issuer_name; | ||||
|         let email = &self.score.email; | ||||
|         let server = &self.score.server; | ||||
|         let namespace = &self.score.namespace; | ||||
|         let cluster_issuer = ClusterIssuer { | ||||
|             metadata: ObjectMeta { | ||||
|                 name: Some(issuer_name.to_string()), | ||||
|                 namespace: Some(namespace.to_string()), | ||||
|                 ..Default::default() | ||||
|             }, | ||||
|             spec: ClusterIssuerSpec { | ||||
|                 acme: AcmeSpec { | ||||
|                     email: email.to_string(), | ||||
|                     private_key_secret_ref: PrivateKeySecretRef { | ||||
|                         name: issuer_name.to_string(), | ||||
|                     }, | ||||
|                     server: server.to_string(), | ||||
|                     solvers: vec![SolverSpec { | ||||
|                         http01: Some(Http01Solver { | ||||
|                             ingress: Http01Ingress { | ||||
|                                 class: "nginx".to_string(), | ||||
|                             }, | ||||
|                         }), | ||||
|                     }], | ||||
|                 }, | ||||
|             }, | ||||
|         }; | ||||
| 
 | ||||
|         Ok(cluster_issuer) | ||||
|     } | ||||
| 
 | ||||
|     pub async fn apply_cluster_issuer( | ||||
|         &self, | ||||
|         client: Arc<K8sClient>, | ||||
|     ) -> Result<Outcome, InterpretError> { | ||||
|         let namespace = self.score.namespace.clone(); | ||||
|         self.validate_cert_manager(&client).await?; | ||||
|         let cluster_issuer = self.build_cluster_issuer().unwrap(); | ||||
|         client | ||||
|             .apply_yaml( | ||||
|                 &serde_yaml::to_value(cluster_issuer).unwrap(), | ||||
|                 Some(&namespace), | ||||
|             ) | ||||
|             .await?; | ||||
|         Ok(Outcome::success(format!( | ||||
|             "successfully deployed cluster operator: {} in namespace: {}", | ||||
|             self.score.issuer_name, self.score.namespace | ||||
|         ))) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| #[derive(CustomResource, Deserialize, Serialize, Clone, Debug, JsonSchema)] | ||||
| #[kube(
 | ||||
|     group = "cert-manager.io", | ||||
|     version = "v1", | ||||
|     kind = "ClusterIssuer", | ||||
|     plural = "clusterissuers" | ||||
| )] | ||||
| #[serde(rename_all = "camelCase")] | ||||
| pub struct ClusterIssuerSpec { | ||||
|     pub acme: AcmeSpec, | ||||
| } | ||||
| 
 | ||||
| #[derive(Deserialize, Serialize, Clone, Debug, JsonSchema)] | ||||
| #[serde(rename_all = "camelCase")] | ||||
| pub struct AcmeSpec { | ||||
|     pub email: String, | ||||
|     pub private_key_secret_ref: PrivateKeySecretRef, | ||||
|     pub server: String, | ||||
|     pub solvers: Vec<SolverSpec>, | ||||
| } | ||||
| 
 | ||||
| #[derive(Deserialize, Serialize, Clone, Debug, JsonSchema)] | ||||
| #[serde(rename_all = "camelCase")] | ||||
| pub struct PrivateKeySecretRef { | ||||
|     pub name: String, | ||||
| } | ||||
| 
 | ||||
| #[derive(Deserialize, Serialize, Clone, Debug, JsonSchema)] | ||||
| #[serde(rename_all = "camelCase")] | ||||
| pub struct SolverSpec { | ||||
|     pub http01: Option<Http01Solver>, | ||||
|     // Other solver types (e.g., dns01) would go here as Options
 | ||||
| } | ||||
| 
 | ||||
| #[derive(Deserialize, Serialize, Clone, Debug, JsonSchema)] | ||||
| #[serde(rename_all = "camelCase")] | ||||
| pub struct Http01Solver { | ||||
|     pub ingress: Http01Ingress, | ||||
| } | ||||
| 
 | ||||
| #[derive(Deserialize, Serialize, Clone, Debug, JsonSchema)] | ||||
| #[serde(rename_all = "camelCase")] | ||||
| pub struct Http01Ingress { | ||||
|     pub class: String, | ||||
| } | ||||
| @ -1,2 +1,3 @@ | ||||
| pub mod cluster_issuer; | ||||
| mod helm; | ||||
| pub use helm::*; | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user