Functional Weave
Code in TypeScript

monitor.alert-mute@1.0.0

impl/rust.rs

2,942 bytes · the Rust implementation · view raw

Imports name this capability’s declared dependencies, which fune builds next to it in your project; each one links to its page.

use super::funejson::Value;  ← the fune runtime: the JSON value the test vectors use; fune build keeps it only where a signature takes one

/// 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<String> {
    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])))
}