phase2d: gemeinsames Ziel-Modell, KI-Box als erster Adapter, strukturierter Update-Verlauf
- kern/ziele.py: Ziel -> Bausteine mit Stand (neu/aktuell/unbekannt/festgehalten/wird-geprueft), Versionen und dem Knopf, der das Update anstoesst; gleiches Modell fuer Box und Homelab - services/box_updates.py: Update-Zwischenspeicher aus dem Router geholt, ki_box_ziel() als Box-Adapter; GET /api/ziele - Update-Verlauf strukturiert: autoupdate.sh und die Update-Knoepfe schreiben je Baustein eine JSON-Zeile (mc2-update-verlauf.jsonl); die Meldungstexte bleiben gleich, aeltere Laeufe kommen weiter aus dem Meldeprotokoll. Updates per Knopf erscheinen jetzt auch im Verlauf. - jobengine: Abschluss-Haken fuer jedes Ende (neben der Nacharbeit fuer den Erfolg) - Sonntags-Lauf setzt seinen Anlass; Hermes-Job aus dem Lauf schreibt nicht doppelt - Vertragstest Bash-Schreiber gegen Python-Leser (laeuft auf der Box mit jq) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
22bb8c672b
commit
589c14d5e9
@@ -0,0 +1,59 @@
|
||||
"""Ziele und Bausteine (Phase 2, 24.09.2026): ein Modell für alles, was Updates bekommt.
|
||||
|
||||
Ein Ziel ist ein Gerät: die KI-Box, der Proxmox-Host, ein Container, die Arcane-VM. Es besteht aus
|
||||
Bausteinen (Betriebssystem, Motor, die App im Container, Docker-Images …). Jeder Baustein sagt, wie
|
||||
sein Stand ist — neu, aktuell, unbekannt (mit Grund) oder festgehalten — und wie man ihn einspielt.
|
||||
|
||||
Die KI-Box meldet ihre Bausteine über den Box-Adapter (services/box_updates.py), der Homelab-Teil
|
||||
ab Phase 3 über Proxmox- und Arcane-Adapter. So wird aus beiden Instanzen EINE Liste offener Updates
|
||||
(User-Entscheid 24.09.: eine Anlaufstelle für Updates im ganzen Homelab).
|
||||
"""
|
||||
|
||||
from dataclasses import asdict, dataclass, field
|
||||
from typing import Literal
|
||||
|
||||
Zustand = Literal["neu", "aktuell", "unbekannt", "festgehalten", "wird-geprueft"]
|
||||
# Reihenfolge für die Anzeige: was Aufmerksamkeit braucht, zuerst.
|
||||
_RANG = {"unbekannt": 0, "festgehalten": 1, "neu": 2, "wird-geprueft": 3, "aktuell": 4}
|
||||
|
||||
|
||||
@dataclass
|
||||
class Aktion:
|
||||
"""Wie ein Update angestoßen wird: eine Schnittstelle der Instanz, die das Ziel pflegt."""
|
||||
methode: str # "POST"
|
||||
pfad: str # "/api/maintenance/engine-update"
|
||||
frage: str # Rückfrage vor dem Klick
|
||||
|
||||
|
||||
@dataclass
|
||||
class BausteinStand:
|
||||
id: str # "engine"
|
||||
name: str # "Motor (llama.cpp)"
|
||||
zustand: Zustand
|
||||
installiert: str | None = None
|
||||
verfuegbar: str | None = None
|
||||
kurz: str = "" # „10 Pakete", „b11160 → b11172", „743 Änderungen"
|
||||
grund: str | None = None # bei „unbekannt" und „festgehalten": warum
|
||||
aktion: Aktion | None = None # None = kein Knopf (aktuell, festgehalten, unbekannt)
|
||||
|
||||
|
||||
@dataclass
|
||||
class ZielStand:
|
||||
id: str # "ki-box"
|
||||
name: str # "KI-Box"
|
||||
art: str # "ki-box" | "proxmox-host" | "container" | "vm"
|
||||
instanz: str # welche Instanz es pflegt: "box" | "homelab"
|
||||
erreichbar: bool | None = None # None = nicht geprüft
|
||||
bausteine: list[BausteinStand] = field(default_factory=list)
|
||||
geprueft: float | None = None # Unix-Sekunden der letzten Prüfung
|
||||
rueckweg: str | None = None # „Sicherung vor jedem Lauf", „Snapshot", „nur Backup"
|
||||
|
||||
def als_dict(self) -> dict:
|
||||
daten = asdict(self)
|
||||
daten["bausteine"].sort(key=lambda b: _RANG.get(b["zustand"], 9))
|
||||
zaehlung: dict[str, int] = {}
|
||||
for b in self.bausteine:
|
||||
zaehlung[b.zustand] = zaehlung.get(b.zustand, 0) + 1
|
||||
daten["zaehlung"] = zaehlung
|
||||
daten["offen"] = zaehlung.get("neu", 0)
|
||||
return daten
|
||||
Reference in New Issue
Block a user