diff --git a/backend/services/homelab/inventar.py b/backend/services/homelab/inventar.py index 46061dc..cb1e411 100644 --- a/backend/services/homelab/inventar.py +++ b/backend/services/homelab/inventar.py @@ -218,6 +218,16 @@ def _arcane_bausteine(basis: str | None, zid: str, gast: dict) -> list[BausteinS return [selbst, docker] +def _status_text(status: object) -> str: + """Warum ein Gast keine Bausteine hat — auf Deutsch. „unknown“ kommt kurz nach dem Hochfahren des Hosts, bevor + Proxmox den Zustand kennt (der Ausführer berichtet dann nach einer Minute erneut).""" + if status == "stopped": + return "Der Gast ist gestoppt." + if status == "paused": + return "Der Gast ist angehalten." + return "Proxmox kennt seinen Zustand gerade nicht (etwa kurz nach dem Hochfahren des Hosts)." + + def _gast_ziel(gast: dict, jetzt: float) -> ZielStand: art = "container" if gast["art"] == "lxc" else "vm" zid = f"{'ct' if art == 'container' else 'vm'}-{gast['vmid']}" @@ -229,7 +239,7 @@ def _gast_ziel(gast: dict, jetzt: float) -> ZielStand: rueckweg=_rueckweg(gast), rueckweg_art=_rueckweg_art(gast), platte=gast.get("platte")) if not laeuft: ziel.bausteine.append(BausteinStand(id="status", name="Status", zustand="unbekannt", - grund=f"Der Gast ist {gast.get('status') or 'unbekannt'}.")) + grund=_status_text(gast.get("status")))) return ziel if app and app.kennung == "arcane": # Arcane läuft über seine eigene Schnittstelle, nicht über den Ausführer: kein Etikett nötig — nur für den diff --git a/backend/tests/test_homelab.py b/backend/tests/test_homelab.py index af58c9c..f2cf78f 100644 --- a/backend/tests/test_homelab.py +++ b/backend/tests/test_homelab.py @@ -483,3 +483,11 @@ 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"] + + +def test_nach_dem_hochfahren_bald_wieder_berichten(): + """25.09.2026: Der erste Bericht nach dem Neustart kam 34 s nach dem Hochfahren — alle Gäste „unknown“.""" + a = _ausfuehrer_modul() + assert a.naechster_bericht_in({"gaeste": [{"status": "running"}, {"status": "stopped"}]}) == a.BERICHT_ALLE_S + assert a.naechster_bericht_in({"gaeste": [{"status": "running"}, {"status": "unknown"}]}) == a.BERICHT_BALD_S == 60 + assert a.naechster_bericht_in({}) == a.BERICHT_ALLE_S diff --git a/deploy/homelab/ausfuehrer.py b/deploy/homelab/ausfuehrer.py index 06d6dd6..6188d62 100644 --- a/deploy/homelab/ausfuehrer.py +++ b/deploy/homelab/ausfuehrer.py @@ -1174,8 +1174,9 @@ def dauerbetrieb() -> None: while True: try: if time.time() >= naechster_bericht: - _anfrage("POST", "/api/homelab/ausfuehrer/bericht", bericht()) - naechster_bericht = time.time() + BERICHT_ALLE_S + daten = bericht() + _anfrage("POST", "/api/homelab/ausfuehrer/bericht", daten) + naechster_bericht = time.time() + naechster_bericht_in(daten) auftrag = _anfrage("GET", "/api/homelab/ausfuehrer/auftrag") if isinstance(auftrag, dict) and auftrag.get("id"): log.info("Auftrag %s: %s %s", auftrag["id"], auftrag.get("aktion"), auftrag.get("parameter")) @@ -1191,6 +1192,17 @@ def dauerbetrieb() -> None: time.sleep(ABFRAGE_ALLE_S) +BERICHT_BALD_S = 60 + + +def naechster_bericht_in(daten: dict) -> int: + """Wann der nächste Bericht fällig ist. Kurz nach dem Hochfahren kennt Proxmox den Zustand der Gäste noch nicht + („unknown“): Am 25.09.2026 kam der erste Bericht 34 s nach dem Neustart, und zehn Minuten lang zeigte die + Oberfläche jeden Gast als unbekannt. Dann schon nach einer Minute wieder.""" + unklar = any(g.get("status") not in ("running", "stopped", "paused") for g in daten.get("gaeste") or []) + return BERICHT_BALD_S if unklar else BERICHT_ALLE_S + + def _konfig_laden() -> dict: try: with open(KONFIG, encoding="utf-8") as f: