[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:
Ricardo Monla
2026-04-14 19:59:20 -03:00
parent 5739ecf689
commit 3b73e0b053
7 changed files with 461 additions and 290 deletions
@@ -5,19 +5,18 @@
# adn/tools/cli/drones/dasuten_exportar_srvv-fenix.rb
# ==========================================================
# Dron: Exportar backup en srvv-fenix
# Flujo: srvv-fenix → Backup comprimido en E:\BK_SQL\
# Salida: Marca evento como 'export_complete' con ruta del backup
# Flujo: srvv-fenix → Backup comprimido en X:\ (share srv-ns8)
# Salida: export_complete con ruta del backup
# ==========================================================
require 'tiny_tds'
require 'time'
require 'json'
require_relative 'lib/dasu_executor'
# Nombre del archivo con timestamp
TIMESTAMP = Time.now.strftime('%Y%m%d_%H%M%S')
BACKUP_FILE = "sysdasuten_FULL_#{TIMESTAMP}.bak"
# Unidad de red mapeada en srvv-fenix (share de srv-ns8) - UNICO DESTINO
BACKUP_NS8 = "X:\\#{BACKUP_FILE}"
puts "[*] Dron: Exportar backup COMPLETO DASUTEN"
@@ -26,10 +25,10 @@ puts " Destino: #{BACKUP_NS8}"
puts " Tipo: FULL (completo)"
begin
# Autorizar candados primero (necesario para acceder a la bóveda)
# Autorizar candados primero
system("ruby adn/tools/candados/candados.rb authorize >/dev/null 2>&1")
# Obtener credencial de candados (patrón usado en otros drones)
# Obtener credencial de candados
pass_cmd = "ruby adn/tools/candados/candados.rb get utnlarioja.intranet:monlaricardo 2>/dev/null"
sql_pass = `#{pass_cmd}`.strip
@@ -37,7 +36,7 @@ begin
sql_host = '10.0.10.200'
if sql_pass.empty?
puts "[!] Error: No se pudo obtener credencial de candados (utnlarioja.intranet:monlaricardo)"
puts "[!] Error: No se pudo obtener credencial de candados"
exit 1
end
@@ -51,8 +50,7 @@ begin
# Crear directorio en share si no existe
puts "\n[0/2] Verificando directorio en share..."
mkdir_sql = "EXEC master.sys.xp_create_subdir 'X:\\'"
client.execute(mkdir_sql)
client.execute("EXEC master.sys.xp_create_subdir 'X:\\'")
puts "[+] Directorio share asegurado: X:\\"
# Generar backup comprimido directamente en share X:
@@ -65,21 +63,14 @@ begin
duracion = (Time.now - start).round(2)
puts "[+] Backup generado en #{duracion} segundos"
# Verificar archivo en share
# Verificar archivo en share usando módulo común
puts "[2/2] Verificando archivo en share..."
begin
verify_ps = <<~PSCMD.strip
if (Test-Path "#{BACKUP_NS8}") {
$size = (Get-Item "#{BACKUP_NS8}").Length
Write-Host "Verificado: #{BACKUP_NS8} ($([math]::Round($size/1MB, 2)) MB)"
} else {
Write-Host "ERROR: No existe #{BACKUP_NS8}"
exit 1
}
PSCMD
client.execute("EXEC xp_cmdshell 'powershell -Command \"#{verify_ps.gsub('"', '\"')}\"'")
rescue => e
puts "[!] Error al verificar en X: - #{e.message}"
file_info = DasuExecutor.get_file_info_on_fenix(client, BACKUP_NS8)
if file_info[:exists]
puts "[+] Archivo verificado: #{BACKUP_NS8} (#{file_info[:size_mb]} MB)"
else
puts "[!] Error: No existe el archivo en #{BACKUP_NS8}"
exit 1
end
@@ -101,7 +92,6 @@ begin
puts "\n✅ Export completado en share"
puts " Output: #{output.to_json}"
# Escribir output para que el orquestador lo lea
File.write('/tmp/dron_export_output.json', output.to_json)
rescue => e