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.
111 lines
3.3 KiB
Ruby
111 lines
3.3 KiB
Ruby
#!/usr/bin/env ruby
|
|
# frozen_string_literal: true
|
|
|
|
# ==========================================================
|
|
# adn/tools/cli/drones/dasuten_exportar_diferencial_srvv-fenix.rb
|
|
# ==========================================================
|
|
# Dron: Exportar backup DIFERENCIAL de DASUTEN en srvv-fenix
|
|
# Flujo: srvv-fenix → Backup diferencial en X:\ (share srv-ns8)
|
|
# Salida: export_differential_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 = "X:\\sysdasuten_DIF_#{TIMESTAMP}.bak"
|
|
|
|
puts "[*] Dron: Exportar backup DIFERENCIAL DASUTEN"
|
|
puts " Nodo: srvv-fenix"
|
|
puts " Destino: #{BACKUP_FILE}"
|
|
puts " Tipo: DIFFERENTIAL (solo cambios desde último backup completo)"
|
|
|
|
begin
|
|
# Autorizar candados primero
|
|
system("ruby adn/tools/candados/candados.rb authorize >/dev/null 2>&1")
|
|
|
|
# Obtener credencial de candados
|
|
pass_cmd = "ruby adn/tools/candados/candados.rb get utnlarioja.intranet:monlaricardo 2>/dev/null"
|
|
sql_pass = `#{pass_cmd}`.strip
|
|
|
|
sql_user = 'UTNlarioja\\monlaricardo'
|
|
sql_host = '10.0.10.200'
|
|
|
|
if sql_pass.empty?
|
|
puts "[!] Error: No se pudo obtener credencial de candados"
|
|
exit 1
|
|
end
|
|
|
|
client = TinyTds::Client.new(
|
|
username: sql_user,
|
|
password: sql_pass,
|
|
host: sql_host,
|
|
timeout: 600
|
|
)
|
|
puts "[+] Conectado a SQL Server en #{sql_host} (auth: Windows)"
|
|
|
|
# Generar backup diferencial directamente en share X:
|
|
puts "\n[0/2] Generando backup diferencial en share X:..."
|
|
start = Time.now
|
|
|
|
sql = <<~SQL.strip
|
|
BACKUP DATABASE sysdasuten
|
|
TO DISK = '#{BACKUP_FILE}'
|
|
WITH DIFFERENTIAL, COMPRESSION, STATS=10
|
|
SQL
|
|
|
|
puts " SQL: #{sql}"
|
|
|
|
result = client.execute(sql)
|
|
result.each { |r| puts " #{r['message']}" if r['message'] }
|
|
|
|
duracion = (Time.now - start).round(2)
|
|
puts "[+] Backup diferencial generado en #{duracion} segundos"
|
|
|
|
# Verificar archivo en share usando módulo común
|
|
puts "\n[1/2] Verificando archivo en share..."
|
|
file_info = DasuExecutor.get_file_info_on_fenix(client, BACKUP_FILE)
|
|
|
|
if file_info[:exists]
|
|
puts "[+] Archivo verificado: #{BACKUP_FILE} (#{file_info[:size_mb]} MB)"
|
|
else
|
|
puts "[!] Error: No existe el archivo en #{BACKUP_FILE}"
|
|
exit 1
|
|
end
|
|
|
|
# Tamaño aproximado de la BD base
|
|
puts "\n[2/2] Información de tamaño..."
|
|
begin
|
|
size_info = client.execute("SELECT size_bytes = (SELECT size * 8192 FROM sys.database_files WHERE name = 'sysdasuten')")
|
|
puts " Tamaño BD base: #{size_info.to_a.first['size_bytes'].to_i / 1024 / 1024} MB"
|
|
rescue => e
|
|
puts "[!] No se pudo obtener tamaño: #{e.message}"
|
|
end
|
|
|
|
# Output para orquestador
|
|
output = {
|
|
paso: 'export_differential_complete',
|
|
backup_ruta: BACKUP_FILE,
|
|
backup_ruta_unix: BACKUP_FILE.gsub('X:\\', '/mnt/ns8Disco2/bkps-dasuten/'),
|
|
backup_tipo: 'differential',
|
|
nodo: 'srvv-fenix',
|
|
nodo_destino: 'srv-ns8',
|
|
duracion: duracion,
|
|
timestamp: Time.now.iso8601,
|
|
siguiente_paso: 'upload_drive'
|
|
}
|
|
|
|
puts "\n✅ Export diferencial completado"
|
|
puts " Output: #{output.to_json}"
|
|
|
|
File.write('/tmp/dron_export_output.json', output.to_json)
|
|
|
|
rescue => e
|
|
puts "[!] Error fatal: #{e.message}"
|
|
puts e.backtrace.first(5).join("\n")
|
|
exit 1
|
|
end
|