* define Ntfy ingress (naive implementation) based on current target * use patched Ntfy Helm Chart * create Ntfy main user only if needed * add info logs * better error bubbling * instrument feature installations * upgrade prometheus alerting charts if already installed * harmony_composer params to control deployment `target` and `profile` Co-authored-by: Ian Letourneau <letourneau.ian@gmail.com> Co-authored-by: Jean-Gabriel Gill-Couture <jg@nationtech.io> Reviewed-on: #107
108 lines
3.5 KiB
Rust
108 lines
3.5 KiB
Rust
use std::sync::Arc;
|
|
|
|
use crate::modules::application::{Application, ApplicationFeature};
|
|
use crate::modules::monitoring::application_monitoring::application_monitoring_score::ApplicationMonitoringScore;
|
|
use crate::modules::monitoring::kube_prometheus::crd::crd_alertmanager_config::CRDPrometheus;
|
|
|
|
use crate::topology::MultiTargetTopology;
|
|
use crate::{
|
|
inventory::Inventory,
|
|
modules::monitoring::{
|
|
alert_channel::webhook_receiver::WebhookReceiver, ntfy::ntfy::NtfyScore,
|
|
},
|
|
score::Score,
|
|
topology::{HelmCommand, K8sclient, Topology, Url, tenant::TenantManager},
|
|
};
|
|
use crate::{
|
|
modules::prometheus::prometheus::PrometheusApplicationMonitoring,
|
|
topology::oberservability::monitoring::AlertReceiver,
|
|
};
|
|
use async_trait::async_trait;
|
|
use base64::{Engine as _, engine::general_purpose};
|
|
use log::{debug, info};
|
|
|
|
#[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
|
|
+ std::fmt::Debug
|
|
+ PrometheusApplicationMonitoring<CRDPrometheus>,
|
|
> ApplicationFeature<T> for Monitoring
|
|
{
|
|
async fn ensure_installed(&self, topology: &T) -> Result<(), String> {
|
|
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 mut alerting_score = ApplicationMonitoringScore {
|
|
sender: CRDPrometheus {
|
|
namespace: namespace.clone(),
|
|
client: topology.k8s_client().await.unwrap(),
|
|
},
|
|
application: self.application.clone(),
|
|
receivers: self.alert_receiver.clone(),
|
|
};
|
|
let ntfy = NtfyScore {
|
|
namespace: namespace.clone(),
|
|
host: "ntfy.harmonydemo.apps.ncd0.harmony.mcd".to_string(),
|
|
};
|
|
ntfy.interpret(&Inventory::empty(), topology)
|
|
.await
|
|
.map_err(|e| e.to_string())?;
|
|
|
|
let ntfy_default_auth_username = "harmony";
|
|
let ntfy_default_auth_password = "harmony";
|
|
let ntfy_default_auth_header = format!(
|
|
"Basic {}",
|
|
general_purpose::STANDARD.encode(format!(
|
|
"{ntfy_default_auth_username}:{ntfy_default_auth_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(())
|
|
}
|
|
fn name(&self) -> String {
|
|
"Monitoring".to_string()
|
|
}
|
|
}
|