Files
TIP/restore_backup.ps1
T
2026-06-09 21:18:13 -03:00

264 lines
11 KiB
PowerShell

<#
.SYNOPSIS
Restaura un backup completo del sistema TIP desde un archivo ZIP.
.DESCRIPTION
Busca el backup más reciente (tip_backup_*.zip), extrae el contenido,
lee el manifiesto y restaura bases de datos, configuración, SSL y sesiones.
ADVERTENCIA: Sobrescribe datos existentes. Usar solo en recuperación.
#>
Write-Host "Esta seguro que desea iniciar un proceso de restauración de backup? Esto sobrescribirá datos actuales. S/N" -ForegroundColor Red
$confirmation = Read-Host
if ($confirmation -notmatch "^[Ss]") {
Write-Host "Restauración cancelada por el usuario." -ForegroundColor Yellow
exit 0
}
# ------------------------------------------------------------------
# 1. Localizar el backup más reciente
# ------------------------------------------------------------------
$backup_zip = Get-ChildItem -Path "." -Filter "tip_backup_*.zip" |
Sort-Object LastWriteTime -Descending |
Select-Object -First 1
if (-not $backup_zip) {
Write-Host "ERROR: No se encontró ningún backup con el patrón 'tip_backup_*.zip' en el directorio actual." -ForegroundColor Red
exit 1
}
Write-Host "Backup encontrado: $($backup_zip.Name)" -ForegroundColor Green
# ------------------------------------------------------------------
# 2. Extraer en carpeta temporal
# ------------------------------------------------------------------
$tempDir = "./temp_restore"
if (Test-Path $tempDir) {
Remove-Item -Recurse -Force $tempDir
}
Expand-Archive -Path $backup_zip.FullName -DestinationPath $tempDir -Force
# ------------------------------------------------------------------
# 3. Leer manifiesto
# ------------------------------------------------------------------
$jsonPath = Join-Path $tempDir "manifest.json"
if (-not (Test-Path $jsonPath)) {
Write-Host "ERROR: No se encontró manifest.json en el backup." -ForegroundColor Red
Remove-Item -Recurse -Force $tempDir
exit 1
}
$jsonContent = Get-Content -Path $jsonPath -Raw | ConvertFrom-Json
$createdAt = $jsonContent.created_at
$createdBy = $jsonContent.created_by
$components = $jsonContent.components
$warnings = $jsonContent.warnings
Write-Host "Backup generado el $createdAt por usuario ID: $createdBy" -ForegroundColor Cyan
# ------------------------------------------------------------------
# 4. Obtener credenciales de bases de datos desde docker-compose.yml
# ------------------------------------------------------------------
# Restaurar docker-compose.yml desde el backup si existe
$composeBackupPath = Join-Path $tempDir "config/docker-compose.yml"
if (Test-Path $composeBackupPath) {
Write-Host "Restaurando docker-compose.yml desde el backup..." -ForegroundColor Yellow
Copy-Item $composeBackupPath -Destination "./docker-compose.yml" -Force
}
if (-not (Test-Path "./docker-compose.yml")) {
Write-Host "ERROR: No se encuentra docker-compose.yml en el directorio actual." -ForegroundColor Red
Remove-Item -Recurse -Force $tempDir
exit 1
}
try {
$composeJson = docker-compose -f docker-compose.yml config --format json | ConvertFrom-Json
} catch {
Write-Host "ERROR: No se pudo obtener la configuración de docker-compose. Verifica que Docker Compose esté instalado." -ForegroundColor Red
Remove-Item -Recurse -Force $tempDir
exit 1
}
$FEEDER_PASS = $composeJson.services.database.environment.MYSQL_ROOT_PASSWORD
$USERS_PASS = $composeJson.services.database_users.environment.MYSQL_ROOT_PASSWORD
if (-not $FEEDER_PASS -or -not $USERS_PASS) {
Write-Host "ERROR: No se pudieron obtener las contraseñas de las bases de datos." -ForegroundColor Red
Remove-Item -Recurse -Force $tempDir
exit 1
}
Write-Host "Credenciales obtenidas correctamente." -ForegroundColor Green
# ------------------------------------------------------------------
# 5. Función auxiliar para buscar archivo SQL
# ------------------------------------------------------------------
function Get-BackupSqlFile {
param(
[string]$DatabaseName,
[string]$SearchDir
)
$pattern = "*${DatabaseName}*.sql"
$file = Get-ChildItem -Path $SearchDir -Filter $pattern -File -ErrorAction SilentlyContinue |
Select-Object -First 1
return $file
}
# ------------------------------------------------------------------
# 6. Procesar componentes del manifiesto
# ------------------------------------------------------------------
foreach ($comp in $components) {
Write-Host "`nProcesando componente: $comp" -ForegroundColor Yellow
# --- Bases de datos ---
if ($comp -like "database:*") {
$dbName = $comp.Split(':')[1]
switch ($dbName) {
"feeder" {
Write-Host " → Restaurando base de datos Feeder..."
docker compose up -d --build database --wait
if ($LASTEXITCODE -ne 0) {
Write-Host " ERROR: No se pudo levantar el contenedor de feeder_db." -ForegroundColor Red
continue
}
$sqlFile = Get-BackupSqlFile -DatabaseName "feeder" -SearchDir (Join-Path $tempDir "databases")
if ($sqlFile) {
Write-Host " Archivo de dump: $($sqlFile.Name)"
Get-Content $sqlFile.FullName | docker exec -i feeder_db mysql -uroot -p"$FEEDER_PASS" feeder
if ($LASTEXITCODE -eq 0) {
Write-Host " Base de datos feeder restaurada exitosamente." -ForegroundColor Green
} else {
Write-Host " ERROR al restaurar feeder." -ForegroundColor Red
}
} else {
Write-Host " ADVERTENCIA: No se encontró archivo .sql para feeder." -ForegroundColor Yellow
}
}
"users" {
Write-Host " → Restaurando base de datos Users..."
docker compose up -d --build database_users --wait
if ($LASTEXITCODE -ne 0) {
Write-Host " ERROR: No se pudo levantar el contenedor de users_db." -ForegroundColor Red
continue
}
$sqlFile = Get-BackupSqlFile -DatabaseName "users" -SearchDir (Join-Path $tempDir "databases")
if ($sqlFile) {
Write-Host " Archivo de dump: $($sqlFile.Name)"
Get-Content $sqlFile.FullName | docker exec -i users_db mysql -uroot -p"$USERS_PASS" users
if ($LASTEXITCODE -eq 0) {
Write-Host " Base de datos users restaurada exitosamente." -ForegroundColor Green
} else {
Write-Host " ERROR al restaurar users." -ForegroundColor Red
}
} else {
Write-Host " ADVERTENCIA: No se encontró archivo .sql para users." -ForegroundColor Yellow
}
}
default {
Write-Host " → Base de datos desconocida: $dbName" -ForegroundColor Yellow
}
}
}
# --- Archivos de configuración ---
elseif ($comp -like "config:*") {
$files = ($comp.Split(':')[1]) -split ','
Write-Host " → Archivos de configuración: $($files -join ', ')"
foreach ($file in $files) {
$source = Join-Path $tempDir "config/$file"
if (Test-Path $source) {
switch ($file) {
"nginx.conf" { $dest = "./nginx/nginx.conf" }
"docker-compose.yml" { $dest = "./docker-compose.yml" }
default { $dest = "./$file" }
}
Write-Host " - Copiando $file a $dest"
Copy-Item $source -Destination $dest -Force
} else {
Write-Host " - Archivo $file no encontrado en el backup, se omite." -ForegroundColor Yellow
}
}
}
# --- Certificados SSL ---
elseif ($comp -eq "ssl") {
Write-Host " → Restaurando certificados SSL..."
$sslSource = Join-Path $tempDir "ssl"
if (Test-Path $sslSource) {
$sslDest = "./nginx/ssl"
if (-not (Test-Path $sslDest)) {
New-Item -ItemType Directory -Path $sslDest -Force | Out-Null
}
# Copiar contenido del directorio
Get-ChildItem -Path $sslSource -File -Recurse | ForEach-Object {
$relativePath = $_.FullName.Substring($sslSource.Length + 1)
$destFile = Join-Path $sslDest $relativePath
$destDir = Split-Path $destFile -Parent
if (-not (Test-Path $destDir)) {
New-Item -ItemType Directory -Path $destDir -Force | Out-Null
}
Copy-Item $_.FullName -Destination $destFile -Force
}
Write-Host " Certificados SSL copiados a $sslDest" -ForegroundColor Green
} else {
Write-Host " ADVERTENCIA: No se encontraron archivos SSL en el backup." -ForegroundColor Yellow
}
}
# --- Sesiones de Telegram ---
elseif ($comp -eq "telegram_sessions") {
Write-Host " → Restaurando sesiones de Telegram..."
$sessionsSource = Join-Path $tempDir "telegram_sessions"
if (Test-Path $sessionsSource) {
$sessionsDest = "./app/telegram_sessions"
if (-not (Test-Path $sessionsDest)) {
New-Item -ItemType Directory -Path $sessionsDest -Force | Out-Null
}
Copy-Item -Path "$sessionsSource/*" -Destination $sessionsDest -Recurse -Force
Write-Host " Sesiones copiadas a $sessionsDest" -ForegroundColor Green
} else {
Write-Host " ADVERTENCIA: No se encontraron sesiones en el backup." -ForegroundColor Yellow
}
}
else {
Write-Host " → Componente no reconocido: $comp" -ForegroundColor Red
}
}
# ------------------------------------------------------------------
# 7. Mostrar advertencias del manifiesto
# ------------------------------------------------------------------
if ($warnings -and $warnings.Count -gt 0) {
Write-Host "`n⚠️ Advertencias durante la generación del backup:" -ForegroundColor Magenta
$warnings | ForEach-Object { Write-Host " - $_" }
}
# ------------------------------------------------------------------
# 8. Limpieza
# ------------------------------------------------------------------
Write-Host "`nEliminando archivos temporales..." -ForegroundColor Gray
Remove-Item -Recurse -Force $tempDir
Write-Host "`nRestauración completada, desea reiniciar los contenedores? S/N" -ForegroundColor Green
$answer = Read-Host
if ($answer -match "^[Ss]") {
Write-Host "Reiniciando contenedores..." -ForegroundColor Green
docker compose down
docker compose up -d --build
if ($LASTEXITCODE -eq 0) {
Write-Host "Contenedores reiniciados exitosamente." -ForegroundColor Green
} else {
Write-Host "ERROR al reiniciar los contenedores. Verifica los logs de Docker." -ForegroundColor Red
}
} else {
Write-Host "Recuerda reiniciar los contenedores para aplicar los cambios." -ForegroundColor Yellow
}
Write-Host "Proceso de restauración completado." -ForegroundColor Green