Skip to content

Prometheus alerts

Maintenance map of the alert code: what goes where, and how to extend it without breaking anything. The admin-facing operation is described in Monitoring & Alerts.

The code is split in two to keep rule generation testable:

  • dnf/lib/alerts.nix : pure functions that produce Prometheus rules from the topology. Tested in dnf/tests/unit/lib/alerts_test.nix.
  • dnf/modules/service/prometheus.nix : impure wiring (Alertmanager, routing by severity, sops, Matrix bot, vhost, blackbox probes).

Any non-trivial logic goes into alerts.nix ; the module merely plugs it in.

Exposed via dnfLib (see dnf/lib/default.nix):

HelperRole
serviceUnitsDNF service → systemd unit (e.g. idmkanidm.service)
nodeClassClass of a node (critical / non-critical / disabled): alert-* features then profile
nodeAlertEligibleSelection: a node is monitored only if it is a network/server node, carries alert-non-critical, or hosts a mapped service
severityForClassClass → severity (critical or warning)
hostExpectedUnitsExpected units of a host (based on its enabled services)
mkNodeRuleGroupsNodeDown, ServiceDown, SystemdUnitFailed (+ reach label local/wan)
mkResourceRuleGroupsDisk, RAM, load, inodes, OOM, read-only FS, disk prediction, clock, conntrack
mkNetworkRuleGroupsBlackbox probes (gateway, tailnet, DNS, ZoneInternetDown)
mkHttpRuleGroupsHTTP probes: ServiceEndpointDown + TLS certificate expiration
mkResticRuleGroupsBackup freshness (ResticBackupStale/Critical)
mkSmartctlRuleGroupsSMART disk health (DiskSmartFailing, DiskTemperatureHigh)
mkPostfixRuleGroupsPostfix relay (PostfixRelayUnhealthy, PostfixDeferredQueueHigh)
mkSynapseRuleGroupsSynapse (SynapseRestarting, SynapseHighErrorRate)
mkMaintenanceRuleGroupsMaintenance flag (silence during rebuild)
mkTailscaleRuleGroupsTailnet self-healing (TailscaleUnhealthy, TailscaleFlapping)
mergeRuleGroupsMerges fragments into a single document
mkAlertRuleGroupsShortcut: nodes + resources + restic + SMART + tailscale
mkSilenceRoutesAlertmanager routes to the null receiver (known, accepted alerts)

Each scrape target carries a host label set to the hostname, assigned by mkHostTargets in prometheus.nix (one static_config per host rather than a single list of targets). Two effects :

  • the Matrix bot displays DiskSpaceLow at srv-backup instead of the raw instance <ip>:<port> ;
  • a silence route can target a single machine.

Setting it at scrape time propagates it for free to all alerts from these jobs, including the generic resource rules, which know nothing of the topology at evaluation time.

Monitoring is opt-out for infrastructure, opt-in for the rest. nodeAlertEligible retains a node only if it is of class critical (gateway/hcs/server profile or alert-critical feature), if it carries alert-non-critical explicitly, or if it hosts at least one service mapped in serviceUnits. A bare laptop/desktop therefore generates no node alerts.

A zone’s Prometheus connects to hosts in other zones (e.g. the public HCS) only over the WAN. When internet goes down, these targets become unreachable and would trigger a false “host down” alert. To prevent this:

  • each node rule carries a reach label (local same zone, wan cross-zone);
  • an ICMP blackbox probe to external IPs feeds ZoneInternetDown (fired only if all external targets fail);
  • an Alertmanager inhibition rule (equal: [zone]) silences reach="wan" alerts of the zone while ZoneInternetDown is active — the real cause is notified, not the symptoms.

So we merge everything via mergeRuleGroups, then emit only one entry :

dnf/modules/service/prometheus.nix
services.prometheus.rules = [
(builtins.toJSON (dnfLib.mergeRuleGroups (
[ (dnfLib.mkAlertRuleGroups { inherit nodes; /* … */ }) ]
++ lib.optional alerting.silenceOnRebuild (dnfLib.mkMaintenanceRuleGroups { /* … */ })
++ lib.optional alerting.network.enable (dnfLib.mkNetworkRuleGroups { /* … */ })
)))
];
I want to…I touch…
monitor a new serviceserviceUnits in alerts.nix
add a new rule familya mkXRuleGroups + add it to the module’s mergeRuleGroups
wire up a metrics exporterexporter in its module (gated monitoring-node, bind preferredIp) + scrape job + mkXRuleGroups gated in prometheus.nix
change a default thresholddefaultThresholds in alerts.nix
change a node’s classalert-*[:zone] feature (no code)
force/exclude a node from monitoringalert-non-critical / alert-disabled feature
monitor a URL + its TLS certificatealerting.network.httpProbeUrls in the config
tune internet outage detectionalerting.network.internetProbeTargets
silence a known, accepted alertalerting.silences in a consumer module (no code)
silence a broken systemd unit across the whole fleetignoredUnits in dnf/config/alerts.nix
add a new destinationthe alertmanager block of prometheus.nix (receiver + route)