Webhooks¶
Generischer Output: bei einem Alert schickt Vesana einen JSON-POST an eine URL deiner Wahl. Damit lässt sich alles anflanschen — eigene Ticket-Systeme, Pager, IFTTT, n8n, Zapier.
Konfiguration¶
/notification-channels → Neuer Channel → Typ Webhook:
| Feld | Wert |
|---|---|
| Name | „Pager-Webhook" |
| URL | https://pager.example.com/incoming/... |
| Method | POST (Default) |
| Auth | None / Basic / Bearer |
| Headers | Custom-Header für Auth o. ä. |
| HMAC-Secret | optional, für Signatur-Validierung |
| Payload-Template | Default oder Custom-Jinja |
Default-Payload¶
{
"version": 1,
"alert_id": "uuid",
"rule_name": "Disk Full Critical",
"rule_id": "uuid",
"status": "CRITICAL",
"trigger_at": "2026-04-25T10:15:30Z",
"is_recovery": false,
"host": {
"id": "uuid",
"name": "web01.acme.local",
"ip_address": "10.10.5.13",
"tenant": { "id": "uuid", "name": "Acme GmbH" },
"tags": ["production","web"],
"url": "https://vesana.example.com/hosts/uuid"
},
"service": {
"id": "uuid",
"display_name": "Disk /var",
"check_type": "agent_disk",
"value": 96.4,
"message": "CRITICAL - /var at 96%",
"perfdata": { "used_percent": 96.4 }
},
"previous_status": "WARNING",
"duration_seconds": 320
}
HMAC-Signierung¶
Wenn webhook_secret gesetzt:
signature wird berechnet als HMAC-SHA256(secret, timestamp + "." + body). Empfänger soll selbst signieren und vergleichen:
import hmac, hashlib
def valid(body: bytes, ts: str, sig: str, secret: str) -> bool:
expected = "sha256=" + hmac.new(
secret.encode(),
f"{ts}.".encode() + body,
hashlib.sha256,
).hexdigest()
return hmac.compare_digest(sig, expected)
Replay-Schutz: Timestamps älter als 5 min ablehnen.
Custom-Payload-Template¶
Wenn der Empfänger ein bestimmtes Format erwartet (z. B. PagerDuty-Events):
{
"routing_key": "{{ env.PAGERDUTY_KEY }}",
"event_action": "{% if alert.is_recovery %}resolve{% else %}trigger{% endif %}",
"dedup_key": "vesana:{{ alert.service.id }}",
"payload": {
"summary": "{{ alert.host.name }} — {{ alert.service.display_name }}: {{ alert.message }}",
"severity": "{{ alert.status | lower }}",
"source": "{{ alert.host.name }}",
"custom_details": {
"tenant": "{{ alert.host.tenant.name }}",
"value": {{ alert.service.value }}
}
}
}
Damit lässt sich Vesana direkt an PagerDuty, OpsGenie, VictorOps etc. anflanschen.
Retry¶
Bei Empfänger-Fehler (Timeout, 5xx):
- 3 Retries mit Backoff: 5 s, 30 s, 5 min
- Nach drittem Fehlversuch:
failed-Eintrag im Notification-Log
4xx-Antworten werden nicht retried — die sieht der Server als „Empfänger sagt nein, akzeptier es".
Gruppen-Payloads¶
Bei aktiver Gruppierung in der Alert-Rule kommt ein Array:
{
"version": 1,
"group_id": "uuid",
"rule_name": "Disk Full Critical",
"alerts": [
{ "host": {...}, "service": {...} },
{ "host": {...}, "service": {...} },
...
],
"alert_count": 12
}
Empfänger sollte beide Cases (single + group) handhaben.
Test¶
/notification-channels → Channel → Test:
- Schickt Fake-Alert-Payload
- UI zeigt HTTP-Status, Response-Body, Latenz
- Wenn HMAC: Signature wird mitgeschickt, Empfänger kann seine Validierung testen
Audit¶
Jede Webhook-Notification (success oder fail) im Audit-Log mit action = notification.send.