Fix Restic backup telemetry

This commit is contained in:
2026-09-27 13:31:07 -04:00
parent dc5c8ec1da
commit 34c03bc047
+62 -5
View File
@@ -1,9 +1,12 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
import subprocess
import json import json
import logging
import subprocess
from datetime import datetime, timezone
RESTIC_ENV = "/etc/restic/edge01.env" RESTIC_ENV = "/etc/restic/edge01.env"
LOGGER = logging.getLogger(__name__)
def collect(): def collect():
@@ -16,17 +19,71 @@ def collect():
) )
if result.returncode != 0: if result.returncode != 0:
LOGGER.error("Restic snapshots failed: %s", result.stderr.strip())
return { return {
"state": "offline", "state": "offline",
"summary": "Restic error", "status": "error",
"detail": result.stderr.strip() "summary": "Backup error",
"detail": "Restic snapshot query failed; see collector logs",
} }
try:
snapshots = json.loads(result.stdout) snapshots = json.loads(result.stdout)
except json.JSONDecodeError:
LOGGER.error("Restic snapshots returned invalid JSON")
return {
"state": "offline",
"status": "error",
"summary": "Backup error",
"detail": "Restic returned invalid snapshot data; see collector logs",
}
if not isinstance(snapshots, list):
LOGGER.error("Restic snapshots returned an unexpected JSON shape")
return {
"state": "offline",
"status": "error",
"summary": "Backup error",
"detail": "Restic returned an unexpected snapshot response; see collector logs",
}
if not snapshots:
return {
"state": "offline",
"status": "error",
"summary": "Backup error",
"detail": "Restic repository contains no snapshots",
"snapshot_count": 0,
}
try:
latest = max(
snapshots,
key=lambda snapshot: datetime.fromisoformat(snapshot["time"]),
)
latest_time = datetime.fromisoformat(latest["time"])
except (KeyError, TypeError, ValueError):
LOGGER.error("Restic snapshots contained an invalid timestamp")
return {
"state": "offline",
"status": "error",
"summary": "Backup error",
"detail": "Restic returned snapshots without valid timestamps; see collector logs",
"snapshot_count": len(snapshots),
}
age_seconds = max(0, int((datetime.now(timezone.utc) - latest_time).total_seconds()))
age_hours, remainder = divmod(age_seconds, 3600)
age_minutes = remainder // 60
age = f"{age_hours}h {age_minutes}m" if age_hours else f"{age_minutes}m"
return { return {
"state": "online", "state": "online",
"status": "healthy",
"summary": "Healthy", "summary": "Healthy",
"detail": f"{len(snapshots)} snapshots", "detail": f"{len(snapshots)} snapshots · latest {latest_time.isoformat()} · age {age}",
"snapshot_count": len(snapshots) "snapshot_count": len(snapshots),
"latest_snapshot": latest_time.isoformat(),
"latest_snapshot_age": age,
"latest_snapshot_age_seconds": age_seconds,
} }