Lesender Selbsttest (Version, Services, Hosts, Downtimes) beim Start und täglich 04:00, Seite /selftest, Teilcheck checkmk_api in /health, Chat-Meldung bei Wechsel. Toleranter Antwort-Parser (value/members, state_type int/String), Fallbacks für Host-Abfrage und Downtime-Liste, Fehlerhinweise je HTTP-Status. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
72 lines
2.2 KiB
Python
Executable File
72 lines
2.2 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
# Checkmk-Local-Check: ruft /health des Bots ab und gibt pro Teilcheck eine Zeile "Status Name Metrik Text" aus.
|
|
import json
|
|
import os
|
|
import sys
|
|
import urllib.error
|
|
import urllib.request
|
|
|
|
HEALTH_URL = os.environ.get("CHECKBOT_HEALTH_URL", "http://127.0.0.1:8080/health")
|
|
# Der Bot prüft seine Backends mit bis zu 10 s Timeout, daher etwas mehr.
|
|
TIMEOUT_SECONDS = 15
|
|
CHECK_NAMES = ("db", "checkmk", "checkmk_api", "ollama", "poller", "telegram", "matrix")
|
|
SERVICE_PREFIX = "Checkbot_"
|
|
API_SERVICE = "Checkbot_api"
|
|
NOT_CONFIGURED = "nicht konfiguriert"
|
|
NOT_YET_RUN = "noch nicht gelaufen"
|
|
WARN_DETAILS = (NOT_CONFIGURED, NOT_YET_RUN)
|
|
MAX_TEXT = 200
|
|
OK, WARN, CRIT = 0, 1, 2
|
|
|
|
|
|
def fetch_health() -> dict:
|
|
request = urllib.request.Request(HEALTH_URL, headers={"Accept": "application/json"})
|
|
try:
|
|
with urllib.request.urlopen(request, timeout=TIMEOUT_SECONDS) as response:
|
|
body = response.read()
|
|
except urllib.error.HTTPError as exc:
|
|
body = exc.read()
|
|
data = json.loads(body)
|
|
if not isinstance(data.get("checks"), dict):
|
|
raise ValueError("Antwort ohne Feld 'checks'")
|
|
return data
|
|
|
|
|
|
def clean(text) -> str:
|
|
return " ".join(str(text).split())[:MAX_TEXT]
|
|
|
|
|
|
def line(state: int, name: str, text: str) -> str:
|
|
return f"{state} {name} - {clean(text)}"
|
|
|
|
|
|
def evaluate(name: str, result: dict | None) -> str:
|
|
service = SERVICE_PREFIX + name
|
|
if result is None:
|
|
return line(OK, service, "deaktiviert")
|
|
detail = result.get("detail", "")
|
|
if result.get("ok"):
|
|
return line(OK, service, detail or "ok")
|
|
if detail in WARN_DETAILS:
|
|
return line(WARN, service, detail)
|
|
return line(CRIT, service, detail or "Fehler")
|
|
|
|
|
|
def main() -> int:
|
|
try:
|
|
checks = fetch_health()["checks"]
|
|
except Exception as exc:
|
|
reason = f"Bot nicht erreichbar ({type(exc).__name__}: {exc})"
|
|
print(line(CRIT, API_SERVICE, reason))
|
|
for name in CHECK_NAMES:
|
|
print(line(CRIT, SERVICE_PREFIX + name, reason))
|
|
return 0
|
|
print(line(OK, API_SERVICE, f"{HEALTH_URL} erreichbar"))
|
|
for name in CHECK_NAMES:
|
|
print(evaluate(name, checks.get(name)))
|
|
return 0
|
|
|
|
|
|
if __name__ == "__main__":
|
|
sys.exit(main())
|