okd_enable_user_workload_monitoring (#160)
Reviewed-on: https://git.nationtech.io/NationTech/harmony/pulls/160 Co-authored-by: Willem <wrolleman@nationtech.io> Co-committed-by: Willem <wrolleman@nationtech.io>
This commit is contained in:
		
							parent
							
								
									c84b2413ed
								
							
						
					
					
						commit
						cbbaae2ac8
					
				| @ -1,13 +1,19 @@ | |||||||
|  | use std::time::Duration; | ||||||
|  | 
 | ||||||
| use derive_new::new; | use derive_new::new; | ||||||
| use k8s_openapi::{ | use k8s_openapi::{ | ||||||
|     ClusterResourceScope, NamespaceResourceScope, |     ClusterResourceScope, NamespaceResourceScope, | ||||||
|     api::{apps::v1::Deployment, core::v1::Pod}, |     api::{ | ||||||
|  |         apps::v1::Deployment, | ||||||
|  |         core::v1::{Pod, PodStatus}, | ||||||
|  |     }, | ||||||
| }; | }; | ||||||
| use kube::{ | use kube::{ | ||||||
|     Client, Config, Error, Resource, |     Client, Config, Error, Resource, | ||||||
|     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}; | ||||||
| @ -19,7 +25,7 @@ use log::{debug, error, trace}; | |||||||
| use serde::{Serialize, de::DeserializeOwned}; | use serde::{Serialize, de::DeserializeOwned}; | ||||||
| use serde_json::{Value, json}; | use serde_json::{Value, json}; | ||||||
| use similar::TextDiff; | use similar::TextDiff; | ||||||
| use tokio::io::AsyncReadExt; | use tokio::{io::AsyncReadExt, time::sleep}; | ||||||
| 
 | 
 | ||||||
| #[derive(new, Clone)] | #[derive(new, Clone)] | ||||||
| pub struct K8sClient { | pub struct K8sClient { | ||||||
| @ -153,6 +159,41 @@ impl K8sClient { | |||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     pub async fn wait_for_pod_ready( | ||||||
|  |         &self, | ||||||
|  |         pod_name: &str, | ||||||
|  |         namespace: Option<&str>, | ||||||
|  |     ) -> Result<(), Error> { | ||||||
|  |         let mut elapsed = 0; | ||||||
|  |         let interval = 5; // seconds between checks
 | ||||||
|  |         let timeout_secs = 120; | ||||||
|  |         loop { | ||||||
|  |             let pod = self.get_pod(pod_name, namespace).await?; | ||||||
|  | 
 | ||||||
|  |             if let Some(p) = pod { | ||||||
|  |                 if let Some(status) = p.status { | ||||||
|  |                     if let Some(phase) = status.phase { | ||||||
|  |                         if phase.to_lowercase() == "running" { | ||||||
|  |                             return Ok(()); | ||||||
|  |                         } | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             if elapsed >= timeout_secs { | ||||||
|  |                 return Err(Error::Discovery(DiscoveryError::MissingResource(format!( | ||||||
|  |                     "'{}' in ns '{}' did not become ready within {}s", | ||||||
|  |                     pod_name, | ||||||
|  |                     namespace.unwrap(), | ||||||
|  |                     timeout_secs | ||||||
|  |                 )))); | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             sleep(Duration::from_secs(interval)).await; | ||||||
|  |             elapsed += interval; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     /// Will execute a commond in the first pod found that matches the specified label
 |     /// Will execute a commond in the first pod found that matches the specified label
 | ||||||
|     /// '{label}={name}'
 |     /// '{label}={name}'
 | ||||||
|     pub async fn exec_app_capture_output( |     pub async fn exec_app_capture_output( | ||||||
| @ -419,9 +460,12 @@ impl K8sClient { | |||||||
|             .as_str() |             .as_str() | ||||||
|             .expect("couldn't get kind as str"); |             .expect("couldn't get kind as str"); | ||||||
| 
 | 
 | ||||||
|         let split: Vec<&str> = api_version.splitn(2, "/").collect(); |         let mut it = api_version.splitn(2, '/'); | ||||||
|         let g = split[0]; |         let first = it.next().unwrap(); | ||||||
|         let v = split[1]; |         let (g, v) = match it.next() { | ||||||
|  |             Some(second) => (first, second), | ||||||
|  |             None => ("", first), | ||||||
|  |         }; | ||||||
| 
 | 
 | ||||||
|         let gvk = GroupVersionKind::gvk(g, v, kind); |         let gvk = GroupVersionKind::gvk(g, v, kind); | ||||||
|         let api_resource = ApiResource::from_gvk(&gvk); |         let api_resource = ApiResource::from_gvk(&gvk); | ||||||
|  | |||||||
| @ -4,4 +4,5 @@ pub mod application_monitoring; | |||||||
| pub mod grafana; | pub mod grafana; | ||||||
| pub mod kube_prometheus; | pub mod kube_prometheus; | ||||||
| pub mod ntfy; | pub mod ntfy; | ||||||
|  | pub mod okd; | ||||||
| pub mod prometheus; | pub mod prometheus; | ||||||
|  | |||||||
							
								
								
									
										149
									
								
								harmony/src/modules/monitoring/okd/enable_user_workload.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										149
									
								
								harmony/src/modules/monitoring/okd/enable_user_workload.rs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,149 @@ | |||||||
|  | use std::{collections::BTreeMap, sync::Arc}; | ||||||
|  | 
 | ||||||
|  | use crate::{ | ||||||
|  |     data::Version, | ||||||
|  |     interpret::{Interpret, InterpretError, InterpretName, InterpretStatus, Outcome}, | ||||||
|  |     inventory::Inventory, | ||||||
|  |     score::Score, | ||||||
|  |     topology::{K8sclient, Topology, k8s::K8sClient}, | ||||||
|  | }; | ||||||
|  | use async_trait::async_trait; | ||||||
|  | use harmony_types::id::Id; | ||||||
|  | use k8s_openapi::api::core::v1::ConfigMap; | ||||||
|  | use kube::api::ObjectMeta; | ||||||
|  | use serde::Serialize; | ||||||
|  | 
 | ||||||
|  | #[derive(Clone, Debug, Serialize)] | ||||||
|  | pub struct OpenshiftUserWorkloadMonitoring {} | ||||||
|  | 
 | ||||||
|  | impl<T: Topology + K8sclient> Score<T> for OpenshiftUserWorkloadMonitoring { | ||||||
|  |     fn name(&self) -> String { | ||||||
|  |         "OpenshiftUserWorkloadMonitoringScore".to_string() | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     fn create_interpret(&self) -> Box<dyn Interpret<T>> { | ||||||
|  |         Box::new(OpenshiftUserWorkloadMonitoringInterpret {}) | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #[derive(Clone, Debug, Serialize)] | ||||||
|  | pub struct OpenshiftUserWorkloadMonitoringInterpret {} | ||||||
|  | 
 | ||||||
|  | #[async_trait] | ||||||
|  | impl<T: Topology + K8sclient> Interpret<T> for OpenshiftUserWorkloadMonitoringInterpret { | ||||||
|  |     async fn execute( | ||||||
|  |         &self, | ||||||
|  |         _inventory: &Inventory, | ||||||
|  |         topology: &T, | ||||||
|  |     ) -> Result<Outcome, InterpretError> { | ||||||
|  |         let client = topology.k8s_client().await.unwrap(); | ||||||
|  |         self.update_cluster_monitoring_config_cm(&client).await?; | ||||||
|  |         self.update_user_workload_monitoring_config_cm(&client) | ||||||
|  |             .await?; | ||||||
|  |         self.verify_user_workload(&client).await?; | ||||||
|  |         Ok(Outcome::success( | ||||||
|  |             "successfully enabled user-workload-monitoring".to_string(), | ||||||
|  |         )) | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     fn get_name(&self) -> InterpretName { | ||||||
|  |         InterpretName::Custom("OpenshiftUserWorkloadMonitoring") | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     fn get_version(&self) -> Version { | ||||||
|  |         todo!() | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     fn get_status(&self) -> InterpretStatus { | ||||||
|  |         todo!() | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     fn get_children(&self) -> Vec<Id> { | ||||||
|  |         todo!() | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl OpenshiftUserWorkloadMonitoringInterpret { | ||||||
|  |     pub async fn update_cluster_monitoring_config_cm( | ||||||
|  |         &self, | ||||||
|  |         client: &Arc<K8sClient>, | ||||||
|  |     ) -> Result<Outcome, InterpretError> { | ||||||
|  |         let mut data = BTreeMap::new(); | ||||||
|  |         data.insert( | ||||||
|  |             "config.yaml".to_string(), | ||||||
|  |             r#" | ||||||
|  | enableUserWorkload: true | ||||||
|  | alertmanagerMain: | ||||||
|  |   enableUserAlertmanagerConfig: true | ||||||
|  | "#
 | ||||||
|  |             .to_string(), | ||||||
|  |         ); | ||||||
|  | 
 | ||||||
|  |         let cm = ConfigMap { | ||||||
|  |             metadata: ObjectMeta { | ||||||
|  |                 name: Some("cluster-monitoring-config".to_string()), | ||||||
|  |                 namespace: Some("openshift-monitoring".to_string()), | ||||||
|  |                 ..Default::default() | ||||||
|  |             }, | ||||||
|  |             data: Some(data), | ||||||
|  |             ..Default::default() | ||||||
|  |         }; | ||||||
|  |         client.apply(&cm, Some("openshift-monitoring")).await?; | ||||||
|  | 
 | ||||||
|  |         Ok(Outcome::success( | ||||||
|  |             "updated cluster-monitoring-config-map".to_string(), | ||||||
|  |         )) | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     pub async fn update_user_workload_monitoring_config_cm( | ||||||
|  |         &self, | ||||||
|  |         client: &Arc<K8sClient>, | ||||||
|  |     ) -> Result<Outcome, InterpretError> { | ||||||
|  |         let mut data = BTreeMap::new(); | ||||||
|  |         data.insert( | ||||||
|  |             "config.yaml".to_string(), | ||||||
|  |             r#" | ||||||
|  | alertmanager:  | ||||||
|  |   enabled: true | ||||||
|  |   enableAlertmanagerConfig: true | ||||||
|  | "#
 | ||||||
|  |             .to_string(), | ||||||
|  |         ); | ||||||
|  |         let cm = ConfigMap { | ||||||
|  |             metadata: ObjectMeta { | ||||||
|  |                 name: Some("user-workload-monitoring-config".to_string()), | ||||||
|  |                 namespace: Some("openshift-user-workload-monitoring".to_string()), | ||||||
|  |                 ..Default::default() | ||||||
|  |             }, | ||||||
|  |             data: Some(data), | ||||||
|  |             ..Default::default() | ||||||
|  |         }; | ||||||
|  |         client | ||||||
|  |             .apply(&cm, Some("openshift-user-workload-monitoring")) | ||||||
|  |             .await?; | ||||||
|  | 
 | ||||||
|  |         Ok(Outcome::success( | ||||||
|  |             "updated openshift-user-monitoring-config-map".to_string(), | ||||||
|  |         )) | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     pub async fn verify_user_workload( | ||||||
|  |         &self, | ||||||
|  |         client: &Arc<K8sClient>, | ||||||
|  |     ) -> Result<Outcome, InterpretError> { | ||||||
|  |         let namespace = "openshift-user-workload-monitoring"; | ||||||
|  |         let alertmanager_name = "alertmanager-user-workload-0"; | ||||||
|  |         let prometheus_name = "prometheus-user-workload-0"; | ||||||
|  |         client | ||||||
|  |             .wait_for_pod_ready(alertmanager_name, Some(namespace)) | ||||||
|  |             .await?; | ||||||
|  |         client | ||||||
|  |             .wait_for_pod_ready(prometheus_name, Some(namespace)) | ||||||
|  |             .await?; | ||||||
|  | 
 | ||||||
|  |         Ok(Outcome::success(format!( | ||||||
|  |             "pods: {}, {} ready in ns: {}", | ||||||
|  |             alertmanager_name, prometheus_name, namespace | ||||||
|  |         ))) | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										1
									
								
								harmony/src/modules/monitoring/okd/mod.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								harmony/src/modules/monitoring/okd/mod.rs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1 @@ | |||||||
|  | pub mod enable_user_workload; | ||||||
		Loading…
	
		Reference in New Issue
	
	Block a user