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 262 additions and 177 deletions
Showing only changes of commit f6c146b14b - Show all commits

View File

@ -40,7 +40,6 @@ enum K8sSource {
pub struct K8sAnywhereTopology {
k8s_state: OnceCell<Option<K8sState>>,
tenant_manager: OnceCell<K8sTenantManager>,
k8s_monitor: OnceCell<K8sMonitor>,
config: K8sAnywhereConfig,
}
@ -66,7 +65,6 @@ impl K8sAnywhereTopology {
Self {
k8s_state: OnceCell::new(),
tenant_manager: OnceCell::new(),
k8s_monitor: OnceCell::new(),
config: K8sAnywhereConfig::from_env(),
}
}
@ -75,7 +73,6 @@ impl K8sAnywhereTopology {
Self {
k8s_state: OnceCell::new(),
tenant_manager: OnceCell::new(),
k8s_monitor: OnceCell::new(),
config,
}
}
@ -206,30 +203,6 @@ impl K8sAnywhereTopology {
)),
}
}
async fn ensure_k8s_monitor(&self) -> Result<(), String> {
if let Some(_) = self.k8s_monitor.get() {
return Ok(());
}
self.k8s_monitor
.get_or_try_init(async || -> Result<K8sMonitor, String> {
let config = K8sMonitorConfig::cluster_monitor();
Ok(K8sMonitor { config })
})
.await
.unwrap();
Ok(())
}
fn get_k8s_monitor(&self) -> Result<&K8sMonitor, ExecutorError> {
match self.k8s_monitor.get() {
Some(k) => Ok(k),
None => Err(ExecutorError::UnexpectedError(
"K8sMonitor not available".to_string(),
)),
}
}
}
pub struct K8sAnywhereConfig {
@ -281,10 +254,6 @@ impl Topology for K8sAnywhereTopology {
"No K8s client could be found or installed".to_string(),
))?;
self.ensure_k8s_monitor()
.await
.map_err(|e| InterpretError::new(e))?;
self.ensure_k8s_tenant_manager()
.await
.map_err(|e| InterpretError::new(e))?;
@ -309,20 +278,3 @@ impl TenantManager for K8sAnywhereTopology {
.await
}
}
#[async_trait]
impl Monitor for K8sAnywhereTopology {
async fn provision_monitor<T: Topology + HelmCommand>(
&self,
inventory: &Inventory,
topology: &T,
alert_receivers: Option<Vec<Box<dyn AlertChannelConfig>>>,
) -> Result<Outcome, InterpretError> {
self.get_k8s_monitor()?
.provision_monitor(inventory, topology, alert_receivers)
.await
}
fn delete_monitor(&self) -> Result<Outcome, InterpretError> {
todo!()
}
}

View File

@ -1,8 +1,76 @@
use url::Url;
//#[derive(Debug, Clone)]
//pub struct DiscordWebhookAlertChannel {
// pub webhook_url: Url,
// pub name: String,
// pub send_resolved_notifications: bool,
//}
#[derive(Debug, Clone)]
pub struct DiscordWebhookAlertChannel {
pub webhook_url: Url,
pub name: String,
pub send_resolved_notifications: bool,
use serde::Serialize;
use crate::{interpret::Interpret, modules::monitoring::{alert_receiver::{AlertReceiver, AlertReceiverInterpret}, alert_rule::AlertRule, prometheus::{Prometheus, PrometheusReceiver, PrometheusRule, PrometheusScrapeTarget}, scrape_target::ScrapeTarget}, score::Score, topology::Topology};
#[derive(Debug, Clone, Serialize)]
struct DiscordWebhook;
impl DiscordWebhook {
fn as_prometheus_receiver(&self) -> PrometheusReceiver {
PrometheusReceiver {}
}
}
impl AlertReceiver for DiscordWebhook {
type Sender = Prometheus;
fn install(&self, sender: &Self::Sender) -> Result<(), String> {
sender.configure_receiver(self.as_prometheus_receiver())
}
}
#[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!()
}
}
impl ScrapeTarget for DiscordWebhook {
type Sender = Prometheus;
fn install(&self, sender: &Self::Sender) {
sender.configure_scrape_target(self.as_prometheus_scrape_target())
}
}
impl DiscordWebhook {
fn as_prometheus_scrape_target(&self) -> PrometheusScrapeTarget {
PrometheusScrapeTarget { definition: todo!() }
}
}
impl AlertRule for DiscordWebhook {
type Sender = Prometheus;
fn install(&self, sender: &Self::Sender) {
sender.configure_rule(self.as_prometheus_rule())
}
}
impl DiscordWebhook {
fn as_prometheus_rule(&self) -> PrometheusRule {
PrometheusRule { definition: todo!() }
}
}

View File

@ -0,0 +1,55 @@
use std::fmt::Debug;
use async_trait::async_trait;
use crate::{
data::{Id, Version},
interpret::{Interpret, InterpretError, InterpretName, InterpretStatus, Outcome},
inventory::Inventory,
topology::Topology,
};
use super::prometheus::AlertSender;
pub trait AlertReceiver: Debug + Send + Sync {
type Sender: AlertSender;
fn install(&self, sender: &Self::Sender) -> Result<(), String>;
}
struct AlertReceiverConfig<S: AlertSender> {
config: String, // Or whatever
sender: S,
}
#[derive(Debug)]
pub struct AlertReceiverInterpret {
pub receiver: Box<dyn AlertReceiver<Sender = dyn AlertSender>>,
}
#[async_trait]
impl<T: Topology> Interpret<T> for AlertReceiverInterpret {
async fn execute(
&self,
inventory: &Inventory,
topology: &T,
) -> Result<Outcome, InterpretError> {
todo!()
}
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!()
}
}

View File

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

View File

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

View File

@ -1,59 +0,0 @@
use crate::{score::Score, topology::Topology};
pub trait AlertSender {}
struct Prometheus {}
impl Prometheus {
fn configure_receiver(&self, receiver: PrometheusReceiver) -> Result<(), String> {
todo!()
}
}
impl AlertSender for Prometheus {}
struct DiscordWebhook;
struct PrometheusReceiver;
impl DiscordWebhook {
fn as_prometheus_receiver(&self) -> PrometheusReceiver {
PrometheusReceiver {}
}
}
impl AlertReceiver for DiscordWebhook {
type Sender = Prometheus;
fn install(&self, sender: &Self::Sender) -> Result<(), String> {
sender.configure_receiver(self.as_prometheus_receiver())
}
}
pub trait AlertReceiver {
type Sender: AlertSender;
fn install(&self) -> Result<(), String>;
}
struct AlertReceiverConfig<S: AlertSender> {
config: String, // Or whatever
sender: S,
}
struct DiscordWebhookScore {
config: DiscordWebhook,
}
impl<T: Topology> Score<T> for DiscordWebhookScore {
fn create_interpret(&self) -> Box<AlertReceiverInterpret> {
AlertReceiverInterpret { receiver: Box::new(self.config.clone())}
}
fn name(&self) -> String {
todo!()
}
}
struct AlertReceiverInterpret {
receiver: Box<dyn AlertReceiver>,
}

View File

@ -11,74 +11,22 @@ use crate::{
topology::{HelmCommand, Topology},
};
use super::alert_receiver::AlertReceiver;
use super::alert_rule::AlertRule;
use super::scrape_target::ScrapeTarget;
pub trait MonitoringSystem {}
trait PrometheusReceiver {
fn get_config(&self) -> PrometheusReceiverConfig;
}
struct PrometheusReceiverConfig {
config: Value, // either a serde Value or a more specific type that understands prometheus
// config
}
struct PrometheusRule {
definition: String, // Not a string but an actual prometheus rule config
}
struct PrometheusScrapeTarget {
definition: String, // Not a string but an actual prometheus scraping config
}
pub struct PrometheusMonitoringScore {
alert_receivers: Vec<Box<dyn PrometheusReceiver>>,
alert_rules: Vec<Box<PrometheusRule>>,
scrape_targets: Vec<Box<PrometheusScrapeTarget>>,
}
pub struct PrometheusMonitoringInterpret {}
#[async_trait]
impl<T: Topology + PrometheusCapability> Interpret<T> for PrometheusMonitoringInterpret {
async fn execute(
&self,
inventory: &Inventory,
topology: &T,
) -> Result<Outcome, InterpretError> {
todo!()
}
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!()
}
}
pub trait PrometheusCapability {
fn install_alert_receivers(&self, receivers: Vec<Box<dyn PrometheusReceiver>>);
fn install_alert_rules(&self, rules: Vec<Box<PrometheusRule>>);
fn install_scrape_targets(&self, receivers: Vec<Box<PrometheusScrapeTarget>>);
}
#[derive(Debug, Clone, Serialize)]
pub struct MonitoringAlertingScore<M: MonitoringSystem> {
alert_receivers: Vec<Box<dyn AlertReceiver<M>>>,
alert_rules: Vec<Box<dyn AlertRules<M>>>,
monitoring_targets: Vec<Box<dyn MonitoringTarget<M>>>,
alert_receivers: Vec<Box<dyn AlertReceiver<Sender = M>>>,
alert_rules: Vec<Box<dyn AlertRule<Sender = M>>>,
scrape_targets: Vec<Box<dyn ScrapeTarget<Sender = M>>>,
}
impl<T: Topology + Monitor> Score<T> for MonitoringAlertingScore {
impl<T: Topology, M: MonitoringSystem> Score<T> for MonitoringAlertingScore<M> {
fn create_interpret(&self) -> Box<dyn Interpret<T>> {
Box::new(MonitoringAlertingInterpret {
score: self.clone(),
@ -96,7 +44,7 @@ struct MonitoringAlertingInterpret {
}
#[async_trait]
impl<T: Topology + HelmCommand + Monitor> Interpret<T> for MonitoringAlertingInterpret {
impl<T: Topology> Interpret<T> for MonitoringAlertingInterpret {
async fn execute(
&self,
inventory: &Inventory,
@ -127,4 +75,3 @@ impl<T: Topology + HelmCommand + Monitor> Interpret<T> for MonitoringAlertingInt
todo!()
}
}

View File

@ -0,0 +1,99 @@
use async_trait::async_trait;
use serde::Serialize;
use serde_value::Value;
use crate::{
data::{Id, Version},
interpret::{Interpret, InterpretError, InterpretName, InterpretStatus, Outcome},
inventory::Inventory,
score::Score,
topology::Topology,
};
use std::fmt::Debug;
pub trait AlertSender {}
#[derive(Debug, Clone, Serialize)]
pub struct Prometheus {}
impl Prometheus {
pub fn configure_receiver(&self, receiver: PrometheusReceiver) -> Result<(), String> {
todo!()
}
pub fn configure_rule(&self, rule: PrometheusRule) {
todo!()
}
pub fn configure_scrape_target(&self, target: PrometheusScrapeTarget) {
todo!()
}
}
pub trait PrometheusCapability {
fn install_alert_receivers(&self, receivers: Vec<Box<dyn PrometheusReceiver>>);
fn install_alert_rules(&self, rules: Vec<Box<dyn PrometheusRule>>);
fn install_scrape_targets(&self, receivers: Vec<Box<dyn PrometheusScrapeTarget>>);
}
impl AlertSender for Prometheus {}
pub trait PrometheusReceiver{
fn get_prometheus_config(&self) -> PrometheusReceiverConfig;
}
pub struct PrometheusReceiverConfig {
config: Value, // either a serde Value or a more specific type that understands prometheus
// config
}
pub trait PrometheusRule{
fn get_prometheus_config(&self) -> PrometheusRuleConfig;
}
pub struct PrometheusRuleConfig {
pub definition: String, // Not a string but an actual prometheus rule config
}
pub trait PrometheusScrapeTarget {
fn get_prometheus_config(&self) -> PrometheusScrapeTargetConfig;
}
pub struct PrometheusScrapeTargetConfig {
pub definition: String, // Not a string but an actual prometheus scraping config
}
pub struct PrometheusMonitoringScore {
alert_receivers: Vec<Box<PrometheusReceiverConfig>>,
alert_rules: Vec<Box<PrometheusRuleConfig>>,
scrape_targets: Vec<Box<PrometheusScrapeTargetConfig>>,
}
#[derive(Debug)]
pub struct PrometheusMonitoringInterpret {}
#[async_trait]
impl<T: Topology + PrometheusCapability> Interpret<T> for PrometheusMonitoringInterpret {
async fn execute(
&self,
inventory: &Inventory,
topology: &T,
) -> Result<Outcome, InterpretError> {
todo!()
}
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!()
}
}

View File

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