wip(update-ingress): built basic structure for the okd commands to update the default ingress to allow dynamically provisioning tls certificates for ingresses added quality of life function to check if a deployement exists using the k8sclient
	
		
			
	
		
	
	
		
	
		
			All checks were successful
		
		
	
	
		
			
				
	
				Run Check Script / check (pull_request) Successful in 57s
				
			
		
		
	
	
				
					
				
			
		
			All checks were successful
		
		
	
	Run Check Script / check (pull_request) Successful in 57s
				
			This commit is contained in:
		
							parent
							
								
									c84b2413ed
								
							
						
					
					
						commit
						41f1bca69c
					
				| @ -8,6 +8,7 @@ use kube::{ | |||||||
|     api::{Api, AttachParams, DeleteParams, ListParams, Patch, PatchParams, ResourceExt}, |     api::{Api, AttachParams, DeleteParams, ListParams, Patch, PatchParams, ResourceExt}, | ||||||
|     config::{KubeConfigOptions, Kubeconfig}, |     config::{KubeConfigOptions, Kubeconfig}, | ||||||
|     core::ErrorResponse, |     core::ErrorResponse, | ||||||
|  |     error::DiscoveryError, | ||||||
|     runtime::reflector::Lookup, |     runtime::reflector::Lookup, | ||||||
| }; | }; | ||||||
| use kube::{api::DynamicObject, runtime::conditions}; | use kube::{api::DynamicObject, runtime::conditions}; | ||||||
| @ -21,6 +22,8 @@ use serde_json::{Value, json}; | |||||||
| use similar::TextDiff; | use similar::TextDiff; | ||||||
| use tokio::io::AsyncReadExt; | use tokio::io::AsyncReadExt; | ||||||
| 
 | 
 | ||||||
|  | use crate::interpret::Outcome; | ||||||
|  | 
 | ||||||
| #[derive(new, Clone)] | #[derive(new, Clone)] | ||||||
| pub struct K8sClient { | pub struct K8sClient { | ||||||
|     client: Client, |     client: Client, | ||||||
| @ -53,6 +56,57 @@ impl K8sClient { | |||||||
|         }) |         }) | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     pub async fn ensure_deployment( | ||||||
|  |         &self, | ||||||
|  |         resource_name: &str, | ||||||
|  |         resource_namespace: &str, | ||||||
|  |     ) -> Result<Outcome, Error> { | ||||||
|  |         match self | ||||||
|  |             .get_deployment(resource_name, Some(&resource_namespace)) | ||||||
|  |             .await | ||||||
|  |         { | ||||||
|  |             Ok(Some(deployment)) => { | ||||||
|  |                 if let Some(status) = deployment.status { | ||||||
|  |                     let ready_count = status.ready_replicas.unwrap_or(0); | ||||||
|  |                     if ready_count >= 1 { | ||||||
|  |                         Ok(Outcome::success(format!( | ||||||
|  |                             "'{}' is ready with {} replica(s).", | ||||||
|  |                             resource_name, ready_count | ||||||
|  |                         ))) | ||||||
|  |                     } else { | ||||||
|  |                         Err(Error::Discovery(DiscoveryError::MissingResource(format!( | ||||||
|  |                             "Deployment '{}' in namespace '{}' has 0 ready replicas", | ||||||
|  |                             resource_name, resource_namespace | ||||||
|  |                         )))) | ||||||
|  |                     } | ||||||
|  |                 } else { | ||||||
|  |                     Err(Error::Api(ErrorResponse { | ||||||
|  |                         status: "Failure".to_string(), | ||||||
|  |                         message: format!( | ||||||
|  |                             "No status found for deployment '{}' in namespace '{}'", | ||||||
|  |                             resource_name, resource_namespace | ||||||
|  |                         ), | ||||||
|  |                         reason: "MissingStatus".to_string(), | ||||||
|  |                         code: 404, | ||||||
|  |                     })) | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |             Ok(None) => Err(Error::Discovery(DiscoveryError::MissingResource(format!( | ||||||
|  |                 "Deployment '{}' not found in namespace '{}'", | ||||||
|  |                 resource_name, resource_namespace | ||||||
|  |             )))), | ||||||
|  |             Err(e) => Err(Error::Api(ErrorResponse { | ||||||
|  |                 status: "Failure".to_string(), | ||||||
|  |                 message: format!( | ||||||
|  |                     "Failed to fetch deployment '{}' in namespace '{}': {}", | ||||||
|  |                     resource_name, resource_namespace, e | ||||||
|  |                 ), | ||||||
|  |                 reason: "ApiError".to_string(), | ||||||
|  |                 code: 500, | ||||||
|  |             })), | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     pub async fn get_resource_json_value( |     pub async fn get_resource_json_value( | ||||||
|         &self, |         &self, | ||||||
|         name: &str, |         name: &str, | ||||||
|  | |||||||
							
								
								
									
										124
									
								
								harmony/src/modules/cert_manager/generate_cert_score.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										124
									
								
								harmony/src/modules/cert_manager/generate_cert_score.rs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,124 @@ | |||||||
|  | use std::{path::PathBuf, sync::Arc}; | ||||||
|  | 
 | ||||||
|  | use fqdn::FQDN; | ||||||
|  | use harmony_types::id::Id; | ||||||
|  | 
 | ||||||
|  | use crate::{ | ||||||
|  |     data::Version, | ||||||
|  |     interpret::{Interpret, InterpretError, InterpretName, InterpretStatus, Outcome}, | ||||||
|  |     inventory::Inventory, | ||||||
|  |     score::Score, | ||||||
|  |     topology::{k8s::K8sClient, K8sclient, Topology}, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | pub struct UpdateDefaultOkdIngressScore { | ||||||
|  |     ca_name: String, | ||||||
|  |     domain: FQDN, | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl<T: Topology> Score<T> for UpdateDefaultOkdIngressScore { | ||||||
|  |     fn name(&self) -> String { | ||||||
|  |         "UpdateDefaultOkdIngressScore".to_string() | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     #[doc(hidden)] | ||||||
|  |     fn create_interpret(&self) -> Box<dyn Interpret<T>> { | ||||||
|  |         Box::new(UpdateDefaultOkdIngressInterpret { | ||||||
|  |             score: self.clone(), | ||||||
|  |         }) | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | pub struct UpdateDefaultOkdIngressInterpret { | ||||||
|  |     score: UpdateDefaultOkdIngressScore, | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #[async_trait] | ||||||
|  | impl<T: Topology + K8sclient> Interpret<T> for UpdateDefaultOkdIngressInterpret { | ||||||
|  |     async fn execute(&self, inventory: &Inventory, topology: &T) -> Result<Outcome, InterpretError> { | ||||||
|  |         let client = topology.k8s_client().await?; | ||||||
|  |         let ca_name = self.score.ca_name.clone(); | ||||||
|  |         let domain = self.score.domain.clone(); | ||||||
|  |         let secret_name = "ingress_ca_secret"; | ||||||
|  |         self.ensure_ingress_operator(&client).await?; | ||||||
|  |         self.create_ca_cm(&client, &domain, &ca_name).await?; | ||||||
|  |         self.patch_proxy(&client, &ca_name).await?; | ||||||
|  |         self.create_tls_secret(&client, &secret_name).await?; | ||||||
|  |         self.patch_ingress(&client, &secret_name).await?; | ||||||
|  | 
 | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     fn get_name(&self) -> InterpretName { | ||||||
|  |         InterpretName::Custom("UpdateDefaultOkd") | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     fn get_version(&self) -> Version { | ||||||
|  |         todo!() | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     fn get_status(&self) -> InterpretStatus { | ||||||
|  |         todo!() | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     fn get_children(&self) -> Vec<Id> { | ||||||
|  |         todo!() | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl UpdateDefaultOkdIngressInterpret { | ||||||
|  |     async fn ensure_ingress_operator( | ||||||
|  |         &self, | ||||||
|  |         client: &Arc<K8sClient>, | ||||||
|  |     ) -> Result<Outcome, InterpretError> { | ||||||
|  |         let operator_name = "ingress-operator"; | ||||||
|  |         let operator_namespace = "openshift-ingress-operator"; | ||||||
|  |         client | ||||||
|  |             .ensure_deployment(operator_name, Some(operator_namespace)) | ||||||
|  |             .await? | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     async fn create_ca_cm( | ||||||
|  |         &self, | ||||||
|  |         client: &Arc<K8sClient>, | ||||||
|  |         fqdn: &FQDN, | ||||||
|  |         ca_name: &str, | ||||||
|  |     ) -> Result<Outcome, InterpretError> { | ||||||
|  |         let cm = format!( | ||||||
|  |             r"#
 | ||||||
|  | apiVersion: v1 | ||||||
|  | kind: ConfigMap | ||||||
|  | metadata: | ||||||
|  |   name: custom-ca | ||||||
|  |   namespace: openshift-config | ||||||
|  | data: | ||||||
|  |   ca-bundle.crt: {} | ||||||
|  |         #", fqdn
 | ||||||
|  |         ); | ||||||
|  |         client.apply_yaml(serde_yaml::to_value(&cm), None).await?; | ||||||
|  |         Ok(Outcome::success(format!( | ||||||
|  |             "successfully created cm : {} in default namespace", | ||||||
|  |             ca_name | ||||||
|  |         ))) | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     async fn patch_proxy( | ||||||
|  |         &self, | ||||||
|  |         client: &Arc<K8sClient>, | ||||||
|  |         ca_name: &str, | ||||||
|  |     ) -> Result<Outcome, InterpretError> { | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     async fn create_tls_secret( | ||||||
|  |         &self, | ||||||
|  |         client: &Arc<K8sClient>, | ||||||
|  |         secret_name: &str, | ||||||
|  |     ) -> Result<Outcome, InterpretError> { | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     async fn patch_ingress( | ||||||
|  |         &self, | ||||||
|  |         client: &Arc<K8sClient>, | ||||||
|  |         secret_name: &str, | ||||||
|  |     ) -> Result<Outcome, InterpretError> { | ||||||
|  |     } | ||||||
|  | } | ||||||
		Loading…
	
		Reference in New Issue
	
	Block a user