phase3+4: Homelab-Teil (Ausfuehrer, Ziele, Jetzt updaten mit Rueckweg) und Seite Homelab fuer alle Geraete

- deploy/homelab/ausfuehrer.py: laeuft als root auf dem Proxmox-Host, holt Auftraege beim Homelab-Teil
  ab (Pull, kein offener Port), feste Aktionsliste, prueft Etiketten selbst; Bericht gegen den echten
  Host erprobt (nur lesend). Kein Proxmox-Schluessel im Container noetig.
- services/homelab: Kanal mit gemeinsamem Geheimnis, App-Katalog, Inventar -> Ziele im gemeinsamen
  Modell (GitHub-Versionen, Webpruefung, alte Paketlisten = unklar), Jetzt updaten: Snapshot ->
  Update -> Pruefung -> bei Rot zurueck + dringende Meldung
- Waechter in der Rolle homelab: Ausfuehrer schweigt, Gaeste antworten nicht
- kern/github.py fuer beide Rollen (auch untagged Releases mit Version im Namen)
- Oberflaeche: Seite Homelab zeigt alle Geraete als Karten (KI-Box ueber /api/ziele, Homelab ueber
  /api/homelab/ziele) mit Stand, Rueckweg und Knopf samt Rueckfrage
- Einrichtung als Skripte (container-anlegen, ausrollen, ausfuehrer-einrichten, box-partner) — noch
  nicht ausgefuehrt, jeder Schritt braucht das User-OK
- frontend-bauen-box.sh: Frontend-Pruefung und Build auf der Box, wenn der PC keinen Speicher hat

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Hitonabi
2026-09-24 18:39:59 +02:00
co-authored by Claude Opus 5.5
parent a47489fa85
commit 5e9227c4a3
66 changed files with 2472 additions and 170 deletions
+31 -2
View File
@@ -9,8 +9,8 @@ import { fehlerText, laeuftNoch } from "./anzeige"
import { melden } from "./meldungen"
import { stromVerbunden } from "./strom"
import type {
AktionsErgebnis, AufraeumKandidat, Instanz, Job, Modell, Nutzung, PartnerStatus, Radar, Sicherung, Start,
UpdateDetails,
AktionsErgebnis, AufraeumKandidat, HomelabLauf, HomelabStand, Instanz, Job, Modell, Nutzung, PartnerStatus, Radar,
Sicherung, Start, UpdateDetails, ZielAktion, ZielStand,
} from "./typen"
import { gbText } from "./zeit"
@@ -262,3 +262,32 @@ export const useInstanz = () =>
/** Lebenszeichen der anderen Instanz — die Box prüft den Homelab-Teil und umgekehrt. */
export const usePartner = () =>
useQuery({ queryKey: ["partner"], queryFn: () => api<PartnerStatus>("/api/partner"), refetchInterval: 30_000 })
/** Die KI-Box im gemeinsamen Ziel-Modell (Box-Adapter, GET /api/ziele). */
export const useBoxZiele = () =>
useQuery({ queryKey: ["ziele-box"], queryFn: () => api<{ ziele: ZielStand[] }>("/api/ziele"), refetchInterval: takt(30_000) })
/** Proxmox-Host und Gäste — nur, wenn es den Homelab-Teil gibt (sonst gäbe es nur 404). */
export const useHomelab = (aktiv: boolean) =>
useQuery({
queryKey: ["homelab"],
queryFn: () => api<HomelabStand>("/api/homelab/ziele"),
enabled: aktiv,
refetchInterval: 30_000,
})
export const useHomelabLaeufe = (aktiv: boolean) =>
useQuery({
queryKey: ["homelab-laeufe"],
queryFn: () => api<{ laeufe: HomelabLauf[] }>("/api/homelab/laeufe"),
enabled: aktiv,
// Läuft ein Update, die Schritte zeitnah zeigen.
refetchInterval: (q) => (q.state.data?.laeufe.some((l) => l.status === "laeuft") ? 3000 : 30_000),
})
/** Knopf eines Bausteins: die Aktion steht im Baustein selbst (Methode, Pfad, Rückfrage). */
export const useZielAktion = () =>
useAktion((a: ZielAktion) => api<AktionsErgebnis>(a.pfad, { method: a.methode }), {
erfolg: (a) => `${a.label}: gestartet. Das Ergebnis kommt als Meldung.`,
neuLaden: ["homelab", "homelab-laeufe", "ziele-box", "jobs", "start"],
})
+59
View File
@@ -243,3 +243,62 @@ export interface PartnerStatus {
/** Unix-Sekunden */
geprueft?: number
}
// --- Gemeinsames Ziel-Modell (backend/kern/ziele.py, seit Phase 2) ---------------------------------
export type BausteinZustand = "neu" | "aktuell" | "unbekannt" | "festgehalten" | "wird-geprueft"
/** Wie ein Update angestoßen wird: eine Schnittstelle der Instanz, die das Gerät pflegt. */
export interface ZielAktion {
methode: string
pfad: string
frage: string
label: string
}
export interface BausteinStand {
id: string
name: string
zustand: BausteinZustand
installiert: string | null
verfuegbar: string | null
kurz: string
grund: string | null
aktion: ZielAktion | null
}
/** Ein Gerät (KI-Box, Proxmox-Host, Container, VM) mit seinen Bausteinen. */
export interface ZielStand {
id: string
name: string
art: "ki-box" | "proxmox-host" | "container" | "vm" | string
instanz: "box" | "homelab" | string
erreichbar: boolean | null
bausteine: BausteinStand[]
/** Unix-Sekunden */
geprueft: number | null
rueckweg: string | null
zaehlung: Partial<Record<BausteinZustand, number>>
offen: number
}
/** GET /api/homelab/ziele */
export interface HomelabStand {
ziele: ZielStand[]
bericht: { empfangen: number; veraltet: boolean } | null
ausfuehrer: { verbunden: boolean; zuletzt: number | null }
}
/** Ein „Jetzt updaten“-Lauf im Homelab (GET /api/homelab/laeufe). */
export interface HomelabLauf {
id: string
ziel: string
baustein: string
name: string
status: "laeuft" | "fertig" | "unterbrochen"
start: number
ende: number | null
ergebnis: "eingespielt" | "zurueckgerollt" | "fehler" | "neustart" | null
text: string | null
schritte: string[]
}