{# alerts/rules_form.html — a new rule, or one rule's own page (#5317): named for the rule, in three sections (what it watches, when it fires, what happens), then Delete at the foot, behind the confirm dialog, saying that its history goes with it. #} {% extends "base.html" %} {% from "_macros.html" import crumbs, page_header %} {% block title %}{{ rule.name if rule else "New alert rule" }} — Alerts — Steward{% endblock %} {% block breadcrumb %}{{ crumbs([("Alerts", "/alerts/"), (rule.name if rule else "New rule", "")]) }}{% endblock %} {% block content %}
{% if rule %} {% call page_header(rule.name) %} History {% endcall %}

{%- if not rule.enabled %}Off · {% endif -%} {%- if fired %}Last fired {{ fired|ago }}{% else %}Never fired{% endif -%} {%- if history_count is defined and history_count is not none %} · {{ history_count }} change{{ "s" if history_count != 1 }} of state on record{% endif -%}

{% else %} {{ page_header("New alert rule") }} {% endif %}
{{ csrf_field() }} {# ── What it watches ─────────────────────────────────────────────────── #}

What it watches

{# ── Source module ───────────────────────────────────────────────────── #}
{# ── Dynamic resource + metric ────────────────────────────────────────── #}
{% with current_resource = rule.resource_name if rule else "", current_metric = rule.metric_name if rule else "" %} {% include "alerts/_rule_fields.html" %} {% endwith %}
{# ── Metric reference ────────────────────────────────────────────────── #}
What each metric measures
{% for src, names in catalog.items() if names %}
{{ source_label(src) }}
{% for m in names %}
{{ metric_label(m) }}{% if metric_unit(m) %} ({{ metric_unit(m) }}){% endif %} {{ metric_about(m) }}
{% endfor %}
{% endfor %}
{# ── When it fires ───────────────────────────────────────────────────── #}

When it fires

{# ── Condition: a threshold in the metric's unit, or for an up/down metric the word it fires on (sent as binary_when; the route turns it into < 0.5 or >= 0.5). The script swaps the two as the metric changes. #} {% set m0 = rule.metric_name if rule else "" %} {% set binary = m0 in ("is_up", "is_healthy") %} {% set fires_down = not rule or rule.operator.value in ("<", "<=") %}

{%- if rule and metric_unit(m0) == "seconds" %}= {{ metric_value(m0, rule.threshold) }}{% endif %}

A check is each new reading of the metric, as its source reports it. A firing or acknowledged alert clears only after that many readings in a row are back within the threshold; an acknowledgement holds until then.

{# ── What happens ────────────────────────────────────────────────────── #}

What happens

{%- if notify %}It notifies {{ notify|join(" and ") }}. {%- else %}It notifies nobody yet: no email server with recipients and no webhook is set {%- if session.user_role == 'admin' %} (Settings → Notifications){% endif %}.{% endif -%}

Silence is always shown as NO DATA on the Alerts page: no sample for three of the metric's usual gaps (at least 5 minutes). This also sends a notification when it starts and when data resumes. A firing alert that goes silent stays firing.

{# ── Ansible action (admin only) ─────────────────────────────────────── #} {% if session.get("user_role") == "admin" %} {% set act = rule.ansible_action if rule and rule.ansible_action else None %}

Admins only. Runs once each time the alert starts firing, with steward_alert_* variables (resource, metric, value…) passed to it.

{% endif %}
Cancel
{# ── Delete: on the rule's own page, never in the list (#5317) ─────────── #} {% if rule and session.user_role == 'admin' %}

Delete this rule

Its history goes with it{% if history_count %} ({{ history_count }} change{{ "s" if history_count != 1 }} of state){% endif %}. Disabling it on the Alerts page keeps the history.

{{ csrf_field() }}
{% endif %}
{% endblock %}