140 lines
4.4 KiB
Rust
140 lines
4.4 KiB
Rust
use crate::modules::application::{
|
|
Application, ApplicationFeature, InstallationError, InstallationOutcome,
|
|
};
|
|
use crate::modules::monitoring::application_monitoring::application_monitoring_score::ApplicationMonitoringScore;
|
|
use crate::modules::monitoring::grafana::grafana::Grafana;
|
|
use crate::modules::monitoring::kube_prometheus::crd::crd_alertmanager_config::CRDPrometheus;
|
|
use crate::modules::monitoring::kube_prometheus::crd::service_monitor::{
|
|
ServiceMonitor, ServiceMonitorSpec,
|
|
};
|
|
use crate::topology::MultiTargetTopology;
|
|
use crate::topology::ingress::Ingress;
|
|
use crate::{
|
|
inventory::Inventory,
|
|
modules::monitoring::{
|
|
alert_channel::webhook_receiver::WebhookReceiver, ntfy::ntfy::NtfyScore,
|
|
},
|
|
score::Score,
|
|
topology::{HelmCommand, K8sclient, Topology, tenant::TenantManager},
|
|
};
|
|
use crate::{
|
|
modules::prometheus::prometheus::PrometheusMonitoring,
|
|
topology::oberservability::monitoring::AlertReceiver,
|
|
};
|
|
use async_trait::async_trait;
|
|
use base64::{Engine as _, engine::general_purpose};
|
|
use harmony_secret::SecretManager;
|
|
use harmony_secret_derive::Secret;
|
|
use harmony_types::net::Url;
|
|
use kube::api::ObjectMeta;
|
|
use log::{debug, info};
|
|
use serde::{Deserialize, Serialize};
|
|
use std::sync::Arc;
|
|
|
|
#[derive(Debug, Clone)]
|
|
pub struct Monitoring {
|
|
pub application: Arc<dyn Application>,
|
|
pub alert_receiver: Vec<Box<dyn AlertReceiver<CRDPrometheus>>>,
|
|
}
|
|
|
|
#[async_trait]
|
|
impl<
|
|
T: Topology
|
|
+ HelmCommand
|
|
+ 'static
|
|
+ TenantManager
|
|
+ K8sclient
|
|
+ MultiTargetTopology
|
|
+ PrometheusMonitoring<CRDPrometheus>
|
|
+ Grafana
|
|
+ Ingress
|
|
+ std::fmt::Debug,
|
|
> ApplicationFeature<T> for Monitoring
|
|
{
|
|
async fn ensure_installed(
|
|
&self,
|
|
topology: &T,
|
|
) -> Result<InstallationOutcome, InstallationError> {
|
|
info!("Ensuring monitoring is available for application");
|
|
let namespace = topology
|
|
.get_tenant_config()
|
|
.await
|
|
.map(|ns| ns.name.clone())
|
|
.unwrap_or_else(|| self.application.name());
|
|
let domain = topology.get_domain("ntfy").await.unwrap();
|
|
|
|
let app_service_monitor = ServiceMonitor {
|
|
metadata: ObjectMeta {
|
|
name: Some(self.application.name()),
|
|
namespace: Some(namespace.clone()),
|
|
..Default::default()
|
|
},
|
|
spec: ServiceMonitorSpec::default(),
|
|
};
|
|
|
|
let mut alerting_score = ApplicationMonitoringScore {
|
|
sender: CRDPrometheus {
|
|
namespace: namespace.clone(),
|
|
client: topology.k8s_client().await.unwrap(),
|
|
service_monitor: vec![app_service_monitor],
|
|
},
|
|
application: self.application.clone(),
|
|
receivers: self.alert_receiver.clone(),
|
|
};
|
|
let ntfy = NtfyScore {
|
|
namespace: namespace.clone(),
|
|
host: domain,
|
|
};
|
|
ntfy.interpret(&Inventory::empty(), topology)
|
|
.await
|
|
.map_err(|e| e.to_string())?;
|
|
|
|
let config = SecretManager::get_or_prompt::<NtfyAuth>().await.unwrap();
|
|
|
|
let ntfy_default_auth_header = format!(
|
|
"Basic {}",
|
|
general_purpose::STANDARD.encode(format!("{}:{}", config.username, config.password))
|
|
);
|
|
|
|
debug!("ntfy_default_auth_header: {ntfy_default_auth_header}");
|
|
|
|
let ntfy_default_auth_param = general_purpose::STANDARD
|
|
.encode(ntfy_default_auth_header)
|
|
.replace("=", "");
|
|
|
|
debug!("ntfy_default_auth_param: {ntfy_default_auth_param}");
|
|
|
|
let ntfy_receiver = WebhookReceiver {
|
|
name: "ntfy-webhook".to_string(),
|
|
url: Url::Url(
|
|
url::Url::parse(
|
|
format!(
|
|
"http://ntfy.{}.svc.cluster.local/rust-web-app?auth={ntfy_default_auth_param}",
|
|
namespace.clone()
|
|
)
|
|
.as_str(),
|
|
)
|
|
.unwrap(),
|
|
),
|
|
};
|
|
|
|
alerting_score.receivers.push(Box::new(ntfy_receiver));
|
|
alerting_score
|
|
.interpret(&Inventory::empty(), topology)
|
|
.await
|
|
.map_err(|e| e.to_string())?;
|
|
|
|
Ok(InstallationOutcome::success())
|
|
}
|
|
|
|
fn name(&self) -> String {
|
|
"Monitoring".to_string()
|
|
}
|
|
}
|
|
|
|
#[derive(Secret, Serialize, Deserialize, Clone, Debug)]
|
|
struct NtfyAuth {
|
|
username: String,
|
|
password: String,
|
|
}
|