#!/bin/bash # ESPO-12-Snapshot-wiederherstellen - setzt die Instanz auf den Stand vor dem Update zurueck. # Aufruf: ohne Argumente. Verwendet den Snapshot, den ESPO-10 angelegt hat. # # Der Snapshot wird dabei VERBRAUCHT: Nach dem Zusammenfuehren existiert er nicht mehr, ein zweiter # Rueckweg ist dann nicht moeglich. Zurueckgenommen wird ganz /srv - also auch die gerenderte Compose # mit dem alten Image-Tag. Deshalb startet die Instanz danach von selbst wieder auf dem alten Stand. set -u echo "ESPO-12-Snapshot-wiederherstellen, Skriptstand 2026-09-24" VG=ubuntu-vg SNAPSHOT=srv-vor-update COMPOSE=/srv/espo/docker-compose.yml WARTE_MAX=900 fehler() { echo "FEHLER: $*"; echo "ESPO12_ERGEBNIS: FEHLER"; exit 1; } # Bringt den Dienst wieder hoch, wenn der Rueckweg abgebrochen wird - eine stehende Instanz # ist das schlechteste aller Ergebnisse. dienst_zurueck() { mountpoint -q /srv || mount /srv 2>/dev/null || true [ -f "$COMPOSE" ] && docker compose -f "$COMPOSE" up -d --quiet-pull >/dev/null 2>&1 || true } # 1. Vorbedingungen. [ "$(id -u)" -eq 0 ] || fehler "nicht als root gestartet" command -v lvconvert >/dev/null || fehler "LVM-Werkzeuge fehlen" command -v docker >/dev/null && docker info >/dev/null 2>&1 || fehler "Docker laeuft nicht" # 2. Der Snapshot muss da und gueltig sein. Ein 'I' im Attributfeld heisst vollgelaufen und verworfen - # dann traegt der Rueckweg nicht mehr, und ein Versuch waere schlimmer als ein ehrlicher Abbruch. lvs --noheadings -o lv_name "$VG" 2>/dev/null | grep -qw "$SNAPSHOT" \ || fehler "kein Snapshot '$SNAPSHOT' vorhanden - es gibt nichts zurueckzunehmen" ATTR="$(lvs --noheadings -o lv_attr "$VG/$SNAPSHOT" 2>/dev/null | tr -d ' ')" case "$ATTR" in *I*) fehler "Snapshot '$SNAPSHOT' ist ungueltig (vollgelaufen) - der Rueckweg traegt nicht mehr" ;; esac echo "--- Snapshot" lvs -o lv_name,lv_attr,origin,lv_size,data_percent "$VG/$SNAPSHOT" 2>/dev/null | sed 's/^/ /' # 3. Stack anhalten. Solange Container laufen, haelt Docker /srv offen. echo "--- Stack anhalten" docker compose -f "$COMPOSE" down 2>&1 | tail -n 5 # 4. /srv aushaengen. Ist der Ursprung geoeffnet, verschiebt LVM das Zusammenfuehren auf die naechste # Aktivierung - also auf einen Neustart. Wir wollen es hier, jetzt und nachpruefbar. if ! umount /srv 2>/dev/null; then echo "--- /srv ist belegt von:" { command -v fuser >/dev/null && fuser -vm /srv 2>&1 | head -n 20; } || echo " (fuser nicht verfuegbar)" dienst_zurueck fehler "/srv liess sich nicht aushaengen - es wurde nichts zurueckgenommen, der Dienst laeuft wieder" fi # 5. Zusammenfuehren. if ! lvconvert --merge "$VG/$SNAPSHOT" >/dev/null 2>&1; then dienst_zurueck fehler "Zusammenfuehren fehlgeschlagen - Stand unveraendert, der Dienst laeuft wieder" fi echo "Snapshot zusammengefuehrt - /srv steht auf dem Stand vor dem Update." # 5b. Nachweis: Beim Zusammenfuehren verbraucht LVM den Snapshot, er verschwindet also. Bleibt er stehen, # hat LVM das Zusammenfuehren auf die naechste Aktivierung verschoben - dann ist /srv noch NICHT zurueck. if lvs --noheadings -o lv_name "$VG" 2>/dev/null | grep -qw "$SNAPSHOT"; then echo "HINWEIS: '$SNAPSHOT' besteht noch - LVM hat das Zusammenfuehren verschoben." echo " Der Stand ist erst nach dem naechsten Neustart zurueckgenommen." else echo "Snapshot '$SNAPSHOT' ist verbraucht und nicht mehr vorhanden." fi # 6. Wieder einhaengen und mit der ebenfalls zurueckgenommenen Compose starten. mount /srv || fehler "/srv liess sich nicht wieder einhaengen - Handarbeit noetig" [ -f "$COMPOSE" ] || fehler "$COMPOSE fehlt nach dem Zurueckrollen - Handarbeit noetig" START_AUSGABE="$(docker compose -f "$COMPOSE" up -d --quiet-pull 2>&1)" || { echo "$START_AUSGABE" | tail -n 20 fehler "Start nach dem Zurueckrollen fehlgeschlagen" } # 7. Auf die Anwendung warten. ENDE=$(( SECONDS + WARTE_MAX )) while [ "$SECONDS" -lt "$ENDE" ]; do [ "$(docker inspect -f '{{.State.Health.Status}}' espocrm 2>/dev/null)" = "healthy" ] && break sleep 10 done [ "$(docker inspect -f '{{.State.Health.Status}}' espocrm 2>/dev/null)" = "healthy" ] \ || fehler "espocrm nach ${WARTE_MAX}s nicht gesund - 'docker logs espocrm' ansehen" # 8. Ergebnis zeigen. echo "--- Container" docker compose -f "$COMPOSE" ps --format 'table {{.Name}}\t{{.Status}}' echo "--- Instanz nach dem Rueckweg" IMAGE="$(docker inspect -f '{{.Config.Image}}' espocrm 2>/dev/null)" echo "Image: $IMAGE" echo "Version: $(docker exec espocrm php -r '$v=""; foreach (["/var/www/html/application/Espo/Resources/defaults/config.php","/var/www/html/data/config.php","/var/www/html/data/config-internal.php"] as $f) { $a=@include $f; if (is_array($a) && !empty($a["version"])) { $v=$a["version"]; } } echo $v;' 2>/dev/null)" echo "--- Platz" vgs --units g -o vg_name,vg_size,vg_free "$VG" 2>/dev/null | sed 's/^/ /' echo "--- Hinweis" echo "Der Snapshot ist verbraucht. Ein erneuter Rueckweg ist erst nach einem neuen ESPO-10 moeglich." echo "Ursache des gescheiterten Updates klaeren, bevor es wiederholt wird." echo "ESPO12_ERGEBNIS: OK"