forked from NationTech/harmony
		
	wip: fixing grafana datasource for openshift which requires creating a token, sa, secret and inserting them into the grafanadatasource
This commit is contained in:
		
							parent
							
								
									1f3796f503
								
							
						
					
					
						commit
						85bec66e58
					
				| @ -1,7 +1,15 @@ | ||||
| use std::{collections::BTreeMap, process::Command, sync::Arc}; | ||||
| 
 | ||||
| use async_trait::async_trait; | ||||
| use kube::api::{GroupVersionKind, ObjectMeta}; | ||||
| use k8s_openapi::api::{ | ||||
|     authentication::v1::{TokenRequest, TokenRequestSpec}, | ||||
|     core::v1::{Secret, ServiceAccount}, | ||||
|     rbac::v1::{ClusterRoleBinding, RoleRef, Subject}, | ||||
| }; | ||||
| use kube::{ | ||||
|     Api, | ||||
|     api::{GroupVersionKind, ObjectMeta, PostParams}, | ||||
| }; | ||||
| use log::{debug, info, warn}; | ||||
| use serde::Serialize; | ||||
| use tokio::sync::OnceCell; | ||||
| @ -19,12 +27,14 @@ use crate::{ | ||||
|                 crd_alertmanager_config::CRDPrometheus, | ||||
|                 crd_grafana::{ | ||||
|                     Grafana as GrafanaCRD, GrafanaDashboard, GrafanaDashboardSpec, | ||||
|                     GrafanaDatasource, GrafanaDatasourceConfig, GrafanaDatasourceSpec, GrafanaSpec, | ||||
|                     GrafanaDatasource, GrafanaDatasourceConfig, GrafanaDatasourceJsonData, | ||||
|                     GrafanaDatasourceSecureJsonData, GrafanaDatasourceSpec, GrafanaSpec, | ||||
|                 }, | ||||
|                 crd_prometheuses::LabelSelector, | ||||
|                 grafana_default_dashboard::build_default_dashboard, | ||||
|                 prometheus_operator::prometheus_operator_helm_chart_score, | ||||
|                 rhob_alertmanager_config::RHOBObservability, | ||||
|                 role::build_prom_service_account, | ||||
|                 service_monitor::ServiceMonitor, | ||||
|             }, | ||||
|         }, | ||||
| @ -142,8 +152,26 @@ impl Grafana for K8sAnywhereTopology { | ||||
|         }; | ||||
| 
 | ||||
|         let client = self.k8s_client().await?; | ||||
|         let url = format!("{}:9091", self.get_domain("thanos-querier").await.unwrap()); | ||||
|     
 | ||||
|         let sa = self.build_service_account(); | ||||
|         //TODO finish this section 
 | ||||
|         //needs apply Api<Secret> or something
 | ||||
|         client.apply(&sa, Some(ns)).await?; | ||||
| 
 | ||||
|         let datasource = self.build_grafana_datasource(ns, &label_selector); | ||||
|         let token_request =self.get_token_request(); | ||||
|         //this wont work needs a new function for apply secret
 | ||||
|         client.apply(&token_request, Some(ns)).await?; | ||||
| 
 | ||||
|         let clusterrolebinding = self.build_cluster_rolebinding(); | ||||
| 
 | ||||
|         client.apply(&clusterrolebinding, Some(ns)).await?; | ||||
| 
 | ||||
|         let secret = self.build_token_secret(); | ||||
|         
 | ||||
|         client.apply(&secret, Some(ns)).await?; | ||||
| 
 | ||||
|         let datasource = self.build_grafana_datasource(ns, &label_selector, &url); | ||||
| 
 | ||||
|         client.apply(&datasource, Some(ns)).await?; | ||||
| 
 | ||||
| @ -334,35 +362,121 @@ impl K8sAnywhereTopology { | ||||
|             .clone() | ||||
|     } | ||||
| 
 | ||||
|     pub fn build_service_account(&self, name: &str, namespace: &str) -> ServiceAccount { | ||||
|         build_prom_service_account(name.to_string(), namespace.to_string()) | ||||
|     } | ||||
| 
 | ||||
|     pub fn build_cluster_rolebinding( | ||||
|         &self, | ||||
|         ns: &str, | ||||
|         account_name: &str, | ||||
|         role: &str, | ||||
|     ) -> ClusterRoleBinding { | ||||
|         ClusterRoleBinding { | ||||
|             metadata: ObjectMeta { | ||||
|                 name: Some(format!("{}-view-binding", account_name)), | ||||
|                 ..Default::default() | ||||
|             }, | ||||
|             role_ref: RoleRef { | ||||
|                 api_group: "rbac.authorization.k8s.io".into(), | ||||
|                 kind: "ClusterRole".into(), | ||||
|                 name: role.into(), | ||||
|             }, | ||||
|             subjects: Some(vec![Subject { | ||||
|                 kind: "ServiceAccount".into(), | ||||
|                 name: account_name.into(), | ||||
|                 namespace: Some(ns.into()), | ||||
|                 ..Default::default() | ||||
|             }]), | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     pub fn get_token_request(&self) -> TokenRequest { | ||||
|         TokenRequest { | ||||
|             spec: TokenRequestSpec { | ||||
|                 audiences: vec!["https://kubernetes.default.svc".to_string()], | ||||
|                 expiration_seconds: Some(3600), | ||||
|                 ..Default::default() | ||||
|             }, | ||||
|             ..Default::default() | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     pub fn build_token_secret(&self, token: &str, ns: &str) -> Secret { | ||||
|         Secret { | ||||
|             metadata: ObjectMeta { | ||||
|                 name: Some("grafana-credentials".into()), | ||||
|                 namespace: Some(ns.into()), | ||||
|                 ..Default::default() | ||||
|             }, | ||||
|             string_data: Some(std::collections::BTreeMap::from([( | ||||
|                 "PROMETHEUS_TOKEN".into(), | ||||
|                 format!("Bearer {}", token), | ||||
|             )])), | ||||
|             ..Default::default() | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     fn build_grafana_datasource( | ||||
|         &self, | ||||
|         ns: &str, | ||||
|         label_selector: &LabelSelector, | ||||
|         url: &str, | ||||
|     ) -> GrafanaDatasource { | ||||
|         let mut json_data = BTreeMap::new(); | ||||
|         json_data.insert("timeInterval".to_string(), "5s".to_string()); | ||||
|         //
 | ||||
|         // let graf_data_source = GrafanaDatasource {
 | ||||
|         //     metadata: ObjectMeta {
 | ||||
|         //         name: Some(format!("grafana-datasource-{}", ns)),
 | ||||
|         //         namespace: Some(ns.to_string()),
 | ||||
|         //         ..Default::default()
 | ||||
|         //     },
 | ||||
|         //     spec: GrafanaDatasourceSpec {
 | ||||
|         //         instance_selector: label_selector.clone(),
 | ||||
|         //         allow_cross_namespace_import: Some(false),
 | ||||
|         //         datasource: GrafanaDatasourceConfig {
 | ||||
|         //             access: "proxy".to_string(),
 | ||||
|         //             database: Some("prometheus".to_string()),
 | ||||
|         //             json_data: Some(json_data),
 | ||||
|         //             //this is fragile
 | ||||
|         //             name: format!("prometheus-{}-0", ns),
 | ||||
|         //             r#type: "prometheus".to_string(),
 | ||||
|         //             url: url.to_string(),
 | ||||
|         //             //url: format!("http://prometheus-operated.{}.svc.cluster.local:9090", ns),
 | ||||
|         //         },
 | ||||
|         //     },
 | ||||
|         // };
 | ||||
|         // graf_data_source
 | ||||
| 
 | ||||
|         let graf_data_source = GrafanaDatasource { | ||||
|         GrafanaDatasource { | ||||
|             metadata: ObjectMeta { | ||||
|                 name: Some(format!("grafana-datasource-{}", ns)), | ||||
|                 name: Some("thanos-prometheus".to_string()), | ||||
|                 namespace: Some(ns.to_string()), | ||||
|                 ..Default::default() | ||||
|             }, | ||||
|             spec: GrafanaDatasourceSpec { | ||||
|                 instance_selector: label_selector.clone(), | ||||
|                 allow_cross_namespace_import: Some(false), | ||||
|                 allow_cross_namespace_import: Some(true), | ||||
|                 datasource: GrafanaDatasourceConfig { | ||||
|                     access: "proxy".to_string(), | ||||
|                     database: Some("prometheus".to_string()), | ||||
|                     json_data: Some(json_data), | ||||
|                     //this is fragile
 | ||||
|                     name: format!("prometheus-{}-0", ns), | ||||
|                     name: "OpenShift-Thanos".to_string(), | ||||
|                     r#type: "prometheus".to_string(), | ||||
|                     url: format!("http://prometheus-operated.{}.svc.cluster.local:9090", ns), | ||||
|                     url: url.to_string(), | ||||
|                     database: None, | ||||
|                     json_data: Some(GrafanaDatasourceJsonData { | ||||
|                         time_interval: Some("60s".to_string()), | ||||
|                         http_header_name1: Some("Authorization".to_string()), | ||||
|                     }), | ||||
|                     secure_json_data: Some(GrafanaDatasourceSecureJsonData { | ||||
|                         http_header_value1: Some("Bearer eyJhbGc...".to_string()), | ||||
|                     }), | ||||
|                     is_default: Some(false), | ||||
|                     editable: Some(true), | ||||
|                     version: Some(1), | ||||
|                 }, | ||||
|             }, | ||||
|         }; | ||||
|         graf_data_source | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     fn build_grafana_dashboard( | ||||
|  | ||||
| @ -133,13 +133,43 @@ pub struct GrafanaDatasourceSpec { | ||||
| pub struct GrafanaDatasourceConfig { | ||||
|     pub access: String, | ||||
|     pub database: Option<String>, | ||||
|     #[serde(default, skip_serializing_if = "Option::is_none")] | ||||
|     pub json_data: Option<BTreeMap<String, String>>, | ||||
|     pub name: String, | ||||
|     pub r#type: String, | ||||
|     pub url: String, | ||||
|     /// Represents jsonData in the GrafanaDatasource spec
 | ||||
|     #[serde(default, skip_serializing_if = "Option::is_none")] | ||||
|     pub json_data: Option<GrafanaDatasourceJsonData>, | ||||
| 
 | ||||
|     /// Represents secureJsonData (secrets)
 | ||||
|     #[serde(default, skip_serializing_if = "Option::is_none")] | ||||
|     pub secure_json_data: Option<GrafanaDatasourceSecureJsonData>, | ||||
| 
 | ||||
|     #[serde(default, skip_serializing_if = "Option::is_none")] | ||||
|     pub is_default: Option<bool>, | ||||
| 
 | ||||
|     #[serde(default, skip_serializing_if = "Option::is_none")] | ||||
|     pub editable: Option<bool>, | ||||
| 
 | ||||
|     #[serde(default, skip_serializing_if = "Option::is_none")] | ||||
|     pub version: Option<i32>, | ||||
| } | ||||
| 
 | ||||
| #[derive(Serialize, Deserialize, Debug, Clone, JsonSchema)] | ||||
| #[serde(rename_all = "camelCase")] | ||||
| pub struct GrafanaDatasourceJsonData { | ||||
|     #[serde(default, skip_serializing_if = "Option::is_none")] | ||||
|     pub time_interval: Option<String>, | ||||
| 
 | ||||
|     #[serde(default, skip_serializing_if = "Option::is_none")] | ||||
|     pub http_header_name1: Option<String>, | ||||
| } | ||||
| 
 | ||||
| #[derive(Serialize, Deserialize, Debug, Clone, JsonSchema)] | ||||
| #[serde(rename_all = "camelCase")] | ||||
| pub struct GrafanaDatasourceSecureJsonData { | ||||
|     #[serde(default, skip_serializing_if = "Option::is_none")] | ||||
|     pub http_header_value1: Option<String>, | ||||
| } | ||||
| // ------------------------------------------------------------------------------------------------
 | ||||
| 
 | ||||
| #[derive(Serialize, Deserialize, Debug, Clone, JsonSchema, Default)] | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user