use super::funejson::Value; /// Hold an alert back, as Alertmanager's silences and inhibit rules do: /// during its component's maintenance if its kind is one maintenance mutes, /// or while an alert that inhibits it fires on the same component. The whole /// policy is checked every time, so a mistake in it fails loudly rather than /// silently never muting. The caller passes `condition && !muted` to /// monitor.alert-state. /// /// # Panics /// Panics on an empty kind, an empty maintenance kind, or an inhibition with /// an empty side or the same kind on both sides. pub fn mute_alert(kind: &str, under_maintenance: bool, firing_kinds: &[String], policy: &MutePolicy) -> AlertMute { if kind.is_empty() { panic!("kind must not be empty"); } for k in &policy.maintenance { if k.is_empty() { panic!("maintenance kinds must not be empty"); } } for rule in &policy.inhibit { if rule.source.is_empty() { panic!("inhibition source must not be empty"); } if rule.target.is_empty() { panic!("inhibition target must not be empty"); } if rule.source == rule.target { panic!("an alert kind cannot inhibit itself: {}", rule.source); } } if under_maintenance && policy.maintenance.iter().any(|k| k == kind) { return AlertMute { muted: true, reason: Some("maintenance".to_string()), by: None }; } for rule in &policy.inhibit { // source != target, so an alert listed among firing_kinds never inhibits itself. if rule.target == kind && firing_kinds.iter().any(|k| *k == rule.source) { return AlertMute { muted: true, reason: Some("inhibited".to_string()), by: Some(rule.source.clone()) }; } } AlertMute { muted: false, reason: None, by: None } } fn strings(v: &Value) -> Vec { v.as_arr().iter().map(|s| s.as_str().to_string()).collect() } pub fn mute_policy_from_value(v: &Value) -> MutePolicy { MutePolicy { maintenance: strings(v.get("maintenance")), inhibit: v .get("inhibit") .as_arr() .iter() .map(|r| Inhibition { source: r.get("source").as_str().to_string(), target: r.get("target").as_str().to_string() }) .collect(), } } pub fn alert_mute_to_value(m: &AlertMute) -> Value { Value::obj(vec![ ("muted", Value::Bool(m.muted)), ("reason", match &m.reason { Some(s) => Value::str(s), None => Value::Null }), ("by", match &m.by { Some(s) => Value::str(s), None => Value::Null }), ]) } pub fn fune_vector(args: &[Value]) -> Value { let under_maintenance = match &args[1] { Value::Bool(b) => *b, _ => panic!("underMaintenance must be true or false"), }; alert_mute_to_value(&mute_alert(args[0].as_str(), under_maintenance, &strings(&args[2]), &mute_policy_from_value(&args[3]))) }