ESPO-03, ESPO-10, ESPO-12 und ESPO-20 lasen version aus defaults/config.php, config.php und config-internal.php. EspoCRM 10 fuehrt version aber als State-Parameter in data/state.php, und Config::load() liest die Image-Vorgaben gar nicht. Gemeldet wurde also der Vorgabewert des Images: nach einem gescheiterten migrate die neue Version, obwohl die Instanz auf der alten steht. Jetzt fragen die Skripte EspoCRM ueber "command.php version" - derselbe Wert, gegen den auch Extensions ihre acceptableVersions pruefen. Aufruf als www-data mit absolutem Pfad (bootstrap.php wechselt selbst ins Installationsverzeichnis); akzeptiert wird nur eine Zeile der Form 1.2.3, damit eine PHP-Warnung nie als Version in ein Custom Field geraet. Die grep-Rueckfallwege auf config.php entfallen, sie lasen dieselbe falsche Quelle. Probe gegen die Integrationsinstanz 10.0.8: Ausgabe "10.0.8". Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
119 lines
5.3 KiB
Bash
Executable File
119 lines
5.3 KiB
Bash
Executable File
#!/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-29"
|
|
|
|
VG=ubuntu-vg
|
|
SNAPSHOT=srv-vor-update
|
|
COMPOSE=/srv/espo/docker-compose.yml
|
|
WARTE_MAX=900
|
|
|
|
# Wartet, bis alle vier Container "healthy" melden - "starting" ist keine Aussage.
|
|
alle_gesund() {
|
|
local c
|
|
for c in espocrm-db espocrm espocrm-daemon espocrm-websocket; do
|
|
[ "$(docker inspect -f '{{.State.Health.Status}}' "$c" 2>/dev/null)" = "healthy" ] || return 1
|
|
done
|
|
return 0
|
|
}
|
|
|
|
# Nennt die Container, die noch nicht gesund sind - fuer die Fehlermeldung.
|
|
nicht_gesund() {
|
|
local c z=""
|
|
for c in espocrm-db espocrm espocrm-daemon espocrm-websocket; do
|
|
[ "$(docker inspect -f '{{.State.Health.Status}}' "$c" 2>/dev/null)" = "healthy" ] \
|
|
|| z="$z $c=$(docker inspect -f '{{.State.Health.Status}}' "$c" 2>/dev/null || echo fehlt)"
|
|
done
|
|
printf '%s' "${z# }"
|
|
}
|
|
|
|
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
|
|
alle_gesund && break
|
|
sleep 10
|
|
done
|
|
alle_gesund || fehler "nach ${WARTE_MAX}s nicht alle Container gesund: $(nicht_gesund) - 'docker logs <name>' 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 -u www-data espocrm php /var/www/html/command.php version 2>/dev/null | grep -E '^[0-9]+\.[0-9]+\.[0-9]+' | tail -n 1)"
|
|
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"
|