[A04.P006] Drones de exportación actualizados con formato estandarizado
Cambios realizados:
1. dasuten_exportar_srvv-fenix.rb (FULL):
- Nuevo formato: E:\BK_SQL\sysdasuten\sysdasuten_FULL_YYYYMMDD_HHMMSS.bak
- Crea directorio con xp_create_subdir si no existe
- Usa compresión nativa de SQL Server (WITH COMPRESSION)
- Output: backup_tipo='full'
2. dasuten_exportar_diferencial_srvv-fenix.rb (DIF):
- Nuevo formato: E:\BK_SQL\sysdasuten\sysdasuten_DIF_YYYYMMDD_HHMMSS.bak
- Crea directorio si no existe
- Usa compresión nativa (WITH DIFFERENTIAL, COMPRESSION)
- Output: backup_tipo='differential'
3. dasuten_download_drive-dasu-sql4.rb:
- Lee nombre de archivo desde upload_output JSON
- Guarda como F:\BACKUP\{nombre_real_del_archivo}.bak
- Soporta formatos FULL y DIF
4. dasuten_restaurar_dasu-sql4.rb:
- Lee backup_local desde download_output JSON
- Busca patrón sysdasuten_FULL_*.bak si no hay output
- Encuentra el más reciente por LastWriteTime
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.6
parent
358cee8e9a
commit
0f9ebe9ef5
@@ -0,0 +1,116 @@
|
||||
#!/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
|
||||
Reference in New Issue
Block a user