Selbst-Update im Docker-Betrieb direkt aus der Weboberfläche anstoßen (Host-Watcher wie in FilaDex) #16
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Problem
Unter Einstellungen → Updates kann man bei einer Docker-Installation zwar sehen, dass es eine neue PatchPilot-Version gibt. „Update anwenden“ zeigt aber nur einen Befehl zum Kopieren an (
manual_commandsfür Debian/Ubuntu), den man dann selbst per SSH auf dem Server ausführen muss. Das ist umständlich, und genau dafür ist PatchPilot eigentlich da.Ziel: Das Update lässt sich direkt über die Weboberfläche anstoßen, ohne SSH, auf Debian und Ubuntu. Das Verfahren soll genau so funktionieren wie in FilaDex, wo das schon umgesetzt ist.
Stand in PatchPilot
backend/self_update.py:beta/main, der Cache undlist_releases()für einen gezielten Tag bzw. ein Downgrade gibt es schon.apply_update()funktioniert nur bei Bare-Metal-Installationen (git checkout+ pip + npm +os._exit(0)→ systemd startet neu).deployment_mode()erkennt Docker über/.dockerenv.backend/routers/system_update.py→POST /api/system-update/apply: Bei Docker wird nichts ausgeführt, nurmanual_command(s)zurückgegeben. Das ist eine bewusste Entscheidung: kein Zugriff auf den Docker-Socket, weil das faktisch root auf dem Host wäre.frontend/src/pages/Settings.tsx(Tab Updates) zeigt bei Docker die Befehle zum Kopieren an (applyResult.manual_commands)./opt/patchpilot, Systembenutzerpatchpilot(in der Gruppedocker),docker compose up -d --build.Dockerfile), unddata/gehört perchown -R 1000:1000dieser UID.patchpilotist dagegen ein Systembenutzer mit einer anderen UID (useradd --systemvergibt z. B. 999). ⚠️ Das ist wichtig für die Umsetzung, siehe unten.So löst FilaDex das
Der Container bekommt weiterhin keinen Docker-Socket. Stattdessen verständigen sich Container und Host über eine Datei im gemeinsamen
data/-Ordner:data/update.request(JSON:tag,channel,requested_at), atomar über.tmp+rename, damit der Host keine halbe Datei liest.update.resultwird gelöscht undupdate.loggeleert.deploy/filadex-updater.path(systemd,PathExists=/opt/filadex/data/update.request) startetdeploy/filadex-updater.service. Das istType=oneshot, läuft als Dienstbenutzer, nicht als root, mitTimeoutStartSec=3600.scripts/apply-update.shist die Sicherheitsgrenze. Das Script:trap … EXIT, sonst würde die Path-Unit endlos neu auslösen,data/schreiben darf, und bricht sonst mit einer klaren Meldung ab (UID-Problem),git describe --tags --exact-matchbzw.rev-parse HEAD),git fetch --tags --prune→git checkout <tag>→APP_VERSION=<tag> docker compose up -d --buildaus,data/update.logund am Endedata/update.result(statusok/fehler,meldung,version).GET /api/system/logist ein SSE-Stream, derupdate.logZeile für Zeile streamt und mit dem Ereignisfertigendet, sobaldupdate.resultda ist undupdate.requestweg ist.get_status()liefert zusätzlichlaeuft(Anforderung liegt noch) undletztes_ergebnis.update.request/update.loglänger alsSTILLSTAND_MINUTEN = 10nichts geändert, wird die Anforderung beim nächsten Klick verworfen, mit dem Hinweis „Läuft der Watcher?systemctl status …-updater.path“. Sonst würde eine einzige liegengebliebene Datei alle weiteren Updates dauerhaft sperren.docker-compose.ymlstehtuser: "${FILADEX_UID:-1000}:${FILADEX_GID:-1000}". Die echten Werte des Host-Benutzers stehen in der.env, unddata/gehört diesem Benutzer. Ohne das legt der Container Dateien an, die der Host-Dienst weder schreiben noch löschen kann, und das Update bleibt kommentarlos bei „Warte auf den Host-Dienst“ stehen.Plan für PatchPilot
Backend
backend/self_update.py:DATA_DIR = REPO_ROOT / "data",REQUEST_FILE,RESULT_FILE,LOG_FILE,STALE_MINUTES = 10.apply_update()aufteilen: den Tag bestimmen und gegen die Release-Liste prüfen (gibt es schon), dann_docker_request(tag)bzw._baremetal_apply(tag)aufrufen. Die Bare-Metal-Variante bleibt inhaltlich gleich, schreibt aber zusätzlich nachLOG_FILE, damit beide Varianten dieselbe Log-Anzeige nutzen._docker_request(tag): Anforderung atomar schreiben, hängende Anforderungen erkennen und verwerfen, „läuft bereits“ melden,update.resultlöschen,update.logleeren.get_status()umrunning(liegtREQUEST_FILE?) undlast_result(Inhalt vonRESULT_FILE) erweitern.manual_docker_command(s)bleibt nur noch als Fallback im Status bzw. in der Fehlermeldung, für den Fall, dass der Watcher nicht eingerichtet ist.backend/routers/system_update.py:POST /applylegt bei Docker die Anforderung ab, statt nur den Befehl zurückzugeben.GET /logals SSE-Stream aufdata/update.logmit dem Ereignisfertig. Die Auth muss dabei wie beim bestehenden SSE-Log der Update-Läufe funktionieren, weilEventSourcekeine Header senden kann.scheduled_check_and_maybe_apply(): Auto-Apply funktioniert damit auch bei Docker. Der Sonderfall „bei Docker nur benachrichtigen“ und der Hinweistext „Manueller Befehl nötig“ werden angepasst.Host-Seite (neu)
deploy/patchpilot-updater.path:PathExists=/opt/patchpilot/data/update.request.deploy/patchpilot-updater.service:Type=oneshot,User=patchpilot,Group=patchpilot,WorkingDirectory=/opt/patchpilot,After=/Requires=docker.service,TimeoutStartSec=3600.scripts/apply-update.sh, übernommen aus FilaDex und angepasst:REPO="AxonByteDev/PatchPilot",INSTALL_DIR="${PATCHPILOT_DIR:-/opt/patchpilot}".prerelease-Flag, FilaDex über den Tag-Suffix. Für die Prüfung im Script spielt das keine Rolle, weil nur „Tag existiert als Release, kein Draft“ geprüft wird.data/orchestrator.db) übersqlite3.backup(), abgelegt alsdata/backups/patchpilot-<zeitstempel>.db. Die Postgres-Variante aus FilaDex entfällt.APP_VERSIONbeim Build:docker-compose.ymlerwartet laut Kommentar den Tag mitv(git describe). Das muss einheitlich sein, entwederAPP_VERSION="${ZIEL_TAG}"oder überall ohnev, sonst zeigt die Oberfläche die Version danach anders an.UID-Problem (Voraussetzung, sonst funktioniert es nicht)
docker-compose.yml:user: "${PATCHPILOT_UID:-1000}:${PATCHPILOT_GID:-1000}"beim Dienstpatchpilotergänzen. ImDockerfilebleibt der Benutzer 1000 als Default, nur/app/datamuss für die tatsächliche UID beschreibbar sein. Das ist über den Bind-Mount gegeben, sobalddata/dem Host-Benutzer gehört.data/gehört danach dem Host-Benutzerpatchpilot, nicht mehr UID 1000.Einrichtung auf Debian und Ubuntu (einmalig, als root bzw. mit sudo)
Der einzige Unterschied ist
sugegenübersudo, die systemd-Units sind identisch. Anleitung im Wiki (Installation + Selbst-Update):Wichtig:
enable --nowstatt nurenable, sonst wartet bis zum nächsten Neustart des Servers niemand auf die Anforderung (in FilaDex genau so passiert).Bestehende Installationen: Das allererste Update auf die Version mit Watcher muss noch von Hand laufen (bisheriger Befehl), danach einmal die Einrichtung oben ausführen. Das gehört in die Release-Notes. Optional ein kleines
scripts/install-updater.sh, das die Schritte oben idempotent für Debian und Ubuntu erledigt.Frontend (
Settings.tsx, Tab Updates)EventSource(Log-Box, die in sich scrollt, nicht die ganze Seite; in FilaDex auch so behoben).last_result.journalctl -u patchpilot-updater.service.last_resultnach einem Update anzeigen (ok / fehlgeschlagen + ggf. „Rücksprung auf vX erfolgreich“).Nicht Teil dieses Issues
Aus FilaDex bewusst nicht übernommen: PostgreSQL-Sicherung, der komplette
install.sh/uninstall.sh-Installer undfiladex.service(Start beim Booten; PatchPilot regelt das überrestart: unless-stopped).Akzeptanzkriterien
PATCHPILOT_UID/GID), und das Script erkennt fehlende Schreibrechte frühauto_apply) funktioniert auch bei Dockerrunning/last_result,/applybei Docker