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 json
|
||||||
import os
|
import os
|
||||||
|
import random
|
||||||
import shutil
|
import shutil
|
||||||
import subprocess
|
import subprocess
|
||||||
import sys
|
import sys
|
||||||
@ -13,6 +14,12 @@ CREDENTIALS_PATH = os.environ.get(
|
|||||||
"TUXFLOTTE_AGENT_CREDENTIALS", "/etc/tuxflotte/agent.credentials"
|
"TUXFLOTTE_AGENT_CREDENTIALS", "/etc/tuxflotte/agent.credentials"
|
||||||
)
|
)
|
||||||
FALLBACK_INTERVAL_SECONDS = 60
|
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):
|
def log(message):
|
||||||
@ -71,9 +78,55 @@ def bootstrap(device_id):
|
|||||||
return json.loads(response.read().decode("utf-8"))
|
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):
|
def checkin(device_id, agent_secret):
|
||||||
return api_request(
|
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}")
|
log(f"Check-in-Fehler: {exc}")
|
||||||
interval = FALLBACK_INTERVAL_SECONDS
|
interval = FALLBACK_INTERVAL_SECONDS
|
||||||
|
|
||||||
|
if interval >= JITTER_THRESHOLD_SECONDS:
|
||||||
|
interval += random.uniform(0, JITTER_MAX_SECONDS)
|
||||||
|
|
||||||
time.sleep(interval)
|
time.sleep(interval)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user