feat/impl_installable_crd_prometheus #170
@ -1,21 +1,12 @@
|
||||
use std::{
|
||||
collections::{BTreeMap, HashMap},
|
||||
process::Command,
|
||||
sync::Arc,
|
||||
};
|
||||
use std::{collections::BTreeMap, process::Command, sync::Arc};
|
||||
|
||||
use async_trait::async_trait;
|
||||
use base64::{Engine, engine::general_purpose};
|
||||
use k8s_openapi::api::{
|
||||
authentication::v1::{
|
||||
BoundObjectReference, TokenRequest, TokenRequestSpec, TokenRequestStatus,
|
||||
},
|
||||
core::v1::{Secret, ServiceAccount},
|
||||
core::v1::Secret,
|
||||
rbac::v1::{ClusterRoleBinding, RoleRef, Subject},
|
||||
};
|
||||
use kube::{
|
||||
Api,
|
||||
api::{GroupVersionKind, ObjectMeta, PostParams},
|
||||
};
|
||||
use kube::api::{DynamicObject, GroupVersionKind, ObjectMeta};
|
||||
use log::{debug, info, warn};
|
||||
use serde::Serialize;
|
||||
use tokio::sync::OnceCell;
|
||||
@ -35,14 +26,11 @@ use crate::{
|
||||
Grafana as GrafanaCRD, GrafanaCom, GrafanaDashboard,
|
||||
GrafanaDashboardDatasource, GrafanaDashboardSpec, GrafanaDatasource,
|
||||
GrafanaDatasourceConfig, GrafanaDatasourceJsonData,
|
||||
GrafanaDatasourceSecureJsonData, GrafanaDatasourceSpec, GrafanaSecretKeyRef,
|
||||
GrafanaSpec, GrafanaValueFrom, GrafanaValueSource,
|
||||
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,
|
||||
},
|
||||
},
|
||||
@ -148,24 +136,23 @@ impl Grafana for K8sAnywhereTopology {
|
||||
};
|
||||
}
|
||||
async fn install_grafana(&self) -> Result<PreparationOutcome, PreparationError> {
|
||||
debug!("install grafana");
|
||||
let ns = "grafana";
|
||||
|
||||
let mut label = BTreeMap::new();
|
||||
|
||||
label.insert("dashboards".to_string(), "grafana".to_string());
|
||||
|
||||
let label_selector = LabelSelector {
|
||||
match_labels: label.clone(),
|
||||
match_expressions: vec![],
|
||||
};
|
||||
debug!("getting client");
|
||||
|
||||
let client = self.k8s_client().await?;
|
||||
|
||||
info!("creating grafanas crd");
|
||||
let grafana = self.build_grafana(ns, &label);
|
||||
|
||||
client.apply(&grafana, Some(ns)).await?;
|
||||
|
||||
//TODO change this to a ensure ready or something better than just a timeout
|
||||
client
|
||||
.wait_until_deployment_ready(
|
||||
"grafana-grafana-deployment".to_string(),
|
||||
@ -175,16 +162,25 @@ impl Grafana for K8sAnywhereTopology {
|
||||
.await?;
|
||||
|
||||
let sa_name = "grafana-grafana-sa";
|
||||
|
||||
let token_secret_name = "grafana-sa-token-secret";
|
||||
|
||||
// let sa_token_secret = self.build_sa_token_secret(token_secret_name, sa_name, ns);
|
||||
//
|
||||
// client.apply(&sa_token_secret, Some(ns)).await?;
|
||||
let sa_token_secret = self.build_sa_token_secret(token_secret_name, sa_name, ns);
|
||||
|
||||
let secret = self.build_token_secret(token_secret_name, ns).await;
|
||||
client.apply(&secret, Some(ns)).await?;
|
||||
let token_request_status = self.create_service_account_token(sa_name, ns).await?;
|
||||
client.apply(&sa_token_secret, Some(ns)).await?;
|
||||
let secret_gvk = GroupVersionKind {
|
||||
group: "".to_string(),
|
||||
version: "v1".to_string(),
|
||||
kind: "Secret".to_string(),
|
||||
};
|
||||
|
||||
let secret = client
|
||||
.get_resource_json_value(token_secret_name, Some(ns), &secret_gvk)
|
||||
.await?;
|
||||
|
||||
let token = format!(
|
||||
"Bearer {}",
|
||||
self.extract_and_normalize_token(&secret).unwrap()
|
||||
);
|
||||
|
||||
debug!("creating grafana clusterrole binding");
|
||||
|
||||
@ -195,8 +191,6 @@ impl Grafana for K8sAnywhereTopology {
|
||||
|
||||
debug!("creating grafana datasource crd");
|
||||
|
||||
// let token_str = format!("Bearer {}", token.token);
|
||||
|
||||
let thanos_url = format!(
|
||||
"https://{}",
|
||||
self.get_domain("thanos-querier-openshift-monitoring")
|
||||
@ -209,7 +203,7 @@ impl Grafana for K8sAnywhereTopology {
|
||||
ns,
|
||||
&label_selector,
|
||||
&thanos_url,
|
||||
&token_request_status.token, // Pass the secret name here
|
||||
&token,
|
||||
);
|
||||
|
||||
client.apply(&thanos_openshift_datasource, Some(ns)).await?;
|
||||
@ -398,8 +392,21 @@ impl K8sAnywhereTopology {
|
||||
.clone()
|
||||
}
|
||||
|
||||
pub fn build_service_account(&self, name: &str, namespace: &str) -> ServiceAccount {
|
||||
build_prom_service_account(name.to_string(), namespace.to_string())
|
||||
fn extract_and_normalize_token(&self, secret: &DynamicObject) -> Option<String> {
|
||||
let token_b64 = secret
|
||||
.data
|
||||
.get("token")
|
||||
.or_else(|| secret.data.get("data").and_then(|d| d.get("token")))
|
||||
.and_then(|v| v.as_str())?;
|
||||
|
||||
let bytes = general_purpose::STANDARD.decode(token_b64).ok()?;
|
||||
|
||||
let s = String::from_utf8(bytes).ok()?;
|
||||
|
||||
let cleaned = s
|
||||
.trim_matches(|c: char| c.is_whitespace() || c == '\0')
|
||||
.to_string();
|
||||
Some(cleaned)
|
||||
}
|
||||
|
||||
pub fn build_cluster_rolebinding(
|
||||
@ -451,69 +458,13 @@ impl K8sAnywhereTopology {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_token_request(&self, ns: &str) -> TokenRequest {
|
||||
debug!("building token request");
|
||||
TokenRequest {
|
||||
metadata: ObjectMeta {
|
||||
namespace: Some(ns.to_string()),
|
||||
..Default::default()
|
||||
},
|
||||
spec: TokenRequestSpec {
|
||||
audiences: vec!["https://kubernetes.default.svc".to_string()],
|
||||
expiration_seconds: Some(3600),
|
||||
bound_object_ref: Some(BoundObjectReference {
|
||||
kind: Some("Secret".to_string()),
|
||||
name: Some("grafana-sa-token-secret".to_string()),
|
||||
..Default::default()
|
||||
}),
|
||||
},
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn create_service_account_token(
|
||||
&self,
|
||||
service_account_name: &str,
|
||||
ns: &str,
|
||||
) -> Result<TokenRequestStatus, PreparationError> {
|
||||
debug!("creating service account token");
|
||||
let token_request = self.get_token_request(ns);
|
||||
let client = self.k8s_client().await?;
|
||||
let pp = PostParams::default();
|
||||
let token_requests_api = client.service_account_api(ns).await;
|
||||
|
||||
let data = serde_json::to_vec(&token_request).unwrap();
|
||||
|
||||
let created_token_request = token_requests_api
|
||||
.create_subresource::<TokenRequest>("token", service_account_name, &pp, data)
|
||||
.await?;
|
||||
|
||||
let status = created_token_request
|
||||
.status
|
||||
.ok_or_else(|| PreparationError::new("missing token request status".to_string()))?;
|
||||
|
||||
Ok(status)
|
||||
}
|
||||
|
||||
pub async fn build_token_secret(&self, secret_name: &str, ns: &str) -> Secret {
|
||||
Secret {
|
||||
metadata: ObjectMeta {
|
||||
name: Some(secret_name.into()),
|
||||
namespace: Some(ns.into()),
|
||||
..Default::default()
|
||||
},
|
||||
string_data: None,
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
|
||||
fn build_grafana_datasource(
|
||||
&self,
|
||||
name: &str,
|
||||
ns: &str,
|
||||
label_selector: &LabelSelector,
|
||||
url: &str,
|
||||
token: &str, // Pass in the secret name
|
||||
token: &str,
|
||||
) -> GrafanaDatasource {
|
||||
let mut json_data = BTreeMap::new();
|
||||
json_data.insert("timeInterval".to_string(), "5s".to_string());
|
||||
|
@ -105,7 +105,7 @@ pub struct GrafanaDashboardSpec {
|
||||
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub datasources: Option<Vec<GrafanaDashboardDatasource>>,
|
||||
|
||||
|
||||
pub instance_selector: LabelSelector,
|
||||
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
@ -156,7 +156,6 @@ pub struct GrafanaDatasourceSpec {
|
||||
pub values_from: Option<Vec<GrafanaValueFrom>>,
|
||||
}
|
||||
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, JsonSchema)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct GrafanaValueFrom {
|
||||
|
@ -11,7 +11,9 @@ use std::process::Command;
|
||||
use crate::modules::monitoring::kube_prometheus::crd::crd_alertmanager_config::CRDPrometheus;
|
||||
use crate::modules::monitoring::kube_prometheus::crd::crd_default_rules::build_default_application_rules;
|
||||
use crate::modules::monitoring::kube_prometheus::crd::crd_grafana::{
|
||||
Grafana, GrafanaDashboard, GrafanaDashboardSpec, GrafanaDatasource, GrafanaDatasourceConfig, GrafanaDatasourceJsonData, GrafanaDatasourceSpec, GrafanaSecretKeyRef, GrafanaSpec, GrafanaValueFrom, GrafanaValueSource
|
||||
Grafana, GrafanaDashboard, GrafanaDashboardSpec, GrafanaDatasource, GrafanaDatasourceConfig,
|
||||
GrafanaDatasourceJsonData, GrafanaDatasourceSpec, GrafanaSecretKeyRef, GrafanaSpec,
|
||||
GrafanaValueFrom, GrafanaValueSource,
|
||||
};
|
||||
use crate::modules::monitoring::kube_prometheus::crd::crd_prometheus_rules::{
|
||||
PrometheusRule, PrometheusRuleSpec, RuleGroup,
|
||||
|
Loading…
Reference in New Issue
Block a user