Welle 1 · Vorhersage „voll in etwa N Tagen“: Pool, NAS, Systemplatte, Container, VMs und die Platte der KI-Box

Aus dem Verlauf der Woche (Tagesmittel, Schutz gegen einmalige Sprünge, schneller werdendes Volllaufen zählt sofort):
gelb unter 14, rot unter 3 Tagen. Der Wächter meldet es, auch wenn der Füllstand selbst noch unauffällig ist;
Speicherkarte, Geräte-Tabelle, Instrumente der Übersicht und die KI-Box-Seite zeigen es an. Jeder Bericht des
Ausführers schreibt dafür die Belegungen in die Messreihe „speicher“.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Hitonabi
2026-09-25 16:21:38 +02:00
co-authored by Claude Opus 5.5
parent 34360c9644
commit f7a9b8ad50
19 changed files with 691 additions and 72 deletions
+42 -22
View File
@@ -9,7 +9,7 @@ gesehen. Dieser Wächter schaut deshalb breiter hin:
• Timer-Läufe Einmal-Dienste hinter Timern (projekte-sync, Sicherung)
• Hermes-Jobs Status der Cron-Jobs + Werkzeugfehler im letzten Lauf (errors.log)
• Kern Engine, Hirn, Hermes, Hör-Dienst, MC2, Gateway antworten per HTTP
• Platte Füllstand des Modell-Laufwerks
• Platte Füllstand des Modell-Laufwerks, seit 25.09.2026 auch das Tempo („in etwa N Tagen voll“)
• Updates Bausteine, die der Sonntags-Lauf nach einem Fehlschlag festhält
• Probe monatliche Probe-Wiederherstellung der Sicherung (rot oder zu alt = gelb)
@@ -44,7 +44,7 @@ from pathlib import Path
import httpx
import psutil
from config import HERMES_API_KEY, HERMES_API_URL, HERMES_HOME, VOICE_SERVICE_URL
from kern import partner
from kern import partner, prognose
from kern.einstellungen import einstellungen
from kern.zeit import LOCAL_TZ
@@ -454,19 +454,29 @@ def pruefe_kern() -> list[Befund]:
def pruefe_platte() -> list[Befund]:
"""Füllstand der eigenen Platte (gelb ab DISK_GELB_PCT, rot ab DISK_ROT_PCT). Auf der KI-Box seit 25.09.2026
auch das Tempo des Modell-Laufwerks (kern/prognose.py): in weniger als 14 Tagen voll = gelb, unter 3 Tagen rot —
als eigener Hinweis, wenn er ernster ist als der Füllstand."""
befunde, stufe = [], "ok"
try:
pct = psutil.disk_usage(str(DATEN_DIR) if DATEN_DIR.exists() else os.getcwd()).percent
except Exception:
return []
if pct >= DISK_ROT_PCT:
stufe = "rot"
elif pct >= DISK_GELB_PCT:
stufe = "gelb"
else:
return []
return [Befund(id="platte", stufe=stufe, titel=f"Die Platte ist zu {pct:.0f} % voll",
text="Es wird eng für Modelle und Sicherungen. Alte Modelldateien löschen hilft am meisten.",
quelle="platte", sofort=True)]
pct = None
if pct is not None and pct >= DISK_GELB_PCT:
stufe = "rot" if pct >= DISK_ROT_PCT else "gelb"
befunde.append(Befund(id="platte", stufe=stufe, titel=f"Die Platte ist zu {pct:.0f} % voll",
text="Es wird eng für Modelle und Sicherungen. Alte Modelldateien löschen hilft am meisten.",
quelle="platte", sofort=True))
if ROLLE == "box":
from services import messwerte
v = prognose.aus_messreihe(messwerte.QUELLE, "platte")
kuenftig, kommend = prognose.schlimmer(stufe, v)
if kommend:
befunde.append(Befund(
id="platte:tempo", stufe=kuenftig, titel=f"Die Platte ist {prognose.in_tagen(v['tage'])} voll",
text=f"{prognose.tempo(v)} Alte Modelldateien löschen hilft am meisten: KI-Box → Modelle → Aufräumen.",
quelle="platte"))
return befunde
def pruefe_probe_wiederherstellung() -> list[Befund]:
@@ -563,28 +573,38 @@ def _gb_komma(n: float) -> str:
def pruefe_gast_platten() -> list[Befund]:
"""Homelab: Läuft die Platte eines Containers voll? Am 24.09.2026 stand AdGuard bei 100 %: Das Abfrageprotokoll
schrieb nicht mehr, die Paketsuche scheiterte — und keine Anzeige sagte es."""
from services.homelab import apps, kanal
schrieb nicht mehr, die Paketsuche scheiterte — und keine Anzeige sagte es. Seit 25.09.2026 auch nach dem Tempo
(kern/prognose.py): in weniger als 14 Tagen voll = gelb, unter 3 Tagen rot."""
from services.homelab import apps, kanal, speicher
daten = kanal.bericht()
befunde = []
for g in (daten or {}).get("bericht", {}).get("gaeste") or []:
platte = g.get("platte") or {}
gesamt, belegt = platte.get("gesamt"), platte.get("belegt") or 0
if not gesamt or belegt / gesamt < GAST_PLATTE_GELB:
if not gesamt:
continue
app = apps.app_fuer((g.get("app") or {}).get("kennung"), g.get("name"))
name = app.name if app else str(g.get("name") or g["vmid"])
anteil = belegt / gesamt
# Seit 25.09.2026 kennt der Bericht auch die Platte der VMs (über den Gast-Agenten).
vm = g.get("art") != "lxc"
zid = f"{'vm' if vm else 'ct'}-{g['vmid']}"
v = speicher.platten_vorhersage(zid)
jetzt_stufe = "rot" if anteil >= GAST_PLATTE_ROT else "gelb" if anteil >= GAST_PLATTE_GELB else "ok"
stufe, kommend = prognose.schlimmer(jetzt_stufe, v)
if stufe == "ok":
continue
app = apps.app_fuer((g.get("app") or {}).get("kennung"), g.get("name"))
name = app.name if app else str(g.get("name") or g["vmid"])
vergroessern = ("VM → Hardware → Festplatte → Aktion → Größe ändern, danach in der VM das Dateisystem "
"mitwachsen lassen" if vm else "Container → Ressourcen → Laufwerk → Größe ändern")
befunde.append(Befund(
id=f"gast-platte:{g['vmid']}", stufe="rot" if anteil >= GAST_PLATTE_ROT else "gelb",
titel=f"Platte von {name} zu {min(100, round(anteil * 100))} % voll",
text=(f"{_gb_komma(belegt)} von {_gb_komma(gesamt)} GB belegt ({'VM' if vm else 'Container'} {g['vmid']}). "
f"Platz schaffen oder in Proxmox die Platte vergrößern: {vergroessern}."),
quelle=f"{'vm' if vm else 'ct'}-{g['vmid']}"))
id=f"gast-platte:{g['vmid']}", stufe=stufe,
titel=(f"Platte von {name} {prognose.in_tagen(v['tage'])} voll" if kommend
else f"Platte von {name} zu {min(100, round(anteil * 100))} % voll"),
text=((f"{prognose.tempo(v)} " if kommend else "")
+ f"{_gb_komma(belegt)} von {_gb_komma(gesamt)} GB belegt ({'VM' if vm else 'Container'} {g['vmid']})."
+ ("" if kommend else prognose.dazu(v))
+ f" Platz schaffen oder in Proxmox die Platte vergrößern: {vergroessern}."),
quelle=zid))
return befunde