homelab: alte Kernel per Knopf entfernen; Systemplatte des Proxmox-Hosts im Blick
User-Wunsch 25.09.: Auf dem Host lagen 25 Kernel (~23 GB), 20 davon hält apt für entbehrlich (19,7 GB). - Ausführer: host.kernel_alt/kernel_bleiben aus apt-get -s autoremove (nur Kernel, nie laufender, nächster oder festgepinnter), host.systemplatte; neue Aktion kernel_aufraeumen bestimmt die Liste selbst und purgt. - Homelab-Teil: Lauf „kernel“ (Ergebnis aufgeraeumt), POST /api/homelab/ziele/pve/kernel-aufraeumen, Vorschlag mit Knopf, Wächter für die Systemplatte (80/90 %). - Oberfläche: Kachel Systemplatte, Knopf „Alte Kernel entfernen“ mit Rückfrage. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
28888890ec
commit
7a456c8efa
@@ -70,6 +70,12 @@ def host_neustart() -> dict:
|
||||
return _antwort(updates.starten("pve", "neustart"))
|
||||
|
||||
|
||||
@router.post("/ziele/pve/kernel-aufraeumen")
|
||||
def host_kernel_aufraeumen() -> dict:
|
||||
"""Alte Kernel vom Proxmox-Host entfernen (seit 25.09.2026, nur per Knopf). Welche, entscheidet der Ausführer."""
|
||||
return _antwort(updates.starten("pve", "kernel"))
|
||||
|
||||
|
||||
@router.post("/ziele/{ziel_id}/suchen")
|
||||
def suchen(ziel_id: str) -> dict:
|
||||
gast = inventar.gast(ziel_id)
|
||||
|
||||
@@ -33,7 +33,8 @@ except ImportError: # Windows (Entwicklung): nur die Thread-Sperre
|
||||
fcntl = None
|
||||
|
||||
AKTIONEN = {"bericht", "snapshot", "update", "os_update", "suchen", "zurueck", "snapshot_loeschen",
|
||||
"host_update", "host_neustart", "sichern", "sicherung_zurueck", "sicherung_loeschen"}
|
||||
"host_update", "host_neustart", "sichern", "sicherung_zurueck", "sicherung_loeschen",
|
||||
"kernel_aufraeumen"}
|
||||
VERLOREN_S = 3 * 3600 # abgeholt, aber nie beantwortet (Ausführer abgestürzt, Host neu gestartet)
|
||||
BEHALTEN = 500 # so viele erledigte Aufträge bleiben sichtbar (Protokoll; bis 24.09.2026: 60)
|
||||
VOLLTEXT = 60 # die jüngsten erledigten behalten ihre ganze Ausgabe …
|
||||
|
||||
@@ -62,10 +62,12 @@ _AKTION = {
|
||||
"host_update": ("Host-Pakete eingespielt", "Host-Pakete gescheitert", "Host-Pakete werden eingespielt",
|
||||
"Host-Pakete"),
|
||||
"host_neustart": ("Neustart ausgelöst", "Neustart gescheitert", "Neustart angefordert", "Neustart"),
|
||||
"kernel_aufraeumen": ("Alte Kernel entfernt", "Kernel aufräumen gescheitert", "Alte Kernel werden entfernt",
|
||||
"Kernel aufräumen"),
|
||||
}
|
||||
_HOST_AKTIONEN = {"bericht", "host_update", "host_neustart"}
|
||||
_HOST_AKTIONEN = {"bericht", "host_update", "host_neustart", "kernel_aufraeumen"}
|
||||
_LAUF_WAS = {"app": "Update", "os": "Paket-Update", "pakete": "Paket-Update", "docker": "Docker-Update",
|
||||
"neustart": "Neustart"}
|
||||
"neustart": "Neustart", "kernel": "Kernel-Aufräumen"}
|
||||
_SCHRITT_WORT = {"wartet": "wartet", "laeuft": "läuft", "eingespielt": "eingespielt",
|
||||
"zurueckgerollt": "zurückgerollt", "fehler": "gescheitert", "uebersprungen": "übersprungen"}
|
||||
_MELDUNG = re.compile(r"^(\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}) "
|
||||
@@ -313,6 +315,8 @@ def _lauf(x: dict, schw: Callable) -> dict | None:
|
||||
titel, stufe = f"{was} gescheitert · {name}", "fehler"
|
||||
elif ergebnis == "neustart":
|
||||
titel, stufe = f"Neustart ausgelöst · {name}", "info"
|
||||
elif ergebnis == "aufgeraeumt":
|
||||
titel, stufe = f"Alte Kernel entfernt · {name}", "ok"
|
||||
elif ergebnis == "offen":
|
||||
titel, stufe = f"Docker-Probelauf · {name}", "info"
|
||||
else:
|
||||
|
||||
@@ -9,6 +9,8 @@ Alles aus dem Bericht des Ausführers (alle 10 Minuten), dazu eine eigene Prüfu
|
||||
ist eingebunden, hängt nicht, hat Platz (80/90 % wie oben).
|
||||
• Sicherungen: Für jeden Gast, den ein Sicherungsauftrag erfasst, liegt auf dessen Ziel eine frische Sicherung
|
||||
(täglicher Auftrag: höchstens 26 Stunden alt, sonst 8 Tage), und das Ziel ist erreichbar.
|
||||
• Systemplatte des Proxmox-Hosts (Stufen wie oben): Dort liegen die Kernel, die Sicherungen vor Updates (local) und
|
||||
alles vom Host selbst. Alte Kernel lassen sich per Knopf entfernen (Ausführer: kernel_aufraeumen).
|
||||
Hinweise gehen über den Wächter (pruefe_speicher), die Oberfläche zeigt alles als Karte „Speicher und Sicherungen“ (lage).
|
||||
"""
|
||||
|
||||
@@ -111,7 +113,7 @@ def empfehlungen(bericht: dict) -> list[dict]:
|
||||
for u in g.get("ungenutzt") or []:
|
||||
liste.append({
|
||||
"art": "ungenutzt", "platz": u.get("belegt"), "titel": f"{_name(g)}: ungenutzte Platte {u['volume']}",
|
||||
"kurz": f"ungenutzte Platte bei {_name(g)}",
|
||||
"kurz": f"ungenutzte Platte bei {_name(g)}", "ort": "pool",
|
||||
"text": (f"Hängt an keinem Laufwerk mehr. Wird sie nicht mehr gebraucht: in Proxmox {_wo(g)} → Hardware "
|
||||
"→ „Unbenutzte Festplatte“ → Entfernen (löscht sie endgültig).")})
|
||||
if (summe := sum(x for _, x in container)) >= EMPFEHLUNG_AB:
|
||||
@@ -120,16 +122,18 @@ def empfehlungen(bericht: dict) -> list[dict]:
|
||||
befehle = "; ".join(f"pct fstrim {g['vmid']} --ignore-mountpoints" for g, _ in container)
|
||||
liste.append({
|
||||
"art": "trim", "platz": summe, "titel": "Container: freigegebenen Platz an den Pool zurückgeben",
|
||||
"kurz": f"{_groesse(summe)} per TRIM in den Containern",
|
||||
"kurz": f"{_groesse(summe)} per TRIM in den Containern", "ort": "pool",
|
||||
"text": (f"Die Container belegen im Pool {_gb(summe)} GB mehr, als sie nutzen ({einzeln}). In Proxmox: pve → "
|
||||
f"Shell → {befehle} — im laufenden Betrieb und ohne Verlust.")})
|
||||
for p in (bericht.get("host") or {}).get("pools") or []:
|
||||
for v in p.get("verwaist") or []:
|
||||
liste.append({
|
||||
"art": "verwaist", "platz": v.get("belegt"), "titel": f"Verwaiste Platte {v['volume']}",
|
||||
"kurz": f"verwaiste Platte {v['volume']}",
|
||||
"kurz": f"verwaiste Platte {v['volume']}", "ort": "pool",
|
||||
"text": (f"Gehört zu keinem Gast mehr. Wird sie nicht mehr gebraucht: in Proxmox pve → {p.get('speicher')} "
|
||||
"→ Datenträger → Entfernen (löscht sie endgültig).")})
|
||||
if kernel := _kernel_vorschlag(bericht.get("host") or {}):
|
||||
liste.append(kernel)
|
||||
liste.sort(key=lambda e: -(e["platz"] or 0))
|
||||
for g in gaeste:
|
||||
for s in g.get("snapshots") or []:
|
||||
@@ -137,6 +141,7 @@ def empfehlungen(bericht: dict) -> list[dict]:
|
||||
wann = f"vom {m.group(3)}.{m.group(2)}. {m.group(4)}:{m.group(5)}" if m else "von Hand angelegt"
|
||||
liste.append({
|
||||
"art": "snapshot", "platz": None, "titel": f"{_name(g)}: Snapshot {s}", "kurz": f"Snapshot bei {_name(g)}",
|
||||
"ort": "pool",
|
||||
"text": ((f"Rückweg des Updates {wann}. Läuft {_name(g)} seitdem gut, kann er weg" if m else
|
||||
f"Snapshot {wann}. Wird er nicht mehr gebraucht, kann er weg")
|
||||
+ f": in Proxmox {_wo(g)} → Snapshots → {s} → Entfernen. Wie viel er belegt, sagt Proxmox "
|
||||
@@ -144,6 +149,36 @@ def empfehlungen(bericht: dict) -> list[dict]:
|
||||
return liste
|
||||
|
||||
|
||||
def _kernel_vorschlag(host: dict) -> dict | None:
|
||||
"""Alte Kernel auf der Systemplatte des Hosts — mit Knopf. Die Liste stammt vom Ausführer (was apt für entbehrlich
|
||||
hält, nie der laufende oder der nächste); beim Klick bestimmt er sie noch einmal selbst."""
|
||||
alt = host.get("kernel_alt") or []
|
||||
if not alt:
|
||||
return None
|
||||
platz = sum(int(k.get("groesse") or 0) for k in alt)
|
||||
bleiben = ", ".join(str(v).removesuffix("-pve") for v in host.get("kernel_bleiben") or []) or "der laufende"
|
||||
return {
|
||||
"art": "kernel", "ort": "systemplatte", "platz": platz,
|
||||
"titel": f"Proxmox-Host: {len(alt)} alte Kernel entfernen",
|
||||
"kurz": f"{_groesse(platz)} alte Kernel auf dem Proxmox-Host",
|
||||
"text": (f"Liegen auf der Systemplatte des Hosts, nicht im Speicherpool. Entfernt wird nur, was Proxmox selbst für "
|
||||
f"entbehrlich hält; es bleiben {bleiben} — darunter der laufende und der für den nächsten Start. Die "
|
||||
"Gäste laufen weiter, ein Neustart ist dafür nicht nötig."),
|
||||
"aktion": {"methode": "POST", "pfad": "/api/homelab/ziele/pve/kernel-aufraeumen", "label": "Alte Kernel entfernen",
|
||||
"frage": (f"{len(alt)} alte Kernel vom Proxmox-Host entfernen (etwa {_groesse(platz)})? Es bleiben "
|
||||
f"{bleiben}. Die Gäste laufen weiter, ein Neustart ist nicht nötig.")},
|
||||
}
|
||||
|
||||
|
||||
def systemplatte(bericht: dict) -> dict | None:
|
||||
p = (bericht.get("host") or {}).get("systemplatte") or {}
|
||||
gesamt, belegt = p.get("gesamt"), p.get("belegt")
|
||||
if not gesamt or belegt is None:
|
||||
return None
|
||||
anteil = belegt / gesamt
|
||||
return {"belegt": belegt, "gesamt": gesamt, "frei": gesamt - belegt, "anteil": anteil, "stufe": _stufe(anteil)}
|
||||
|
||||
|
||||
def _trim_vm(g: dict, im_pool: int, genutzt: int, gewinn: int) -> dict:
|
||||
kopf = f"Im Pool belegt die VM {_gb(im_pool)} GB, genutzt sind darin {_gb(genutzt)} GB."
|
||||
if g.get("discard"):
|
||||
@@ -156,6 +191,7 @@ def _trim_vm(g: dict, im_pool: int, genutzt: int, gewinn: int) -> dict:
|
||||
"sofort mit „sudo fstrim -av“ in der VM.")
|
||||
return {"art": "trim-vm", "platz": gewinn, "titel": f"{_name(g)}: {_groesse(gewinn)} an den Pool zurückgeben",
|
||||
"kurz": f"{_groesse(gewinn)} bei {_name(g)} per TRIM" + ("" if g.get("discard") else " (Discard einschalten)"),
|
||||
"ort": "pool",
|
||||
"text": text}
|
||||
|
||||
|
||||
@@ -258,8 +294,8 @@ def sicherungen(bericht: dict, jetzt: float) -> dict:
|
||||
def lage(jetzt: float | None = None) -> dict:
|
||||
b = _bericht()
|
||||
jetzt = time.time() if jetzt is None else jetzt
|
||||
return {"bericht": bool(b), "pools": pools(b), "nas": nas(b), "sicherungen": sicherungen(b, jetzt),
|
||||
"empfehlungen": empfehlungen(b)}
|
||||
return {"bericht": bool(b), "pools": pools(b), "systemplatte": systemplatte(b), "nas": nas(b),
|
||||
"sicherungen": sicherungen(b, jetzt), "empfehlungen": empfehlungen(b)}
|
||||
|
||||
|
||||
def pruefe_speicher(jetzt: float | None = None) -> list:
|
||||
@@ -271,7 +307,7 @@ def pruefe_speicher(jetzt: float | None = None) -> list:
|
||||
jetzt = time.time() if jetzt is None else jetzt
|
||||
befunde = []
|
||||
tipps = empfehlungen(b)
|
||||
platz_tipp = "; ".join(e["kurz"] for e in tipps[:3])
|
||||
platz_tipp = "; ".join([e["kurz"] for e in tipps if e.get("ort") == "pool"][:3])
|
||||
for p in pools(b):
|
||||
if p["stufe"] == "ok":
|
||||
continue
|
||||
@@ -284,6 +320,16 @@ def pruefe_speicher(jetzt: float | None = None) -> list:
|
||||
+ (f"Platz bringt: {platz_tipp}. " if platz_tipp else "")
|
||||
+ "Alles dazu im Homelab-Cockpit unter „Speicher und Sicherungen“."),
|
||||
quelle="pve"))
|
||||
sp = systemplatte(b)
|
||||
if sp and sp["stufe"] != "ok":
|
||||
kernel = next((e for e in tipps if e["art"] == "kernel"), None)
|
||||
befunde.append(Befund(
|
||||
id="host-platte", stufe=sp["stufe"],
|
||||
titel=f"Systemplatte des Proxmox-Hosts zu {min(100, round(sp['anteil'] * 100))} % voll",
|
||||
text=(f"Noch {_groesse(sp['frei'])} frei. Läuft sie voll, scheitern Updates und die Sicherungen vor Updates. "
|
||||
+ (f"Platz bringt: {kernel['kurz']} (Knopf im Homelab-Cockpit unter „Speicher und Sicherungen“)."
|
||||
if kernel else "Alte Sicherungen unter /var/lib/vz/dump und ISO-Abbilder prüfen.")),
|
||||
quelle="pve"))
|
||||
for n in nas(b):
|
||||
if n["stufe"] == "ok":
|
||||
continue
|
||||
|
||||
@@ -316,6 +316,16 @@ def _docker_lauf(lauf: dict, basis: str, gast: dict) -> None:
|
||||
|
||||
def _host_lauf(lauf: dict) -> None:
|
||||
try:
|
||||
if lauf["baustein"] == "kernel":
|
||||
# Welche Kernel gehen, bestimmt der Ausführer selbst (nie der laufende oder der nächste).
|
||||
a = _auftrag(lauf, "kernel_aufraeumen", {}, ZEITLIMIT_SICHERUNG_S)
|
||||
werte = dict(z.split("=", 1) for z in str(a.get("text") or "").splitlines()[:2] if "=" in z)
|
||||
anzahl, frei = int(werte.get("entfernt") or 0), int(werte.get("frei") or 0)
|
||||
_auftrag(lauf, "bericht", {}, 5 * 60)
|
||||
_ende(lauf, "aufgeraeumt", f"Proxmox-Host: {anzahl} alte Kernel entfernt, "
|
||||
f"{frei / 1e9:.1f} GB frei geworden.".replace(".", ",", 1)
|
||||
if anzahl else "Proxmox-Host: kein alter Kernel zu entfernen.")
|
||||
return
|
||||
if lauf["baustein"] == "neustart":
|
||||
_auftrag(lauf, "host_neustart", {}, 60)
|
||||
_ende(lauf, "neustart", "Der Proxmox-Host startet neu. Die KI-Box meldet, ob alles wiederkommt.")
|
||||
@@ -324,7 +334,8 @@ def _host_lauf(lauf: dict) -> None:
|
||||
_auftrag(lauf, "bericht", {}, 5 * 60)
|
||||
_ende(lauf, "eingespielt", "Proxmox-Host: Pakete eingespielt. Ein Neustart ist ein eigener Knopf.")
|
||||
except RuntimeError as exc:
|
||||
_ende(lauf, "fehler", f"Proxmox-Host: Update gescheitert — {exc}", dringend=True)
|
||||
was = "Kernel aufräumen" if lauf["baustein"] == "kernel" else "Update"
|
||||
_ende(lauf, "fehler", f"Proxmox-Host: {was} gescheitert — {exc}", dringend=True)
|
||||
|
||||
|
||||
def _ende(lauf: dict, ergebnis: str, text: str, dringend: bool = False) -> None:
|
||||
@@ -358,7 +369,7 @@ def starten(ziel_id: str, baustein: str, sammellauf: dict | None = None) -> dict
|
||||
|
||||
sammellauf ({"id", "start"}) setzt nur „Alle aktualisieren“ (sammellauf.py) für seine Schritte; ohne ihn lehnt
|
||||
der Knopf ab, solange ein Sammellauf läuft."""
|
||||
if baustein not in ("app", "os", "pakete", "neustart", "docker"):
|
||||
if baustein not in ("app", "os", "pakete", "neustart", "docker", "kernel"):
|
||||
return {"ok": False, "detail": "Unbekannter Baustein."}
|
||||
with START_SPERRE:
|
||||
if sammellauf is None and _sammellauf_laeuft():
|
||||
@@ -368,7 +379,8 @@ def starten(ziel_id: str, baustein: str, sammellauf: dict | None = None) -> dict
|
||||
if ziel_id == "pve":
|
||||
name, gast = "Proxmox-Host", None
|
||||
host = ((kanal.bericht() or {}).get("bericht") or {}).get("host") or {}
|
||||
mehr = {"pakete": len(host.get("updates") or [])} if baustein == "pakete" else {}
|
||||
mehr = ({"pakete": len(host.get("updates") or [])} if baustein == "pakete"
|
||||
else {"kernel": len(host.get("kernel_alt") or [])} if baustein == "kernel" else {})
|
||||
else:
|
||||
gast = inventar.gast(ziel_id)
|
||||
if not gast:
|
||||
|
||||
@@ -148,6 +148,8 @@ def _ausfuehrer_spielen(stopp: threading.Event, neue_version: str, protokoll: li
|
||||
text = ""
|
||||
if auftrag["aktion"] == "snapshot":
|
||||
text = "snapshot=mc2-20260924-190000"
|
||||
elif auftrag["aktion"] == "kernel_aufraeumen":
|
||||
text = "entfernt=20\nfrei=18300000000\nRemoving proxmox-kernel-6.17.2-1-pve-signed …"
|
||||
elif auftrag["aktion"] == "bericht":
|
||||
neu = json.loads(json.dumps(BERICHT))
|
||||
next(g for g in neu["gaeste"] if g["vmid"] == 104)["app"]["version"] = neue_version
|
||||
@@ -451,3 +453,33 @@ def test_neuer_kernel_heisst_neustart(daten):
|
||||
host = {b["id"]: b for b in next(z for z in inventar.ziele()["ziele"] if z["id"] == "pve")["bausteine"]}
|
||||
assert host["neustart"]["grund"] == "Neuer Kernel 7.0.14-19-pve ist installiert, es läuft noch 7.0.14-12-pve."
|
||||
assert host["neustart"]["aktion"]["label"] == "Jetzt neu starten"
|
||||
|
||||
|
||||
def test_alte_kernel_nur_auf_knopfdruck(ausfuehrer):
|
||||
"""25.09.2026: 25 Kernel auf dem Host, 20 davon hielt apt für entbehrlich."""
|
||||
starten, protokoll, meldungen, verlauf = ausfuehrer
|
||||
starten("1.27.3")
|
||||
lauf = _auf_ende(updates.starten("pve", "kernel")["lauf"])
|
||||
assert (lauf["ergebnis"], protokoll) == ("aufgeraeumt", ["kernel_aufraeumen", "bericht"])
|
||||
assert meldungen[-1] == ("Proxmox-Host: 20 alte Kernel entfernt, 18,3 GB frei geworden.", False)
|
||||
assert verlauf[-1][2:4] == ("pve", "aufgeraeumt")
|
||||
from services.homelab import protokoll as prot
|
||||
assert prot._lauf(lauf, lambda *a: None) is None or True # Titel-Zweig existiert (kein KeyError)
|
||||
|
||||
|
||||
def test_ausfuehrer_waehlt_alte_kernel_selbst():
|
||||
a = _ausfuehrer_modul()
|
||||
simulation = """NOTE: This is only a simulation!
|
||||
Reading package lists...
|
||||
The following packages will be REMOVED:
|
||||
proxmox-kernel-6.14.11-2-pve-signed proxmox-kernel-7.0.14-12-pve-signed libfoo1
|
||||
Remv proxmox-kernel-6.14.11-2-pve-signed [6.14.11-2]
|
||||
Remv proxmox-kernel-7.0.14-12-pve-signed [7.0.14-12]
|
||||
Remv proxmox-kernel-7.0.14-5-pve-signed [7.0.14-5]
|
||||
Remv proxmox-kernel-6.17 [6.17.13-21]
|
||||
Remv libfoo1 [1.2-3]
|
||||
Remv pve-kernel-6.8.12-4-pve [6.8.12-4]
|
||||
"""
|
||||
behalten = {"7.0.14-12-pve", "7.0.14-19-pve"}
|
||||
assert a.alte_kernel(simulation, behalten) == [
|
||||
"proxmox-kernel-6.14.11-2-pve-signed", "proxmox-kernel-7.0.14-5-pve-signed", "pve-kernel-6.8.12-4-pve"]
|
||||
|
||||
@@ -239,3 +239,27 @@ def test_schnittstelle(monkeypatch):
|
||||
assert daten["bericht"] is True and daten["pools"][0]["stufe"] == "ok"
|
||||
assert daten["nas"][0]["erreichbar"] is True and daten["sicherungen"]["stufe"] == "ok"
|
||||
assert daten["empfehlungen"][0]["art"] == "trim-vm"
|
||||
|
||||
|
||||
def test_alte_kernel_mit_knopf_und_systemplatte(monkeypatch):
|
||||
b = _bericht()
|
||||
b["host"].update(
|
||||
kernel_alt=[{"paket": f"proxmox-kernel-6.17.{i}-1-pve-signed", "version": f"6.17.{i}-1-pve", "groesse": 915_000_000}
|
||||
for i in range(20)],
|
||||
kernel_bleiben=["6.14.8-2-pve", "6.17.13-21-pve", "7.0.14-12-pve", "7.0.14-19-pve"],
|
||||
systemplatte={"belegt": 47_000_000_000, "gesamt": 94_000_000_000})
|
||||
tipps = speicher.empfehlungen(b)
|
||||
assert [t["art"] for t in tipps] == ["trim-vm", "kernel", "trim", "snapshot"]
|
||||
kernel = tipps[1]
|
||||
assert kernel["titel"] == "Proxmox-Host: 20 alte Kernel entfernen" and kernel["platz"] == 18_300_000_000
|
||||
assert kernel["ort"] == "systemplatte" and kernel["aktion"]["pfad"] == "/api/homelab/ziele/pve/kernel-aufraeumen"
|
||||
assert "es bleiben 6.14.8-2, 6.17.13-21, 7.0.14-12, 7.0.14-19" in kernel["text"]
|
||||
assert speicher.systemplatte(b)["stufe"] == "ok"
|
||||
# Die Systemplatte läuft voll: eigener Hinweis mit dem Kernel-Vorschlag; der Pool-Hinweis nennt ihn nicht.
|
||||
b["host"]["systemplatte"]["belegt"] = 80_000_000_000
|
||||
b["host"]["pools"][0]["belegt"] = int(b["host"]["pools"][0]["gesamt"] * 0.95)
|
||||
monkeypatch.setattr(speicher, "antwortet", lambda s, p: True)
|
||||
monkeypatch.setattr(speicher, "_bericht", lambda: b)
|
||||
befunde = {x.id: x for x in speicher.pruefe_speicher(JETZT)}
|
||||
assert befunde["host-platte"].stufe == "gelb" and "18 GB alte Kernel auf dem Proxmox-Host" in befunde["host-platte"].text
|
||||
assert "Kernel" not in befunde["pool:local-lvm"].text
|
||||
|
||||
Reference in New Issue
Block a user