feat: added a default config structure for kubeprometheus chart
This commit is contained in:
parent
8d3d167848
commit
87b1b15d57
@ -1,4 +1,3 @@
|
|||||||
pub mod monitoring_alerting;
|
|
||||||
mod ha_cluster;
|
mod ha_cluster;
|
||||||
mod host_binding;
|
mod host_binding;
|
||||||
mod http;
|
mod http;
|
||||||
|
@ -1,108 +0,0 @@
|
|||||||
use std::sync::Arc;
|
|
||||||
|
|
||||||
use log::warn;
|
|
||||||
use tokio::sync::OnceCell;
|
|
||||||
|
|
||||||
use k8s_openapi::api::core::v1::Pod;
|
|
||||||
use kube::{
|
|
||||||
Client,
|
|
||||||
api::{Api, ListParams},
|
|
||||||
};
|
|
||||||
|
|
||||||
use async_trait::async_trait;
|
|
||||||
|
|
||||||
use crate::{
|
|
||||||
interpret::{InterpretError, Outcome},
|
|
||||||
inventory::Inventory,
|
|
||||||
maestro::Maestro,
|
|
||||||
modules::monitoring::monitoring_alerting::MonitoringAlertingStackScore,
|
|
||||||
score::Score,
|
|
||||||
};
|
|
||||||
|
|
||||||
use super::{HelmCommand, K8sAnywhereTopology, Topology, k8s::K8sClient};
|
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
|
||||||
struct MonitoringState {
|
|
||||||
message: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct MonitoringAlertingTopology {
|
|
||||||
monitoring_state: OnceCell<Option<MonitoringState>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl MonitoringAlertingTopology {
|
|
||||||
pub fn new() -> Self {
|
|
||||||
Self {
|
|
||||||
monitoring_state: OnceCell::new(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn get_monitoring_state(&self) -> Result<Option<MonitoringState>, InterpretError> {
|
|
||||||
let client = Client::try_default()
|
|
||||||
.await
|
|
||||||
.map_err(|e| InterpretError::new(format!("Kubernetes client error: {}", e)))?;
|
|
||||||
|
|
||||||
for ns in &["monitoring", "openshift-monitoring"] {
|
|
||||||
let pods: Api<Pod> = Api::namespaced(client.clone(), ns);
|
|
||||||
//TODO hardcoding the label is a problem
|
|
||||||
//check all pods are ready
|
|
||||||
let lp = ListParams::default().labels("app.kubernetes.io/name=prometheus");
|
|
||||||
|
|
||||||
match pods.list(&lp).await {
|
|
||||||
Ok(pod_list) => {
|
|
||||||
for p in pod_list.items {
|
|
||||||
if let Some(status) = p.status {
|
|
||||||
if let Some(conditions) = status.conditions {
|
|
||||||
if conditions
|
|
||||||
.iter()
|
|
||||||
.any(|c| c.type_ == "Ready" && c.status == "True")
|
|
||||||
{
|
|
||||||
return Ok(Some(MonitoringState {
|
|
||||||
message: format!(
|
|
||||||
"Prometheus is ready in namespace: {}",
|
|
||||||
ns
|
|
||||||
),
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Err(e) => {
|
|
||||||
warn!("Failed to query pods in ns {}: {}", ns, e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(None)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: Topology> Clone for Box<dyn Score<T>> {
|
|
||||||
fn clone(&self) -> Box<dyn Score<T>> {
|
|
||||||
self.clone_box()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[async_trait]
|
|
||||||
impl Topology for MonitoringAlertingTopology {
|
|
||||||
fn name(&self) -> &str {
|
|
||||||
"MonitoringAlertingTopology"
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn ensure_ready(&self) -> Result<Outcome, InterpretError> {
|
|
||||||
if let Some(state) = self.get_monitoring_state().await? {
|
|
||||||
// Monitoring stack is already ready — stop app.
|
|
||||||
println!("{}", state.message);
|
|
||||||
std::process::exit(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Monitoring not found — proceed with installation.
|
|
||||||
Ok(Outcome::success(
|
|
||||||
"Monitoring stack installation started.".to_string(),
|
|
||||||
))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl HelmCommand for MonitoringAlertingTopology {}
|
|
@ -159,7 +159,8 @@ impl<T: Topology + HelmCommand> Interpret<T> for HelmChartInterpret {
|
|||||||
|
|
||||||
self.add_repo()?;
|
self.add_repo()?;
|
||||||
|
|
||||||
let helm_executor = DefaultHelmExecutor::new();
|
let helm_path = NonBlankString::from_str("helm").unwrap();
|
||||||
|
let helm_executor = DefaultHelmExecutor::new_with_opts(&helm_path, None, 9000, false, false);
|
||||||
|
|
||||||
let mut helm_options = Vec::new();
|
let mut helm_options = Vec::new();
|
||||||
if self.score.create_namespace {
|
if self.score.create_namespace {
|
||||||
|
37
harmony/src/modules/monitoring/config.rs
Normal file
37
harmony/src/modules/monitoring/config.rs
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct KubePrometheusConfig {
|
||||||
|
pub namespace: String,
|
||||||
|
pub node_exporter: bool,
|
||||||
|
pub alert_manager: bool,
|
||||||
|
pub prometheus: bool,
|
||||||
|
pub grafana: bool,
|
||||||
|
pub windows_monitoring: bool,
|
||||||
|
pub kubernetes_service_monitors: bool,
|
||||||
|
pub kubelet: bool,
|
||||||
|
pub kube_controller_manager: bool,
|
||||||
|
pub kube_etcd: bool,
|
||||||
|
pub kube_proxy: bool,
|
||||||
|
pub kube_state_metrics: bool,
|
||||||
|
pub prometheus_operator: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for KubePrometheusConfig {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
namespace: "monitoring".into(),
|
||||||
|
node_exporter: false,
|
||||||
|
alert_manager: false,
|
||||||
|
prometheus: true,
|
||||||
|
grafana: true,
|
||||||
|
windows_monitoring: false,
|
||||||
|
kubernetes_service_monitors: true,
|
||||||
|
kubelet: true,
|
||||||
|
kube_controller_manager: true,
|
||||||
|
kube_etcd: true,
|
||||||
|
kube_proxy: true,
|
||||||
|
kube_state_metrics: true,
|
||||||
|
prometheus_operator: true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,10 +1,12 @@
|
|||||||
use std::str::FromStr;
|
use std::{collections::HashMap, str::FromStr};
|
||||||
|
|
||||||
use non_blank_string_rs::NonBlankString;
|
use non_blank_string_rs::NonBlankString;
|
||||||
|
|
||||||
use crate::modules::helm::chart::HelmChartScore;
|
use crate::modules::helm::chart::HelmChartScore;
|
||||||
|
|
||||||
pub fn kube_prometheus_score(ns: &str) -> HelmChartScore {
|
use super::config::KubePrometheusConfig;
|
||||||
|
|
||||||
|
pub fn kube_prometheus_score(config: KubePrometheusConfig) -> HelmChartScore {
|
||||||
//TODO this should be make into a rule with default formatting that can be easily passed as a vec
|
//TODO this should be make into a rule with default formatting that can be easily passed as a vec
|
||||||
//to the overrides or something leaving the user to deal with formatting here seems bad
|
//to the overrides or something leaving the user to deal with formatting here seems bad
|
||||||
let values = r#"
|
let values = r#"
|
||||||
@ -32,8 +34,31 @@ additionalPrometheusRulesMap:
|
|||||||
description: The PVC {{ $labels.persistentvolumeclaim }} in namespace {{ $labels.namespace }} is predicted to fill over 95% in less than 2 days.
|
description: The PVC {{ $labels.persistentvolumeclaim }} in namespace {{ $labels.namespace }} is predicted to fill over 95% in less than 2 days.
|
||||||
title: PVC {{ $labels.persistentvolumeclaim }} in namespace {{ $labels.namespace }} will fill over 95% in less than 2 days
|
title: PVC {{ $labels.persistentvolumeclaim }} in namespace {{ $labels.namespace }} will fill over 95% in less than 2 days
|
||||||
"#;
|
"#;
|
||||||
|
let mut values_overrides: HashMap<NonBlankString, String> = HashMap::new();
|
||||||
|
|
||||||
|
|
||||||
|
macro_rules! insert_flag {
|
||||||
|
($key:expr, $val:expr) => {
|
||||||
|
values_overrides.insert(NonBlankString::from_str($key).unwrap(), $val.to_string());
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
insert_flag!("nodeExporter.enabled", config.node_exporter);
|
||||||
|
insert_flag!("windowsMonitoring.enabled", config.windows_monitoring);
|
||||||
|
insert_flag!("grafana.enabled", config.grafana);
|
||||||
|
insert_flag!("alertmanager.enabled", config.alert_manager);
|
||||||
|
insert_flag!("prometheus.enabled", config.prometheus);
|
||||||
|
insert_flag!("kubernetes_service_monitors.enabled", config.kubernetes_service_monitors);
|
||||||
|
insert_flag!("kubelet.enabled", config.kubelet);
|
||||||
|
insert_flag!("kubeControllerManager.enabled", config.kube_controller_manager);
|
||||||
|
insert_flag!("kubeProxy.enabled", config.kube_proxy);
|
||||||
|
insert_flag!("kubeEtcd.enabled", config.kube_etcd);
|
||||||
|
insert_flag!("kubeStateMetrics.enabled", config.kube_state_metrics);
|
||||||
|
insert_flag!("prometheusOperator.enabled", config.prometheus_operator);
|
||||||
|
|
||||||
|
|
||||||
HelmChartScore {
|
HelmChartScore {
|
||||||
namespace: Some(NonBlankString::from_str(ns).unwrap()),
|
namespace: Some(NonBlankString::from_str(&config.namespace).unwrap()),
|
||||||
release_name: NonBlankString::from_str("kube-prometheus").unwrap(),
|
release_name: NonBlankString::from_str("kube-prometheus").unwrap(),
|
||||||
chart_name: NonBlankString::from_str(
|
chart_name: NonBlankString::from_str(
|
||||||
"oci://ghcr.io/prometheus-community/charts/kube-prometheus-stack", //use kube prometheus chart which includes grafana, prometheus, alert
|
"oci://ghcr.io/prometheus-community/charts/kube-prometheus-stack", //use kube prometheus chart which includes grafana, prometheus, alert
|
||||||
@ -41,7 +66,7 @@ additionalPrometheusRulesMap:
|
|||||||
)
|
)
|
||||||
.unwrap(),
|
.unwrap(),
|
||||||
chart_version: None,
|
chart_version: None,
|
||||||
values_overrides: None,
|
values_overrides: Some(values_overrides),
|
||||||
values_yaml: Some(values.to_string()),
|
values_yaml: Some(values.to_string()),
|
||||||
create_namespace: true,
|
create_namespace: true,
|
||||||
install_only: true,
|
install_only: true,
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
pub mod monitoring_alerting;
|
pub mod monitoring_alerting;
|
||||||
|
mod config;
|
||||||
mod kube_prometheus;
|
mod kube_prometheus;
|
||||||
|
|
||||||
|
@ -3,142 +3,45 @@ use log::info;
|
|||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
data::{Id, Version},
|
interpret::Interpret,
|
||||||
interpret::{Interpret, InterpretError, InterpretName, InterpretStatus, Outcome},
|
modules::helm::chart::HelmChartScore,
|
||||||
inventory::Inventory,
|
score::{CloneBoxScore, Score, SerializeScore},
|
||||||
maestro::Maestro,
|
topology::{HelmCommand, Topology},
|
||||||
score::{CloneBoxScore, Score},
|
|
||||||
topology::{HelmCommand, Topology, monitoring_alerting::MonitoringAlertingTopology},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::kube_prometheus::kube_prometheus_score;
|
use super::{config::KubePrometheusConfig, kube_prometheus::kube_prometheus_score};
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug, Clone, Serialize)]
|
||||||
pub struct MonitoringAlertingStackScore {
|
pub struct KubePrometheusStackScore {
|
||||||
//TODO add documenation to explain why its here
|
pub monitoring_stack: HelmChartScore,
|
||||||
//keeps it open for the end user to specify which stack they want
|
|
||||||
//if it isnt default kube-prometheus
|
|
||||||
pub monitoring_stack: Vec<Box<dyn Score<MonitoringAlertingTopology>>>,
|
|
||||||
pub namespace: String,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MonitoringAlertingStackScore {
|
impl KubePrometheusStackScore {
|
||||||
pub fn new(
|
pub fn new(monitoring_stack: HelmChartScore) -> Self {
|
||||||
monitoring_stack: Vec<Box<dyn Score<MonitoringAlertingTopology>>>,
|
|
||||||
namespace: String,
|
|
||||||
) -> Self {
|
|
||||||
Self {
|
Self {
|
||||||
monitoring_stack,
|
monitoring_stack,
|
||||||
namespace,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for MonitoringAlertingStackScore {
|
impl Default for KubePrometheusStackScore {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
let ns = "monitoring";
|
let config = KubePrometheusConfig::default();
|
||||||
|
let monitoring_stack = kube_prometheus_score(config);
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
monitoring_stack: vec![Box::new(kube_prometheus_score(ns))],
|
monitoring_stack
|
||||||
namespace: ns.to_string(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl Clone for MonitoringAlertingStackScore {
|
|
||||||
fn clone(&self) -> Self {
|
|
||||||
Self {
|
|
||||||
monitoring_stack: self
|
|
||||||
.monitoring_stack
|
|
||||||
.iter()
|
|
||||||
.map(|s| s.clone_box())
|
|
||||||
.collect(),
|
|
||||||
namespace: self.namespace.clone(),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Serialize for MonitoringAlertingStackScore {
|
impl<T: Topology + HelmCommand> Score<T> for KubePrometheusStackScore {
|
||||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
|
||||||
where
|
|
||||||
S: serde::Serializer,
|
|
||||||
{
|
|
||||||
use serde::ser::SerializeStruct;
|
|
||||||
let mut s = serializer.serialize_struct("MonitoringAlertingStackScore", 1)?;
|
|
||||||
let monitoring_values: Vec<_> = self
|
|
||||||
.monitoring_stack
|
|
||||||
.iter()
|
|
||||||
.map(|m| m.serialize())
|
|
||||||
.collect();
|
|
||||||
s.serialize_field("monitoring", &monitoring_values)?;
|
|
||||||
s.end()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T:Topology> Score<T> for MonitoringAlertingStackScore {
|
|
||||||
fn create_interpret(&self) -> Box<dyn Interpret<T>> {
|
|
||||||
Box::new(MonitoringAlertingStackInterpret {
|
|
||||||
score: MonitoringAlertingStackScore {
|
|
||||||
monitoring_stack: self
|
|
||||||
.monitoring_stack
|
|
||||||
.iter()
|
|
||||||
.map(|s| s.clone_box())
|
|
||||||
.collect(),
|
|
||||||
namespace: self.namespace.clone(),
|
|
||||||
},
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
fn name(&self) -> String {
|
fn name(&self) -> String {
|
||||||
format!("MonitoringAlertingStackScore")
|
format!("MonitoringAlertingStackScore")
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
fn create_interpret(&self) -> Box<dyn Interpret<T>> {
|
||||||
struct MonitoringAlertingStackInterpret {
|
self.monitoring_stack.create_interpret()
|
||||||
pub score: MonitoringAlertingStackScore,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[async_trait]
|
|
||||||
impl <T: Topology> Interpret<T> for MonitoringAlertingStackInterpret {
|
|
||||||
async fn execute(
|
|
||||||
&self,
|
|
||||||
_inventory: &Inventory,
|
|
||||||
_topology: &T,
|
|
||||||
) -> Result<Outcome, InterpretError> {
|
|
||||||
let inventory = Inventory::autoload();
|
|
||||||
let topology = MonitoringAlertingTopology::new();
|
|
||||||
let maestro = match Maestro::initialize(inventory, topology).await {
|
|
||||||
Ok(m) => m,
|
|
||||||
Err(e) => {
|
|
||||||
println!("failed to initialize Maestro: {}", e);
|
|
||||||
std::process::exit(1);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let scores_vec = self.score.monitoring_stack.clone();
|
|
||||||
for s in scores_vec{
|
|
||||||
info!("Running: {}", s.name());
|
|
||||||
maestro.interpret(s).await?;
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(Outcome::success(format!(
|
|
||||||
"monitoring stack installed in {} namespace",
|
|
||||||
self.score.namespace
|
|
||||||
)))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_name(&self) -> InterpretName {
|
|
||||||
todo!()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_version(&self) -> Version {
|
|
||||||
todo!()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_status(&self) -> InterpretStatus {
|
|
||||||
todo!()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_children(&self) -> Vec<Id> {
|
|
||||||
todo!()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user