Files
dtic-DIIAA/adn/tools/cli/drones/dasuten_download_drive-dasu-sql4.rb
T
Ricardo MonlaandClaude Opus 4.6 0f9ebe9ef5 [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>
2026-04-14 17:48:05 -03:00

269 lines
9.4 KiB
Ruby
Executable File

#!/usr/bin/env ruby
# frozen_string_literal: true
# ==========================================================
# adn/tools/cli/drones/dasuten_download_drive-dasu-sql4.rb
# ==========================================================
# Dron: Download desde Google Drive a dasu-sql4
# Flujo: Google Drive → F:\BACKUP\sysdasuten_compressed_ADN.bak
# Usa: Invoke-WebRequest (sin rclone)
# ==========================================================
require 'time'
require 'json'
require 'shellwords'
require 'optparse'
require 'base64'
require 'tempfile'
opciones = {
test_file: nil,
file_id: nil # Google Drive file ID
}
OptionParser.new do |opts|
opts.banner = "Uso: dron lanzar --nota 'Download' --nodo dasu-sql4 -- ruby dasuten_download_drive.rb [opciones]"
opts.on("--test-file ARCHIVO", "Archivo específico para test (ej: test_Backup.bak)") { |f| opciones[:test_file] = f }
opts.on("--file-id ID", "Google Drive file ID") { |id| opciones[:file_id] = id }
end.parse!(ARGV)
BACKUP_DIR_WINDOWS = "F:\\BACKUP"
BACKUP_NAME_DEFAULT = "sysdasuten_compressed_ADN.bak"
TARGET_IP = "192.168.1.11"
TARGET_USER = "Administrador"
TARGET_PASS = "UTNlarioja00DASU"
# Determinar nombre del archivo backup
LOCAL_BACKUP = "#{BACKUP_DIR_WINDOWS}\\#{BACKUP_NAME_DEFAULT}"
puts "[*] Dron: Download desde Google Drive"
puts " Nodo: dasu-sql4"
# Determinar archivo a descargar
if opciones[:test_file]
puts " 🧪 MODO TEST: Descargando archivo específico"
# File ID conocido para test_Backup.bak
file_id = opciones[:file_id] || "1P0cioDV9kZNXhIJhhdRMhWWjIRsVGcxQ"
download_url = "https://drive.google.com/uc?export=download&id=#{file_id}"
puts " File ID: #{file_id}"
puts " Destino: #{LOCAL_BACKUP}"
elsif opciones[:file_id]
puts " Download por file ID"
download_url = "https://drive.google.com/uc?export=download&id=#{opciones[:file_id]}"
puts " File ID: #{opciones[:file_id]}"
puts " Destino: #{LOCAL_BACKUP}"
else
# Intentar leer file_id desde el output del upload
UPLOAD_OUTPUT = '/tmp/dron_upload_output.json'
if File.exist?(UPLOAD_OUTPUT)
upload_data = JSON.parse(File.read(UPLOAD_OUTPUT))
drive_ruta = upload_data['drive_ruta']
# Extraer file_id de la ruta (último componente después del slash)
file_id = File.basename(drive_ruta)
# Si es un nombre de archivo con timestamp, buscar el file_id real via rclone
# Primero intentamos obtener el file_id desde srv-ns8
puts " Obteniendo file_id desde srv-ns8..."
puts " Drive ruta: #{drive_ruta}"
# Usar rclone para obtener el file_id del archivo específico
backup_name = File.basename(drive_ruta)
drive_folder = drive_ruta.rpartition('/').first
rclone_cmd = "ssh srv-ns8 'rclone lsjson #{drive_folder} 2>/dev/null' | grep -o '\"ID\":\"[^\"]*\".*\"Name\":\"#{backup_name}\"' | head -1 | grep -o '\"ID\":\"[^\"]*\"' | cut -d'\"' -f4"
file_id_result = `#{rclone_cmd}`.strip
if file_id_result && !file_id_result.empty?
file_id = file_id_result
puts " File ID obtenido: #{file_id}"
else
puts " [!] No se pudo obtener file_id, usando nombre de archivo"
file_id = File.basename(drive_ruta)
end
download_url = "https://drive.google.com/uc?export=download&id=#{file_id}"
backup_name = file_id # Usar el nombre del archivo desde drive_ruta
puts " Download URL: #{download_url}"
puts " Backup nombre: #{backup_name}"
puts " Destino: #{BACKUP_DIR_WINDOWS}\\#{backup_name}"
else
puts " [!] Error: Se requiere --test-file o --file-id"
puts " Para produccion: obtener file_id con rclone lsjson desde srv-ns8"
exit 1
end
end
# PowerShell script para download
# Para archivos grandes, Google Drive muestra página de confirmación de virus.
# Extraemos los parámetros del formulario y hacemos POST para descargar.
ps_script = <<~'PSCMD'
$ErrorActionPreference = "Stop"
$BACKUP_DIR = "F:\BACKUP"
$DOWNLOAD_URL = "DOWNLOAD_URL_PLACEHOLDER"
$BACKUP_NAME = "BACKUP_NAME_PLACEHOLDER"
$LOCAL_BACKUP = "$BACKUP_DIR\$BACKUP_NAME"
$JSON_PATH = "C:\temp\dron_download_output.json"
# Asegurar directorios
$null = New-Item -ItemType Directory -Force -Path "C:\temp"
$null = New-Item -ItemType Directory -Force -Path $BACKUP_DIR
Write-Host "[1/3] Iniciando descarga..."
Write-Host " URL: $DOWNLOAD_URL"
Write-Host "[2/3] Descargando..."
$start = Get-Date
try {
# Paso 1: Obtener página de confirmación
$response = Invoke-WebRequest -Uri $DOWNLOAD_URL -UseBasicParsing -Headers @{
"User-Agent" = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"
}
# Extraer parámetros del formulario de confirmación
$html = $response.Content
$fileId = ""
$uuid = ""
$confirm = "t"
if ($html -match 'name="id" value="([^"]+)"') { $fileId = $matches[1] }
if ($html -match 'name="uuid" value="([^"]+)"') { $uuid = $matches[1] }
if ($html -match 'name="confirm" value="([^"]+)"') { $confirm = $matches[1] }
Write-Host " File ID: $fileId"
Write-Host " UUID: $uuid"
# Paso 2: Construir URL de descarga con confirmación
$downloadConfirmUrl = "https://drive.usercontent.google.com/download?id=$fileId&export=download&confirm=$confirm&uuid=$uuid"
Write-Host " URL confirmada: $downloadConfirmUrl"
# Paso 3: Descargar archivo real
$finalResponse = Invoke-WebRequest -Uri $downloadConfirmUrl -UseBasicParsing -Headers @{
"User-Agent" = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"
}
# Guardar contenido
[System.IO.File]::WriteAllBytes($LOCAL_BACKUP, $finalResponse.Content)
$dur = (New-TimeSpan -Start $start -End (Get-Date)).TotalSeconds
Write-Host "[+] Descarga en $([math]::Round($dur, 2))s"
} catch {
Write-Host "[!] Error: $_"
exit 1
}
Write-Host "[3/3] Verificando..."
if (Test-Path $LOCAL_BACKUP) {
$tam = (Get-Item $LOCAL_BACKUP).Length
Write-Host " Tamano: $([math]::Round($tam / 1MB, 2)) MB"
if ($tam -eq 0) {
Write-Host "[!] Archivo vacío"
exit 1
}
} else {
Write-Host "[!] No existe"
exit 1
}
$res = @{
paso = "download_complete"
backup_local = $LOCAL_BACKUP
drive_origen = "Google Drive"
nodo = "dasu-sql4"
duracion = [math]::Round($dur, 2)
timestamp = (Get-Date -Format "o")
siguiente_paso = "restaurar_backup"
}
$res | ConvertTo-Json | Out-File -FilePath $JSON_PATH -Encoding utf8
Write-Host " Output: $($res | ConvertTo-Json -Compress)"
PSCMD
# Reemplazar placeholders con valores reales
ps_script = ps_script.gsub('DOWNLOAD_URL_PLACEHOLDER', download_url)
ps_script = ps_script.gsub('BACKUP_NAME_PLACEHOLDER', backup_name)
# Codificar script en base64
ps_encoded = Base64.strict_encode64(ps_script)
# 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
# Guardar script bash en archivo temporal
bash_file = Tempfile.new(['download', '.sh'])
bash_file.write(bash_script)
bash_file.chmod(0755)
bash_file.close
remote_bash_path = "/tmp/dron_download_#{Time.now.to_i}.sh"
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_download_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✅ Download completado"
puts " Backup: #{resultado['backup_local']}"
puts " Duración: #{resultado['duracion']}s"
File.write('/tmp/dron_download_output.json', resultado_json)
puts " JSON guardado en: /tmp/dron_download_output.json"
else
puts "[!] Error en ejecución (código: #{$?.exitstatus})"
exit 1
end