einstellungen: Zeitfenster, Radar-Schalter, Telegram-Test, Software-Stand und Altreste
Einstellungen, die etwas einstellen (services/einstellungen.py, /api/einstellungen): - Update-Zeitfenster: Wochentag und Uhrzeit des Update-Laufs als Drop-in mc2-autoupdate.timer.d/zeitfenster.conf. Gegen die Nachhol-Falle von Persistent=true (24.09.): Timer vor dem daemon-reload stoppen, Stempel auf jetzt, dann starten. Bei Fehler zurück auf das alte Drop-in. Während eines Update-Laufs abgelehnt. - Neustart nur im eingestellten Fenster (deploy/wartungsfenster.sh, drei Stunden ab der vollen Stunde des Beginns; Standard So 04:00-06:59). - Radar an/aus: disable --now bzw. enable + Stempel + start (kein Nachholen). deploy.sh respektiert den Schalter und startet den Radar-Timer nur mit Stempel; das Zeitfenster-Drop-in fasst er nie an. - Wächter: schläft der Timer eines Timer-Dienstes, ist ein alter Fehlschlag kein Befund mehr (der Dienst selbst ist static und schläft nie). - Telegram-Test je Instanz (/api/einstellungen/telegram-test und /api/homelab/einstellungen/telegram-test) über notify.sh -d; Ergebnis und Grund aus dem Melde-Log. notify.sh schreibt jetzt auch den Grund des gescheiterten Zweitwegs in den FALLBACK-Eintrag. - Einstellungsdatei mc2-einstellungen.json im Datenordner. Software-Stand: deploy.sh und homelab/ausrollen.sh schreiben nach dem Umschalten mc2-stand.json (deploy/stand-schreiben.py); /api/instanz liefert den Stand, die Einstellungen zeigen beide Instanzen und warnen bei Abweichung. Ohne Datei aus git, sonst unbekannt. Aufräumen: Altreste neben dem Betrieb aus einer festen, auf der Box geprüften Liste (Größe, Hinweis, nur was da und nicht in Gebrauch ist). Löschen nur per Kennung und Klick mit Rückfrage; Worktrees mit git worktree prune, Alt-Units mit daemon-reload, /opt/llamacpp notfalls mit sudo -n. Tests: pytest mit einem systemd-Abbild samt Nachhol-Regel, echtem notify.sh (Ersatz-Hermes, Tmp-Zugang, lokale Bot-API), Shell-Funktionen des Wartungsfensters und von deploy.sh; vitest für die Rückfragen der Schublade. 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
3d8df1c6fd
@@ -0,0 +1,77 @@
|
||||
"""
|
||||
Software-Stand einer Instanz (seit 24.09.2026): welcher Commit seit wann live ist.
|
||||
|
||||
Nach einem erfolgreichen Umschalten schreibt deploy/deploy.sh (KI-Box) bzw. deploy/homelab/ausrollen.sh
|
||||
(Container des Homelab-Teils) die Stand-Datei mc2-stand.json in den Datenordner (deploy/stand-schreiben.py):
|
||||
Commit kurz, Betreff, Commit-Datum und den Zeitpunkt des Deploys. Die Oberfläche zeigt sie unter
|
||||
Einstellungen → Software-Stand, für diese Instanz über /api/instanz und für die andere über /api/partner/instanz.
|
||||
|
||||
Ohne Stand-Datei (Entwicklung am PC, Box vor dem ersten Deploy mit dieser Datei) kommt der Stand aus git, sonst
|
||||
heißt er „unbekannt“. Nur lesend.
|
||||
"""
|
||||
|
||||
import json
|
||||
import os
|
||||
import subprocess
|
||||
import threading
|
||||
import time
|
||||
from pathlib import Path
|
||||
|
||||
from kern.einstellungen import einstellungen
|
||||
|
||||
REPO = Path(__file__).resolve().parents[2]
|
||||
GIT_CACHE_S = 60.0
|
||||
|
||||
_lock = threading.Lock()
|
||||
_git_cache: dict = {"ts": 0.0, "stand": None}
|
||||
|
||||
|
||||
def stand_datei() -> Path:
|
||||
return Path(os.environ.get("MC_STAND_DATEI", str(einstellungen().daten_dir / "mc2-stand.json")))
|
||||
|
||||
|
||||
def _text(wert: object) -> str | None:
|
||||
return wert.strip() if isinstance(wert, str) and wert.strip() else None
|
||||
|
||||
|
||||
def _aus_datei() -> dict | None:
|
||||
try:
|
||||
daten = json.loads(stand_datei().read_text(encoding="utf-8"))
|
||||
except (OSError, ValueError):
|
||||
return None
|
||||
if not isinstance(daten, dict) or not _text(daten.get("commit")):
|
||||
return None
|
||||
return {"quelle": "deploy", **{k: _text(daten.get(k)) for k in ("commit", "betreff", "commit_datum",
|
||||
"deploy_zeit")}}
|
||||
|
||||
|
||||
def _git_log() -> str | None:
|
||||
"""Kopf des Checkouts, in dem dieser Code liegt. Die Schicht, die Tests ersetzen."""
|
||||
try:
|
||||
r = subprocess.run(["git", "-C", str(REPO), "log", "-1", "--format=%h%n%cI%n%s"],
|
||||
capture_output=True, text=True, encoding="utf-8", errors="replace", timeout=5)
|
||||
except (OSError, subprocess.SubprocessError):
|
||||
return None
|
||||
return r.stdout if r.returncode == 0 else None
|
||||
|
||||
|
||||
def _aus_git() -> dict | None:
|
||||
with _lock:
|
||||
if time.time() - _git_cache["ts"] < GIT_CACHE_S:
|
||||
return _git_cache["stand"]
|
||||
ausgabe = _git_log()
|
||||
stand = None
|
||||
if ausgabe:
|
||||
commit, datum, betreff = ([z.strip() for z in ausgabe.splitlines()] + ["", "", ""])[:3]
|
||||
if commit:
|
||||
stand = {"quelle": "git", "commit": commit, "betreff": betreff or None,
|
||||
"commit_datum": datum or None, "deploy_zeit": None}
|
||||
with _lock:
|
||||
_git_cache.update(ts=time.time(), stand=stand)
|
||||
return stand
|
||||
|
||||
|
||||
def stand() -> dict:
|
||||
"""{"quelle": "deploy"|"git"|"unbekannt", "commit", "betreff", "commit_datum", "deploy_zeit"}."""
|
||||
return _aus_datei() or _aus_git() or {"quelle": "unbekannt", "commit": None, "betreff": None,
|
||||
"commit_datum": None, "deploy_zeit": None}
|
||||
Reference in New Issue
Block a user