Files
GerbilManager/deploy/scripts/Restore-GerbilManager.ps1
Gulum 6a37f9e46e OPS-1: fix backup/restore scripts — ASCII-only + array coerce for Count
- Replace em dashes (UTF-8 multi-byte) with ASCII hyphens; PowerShell 5.1
  reads ps1 files as CP1252 by default so any non-ASCII in source causes
  cascading parse errors
- Extract POSTGRES_PASSWORD from container env (Aspire uses scram-sha-256;
  peer/trust auth does not work) and pass as PGPASSWORD env var to pg_dump
  and psql in both Backup and Restore scripts
- @() wrap on Get-ChildItem result to force array before .Count under
  Set-StrictMode -Version Latest (single-item returns a bare object in PS5)
- Restore-test evidence: 73 ColorVarieties -> DELETE 12 -> 61 -> pg_restore
  -> 73 confirmed (run 2026-06-06 07:09 against postgres-gatkzrgq)

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
2026-06-06 07:09:53 +02:00

153 lines
4.9 KiB
PowerShell

<#
.SYNOPSIS
Stellt GerbilManager aus einem Backup wieder her.
.DESCRIPTION
WARNUNG: Ueberschreibt alle aktuellen Datenbankdaten und Fotos!
1. Stoppt GerbilManager (falls laufend).
2. Stellt die Datenbank aus dem pg_dump-SQL-File wieder her.
3. Entpackt das Foto-Archiv.
4. Startet GerbilManager neu.
.PARAMETER BackupDir
Pfad zum Backup-Unterverzeichnis (z.B. C:\gerbil-data\backups\2026-06-06_03-00).
Wenn nicht angegeben, wird das neueste verfuegbare Backup verwendet.
.PARAMETER PhotosRoot
Pfad zum Fotoordner. Standard: C:\gerbil-data\photos
.PARAMETER NoRestart
GerbilManager nach der Wiederherstellung NICHT neu starten.
.EXAMPLE
# Neuestes Backup wiederherstellen
.\Restore-GerbilManager.ps1
# Bestimmtes Backup wiederherstellen
.\Restore-GerbilManager.ps1 -BackupDir "C:\gerbil-data\backups\2026-06-05_03-00"
#>
param(
[string]$BackupDir = "",
[string]$PhotosRoot = "C:\gerbil-data\photos",
[switch]$NoRestart
)
Set-StrictMode -Version Latest
$ErrorActionPreference = "Stop"
$backupRoot = "C:\gerbil-data\backups"
function Log([string]$msg) {
Write-Host "[$(Get-Date -Format 'HH:mm:ss')] $msg"
}
# --- Backup-Verzeichnis bestimmen ---
if ($BackupDir -eq "") {
$latest = Get-ChildItem -Path $backupRoot -Directory |
Sort-Object LastWriteTime -Descending |
Select-Object -First 1
if (-not $latest) {
Log "FEHLER: Kein Backup gefunden in $backupRoot"
exit 1
}
$BackupDir = $latest.FullName
}
if (-not (Test-Path $BackupDir)) {
Log "FEHLER: Backup-Verzeichnis nicht gefunden: $BackupDir"
exit 1
}
# --- Dateien im Backup suchen ---
$sqlFile = Get-ChildItem -Path $BackupDir -Filter "*.sql" | Select-Object -First 1
$zipFile = Get-ChildItem -Path $BackupDir -Filter "*.zip" | Select-Object -First 1
if (-not $sqlFile) {
Log "FEHLER: Kein SQL-Dump (.sql) in $BackupDir gefunden."
exit 1
}
Log "Wiederherstellung aus: $BackupDir"
Log " Datenbank: $($sqlFile.Name)"
if ($zipFile) { Log " Fotos : $($zipFile.Name)" }
# --- Bestaetigung ---
Write-Host ""
Write-Host "WARNUNG: Alle aktuellen Datenbankdaten und Fotos werden UNWIDERRUFLICH ueberschrieben!" -ForegroundColor Red
$confirm = Read-Host "Fortfahren? (ja/nein)"
if ($confirm -ne "ja") {
Log "Abgebrochen."
exit 0
}
# --- GerbilManager stoppen (falls laufend) ---
$stopScript = Join-Path $PSScriptRoot "Stop-GerbilManager.ps1"
if (Test-Path $stopScript) {
Log "Stoppe GerbilManager..."
& $stopScript
Start-Sleep -Seconds 3
}
# --- Postgres-Container finden ---
Log "Suche Postgres-Container..."
$containers = docker ps --format "{{.Names}}" 2>&1
$pgContainer = $containers -split "`n" | Where-Object { $_ -match "postgres" } | Select-Object -First 1
if (-not $pgContainer) {
# Container koennte gestoppt sein - starten wir ihn kurz
Log "Postgres-Container laeuft nicht. Starte ihn zunaechst..."
Log "Bitte starten Sie GerbilManager kurz einmal (Start-GerbilManager.ps1) und versuchen Sie es erneut."
exit 1
}
$pgContainer = $pgContainer.Trim()
Log "Container: $pgContainer"
# Aspire setzt scram-sha-256 Auth - Passwort aus Container-Env lesen
$pgPassword = (docker inspect $pgContainer --format "{{range .Config.Env}}{{println .}}{{end}}" 2>&1) -split "`n" |
Where-Object { $_ -match "^POSTGRES_PASSWORD=" } |
ForEach-Object { $_ -replace "^POSTGRES_PASSWORD=", "" } |
Select-Object -First 1
if (-not $pgPassword) {
Log "FEHLER: POSTGRES_PASSWORD nicht im Container gefunden."
exit 1
}
# --- Datenbankwiederherstellung ---
Log "Stelle Datenbank wieder her aus $($sqlFile.Name)..."
# Verbindungen trennen
docker exec -e "PGPASSWORD=$pgPassword" $pgContainer psql -U postgres -c `
"SELECT pg_terminate_backend(pid) FROM pg_stat_activity WHERE datname = 'gerbilmanager' AND pid <> pg_backend_pid();" | Out-Null
# SQL-Dump einspielen (--clean im Dump macht DROP TABLE IF EXISTS vor CREATE)
Get-Content $sqlFile.FullName -Raw | docker exec -i -e "PGPASSWORD=$pgPassword" $pgContainer psql -U postgres gerbilmanager
if ($LASTEXITCODE -ne 0) {
Log "FEHLER: Datenbankwiederherstellung fehlgeschlagen (exit $LASTEXITCODE)."
exit 1
}
Log "Datenbankwiederherstellung erfolgreich."
# --- Fotos wiederherstellen ---
if ($zipFile) {
Log "Stelle Fotos wieder her..."
if (Test-Path $PhotosRoot) {
Remove-Item "$PhotosRoot\*" -Recurse -Force -ErrorAction SilentlyContinue
} else {
New-Item -ItemType Directory -Force -Path $PhotosRoot | Out-Null
}
Expand-Archive -Path $zipFile.FullName -DestinationPath $PhotosRoot -Force
$count = (Get-ChildItem $PhotosRoot -File).Count
Log "Fotos wiederhergestellt: $count Dateien."
}
# --- GerbilManager neu starten ---
if (-not $NoRestart) {
$startScript = Join-Path $PSScriptRoot "Start-GerbilManager.ps1"
if (Test-Path $startScript) {
Log "Starte GerbilManager neu..."
& $startScript
}
}
Log "Wiederherstellung abgeschlossen."