feat/monitoring_alerting #61

Merged
johnride merged 12 commits from feat/monitoring_alerting into master 2025-06-19 14:37:20 +00:00
9 changed files with 163 additions and 52 deletions
Showing only changes of commit c6a39a39a1 - Show all commits

View File

@ -0,0 +1,73 @@
pub trait MonitoringSystem {}
// 1. Modified AlertReceiver trait:
// - Removed the problematic `clone` method.
// - Added `box_clone` which returns a Box<dyn AlertReceiver>.
pub trait AlertReceiver {
type M: MonitoringSystem;
fn install(&self, sender: &Self::M) -> Result<(), String>;
// This method allows concrete types to clone themselves into a Box<dyn AlertReceiver>
fn box_clone(&self) -> Box<dyn AlertReceiver<M = Self::M>>;
}
#[derive(Clone)]
struct Prometheus{}
impl MonitoringSystem for Prometheus {}
#[derive(Clone)] // Keep derive(Clone) for DiscordWebhook itself
struct DiscordWebhook{}
impl AlertReceiver for DiscordWebhook {
type M = Prometheus;
fn install(&self, sender: &Self::M) -> Result<(), String> {
// Placeholder for actual installation logic
println!("DiscordWebhook installed for Prometheus monitoring.");
Ok(())
}
// 2. Implement `box_clone` for DiscordWebhook:
// This uses the derived `Clone` for DiscordWebhook to create a new boxed instance.
fn box_clone(&self) -> Box<dyn AlertReceiver<M = Self::M>> {
Box::new(self.clone())
}
}
// 3. Implement `std::clone::Clone` for `Box<dyn AlertReceiver<M= M>>`:
// This allows `Box<dyn AlertReceiver>` to be cloned.
// The `+ 'static` lifetime bound is often necessary for trait objects stored in collections,
// ensuring they live long enough.
impl<M: MonitoringSystem + 'static> Clone for Box<dyn AlertReceiver<M= M>> {
fn clone(&self) -> Self {
self.box_clone() // Call the custom `box_clone` method
}
}
// MonitoringConfig can now derive Clone because its `receivers` field
// (Vec<Box<dyn AlertReceiver<M = M>>>) is now cloneable.
#[derive(Clone)]
struct MonitoringConfig <M: MonitoringSystem + 'static>{
receivers: Vec<Box<dyn AlertReceiver<M = M>>>
}
// Example usage to demonstrate compilation and functionality
fn main() {
let prometheus_instance = Prometheus{};
let discord_webhook_instance = DiscordWebhook{};
let mut config = MonitoringConfig {
receivers: Vec::new()
};
// Create a boxed alert receiver
let boxed_receiver: Box<dyn AlertReceiver<M = Prometheus>> = Box::new(discord_webhook_instance);
config.receivers.push(boxed_receiver);
// Clone the config, which will now correctly clone the boxed receiver
let cloned_config = config.clone();
println!("Original config has {} receivers.", config.receivers.len());
println!("Cloned config has {} receivers.", cloned_config.receivers.len());
// Example of using the installed receiver
if let Some(receiver) = config.receivers.get(0) {
let _ = receiver.install(&prometheus_instance);
}
}

View File

@ -2,7 +2,13 @@ use harmony::{
data::Version,
inventory::Inventory,
maestro::Maestro,
modules::{lamp::{LAMPConfig, LAMPScore}, monitoring::monitoring_alerting::MonitoringAlertingScore},
modules::{
lamp::{LAMPConfig, LAMPScore},
monitoring::{
alert_channel::discord_alert_channel::DiscordWebhook,
monitoring_alerting::MonitoringAlertingScore,
},
},
topology::{K8sAnywhereTopology, Url},
};
@ -29,7 +35,15 @@ async fn main() {
},
};
let monitoring = MonitoringAlertingScore { alert_channel_configs: todo!() };
let monitoring = MonitoringAlertingScore {
alert_receivers: vec![Box::new(DiscordWebhook {
url: Url::Url(url::Url::parse("https://discord.idonotexist.com").unwrap()),
// TODO write url macro
// url: url!("https://discord.idonotexist.com"),
})],
alert_rules: vec![],
scrape_targets: vec![],
};
// You can choose the type of Topology you want, we suggest starting with the
// K8sAnywhereTopology as it is the most automatic one that enables you to easily deploy
@ -42,7 +56,8 @@ async fn main() {
.await
.unwrap();
maestro.register_all(vec![Box::new(lamp_stack)]);
// maestro.register_all(vec![Box::new(lamp_stack)]);
maestro.register_all(vec![Box::new(monitoring)]);
// Here we bootstrap the CLI, this gives some nice features if you need them
harmony_cli::init(maestro, None).await.unwrap();
}

View File

@ -1,17 +1,17 @@
use serde::Serialize;
use crate::{
interpret::Interpret,
modules::monitoring::{
alert_receiver::{AlertReceiver, AlertReceiverInterpret},
alert_receiver::AlertReceiver,
prometheus::{Prometheus, PrometheusReceiver},
},
score::Score,
topology::Topology,
topology::Url,
};
#[derive(Debug, Clone, Serialize)]
struct DiscordWebhook;
pub struct DiscordWebhook {
pub url: Url,
}
impl AlertReceiver for DiscordWebhook {
type Sender = Prometheus;
@ -19,6 +19,12 @@ impl AlertReceiver for DiscordWebhook {
fn install(&self, sender: &Self::Sender) -> Result<(), String> {
sender.configure_receiver(Box::new(self))
}
fn clone(&self) -> Self
where
Self: Sized {
<Self as Clone>::clone(self)
}
}
impl PrometheusReceiver for DiscordWebhook {
@ -29,19 +35,19 @@ impl PrometheusReceiver for DiscordWebhook {
}
}
#[derive(Debug, Clone, Serialize)]
pub struct DiscordWebhookScore {
pub config: DiscordWebhook,
}
impl<T: Topology> Score<T> for DiscordWebhookScore {
fn create_interpret(&self) -> Box<dyn Interpret<T>> {
Box::new(AlertReceiverInterpret {
receiver: Box::new(self.config.clone()),
})
}
fn name(&self) -> String {
todo!()
}
}
// #[derive(Debug, Clone, Serialize)]
// pub struct DiscordWebhookScore {
// pub config: DiscordWebhook,
// }
//
// impl<T: Topology> Score<T> for DiscordWebhookScore {
// fn create_interpret(&self) -> Box<dyn Interpret<T>> {
// Box::new(AlertReceiverInterpret {
// receiver: Box::new(self.config.clone()),
// })
// }
//
// fn name(&self) -> String {
// todo!()
// }
// }

View File

@ -9,12 +9,13 @@ use crate::{
topology::Topology,
};
use super::{monitoring_alerting::CloneBox, prometheus::AlertSender};
use super::prometheus::AlertSender;
pub trait AlertReceiver: Debug + Send + Sync + CloneBox {
pub trait AlertReceiver: Debug + Send + Sync {
type Sender: AlertSender;
fn install(&self, sender: &Self::Sender) -> Result<(), String>;
fn clone_box(&self) -> Box<dyn AlertReceiver<Sender = Self::Sender>>;
}
struct AlertReceiverConfig<S: AlertSender> {

View File

@ -1,11 +1,11 @@
use std::fmt::Debug;
use dyn_clone::DynClone;
use super::prometheus::AlertSender;
pub trait AlertRule: Debug + Send + Sync {
pub trait AlertRule: Debug + Send + Sync + DynClone {
type Sender: AlertSender;
fn install(&self, sender: &Self::Sender);
}

View File

@ -1,7 +1,7 @@
pub mod alert_channel;
pub mod alert_receiver;
pub mod alert_rule;
pub mod kube_prometheus;
pub mod monitoring_alerting;
pub mod prometheus;
pub mod alert_receiver;
pub mod alert_rule;
pub mod scrape_target;

View File

@ -11,7 +11,7 @@ use crate::{
topology::Topology,
};
use super::alert_receiver::AlertReceiver;
use super::{alert_receiver::AlertReceiver, prometheus::AlertSender};
use super::alert_rule::AlertRule;
use super::scrape_target::ScrapeTarget;
@ -19,15 +19,34 @@ pub trait MonitoringSystem: std::fmt::Debug + Clone + Serialize + 'static {}
#[derive(Debug, Clone)]
pub struct MonitoringAlertingScore<M: MonitoringSystem> {
alert_receivers: Arc<Vec<Box<dyn AlertReceiver<Sender = M>>>>,
alert_rules: Arc<Vec<Box<dyn AlertRule<Sender = M>>>>,
scrape_targets: Arc<Vec<Box<dyn ScrapeTarget<Sender = M>>>>,
pub alert_receivers: Vec<Box<dyn AlertReceiver<Sender = M>>>,
pub alert_rules: Vec<Box<dyn AlertRule<Sender = M>>>,
pub scrape_targets: Vec<Box<dyn ScrapeTarget<Sender = M>>>,
}
impl <M: MonitoringSystem> Serialize for MonitoringAlertingScore<M> {
impl <M: MonitoringSystem + AlertSender> Clone for Box<dyn AlertReceiver<Sender = M>>{
fn clone(&self) -> Self {
self.clone_box()
}
}
impl <M: MonitoringSystem> Clone for Box<dyn AlertRule<Sender = M>>{
fn clone(&self) -> Self {
todo!()
}
}
impl <M: MonitoringSystem> Clone for Box<dyn ScrapeTarget<Sender = M>>{
fn clone(&self) -> Self {
todo!()
}
}
impl<M: MonitoringSystem> Serialize for MonitoringAlertingScore<M> {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer {
S: serde::Serializer,
{
todo!()
}
}
@ -75,16 +94,3 @@ impl<M: MonitoringSystem, T: Topology> Interpret<T> for MonitoringAlertingInterp
todo!()
}
}
pub trait CloneBox {
fn clone_box(&self) -> Box<dyn CloneBox>;
}
impl<C> CloneBox for C
where
C: Clone + 'static,
{
fn clone_box(&self) -> Box<dyn CloneBox> {
Box::new(self.clone())
}
}

View File

@ -10,13 +10,18 @@ use crate::{
};
use std::fmt::Debug;
use super::monitoring_alerting::MonitoringSystem;
pub trait AlertSender: std::fmt::Debug {}
#[derive(Debug, Clone, Serialize)]
pub struct Prometheus {}
impl Prometheus {
pub fn configure_receiver(&self, _receiver: Box<&dyn PrometheusReceiver>) -> Result<(), String> {
pub fn configure_receiver(
&self,
_receiver: Box<&dyn PrometheusReceiver>,
) -> Result<(), String> {
todo!()
}
pub fn configure_rule(&self, _rule: Box<&dyn PrometheusRule>) {
@ -27,6 +32,8 @@ impl Prometheus {
}
}
impl MonitoringSystem for Prometheus {}
pub trait PrometheusCapability {
fn install_alert_receivers(&self, receivers: Vec<Box<dyn PrometheusReceiver>>);
fn install_alert_rules(&self, rules: Vec<Box<dyn PrometheusRule>>);

View File

@ -1,9 +1,12 @@
use std::fmt::Debug;
use dyn_clone::DynClone;
use super::prometheus::AlertSender;
pub trait ScrapeTarget: Debug + Send + Sync {
pub trait ScrapeTarget: Debug + Send + Sync + DynClone {
type Sender: AlertSender;
fn install(&self, sender: &Self::Sender);
}