Health-Metriken im Checkin + Jitter aufs Standardintervall
collect_health() sammelt Diskbelegung/RAM/Uptime/Load Average rein per Stdlib (shutil.disk_usage, /proc/meminfo, /proc/uptime, os.getloadavg), jeder Wert einzeln try/except. checkin() schickt das Ergebnis jetzt mit. main()-Loop wendet 0-30 Min Jitter nur auf 'große' Intervalle (>=1h) an - der kurze Debug-Modus (60s) und der Fallback-Retry bleiben unverjittert, sonst würde Jitter den Debug-Zweck untergraben. Boot-Checkin war schon vorher vorhanden (run_once() läuft immer vor der ersten sleep()), hier nicht angefasst. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
parent
26fabfff03
commit
1046f9f13c
58
agent.py
58
agent.py
@ -1,5 +1,6 @@
|
||||
import json
|
||||
import os
|
||||
import random
|
||||
import shutil
|
||||
import subprocess
|
||||
import sys
|
||||
@ -13,6 +14,12 @@ CREDENTIALS_PATH = os.environ.get(
|
||||
"TUXFLOTTE_AGENT_CREDENTIALS", "/etc/tuxflotte/agent.credentials"
|
||||
)
|
||||
FALLBACK_INTERVAL_SECONDS = 60
|
||||
# Jitter (26.08.2026-Planung): nur auf "grosse" Intervalle (Standard 6h)
|
||||
# anwenden, nicht auf den kurzen Debug-Modus (60s) oder den Fallback-Retry
|
||||
# (FALLBACK_INTERVAL_SECONDS) - sonst wuerde Jitter genau den Zweck des
|
||||
# schnellen Debug-Zyklus untergraben.
|
||||
JITTER_THRESHOLD_SECONDS = 60 * 60
|
||||
JITTER_MAX_SECONDS = 30 * 60
|
||||
|
||||
|
||||
def log(message):
|
||||
@ -71,9 +78,55 @@ def bootstrap(device_id):
|
||||
return json.loads(response.read().decode("utf-8"))
|
||||
|
||||
|
||||
def collect_health():
|
||||
"""
|
||||
Health-Metriken fuers Checkin (26.08.2026-Planung) - reines Stdlib,
|
||||
keine neue Abhaengigkeit. Jeder Einzelwert einzeln in try/except: ein
|
||||
fehlschlagender Wert (z.B. Load Average auf einem ungewoehnlichen
|
||||
System) darf die anderen nicht verhindern.
|
||||
"""
|
||||
|
||||
health = {}
|
||||
|
||||
try:
|
||||
nutzung = shutil.disk_usage("/")
|
||||
health["disk_used_percent"] = round(nutzung.used / nutzung.total * 100, 1)
|
||||
except OSError as exc:
|
||||
log(f"Health: Diskbelegung nicht ermittelbar: {exc}")
|
||||
|
||||
try:
|
||||
werte = {}
|
||||
with open("/proc/meminfo", "r", encoding="utf-8") as f:
|
||||
for zeile in f:
|
||||
schluessel, _, rest = zeile.partition(":")
|
||||
if schluessel in ("MemTotal", "MemAvailable"):
|
||||
werte[schluessel] = int(rest.strip().split()[0])
|
||||
if werte.get("MemTotal"):
|
||||
belegt = werte["MemTotal"] - werte.get("MemAvailable", 0)
|
||||
health["ram_used_percent"] = round(belegt / werte["MemTotal"] * 100, 1)
|
||||
except (OSError, ValueError) as exc:
|
||||
log(f"Health: RAM-Auslastung nicht ermittelbar: {exc}")
|
||||
|
||||
try:
|
||||
with open("/proc/uptime", "r", encoding="utf-8") as f:
|
||||
health["uptime_seconds"] = int(float(f.read().split()[0]))
|
||||
except (OSError, ValueError) as exc:
|
||||
log(f"Health: Uptime nicht ermittelbar: {exc}")
|
||||
|
||||
try:
|
||||
load1, load5, load15 = os.getloadavg()
|
||||
health["load_1m"] = round(load1, 2)
|
||||
health["load_5m"] = round(load5, 2)
|
||||
health["load_15m"] = round(load15, 2)
|
||||
except OSError as exc:
|
||||
log(f"Health: Load Average nicht ermittelbar: {exc}")
|
||||
|
||||
return health
|
||||
|
||||
|
||||
def checkin(device_id, agent_secret):
|
||||
return api_request(
|
||||
"/api/v1/agent/checkin", agent_secret, {"device_id": device_id}
|
||||
"/api/v1/agent/checkin", agent_secret, {"device_id": device_id, "health": collect_health()}
|
||||
)
|
||||
|
||||
|
||||
@ -205,6 +258,9 @@ def main():
|
||||
log(f"Check-in-Fehler: {exc}")
|
||||
interval = FALLBACK_INTERVAL_SECONDS
|
||||
|
||||
if interval >= JITTER_THRESHOLD_SECONDS:
|
||||
interval += random.uniform(0, JITTER_MAX_SECONDS)
|
||||
|
||||
time.sleep(interval)
|
||||
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user