homelab: Wartezeit nach Skriptaenderung, PBS mit Sicherung statt Snapshot, woechentliches Suchen
- karenz.py: ct/<app>.sh juenger als MC_HOMELAB_KARENZ_H (Standard 48 h) -> Baustein "neu" ohne Knopf, updates.starten lehnt mit demselben Satz ab (Berliner Zeit). GitHub stumm -> nicht blockieren, die Rueckfrage sagt es. - Ausfuehrer: neue Aktionen sichern, sicherung_zurueck, sicherung_loeschen. vzdump auf den ersten lokalen Speicher mit Inhalt backup (oder sicherung_speicher aus /etc/mc2-ausfuehrer.json), nie auf pbs; vorher Platz pruefen (frei > belegt x 1,2); Notiz mc2-sicherung, nur solche werden zurueckgespielt/geloescht; Rueckweg: stoppen, pct restore --force auf den bisherigen rootfs-Speicher, starten. Bericht mit host.sicherung, sicherung_moeglich/_grund, eigenen Sicherungen und nur_lesen. Unerwartete Fehler werden beantwortet statt verschluckt; vzdump/restore beim Zeitlimit erst SIGTERM. - updates.py: Sicherung, wo kein Snapshot geht; bei Rot zurueckspielen, nach Gruen aeltere Sicherungen weg. Scheitert Snapshot oder Sicherung, beginnt das Update nicht (nicht dringend gemeldet). - pflege.py: "suchen" fuer Gaeste mit Paketlisten aelter als 7 Tage, nachts 02-05 Uhr (sonst nachholen), einmal je Gast und Tag, nie neben einem Update oder offenen Auftrag; gelber Waechter-Hinweis, wenn es zweimal hintereinander scheitert. Eine Registrierungszeile in waechter.py. - kanal.py: Auftragsliste unter flock, weil jetzt auch der Steward Auftraege anlegt. - inventar.py: Rueckweg und Rueckfrage fuer die Sicherung; Gaeste mitten im Update-Lauf nicht in der Webpruefung des Waechters (sonst zweiter Alarm beim Zurueckspielen). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
40d2840b16
commit
f2733f44fe
@@ -7,7 +7,9 @@ Dazu prüft dieser Teil selbst, ob die Weboberfläche jedes Gasts antwortet.
|
||||
|
||||
Wie ehrlich der Stand ist, steht dabei: Sind die Paketlisten im Gast älter als zwei Wochen, heißt es
|
||||
„unbekannt“ (mit Knopf zum Suchen) statt „aktuell“; ist der Bericht älter als eine halbe Stunde, sagt
|
||||
die Übersicht, dass der Ausführer schweigt.
|
||||
die Übersicht, dass der Ausführer schweigt. Ist das Update-Skript einer App frisch geändert, bleibt sie
|
||||
„neu“, aber ohne Knopf (karenz.py). Rückweg und Rückfrage sagen, was vor dem Update geschieht: Snapshot,
|
||||
wo keiner geht eine Sicherung, sonst keiner.
|
||||
"""
|
||||
|
||||
import re
|
||||
@@ -20,7 +22,7 @@ from kern.github import neueste_version
|
||||
from kern.zeit import LOCAL_TZ
|
||||
from kern.ziele import Aktion, BausteinStand, ZielStand
|
||||
|
||||
from services.homelab import apps, arcane, kanal
|
||||
from services.homelab import apps, arcane, kanal, karenz
|
||||
|
||||
BERICHT_ALT_S = 30 * 60
|
||||
LISTEN_ALT_S = 14 * 24 * 3600
|
||||
@@ -70,6 +72,30 @@ def _datum(ts: float | None) -> str:
|
||||
return datetime.fromtimestamp(ts, LOCAL_TZ).strftime("%d.%m.%Y") if ts else "?"
|
||||
|
||||
|
||||
def _rueckweg(gast: dict) -> str:
|
||||
"""Die Zeile „Rückweg“ der Karte: was vor jedem Update geschieht."""
|
||||
if gast.get("snapshot_moeglich"):
|
||||
return "Snapshot vor jedem Update"
|
||||
grund = gast.get("snapshot_grund") or "kein Snapshot möglich"
|
||||
if gast.get("sicherung_moeglich"):
|
||||
return f"Sicherung auf „{gast.get('sicherung_speicher') or 'dem Host'}“ vor jedem Update ({grund})"
|
||||
if gast.get("sicherung_grund"):
|
||||
return f"Kein automatischer Rückweg: {grund}. Auch keine Sicherung: {gast['sicherung_grund']}"
|
||||
return grund
|
||||
|
||||
|
||||
def _rueckweg_frage(gast: dict) -> str:
|
||||
"""Der Satz zum Rückweg in der Rückfrage vor „Jetzt updaten“."""
|
||||
if gast.get("snapshot_moeglich"):
|
||||
return "Vorher wird ein Snapshot angelegt; ist die Prüfung danach rot, geht es von selbst zurück."
|
||||
if gast.get("sicherung_moeglich"):
|
||||
return "Vorher wird eine Sicherung angelegt; ist die Prüfung danach rot, wird sie zurückgespielt."
|
||||
satz = "Ein Snapshot ist hier nicht möglich — scheitert das Update, gibt es keinen automatischen Rückweg."
|
||||
if gast.get("sicherung_grund"):
|
||||
satz += f" Eine Sicherung geht auch nicht: {gast['sicherung_grund']}"
|
||||
return satz
|
||||
|
||||
|
||||
def _app_baustein(gast: dict, app: apps.App, zid: str) -> BausteinStand:
|
||||
installiert = (gast.get("app") or {}).get("version")
|
||||
stand = BausteinStand(id="app", name=app.name, zustand="aktuell", installiert=installiert)
|
||||
@@ -103,10 +129,15 @@ def _app_baustein(gast: dict, app: apps.App, zid: str) -> BausteinStand:
|
||||
stand.grund = f"{app.name} aktualisiert sich über die eigene Oberfläche; das Community-Script tut es nicht."
|
||||
elif ist_neuer:
|
||||
stand.zustand, stand.kurz = "neu", f"{installiert} → {neu['version']}"
|
||||
rueckweg = ("Vorher wird ein Snapshot angelegt; ist die Prüfung danach rot, geht es von selbst zurück."
|
||||
if gast.get("snapshot_moeglich") else
|
||||
"Ein Snapshot ist hier nicht möglich — scheitert das Update, gibt es keinen automatischen Rückweg.")
|
||||
stand.aktion = Aktion("POST", f"/api/homelab/ziele/{zid}/update", f"{app.name} jetzt aktualisieren? {rueckweg}")
|
||||
# Frisch geänderte Update-Skripte erst nach der Wartezeit (karenz.py): „neu“, aber ohne Knopf.
|
||||
wartezeit = karenz.pruefen(app.kennung)
|
||||
if wartezeit["gesperrt"]:
|
||||
stand.grund = wartezeit["gesperrt"]
|
||||
return stand
|
||||
frage = f"{app.name} jetzt aktualisieren? {_rueckweg_frage(gast)}"
|
||||
if not wartezeit["geprueft"]:
|
||||
frage += f" {karenz.NICHT_GEPRUEFT}"
|
||||
stand.aktion = Aktion("POST", f"/api/homelab/ziele/{zid}/update", frage)
|
||||
return stand
|
||||
|
||||
|
||||
@@ -124,7 +155,7 @@ def _os_baustein(gast: dict, zid: str, jetzt: float) -> BausteinStand:
|
||||
elif anzahl > 0:
|
||||
stand.zustand, stand.kurz = "neu", f"{anzahl} Pakete"
|
||||
stand.aktion = Aktion("POST", f"/api/homelab/ziele/{zid}/os-update",
|
||||
f"{anzahl} Pakete im Gast jetzt einspielen? Vorher wird, wo möglich, ein Snapshot angelegt.")
|
||||
f"{anzahl} Pakete im Gast jetzt einspielen? {_rueckweg_frage(gast)}")
|
||||
return stand
|
||||
|
||||
|
||||
@@ -172,8 +203,7 @@ def _gast_ziel(gast: dict, jetzt: float) -> ZielStand:
|
||||
laeuft = gast.get("status") == "running"
|
||||
ziel = ZielStand(id=zid, name=app.name if app else str(gast.get("name") or zid), art=art, instanz="homelab",
|
||||
erreichbar=(erreichbar(url) if laeuft else False) if url else (laeuft or None),
|
||||
rueckweg=("Snapshot vor jedem Update" if gast.get("snapshot_moeglich")
|
||||
else gast.get("snapshot_grund") or "kein Snapshot möglich"))
|
||||
rueckweg=_rueckweg(gast))
|
||||
if not laeuft:
|
||||
ziel.bausteine.append(BausteinStand(id="status", name="Status", zustand="unbekannt",
|
||||
grund=f"Der Gast ist {gast.get('status') or 'unbekannt'}."))
|
||||
@@ -238,14 +268,18 @@ def ziele() -> dict:
|
||||
|
||||
|
||||
def erreichbarkeit() -> list[dict]:
|
||||
"""Für den Wächter: jede Weboberfläche laufender, freigegebener Gäste — ohne GitHub-Abfragen."""
|
||||
"""Für den Wächter: jede Weboberfläche laufender, freigegebener Gäste — ohne GitHub-Abfragen. Gäste mitten in
|
||||
einem Update-Lauf bleiben außen vor: Sicherung, Update und Zurückspielen legen sie kurz still, und was dabei
|
||||
herauskommt, meldet der Lauf selbst (sonst käme ein zweiter Alarm samt „wieder ok“)."""
|
||||
from services.homelab import updates # updates importiert dieses Modul
|
||||
eingang = kanal.bericht()
|
||||
im_update = updates.laufende_ziele()
|
||||
ergebnis = []
|
||||
for g in (eingang or {}).get("bericht", {}).get("gaeste") or []:
|
||||
app = apps.app_fuer((g.get("app") or {}).get("kennung"), g.get("name"))
|
||||
url = apps.adresse(app, g.get("ip"))
|
||||
if url and g.get("erlaubt"):
|
||||
zid = f"{'ct' if g['art'] == 'lxc' else 'vm'}-{g['vmid']}"
|
||||
zid = f"{'ct' if g['art'] == 'lxc' else 'vm'}-{g['vmid']}"
|
||||
if url and g.get("erlaubt") and zid not in im_update:
|
||||
ergebnis.append({"id": zid, "name": app.name if app else g.get("name"), "url": url,
|
||||
"laeuft": g.get("status") == "running",
|
||||
"ok": g.get("status") == "running" and erreichbar(url)})
|
||||
|
||||
Reference in New Issue
Block a user