#!/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 E:\BK_SQL\ # Salida: Marca evento como 'export_complete' con ruta del backup # ========================================================== require 'tiny_tds' require 'time' require 'json' # Nombre del archivo con timestamp TIMESTAMP = Time.now.strftime('%Y%m%d_%H%M%S') BACKUP_DIR = "E:\\BK_SQL\\sysdasuten" BACKUP_FILE = "#{BACKUP_DIR}\\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)" puts " Directorio: #{BACKUP_DIR}" begin # Autorizar candados primero (necesario para acceder a la bóveda) system("ruby adn/tools/candados/candados.rb authorize >/dev/null 2>&1") # Obtener credencial de candados (patrón usado en otros drones) 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 (utnlarioja.intranet:monlaricardo)" 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)" # Crear directorio si no existe puts "\n[0/3] Verificando directorio..." mkdir_sql = "EXEC master.sys.xp_create_subdir '#{BACKUP_DIR}'" client.execute(mkdir_sql) puts "[+] Directorio asegurado: #{BACKUP_DIR}" # Generar backup diferencial puts "\n[1/2] Generando backup diferencial..." 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" # Obtener tamaño del archivo (vía PowerShell remoto o xp_fileexist) puts "\n[2/2] Verificando archivo..." begin file_result = client.execute("EXEC master.sys.xp_fileexist '#{BACKUP_FILE}'") file_info = file_result.first if file_info && file_result.to_a.any? { |f| f['File Exists'] == 1 } puts "[+] Archivo verificado: #{BACKUP_FILE}" # Obtener tamaño aproximado 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" else puts "[!] Advertencia: No se pudo verificar existencia del archivo" end rescue => e puts "[!] Advertencia: #{e.message}" end # Output para orquestador output = { paso: 'export_differential_complete', backup_ruta: BACKUP_FILE, backup_tipo: 'differential', nodo: 'srvv-fenix', duracion: duracion, timestamp: Time.now.iso8601, siguiente_paso: 'transferir' } puts "\n✅ Export diferencial completado" puts " Output: #{output.to_json}" # Escribir output para que el orquestador lo lea File.write('/tmp/dron_export_dif_output.json', output.to_json) rescue => e puts "[!] Error fatal: #{e.message}" puts e.backtrace.first(5).join("\n") exit 1 end