Files
brain-of-reese/tests/fixtures/docs/homelab/scripts/uptime_probe.py
T

61 lines
1.6 KiB
Python

"""Uptime probe — the homelab healthcheck runner.
Polls every service listed in ``CHECKS`` every 5 minutes and posts a
failure to the ntfy topic ``homelab-alerts``.
"""
from __future__ import annotations
import subprocess
#: (name, health URL) for every long-running service.
CHECKS: list[tuple[str, str]] = [
("k3s", "https://10.0.1.10:6443/healthz"),
("gitea", "https://gitea.reeseapps.com/api/healthz"),
("ntfy", "https://ntfy.reeseapps.com/health"),
("gitlab", "https://gitlab.reeseapps.com/-/health_check"),
]
def probe(name: str, url: str) -> bool:
"""One HTTP check; returns True when the service answered 200."""
result = subprocess.run(
["curl", "-s", "-o", "/dev/null", "-w", "%{http_code}", "--max-time", "10", url],
capture_output=True,
text=True,
)
return result.stdout.strip() == "200"
def notify_failure(name: str) -> None:
"""Push an alert to ntfy (best effort — alerting must not crash the probe)."""
subprocess.run(
[
"curl",
"-s",
"-X",
"POST",
"https://ntfy.reeseapps.com/homelab-alerts",
"-H",
"Title: homelab check failed",
"-d",
f"{name} is down",
],
capture_output=True,
)
def run_round() -> int:
"""Probe everything once; returns the number of failing services."""
failed = 0
for name, url in CHECKS:
if not probe(name, url):
failed += 1
notify_failure(name)
return failed
if __name__ == "__main__":
import sys
sys.exit(run_round())