Add Voyager tunnel and monitoring telemetry

This commit is contained in:
2026-09-27 22:11:16 -04:00
parent 34c03bc047
commit b91af32561
5 changed files with 189 additions and 24 deletions
+82
View File
@@ -0,0 +1,82 @@
#!/usr/bin/env python3
import re
import sqlite3
import subprocess
CONTAINER = "uptime-kuma"
DATABASE = "/opt/docker/uptime-kuma/data/kuma.db"
def _failure(detail):
return {
"state": "offline", "health": "unavailable", "summary": "Unavailable",
"detail": detail, "container_available": False, "version": None,
"active_monitors": 0, "up_count": 0, "down_count": 0, "unknown_count": 0,
}
def _container_info():
result = subprocess.run(
["docker", "inspect", "--format",
"{{.State.Status}}\t{{.State.Health.Status}}\t{{.Config.Image}}",
CONTAINER], capture_output=True, text=True)
if result.returncode != 0:
return None
fields = result.stdout.strip().split("\t")
if len(fields) != 3:
return None
status, health, image = fields
match = re.search(r":([^:@]+)$", image)
return status, health, match.group(1) if match else None
def _database_counts():
connection = sqlite3.connect(f"file:{DATABASE}?mode=ro", uri=True, timeout=5)
try:
rows = connection.execute(
"""
SELECT m.id,
(SELECT h.status FROM heartbeat h
WHERE h.monitor_id = m.id
ORDER BY h.id DESC LIMIT 1) AS latest_status
FROM monitor m
WHERE m.active = 1
"""
).fetchall()
finally:
connection.close()
counts = {"active": len(rows), "up": 0, "down": 0, "unknown": 0}
for _, status in rows:
if status == 1:
counts["up"] += 1
elif status == 0:
counts["down"] += 1
else:
counts["unknown"] += 1
return counts
def collect():
container = _container_info()
if container is None:
return _failure("Uptime Kuma container unavailable")
container_status, container_health, version = container
if container_status != "running":
return _failure("Uptime Kuma container is not running")
try:
counts = _database_counts()
except (OSError, sqlite3.Error):
return _failure("Uptime Kuma aggregate query unavailable")
active, up = counts["active"], counts["up"]
down, unknown = counts["down"], counts["unknown"]
degraded = container_health == "unhealthy" or down > 0 or unknown > 0
version_detail = f"Uptime Kuma {version}" if version else "Uptime Kuma"
return {
"state": "warning" if degraded else "online",
"health": "partial" if degraded else "healthy",
"summary": f"{up}/{active} monitors up",
"detail": f"{version_detail} · edge01 monitoring operational",
"container_available": True, "container_health": container_health,
"version": version, "active_monitors": active, "up_count": up,
"down_count": down, "unknown_count": unknown,
}
+63
View File
@@ -0,0 +1,63 @@
#!/usr/bin/env python3
import subprocess
import time
INTERFACE = "wg0"
RECENT_HANDSHAKE_SECONDS = 30 * 60
def _failure(detail):
return {
"state": "offline", "health": "unavailable", "summary": "Unavailable",
"detail": detail, "interface": INTERFACE, "interface_active": False,
"configured_peers": 0, "recent_handshakes": 0, "stale_handshakes": 0,
"rx_bytes": 0, "tx_bytes": 0,
"recent_handshake_threshold_seconds": RECENT_HANDSHAKE_SECONDS,
}
def _format_bytes(value):
units = ("B", "KiB", "MiB", "GiB", "TiB")
amount = float(value)
for unit in units:
if amount < 1024 or unit == units[-1]:
return f"{amount:.2f} {unit}" if unit != "B" else f"{int(amount)} B"
amount /= 1024
def collect():
result = subprocess.run(["wg", "show", INTERFACE, "dump"],
capture_output=True, text=True)
if result.returncode != 0:
return _failure("WireGuard telemetry unavailable")
lines = [line.split() for line in result.stdout.splitlines() if line.strip()]
if not lines or len(lines[0]) < 4:
return _failure("WireGuard returned invalid telemetry")
peers = lines[1:]
now = int(time.time())
recent = rx_bytes = tx_bytes = 0
try:
for peer in peers:
if len(peer) < 8:
return _failure("WireGuard returned incomplete telemetry")
handshake = int(peer[4])
rx_bytes += int(peer[5])
tx_bytes += int(peer[6])
if handshake and now - handshake <= RECENT_HANDSHAKE_SECONDS:
recent += 1
except (TypeError, ValueError):
return _failure("WireGuard returned invalid telemetry")
configured = len(peers)
stale = configured - recent
state = "online" if configured and recent == configured else "warning"
health = "healthy" if state == "online" else "partial"
return {
"state": state, "health": health,
"summary": f"{recent}/{configured} peers recent",
"detail": (f"WireGuard active · {_format_bytes(rx_bytes)} RX · "
f"{_format_bytes(tx_bytes)} TX"),
"interface": INTERFACE, "interface_active": True,
"configured_peers": configured, "recent_handshakes": recent,
"stale_handshakes": stale, "rx_bytes": rx_bytes, "tx_bytes": tx_bytes,
"recent_handshake_threshold_seconds": RECENT_HANDSHAKE_SECONDS,
}