feat: added impl for Discordwebhook receiver to receive application alerts from namespaces from application feature
Some checks failed
Run Check Script / check (pull_request) Failing after 49s

This commit is contained in:
Willem 2025-07-14 13:06:47 -04:00
parent 819f4a32fd
commit e61ec015ab
3 changed files with 63 additions and 48 deletions

View File

@ -1,10 +1,17 @@
use std::collections::BTreeMap;
use std::sync::Arc;
use async_trait::async_trait; use async_trait::async_trait;
use k8s_openapi::api::core::v1::Secret;
use kube::api::ObjectMeta; use kube::api::ObjectMeta;
use kube::{Api, Client, ResourceExt};
use log::{debug, info};
use serde::Serialize; use serde::Serialize;
use serde_json::json; use serde_json::json;
use serde_yaml::{Mapping, Value}; use serde_yaml::{Mapping, Value};
use crate::modules::monitoring::kube_prometheus::alert_manager_config::AlertmanagerConfigSpec; use crate::modules::monitoring::kube_prometheus::alert_manager_config::AlertmanagerConfigSpec;
use crate::topology::k8s::K8sClient;
use crate::{ use crate::{
interpret::{InterpretError, Outcome}, interpret::{InterpretError, Outcome},
modules::monitoring::{ modules::monitoring::{
@ -30,33 +37,63 @@ impl CRDAlertManagerReceiver for DiscordWebhook {
self.name.clone() self.name.clone()
} }
async fn configure_receiver(&self) -> AlertmanagerConfig { async fn configure_receiver(&self, client: &Arc<K8sClient>, ns: String) -> AlertmanagerConfig {
let secret_name = format!("{}-secret", self.name.clone());
let webhook_key = format!("{}", self.url.clone());
let mut string_data = BTreeMap::new();
string_data.insert("webhook-url".to_string(), webhook_key.clone());
let secret = Secret {
metadata: kube::core::ObjectMeta {
name: Some(secret_name.clone()),
..Default::default()
},
string_data: Some(string_data),
type_: Some("Opaque".to_string()),
..Default::default()
};
let _ = client.apply(&secret, Some(&ns)).await;
let spec = AlertmanagerConfigSpec { let spec = AlertmanagerConfigSpec {
route: Some(json!({ data: json!({
"group_by": ["alertname"], "route": {
"receiver": self.name, "receiver": self.name,
})), },
receivers: Some(json!([ "receivers": [
{ {
"name": self.name, "name": self.name,
"webhook_configs": [ "discordConfigs": [
{ {
"url": self.url "apiURL": {
"name": secret_name,
"key": "webhook-url",
},
"title": "{{ template \"discord.default.title\" . }}",
"message": "{{ template \"discord.default.message\" . }}"
} }
] ]
} }
])), ]
}),
}; };
AlertmanagerConfig { let am = AlertmanagerConfig {
metadata: ObjectMeta { metadata: ObjectMeta {
name: Some(self.name.clone()), name: Some(self.name.clone()),
//TODO this cant be hardcoded labels: Some(std::collections::BTreeMap::from([(
namespace: Some("monitoring".into()), "alertmanagerConfig".to_string(),
"enabled".to_string(),
)])),
namespace: Some(ns),
..Default::default() ..Default::default()
}, },
spec, spec,
} };
debug!(" am: \n{:#?}", am.clone());
am
} }
fn clone_box(&self) -> Box<dyn CRDAlertManagerReceiver> { fn clone_box(&self) -> Box<dyn CRDAlertManagerReceiver> {
Box::new(self.clone()) Box::new(self.clone())
@ -174,27 +211,6 @@ impl DiscordWebhook {
} }
} }
impl From<DiscordWebhook> for AlertmanagerConfigSpec {
fn from(dw: DiscordWebhook) -> Self {
AlertmanagerConfigSpec {
route: Some(json!({
"group_by": ["alertname"],
"receiver": dw.name,
})),
receivers: Some(json!([
{
"name": dw.name,
"webhook_configs": [
{
"url": dw.url
}
]
}
])),
}
}
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;

View File

@ -99,12 +99,11 @@ use crate::{
plural = "alertmanagerconfigs", plural = "alertmanagerconfigs",
namespaced namespaced
)] )]
pub struct AlertmanagerConfigSpec { pub struct AlertmanagerConfigSpec {
// Define the spec fields here, or use serde's `flatten` if you want to store arbitrary data // Define the spec fields here, or use serde's `flatten` if you want to store arbitrary data
// Example placeholder: // Example placeholder:
pub route: Option<serde_json::Value>, #[serde(flatten)]
pub receivers: Option<serde_json::Value>, pub data: serde_json::Value,
} }
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
@ -139,7 +138,7 @@ pub trait CRDAlertManagerReceiver:
AlertReceiver<CRDAlertManager> + Send + Sync + std::fmt::Debug AlertReceiver<CRDAlertManager> + Send + Sync + std::fmt::Debug
{ {
fn name(&self) -> String; fn name(&self) -> String;
async fn configure_receiver(&self) -> AlertmanagerConfig; async fn configure_receiver(&self, client: &Arc<K8sClient>, ns: String) -> AlertmanagerConfig;
// This new method is for cloning the trait object // This new method is for cloning the trait object
fn clone_box(&self) -> Box<dyn CRDAlertManagerReceiver>; fn clone_box(&self) -> Box<dyn CRDAlertManagerReceiver>;
} }

View File

@ -48,9 +48,9 @@ impl<T: Topology + K8sclient> Interpret<T> for HelmPrometheusApplicationAlerting
inventory: &Inventory, inventory: &Inventory,
topology: &T, topology: &T,
) -> Result<Outcome, InterpretError> { ) -> Result<Outcome, InterpretError> {
for receiver in self.receivers.iter() {
let alertmanager_config: AlertmanagerConfig = receiver.configure_receiver().await;
let client = topology.k8s_client().await.unwrap(); let client = topology.k8s_client().await.unwrap();
for receiver in self.receivers.iter() {
let alertmanager_config: AlertmanagerConfig = receiver.configure_receiver(&client, self.namespace.clone()).await;
client client
.apply(&alertmanager_config, Some(&self.namespace)) .apply(&alertmanager_config, Some(&self.namespace))
.await?; .await?;