[A04.P005] Extraído módulo común DasuExecutor para eliminar código repetido
Problema: 6 drones repetían el mismo patrón de ejecución remota: - Base64 encoding de scripts PowerShell - SSH vía srv-dasu con sshpass - Lectura de JSON output desde dasu-sql4 - Verificación de archivos en fenix vía xp_cmdshell Solución: adn/tools/cli/drones/lib/dasu_executor.rb Funciones del módulo: - execute_ps_on_dasu(ps_script) → ejecuta PowerShell en dasu-sql4 - read_json_from_dasu(path) → lee JSON output - execute_ps_with_json_output(ps_script) → combina ambas - execute_ps_on_fenix(client, ps_script) → PowerShell en fenix - file_exists_on_fenix?(client, path) → verifica existencia - get_file_info_on_fenix(client, path) → info completa de archivo Drones refactorizados (líneas ahorradas): - dasuten_restaurar_dasu-sql4.rb: 200 → 95 líneas (-52%) - dasuten_restaurar_diferencial_dasu-sql4.rb: 207 → 100 líneas (-52%) - dasuten_download_drive-dasu-sql4.rb: 269 → 130 líneas (-52%) - dasuten_verificar-integridad_dasu-sql4.rb: 182 → 85 líneas (-53%) - dasuten_exportar_srvv-fenix.rb: usa módulo para verificación - dasuten_exportar_diferencial_srvv-fenix.rb: usa módulo para verificación Beneficio: Si se modifica el patrón SSH/PowerShell, se cambia en 1 solo lugar.
This commit is contained in:
@@ -12,18 +12,16 @@
|
||||
|
||||
require 'time'
|
||||
require 'json'
|
||||
require 'base64'
|
||||
require 'tempfile'
|
||||
require 'shellwords'
|
||||
require_relative 'lib/dasu_executor'
|
||||
|
||||
DOWNLOAD_OUTPUT = '/tmp/dron_download_output.json'
|
||||
BACKUP_DIR_WINDOWS = 'F:\\BACKUP'
|
||||
JSON_PATH = 'C:\temp\dron_restore_output.json'
|
||||
|
||||
# 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']
|
||||
# Convertir path Unix a Windows si es necesario
|
||||
backup_name = File.basename(backup_local)
|
||||
LOCAL_BACKUP = "#{BACKUP_DIR_WINDOWS}\\#{backup_name}"
|
||||
puts "[*] Dron: Restaurar backup DASUTEN"
|
||||
@@ -32,24 +30,18 @@ else
|
||||
puts "[*] Dron: Restaurar backup DASUTEN (buscar más reciente)"
|
||||
end
|
||||
|
||||
TARGET_IP = "192.168.1.11"
|
||||
TARGET_USER = "Administrador"
|
||||
TARGET_PASS = "UTNlarioja00DASU"
|
||||
|
||||
puts " Nodo: dasu-sql4"
|
||||
puts " Backup: #{LOCAL_BACKUP}"
|
||||
|
||||
# PowerShell script para restore (sin checkdb)
|
||||
ps_script = <<~'PSCMD'
|
||||
# PowerShell script para restore
|
||||
ps_script = <<~'PSCMD'.strip
|
||||
$ErrorActionPreference = "Stop"
|
||||
$BACKUP_DIR = "F:\BACKUP"
|
||||
$BACKUP_PATTERN = "sysdasuten_FULL_*.bak"
|
||||
$JSON_PATH = "C:\temp\dron_restore_output.json"
|
||||
|
||||
# Asegurar directorio temp
|
||||
$null = New-Item -ItemType Directory -Force -Path "C:\temp"
|
||||
|
||||
# Buscar el backup completo más reciente
|
||||
Write-Host "[0/1] Buscando backup completo más reciente..."
|
||||
$backupFile = Get-ChildItem "$BACKUP_DIR\$BACKUP_PATTERN" | Sort-Object LastWriteTime -Descending | Select-Object -First 1
|
||||
if (-not $backupFile) {
|
||||
@@ -63,10 +55,8 @@ ps_script = <<~'PSCMD'
|
||||
Write-Host "[1/1] Ejecutando RESTORE DATABASE..."
|
||||
$start = Get-Date
|
||||
|
||||
# Ruta completa a sqlcmd (SQL Server 2019)
|
||||
$sqlcmd = "C:\Program Files\Microsoft SQL Server\Client SDK\ODBC\170\Tools\Binn\sqlcmd.exe"
|
||||
|
||||
# Comando RESTORE
|
||||
$restoreSql = @"
|
||||
RESTORE DATABASE sysdasuten
|
||||
FROM DISK = '$LOCAL_BACKUP'
|
||||
@@ -77,7 +67,6 @@ ps_script = <<~'PSCMD'
|
||||
|
||||
Write-Host " SQL: $restoreSql"
|
||||
|
||||
# Ejecutar restore
|
||||
$restoreOutput = & $sqlcmd -S localhost -Q $restoreSql 2>&1
|
||||
$exitoRestore = $LASTEXITCODE -eq 0
|
||||
$duracionRestore = [math]::Round((New-TimeSpan -Start $start -End (Get-Date)).TotalSeconds, 2)
|
||||
@@ -90,14 +79,11 @@ ps_script = <<~'PSCMD'
|
||||
|
||||
Write-Host "[+] Restore completado en $duracionRestore segundos"
|
||||
|
||||
$duracionTotal = $duracionRestore
|
||||
|
||||
# Output JSON
|
||||
$res = @{
|
||||
paso = "restore_complete"
|
||||
backup_ruta = $LOCAL_BACKUP
|
||||
nodo = "dasu-sql4"
|
||||
duracion_total = $duracionTotal
|
||||
duracion_total = $duracionRestore
|
||||
duracion_restore = $duracionRestore
|
||||
estado_integridad = "PENDING_CHECKDB"
|
||||
timestamp = (Get-Date -Format "o")
|
||||
@@ -110,90 +96,18 @@ ps_script = <<~'PSCMD'
|
||||
$res | ConvertTo-Json | Out-File -FilePath $JSON_PATH -Encoding utf8
|
||||
PSCMD
|
||||
|
||||
# Codificar script en base64
|
||||
ps_encoded = Base64.strict_encode64(ps_script)
|
||||
puts "\n[1/2] Ejecutando restore en dasu-sql4..."
|
||||
DasuExecutor.execute_ps_on_dasu(ps_script, output_path: JSON_PATH)
|
||||
|
||||
# Script bash que se ejecuta en srv-dasu
|
||||
bash_script = <<~BASHHEREDOC
|
||||
#!/bin/bash
|
||||
export SSHPASS="#{TARGET_PASS}"
|
||||
sshpass -e ssh -o StrictHostKeyChecking=no -p 7022 #{TARGET_USER}@#{TARGET_IP} \
|
||||
"powershell -Command \\\"Invoke-Expression ([System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String('#{ps_encoded}')))\\\""
|
||||
BASHHEREDOC
|
||||
puts "\n[2/2] Leyendo output JSON..."
|
||||
resultado = DasuExecutor.read_json_from_dasu(JSON_PATH)
|
||||
|
||||
# Guardar script bash en archivo temporal
|
||||
bash_file = Tempfile.new(['restore', '.sh'])
|
||||
bash_file.write(bash_script)
|
||||
bash_file.chmod(0755)
|
||||
bash_file.close
|
||||
puts " Output: #{resultado.to_json}"
|
||||
|
||||
remote_bash_path = "/tmp/dron_restore_#{Time.now.to_i}.sh"
|
||||
puts "\n✅ Restauración completada"
|
||||
puts " Backup: #{resultado['backup_ruta']}"
|
||||
puts " Estado: #{resultado['estado_integridad']}"
|
||||
puts " Duración: #{resultado['duracion_total']}s"
|
||||
|
||||
puts "\n[1/3] Copiando script a srv-dasu..."
|
||||
scp_cmd = "scp -o StrictHostKeyChecking=no #{bash_file.path} srv-dasu:#{remote_bash_path}"
|
||||
unless system(scp_cmd)
|
||||
puts "[!] Error al copiar script"
|
||||
bash_file.unlink
|
||||
exit 1
|
||||
end
|
||||
|
||||
puts "\n[2/3] Ejecutando en dasu-sql4 vía srv-dasu..."
|
||||
ssh_cmd = "ssh srv-dasu 'bash #{remote_bash_path}'"
|
||||
output = `#{ssh_cmd}`
|
||||
output = output.encode('UTF-8', invalid: :replace, undef: :replace, replace: '?') if output
|
||||
puts output
|
||||
|
||||
# Limpieza
|
||||
bash_file.unlink
|
||||
system("ssh srv-dasu 'rm -f #{remote_bash_path}' 2>/dev/null")
|
||||
|
||||
if $?.success?
|
||||
puts "\n[3/3] Leyendo output JSON..."
|
||||
|
||||
json_ps = 'Get-Content C:\temp\dron_restore_output.json -Raw'
|
||||
json_encoded = Base64.strict_encode64(json_ps)
|
||||
|
||||
json_script = <<~JSONBASH.strip
|
||||
#!/bin/bash
|
||||
export SSHPASS="#{TARGET_PASS}"
|
||||
sshpass -e ssh -o StrictHostKeyChecking=no -p 7022 #{TARGET_USER}@#{TARGET_IP} \
|
||||
"powershell -Command \\\"Invoke-Expression ([System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String('#{json_encoded}')))\\\""
|
||||
JSONBASH
|
||||
|
||||
json_file = Tempfile.new(['json', '.sh'])
|
||||
json_file.write(json_script)
|
||||
json_file.chmod(0755)
|
||||
json_file.close
|
||||
|
||||
remote_json_path = "/tmp/dron_json_#{Time.now.to_i}.sh"
|
||||
system("scp -o StrictHostKeyChecking=no #{json_file.path} srv-dasu:#{remote_json_path}")
|
||||
|
||||
json_cmd = "ssh srv-dasu 'bash #{remote_json_path}'"
|
||||
resultado_json = `#{json_cmd}`.strip
|
||||
resultado_json = resultado_json.encode('UTF-8', invalid: :replace, undef: :replace, replace: '?') if resultado_json
|
||||
|
||||
json_file.unlink
|
||||
system("ssh srv-dasu 'rm -f #{remote_json_path}' 2>/dev/null")
|
||||
|
||||
if resultado_json.empty?
|
||||
puts "[!] No se pudo leer output JSON"
|
||||
exit 1
|
||||
end
|
||||
|
||||
json_match = resultado_json.match(/\{.*\}/m)
|
||||
resultado_json = json_match ? json_match[0] : resultado_json
|
||||
|
||||
puts " Output: #{resultado_json}"
|
||||
resultado = JSON.parse(resultado_json)
|
||||
|
||||
puts "\n✅ Restauración completada"
|
||||
puts " Backup: #{resultado['backup_ruta']}"
|
||||
puts " Estado: #{resultado['estado_integridad']}"
|
||||
puts " Duración: #{resultado['duracion_total']}s"
|
||||
|
||||
File.write('/tmp/dron_restore_output.json', resultado_json)
|
||||
puts " JSON guardado en: /tmp/dron_restore_output.json"
|
||||
else
|
||||
puts "[!] Error en ejecución (código: #{$?.exitstatus})"
|
||||
exit 1
|
||||
end
|
||||
File.write('/tmp/dron_restore_output.json', resultado.to_json)
|
||||
puts " JSON guardado en: /tmp/dron_restore_output.json"
|
||||
|
||||
Reference in New Issue
Block a user