#!/bin/bash # ============================================================================= # TimeClock v3 - Backup-Restore Script # ============================================================================= # Stellt ein Datenbank-Backup wieder her # # Verwendung: # ./restore-backup.sh [BACKUP_FILE] # ./restore-backup.sh # Zeigt Liste der verfügbaren Backups # ./restore-backup.sh timeclock_db_20251018_020000.sql.gz # # WARNUNG: Dies überschreibt die aktuelle Datenbank! # ============================================================================= set -e # Farben RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' BLUE='\033[0;34m' NC='\033[0m' # Konfiguration BACKUP_DIR="/var/backups/timeclock" PROJECT_DIR="/var/www/timeclock" ENV_FILE="$PROJECT_DIR/backend/.env" # Logging log() { echo -e "${BLUE}ℹ️ $1${NC}" } log_success() { echo -e "${GREEN}✅ $1${NC}" } log_warning() { echo -e "${YELLOW}⚠️ $1${NC}" } log_error() { echo -e "${RED}❌ $1${NC}" } # ============================================================================= # Voraussetzungen prüfen # ============================================================================= if [ ! -f "$ENV_FILE" ]; then log_error ".env Datei nicht gefunden: $ENV_FILE" exit 1 fi if [ ! -d "$BACKUP_DIR" ]; then log_error "Backup-Verzeichnis nicht gefunden: $BACKUP_DIR" exit 1 fi # ============================================================================= # Datenbank-Credentials aus .env lesen # ============================================================================= get_env_value() { grep "^$1=" "$ENV_FILE" | cut -d '=' -f2- | tr -d '"' | tr -d "'" } DB_HOST=$(get_env_value "DB_HOST") DB_PORT=$(get_env_value "DB_PORT") DB_NAME=$(get_env_value "DB_NAME") DB_USER=$(get_env_value "DB_USER") DB_PASSWORD=$(get_env_value "DB_PASSWORD") # Defaults DB_HOST=${DB_HOST:-localhost} DB_PORT=${DB_PORT:-3306} if [ -z "$DB_NAME" ] || [ -z "$DB_USER" ] || [ -z "$DB_PASSWORD" ]; then log_error "Datenbank-Credentials unvollständig in .env" exit 1 fi # ============================================================================= # Verfügbare Backups auflisten # ============================================================================= list_backups() { echo "" log "Verfügbare Backups in $BACKUP_DIR:" echo "" BACKUPS=($(ls -t "$BACKUP_DIR"/timeclock_db_*.sql.gz 2>/dev/null)) if [ ${#BACKUPS[@]} -eq 0 ]; then log_warning "Keine Backups gefunden!" exit 1 fi for i in "${!BACKUPS[@]}"; do BACKUP="${BACKUPS[$i]}" FILENAME=$(basename "$BACKUP") SIZE=$(du -h "$BACKUP" | cut -f1) DATE=$(stat -c %y "$BACKUP" | cut -d'.' -f1) printf "%2d) %-50s %6s %s\n" $((i+1)) "$FILENAME" "$SIZE" "$DATE" done echo "" } # ============================================================================= # Backup-Datei auswählen # ============================================================================= select_backup() { list_backups read -p "Wähle ein Backup (Nummer) oder 'q' zum Beenden: " selection if [ "$selection" = "q" ] || [ "$selection" = "Q" ]; then log "Abgebrochen." exit 0 fi if ! [[ "$selection" =~ ^[0-9]+$ ]]; then log_error "Ungültige Eingabe!" exit 1 fi BACKUPS=($(ls -t "$BACKUP_DIR"/timeclock_db_*.sql.gz 2>/dev/null)) INDEX=$((selection - 1)) if [ $INDEX -lt 0 ] || [ $INDEX -ge ${#BACKUPS[@]} ]; then log_error "Ungültige Auswahl!" exit 1 fi BACKUP_FILE="${BACKUPS[$INDEX]}" } # ============================================================================= # Restore durchführen # ============================================================================= restore_backup() { local backup_file=$1 if [ ! -f "$backup_file" ]; then log_error "Backup-Datei nicht gefunden: $backup_file" exit 1 fi echo "" log_warning "WARNUNG: Dies wird die aktuelle Datenbank '$DB_NAME' überschreiben!" log "Backup-Datei: $(basename $backup_file)" log "Größe: $(du -h $backup_file | cut -f1)" log "Datenbank: $DB_USER@$DB_HOST:$DB_PORT/$DB_NAME" echo "" read -p "Fortfahren? (yes/no): " confirm if [ "$confirm" != "yes" ]; then log "Abgebrochen." exit 0 fi # Erstelle Backup der aktuellen Datenbank (Sicherheitskopie) log "Erstelle Sicherheitskopie der aktuellen Datenbank..." SAFETY_BACKUP="$BACKUP_DIR/timeclock_db_pre_restore_$(date +%Y%m%d_%H%M%S).sql.gz" if mysqldump \ --host="$DB_HOST" \ --port="$DB_PORT" \ --user="$DB_USER" \ --password="$DB_PASSWORD" \ --single-transaction \ --databases "$DB_NAME" \ | gzip > "$SAFETY_BACKUP"; then log_success "Sicherheitskopie erstellt: $(basename $SAFETY_BACKUP)" else log_error "Sicherheitskopie fehlgeschlagen!" read -p "Trotzdem fortfahren? (yes/no): " force if [ "$force" != "yes" ]; then exit 1 fi fi # Restore durchführen log "Stelle Backup wieder her..." # Datenbank leeren (optional, aber empfohlen) log "Leere Datenbank..." mysql \ --host="$DB_HOST" \ --port="$DB_PORT" \ --user="$DB_USER" \ --password="$DB_PASSWORD" \ -e "DROP DATABASE IF EXISTS $DB_NAME; CREATE DATABASE $DB_NAME;" # Backup einspielen if gunzip < "$backup_file" | mysql \ --host="$DB_HOST" \ --port="$DB_PORT" \ --user="$DB_USER" \ --password="$DB_PASSWORD"; then log_success "Backup erfolgreich wiederhergestellt!" # Datenbank-Statistiken TABLE_COUNT=$(mysql \ --host="$DB_HOST" \ --port="$DB_PORT" \ --user="$DB_USER" \ --password="$DB_PASSWORD" \ -e "SELECT COUNT(*) FROM information_schema.tables WHERE table_schema = '$DB_NAME';" -s -N) log "Datenbank-Statistik:" log " 📊 Tabellen: $TABLE_COUNT" # Optional: Service neu starten log_warning "Möchtest du den Backend-Service neu starten?" read -p "Service neu starten? (y/n): " restart if [ "$restart" = "y" ] || [ "$restart" = "Y" ]; then if command -v pm2 &> /dev/null && pm2 list | grep -q "timeclock-backend"; then pm2 restart timeclock-backend log_success "PM2-Service neu gestartet" elif systemctl is-active --quiet timeclock; then sudo systemctl restart timeclock log_success "systemd-Service neu gestartet" else log_warning "Service-Verwaltung nicht gefunden - bitte manuell neu starten" fi fi echo "" log_success "Restore abgeschlossen!" log "Sicherheitskopie der alten Datenbank: $(basename $SAFETY_BACKUP)" else log_error "Restore fehlgeschlagen!" log "Die Sicherheitskopie befindet sich unter: $(basename $SAFETY_BACKUP)" exit 1 fi } # ============================================================================= # Hauptprogramm # ============================================================================= echo "" echo -e "${BLUE}════════════════════════════════════════════════════════════${NC}" echo -e "${BLUE} TimeClock v3 - Backup Restore${NC}" echo -e "${BLUE}════════════════════════════════════════════════════════════${NC}" echo "" # Wenn Backup-Datei als Argument übergeben wurde if [ $# -eq 1 ]; then BACKUP_FILE="$1" # Wenn nur Dateiname (ohne Pfad) übergeben wurde if [ ! -f "$BACKUP_FILE" ]; then BACKUP_FILE="$BACKUP_DIR/$1" fi restore_backup "$BACKUP_FILE" else # Interaktive Auswahl select_backup restore_backup "$BACKUP_FILE" fi exit 0