arazzo: 1.0.1 info: title: Prometheus Test an Alertmanager Routing Path summary: Send a synthetic alert and follow it through to the receiver that will be paged. description: >- Routing trees are configuration, and configuration is only correct once it has been exercised. Rather than waiting for a real incident to discover a typo in a match block, this workflow checks the Alertmanager is healthy, confirms the intended receiver actually exists in the loaded configuration, posts a synthetic alert directly to the API the way Prometheus would, confirms it was accepted, and reads the alert groups to see which receiver the routing tree actually chose. Every step spells out its request inline so the flow can be read and executed without opening the underlying OpenAPI description. version: 1.0.0 sourceDescriptions: - name: alertmanagerApi url: ../openapi/prometheus-alertmanager-api-openapi.yml type: openapi workflows: - workflowId: test-alert-routing summary: Post a synthetic alert and confirm which receiver it routes to. description: >- Give the synthetic alert a short endsAt so it self-resolves rather than lingering as a permanent fake incident, and label it clearly so nobody mistakes the resulting page for a real one. inputs: type: object required: - alertName - alertNameMatcher - severity - expectedReceiver - startsAt - endsAt properties: alertName: type: string description: >- The alertname for the synthetic alert (e.g. RoutingSmokeTest). alertNameMatcher: type: string description: >- The same alert as a label matcher (e.g. alertname="RoutingSmokeTest"). severity: type: string description: >- The severity label to exercise a specific branch of the routing tree (e.g. critical). expectedReceiver: type: string description: >- The receiver name this alert is expected to route to, used to check the routing tree did what was intended. startsAt: type: string description: Alert start time as an RFC3339 timestamp. endsAt: type: string description: >- Alert end time as an RFC3339 timestamp. Keep this close so the synthetic alert resolves itself shortly after the test. generatorURL: type: string description: >- Optional URL linking back to whatever generated this alert, for the benefit of whoever receives the test page. steps: - stepId: checkAlertmanagerStatus description: >- Confirm the Alertmanager is up and its cluster has settled. Posting alerts at a cluster still in the settling state can produce duplicate or missing notifications that have nothing to do with the routing tree. operationId: getStatus successCriteria: - condition: $statusCode == 200 - condition: $response.body#/cluster/status == "ready" outputs: clusterStatus: $response.body#/cluster/status clusterPeers: $response.body#/cluster/peers version: $response.body#/versionInfo/version uptime: $response.body#/uptime - stepId: confirmReceiverExists description: >- List the receivers defined in the loaded configuration. If the expected receiver is not in this list the routing tree cannot possibly select it, and the test would fail for a reason the alert itself never reveals. operationId: listReceivers successCriteria: - condition: $statusCode == 200 outputs: receivers: $response.body firstReceiverName: $response.body#/0/name - stepId: postSyntheticAlert description: >- Post the synthetic alert exactly as Prometheus would. The labels decide routing; the annotations are carried through to the notification template so the recipient can see this is a test. operationId: postAlerts requestBody: contentType: application/json payload: - labels: alertname: $inputs.alertName severity: $inputs.severity annotations: summary: Synthetic alert posted to verify the Alertmanager routing tree. description: >- This alert was generated by an automated routing test and does not indicate a real problem. It resolves automatically. startsAt: $inputs.startsAt endsAt: $inputs.endsAt generatorURL: $inputs.generatorURL successCriteria: - condition: $statusCode == 200 - stepId: confirmAlertAccepted description: >- Read the alert back to confirm Alertmanager accepted and is now tracking it. The receivers field names every receiver it will notify. operationId: getAlerts parameters: - name: filter in: query value: - $inputs.alertNameMatcher - name: active in: query value: true - name: silenced in: query value: true - name: inhibited in: query value: true successCriteria: - condition: $statusCode == 200 outputs: alerts: $response.body fingerprint: $response.body#/0/fingerprint statusState: $response.body#/0/status/state receivers: $response.body#/0/receivers - stepId: confirmRouting description: >- Read the alert groups to see the receiver the routing tree actually chose and the group labels it was grouped under. This is the answer the test exists to produce. operationId: getAlertGroups parameters: - name: filter in: query value: - $inputs.alertNameMatcher - name: active in: query value: true - name: silenced in: query value: true - name: inhibited in: query value: true successCriteria: - condition: $statusCode == 200 outputs: groups: $response.body routedReceiver: $response.body#/0/receiver/name groupLabels: $response.body#/0/groupLabels groupedAlerts: $response.body#/0/alerts outputs: version: $steps.checkAlertmanagerStatus.outputs.version configuredReceivers: $steps.confirmReceiverExists.outputs.receivers fingerprint: $steps.confirmAlertAccepted.outputs.fingerprint routedReceiver: $steps.confirmRouting.outputs.routedReceiver groupLabels: $steps.confirmRouting.outputs.groupLabels