diff --git a/backend/services/maintenance.py b/backend/services/maintenance.py index d344bfc..36feccc 100644 --- a/backend/services/maintenance.py +++ b/backend/services/maintenance.py @@ -495,10 +495,10 @@ def engine_update_job(sudo_password: str | None = None) -> dict | None: def on_done(): _engine_cache.update(ts=0.0, avail=False) # Cache leeren → frischer Build-Vergleich - # update-engine.sh läuft via sudo als root und startet llama-swap am Ende selbst neu. - # Danach Stack-Funktionsprüfung (echte Inferenz) → Job wird rot, wenn der neue Build kaputt ist. - cmd = f"{ENGINE_UPDATE_CMD} && bash {STACK_POSTCHECK}" - job_id = jobengine.start_job(["bash", "-c", cmd], + # update-engine.sh sichert den alten Build, aktualisiert, startet llama-swap neu, prüft den + # Stack (stack-postcheck.sh) und rollt bei Fehler selbst zurück. Exit 0 nur bei verifiziertem + # neuen Build → on_done (Cache leeren) läuft nur dann; bei Rollback (Exit 1/2) bleibt das Badge. + job_id = jobengine.start_job(["bash", "-c", ENGINE_UPDATE_CMD], "Engine-Update (llama.cpp Vulkan)", on_done=on_done, sudo_password=sudo_password) return {"ok": True, "job_id": job_id} @@ -513,10 +513,10 @@ def swap_update_job(sudo_password: str | None = None) -> dict | None: def on_done(): _swap_cache.update(ts=0.0, avail=False) # Cache leeren → frischer Versions-Vergleich - # update-swap.sh läuft via sudo als root, ersetzt die Binary und startet llama-swap neu. - # Danach Stack-Funktionsprüfung (echte Inferenz) → Job wird rot, wenn der Router kaputt ist. - cmd = f"{SWAP_UPDATE_CMD} && bash {STACK_POSTCHECK}" - job_id = jobengine.start_job(["bash", "-c", cmd], + # update-swap.sh sichert die alte Binary, aktualisiert, startet llama-swap neu, prüft den Stack + # (stack-postcheck.sh) und rollt bei Fehler selbst zurück. Exit 0 nur bei verifizierter neuer + # Version → on_done (Cache leeren) läuft nur dann; bei Rollback (Exit 1/2) bleibt das Badge. + job_id = jobengine.start_job(["bash", "-c", SWAP_UPDATE_CMD], "Router-Update (llama-swap)", on_done=on_done, sudo_password=sudo_password) return {"ok": True, "job_id": job_id} diff --git a/deploy/update-engine.sh b/deploy/update-engine.sh index f96fc38..7e6931f 100644 --- a/deploy/update-engine.sh +++ b/deploy/update-engine.sh @@ -1,11 +1,17 @@ #!/usr/bin/env bash # Aktualisiert den Vulkan-llama.cpp-Build auf den neuesten ggml-org-Release. # Wird vom MC2-„Engine Update"-Button via `sudo bash …` als ROOT aufgerufen -# (deshalb KEIN internes sudo). Startet llama-swap am Ende neu. +# (deshalb KEIN internes sudo). Startet llama-swap neu, VERIFIZIERT den Stack +# (stack-postcheck.sh) und ROLLT bei Fehler automatisch auf den vorherigen Build zurück. +# +# Exit 0 = neuer Build verifiziert · 1 = fehlgeschlagen, Rollback ok (alter Build läuft) +# · 2 = Update UND Rollback fehlgeschlagen (Stack evtl. kaputt — bitte prüfen) set -euo pipefail VULKAN_DIR=/opt/llamacpp-vulkan -PIN_BUILD="${MC_ENGINE_BUILD:-}" # leer = neuester Release +BAK_DIR=/opt/llamacpp-vulkan.bak # „letzter funktionierender Build" für Auto-Rollback +SRC_DIR="$(cd "$(dirname "$0")" && pwd)" +PIN_BUILD="${MC_ENGINE_BUILD:-}" # leer = neuester Release if [ -n "$PIN_BUILD" ]; then TAG="$PIN_BUILD" @@ -22,10 +28,40 @@ trap 'rm -rf "$TMP"' EXIT echo "Lade Engine ${TAG} …" curl -fsSL -o "$TMP/v.tgz" "$URL" tar xzf "$TMP/v.tgz" -C "$TMP" + +# Sicherung des aktuellen (funktionierenden) Builds VOR dem Überschreiben → Auto-Rollback. +if [ -d "$VULKAN_DIR" ]; then + echo "Sichere aktuellen Build → ${BAK_DIR}" + rm -rf "$BAK_DIR" + cp -a "$VULKAN_DIR" "$BAK_DIR" +fi + mkdir -p "$VULKAN_DIR" cp -rf "$TMP"/llama-*/. "$VULKAN_DIR"/ test -x "$VULKAN_DIR/llama-server" ln -sfn "$VULKAN_DIR/llama-server" /usr/local/bin/llama-server - systemctl restart llama-swap -echo "Engine aktualisiert auf ${TAG} und llama-swap neugestartet." + +echo "Engine auf ${TAG} aktualisiert — verifiziere Stack…" +if bash "$SRC_DIR/stack-postcheck.sh"; then + echo "Engine-Update ${TAG} erfolgreich verifiziert." + exit 0 +fi + +# --- Auto-Rollback auf den gesicherten Build --- +echo "!! Stack-Check fehlgeschlagen — ROLLBACK auf vorherigen Build." +if [ -d "$BAK_DIR" ]; then + rm -rf "$VULKAN_DIR" + cp -a "$BAK_DIR" "$VULKAN_DIR" + ln -sfn "$VULKAN_DIR/llama-server" /usr/local/bin/llama-server + systemctl restart llama-swap + echo "Vorheriger Build wiederhergestellt — prüfe Stack erneut…" + if bash "$SRC_DIR/stack-postcheck.sh"; then + echo "Rollback erfolgreich: vorheriger Build läuft wieder. (Update ${TAG} NICHT angewendet.)" + exit 1 + fi + echo "!!! Rollback-Check ebenfalls fehlgeschlagen — Stack möglicherweise kaputt!" + exit 2 +fi +echo "!!! Kein Backup vorhanden — Rollback nicht möglich!" +exit 2 diff --git a/deploy/update-swap.sh b/deploy/update-swap.sh index c93ca35..5a9c81f 100755 --- a/deploy/update-swap.sh +++ b/deploy/update-swap.sh @@ -1,11 +1,17 @@ #!/usr/bin/env bash # Aktualisiert den llama-swap-Router (mostlygeek/llama-swap) auf den neuesten Release. # Wird vom MC2-„Router Update"-Button via `sudo bash …` als ROOT aufgerufen -# (deshalb KEIN internes sudo). Ersetzt die Binary und startet llama-swap neu. +# (deshalb KEIN internes sudo). Ersetzt die Binary, startet llama-swap neu, VERIFIZIERT +# den Stack (stack-postcheck.sh) und ROLLT bei Fehler automatisch auf die alte Binary zurück. +# +# Exit 0 = neue Version verifiziert · 1 = fehlgeschlagen, Rollback ok (alte Version läuft) +# · 2 = Update UND Rollback fehlgeschlagen (Stack evtl. kaputt — bitte prüfen) set -euo pipefail SWAP_BIN="${MC_SWAP_BIN:-/usr/local/bin/llama-swap}" -PIN_VER="${MC_SWAP_VERSION:-}" # leer = neuester Release +BAK="${SWAP_BIN}.bak" # „letzte funktionierende Version" für Auto-Rollback +SRC_DIR="$(cd "$(dirname "$0")" && pwd)" +PIN_VER="${MC_SWAP_VERSION:-}" # leer = neuester Release if [ -n "$PIN_VER" ]; then TAG="$PIN_VER" @@ -26,8 +32,31 @@ curl -fsSL -o "$TMP/s.tgz" "$URL" tar xzf "$TMP/s.tgz" -C "$TMP" NEW="$(find "$TMP" -type f -name llama-swap | head -1)" [ -n "$NEW" ] || { echo "llama-swap-Binary im Archiv nicht gefunden"; exit 1; } + +# Sicherung der aktuellen (funktionierenden) Binary VOR dem Überschreiben → Auto-Rollback. +[ -x "$SWAP_BIN" ] && cp -a "$SWAP_BIN" "$BAK" install -m 0755 "$NEW" "$SWAP_BIN" test -x "$SWAP_BIN" - systemctl restart llama-swap -echo "Router aktualisiert auf ${TAG} und llama-swap neugestartet." + +echo "Router auf ${TAG} aktualisiert — verifiziere Stack…" +if bash "$SRC_DIR/stack-postcheck.sh"; then + echo "Router-Update ${TAG} erfolgreich verifiziert." + exit 0 +fi + +# --- Auto-Rollback auf die gesicherte Binary --- +echo "!! Stack-Check fehlgeschlagen — ROLLBACK auf vorherige Version." +if [ -x "$BAK" ]; then + cp -a "$BAK" "$SWAP_BIN" + systemctl restart llama-swap + echo "Vorherige Binary wiederhergestellt — prüfe Stack erneut…" + if bash "$SRC_DIR/stack-postcheck.sh"; then + echo "Rollback erfolgreich: vorherige llama-swap-Version läuft wieder. (Update ${TAG} NICHT angewendet.)" + exit 1 + fi + echo "!!! Rollback-Check ebenfalls fehlgeschlagen — Stack möglicherweise kaputt!" + exit 2 +fi +echo "!!! Kein Backup vorhanden — Rollback nicht möglich!" +exit 2