feat/impl_installable_crd_prometheus #170
@ -1,7 +1,15 @@
|
|||||||
use std::{collections::BTreeMap, process::Command, sync::Arc};
|
use std::{collections::BTreeMap, process::Command, sync::Arc};
|
||||||
|
|
||||||
use async_trait::async_trait;
|
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 log::{debug, info, warn};
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
use tokio::sync::OnceCell;
|
use tokio::sync::OnceCell;
|
||||||
@ -19,12 +27,14 @@ use crate::{
|
|||||||
crd_alertmanager_config::CRDPrometheus,
|
crd_alertmanager_config::CRDPrometheus,
|
||||||
crd_grafana::{
|
crd_grafana::{
|
||||||
Grafana as GrafanaCRD, GrafanaDashboard, GrafanaDashboardSpec,
|
Grafana as GrafanaCRD, GrafanaDashboard, GrafanaDashboardSpec,
|
||||||
GrafanaDatasource, GrafanaDatasourceConfig, GrafanaDatasourceSpec, GrafanaSpec,
|
GrafanaDatasource, GrafanaDatasourceConfig, GrafanaDatasourceJsonData,
|
||||||
|
GrafanaDatasourceSecureJsonData, GrafanaDatasourceSpec, GrafanaSpec,
|
||||||
},
|
},
|
||||||
crd_prometheuses::LabelSelector,
|
crd_prometheuses::LabelSelector,
|
||||||
grafana_default_dashboard::build_default_dashboard,
|
grafana_default_dashboard::build_default_dashboard,
|
||||||
prometheus_operator::prometheus_operator_helm_chart_score,
|
prometheus_operator::prometheus_operator_helm_chart_score,
|
||||||
rhob_alertmanager_config::RHOBObservability,
|
rhob_alertmanager_config::RHOBObservability,
|
||||||
|
role::build_prom_service_account,
|
||||||
service_monitor::ServiceMonitor,
|
service_monitor::ServiceMonitor,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -142,8 +152,26 @@ impl Grafana for K8sAnywhereTopology {
|
|||||||
};
|
};
|
||||||
|
|
||||||
let client = self.k8s_client().await?;
|
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?;
|
client.apply(&datasource, Some(ns)).await?;
|
||||||
|
|
||||||
@ -334,35 +362,121 @@ impl K8sAnywhereTopology {
|
|||||||
.clone()
|
.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(
|
fn build_grafana_datasource(
|
||||||
&self,
|
&self,
|
||||||
ns: &str,
|
ns: &str,
|
||||||
label_selector: &LabelSelector,
|
label_selector: &LabelSelector,
|
||||||
|
url: &str,
|
||||||
) -> GrafanaDatasource {
|
) -> GrafanaDatasource {
|
||||||
let mut json_data = BTreeMap::new();
|
let mut json_data = BTreeMap::new();
|
||||||
json_data.insert("timeInterval".to_string(), "5s".to_string());
|
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 {
|
metadata: ObjectMeta {
|
||||||
name: Some(format!("grafana-datasource-{}", ns)),
|
name: Some("thanos-prometheus".to_string()),
|
||||||
namespace: Some(ns.to_string()),
|
namespace: Some(ns.to_string()),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
spec: GrafanaDatasourceSpec {
|
spec: GrafanaDatasourceSpec {
|
||||||
instance_selector: label_selector.clone(),
|
instance_selector: label_selector.clone(),
|
||||||
allow_cross_namespace_import: Some(false),
|
allow_cross_namespace_import: Some(true),
|
||||||
datasource: GrafanaDatasourceConfig {
|
datasource: GrafanaDatasourceConfig {
|
||||||
access: "proxy".to_string(),
|
access: "proxy".to_string(),
|
||||||
database: Some("prometheus".to_string()),
|
name: "OpenShift-Thanos".to_string(),
|
||||||
json_data: Some(json_data),
|
|
||||||
//this is fragile
|
|
||||||
name: format!("prometheus-{}-0", ns),
|
|
||||||
r#type: "prometheus".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(
|
fn build_grafana_dashboard(
|
||||||
|
@ -133,13 +133,43 @@ pub struct GrafanaDatasourceSpec {
|
|||||||
pub struct GrafanaDatasourceConfig {
|
pub struct GrafanaDatasourceConfig {
|
||||||
pub access: String,
|
pub access: String,
|
||||||
pub database: Option<String>,
|
pub database: Option<String>,
|
||||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
|
||||||
pub json_data: Option<BTreeMap<String, String>>,
|
|
||||||
pub name: String,
|
pub name: String,
|
||||||
pub r#type: String,
|
pub r#type: String,
|
||||||
pub url: 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)]
|
#[derive(Serialize, Deserialize, Debug, Clone, JsonSchema, Default)]
|
||||||
|
Loading…
Reference in New Issue
Block a user