wip: trying to install the helm chart for HelmKubePrometheus

This commit is contained in:
Willem 2025-06-19 16:40:00 -04:00 committed by tahahawa
parent 50e38fed0a
commit a41230ac7b
7 changed files with 113 additions and 42 deletions

View File

@ -1,6 +1,10 @@
use harmony::{ use harmony::{
inventory::Inventory, maestro::Maestro, inventory::Inventory,
modules::monitoring::{alert_channel::discord_alert_channel::DiscordWebhook, kube_prometheus::helm_prometheus_alert_score::HelmPrometheusAlertingScore}, maestro::Maestro,
modules::monitoring::{
alert_channel::discord_alert_channel::DiscordWebhook,
kube_prometheus::helm_prometheus_alert_score::HelmPrometheusAlertingScore,
},
topology::{K8sAnywhereTopology, Url}, topology::{K8sAnywhereTopology, Url},
}; };
@ -10,7 +14,9 @@ async fn main() {
name: "test-discord".to_string(), name: "test-discord".to_string(),
url: Url::Url(url::Url::parse("https://discord.i.dont.exist.com").unwrap()), url: Url::Url(url::Url::parse("https://discord.i.dont.exist.com").unwrap()),
}; };
let alerting_score = HelmPrometheusAlertingScore { receivers: vec![Box::new(discord_receiver)] }; let alerting_score = HelmPrometheusAlertingScore {
receivers: vec![Box::new(discord_receiver)],
};
let mut maestro = Maestro::<K8sAnywhereTopology>::initialize( let mut maestro = Maestro::<K8sAnywhereTopology>::initialize(
Inventory::autoload(), Inventory::autoload(),
K8sAnywhereTopology::from_env(), K8sAnywhereTopology::from_env(),
@ -18,12 +24,6 @@ async fn main() {
.await .await
.unwrap(); .unwrap();
//let monitoring = MonitoringAlertingScore {
// alert_receivers: vec![],
// alert_rules: vec![],
// scrape_targets: vec![],
//};
//maestro.register_all(vec![Box::new(monitoring)]);
maestro.register_all(vec![Box::new(alerting_score)]); maestro.register_all(vec![Box::new(alerting_score)]);
harmony_cli::init(maestro, None).await.unwrap(); harmony_cli::init(maestro, None).await.unwrap();
} }

View File

@ -2,6 +2,8 @@ use async_trait::async_trait;
use crate::interpret::InterpretError; use crate::interpret::InterpretError;
use super::oberservability::monitoring::AlertSender;
#[async_trait] #[async_trait]
pub trait Installable { pub trait Installable {
async fn ensure_installed(&self) -> Result<(), InterpretError>; async fn ensure_installed(&self) -> Result<(), InterpretError>;

View File

@ -7,7 +7,11 @@ use crate::{
topology::{Topology, installable::Installable}, topology::{Topology, installable::Installable},
}; };
pub trait AlertSender: Send + Sync + std::fmt::Debug + Installable {} #[async_trait]
pub trait AlertSender: Send + Sync + std::fmt::Debug + Installable {
fn name(&self) -> String;
async fn install(&self) -> Result<Outcome, InterpretError>;
}
#[derive(Debug)] #[derive(Debug)]
pub struct AlertingInterpret<S: AlertSender> { pub struct AlertingInterpret<S: AlertSender> {
@ -16,7 +20,7 @@ pub struct AlertingInterpret<S: AlertSender> {
} }
#[async_trait] #[async_trait]
impl<S: AlertSender, T: Topology> Interpret<T> for AlertingInterpret<S> { impl<S: AlertSender + Installable, T: Topology> Interpret<T> for AlertingInterpret<S> {
async fn execute( async fn execute(
&self, &self,
inventory: &Inventory, inventory: &Inventory,
@ -25,7 +29,11 @@ impl<S: AlertSender, T: Topology> Interpret<T> for AlertingInterpret<S> {
for receiver in self.receivers.iter() { for receiver in self.receivers.iter() {
receiver.install(&self.sender).await?; receiver.install(&self.sender).await?;
} }
todo!() self.sender.ensure_installed();
Ok(Outcome::success(format!(
"successfully installed alert sender {}",
self.sender.name()
)))
} }
fn get_name(&self) -> InterpretName { fn get_name(&self) -> InterpretName {
@ -47,7 +55,7 @@ impl<S: AlertSender, T: Topology> Interpret<T> for AlertingInterpret<S> {
#[async_trait] #[async_trait]
pub trait AlertReceiver<S: AlertSender>: std::fmt::Debug + Send + Sync { pub trait AlertReceiver<S: AlertSender>: std::fmt::Debug + Send + Sync {
async fn install(&self, sender: &S) -> Result<(), InterpretError>; async fn install(&self, sender: &S) -> Result<Outcome, InterpretError>;
fn clone_box(&self) -> Box<dyn AlertReceiver<S>>; fn clone_box(&self) -> Box<dyn AlertReceiver<S>>;
} }

View File

@ -2,7 +2,7 @@ use async_trait::async_trait;
use serde_yaml::{Mapping, Value}; use serde_yaml::{Mapping, Value};
use crate::{ use crate::{
interpret::InterpretError, interpret::{InterpretError, Outcome},
modules::monitoring::kube_prometheus::{ modules::monitoring::kube_prometheus::{
prometheus::{Prometheus, PrometheusReceiver}, prometheus::{Prometheus, PrometheusReceiver},
types::AlertChannelConfig, types::AlertChannelConfig,
@ -18,7 +18,7 @@ pub struct DiscordWebhook {
#[async_trait] #[async_trait]
impl AlertReceiver<Prometheus> for DiscordWebhook { impl AlertReceiver<Prometheus> for DiscordWebhook {
async fn install(&self, sender: &Prometheus) -> Result<(), InterpretError> { async fn install(&self, sender: &Prometheus) -> Result<Outcome, InterpretError> {
sender.install_receiver(self).await sender.install_receiver(self).await
} }
fn clone_box(&self) -> Box<dyn AlertReceiver<Prometheus>> { fn clone_box(&self) -> Box<dyn AlertReceiver<Prometheus>> {
@ -29,8 +29,11 @@ impl AlertReceiver<Prometheus> for DiscordWebhook {
#[async_trait] #[async_trait]
impl PrometheusReceiver for DiscordWebhook { impl PrometheusReceiver for DiscordWebhook {
//TODO not return a tuple //TODO not return a tuple
async fn receiver_config(&self) -> (Option<Value>, Value, Value) { fn name(&self) -> String {
(self.alert_channel_global_config().await, self.alert_channel_receiver().await, self.alert_channel_route().await) self.name.clone()
}
async fn receiver_config(&self) -> Value {
self.alert_channel_receiver().await
} }
} }

View File

@ -4,9 +4,7 @@ use std::str::FromStr;
use crate::modules::helm::chart::HelmChartScore; use crate::modules::helm::chart::HelmChartScore;
pub fn kube_prometheus_helm_chart_score() -> HelmChartScore { pub fn kube_prometheus_helm_chart_score(config: KubePrometheusConfig) -> HelmChartScore {
let config = KubePrometheusConfig::new();
//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 default_rules = config.default_rules.to_string(); let default_rules = config.default_rules.to_string();

View File

@ -1,9 +1,12 @@
use std::sync::Mutex;
use serde::Serialize; use serde::Serialize;
use crate::{ use crate::{
score::Score, score::Score,
topology::{ topology::{
HelmCommand, Topology, HelmCommand, Topology,
installable::Installable,
oberservability::monitoring::{AlertReceiver, AlertingInterpret}, oberservability::monitoring::{AlertReceiver, AlertingInterpret},
}, },
}; };
@ -15,13 +18,16 @@ pub struct HelmPrometheusAlertingScore {
pub receivers: Vec<Box<dyn AlertReceiver<Prometheus>>>, pub receivers: Vec<Box<dyn AlertReceiver<Prometheus>>>,
} }
impl<T: Topology + HelmCommand> Score<T> for HelmPrometheusAlertingScore { impl<T: Topology + HelmCommand + Installable> Score<T> for HelmPrometheusAlertingScore {
fn create_interpret(&self) -> Box<dyn crate::interpret::Interpret<T>> { fn create_interpret(&self) -> Box<dyn crate::interpret::Interpret<T>> {
Box::new(AlertingInterpret { Box::new(AlertingInterpret {
sender: Prometheus { config: KubePrometheusConfig::new() }, sender: Prometheus {
config: Mutex::new(KubePrometheusConfig::new()),
},
receivers: self.receivers.clone(), receivers: self.receivers.clone(),
}) })
} fn name(&self) -> String { }
fn name(&self) -> String {
"HelmPrometheusAlertingScore".to_string() "HelmPrometheusAlertingScore".to_string()
} }
} }

View File

@ -1,15 +1,38 @@
use std::sync::Mutex;
use async_trait::async_trait; use async_trait::async_trait;
use log::debug; use log::debug;
use serde_yaml::Value; use serde_yaml::Value;
use crate::{ use crate::{
interpret::InterpretError, interpret::{InterpretError, Outcome},
topology::{installable::Installable, oberservability::monitoring::AlertSender}, inventory::Inventory,
score,
topology::{
HelmCommand, K8sAnywhereTopology, Topology, installable::Installable,
oberservability::monitoring::AlertSender,
},
}; };
use super::helm::config::KubePrometheusConfig; use score::Score;
impl AlertSender for Prometheus {} use super::helm::{
config::KubePrometheusConfig, kube_prometheus_helm_chart::kube_prometheus_helm_chart_score,
};
#[async_trait]
impl AlertSender for Prometheus {
fn name(&self) -> String {
"HelmKubePrometheus".to_string()
}
async fn install(&self) -> Result<Outcome, InterpretError> {
self.install_prometheus();
todo!()
}
}
//im not totally sure what to do in the impl installable
//should we have a oncecell that checks insured is true?
#[async_trait] #[async_trait]
impl Installable for Prometheus { impl Installable for Prometheus {
@ -18,32 +41,63 @@ impl Installable for Prometheus {
} }
} }
//before we talked about having a trait installable and a trait installer for the topology
// i feel like that might still be necessary to meet the requirement of inventory and topology on
// the score.create_interpret().execute(inventory, topology) method
#[async_trait]
trait Installer {
async fn install(&self, sender: Box<&dyn Installable>) -> Result<(), InterpretError>;
}
#[async_trait]
impl Installer for K8sAnywhereTopology {
async fn install(&self, installable: Box<&dyn Installable>) -> Result<(), InterpretError> {
installable.install().await?;
Ok(())
}
}
#[derive(Debug)] #[derive(Debug)]
pub struct Prometheus{ pub struct Prometheus {
pub config: KubePrometheusConfig, pub config: Mutex<KubePrometheusConfig>,
} }
impl Prometheus { impl Prometheus {
pub async fn install_receiver( pub async fn install_receiver(
&self, &self,
prometheus_receiver: &dyn PrometheusReceiver, prometheus_receiver: &dyn PrometheusReceiver,
) -> Result<(), InterpretError> { ) -> Result<Outcome, InterpretError> {
let prom_receiver = prometheus_receiver.receiver_config().await;
debug!(
"adding alert receiver to prometheus config: {:#?}",
&prom_receiver
);
let mut config = self.config.lock().unwrap();
config.alert_receiver_configs.push(prom_receiver);
debug!("adding alert receiver to prometheus config: {:#?}", prometheus_receiver.receiver_config()); let prom_receiver_name = prometheus_receiver.name();
self.config.alert_receiver_configs.push(prometheus_receiver.receiver_config()); debug!("installed alert receiver {}", &prom_receiver_name);
todo!() Ok(Outcome::success(format!(
"Sucessfully installed receiver {}",
prom_receiver_name
)))
}
pub async fn install_prometheus(&self) -> Result<Outcome, InterpretError> {
kube_prometheus_helm_chart_score(self.config.lock().unwrap().clone())
.create_interpret()
.execute()
.await
} }
} }
#[async_trait] #[async_trait]
pub trait PrometheusReceiver: Send + Sync + std::fmt::Debug{ pub trait PrometheusReceiver: Send + Sync + std::fmt::Debug {
async fn receiver_config(&self) -> (Option<Value>, Value, Value); fn name(&self) -> String;
async fn receiver_config(&self) -> Value;
//this probably needs to be a type //this probably needs to be a type
//that //that
//represents //represents
//a //a
//promtheusreceiver //promtheusreceiver
} }