install.sh wird update-faehig, update.sh auf Bootstrapper reduziert

install.sh erkennt jetzt selbststaendig eine bestehende Installation
(an sqlite.db) und verhaelt sich entsprechend:
- Keine vorhandene Installation -> normale Frischinstallation (wie
  bisher).
- Vorhanden, SCHEMA_VERSION unveraendert -> einfaches In-Place-Update,
  kein Backup noetig (rsync schliesst sqlite.db ohnehin aus).
- Vorhanden, SCHEMA_VERSION unbekannt/abweichend -> Update MIT
  Sicherheitsnetz: die KOMPLETTE bisherige Installation (Code, venv,
  Datenbank, Schluessel) wird vorher 1:1 nach
  /srv/tesm-backup-pre-migration-<timestamp> kopiert (bewusst nicht nur
  die Datenbank -- ein reines DB-Rollback wuerde beim naechsten Start
  mit dem NEUEN Code sofort denselben Migrationsfehler wiederholen).
  Die eigentliche Schema-Migration uebernimmt danach die App selbst
  beim Start (_ensure_schema() in app.py). Kommt der Dienst
  anschliessend per HTTP-Check auf /login nachweislich NICHT gesund
  hoch, wird automatisch die komplette Sicherung zurueckgespielt und
  bleibt zur manuellen Pruefung erhalten. Kommt er gesund hoch, gilt
  die Migration als erfolgreich und das Backup wird geloescht.

update.sh delegiert diese gesamte /srv/tesm-spezifische Logik jetzt an
install.sh und ist selbst nur noch fuer das Ablösen AELTERER, TESM
vorausgehender Installationsstufen zustaendig (PoE Manager unter
/srv/poe_manager, das urspruengliche reine Bash-Setup) -- bleibt aber
als bequemer Ein-Skript-Bootstrapper (Download + Entpacken + Aufruf von
install.sh) bestehen, wie gewuenscht. install.sh selbst ist dadurch
jetzt auch OHNE update.sh direkt aus einem entpackten Release-Paket
lauffaehig und erkennt ein Update trotzdem korrekt.

VERSION: 1.0.3 (SCHEMA_VERSION unveraendert, 1 -- keine echte Schema-
Aenderung in diesem Release, In-Place-Update-Pfad bleibt der Normalfall).
This commit is contained in:
2026-08-22 10:09:14 +02:00
parent e934c3ff0f
commit e17d91743a
3 changed files with 128 additions and 138 deletions
+89 -2
View File
@@ -1,15 +1,37 @@
#!/bin/bash
# ============================================================================
# TESM — Installer
# TESM — Installer/Updater
# Richtet System-Pakete, die Flask-App (systemd) sowie den Erreichbarkeits-
# Check-Dienst (systemd + Timer) ein. Auszuführen als root, nachdem dieses
# Repo z.B. nach /root/tesm geklont wurde.
# Repo/Release-Paket z.B. nach /root/tesm entpackt wurde.
#
# 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.
# ============================================================================
set -e
REPO_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m'
print_status() { echo -e "${GREEN}${NC} ${1} completed."; }
@@ -23,6 +45,41 @@ step() { echo -e "${RED}→${NC} ${1}..." | tee -a /var/log/tesm-install
# nie fatal.
clear 2>/dev/null || true
# ---- Bestehende Installation erkennen ----
EXISTING_INSTALL=0
[ -f /srv/tesm/sqlite.db ] && EXISTING_INSTALL=1
NEEDS_MIGRATION_GUARD=0
BACKUP_DIR=""
if [ "$EXISTING_INSTALL" -eq 1 ]; then
OLD_SCHEMA_VERSION=""
[ -f /srv/tesm/SCHEMA_VERSION ] && OLD_SCHEMA_VERSION="$(tr -d '[:space:]' < /srv/tesm/SCHEMA_VERSION)"
NEW_SCHEMA_VERSION=""
[ -f "$REPO_DIR/srv/tesm/SCHEMA_VERSION" ] && NEW_SCHEMA_VERSION="$(tr -d '[:space:]' < "$REPO_DIR/srv/tesm/SCHEMA_VERSION")"
step "Stopping tesm.service for update"
systemctl stop tesm.service tesm-check.service tesm-check-restart.timer 2>/dev/null || true
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."
else
if [ -n "$OLD_SCHEMA_VERSION" ] && [ -n "$NEW_SCHEMA_VERSION" ]; then
reason="Datenbank-Schema hat sich geändert (${OLD_SCHEMA_VERSION} -> ${NEW_SCHEMA_VERSION})"
else
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)."
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
# ---- Pakete ----
step "Installing system packages"
sudo apt-get update >>/var/log/tesm-install.log 2>&1 && print_status "apt update"
@@ -107,4 +164,34 @@ 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.
if [ "$NEEDS_MIGRATION_GUARD" -eq 1 ]; then
step "Verifying migrated installation"
HEALTHY=0
for i in $(seq 1 15); do
sleep 2
if curl -fsS -o /dev/null http://127.0.0.1:5000/login 2>/dev/null; then
HEALTHY=1
break
fi
done
if [ "$HEALTHY" -eq 1 ]; then
print_status "Migration verified healthy"
rm -rf "$BACKUP_DIR"
echo -e "${GREEN}${NC} Migration erfolgreich -- Backup wieder entfernt."
else
echo -e "${RED}✖ Migration 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
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."
fi
fi
echo -e "${GREEN}${NC} Installation abgeschlossen. Web-App erreichbar auf Port 80 (nginx) bzw. 5000 (Flask direkt)."