From 6e93529bc30f901789525d4dbf9a4f2503c80109 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=B6rdle=20Bot?= Date: Wed, 3 Dec 2025 16:25:50 +0100 Subject: [PATCH] Add backup metadata and restore script for full DB rollback --- scripts/deploy.sh | 27 ++++++++++---- scripts/restore.sh | 93 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 113 insertions(+), 7 deletions(-) create mode 100644 scripts/restore.sh diff --git a/scripts/deploy.sh b/scripts/deploy.sh index cf92b0f..48ba607 100755 --- a/scripts/deploy.sh +++ b/scripts/deploy.sh @@ -1,10 +1,10 @@ #!/bin/bash set -e -echo "🚀 Starting optimized deployment..." +echo "🚀 Starting optimized deployment with full rollback support..." -# Backup database -echo "💾 Creating database backup..." +# Backup database (per Deployment, inkl. Metadaten für Rollback) +echo "💾 Creating database backup for this deployment..." # Try to find database path from docker-compose.yml or .env DB_PATH="" @@ -26,16 +26,29 @@ if [ -n "$DB_PATH" ]; then # Convert container path to host path if needed # /app/data/prod.db -> ./data/prod.db DB_PATH=$(echo "$DB_PATH" | sed 's|/app/|./|') - + if [ -f "$DB_PATH" ]; then # Create backups directory mkdir -p ./backups - + # Create timestamped backup - BACKUP_FILE="./backups/$(basename "$DB_PATH" .db)_$(date +%Y%m%d_%H%M%S).db" + DEPLOY_TS="$(date +%Y%m%d_%H%M%S)" + BACKUP_FILE="./backups/$(basename "$DB_PATH" .db)_${DEPLOY_TS}.db" cp "$DB_PATH" "$BACKUP_FILE" echo "✅ Database backed up to: $BACKUP_FILE" - + + # Store metadata for restore (Timestamp, DB-Path, Git-Commit) + CURRENT_COMMIT="$(git rev-parse HEAD || echo 'unknown')" + { + echo "timestamp=${DEPLOY_TS}" + echo "db_path=${DB_PATH}" + echo "backup_file=${BACKUP_FILE}" + echo "git_commit=${CURRENT_COMMIT}" + } > "./backups/last_deploy.meta" + + # Append to history manifest (eine Zeile pro Deployment) + echo "${DEPLOY_TS}|${DB_PATH}|${BACKUP_FILE}|${CURRENT_COMMIT}" >> "./backups/deploy_history.log" + # Keep only last 10 backups ls -t ./backups/*.db | tail -n +11 | xargs -r rm echo "🧹 Cleaned old backups (keeping last 10)" diff --git a/scripts/restore.sh b/scripts/restore.sh new file mode 100644 index 0000000..e53c444 --- /dev/null +++ b/scripts/restore.sh @@ -0,0 +1,93 @@ +#!/bin/bash +set -e + +echo "🧯 Hördle restore script – Rollback auf früheres Datenbank-Backup" + +# Hilfsfunktion für Fehlerausgabe +die() { + echo "❌ $1" >&2 + exit 1 +} + +# Backup-Verzeichnis +BACKUP_DIR="./backups" + +if [ ! -d "$BACKUP_DIR" ]; then + die "Kein Backup-Verzeichnis gefunden (${BACKUP_DIR}). Es scheint noch kein Deployment-Backup erstellt worden zu sein." +fi + +# Argument: gewünschter Backup-Timestamp oder 'latest' +TARGET="$1" + +if [ -z "$TARGET" ]; then + echo "⚙️ Nutzung:" + echo " ./scripts/restore.sh latest # neuestes Backup zurückspielen" + echo " ./scripts/restore.sh 20250101_120000 # bestimmtes Backup (Timestamp aus Dateiname)" + echo "" + echo "Verfügbare Backups:" + ls -1 "${BACKUP_DIR}"/*.db 2>/dev/null || echo " (keine .db-Backups gefunden)" + exit 1 +fi + +# DB-Pfad wie in deploy.sh bestimmen +DB_PATH="" + +if [ -f "docker-compose.yml" ]; then + DB_PATH=$(grep -oP 'DATABASE_URL=file:\K[^\s]+' docker-compose.yml | head -1) +fi + +if [ -z "$DB_PATH" ] && [ -f ".env" ]; then + DB_PATH=$(grep -oP '^DATABASE_URL=file:\K.+' .env | head -1) +fi + +DB_PATH=$(echo "$DB_PATH" | tr -d '"' | tr -d "'") + +if [ -z "$DB_PATH" ]; then + die "Konnte den Datenbank-Pfad aus docker-compose.yml oder .env nicht ermitteln." +fi + +# Containerpfad zu Hostpfad umbauen (/app/... -> ./...) +DB_PATH=$(echo "$DB_PATH" | sed 's|/app/|./|') + +echo "📁 Ziel-Datenbank-Datei: $DB_PATH" + +# Backup-Datei bestimmen +if [ "$TARGET" = "latest" ]; then + BACKUP_FILE=$(ls -t "${BACKUP_DIR}"/*.db 2>/dev/null | head -1 || true) + [ -z "$BACKUP_FILE" ] && die "Kein Backup gefunden." +else + # Versuchen, exakten Dateinamen zu finden + if [ -f "${BACKUP_DIR}/${TARGET}" ]; then + BACKUP_FILE="${BACKUP_DIR}/${TARGET}" + else + # Versuchen, anhand des Timestamps ein Backup zu finden + BACKUP_FILE=$(ls "${BACKUP_DIR}"/*"${TARGET}"*.db 2>/dev/null | head -1 || true) + fi + + [ -z "$BACKUP_FILE" ] && die "Kein Backup für '${TARGET}' gefunden." +fi + +echo "⏪ Verwende Backup-Datei: $BACKUP_FILE" + +if [ ! -f "$BACKUP_FILE" ]; then + die "Backup-Datei existiert nicht: $BACKUP_FILE" +fi + +read -p "❗ Dies überschreibt die aktuelle Datenbank-Datei. Fortfahren? [y/N] " CONFIRM +if [[ ! "$CONFIRM" =~ ^[Yy]$ ]]; then + echo "Abgebrochen." + exit 0 +fi + +echo "📦 Kopiere Backup nach: $DB_PATH" +cp "$BACKUP_FILE" "$DB_PATH" + +echo "🔄 Starte Docker-Container neu..." +docker compose restart hoerdle + +echo "✅ Restore abgeschlossen." +echo "ℹ️ Hinweis: Der Code-Stand (Git-Commit) ist nicht automatisch zurückgedreht." +echo " Falls du auch die App-Version zurückrollen möchtest, checke lokal den passenden Commit/Tag aus" +echo " und führe anschließend wieder ./scripts/deploy.sh aus." + +