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:
+57
-34
@@ -8,23 +8,30 @@
|
|||||||
# Erkennt selbstständig, ob unter /srv/tesm bereits eine Installation
|
# Erkennt selbstständig, ob unter /srv/tesm bereits eine Installation
|
||||||
# existiert (an sqlite.db), und verhält sich entsprechend:
|
# existiert (an sqlite.db), und verhält sich entsprechend:
|
||||||
#
|
#
|
||||||
# - Keine vorhandene Installation -> normale Frischinstallation.
|
# - Keine vorhandene Installation -> normale Frischinstallation, kein
|
||||||
# - Vorhanden, SCHEMA_VERSION unverändert -> einfaches In-Place-Update
|
# Backup nötig (nichts, worauf zurückgerollt werden könnte).
|
||||||
# (Code/Templates/Abhängigkeiten aktualisieren; sqlite.db bleibt
|
# - Vorhanden (egal ob SCHEMA_VERSION gleich geblieben oder sich
|
||||||
# unangetastet -- rsync schließt sie ohnehin aus). Kein Backup nötig,
|
# geändert hat) -> Update MIT Sicherheitsnetz: die komplette bisherige
|
||||||
# da sich am Datenbank-Schema nichts ändert.
|
# Installation (Code, venv, Datenbank, Schlüssel) wird vorher 1:1 nach
|
||||||
# - Vorhanden, SCHEMA_VERSION unbekannt oder abweichend -> Update MIT
|
# /srv/tesm-backup-pre-update-<timestamp> kopiert. Eine eigentliche
|
||||||
# Sicherheitsnetz: die komplette bisherige Installation (Code, venv,
|
# Schema-Migration übernimmt danach die App selbst beim Start (siehe
|
||||||
# Datenbank, Schlüssel) wird vorher 1:1 nach /srv/tesm-backup-pre-
|
# _ensure_schema() in app.py). Kommt der Dienst anschließend
|
||||||
# migration-<timestamp> kopiert. Die eigentliche Schema-Migration
|
# nachweislich NICHT gesund hoch (HTTP-Check auf /login), wird
|
||||||
# übernimmt danach die App selbst beim Start (siehe _ensure_schema()
|
# automatisch die komplette Sicherung zurückgespielt (alter Code +
|
||||||
# in app.py). Kommt der Dienst anschließend nachweislich NICHT gesund
|
# alte Datenbank zusammen -- ein reines DB-Rollback allein würde
|
||||||
# hoch (HTTP-Check auf /login), wird automatisch die komplette
|
# denselben Fehler beim nächsten Start mit dem neuen Code sofort
|
||||||
# Sicherung zurückgespielt (alter Code + alte Datenbank zusammen --
|
# wiederholen) und das Backup bleibt zur manuellen Prüfung erhalten.
|
||||||
# ein reines DB-Rollback allein würde denselben Migrationsfehler beim
|
# Kommt er gesund hoch, gilt das Update als erfolgreich und das
|
||||||
# nächsten Start mit dem neuen Code sofort wiederholen) und das
|
# Backup wird gelöscht.
|
||||||
# Backup bleibt zur manuellen Prüfung erhalten. Kommt er gesund hoch,
|
#
|
||||||
# gilt die Migration 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
|
set -e
|
||||||
|
|
||||||
@@ -46,6 +53,15 @@ step() { echo -e "${RED}→${NC} ${1}..." | tee -a /var/log/tesm-install
|
|||||||
clear 2>/dev/null || true
|
clear 2>/dev/null || true
|
||||||
|
|
||||||
# ---- Bestehende Installation erkennen ----
|
# ---- 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
|
EXISTING_INSTALL=0
|
||||||
[ -f /srv/tesm/sqlite.db ] && EXISTING_INSTALL=1
|
[ -f /srv/tesm/sqlite.db ] && EXISTING_INSTALL=1
|
||||||
|
|
||||||
@@ -63,7 +79,7 @@ if [ "$EXISTING_INSTALL" -eq 1 ]; then
|
|||||||
print_status "Service stopped"
|
print_status "Service stopped"
|
||||||
|
|
||||||
if [ -n "$OLD_SCHEMA_VERSION" ] && [ -n "$NEW_SCHEMA_VERSION" ] && [ "$OLD_SCHEMA_VERSION" == "$NEW_SCHEMA_VERSION" ]; then
|
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
|
else
|
||||||
if [ -n "$OLD_SCHEMA_VERSION" ] && [ -n "$NEW_SCHEMA_VERSION" ]; then
|
if [ -n "$OLD_SCHEMA_VERSION" ] && [ -n "$NEW_SCHEMA_VERSION" ]; then
|
||||||
reason="Datenbank-Schema hat sich geändert (${OLD_SCHEMA_VERSION} -> ${NEW_SCHEMA_VERSION})"
|
reason="Datenbank-Schema hat sich geändert (${OLD_SCHEMA_VERSION} -> ${NEW_SCHEMA_VERSION})"
|
||||||
@@ -71,13 +87,13 @@ if [ "$EXISTING_INSTALL" -eq 1 ]; then
|
|||||||
reason="Schema-Version der bestehenden Installation oder dieses Pakets unbekannt"
|
reason="Schema-Version der bestehenden Installation oder dieses Pakets unbekannt"
|
||||||
fi
|
fi
|
||||||
echo -e "${YELLOW}Bestehende Installation erkannt, ${reason}:${NC}"
|
echo -e "${YELLOW}Bestehende Installation erkannt, ${reason}:${NC}"
|
||||||
echo "Update mit automatischer Migration und Sicherheitsnetz (Rückroll-Backup)."
|
echo "Update mit automatischer Migration."
|
||||||
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"
|
|
||||||
cp -a /srv/tesm "$BACKUP_DIR"
|
|
||||||
print_status "Backup created"
|
|
||||||
fi
|
fi
|
||||||
|
NEEDS_MIGRATION_GUARD=1
|
||||||
|
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 ----
|
# ---- Pakete ----
|
||||||
@@ -164,11 +180,10 @@ sudo systemctl enable --now tesm.service
|
|||||||
sudo systemctl enable --now tesm-check.service tesm-check-restart.timer
|
sudo systemctl enable --now tesm-check.service tesm-check-restart.timer
|
||||||
print_status "Services enabled and started"
|
print_status "Services enabled and started"
|
||||||
|
|
||||||
# ---- Migrations-Sicherheitsnetz prüfen ----
|
# ---- Sicherheitsnetz prüfen ----
|
||||||
# Nur relevant, wenn oben tatsächlich eine riskante Migration (abweichende/
|
# Läuft bei JEDEM Update einer bestehenden Installation (NEEDS_MIGRATION_
|
||||||
# unbekannte SCHEMA_VERSION) erkannt wurde -- beim einfachen In-Place-Update
|
# GUARD=1, siehe oben) -- nur bei einer Frischinstallation ist BACKUP_DIR
|
||||||
# oder einer Frischinstallation ist BACKUP_DIR leer und dieser Block wird
|
# leer und dieser Block wird komplett übersprungen.
|
||||||
# komplett übersprungen.
|
|
||||||
if [ "$NEEDS_MIGRATION_GUARD" -eq 1 ]; then
|
if [ "$NEEDS_MIGRATION_GUARD" -eq 1 ]; then
|
||||||
step "Verifying migrated installation"
|
step "Verifying migrated installation"
|
||||||
HEALTHY=0
|
HEALTHY=0
|
||||||
@@ -182,15 +197,23 @@ if [ "$NEEDS_MIGRATION_GUARD" -eq 1 ]; then
|
|||||||
if [ "$HEALTHY" -eq 1 ]; then
|
if [ "$HEALTHY" -eq 1 ]; then
|
||||||
print_status "Migration verified healthy"
|
print_status "Migration verified healthy"
|
||||||
rm -rf "$BACKUP_DIR"
|
rm -rf "$BACKUP_DIR"
|
||||||
echo -e "${GREEN}✔${NC} Migration erfolgreich -- Backup wieder entfernt."
|
echo -e "${GREEN}✔${NC} Update erfolgreich -- Backup wieder entfernt."
|
||||||
else
|
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 systemctl stop tesm.service 2>/dev/null || true
|
||||||
sudo rm -rf /srv/tesm
|
# Fehlgeschlagene Installation NICHT einfach löschen, sondern separat
|
||||||
sudo mv "$BACKUP_DIR" /srv/tesm
|
# 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
|
sudo systemctl start tesm.service
|
||||||
echo -e "${YELLOW}Zurückgerollt auf den Stand vor dem Update (alter Code + alte Datenbank zusammen).${NC}"
|
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
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -1 +1 @@
|
|||||||
1.0.3
|
1.0.4
|
||||||
|
|||||||
Reference in New Issue
Block a user