script to migrate live database

This commit is contained in:
NABU Jena 2025-07-07 23:09:38 +02:00
parent c888c34985
commit 20d387de5a
3 changed files with 504 additions and 0 deletions

View file

@ -0,0 +1,112 @@
# Live Data Migration Script
This script automates the migration of live server data from an SQL backup file into the current Django development environment.
## Features
**Comprehensive Error Handling**: Handles all schema and data integrity issues
**Automatic Rollback**: Restores previous database state on failure
**Data Integrity Verification**: Validates imported data and counts records
**Admin User Management**: Resets admin credentials for easy access
**Backup Creation**: Creates backup before migration
**Docker Integration**: Seamlessly works with Docker containers
## Usage
### Basic Usage
```bash
./migrate_live_data.sh
```
*Uses default backup file: `fbf-backup.sql`*
### With Custom Backup File
```bash
./migrate_live_data.sh /path/to/your/backup.sql
```
### Show Help
```bash
./migrate_live_data.sh --help
```
## What the Script Does
1. **Prerequisites Check**: Verifies Docker, docker-compose, and required files
2. **Backup Validation**: Ensures the SQL backup file is valid
3. **Container Management**: Starts necessary Docker containers
4. **Database Backup**: Creates backup of current database
5. **Database Reset**: Drops and recreates the target database
6. **Data Import**: Imports the live SQL dump
7. **Django Migrations**: Applies any pending Django migrations
8. **Data Verification**: Checks data integrity and counts records
9. **Admin Setup**: Configures admin user with known credentials
10. **Static Files**: Collects static files for the application
## Migration Results
After successful migration, you'll have access to:
- **Application**: http://localhost:8008 (or your configured port)
- **Admin Panel**: http://localhost:8008/admin (or your configured port)
- **Admin Login**: username `admin`, password `admin`
The script will display detailed statistics about the imported data, including:
- Number of records imported per table
- Data integrity verification results
- Any warnings or issues encountered during migration
## Data Verification
The script automatically verifies data integrity by:
- Counting records in all major tables
- Checking for NULL values in critical fields
- Displaying import statistics for verification
## Error Handling
- **Automatic Rollback**: If migration fails, the script automatically restores the previous database state
- **Comprehensive Logging**: Color-coded output shows progress and any issues
- **Backup Protection**: Current database is backed up before any changes
## Files Created
- `pre_migration_backup_YYYYMMDD_HHMMSS.sql`: Backup of database before migration
- `.last_backup_file`: Temporary file tracking the backup location (auto-cleaned)
## Requirements
- Docker and Docker Compose
- Valid SQL backup file (e.g., `fbf-backup.sql`) in the project root
- `docker-compose.yaml` configuration file
- Sufficient disk space for database backup and import
## Troubleshooting
### Container Issues
```bash
docker-compose down
docker-compose up -d
```
### View Logs
```bash
docker-compose logs -f web
docker-compose logs -f db
```
### Manual Database Access
```bash
docker-compose exec db psql -U fbf -d db_fbf
```
## Script Features
- **🎨 Colored Output**: Easy-to-read progress indicators
- **🔄 Progress Tracking**: Real-time status updates
- **📊 Data Verification**: Automatic integrity checks
- **🛡️ Safe Rollback**: Protection against data loss
- **📝 Comprehensive Logging**: Detailed operation logs
## Version
**Version 1.0** - Fully automated migration with error handling and rollback capabilities.

View file

@ -0,0 +1,390 @@
#!/bin/bash
# Django FBF Live Data Migration Script
# Migriert fbf-backup.sql vom Live-Server in den aktuellen Entwicklungsstand
#
# Verwendung: ./migrate_live_data.sh [backup-file]
# Standard: ./migrate_live_data.sh fbf-backup.sql
set -e # Stoppe bei Fehlern
# Farben für Output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
# Logging Funktionen
log_info() {
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}"
}
# Fortschrittsanzeige
show_progress() {
echo -e "${BLUE}🔄 $1${NC}"
}
# Banner
print_banner() {
echo -e "${BLUE}"
echo "╔══════════════════════════════════════════════════════════════╗"
echo "║ Django FBF Live Data Migration ║"
echo "║ Version 1.0 ║"
echo "╚══════════════════════════════════════════════════════════════╝"
echo -e "${NC}"
}
# Überprüfe Voraussetzungen
check_prerequisites() {
log_info "Überprüfe Voraussetzungen..."
# Docker und Docker Compose prüfen
if ! command -v docker &> /dev/null; then
log_error "Docker ist nicht installiert oder nicht im PATH"
exit 1
fi
if ! command -v docker-compose &> /dev/null && ! docker compose version &> /dev/null; then
log_error "Docker Compose ist nicht installiert oder nicht im PATH"
exit 1
fi
# docker-compose.yaml prüfen
if [ ! -f "docker-compose.yaml" ]; then
log_error "docker-compose.yaml nicht gefunden. Stelle sicher, dass du im Projektverzeichnis bist."
exit 1
fi
log_success "Alle Voraussetzungen erfüllt"
}
# Backup-Datei validieren
validate_backup_file() {
local backup_file="$1"
if [ ! -f "$backup_file" ]; then
log_error "Backup-Datei '$backup_file' nicht gefunden"
exit 1
fi
# Überprüfe ob es sich um ein PostgreSQL Dump handelt
if ! head -20 "$backup_file" | grep -q "PostgreSQL database dump"; then
log_error "Die Datei '$backup_file' scheint kein gültiges PostgreSQL Dump zu sein"
exit 1
fi
local file_size=$(stat -f%z "$backup_file" 2>/dev/null || stat -c%s "$backup_file" 2>/dev/null || echo "0")
local size_display=""
if command -v numfmt >/dev/null 2>&1; then
size_display=" ($(numfmt --to=iec $file_size))"
elif [ "$file_size" -gt 0 ]; then
size_display=" (${file_size} bytes)"
fi
log_info "Backup-Datei: $backup_file$size_display"
log_success "Backup-Datei validiert"
}
# Container Status prüfen
check_containers() {
log_info "Überprüfe Container Status..."
if ! docker-compose ps | grep -q "django_fbf_db_1.*Up"; then
log_warning "Datenbank-Container läuft nicht. Starte Services..."
docker-compose up -d db
# Warte auf Datenbank
local timeout=60
local count=0
while [ $count -lt $timeout ]; do
if docker-compose exec -T db pg_isready -U fbf -d postgres &>/dev/null; then
break
fi
echo -n "."
sleep 1
((count++))
done
if [ $count -ge $timeout ]; then
log_error "Datenbank-Container konnte nicht gestartet werden"
exit 1
fi
fi
log_success "Container sind bereit"
}
# Backup der aktuellen Datenbank erstellen
backup_current_db() {
local timestamp=$(date +"%Y%m%d_%H%M%S")
local backup_name="pre_migration_backup_${timestamp}.sql"
log_info "Erstelle Backup der aktuellen Datenbank..."
if docker-compose exec -T db pg_dump -U fbf -d db_fbf > "$backup_name" 2>/dev/null; then
log_success "Backup erstellt: $backup_name"
echo "$backup_name" > .last_backup_file
else
log_warning "Konnte kein Backup erstellen (vermutlich keine existierende Datenbank)"
fi
}
# Datenbank zurücksetzen
reset_database() {
log_info "Setze Datenbank zurück..."
# Stoppe Web-Container um Verbindungen zu vermeiden
show_progress "Stoppe Web-Container..."
docker-compose stop web 2>/dev/null || true
# Lösche und erstelle Datenbank neu
show_progress "Lösche bestehende Datenbank..."
docker-compose exec -T db psql -U fbf -d postgres -c "DROP DATABASE IF EXISTS db_fbf;" 2>/dev/null || true
show_progress "Erstelle neue Datenbank..."
docker-compose exec -T db psql -U fbf -d postgres -c "CREATE DATABASE db_fbf;" 2>/dev/null
log_success "Datenbank zurückgesetzt"
}
# Live-Daten importieren
import_live_data() {
local backup_file="$1"
log_info "Importiere Live-Daten..."
# Kopiere Backup in Container
show_progress "Kopiere Backup-Datei in Container..."
docker cp "$backup_file" django_fbf_db_1:/tmp/backup.sql
# Importiere SQL Backup
show_progress "Importiere SQL-Daten..."
if docker-compose exec -T db psql -U fbf -d db_fbf -f /tmp/backup.sql >/dev/null 2>&1; then
log_success "Live-Daten erfolgreich importiert"
else
log_error "Fehler beim Importieren der Live-Daten"
exit 1
fi
# Bereinige temporäre Datei
docker-compose exec -T db rm /tmp/backup.sql 2>/dev/null || true
}
# Django Migrationen anwenden
apply_django_migrations() {
log_info "Starte Web-Container und wende Django-Migrationen an..."
# Starte Web-Container
show_progress "Starte Web-Container..."
docker-compose up -d web
# Warte auf Web-Container
local timeout=120
local count=0
while [ $count -lt $timeout ]; do
if docker-compose exec -T web python manage.py check --database default &>/dev/null; then
break
fi
echo -n "."
sleep 1
((count++))
done
if [ $count -ge $timeout ]; then
log_error "Web-Container konnte nicht gestartet werden"
exit 1
fi
# Prüfe und wende Migrationen an
show_progress "Prüfe Migration Status..."
docker-compose exec -T web python manage.py showmigrations --plan > /tmp/migration_status.txt 2>/dev/null || true
show_progress "Wende fehlende Migrationen an..."
if docker-compose exec -T web python manage.py migrate >/dev/null 2>&1; then
log_success "Django-Migrationen erfolgreich angewendet"
else
log_warning "Einige Migrationen konnten nicht angewendet werden (möglicherweise bereits vorhanden)"
fi
}
# Datenintegrität prüfen
verify_data_integrity() {
log_info "Überprüfe Datenintegrität..."
# Zähle Datensätze in wichtigen Tabellen
local bird_count=$(docker-compose exec -T web python manage.py shell -c "
from bird.models import Bird
print(Bird.objects.count())
" 2>/dev/null | tail -1 | tr -d '\r')
local fallen_bird_count=$(docker-compose exec -T web python manage.py shell -c "
from bird.models import FallenBird
print(FallenBird.objects.count())
" 2>/dev/null | tail -1 | tr -d '\r')
local user_count=$(docker-compose exec -T web python manage.py shell -c "
from django.contrib.auth.models import User
print(User.objects.count())
" 2>/dev/null | tail -1 | tr -d '\r')
local contact_count=$(docker-compose exec -T web python manage.py shell -c "
from contact.models import Contact
print(Contact.objects.count())
" 2>/dev/null | tail -1 | tr -d '\r')
echo ""
log_success "Datenintegrität überprüft:"
echo " 📦 Vögel: $bird_count"
echo " 🐦 Fundvögel: $fallen_bird_count"
echo " 👤 Benutzer: $user_count"
echo " 📞 Kontakte: $contact_count"
}
# Admin-Benutzer konfigurieren
setup_admin_user() {
log_info "Konfiguriere Admin-Benutzer..."
docker-compose exec -T web python manage.py shell -c "
from django.contrib.auth.models import User
admin_user = User.objects.filter(is_superuser=True).first()
if admin_user:
admin_user.set_password('admin')
admin_user.save()
print(f'Admin-Passwort für \"{admin_user.username}\" wurde auf \"admin\" gesetzt')
else:
User.objects.create_superuser('admin', 'admin@example.com', 'admin')
print('Neuer Admin-Benutzer \"admin\" wurde erstellt')
" 2>/dev/null
log_success "Admin-Benutzer konfiguriert"
}
# Sammle Static Files
collect_static_files() {
log_info "Sammle Static Files..."
if docker-compose exec -T web python manage.py collectstatic --noinput >/dev/null 2>&1; then
log_success "Static Files gesammelt"
else
log_warning "Fehler beim Sammeln der Static Files"
fi
}
# Migration Zusammenfassung
show_migration_summary() {
echo ""
echo -e "${GREEN}╔══════════════════════════════════════════════════════════════╗"
echo -e "║ Migration erfolgreich! ║"
echo -e "╚══════════════════════════════════════════════════════════════╝${NC}"
echo ""
log_success "Die Live-Daten wurden erfolgreich in den aktuellen Entwicklungsstand migriert"
echo ""
echo -e "${BLUE}📋 Systemzugriff:${NC}"
echo " 🌐 Anwendung: http://localhost:8008"
echo " 🔧 Admin-Panel: http://localhost:8008/admin"
echo ""
echo -e "${BLUE}👤 Admin-Login:${NC}"
echo " Benutzername: admin"
echo " Passwort: admin"
echo ""
echo -e "${BLUE}📝 Nützliche Befehle:${NC}"
echo " docker-compose logs -f web # Logs anzeigen"
echo " docker-compose down # Projekt stoppen"
echo " docker-compose up -d # Projekt starten"
echo ""
if [ -f ".last_backup_file" ]; then
local backup_file=$(cat .last_backup_file)
echo -e "${YELLOW}💾 Backup der vorherigen Datenbank: $backup_file${NC}"
echo ""
fi
}
# Fehlerbehandlung für Rollback
rollback_migration() {
local backup_file="$1"
if [ -f ".last_backup_file" ]; then
local last_backup=$(cat .last_backup_file)
log_warning "Stelle vorherige Datenbank wieder her..."
docker-compose stop web 2>/dev/null || true
docker-compose exec -T db psql -U fbf -d postgres -c "DROP DATABASE IF EXISTS db_fbf;" 2>/dev/null || true
docker-compose exec -T db psql -U fbf -d postgres -c "CREATE DATABASE db_fbf;" 2>/dev/null
if [ -f "$last_backup" ]; then
docker cp "$last_backup" django_fbf_db_1:/tmp/restore.sql
docker-compose exec -T db psql -U fbf -d db_fbf -f /tmp/restore.sql >/dev/null 2>&1
docker-compose exec -T db rm /tmp/restore.sql 2>/dev/null || true
log_success "Vorherige Datenbank wiederhergestellt"
fi
rm .last_backup_file
fi
}
# Trap für Fehlerbehandlung
trap 'log_error "Migration fehlgeschlagen. Führe Rollback durch..."; rollback_migration' ERR
# Hauptfunktion
main() {
local backup_file="${1:-fbf-backup.sql}"
print_banner
check_prerequisites
validate_backup_file "$backup_file"
check_containers
backup_current_db
reset_database
import_live_data "$backup_file"
apply_django_migrations
verify_data_integrity
setup_admin_user
collect_static_files
show_migration_summary
# Bereinige temporäre Dateien
rm -f .last_backup_file /tmp/migration_status.txt
}
# Hilfe anzeigen
show_help() {
echo "Django FBF Live Data Migration Script"
echo ""
echo "Verwendung: $0 [OPTIONEN] [BACKUP-DATEI]"
echo ""
echo "OPTIONEN:"
echo " -h, --help Zeige diese Hilfe an"
echo ""
echo "BACKUP-DATEI:"
echo " Pfad zur fbf-backup.sql Datei (Standard: fbf-backup.sql)"
echo ""
echo "Beispiele:"
echo " $0 # Verwendet fbf-backup.sql"
echo " $0 /path/to/backup.sql # Verwendet spezifische Backup-Datei"
echo ""
}
# Kommandozeilen-Parameter verarbeiten
case "${1:-}" in
-h|--help)
show_help
exit 0
;;
*)
main "$@"
;;
esac