#!/usr/bin/env bash # update-ausfuehren.sh — führt einen Update-Auftrag aus der App aus # (Admin → Update, POST /admin/update legt sessions/update/auftrag.json an). # Gestartet vom systemd-Dienst projektuebersicht-update (eingerichtet von # Docker/update-einrichten.sh), läuft als root auf dem Rechner, nicht im # Container: Version vom Git-Server holen, auschecken, Container neu bauen # und starten. Fortschritt in sessions/update/status.json, Protokoll in # sessions/update/update.log, die laufende Version in installiert.json. # # Alles steht in main(): bash liest ein Skript sonst zeilenweise beim # Ausführen — und dieses Skript wird mitten im Lauf durch den Checkout ersetzt. set -u main(){ local REPO DIR AUFTRAG LOG VERSION EIGNER VORHER COMPOSE REPO="$(cd "$(dirname "$0")/.." && pwd)" DIR="$REPO/sessions/update" AUFTRAG="$DIR/auftrag.json" LOG="$DIR/update.log" [ -f "$AUFTRAG" ] || return 0 VERSION=$(sed -n 's/.*"version":"\(v[0-9]\{1,4\}\.[0-9]\{1,4\}\.[0-9]\{1,4\}\)".*/\1/p' "$AUFTRAG") rm -f "$AUFTRAG" : > "$LOG" EIGNER=$(stat -c %U "$REPO") git_(){ runuser -u "$EIGNER" -- git -C "$REPO" "$@"; } status(){ # $1 Schritt, $2 läuft (true/false), $3 Fehlertext (fest, ohne Anführungszeichen) printf '{"version":"%s","schritt":"%s","laeuft":%s,"fehler":"%s","am":"%s"}\n' \ "$VERSION" "$1" "$2" "${3:-}" "$(date -Iseconds)" > "$DIR/status.tmp" && mv "$DIR/status.tmp" "$DIR/status.json" } fehler(){ status "$1" false "$2"; echo "FEHLER: $2" >> "$LOG"; } if [ -z "$VERSION" ]; then fehler "Auftrag" "Der Auftrag enthält keine gültige Version."; return 1; fi echo "Update auf $VERSION, $(date)" >> "$LOG" status "Version holen" true if ! git_ fetch --tags --force origin >> "$LOG" 2>&1; then fehler "Version holen" "Der Git-Server ist nicht erreichbar."; return 1; fi if ! git_ rev-parse -q --verify "refs/tags/$VERSION^{commit}" >/dev/null; then fehler "Version holen" "Die Version gibt es auf dem Git-Server nicht."; return 1; fi # Lokale Änderungen am Code (sessions/ ausgenommen) nie überschreiben. if [ -n "$(git_ status --porcelain --untracked-files=no -- . ':!sessions')" ]; then git_ status --short -- . ':!sessions' >> "$LOG" 2>&1 fehler "Prüfen" "Auf dem Rechner gibt es lokale Änderungen am Code. Bitte von Hand klären."; return 1 fi VORHER=$(git_ rev-parse HEAD) if ! git_ checkout -q --detach "$VERSION" >> "$LOG" 2>&1; then fehler "Auschecken" "Auschecken fehlgeschlagen."; return 1; fi if docker compose version >/dev/null 2>&1; then COMPOSE="docker compose"; else COMPOSE="docker-compose"; fi status "Container bauen" true # Gebaut wird, während die alte Version weiterläuft; erst danach Neustart. if ! $COMPOSE --project-directory "$REPO" -f "$REPO/docker-compose.yml" build >> "$LOG" 2>&1; then git_ checkout -q --detach "$VORHER" >> "$LOG" 2>&1 fehler "Container bauen" "Bauen fehlgeschlagen, die bisherige Version läuft weiter."; return 1 fi status "Neustart" true if ! $COMPOSE --project-directory "$REPO" -f "$REPO/docker-compose.yml" up -d >> "$LOG" 2>&1; then fehler "Neustart" "Der Container ließ sich nicht starten."; return 1 fi local i gesund=0 for i in $(seq 1 60); do if wget -qO- http://127.0.0.1:3003/health >/dev/null 2>&1 || curl -fs http://127.0.0.1:3003/health >/dev/null 2>&1; then gesund=1; break; fi sleep 5 done if [ "$gesund" != 1 ]; then $COMPOSE --project-directory "$REPO" -f "$REPO/docker-compose.yml" logs --tail 40 >> "$LOG" 2>&1 fehler "Neustart" "Die neue Version antwortet nach 5 Minuten nicht. Protokoll prüfen."; return 1 fi printf '{"version":"%s","commit":"%s","am":"%s"}\n' "$VERSION" "$(git_ rev-parse --short HEAD)" "$(date -Iseconds)" > "$DIR/installiert.json" status "Fertig" false echo "Fertig, $(date)" >> "$LOG" } main "$@" exit $?