Welle 2 · Neu entdeckt: neue Geräte mit Vorschlägen, Übernehmen per Klick (Etikett), App-Katalog pflegt sich selbst
Jeder Bericht wird mit einem Register bekannter Geräte verglichen; ein neuer Container oder eine neue VM erscheint im Homelab-Cockpit unter „Neu entdeckt“, und Lucy meldet ihn einmal über Telegram. Übernehmen: „Für Updates freigeben“ (der Ausführer setzt das Etikett watcher — neue Aktion etikett_setzen, sie darf nur watcher und watcher-aus setzen oder entfernen), „Nur beobachten“ oder „Nicht anfassen“ (watcher-aus). Unbekannte Community-Scripts-Kennungen trägt katalog.py aus ihrem Update-Skript nach (Name, GitHub-Projekt, Port, Weg); ein Port, der nicht antwortet, schaltet die Webprüfung nicht ein. Der Ausführer braucht ausfuehrer-einrichten.sh. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
f2bffc7203
commit
c7c396f56d
@@ -34,6 +34,9 @@ Container des Homelab-Teils braucht keinen Proxmox-Schlüssel.
|
||||
• Zertifikate im Bericht (seit 25.09.2026, höchstens alle 30 Minuten neu gelesen): die https-Zertifikate von
|
||||
NPMplus samt dem, was es für den Namen gerade ausliefert, das des Proxmox-Hosts und das des PBS —
|
||||
Laufzeit, Aussteller, Namen. Nur lesend.
|
||||
• Etikett (seit 25.09.2026, Knopf „Übernehmen“ bei neu entdeckten Geräten): setzt oder entfernt genau eines der
|
||||
beiden Etiketten watcher und watcher-aus — die beiden schließen sich aus, alle anderen Etiketten
|
||||
bleiben, wie sie sind. Das geht auch bei Gästen ohne Freigabe: Es IST die Freigabe.
|
||||
|
||||
Nur die Standardbibliothek (Debian-Python des Hosts). Konfiguration: /etc/mc2-ausfuehrer.json
|
||||
{"server": "http://192.168.178.x:9001", "token": "<gemeinsames Geheimnis>", "node": "pve", "nur_lesen": false}
|
||||
@@ -1227,6 +1230,37 @@ def a_host_neustart(p: dict) -> tuple[int, str]:
|
||||
return _laufen(["systemctl", "reboot"], 30)
|
||||
|
||||
|
||||
# Die einzigen Etiketten, die der Server setzen oder entfernen lassen kann (seit 25.09.2026).
|
||||
SETZBARE_ETIKETTEN = ("watcher", AUSGENOMMEN)
|
||||
|
||||
|
||||
def etiketten_neu(vorher: list[str], etikett: str, an: bool) -> list[str]:
|
||||
"""Die Etiketten nach dem Setzen oder Entfernen: watcher und watcher-aus schließen sich aus, alles andere bleibt."""
|
||||
if etikett not in SETZBARE_ETIKETTEN:
|
||||
raise ValueError(f"Etikett {etikett!r} darf der Orchestrator nicht setzen")
|
||||
ohne = [t for t in vorher if t not in SETZBARE_ETIKETTEN] if an else [t for t in vorher if t != etikett]
|
||||
return ohne + [etikett] if an else ohne
|
||||
|
||||
|
||||
def a_etikett_setzen(p: dict) -> tuple[int, str]:
|
||||
"""Freigabe per Etikett (Knopf „Übernehmen“): kein _gast_pruefen — der Gast hat die Freigabe ja noch nicht."""
|
||||
vmid, etikett, an = p.get("vmid"), p.get("etikett"), p.get("an", True)
|
||||
if not isinstance(vmid, int) or not 100 <= vmid <= 999_999_999 or not isinstance(an, bool):
|
||||
raise ValueError("ungültige Gast-Nummer oder Angabe")
|
||||
eintrag = next((e for e in _pvesh("/cluster/resources", "--type", "vm") or []
|
||||
if int(e.get("vmid", -1)) == vmid and e.get("node") == NODE), None)
|
||||
if not eintrag:
|
||||
raise ValueError(f"Gast {vmid} gibt es auf diesem Host nicht")
|
||||
art = eintrag["type"]
|
||||
vorher = _etiketten(_pvesh(f"/nodes/{NODE}/{art}/{vmid}/config").get("tags"))
|
||||
neu = etiketten_neu(vorher, str(etikett), an)
|
||||
if neu == vorher:
|
||||
return 0, f"etiketten={';'.join(neu)}\nSchon so."
|
||||
zusatz = ["--tags", ";".join(neu)] if neu else ["--delete", "tags"]
|
||||
code, text = _laufen(["pvesh", "set", f"/nodes/{NODE}/{art}/{vmid}/config", *zusatz], 60)
|
||||
return code, f"etiketten={';'.join(neu)}\n{text}"
|
||||
|
||||
|
||||
def a_bericht(p: dict) -> tuple[int, str]:
|
||||
return 0, json.dumps(bericht(), ensure_ascii=False)
|
||||
|
||||
@@ -1265,7 +1299,8 @@ AKTIONEN = {"snapshot": a_snapshot, "update": a_update, "os_update": a_os_update
|
||||
"snapshot_loeschen": a_snapshot_loeschen, "host_update": a_host_update,
|
||||
"host_neustart": a_host_neustart, "bericht": a_bericht,
|
||||
"sichern": a_sichern, "sicherung_zurueck": a_sicherung_zurueck, "sicherung_loeschen": a_sicherung_loeschen,
|
||||
"kernel_aufraeumen": a_kernel_aufraeumen, "sicherung_probe": a_sicherung_probe}
|
||||
"kernel_aufraeumen": a_kernel_aufraeumen, "sicherung_probe": a_sicherung_probe,
|
||||
"etikett_setzen": a_etikett_setzen}
|
||||
# Was auch im Nur-Lesen-Modus geht: Es liest nur.
|
||||
NUR_LESEND = {a_bericht, a_sicherung_probe}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user