73 lines
2.4 KiB
Text
73 lines
2.4 KiB
Text
|
|
#!/usr/bin/env python3
|
||
|
|
"""Relais local : reçoit le webhook JSON d'Alertmanager, le transforme en
|
||
|
|
notification ntfy. Géré par Ansible (rôle supervision) — ne pas modifier à la
|
||
|
|
main. N'écoute que sur 127.0.0.1 : jamais exposé en dehors du serveur.
|
||
|
|
|
||
|
|
L'URL ntfy (avec le topic) est un secret : lue depuis {{ supervision_fichier_webhook }}
|
||
|
|
à chaque notification, jamais mise en cache, jamais journalisée.
|
||
|
|
"""
|
||
|
|
import http.server
|
||
|
|
import json
|
||
|
|
import urllib.request
|
||
|
|
|
||
|
|
FICHIER_WEBHOOK = "{{ supervision_fichier_webhook }}"
|
||
|
|
ADRESSE = ("127.0.0.1", {{ supervision_port_relais }})
|
||
|
|
|
||
|
|
|
||
|
|
def lire_url_ntfy():
|
||
|
|
with open(FICHIER_WEBHOOK, encoding="utf-8") as f:
|
||
|
|
return f.read().strip()
|
||
|
|
|
||
|
|
|
||
|
|
class Gestionnaire(http.server.BaseHTTPRequestHandler):
|
||
|
|
def do_POST(self):
|
||
|
|
longueur = int(self.headers.get("Content-Length", 0))
|
||
|
|
corps = self.rfile.read(longueur)
|
||
|
|
try:
|
||
|
|
charge = json.loads(corps)
|
||
|
|
except ValueError:
|
||
|
|
self.send_response(400)
|
||
|
|
self.end_headers()
|
||
|
|
return
|
||
|
|
|
||
|
|
try:
|
||
|
|
url_ntfy = lire_url_ntfy()
|
||
|
|
except OSError:
|
||
|
|
self.send_response(500)
|
||
|
|
self.end_headers()
|
||
|
|
return
|
||
|
|
|
||
|
|
for alerte in charge.get("alerts", []):
|
||
|
|
statut = alerte.get("status", "inconnu")
|
||
|
|
nom = alerte.get("labels", {}).get("alertname", "?")
|
||
|
|
resume = (
|
||
|
|
alerte.get("annotations", {}).get("description")
|
||
|
|
or alerte.get("annotations", {}).get("summary")
|
||
|
|
or nom
|
||
|
|
)
|
||
|
|
titre = f"[{statut.upper()}] {nom}"
|
||
|
|
requete = urllib.request.Request(
|
||
|
|
url_ntfy,
|
||
|
|
data=resume.encode("utf-8"),
|
||
|
|
method="POST",
|
||
|
|
headers={
|
||
|
|
"Title": titre,
|
||
|
|
"Priority": "high" if statut == "firing" else "default",
|
||
|
|
},
|
||
|
|
)
|
||
|
|
try:
|
||
|
|
urllib.request.urlopen(requete, timeout=5)
|
||
|
|
except Exception:
|
||
|
|
pass # ne bloque jamais Alertmanager ; vérifier manuellement en cas de doute
|
||
|
|
|
||
|
|
self.send_response(200)
|
||
|
|
self.end_headers()
|
||
|
|
|
||
|
|
def log_message(self, format, *args): # silencieux : rien de secret à tracer non plus
|
||
|
|
pass
|
||
|
|
|
||
|
|
|
||
|
|
if __name__ == "__main__":
|
||
|
|
serveur = http.server.HTTPServer(ADRESSE, Gestionnaire)
|
||
|
|
serveur.serve_forever()
|