<# .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