#!/usr/bin/env ruby # frozen_string_literal: true # ========================================================== # adn/tools/cli/drones/dasuten_restaurar_diferencial_dasu-sql4.rb # ========================================================== # Dron: Restaurar backup DIFERENCIAL en dasu-sql4 # Flujo: RESTORE DATABASE ... WITH DIFFERENTIAL (sobre BD existente) # Entrada: Backup diferencial en F:\BACKUP\ # Salida: differential_restore_complete # ========================================================== require 'time' require 'json' require_relative 'lib/dasu_executor' DOWNLOAD_OUTPUT = '/tmp/dron_download_output.json' JSON_PATH = 'C:\temp\dron_restore_dif_output.json' BACKUP_DIR_WINDOWS = 'F:\\BACKUP' # Leer ruta del backup desde el output del download if File.exist?(DOWNLOAD_OUTPUT) output = JSON.parse(File.read(DOWNLOAD_OUTPUT)) backup_local = output['backup_local'] backup_name = output['backup_name'] || File.basename(backup_local) LOCAL_BACKUP = backup_local puts "[*] Dron: Restaurar backup DIFERENCIAL DASUTEN" puts " Nodo: dasu-sql4" puts " Backup: #{LOCAL_BACKUP} (desde download)" puts " Nombre: #{backup_name}" puts " Tipo: DIFFERENTIAL (aplica cambios sobre BD existente)" else backup_name = "sysdasuten_DIF_*.bak" LOCAL_BACKUP = "#{BACKUP_DIR_WINDOWS}\\#{backup_name}" puts "[*] Dron: Restaurar backup DIFERENCIAL DASUTEN (buscar más reciente)" puts " Nodo: dasu-sql4" puts " Backup: #{LOCAL_BACKUP} (búsqueda por patrón)" puts " Tipo: DIFFERENTIAL (aplica cambios sobre BD existente)" end # PowerShell script para restore diferencial ps_script = <<~PSCMD.strip $ErrorActionPreference = "Stop" $BACKUP_DIR = "F:\\BACKUP" $BACKUP_NAME = "#{backup_name}" $LOCAL_BACKUP = "$BACKUP_DIR\\$BACKUP_NAME" $JSON_PATH = "C:\\temp\\dron_restore_dif_output.json" $null = New-Item -ItemType Directory -Force -Path "C:\\temp" Write-Host "[1/3] Verificando backup diferencial específico..." Write-Host " Archivo esperado: $LOCAL_BACKUP" if (-not (Test-Path $LOCAL_BACKUP)) { Write-Host "[!] No se encontró backup en $LOCAL_BACKUP" Write-Host " Buscando backup diferencial más reciente como fallback..." $BACKUP_PATTERN = "sysdasuten_DIF_*.bak" $backupFile = Get-ChildItem "$BACKUP_DIR\\$BACKUP_PATTERN" | Sort-Object Name -Descending | Select-Object -First 1 if (-not $backupFile) { Write-Host "[!] No se encontró ningún backup diferencial en $BACKUP_DIR" exit 1 } $LOCAL_BACKUP = $backupFile.FullName Write-Host " Fallback: $LOCAL_BACKUP" } $backupFile = Get-Item $LOCAL_BACKUP Write-Host " Archivo: $LOCAL_BACKUP" Write-Host " Tamaño: $([math]::Round($backupFile.Length / 1MB, 2)) MB" $sqlcmd = "C:\\Program Files\\Microsoft SQL Server\\Client SDK\\ODBC\\170\\Tools\\Binn\\sqlcmd.exe" Write-Host "`n[2/3] Ejecutando RESTORE DATABASE ... WITH DIFFERENTIAL..." $start = Get-Date $restoreSql = @" RESTORE DATABASE sysdasuten FROM DISK = '$LOCAL_BACKUP' WITH NORECOVERY, REPLACE "@ Write-Host " SQL: $restoreSql" $restoreOutput = & $sqlcmd -S localhost -Q $restoreSql 2>&1 $exitoRestore = $LASTEXITCODE -eq 0 $duracionRestore = [math]::Round((New-TimeSpan -Start $start -End (Get-Date)).TotalSeconds, 2) if (-not $exitoRestore) { Write-Host "[!] Error en restore:" Write-Host $restoreOutput exit 1 } Write-Host "[+] Restore diferencial completado en $duracionRestore segundos" Write-Host "`n[3/3] Poniendo base de datos ONLINE..." $recoverySql = "RESTORE DATABASE sysdasuten WITH RECOVERY" $recoveryOutput = & $sqlcmd -S localhost -Q $recoverySql 2>&1 $exitoRecovery = $LASTEXITCODE -eq 0 $duracionRecovery = [math]::Round((New-TimeSpan -Start (Get-Date) -End (Get-Date)).TotalSeconds, 2) if ($exitoRecovery) { Write-Host "[+] Base de datos ONLINE" } else { Write-Host "[!] Error en recovery:" Write-Host $recoveryOutput exit 1 } $duracionTotal = [math]::Round($duracionRestore + $duracionRecovery, 2) $res = @{ paso = "differential_restore_complete" backup_ruta = $LOCAL_BACKUP backup_tipo = "differential" nodo = "dasu-sql4" duracion_total = $duracionTotal duracion_restore = $duracionRestore duracion_recovery = $duracionRecovery estado_integridad = "PENDING_CHECKDB" timestamp = (Get-Date -Format "o") siguiente_paso = "verificar_integridad" } Write-Host "`n✅ Restauración diferencial completada" Write-Host " Estado: BD ONLINE" Write-Host " Output: $($res | ConvertTo-Json -Compress)" $res | ConvertTo-Json | Out-File -FilePath $JSON_PATH -Encoding utf8 PSCMD puts "\n[1/2] Ejecutando restore diferencial en dasu-sql4..." DasuExecutor.execute_ps_on_dasu(ps_script, output_path: JSON_PATH) puts "\n[2/2] Leyendo output JSON..." resultado = DasuExecutor.read_json_from_dasu(JSON_PATH) puts " Output: #{resultado.to_json}" puts "\n✅ Restauración diferencial completada" puts " Backup: #{resultado['backup_ruta']}" puts " Estado: #{resultado['estado_integridad']}" puts " Duración total: #{resultado['duracion_total']}s" File.write('/tmp/dron_restore_dif_output.json', resultado.to_json) puts " JSON guardado en: /tmp/dron_restore_dif_output.json"