install.sh: Sicherheitsnetz gilt jetzt fuer JEDES Update, nicht nur Schema-Aenderungen
Live gefunden: der 'Schema unveraendert -> kein Backup'-Kurzschluss aus v1.0.3 liess einen rein CODE-seitigen Fehler im neuen Paket (z.B. ein kaputtes app.py -- mit dem DB-Schema hat das nichts zu tun) komplett ungeschuetzt durch. Backup + Health-Check + ggf. Rollback laufen jetzt bei JEDEM Update einer bestehenden Installation, unabhaengig von SCHEMA_VERSION -- die bleibt nur noch fuer den Wortlaut der Log-Meldung relevant (In-Place-Update vs. Migration). Zusaetzlich beim Rollback selbst: 'mv' durch 'cp -a' beim Zurueckspielen ersetzt, plus die fehlgeschlagene Installation vorher separat beiseite gelegt (/srv/tesm-failed-update-<timestamp>) statt geloescht -- vorher wurde das Backup beim Zurueckspielen selbst zum neuen /srv/tesm und verschwand dadurch als eigenstaendige Sicherung (widersprach der eigenen Zusage 'Backup bleibt erhalten'). Live auf der Testbox in allen drei Pfaden verifiziert: - Erfolgreiches Update: Backup erstellt, Health-Check bestanden, Backup geloescht, Daten erhalten. - Migration (kuenstlich abweichende SCHEMA_VERSION, echte Struktur unveraendert): Backup erstellt, Health-Check bestanden, Backup geloescht. - Fehlgeschlagenes Update (absichtlich kaputte app.py): Backup erstellt, Health-Check schlaegt korrekt fehl, automatischer Rollback stellt den letzten funktionierenden Zustand wieder her (Dienst aktiv, Health-Check 200, Datenbank-Canary erhalten), Backup UND fehlgeschlagene Installation bleiben als zwei getrennte Verzeichnisse zur Fehlersuche erhalten. VERSION: 1.0.4 (v1.0.3 hatte die oben beschriebene Luecke und wurde bereits ausgerollt, daher hier ein neues Release statt eines erneuten Tags auf v1.0.3).
This commit is contained in:
+55
-32
@@ -8,23 +8,30 @@
|
||||
# Erkennt selbstständig, ob unter /srv/tesm bereits eine Installation
|
||||
# existiert (an sqlite.db), und verhält sich entsprechend:
|
||||
#
|
||||
# - Keine vorhandene Installation -> normale Frischinstallation.
|
||||
# - Vorhanden, SCHEMA_VERSION unverändert -> einfaches In-Place-Update
|
||||
# (Code/Templates/Abhängigkeiten aktualisieren; sqlite.db bleibt
|
||||
# unangetastet -- rsync schließt sie ohnehin aus). Kein Backup nötig,
|
||||
# da sich am Datenbank-Schema nichts ändert.
|
||||
# - Vorhanden, SCHEMA_VERSION unbekannt oder abweichend -> Update MIT
|
||||
# Sicherheitsnetz: die komplette bisherige Installation (Code, venv,
|
||||
# Datenbank, Schlüssel) wird vorher 1:1 nach /srv/tesm-backup-pre-
|
||||
# migration-<timestamp> kopiert. Die eigentliche Schema-Migration
|
||||
# übernimmt danach die App selbst beim Start (siehe _ensure_schema()
|
||||
# in app.py). Kommt der Dienst anschließend nachweislich NICHT gesund
|
||||
# hoch (HTTP-Check auf /login), wird automatisch die komplette
|
||||
# Sicherung zurückgespielt (alter Code + alte Datenbank zusammen --
|
||||
# ein reines DB-Rollback allein würde denselben Migrationsfehler beim
|
||||
# nächsten Start mit dem neuen Code sofort wiederholen) und das
|
||||
# Backup bleibt zur manuellen Prüfung erhalten. Kommt er gesund hoch,
|
||||
# gilt die Migration als erfolgreich und das Backup wird gelöscht.
|
||||
# - Keine vorhandene Installation -> normale Frischinstallation, kein
|
||||
# Backup nötig (nichts, worauf zurückgerollt werden könnte).
|
||||
# - Vorhanden (egal ob SCHEMA_VERSION gleich geblieben oder sich
|
||||
# geändert hat) -> Update MIT Sicherheitsnetz: die komplette bisherige
|
||||
# Installation (Code, venv, Datenbank, Schlüssel) wird vorher 1:1 nach
|
||||
# /srv/tesm-backup-pre-update-<timestamp> kopiert. Eine eigentliche
|
||||
# Schema-Migration übernimmt danach die App selbst beim Start (siehe
|
||||
# _ensure_schema() in app.py). Kommt der Dienst anschließend
|
||||
# nachweislich NICHT gesund hoch (HTTP-Check auf /login), wird
|
||||
# automatisch die komplette Sicherung zurückgespielt (alter Code +
|
||||
# alte Datenbank zusammen -- ein reines DB-Rollback allein würde
|
||||
# denselben Fehler beim nächsten Start mit dem neuen Code sofort
|
||||
# wiederholen) und das Backup bleibt zur manuellen Prüfung erhalten.
|
||||
# Kommt er gesund hoch, gilt das Update als erfolgreich und das
|
||||
# Backup wird gelöscht.
|
||||
#
|
||||
# Das Sicherheitsnetz greift bewusst bei JEDEM Update einer bestehenden
|
||||
# Installation, nicht nur bei einer erkannten Schema-Änderung -- ein
|
||||
# rein code-seitiger Fehler im neuen Paket hat mit dem Datenbank-Schema
|
||||
# nichts zu tun, hätte den Dienst bei einem "Schema unverändert -> kein
|
||||
# Backup"-Kurzschluss aber trotzdem ungeschützt lahmgelegt (live
|
||||
# reproduziert). SCHEMA_VERSION bestimmt nur noch den Wortlaut der
|
||||
# Log-Meldung (In-Place-Update vs. Migration), nicht mehr, OB
|
||||
# abgesichert wird.
|
||||
# ============================================================================
|
||||
set -e
|
||||
|
||||
@@ -46,6 +53,15 @@ step() { echo -e "${RED}→${NC} ${1}..." | tee -a /var/log/tesm-install
|
||||
clear 2>/dev/null || true
|
||||
|
||||
# ---- Bestehende Installation erkennen ----
|
||||
# WICHTIG: das Sicherheitsnetz (Backup + Health-Check + ggf. Rückroll)
|
||||
# greift bei JEDEM Update einer bestehenden Installation, nicht nur bei
|
||||
# einer erkannten Schema-Änderung -- live so gefunden: ein rein
|
||||
# code-seitiger Fehler im neuen Paket (z.B. ein kaputtes app.py, mit dem
|
||||
# Schema selbst hat das nichts zu tun) hätte bei einem reinen "Schema
|
||||
# unverändert -> kein Backup"-Kurzschluss ungeschützt den Dienst
|
||||
# lahmgelegt, ganz ohne automatische Wiederherstellung. Die
|
||||
# SCHEMA_VERSION-Auswertung dient jetzt nur noch der Log-Meldung (WARUM
|
||||
# aktualisiert wird), nicht mehr der Entscheidung OB abgesichert wird.
|
||||
EXISTING_INSTALL=0
|
||||
[ -f /srv/tesm/sqlite.db ] && EXISTING_INSTALL=1
|
||||
|
||||
@@ -63,7 +79,7 @@ if [ "$EXISTING_INSTALL" -eq 1 ]; then
|
||||
print_status "Service stopped"
|
||||
|
||||
if [ -n "$OLD_SCHEMA_VERSION" ] && [ -n "$NEW_SCHEMA_VERSION" ] && [ "$OLD_SCHEMA_VERSION" == "$NEW_SCHEMA_VERSION" ]; then
|
||||
echo -e "${GREEN}Bestehende Installation erkannt, Datenbank-Schema unverändert (Version ${OLD_SCHEMA_VERSION}):${NC} einfaches In-Place-Update, kein Backup nötig."
|
||||
echo -e "${GREEN}Bestehende Installation erkannt, Datenbank-Schema unverändert (Version ${OLD_SCHEMA_VERSION}):${NC} In-Place-Update."
|
||||
else
|
||||
if [ -n "$OLD_SCHEMA_VERSION" ] && [ -n "$NEW_SCHEMA_VERSION" ]; then
|
||||
reason="Datenbank-Schema hat sich geändert (${OLD_SCHEMA_VERSION} -> ${NEW_SCHEMA_VERSION})"
|
||||
@@ -71,14 +87,14 @@ if [ "$EXISTING_INSTALL" -eq 1 ]; then
|
||||
reason="Schema-Version der bestehenden Installation oder dieses Pakets unbekannt"
|
||||
fi
|
||||
echo -e "${YELLOW}Bestehende Installation erkannt, ${reason}:${NC}"
|
||||
echo "Update mit automatischer Migration und Sicherheitsnetz (Rückroll-Backup)."
|
||||
echo "Update mit automatischer Migration."
|
||||
fi
|
||||
NEEDS_MIGRATION_GUARD=1
|
||||
BACKUP_DIR="/srv/tesm-backup-pre-migration-$(date +%Y%m%d-%H%M%S)"
|
||||
step "Backing up current installation to $BACKUP_DIR before migration"
|
||||
BACKUP_DIR="/srv/tesm-backup-pre-update-$(date +%Y%m%d-%H%M%S)"
|
||||
step "Backing up current installation to $BACKUP_DIR before update"
|
||||
cp -a /srv/tesm "$BACKUP_DIR"
|
||||
print_status "Backup created"
|
||||
fi
|
||||
fi
|
||||
|
||||
# ---- Pakete ----
|
||||
step "Installing system packages"
|
||||
@@ -164,11 +180,10 @@ sudo systemctl enable --now tesm.service
|
||||
sudo systemctl enable --now tesm-check.service tesm-check-restart.timer
|
||||
print_status "Services enabled and started"
|
||||
|
||||
# ---- Migrations-Sicherheitsnetz prüfen ----
|
||||
# Nur relevant, wenn oben tatsächlich eine riskante Migration (abweichende/
|
||||
# unbekannte SCHEMA_VERSION) erkannt wurde -- beim einfachen In-Place-Update
|
||||
# oder einer Frischinstallation ist BACKUP_DIR leer und dieser Block wird
|
||||
# komplett übersprungen.
|
||||
# ---- Sicherheitsnetz prüfen ----
|
||||
# Läuft bei JEDEM Update einer bestehenden Installation (NEEDS_MIGRATION_
|
||||
# GUARD=1, siehe oben) -- nur bei einer Frischinstallation ist BACKUP_DIR
|
||||
# leer und dieser Block wird komplett übersprungen.
|
||||
if [ "$NEEDS_MIGRATION_GUARD" -eq 1 ]; then
|
||||
step "Verifying migrated installation"
|
||||
HEALTHY=0
|
||||
@@ -182,15 +197,23 @@ if [ "$NEEDS_MIGRATION_GUARD" -eq 1 ]; then
|
||||
if [ "$HEALTHY" -eq 1 ]; then
|
||||
print_status "Migration verified healthy"
|
||||
rm -rf "$BACKUP_DIR"
|
||||
echo -e "${GREEN}✔${NC} Migration erfolgreich -- Backup wieder entfernt."
|
||||
echo -e "${GREEN}✔${NC} Update erfolgreich -- Backup wieder entfernt."
|
||||
else
|
||||
echo -e "${RED}✖ Migration fehlgeschlagen -- Dienst antwortet nicht gesund. Rolle zurück...${NC}"
|
||||
echo -e "${RED}✖ Update fehlgeschlagen -- Dienst antwortet nicht gesund. Rolle zurück...${NC}"
|
||||
sudo systemctl stop tesm.service 2>/dev/null || true
|
||||
sudo rm -rf /srv/tesm
|
||||
sudo mv "$BACKUP_DIR" /srv/tesm
|
||||
# Fehlgeschlagene Installation NICHT einfach löschen, sondern separat
|
||||
# beiseite legen (zur Fehlersuche) -- und das Backup per "cp" statt
|
||||
# "mv" zurückspielen, damit BEIDES danach getrennt erhalten bleibt
|
||||
# (sonst würde das Backup beim Zurückspielen selbst zum neuen
|
||||
# /srv/tesm werden und als eigenständige Sicherung verschwinden).
|
||||
FAILED_DIR="/srv/tesm-failed-update-$(date +%Y%m%d-%H%M%S)"
|
||||
sudo mv /srv/tesm "$FAILED_DIR"
|
||||
sudo cp -a "$BACKUP_DIR" /srv/tesm
|
||||
sudo systemctl start tesm.service
|
||||
echo -e "${YELLOW}Zurückgerollt auf den Stand vor dem Update (alter Code + alte Datenbank zusammen).${NC}"
|
||||
echo "Bitte /var/log/tesm/app.log prüfen oder Export/Import nutzen, bevor erneut aktualisiert wird."
|
||||
echo "Backup bleibt erhalten unter: ${BACKUP_DIR}"
|
||||
echo "Die fehlgeschlagene Installation liegt zur Fehlersuche unter: ${FAILED_DIR}"
|
||||
echo "Bitte /var/log/tesm/app.log dort prüfen, bevor erneut aktualisiert wird."
|
||||
fi
|
||||
fi
|
||||
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
1.0.3
|
||||
1.0.4
|
||||
|
||||
Reference in New Issue
Block a user