sicherung: PBS-Sicherung zurueck ins Repo (ohne mem0), monatliche Probe-Wiederherstellung
- PBS: deploy/pbs-backup.sh, pbs-backup.service und .timer (User-Units, 03:50) aus der Box uebernommen. Die Sicherung lief vom 09.07. bis 20.08. taeglich gruen und brach am 21.08. ab, weil ihr erster Quellordner /srv/models/mem0 (altes Gedaechtnis) fehlte; danach im KISS-Umbau abgeschaltet. Das neue Skript sichert ~/.hermes und /etc/llama-swap (Pflicht) und ~/wissens-vault (optional), prueft Zugangsdatei und Client, und liest den Zugang erst direkt vor dem Aufruf ein. deploy.sh spielt die Units aus, schaltet sie aber nicht ein (Einschalten von Hand, docs/BETRIEB.md). Der Waechter zeigt einen gescheiterten Lauf gelb. - Probe-Wiederherstellung: services/probe_wiederherstellung.py packt die juengste Sicherung in /var/tmp/mc2-probe-* aus (ohne Geheimnisse und Verknuepfungen), prueft Alter (<= 48 h), Lesbarkeit und Pflichtinhalte (Gedaechtnis und SOUL.md auch gegen den lebenden Stand, Skills, Cron-Skripte und -Jobs, Hermes-Config, .env, llama-swap-Config, Box-Wart-Zustand, Units) und loescht den Ordner wieder. Ergebnis in /srv/models/mc2-probe-wiederherstellung.json, bei Rot Meldung "[Sicherung]" ueber notify.sh in normaler Dringlichkeit. Timer mc2-probe-wiederherstellung.timer: erster Montag im Monat 05:15 (nie sonntags, lange nach 03:30), Persistent=true; deploy.sh aktiviert ihn. - Waechter: gelb, wenn die letzte Probe rot war, aelter als 40 Tage ist oder (mit Timer) noch nie lief; Knoepfe "Jetzt pruefen" und "Protokoll" (Allowlist in services.maintenance). - Tests: Probe gruen/rot je Pflichtinhalt, Abgleich, kaputte und alte Sicherung, Meldung, Waechter-Hinweis, Unit-Listen in deploy.sh, Takt, LF, pbs-backup.sh mit Client-Attrappe. Trockenlauf gegen die echte Sicherung der Box (nur in /tmp): alle Pflichtinhalte gruen, 0,4 s. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
93f6613146
commit
2e0ad70a85
@@ -11,6 +11,7 @@ gesehen. Dieser Wächter schaut deshalb breiter hin:
|
||||
• Kern Engine, Hirn, Hermes, Hör-Dienst, MC2, Gateway antworten per HTTP
|
||||
• Platte Füllstand des Modell-Laufwerks
|
||||
• Updates Bausteine, die der Sonntags-Lauf nach einem Fehlschlag festhält
|
||||
• Probe monatliche Probe-Wiederherstellung der Sicherung (rot oder zu alt = gelb)
|
||||
|
||||
Jeder Befund wird zum Hinweis mit Stufe (rot = jetzt, gelb = bei Gelegenheit), Beginn und
|
||||
Knöpfen. Einfaches behebt er selbst (User-Entscheid 23.09.): Ein ABGESTÜRZTER Dienst
|
||||
@@ -45,8 +46,9 @@ import psutil
|
||||
from config import HERMES_API_KEY, HERMES_API_URL, HERMES_HOME, VOICE_SERVICE_URL
|
||||
from kern import partner
|
||||
from kern.einstellungen import einstellungen
|
||||
from kern.zeit import LOCAL_TZ
|
||||
|
||||
from services import announce, llamaswap, maintenance, update_verlauf
|
||||
from services import announce, llamaswap, maintenance, probe_wiederherstellung, update_verlauf
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
ROLLE = einstellungen().rolle
|
||||
@@ -98,6 +100,9 @@ TIMER_DIENSTE: dict[str, tuple[str, bool]] = {
|
||||
"mc2-morgenmeldung": ("Morgenmeldung", True),
|
||||
# Seit 24.09.2026 ein eigener Timer statt Hermes-Cron (Hermes startet sich beim Update selbst neu).
|
||||
"mc2-autoupdate": ("Updates am Sonntag", True),
|
||||
# Seit 24.09.2026 im Repo (vom 21.08. an aus, weil sie rot lief und niemand es sah). Gelb: Die tägliche
|
||||
# Sicherung (mc2-backup) bleibt die erste Schicht, der PBS ist die Kopie auf dem QNAP. Ausgeschaltet kein Befund.
|
||||
"pbs-backup": ("Sicherung auf den PBS", False),
|
||||
}
|
||||
|
||||
HERMES_JOBS_PATH = HERMES_HOME / "cron" / "jobs.json"
|
||||
@@ -465,6 +470,39 @@ def pruefe_platte() -> list[Befund]:
|
||||
quelle="platte", sofort=True)]
|
||||
|
||||
|
||||
def pruefe_probe_wiederherstellung() -> list[Befund]:
|
||||
"""Monatliche Probe-Wiederherstellung (services/probe_wiederherstellung.py, seit 24.09.2026): gelb, wenn die
|
||||
letzte Probe rot war oder älter als WARN_TAGE ist. Gab es noch keine, erst, wenn ihr Timer eingerichtet ist."""
|
||||
einheit = probe_wiederherstellung.EINHEIT
|
||||
aktionen = [_aktion("neustart", "Jetzt prüfen", dienst=einheit), _aktion("protokoll", "Protokoll", dienst=einheit)]
|
||||
stand = probe_wiederherstellung.lese_stand()
|
||||
if stand is None:
|
||||
z = _systemctl_show(f"{einheit}.timer", False)
|
||||
if not z or z.get("LoadState") in ("not-found", ""):
|
||||
return []
|
||||
return [Befund(id="probe:wiederherstellung", stufe="gelb",
|
||||
titel="Die Sicherung wurde noch nie probeweise ausgepackt",
|
||||
text=("Die Probe läuft am ersten Montag im Monat um 05:15. „Jetzt prüfen“ startet sie sofort; "
|
||||
"sie braucht Sekunden und fasst nichts Lebendes an."),
|
||||
quelle=einheit, aktionen=aktionen, sofort=True)]
|
||||
datum = datetime.fromtimestamp(float(stand["zeit"]), LOCAL_TZ).strftime("%d.%m.%Y")
|
||||
if stand.get("ergebnis") != "gruen":
|
||||
fehler = [str(f) for f in stand.get("fehler") or []] or ["ohne Begründung"]
|
||||
weitere = f" (und {len(fehler) - 1} weitere)" if len(fehler) > 1 else ""
|
||||
return [Befund(id="probe:wiederherstellung", stufe="gelb",
|
||||
titel="Die letzte Probe-Wiederherstellung war rot",
|
||||
text=f"Probe vom {datum} ({stand.get('sicherung') or 'keine Sicherung'}): {fehler[0]}{weitere}"[:400],
|
||||
quelle=einheit, aktionen=aktionen, sofort=True)]
|
||||
tage = (time.time() - float(stand["zeit"])) / 86400
|
||||
if tage > probe_wiederherstellung.WARN_TAGE:
|
||||
return [Befund(id="probe:wiederherstellung", stufe="gelb",
|
||||
titel=f"Die Sicherung wurde seit {int(tage)} Tagen nicht mehr probeweise ausgepackt",
|
||||
text=(f"Die letzte Probe am {datum} war grün. Sie soll am ersten Montag im Monat laufen — "
|
||||
f"ist {einheit}.timer eingeschaltet?"),
|
||||
quelle=einheit, aktionen=aktionen, sofort=True)]
|
||||
return []
|
||||
|
||||
|
||||
def pruefe_festgehalten() -> list[Befund]:
|
||||
"""Festgehaltene Bausteine (Pin-Register von autoupdate.sh). Vom 06. bis 17.09.2026 hielt
|
||||
die Box Motor und Hermes fest, ohne dass es jemand sah — elf Tage ohne Updates."""
|
||||
@@ -520,7 +558,7 @@ def pruefe_gaeste() -> list[Befund]:
|
||||
# den Ausführer auf dem Proxmox-Host und seine Gäste.
|
||||
PRUEFUNGEN = {
|
||||
"box": (pruefe_dienste, pruefe_timer_dienste, pruefe_hermes_jobs, pruefe_kern, pruefe_platte,
|
||||
pruefe_festgehalten, pruefe_partner),
|
||||
pruefe_festgehalten, pruefe_partner, pruefe_probe_wiederherstellung),
|
||||
"homelab": (pruefe_platte, pruefe_partner, pruefe_ausfuehrer, pruefe_gaeste),
|
||||
}[ROLLE]
|
||||
BETREFF_PROBLEM, BETREFF_OK = {"box": ("[Box-Problem]", "[Box wieder ok]"),
|
||||
|
||||
Reference in New Issue
Block a user