Regeln decken die real erlebten Fehlerklassen ab: TargetDown (coturn-Klasse), KubePodRestartLoop (36k-Restarts-Klasse), OOM-Kills, RAM-/Swap-/Disk-Druck. Zustellung in den wartung-Raum ueber einen minimalen Stdlib-Webhook-Receiver (gleiche Machart wie maintenance-notify, gitops Issue #24); Bot-Token kommt beim Deploy per .env (Vorlage in .env.example). UNGETESTET/DEPLOY-PENDING: promtool/amtool-Lint auf dem Mac an haengendem Docker-Hub-Pull gescheitert - vor dem Deploy auf CFGMON ausfuehren (Images liegen dort bereits): docker run --rm -v $PWD/monitoring/prometheus:/cfg:ro --entrypoint promtool prom/prometheus:v3.3.1 check rules /cfg/alerts.yml docker run --rm -v $PWD/monitoring/alertmanager:/cfg:ro --entrypoint amtool prom/alertmanager:v0.28.1 check-config /cfg/alertmanager.yml Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
43 lines
1.9 KiB
Python
43 lines
1.9 KiB
Python
#!/usr/bin/env python3
|
|
# Minimaler Alertmanager-Webhook -> Matrix-Raum (gitops#32). Gleiche Machart wie
|
|
# maintenance-notify (Issue #24 im gitops-Repo): purer Stdlib-HTTP-Server, Bot-Token
|
|
# aus der Umgebung, Nachricht per Client-Server-API. Kein Framework, kein State.
|
|
import json, os, urllib.request, uuid
|
|
from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer
|
|
|
|
HOMESERVER = os.environ["MATRIX_HOMESERVER"]
|
|
ROOM_ID = os.environ["MATRIX_ROOM_ID"]
|
|
TOKEN = os.environ["MATRIX_TOKEN"]
|
|
|
|
def send_matrix(text):
|
|
url = f"{HOMESERVER}/_matrix/client/v3/rooms/{urllib.parse.quote(ROOM_ID)}/send/m.room.message/{uuid.uuid4()}"
|
|
body = json.dumps({"msgtype": "m.text", "body": text}).encode()
|
|
req = urllib.request.Request(url, data=body, method="PUT", headers={
|
|
"Authorization": f"Bearer {TOKEN}", "Content-Type": "application/json"})
|
|
urllib.request.urlopen(req, timeout=10).read()
|
|
|
|
class Handler(BaseHTTPRequestHandler):
|
|
def do_POST(self):
|
|
if self.path != "/alert":
|
|
self.send_response(404); self.end_headers(); return
|
|
data = json.loads(self.rfile.read(int(self.headers.get("Content-Length", 0))))
|
|
lines = []
|
|
for a in data.get("alerts", []):
|
|
icon = "\U0001F534" if a.get("status") == "firing" else "✅"
|
|
name = a.get("labels", {}).get("alertname", "?")
|
|
summary = a.get("annotations", {}).get("summary", "")
|
|
lines.append(f"{icon} [{a.get('status')}] {name}: {summary}")
|
|
if lines:
|
|
try:
|
|
send_matrix("\n".join(lines))
|
|
except Exception as e:
|
|
self.log_message("matrix send failed: %s", e)
|
|
self.send_response(502); self.end_headers(); return
|
|
self.send_response(200); self.end_headers()
|
|
|
|
def log_message(self, fmt, *args):
|
|
print(fmt % args, flush=True)
|
|
|
|
import urllib.parse
|
|
ThreadingHTTPServer(("0.0.0.0", 8080), Handler).serve_forever()
|