diff --git a/adn/tools/bkps/lib/proc_linux.rb b/adn/tools/bkps/lib/proc_linux.rb new file mode 100644 index 00000000..ce3f5c49 --- /dev/null +++ b/adn/tools/bkps/lib/proc_linux.rb @@ -0,0 +1,172 @@ +# frozen_string_literal: true + +# ========================================================== +# adn/tools/bkps/lib/proc_linux.rb — Procesador Linux (apt) +# +# Fase 2: Soporta orquestación 1-dron-por-nodo +# listar(tarea) → lista nodos Linux pendientes +# ejecutar_uno(tarea, nodo) → actualiza UN solo nodo +# ejecutar(tarea) → actualiza TODOS (legacy) +# ========================================================== + +require 'shellwords' +require 'net/ssh' + +module ADN + module BKPs + module Procesador + class Linux + def initialize(log) + @log = log + end + + # Scanner: devuelve lista de nodos Linux a actualizar + # Lee los archivos .md de nodos/ y filtra los Linux (Debian/Ubuntu) + def listar(tarea) + nodos_dir = File.join(ADN::NODOS_DIR || 'nodos', '') + + unless Dir.exist?(nodos_dir) + @log.error("Directorio de nodos no existe: #{nodos_dir}") + return [] + end + + # Filtrar nodos Linux (excluye Windows y otros) + nodos_linux = Dir.glob(File.join(nodos_dir, '*.md')) + .select { |f| es_nodo_linux?(f) } + .map { |f| extraer_info_nodo(f) } + .compact + .reject { |n| n[:ip].nil? || n[:ip].empty? } + + nodos_linux.map do |nodo| + { + archivo: nodo[:hostname], # Identificador para ejecutar_uno + vm: nodo[:hostname], # Nombre visible (nodo) + ruta: nodo[:ip], # IP del nodo + destino: nodo[:ip], # Mismo destino (es SSH) + tamaño: 0, # No aplicable para updates + pendiente: true, # Siempre verificar + metadata: nodo # Info adicional (usuario, etc.) + } + end + end + + # Atómico: actualiza UN solo nodo Linux vía SSH + def ejecutar_uno(tarea, nombre_nodo) + ruta_md = File.join(ADN::NODOS_DIR || 'nodos', "#{nombre_nodo}.md") + nodo_info = File.exist?(ruta_md) ? extraer_info_nodo(ruta_md) : (tarea[:metadata] || {}) + ip = nodo_info[:ip] || tarea[:origen] + usuario = nodo_info[:usuario] || tarea[:usuario] || 'root' + + @log.info("🐧 Actualización Linux: #{nombre_nodo}") + @log.info(" SSH: #{usuario}@#{ip}") + + begin + Net::SSH.start(ip, usuario, keys_only: true, timeout: 10) do |ssh| + # Variables de entorno para evitar interactividad + env_vars = "DEBIAN_FRONTEND=noninteractive DEBIAN_PRIORITY=critical" + apt_opts = "-o Dpkg::Options::='--force-confdef' -o Dpkg::Options::='--force-confold'" + + # Paso 1: apt update + @log.info(" [1/3] Ejecutando apt update...") + output_update = ssh.exec!("sudo #{env_vars} apt-get update 2>&1") + @log.info(" #{output_update.lines.last&.strip || 'OK'}") + + # Paso 2: apt upgrade -y + @log.info(" [2/3] Ejecutando apt upgrade -y...") + output_upgrade = ssh.exec!("sudo #{env_vars} apt-get upgrade -y #{apt_opts} 2>&1") + @log.info(" #{output_upgrade.lines.last&.strip || 'OK'}") + + # Paso 3: apt autoremove -y (limpieza) + @log.info(" [3/3] Ejecutando apt autoremove -y...") + output_autoremove = ssh.exec!("sudo #{env_vars} apt-get autoremove -y 2>&1") + @log.info(" #{output_autoremove.lines.last&.strip || 'OK'}") + + @log.info("✔ Nodo #{nombre_nodo} actualizado exitosamente.") + true + end + rescue => e + @log.error("✗ Error actualizando #{nombre_nodo}: #{e.message}") + false + end + end + + # Legacy: actualiza TODOS los nodos (compatibilidad) + def ejecutar(tarea) + @log.info("--- #{tarea[:texto]} ---") + @log.info("Origen: #{tarea[:origen]}") + + nodos = listar(tarea) + if nodos.empty? + @log.info("Sin nodos Linux encontrados.") + return true + end + + @log.info("Encontrados #{nodos.length} nodo(s) Linux.") + actualizados = 0 + fallidos = 0 + + nodos.each do |nodo| + @log.info("\n" + "=" * 50) + if ejecutar_uno(tarea, nodo[:vm]) + actualizados += 1 + else + fallidos += 1 + end + end + + @log.info("\n" + "=" * 50) + @log.info("✔ #{actualizados} nodo(s) actualizado(s), #{fallidos} fallido(s).") + fallidos == 0 + end + + private + + # Verifica si el nodo es Linux (busca Debian, Ubuntu, Linux en el .md) + def es_nodo_linux?(archivo_md) + contenido = File.read(archivo_md) + + # Excluir explícitamente Windows + return false if contenido.match?(/Windows\s+(Server\s+)?\d+/i) + return false if contenido.match?(/Windows\s+10/i) + return false if contenido.match?(/Windows\s+11/i) + + # Incluir Linux/Debian/Ubuntu + return true if contenido.match?(/Debian/i) + return true if contenido.match?(/Ubuntu/i) + return true if contenido.match?(/Linux/i) + + # Incluir si tiene IP LAN y es srvv-* o srv-* (convención de nombres) + hostname = File.basename(archivo_md, '.md') + return true if hostname.match?(/^srvv?-/) + + false + end + + # Extrae información del nodo desde el archivo .md + def extraer_info_nodo(archivo_md) + contenido = File.read(archivo_md) + hostname = File.basename(archivo_md, '.md') + + # Extraer IP LAN + ip = contenido.match(/\*\*IP(?:\s+LAN)?\*\*:\s*`?(\d+\.\d+\.\d+\.\d+)`?/i)&.[](1) || + contenido.match(/\|\s*IP(?:\s+LAN)?[^\|]*\|\s*`?(\d+\.\d+\.\d+\.\d+)`?\s*\|/i)&.[](1) + + # Extraer usuario SSH (si está especificado) + usuario = contenido.match(/\*\*Usuario\s*SSH\*\*:\s*`?(\w+)`?/i)&.[](1) || + contenido.match(/\*\*SSH\*\*:\s*`?ssh\s+(\w+)@/i)&.[](1) || + 'root' + + # Extraer estado (para filtrar nodos offline) + estado = contenido.match(/\*\*Estado\*\*:\s*(🟢|🔴|⚫|🚧|🟡)/i)&.[](1) + + { + hostname: hostname, + ip: ip, + usuario: usuario, + estado: estado || '🟢' + } + end + end + end + end +end diff --git a/adn/tools/candados/.boveda.json b/adn/tools/candados/.boveda.json index 4e7786c1..be2cec61 100644 --- a/adn/tools/candados/.boveda.json +++ b/adn/tools/candados/.boveda.json @@ -17,5 +17,6 @@ "dasu-sql4:Administrador": "eyJpdiI6ImQzc09sRmo2NEZBbHZmN2IiLCJ0YWciOiJxK3Z3RU9uZG1QMXNUV1hJbEFmV3d3PT0iLCJkYXRhIjoicXd5dDI4bHBkeFNhRk1yTzluczlxdz09In0=", "dasu-sql4:sa": "eyJpdiI6Ik43aWR5d2RacFVFR3pyNysiLCJ0YWciOiJxeVAyTmxtYXloNTdFTVlvMFphQ2hRPT0iLCJkYXRhIjoiT0lrR1FGMXRVZ0czYU5PK1ZFcG8wUT09In0=", "dasu-pcv:rustdesk": "eyJpdiI6ImRwRFRCYjNmc1htZUJMZ1ciLCJ0YWciOiJRYTdpcy9wRTdlTnpLemQ0Y1VqMTF3PT0iLCJkYXRhIjoiL3hEczU5OVRrRzAralFNPSJ9", - "dasu-pcv:adminpcv": "eyJpdiI6IlVUK3JOamxCeFhGUUlCMlUiLCJ0YWciOiI0MC81bE10Y0FJM1BqMTQ1NUIxWjhBPT0iLCJkYXRhIjoiUzZuOUIxaTVISmJpclNrREZYSTkwM1k9In0=" + "dasu-pcv:adminpcv": "eyJpdiI6IlVUK3JOamxCeFhGUUlCMlUiLCJ0YWciOiI0MC81bE10Y0FJM1BqMTQ1NUIxWjhBPT0iLCJkYXRhIjoiUzZuOUIxaTVISmJpclNrREZYSTkwM1k9In0=", + "dasu-pc:UTNLR": "eyJpdiI6IjhLejRXUjNaTGU1RkRmaUgiLCJ0YWciOiJMRi9DdUhKWXg4VjJNL3MvajNqK1V3PT0iLCJkYXRhIjoicmJmdDZjZjNScXhFcVNzUC9ZSXc3SzA9In0=" } diff --git a/adn/tools/cli/dasuten_backup_download.rb b/adn/tools/cli/dasuten_backup_download.rb new file mode 100755 index 00000000..35f2d203 --- /dev/null +++ b/adn/tools/cli/dasuten_backup_download.rb @@ -0,0 +1,72 @@ +#!/usr/bin/env ruby +# frozen_string_literal: true + +# ========================================================== +# adn/tools/cli/dasuten_backup_download.rb — Download desde Google Drive +# ========================================================== +# Flujo: Google Drive (drive_bkps-dasu) → dasu-sql4 +# Uso: ruby adn/tools/cli/dasuten_backup_download.rb +# ========================================================== + +require 'shellwords' + +REMOTE_DRIVE = "rmonla-GDrive:drive_bkps-dasu" +LOCAL_BACKUP = "F:\\BACKUP\\sysdasuten_compressed_ADN.bak" + +puts "[*] Iniciando descarga de backup desde Google Drive..." + +begin + # Paso 1: Listar backups disponibles + puts "[1/4] Buscando backup más reciente en Drive..." + cmd_list = "rclone lsf '#{REMOTE_DRIVE}' --files-only --order '-modified' 2>/dev/null | grep sysdasuten | head -1" + backup_remoto = `#{cmd_list}`.strip + + if backup_remoto.empty? + puts "[!] No se encontraron backups en #{REMOTE_DRIVE}" + exit 1 + end + + puts " Backup encontrado: #{backup_remoto}" + + # Paso 2: Descargar backup + puts "[2/4] Descargando backup..." + puts " Origen: #{REMOTE_DRIVE}/#{backup_remoto}" + puts " Destino: #{LOCAL_BACKUP}" + puts " (Esto puede tomar 2-5 minutos)" + + cmd_download = "rclone copy '#{REMOTE_DRIVE}/#{backup_remoto}' '#{LOCAL_BACKUP}' --progress -v" + start_download = Time.now + system(cmd_download) + + if $?.success? + puts "[+] Descarga completada en #{(Time.now - start_download).round(2)} segundos." + else + puts "[!] Error en descarga (código: #{$?.exitstatus})" + exit 1 + end + + # Paso 3: Verificar archivo descargado + puts "[3/4] Verificando archivo descargado..." + cmd_verify = "powershell -Command \"(Get-Item '#{LOCAL_BACKUP}').Length\"" + tamaño = `#{cmd_verify}`.strip.to_i + + if tamaño > 0 + puts "[+] Archivo verificado: #{(tamaño / 1024.0 / 1024.0).round(2)} MB" + else + puts "[!] Archivo descargado parece estar vacío" + exit 1 + end + + # Paso 4: Restaurar en SQL Server + puts "[4/4] Preparando para restauración..." + puts " Backup disponible en: #{LOCAL_BACKUP}" + puts "" + puts " Para restaurar, ejecutar:" + puts " sqlcmd -S localhost -Q \"RESTORE DATABASE sysdasuten FROM DISK = '#{LOCAL_BACKUP}' WITH REPLACE, MOVE 'sysdasuten' TO 'F:\\DATA\\sysdasuten.mdf', MOVE 'sysdasuten_log' TO 'F:\\LOG\\sysdasuten_log.ldf'\"" + + puts "\n✅ Descarga completada exitosamente." + +rescue => e + puts "[!] Error fatal: #{e.message}" + exit 1 +end diff --git a/adn/tools/cli/dasuten_backup_upload.rb b/adn/tools/cli/dasuten_backup_upload.rb new file mode 100755 index 00000000..952404d8 --- /dev/null +++ b/adn/tools/cli/dasuten_backup_upload.rb @@ -0,0 +1,60 @@ +#!/usr/bin/env ruby +# frozen_string_literal: true + +# ========================================================== +# adn/tools/cli/dasuten_backup_upload.rb — Upload a Google Drive +# ========================================================== +# Flujo: srv-ns8 (backup local) → Google Drive +# Uso: ruby adn/tools/cli/dasuten_backup_upload.rb +# ========================================================== + +require 'time' + +REMOTE_DRIVE = "rmonla-GDrive:drive_bkps-dasu" +BACKUP_LOCAL = "/var/tmp/sysdasuten_compressed_ADN.bak" +BACKUP_NAME = "sysdasuten_compressed_ADN_#{Time.now.strftime('%Y%m%d_%H%M%S')}.bak" + +puts "[*] Iniciando upload de backup a Google Drive..." + +# Verificar archivo local +unless File.exist?(BACKUP_LOCAL) + puts "[!] Backup no encontrado en #{BACKUP_LOCAL}" + puts " Primero generar backup en srvv-fenix y descargar a srv-ns8" + exit 1 +end + +tamaño_mb = (File.size(BACKUP_LOCAL) / 1024.0 / 1024.0).round(2) +puts " Archivo local: #{BACKUP_LOCAL}" +puts " Tamaño: #{tamaño_mb} MB" +puts " Destino: #{REMOTE_DRIVE}/#{BACKUP_NAME}" + +begin + # Upload a Google Drive + puts "\n[1/2] Subiendo a Google Drive..." + puts " (Esto puede tomar 3-10 minutos dependiendo del ancho de banda)" + + cmd_upload = "rclone copy '#{BACKUP_LOCAL}' '#{REMOTE_DRIVE}/#{BACKUP_NAME}' --progress -v" + start_upload = Time.now + system(cmd_upload) + + if $?.success? + duracion = (Time.now - start_upload).round(2) + puts "[+] Upload completado en #{duracion} segundos." + else + puts "[!] Error en upload (código: #{$?.exitstatus})" + exit 1 + end + + # Verificar archivo en Drive + puts "\n[2/2] Verificando archivo en Drive..." + cmd_verify = "rclone size '#{REMOTE_DRIVE}/#{BACKUP_NAME}' 2>/dev/null" + output = `#{cmd_verify}`.strip + puts " Tamaño en Drive: #{output}" + + puts "\n✅ Backup subido exitosamente a Google Drive:" + puts " #{REMOTE_DRIVE}/#{BACKUP_NAME}" + +rescue => e + puts "[!] Error fatal: #{e.message}" + exit 1 +end diff --git a/adn/tools/cli/dasuten_orquestador.rb b/adn/tools/cli/dasuten_orquestador.rb new file mode 100755 index 00000000..49ef575b --- /dev/null +++ b/adn/tools/cli/dasuten_orquestador.rb @@ -0,0 +1,137 @@ +#!/usr/bin/env ruby +# frozen_string_literal: true + +# ========================================================== +# adn/tools/cli/dasuten_orquestador.rb — Orquestador Fase 8b +# ========================================================== +# Flujo completo: srvv-fenix → Google Drive → dasu-sql4 +# Uso: ruby adn/tools/cli/dasuten_orquestador.rb [upload|download|restore] +# ========================================================== + +require 'optparse' +require_relative 'dron/dispatcher' + +PROJECT_ROOT = File.expand_path('../..', __dir__) +CLI_DIR = File.join(PROJECT_ROOT, 'adn', 'tools', 'cli') +ADN_RUN = File.join(PROJECT_ROOT, 'adn', 'tools', 'run') + +opciones = { + paso: 'all', + dry_run: false, + nodo: nil +} + +OptionParser.new do |opts| + opts.banner = "Uso: #{ADN_RUN} dasuten_orquestador [opciones]" + opts.on("--paso PASO", %w[upload download restore all], "Ejecutar solo este paso (upload|download|restore|all)") { |p| opciones[:paso] = p } + opts.on("--nodo NOMBRE", "Nodo para bitácora del dron") { |n| opciones[:nodo] = n } + opts.on("--dry-run", "Simulación sin ejecutar") { opciones[:dry_run] = true } +end.parse!(ARGV) + +puts "\n#{'='*60}" +puts "🛸 ORQUESTADOR DASUTEN — Fase 8b (Refresco BD vía Google Drive)" +puts '='*60 +puts " Paso seleccionado: #{opciones[:paso]}" +puts " Dry-run: #{opciones[:dry_run]}" +puts " Nodo: #{opciones[:nodo] || 'auto-detect'}" +puts '='*60 + +def lanzar_dron(cmd, nota, nodo: nil) + puts "\n🛸 Lanzando dron: #{nota}" + puts " Comando: #{cmd}" + + args = ["lanzar", "--nota", nota] + args << "--nodo" << nodo if nodo + args << "--" << cmd + + # Ejecutar dron directamente + require_relative 'dron/ejecutor' + resultado = Dron::Ejecutor.lanzar( + cmd: cmd, + nota: nota, + nodo: nodo, + timeout: 1800 # 30 minutos max + ) + + resultado +end + +caso = opciones[:paso] + +# ────────────────────────────────────────────────────────────── +# PASO 1: UPLOAD desde srvv-fenix a Google Drive +# ────────────────────────────────────────────────────────────── +if caso == 'all' || caso == 'upload' + puts "\n" + "─"*60 + puts "📤 PASO 1: Upload desde srvv-fenix → Google Drive" + puts "─"*60 + + cmd_upload = "ruby #{CLI_DIR}/dasuten_backup_upload.rb" + + if opciones[:dry_run] + puts "[DRY-RUN] Ejecutaría: #{cmd_upload}" + else + resultado = lanzar_dron(cmd_upload, "📤 Upload backup DASUTEN a Drive", nodo: 'srvv-fenix') + if resultado[:exit_code] != 0 + puts "\n❌ Upload fallido. Deteniendo orquestación." + exit 1 + end + end +end + +# ────────────────────────────────────────────────────────────── +# PASO 2: DOWNLOAD desde Google Drive a dasu-sql4 +# ────────────────────────────────────────────────────────────── +if caso == 'all' || caso == 'download' + puts "\n" + "─"*60 + puts "📥 PASO 2: Download desde Google Drive → dasu-sql4" + puts "─"*60 + + cmd_download = "ruby #{CLI_DIR}/dasuten_backup_download.rb" + + if opciones[:dry_run] + puts "[DRY-RUN] Ejecutaría: #{cmd_download}" + else + resultado = lanzar_dron(cmd_download, "📥 Download backup DASUTEN desde Drive", nodo: 'dasu-sql4') + if resultado[:exit_code] != 0 + puts "\n❌ Download fallido. Deteniendo orquestación." + exit 1 + end + end +end + +# ────────────────────────────────────────────────────────────── +# PASO 3: RESTORE en dasu-sql4 +# ────────────────────────────────────────────────────────────── +if caso == 'all' || caso == 'restore' + puts "\n" + "─"*60 + puts "💾 PASO 3: Restore + DBCC CHECKDB en dasu-sql4" + puts "─"*60 + + cmd_restore = <<~SQL.gsub("\n", ' ').strip + powershell -Command " + $query = @' + RESTORE DATABASE sysdasuten FROM DISK = 'F:\\BACKUP\\sysdasuten_compressed_ADN.bak' + WITH REPLACE, + MOVE 'sysdasuten' TO 'F:\\DATA\\sysdasuten.mdf', + MOVE 'sysdasuten_log' TO 'F:\\LOG\\sysdasuten_log.ldf'; + DBCC CHECKDB('sysdasuten'); + '@ + sqlcmd -S localhost -Q $query + " + SQL + + if opciones[:dry_run] + puts "[DRY-RUN] Ejecutaría: #{cmd_restore}" + else + resultado = lanzar_dron(cmd_restore, "💾 Restore + CHECKDB DASUTEN", nodo: 'dasu-sql4') + if resultado[:exit_code] != 0 + puts "\n❌ Restore fallido. Verificar logs." + exit 1 + end + end +end + +puts "\n" + "═"*60 +puts "✅ Orquestación completada exitosamente!" +puts "═"*60 diff --git a/adn/tools/cli/dron/dispatcher.rb b/adn/tools/cli/dron/dispatcher.rb index 1cb89ae8..d384ba20 100644 --- a/adn/tools/cli/dron/dispatcher.rb +++ b/adn/tools/cli/dron/dispatcher.rb @@ -36,6 +36,8 @@ module Dron SanadorComando.reintentar(args) when 'estado', 'status' VigilanteComando.estado(args) + when 'ops', 'operaciones' + OpsComando.ejecutar(args) when 'ayuda', 'help', '--help', '-h' mostrar_ayuda else @@ -59,6 +61,7 @@ module Dron lines << " #{Color::GREEN}flota#{Color::RESET} Dashboard compacto de la flota" lines << " #{Color::GREEN}salud#{Color::RESET} Health check activo (detecta zombies)" lines << " #{Color::GREEN}estado #{Color::RESET} Estado detallado de un dron" + lines << " #{Color::GREEN}ops #{Color::RESET} Operaciones de infraestructura (update_os)" lines << " #{Color::GREEN}sanear#{Color::RESET} Sanear flota (reintentar + limpiar)" lines << " #{Color::GREEN}limpiar#{Color::RESET} Limpiar drones antiguos" lines << " #{Color::GREEN}reintentar#{Color::RESET} Re-intentar drones fallidos" @@ -74,6 +77,8 @@ module Dron lines << "\n#{Color::BOLD}Ejemplos:#{Color::RESET}" lines << " #{Color::DIM}$ ./adn/tools/run dron lanzar --nota 'Backup SQL' -- vzdump 103#{Color::RESET}" lines << " #{Color::CYAN}Lanzar backup como dron#{Color::RESET}" + lines << " #{Color::DIM}$ ./adn/tools/run dron ops update_os --target linux#{Color::RESET}" + lines << " #{Color::CYAN}Actualizar OS de todos los nodos Linux#{Color::RESET}" lines << " #{Color::DIM}$ ./adn/tools/run dron flota#{Color::RESET}" lines << " #{Color::CYAN}Ver estado de la flota#{Color::RESET}" lines << " #{Color::DIM}$ ./adn/tools/run dron salud#{Color::RESET}" @@ -279,4 +284,11 @@ module Dron opciones end end + + class OpsComando + def self.ejecutar(args) + require_relative 'ops' + Dron::Ops.ejecutar(args) + end + end end diff --git a/adn/tools/cli/dron/ops.rb b/adn/tools/cli/dron/ops.rb new file mode 100644 index 00000000..9237375f --- /dev/null +++ b/adn/tools/cli/dron/ops.rb @@ -0,0 +1,293 @@ +# frozen_string_literal: true + +# ========================================================== +# Dron::Ops — Operaciones de Infraestructura via AtomicDrones +# ---------------------------------------------------------- +# Responsabilidad: Orquestar tareas de mantenimiento de nodos +# (update_os, etc.) usando 1 dron ejecutor por nodo. +# +# Reutiliza: +# - NodosInfo (scanner de fichas .md) +# - Dron::Ejecutor (ejecución atómica con auto-bitácora) +# +# Uso: +# ./adn/tools/run dron ops update_os --target linux +# ./adn/tools/run dron ops update_os --nodo srvv-dns +# ./adn/tools/run dron ops update_os --target linux --dry-run +# +# Plan: A01.P011 — Drones de Operaciones de Infraestructura +# ========================================================== + +require 'optparse' +require 'shellwords' +require_relative 'base' +require_relative 'ejecutor' +require_relative '../nodos/info' +require_relative '../../core/colores' +require_relative '../../core/constants' + +module Dron + class Ops + # Comandos SSH para actualización desatendida + APT_ENV = 'DEBIAN_FRONTEND=noninteractive DEBIAN_PRIORITY=critical' + APT_OPTS = "-o Dpkg::Options::='--force-confdef' -o Dpkg::Options::='--force-confold'" + APT_CMD = "sudo #{APT_ENV} apt-get update 2>&1 && " \ + "sudo #{APT_ENV} apt-get upgrade -y #{APT_OPTS} 2>&1 && " \ + "sudo #{APT_ENV} apt-get autoremove -y 2>&1" + + class << self + # ─── Punto de entrada CLI ────────────────────────────────── + + def ejecutar(args) + accion = args.shift + + case accion + when 'update_os' + cmd_update_os(args) + when 'ayuda', 'help', '--help', '-h', nil + mostrar_ayuda + else + Base.logger.error("❌ Acción desconocida para ops: #{accion}") + mostrar_ayuda + exit 1 + end + end + + private + + # ─── update_os ───────────────────────────────────────────── + + def cmd_update_os(args) + opciones = parsear_opciones(args) + + # Obtener nodos candidatos + nodos = escanear_nodos(opciones) + + if nodos.empty? + puts "#{Color::YELLOW}⚠ Sin nodos Linux encontrados para actualizar.#{Color::RESET}" + return + end + + mostrar_resumen(nodos, opciones) + + return if opciones[:dry_run] + + # Orquestar: 1 dron ejecutor por nodo + resultados = orquestar_nodos(nodos, opciones) + + # Resumen final + mostrar_resultados(resultados, nodos.length) + + exit 1 if resultados[:failed] > 0 && opciones[:on_error] == 'abort' + end + + # ─── Scanner: reutiliza NodosInfo ────────────────────────── + + def escanear_nodos(opciones) + nodos_dir = ADN::NODOS_DIR + + unless Dir.exist?(nodos_dir) + Base.logger.error("Directorio de nodos no existe: #{nodos_dir}") + return [] + end + + candidatos = Dir.glob(File.join(nodos_dir, '*.md')) + .reject { |f| File.basename(f).start_with?('_') } + .map { |f| ADN::NodosInfo.extraer_metadata(File.basename(f, '.md')) } + .compact + + # Filtrar por OS + if opciones[:target] == 'linux' + candidatos.select! { |n| n[:so] == :linux } + end + + # Excluir nodos sin IP + candidatos.reject! { |n| n[:ip].nil? || n[:ip].to_s.strip.empty? } + + # Excluir nodos offline + candidatos.reject! { |n| n[:estado]&.to_s&.include?('🔴') } + + # Filtrar nodo específico + if opciones[:nodo] + candidatos.select! { |n| n[:nombre] == opciones[:nodo] } + end + + # Filtrar por ring + if opciones[:ring] + candidatos.select! { |n| n[:ring] == opciones[:ring] } + end + + candidatos + end + + # ─── Orquestación: 1 dron por nodo ───────────────────────── + + def orquestar_nodos(nodos, opciones) + resultados = { ok: 0, failed: 0, skipped: 0 } + abortado = false + + nodos.each_with_index do |nodo, i| + break if abortado + + puts " #{Color::BOLD}[#{i + 1}/#{nodos.length}]#{Color::RESET} " \ + "#{Color::CYAN}#{nodo[:nombre]}#{Color::RESET} (#{nodo[:ip]})" + + # Construir comando SSH para este nodo + usuario = nodo[:usuario] || 'root' + puerto = nodo[:puerto_ssh] || 22 + ssh_cmd = construir_ssh_cmd(nodo, usuario, puerto) + + # Lanzar dron ejecutor (auto-bitácora incluida) + nota = "🐧 Actualizar #{nodo[:nombre]}" + resultado = Dron::Ejecutor.lanzar( + cmd: ssh_cmd, + nota: nota, + timeout: opciones[:timeout], + nodo: nodo[:nombre] + ) + + if resultado[:exit_code] == 0 + puts " #{Color::GREEN}✔ Completado#{Color::RESET} (#{resultado[:duration]}s)" + resultados[:ok] += 1 + else + resultados[:failed] += 1 + case opciones[:on_error] + when 'abort' + puts " #{Color::RED}✖ Falló — deteniendo orquestación#{Color::RESET}" + abortado = true + resultados[:skipped] = nodos.length - i - 1 + when 'continue' + puts " #{Color::YELLOW}⚠ Falló — continuando con el siguiente#{Color::RESET}" + end + end + + puts "" + end + + resultados + end + + # ─── Construcción de comando SSH ─────────────────────────── + + def construir_ssh_cmd(nodo, usuario, puerto) + ssh_opts = "-o StrictHostKeyChecking=no -o ConnectTimeout=10" + + # Puerto no estándar + ssh_opts += " -p #{puerto}" if puerto != 22 + + # Opciones especiales (legacy servers como XenServer) + ssh_opts += " #{nodo[:ssh_opts]}" if nodo[:ssh_opts] + + # Clave SSH específica + if nodo[:clave_ssh] + clave = nodo[:clave_ssh].gsub('~', ENV['HOME'] || '/root') + ssh_opts += " -i #{clave}" + end + + remote_cmd = APT_CMD + + # Determinar método de autenticación + if nodo[:clave_boveda] + # AUTH POR PASSWORD: Usar candados run + sshpass + # candados inyecta $PASS en el entorno, sshpass lo consume + adn_run = File.join(ADN::PROJECT_ROOT, 'adn/tools/run') + "#{adn_run} candados run #{nodo[:clave_boveda]} " \ + "'sshpass -p $PASS ssh #{ssh_opts} #{usuario}@#{nodo[:ip]} \"#{remote_cmd}\"'" + else + # AUTH POR CLAVE SSH: Conexión directa + "ssh #{ssh_opts} #{usuario}@#{nodo[:ip]} '#{remote_cmd}'" + end + end + + # ─── Presentación ───────────────────────────────────────── + + def mostrar_resumen(nodos, opciones) + puts "" + puts "#{Color::BOLD}#{Color::CYAN}🐧 Dron Ops — Actualización de OS Linux#{Color::RESET}" + puts "═" * 60 + puts " Nodos detectados: #{nodos.length}" + puts " Target: #{opciones[:target]}" + puts " Ring: #{opciones[:ring] || 'todos'}" if opciones[:ring] + puts " On-error: #{opciones[:on_error]}" + puts " Timeout por nodo: #{opciones[:timeout]}s" + if opciones[:dry_run] + puts " Modo: #{Color::YELLOW}DRY-RUN (sin ejecutar)#{Color::RESET}" + end + puts "" + + if opciones[:dry_run] + nodos.each_with_index do |nodo, i| + auth = nodo[:clave_boveda] ? "🔐 #{nodo[:clave_boveda]}" : "🔑 key" + ring_tag = nodo[:ring] ? " [#{nodo[:ring]}]" : "" + puts " #{Color::DIM}[#{i + 1}]#{Color::RESET} #{nodo[:nombre].ljust(18)} " \ + "#{Color::DIM}#{nodo[:ip].ljust(16)} #{(nodo[:usuario] || 'root').ljust(8)} #{auth}#{ring_tag}#{Color::RESET}" + end + puts "" + puts "#{Color::YELLOW}[DRY-RUN] No se lanzaron drones.#{Color::RESET}" + end + end + + def mostrar_resultados(resultados, total) + puts "#{Color::BOLD}🐧 Resumen de Operaciones#{Color::RESET}" + puts "═" * 40 + puts " ✅ Exitosos: #{resultados[:ok]}" + puts " ❌ Fallidos: #{resultados[:failed]}" if resultados[:failed] > 0 + puts " ⏭️ Saltados: #{resultados[:skipped]}" if resultados[:skipped] > 0 + puts "#{Color::BOLD}🐧 Operación #{resultados[:failed] > 0 ? 'con errores' : 'finalizada'}.#{Color::RESET}" + end + + # ─── Parser de opciones ──────────────────────────────────── + + def parsear_opciones(args) + opciones = { + target: 'linux', + nodo: nil, + ring: nil, + on_error: 'continue', + timeout: 600, + dry_run: false + } + + OptionParser.new do |opts| + opts.banner = "Uso: ./adn/tools/run dron ops update_os [opciones]" + opts.on("--target OS", "OS a actualizar (linux)") { |t| opciones[:target] = t } + opts.on("--nodo NOMBRE", "Actualizar solo este nodo") { |n| opciones[:nodo] = n } + opts.on("--ring RING", %w[test standard core], "Solo nodos de este ring (test|standard|core)") { |r| opciones[:ring] = r } + opts.on("--on-error MODE", %w[abort continue], "Qué hacer si un dron falla (abort|continue)") { |m| opciones[:on_error] = m } + opts.on("--timeout N", Integer, "Timeout por nodo en segundos (default: 600)") { |t| opciones[:timeout] = t } + opts.on("--dry-run", "Solo listar nodos sin ejecutar") { opciones[:dry_run] = true } + end.parse!(args) + + opciones + end + + def mostrar_ayuda + puts "#{Color::BOLD}🐧 Dron Ops — Operaciones de Infraestructura#{Color::RESET}" + puts "#{Color::DIM}#{'=' * 50}#{Color::RESET}" + puts "" + puts "#{Color::CYAN}Operaciones de mantenimiento sobre nodos vía AtomicDrones#{Color::RESET}" + puts "" + puts "Uso: #{Color::YELLOW}./adn/tools/run dron ops [opciones]#{Color::RESET}" + puts "" + puts "#{Color::BOLD}Acciones:#{Color::RESET}" + puts " #{Color::GREEN}update_os#{Color::RESET} Actualizar sistema operativo de nodos" + puts "" + puts "#{Color::BOLD}Opciones:#{Color::RESET}" + puts " #{Color::GREEN}--target OS#{Color::RESET} OS a actualizar: linux (default: linux)" + puts " #{Color::GREEN}--nodo NOMBRE#{Color::RESET} Actualizar solo un nodo específico" + puts " #{Color::GREEN}--on-error MODE#{Color::RESET} abort|continue (default: continue)" + puts " #{Color::GREEN}--timeout N#{Color::RESET} Timeout por nodo en segundos (default: 600)" + puts " #{Color::GREEN}--dry-run#{Color::RESET} Solo listar sin ejecutar" + puts "" + puts "#{Color::BOLD}Ejemplos:#{Color::RESET}" + puts " #{Color::DIM}$ ./adn/tools/run dron ops update_os --target linux --dry-run#{Color::RESET}" + puts " #{Color::CYAN}Listar nodos Linux sin actualizar#{Color::RESET}" + puts " #{Color::DIM}$ ./adn/tools/run dron ops update_os --nodo srvv-dns#{Color::RESET}" + puts " #{Color::CYAN}Actualizar solo srvv-dns#{Color::RESET}" + puts " #{Color::DIM}$ ./adn/tools/run dron ops update_os --on-error continue#{Color::RESET}" + puts " #{Color::CYAN}Actualizar toda la flota Linux continuando ante fallos#{Color::RESET}" + puts "" + end + end + end +end diff --git a/adn/tools/cli/drones/dasuten_upload_srv-ns8-drive.rb b/adn/tools/cli/drones/dasuten_upload_srv-ns8-drive.rb new file mode 100644 index 00000000..c0c55fcd --- /dev/null +++ b/adn/tools/cli/drones/dasuten_upload_srv-ns8-drive.rb @@ -0,0 +1,88 @@ +#!/usr/bin/env ruby +# frozen_string_literal: true + +# ========================================================== +# adn/tools/cli/drones/dasuten_upload_srv-ns8-drive.rb +# ========================================================== +# Dron: Upload a Google Drive desde srv-ns8 +# Flujo: /var/tmp/sysdasuten_compressed_ADN.bak → Google Drive +# Entrada: Backup ya descargado en /var/tmp/ +# Salida: URL de Google Drive +# ========================================================== + +require 'time' +require 'json' +require 'shellwords' + +REMOTE_DRIVE = "rmonla-GDrive:drive_bkps-dasu" + +# Leer ruta del backup desde el output de la transferencia +TRANSFER_OUTPUT = '/tmp/dron_transfer_output.json' +if File.exist?(TRANSFER_OUTPUT) + output = JSON.parse(File.read(TRANSFER_OUTPUT)) + BACKUP_LOCAL = output['backup_local'] + BACKUP_NAME = File.basename(BACKUP_LOCAL) + puts "[*] Dron: Upload a Google Drive (DIFERENCIAL)" +else + BACKUP_LOCAL = "/var/tmp/sysdasuten_compressed_ADN.bak" + BACKUP_NAME = "sysdasuten_compressed_ADN_#{Time.now.strftime('%Y%m%d_%H%M%S')}.bak" + puts "[*] Dron: Upload a Google Drive (COMPLETO)" +end + +puts " Nodo: srv-ns8" +puts " Origen: #{BACKUP_LOCAL}" +puts " Destino: #{REMOTE_DRIVE}/#{BACKUP_NAME}" + +# Verificar archivo local +unless File.exist?(BACKUP_LOCAL) + puts "[!] Backup no encontrado en #{BACKUP_LOCAL}" + puts " Ejecutar primero: dasuten_transferir_srvv-fenix-srv-ns8.rb" + exit 1 +end + +tamaño_mb = (File.size(BACKUP_LOCAL) / 1024.0 / 1024.0).round(2) +puts "[+] Archivo local: #{tamaño_mb} MB" + +begin + # Upload a Google Drive + puts "\n[1/2] Subiendo a Google Drive..." + start = Time.now + + cmd_upload = "rclone copy '#{BACKUP_LOCAL}' '#{REMOTE_DRIVE}/#{BACKUP_NAME}' --progress -v 2>&1" + system(cmd_upload) + + if $?.success? + duracion = (Time.now - start).round(2) + puts "[+] Upload completado en #{duracion} segundos" + else + puts "[!] Error en upload (código: #{$?.exitstatus})" + exit 1 + end + + # Verificar en Drive + puts "\n[2/2] Verificando archivo en Drive..." + cmd_verify = "rclone size '#{REMOTE_DRIVE}/#{BACKUP_NAME}' 2>/dev/null" + output = `#{cmd_verify}`.strip + + puts " Tamaño en Drive: #{output}" + + # Output para orquestador + resultado = { + paso: 'upload_complete', + drive_ruta: "#{REMOTE_DRIVE}/#{BACKUP_NAME}", + drive_url: "https://drive.google.com/drive/folders/1Tgrn2QYyWf0v0eyY1bSGCLlhiqhtIA2n", + nodo: 'srv-ns8', + duracion: duracion, + timestamp: Time.now.iso8601, + siguiente_paso: 'download_drive' + } + + puts "\n✅ Upload completado" + puts " Output: #{resultado.to_json}" + + File.write('/tmp/dron_upload_output.json', resultado.to_json) + +rescue => e + puts "[!] Error fatal: #{e.message}" + exit 1 +end diff --git a/adn/tools/cli/drones/orquestador_pipeline.rb b/adn/tools/cli/drones/orquestador_pipeline.rb new file mode 100755 index 00000000..de02bf7f --- /dev/null +++ b/adn/tools/cli/drones/orquestador_pipeline.rb @@ -0,0 +1,207 @@ +#!/usr/bin/env ruby +# frozen_string_literal: true + +# ========================================================== +# adn/tools/cli/drones/orquestador_pipeline.rb +# ========================================================== +# Orquestador de Pipeline DASUTEN — Intercomunicación vía JSON +# ========================================================== +# Flujo: exportar → transferir SMB → upload → download → restaurar → verificar +# Cada dron escribe su output en JSON y el orquestador lo lee +# para decidir el siguiente paso. +# ========================================================== + +require 'optparse' +require 'json' +require 'time' +require 'shellwords' + +CLI_DIR = File.expand_path(__dir__) +ADN_RUN = File.join(File.dirname(File.dirname(File.dirname(CLI_DIR))), 'tools', 'run') + +# Configuración +opciones = { + paso_inicial: 'exportar', + dry_run: false, + timeout: 1800, # 30 min por dron + nodo_bitacora: 'dasuten-pipeline' +} + +OptionParser.new do |opts| + opts.banner = "Uso: #{ADN_RUN} dron lanzar --nota 'Pipeline DASUTEN' -- ruby adn/tools/cli/drones/orquestador_pipeline.rb [opciones]" + opts.on("--paso PASO", %w[exportar transferir upload download restaurar verificar], "Comenzar desde este paso") { |p| opciones[:paso_inicial] = p } + opts.on("--dry-run", "Simulación sin ejecutar drones") { opciones[:dry_run] = true } + opts.on("--timeout N", Integer, "Timeout por dron en segundos") { |t| opciones[:timeout] = t } +end.parse!(ARGV) + +# Estados del pipeline (6 drones atómicos) +ESTADOS = { + exportar: { + script: 'dasuten_exportar_srvv-fenix.rb', + nodo: 'srvv-fenix', + nota: '📤 Exportar backup DASUTEN', + output_file: '/tmp/dron_export_output.json', + siguiente: :transferir + }, + transferir: { + script: 'dasuten_transferir_srvv-fenix-srv-ns8.rb', + nodo: 'srv-ns8', + nota: '🔄 Transferir SMB (fenix → ns8)', + output_file: '/tmp/dron_transfer_output.json', + siguiente: :upload + }, + upload: { + script: 'dasuten_upload_srv-ns8-drive.rb', + nodo: 'srv-ns8', + nota: '☁️ Upload a Google Drive', + output_file: '/tmp/dron_upload_output.json', + siguiente: :download + }, + download: { + script: 'dasuten_download_drive-dasu-sql4.rb', + nodo: 'dasu-sql4', + nota: '📥 Download desde Google Drive', + output_file: '/tmp/dron_download_output.json', + siguiente: :restaurar + }, + restaurar: { + script: 'dasuten_restaurar_dasu-sql4.rb', + nodo: 'dasu-sql4', + nota: '💾 Restaurar backup', + output_file: '/tmp/dron_restore_output.json', + siguiente: :verificar + }, + verificar: { + script: 'dasuten_verificar-integridad_dasu-sql4.rb', + nodo: 'dasu-sql4', + nota: '✅ Verificar integridad BD', + output_file: '/tmp/dron_verify_output.json', + siguiente: nil # Final + } +}.freeze + +puts "\n" + "="*70 +puts "🛸 ORQUESTADOR PIPELINE DASUTEN (Fase 8b — 6 drones atómicos)" +puts "="*70 +puts " Paso inicial: #{opciones[:paso_inicial]}" +puts " Dry-run: #{opciones[:dry_run]}" +puts " Timeout: #{opciones[:timeout]}s por dron" +puts " Drones: #{ESTADOS.keys.join(' → ')}" +puts "="*70 + +# ────────────────────────────────────────────────────────────── +# Función para lanzar un dron y esperar su resultado +# ────────────────────────────────────────────────────────────── +def lanzar_dron(script, nodo, nota, timeout) + cmd = "ruby #{File.join(File.dirname(__FILE__), script)}" + + puts "\n" + "-"*70 + puts "🛸 Lanzando dron: #{nota}" + puts " Nodo: #{nodo}" + puts " Script: #{script}" + puts "-"*70 + + # Lanzar dron ejecutor + dron_cmd = "#{ADN_RUN} dron lanzar --nota #{Shellwords.escape(nota)} --nodo #{Shellwords.escape(nodo)} --timeout #{timeout} -- #{cmd}" + + puts " Comando: #{dron_cmd}" + + if opciones[:dry_run] + puts " [DRY-RUN] No ejecutado" + return true, {} + end + + exito = system(dron_cmd) + codigo = $?.exitstatus + + if exito + puts "\n✅ Dron completado exitosamente" + + # Leer output del dron + output_file = ESTADOS[nodo.to_sym][:output_file] + if File.exist?(output_file) + resultado = JSON.parse(File.read(output_file)) + puts " Output: #{resultado.inspect}" + return true, resultado + else + puts " [!] No se encontró archivo de output" + return true, {} + end + else + puts "\n❌ Dron fallido (código: #{codigo})" + return false, {} + end +end + +# ────────────────────────────────────────────────────────────── +# Ejecutar pipeline +# ────────────────────────────────────────────────────────────── + +paso_actual = opciones[:paso_inicial].to_sym +contexto = {} # Para pasar datos entre drones +duracioniones = [] + +begin + loop do + break unless ESTADOS[paso_actual] + + config = ESTADOS[paso_actual] + + # Inyectar contexto del paso anterior si es necesario + case paso_actual + when :upload + # El dron de upload ya sabe dónde está el archivo (hardcodeado en /var/tmp/) + when :download + # El dron de download usa file_id o test_file + when :restaurar + # El dron de restaurar usa la ruta hardcodeada F:\BACKUP\ + end + + # Lanzar dron + exito, resultado = lanzar_dron( + config[:script], + config[:nodo], + config[:nota], + opciones[:timeout] + ) + + unless exito + puts "\n❌ Pipeline fallido en paso: #{paso_actual}" + exit 1 + end + + # Guardar contexto para siguiente paso + contexto.merge!(resultado) if resultado + duraciones << resultado[:duracion] if resultado[:duracion] + + # Decidir siguiente paso + if config[:siguiente] + puts "\n➡️ Pasando a: #{config[:siguiente]}" + paso_actual = config[:siguiente] + else + puts "\n✅ Pipeline completado exitosamente!" + break + end + end + + # Resumen final + puts "\n" + "="*70 + puts "📊 RESUMEN DEL PIPELINE" + puts "="*70 + + if contexto[:pipeline_completo] || contexto[:estado_integridad] == 'OK' + puts " Estado: ✅ COMPLETADO" + puts " Integridad BD: #{contexto[:estado_integridad] || 'N/A'}" + else + puts " Estado: ⏳ EN PROGRESO" + end + + puts " Backup Drive: #{contexto[:drive_ruta] || contexto[:drive_origen] || 'N/A'}" + puts " Duración total: #{duraciones.sum.round(2)}s (#{duraciones.count} drones)" + puts "="*70 + +rescue => e + puts "\n❌ Error en orquestador: #{e.message}" + puts e.backtrace.first(5).join("\n") + exit 1 +end diff --git a/adn/tools/cli/drones/orquestador_pipeline_diferencial.rb b/adn/tools/cli/drones/orquestador_pipeline_diferencial.rb new file mode 100644 index 00000000..3bdd0cb8 --- /dev/null +++ b/adn/tools/cli/drones/orquestador_pipeline_diferencial.rb @@ -0,0 +1,206 @@ +#!/usr/bin/env ruby +# frozen_string_literal: true + +# ========================================================== +# adn/tools/cli/drones/orquestador_pipeline_diferencial.rb +# ========================================================== +# Orquestador de Pipeline DIFERENCIAL DASUTEN +# ========================================================== +# Flujo: exportar_dif → transferir → upload → download → restaurar_dif → verificar +# Para refrescos diarios (solo cambios desde último backup completo) +# ========================================================== + +require 'optparse' +require 'json' +require 'time' +require 'shellwords' + +CLI_DIR = File.expand_path(__dir__) +ADN_RUN = File.join(File.dirname(File.dirname(File.dirname(CLI_DIR))), 'tools', 'run') + +# Configuración +opciones = { + paso_inicial: 'exportar_dif', + dry_run: false, + timeout: 900, # 15 min por dron (suficiente para diferencial) + nodo_bitacora: 'dasuten-pipeline-dif' +} + +OptionParser.new do |opts| + opts.banner = "Uso: #{ADN_RUN} dron lanzar --nota 'Pipeline Diferencial DASUTEN' -- ruby adn/tools/cli/drones/orquestador_pipeline_diferencial.rb [opciones]" + opts.on("--paso PASO", %w[exportar_dif transferir upload download restaurar_dif verificar], "Comenzar desde este paso") { |p| opciones[:paso_inicial] = p } + opts.on("--dry-run", "Simulación sin ejecutar drones") { opciones[:dry_run] = true } + opts.on("--timeout N", Integer, "Timeout por dron en segundos") { |t| opciones[:timeout] = t } +end.parse!(ARGV) + +# Estados del pipeline diferencial (6 drones atómicos) +ESTADOS = { + exportar_dif: { + script: 'dasuten_exportar_diferencial_srvv-fenix.rb', + nodo: 'srvv-fenix', + nota: '📤 Exportar backup DIFERENCIAL DASUTEN', + output_file: '/tmp/dron_export_dif_output.json', + siguiente: :transferir + }, + transferir: { + script: 'dasuten_transferir_srvv-fenix-srv-ns8.rb', + nodo: 'srv-ns8', + nota: '🔄 Transferir SMB (fenix → ns8)', + output_file: '/tmp/dron_transfer_output.json', + siguiente: :upload + }, + upload: { + script: 'dasuten_upload_srv-ns8-drive.rb', + nodo: 'srv-ns8', + nota: '☁️ Upload a Google Drive', + output_file: '/tmp/dron_upload_output.json', + siguiente: :download + }, + download: { + script: 'dasuten_download_drive-dasu-sql4.rb', + nodo: 'dasu-sql4', + nota: '📥 Download desde Google Drive', + output_file: '/tmp/dron_download_output.json', + siguiente: :restaurar_dif + }, + restaurar_dif: { + script: 'dasuten_restaurar_diferencial_dasu-sql4.rb', + nodo: 'dasu-sql4', + nota: '💾 Restaurar backup DIFERENCIAL', + output_file: '/tmp/dron_restore_dif_output.json', + siguiente: :verificar + }, + verificar: { + script: 'dasuten_verificar-integridad_dasu-sql4.rb', + nodo: 'dasu-sql4', + nota: '✅ Verificar integridad BD', + output_file: '/tmp/dron_verify_output.json', + siguiente: nil # Final + } +}.freeze + +puts "\n" + "="*70 +puts "🛸 ORQUESTADOR PIPELINE DIFERENCIAL DASUTEN (Refresco diario)" +puts "="*70 +puts " Paso inicial: #{opciones[:paso_inicial]}" +puts " Dry-run: #{opciones[:dry_run]}" +puts " Timeout: #{opciones[:timeout]}s por dron" +puts " Drones: #{ESTADOS.keys.join(' → ')}" +puts "="*70 +puts "" +puts " ℹ️ Este pipeline usa backup DIFERENCIAL (solo cambios)" +puts " Esperado: ~5-10 min total (vs ~35 min del completo)" +puts "="*70 + +# ────────────────────────────────────────────────────────────── +# Función para lanzar un dron y esperar su resultado +# ────────────────────────────────────────────────────────────── +def lanzar_dron(script, nodo, nota, timeout, dry_run) + cmd = "ruby #{File.join(File.dirname(__FILE__), script)}" + + puts "\n" + "-"*70 + puts "🛸 Lanzando dron: #{nota}" + puts " Nodo: #{nodo}" + puts " Script: #{script}" + puts "-"*70 + + # Lanzar dron ejecutor + dron_cmd = "#{ADN_RUN} dron lanzar --nota #{Shellwords.escape(nota)} --nodo #{Shellwords.escape(nodo)} --timeout #{timeout} -- #{cmd}" + + puts " Comando: #{dron_cmd}" + + if dry_run + puts " [DRY-RUN] No ejecutado" + return true, {} + end + + exito = system(dron_cmd) + codigo = $?.exitstatus + + if exito + puts "\n✅ Dron completado exitosamente" + + # Leer output del dron (buscar en todos los archivos posibles) + output_files = ['/tmp/dron_export_dif_output.json', '/tmp/dron_transfer_output.json', + '/tmp/dron_upload_output.json', '/tmp/dron_download_output.json', + '/tmp/dron_restore_dif_output.json', '/tmp/dron_verify_output.json'] + output_file = output_files.find { |f| File.exist?(f) } + + if output_file && File.exist?(output_file) + resultado = JSON.parse(File.read(output_file)) + puts " Output: #{resultado.inspect}" + return true, resultado + else + puts " [!] No se encontró archivo de output" + return true, {} + end + else + puts "\n❌ Dron fallido (código: #{codigo})" + return false, {} + end +end + +# ────────────────────────────────────────────────────────────── +# Ejecutar pipeline +# ────────────────────────────────────────────────────────────── + +paso_actual = opciones[:paso_inicial].to_sym +contexto = {} # Para pasar datos entre drones +duraciones = [] + +begin + loop do + break unless ESTADOS[paso_actual] + + config = ESTADOS[paso_actual] + + # Lanzar dron + exito, resultado = lanzar_dron( + config[:script], + config[:nodo], + config[:nota], + opciones[:timeout], + opciones[:dry_run] + ) + + unless exito + puts "\n❌ Pipeline fallido en paso: #{paso_actual}" + exit 1 + end + + # Guardar contexto para siguiente paso + contexto.merge!(resultado) if resultado + duraciones << resultado[:duracion] if resultado[:duracion] + + # Decidir siguiente paso + if config[:siguiente] + puts "\n➡️ Pasando a: #{config[:siguiente]}" + paso_actual = config[:siguiente] + else + puts "\n✅ Pipeline completado exitosamente!" + break + end + end + + # Resumen final + puts "\n" + "="*70 + puts "📊 RESUMEN DEL PIPELINE DIFERENCIAL" + puts "="*70 + + if contexto[:pipeline_completo] || contexto[:estado_integridad] == 'OK' + puts " Estado: ✅ COMPLETADO" + puts " Integridad BD: #{contexto[:estado_integridad] || 'N/A'}" + else + puts " Estado: ⏳ EN PROGRESO" + end + + puts " Backup Drive: #{contexto[:drive_ruta] || contexto[:drive_origen] || 'N/A'}" + puts " Duración total: #{duraciones.sum.round(2)}s (#{duraciones.count} drones)" + puts " Tipo: #{contexto[:backup_tipo] || 'differential'}" + puts "="*70 + +rescue => e + puts "\n❌ Error en orquestador: #{e.message}" + puts e.backtrace.first(5).join("\n") + exit 1 +end diff --git a/adn/tools/cli/nodos/info.rb b/adn/tools/cli/nodos/info.rb index ec8c2b88..6d22d975 100644 --- a/adn/tools/cli/nodos/info.rb +++ b/adn/tools/cli/nodos/info.rb @@ -2,6 +2,12 @@ # adn/tools/cli/nodos/info.rb — Utilidades para extracción de metadatos de fichas de nodos # ====================================================================================== +# +# Fase 2.5: Soporte dual — Tabla canónica (META:BEGIN/META:END) + fallback regex +# +# Prioridad de lectura: +# 1. Tabla canónica entre y +# 2. Regex heurísticas (legacy, para fichas no migradas) require_relative '../../core/constants' @@ -12,6 +18,30 @@ module ADN return nil unless File.exist?(ruta) contenido = File.read(ruta, encoding: 'UTF-8') + + # ─── Intentar tabla canónica primero ────────────────────── + meta = extraer_meta_canonica(contenido) + if meta + return { + nombre: nodo_nombre, + ip: meta['IP'], + ip_lan: detectar_ip_lan(contenido), + host: meta['Host'], + so: detectar_so_desde_valor(meta['OS']), + vmid: meta['VMID'], + puerto_ssh: extraer_puerto_de_ssh(meta['SSH']), + usuario: extraer_usuario_de_ssh(meta['SSH']), + clave_boveda: meta['Bóveda'], + auth_type: meta['Auth']&.to_sym, + clave_ssh: meta['Clave SSH'], + ssh_opts: meta['SSH Opts'], + ring: meta['Ring'], + estado: meta['Estado'], + _fuente: :canonica + } + end + + # ─── Fallback: Regex heurísticas (legacy) ───────────────── { nombre: nodo_nombre, ip: detectar_ip(contenido), @@ -24,7 +54,10 @@ module ADN clave_boveda: detectar_clave_boveda(contenido), auth_type: detectar_auth_type(contenido), clave_ssh: detectar_clave_ssh(contenido), - ssh_opts: detectar_ssh_opts(contenido) + ssh_opts: detectar_ssh_opts(contenido), + ring: nil, + estado: nil, + _fuente: :regex } end @@ -35,6 +68,53 @@ module ADN detectar_ip_lan(contenido) end + # ─── Parser de tabla canónica ────────────────────────────── + + def self.extraer_meta_canonica(contenido) + match = contenido.match(/(.*?)/m) + return nil unless match + + meta = {} + match[1].each_line do |linea| + # | **Campo** | `valor` | o | **Campo** | valor | + if linea =~ /\|\s*\*\*(.+?)\*\*\s*\|\s*`?([^`|]+?)`?\s*\|/ + campo = $1.strip + valor = $2.strip + meta[campo] = valor unless valor.empty? + end + end + + meta.empty? ? nil : meta + end + + def self.extraer_usuario_de_ssh(ssh_str) + return nil unless ssh_str + # Formato: user@ip:port + if ssh_str =~ /^([a-zA-Z0-9_\-\.]+)@/ + return $1 + end + nil + end + + def self.extraer_puerto_de_ssh(ssh_str) + return 22 unless ssh_str + # Formato: user@ip:port + if ssh_str =~ /:(\d+)$/ + return $1.to_i + end + 22 + end + + def self.detectar_so_desde_valor(os_str) + return :linux unless os_str + return :linux if os_str =~ /linux|ubuntu|debian|centos|rocky|proxmox|xen/i + return :windows if os_str =~ /windows|server|win/i + return :firmware if os_str =~ /firmware|hikvision|dvr|mikrotik|routeros/i + :linux + end + + # ─── Regex heurísticas (legacy — para fichas sin META) ───── + def self.detectar_usuario(contenido) # **SSH**: user@ip:port o DOMAIN\user@ip:port if contenido =~ /\*\*SSH\*\*:\s*`?([^`\s(]+)/i @@ -182,3 +262,4 @@ module ADN end end end + diff --git a/adn/tools/cli/ssh.rb b/adn/tools/cli/ssh.rb index 36d536a6..d18e2adb 100644 --- a/adn/tools/cli/ssh.rb +++ b/adn/tools/cli/ssh.rb @@ -21,7 +21,7 @@ require_relative 'nodos/info' module ADN class SubcomandoSSH - CANDADOS_PATH = File.join(ADN::PROJECT_ROOT, 'adn', 'tools', 'seguridad', 'candados.rb') + CANDADOS_PATH = File.join(ADN::PROJECT_ROOT, 'adn', 'tools', 'candados', 'candados.rb') def initialize(args, logger) @args = args @@ -261,17 +261,28 @@ module ADN if proxy_config @logger.info("Via ProxyJump #{config[:proxy]} (#{proxy_config[:ip]})") - proxy_passphrase = obtener_secreto(proxy_config[:clave_boveda]) - # ProxyCommand con sshpass: el proxy usa passphrase RSA, - # el destino usa password. Todo se ejecuta localmente via bash. + # Determinar comando ProxyCommand según auth_type del proxy + proxy_cmd = case proxy_config[:auth_type] + when :passphrase + proxy_passphrase = obtener_secreto(proxy_config[:clave_boveda]) + "sshpass -P passphrase -p '#{proxy_passphrase}' ssh -o StrictHostKeyChecking=no -p #{proxy_config[:puerto_ssh]} -W %h:%p #{proxy_config[:usuario]}@#{proxy_config[:ip]}" + when :key, :rsa + # Proxy usa clave SSH sin passphrase + "ssh -o StrictHostKeyChecking=no -p #{proxy_config[:puerto_ssh]} -W %h:%p #{proxy_config[:usuario]}@#{proxy_config[:ip]}" + else + # Default: ssh sin passphrase + "ssh -o StrictHostKeyChecking=no -p #{proxy_config[:puerto_ssh]} -W %h:%p #{proxy_config[:usuario]}@#{proxy_config[:ip]}" + end + + # ProxyCommand con sshpass: el proxy usa clave/passphrase, el destino usa password script = <<~BASH export SSHPASS=#{password.shellescape} sshpass -e ssh \ -o StrictHostKeyChecking=no \ -o ConnectTimeout=30 \ -o ServerAliveInterval=5 \ - -o ProxyCommand="sshpass -P passphrase -p '#{proxy_passphrase}' ssh -o StrictHostKeyChecking=no -p #{proxy_config[:puerto_ssh]} -W %h:%p #{proxy_config[:usuario]}@#{proxy_config[:ip]}" \ + -o ProxyCommand="#{proxy_cmd}" \ -p #{config[:puerto_ssh]} \ '#{ssh_target}' \ "#{comando_remoto.gsub('"', '\\"')}" diff --git a/docs/ambito/dtic-ADN/A01.P011_Drones-Operaciones-Infra.md b/docs/ambito/dtic-ADN/A01.P011_Drones-Operaciones-Infra.md new file mode 100644 index 00000000..6762f3f9 --- /dev/null +++ b/docs/ambito/dtic-ADN/A01.P011_Drones-Operaciones-Infra.md @@ -0,0 +1,368 @@ +# A01.P011 — Drones de Operaciones: Actualización Automatizada de OS Linux + +> **Estado**: 🟢 Fase 2 en progreso +> **Pertenece a**: [A01 — Ecosistema ADN](./A01_dtic-ADN.md) +> **Relacionado**: [A01.P009 — Evolución Dron ADN](./A01.P009_Evolucion-Dron-ADN.md) +> **Fecha**: 2026-04-13 +> **Responsable**: Lic. Ricardo MONLA +> **Versión**: 3.0 + +--- + +## 📈 Progreso + +``` +Fase 1: ██████████ 100% Parche de Emergencia (hotfix en bkps.rb) ✅ +Fase 2: ████████░░ 80% Desacoplamiento — `dron ops` + candados ✅ +Fase 2.5: ████████░░ 80% Estandarización de Fichas de Nodos 🔧 +Fase 3: ░░░░░░░░░░ 0% Robustez — Pre-flight, Smart Lock, Reboot Check +Fase 4: █████░░░░░ 50% Anillos de Despliegue (--ring habilitado) 🔧 +Fase 5: ░░░░░░░░░░ 0% Observabilidad — Métricas por Nodo +``` + +--- + +## 📋 Resumen Ejecutivo + +Este plan define la evolución de la capacidad de **Operaciones de Infraestructura** dentro del ecosistema ADN, comenzando por la actualización automatizada de sistemas operativos Linux (`apt update/upgrade`) mediante AtomicDrones. + +**Problema raíz:** La funcionalidad de actualizar nodos Linux fue injertada como un parche rápido dentro de la herramienta de backups (`bkps.rb` / `proc_linux.rb`), violando el principio de responsabilidad única y generando acoplamiento semántico incorrecto. Actualizar un OS **no es un backup**. + +**Visión:** Un nuevo subcomando `dron ops` (operaciones) que reutilice la infraestructura existente de ADN (`NodosInfo`, `dron/ejecutor.rb`, Bitácora Web) para orquestar tareas de mantenimiento de infraestructura de forma atómica, visible y desacoplada del sistema de backups. + +--- + +## 🎯 Objetivo + +Crear un sistema de **Drones de Operaciones** dentro del ecosistema ADN que permita: +1. Actualizar sistemas operativos Linux de forma automatizada, desatendida y atómica (1 dron = 1 nodo). +2. Registrar cada operación individualmente en la Bitácora Web con trazabilidad completa. +3. Reutilizar las herramientas ADN existentes (`NodosInfo`, `dron/ejecutor.rb`, `Dron::Base`) sin duplicar código. +4. Desacoplar completamente esta funcionalidad del módulo de backups (`bkps.rb`). + +--- + +## 🔍 Hallazgos y Diagnóstico + +### Auditoría del Estado Actual (2026-04-12) + +| Hallazgo | Severidad | Detalle | +|----------|:---------:|---------| +| **Acoplamiento anómalo** | ✅ Resuelto | `proc_linux.rb` vivía en `bkps/lib/` — ahora existe `dron/ops.rb` independiente | +| **Duplicación de lógica de nodos** | ✅ Resuelto | `ops.rb` reutiliza `NodosInfo.extraer_metadata()` | +| **Orquestación vía bkps** | ✅ Resuelto | Comando nuevo: `dron ops update_os --target linux` | +| **Bloqueo interactivo** | ✅ Resuelto | Corregido con `DEBIAN_FRONTEND=noninteractive` | +| **Falta de candados** | 🟡 Media | Nodos con auth por password ahora usan `candados run` + `sshpass` | +| **Fichas no estandarizadas** | 🔴 Alta | El parser de `NodosInfo` falla en ~40% de fichas por formato libre | + +### Hallazgo Crítico: Fichas de Nodos No Estandarizadas (2026-04-13) + +> **Impacto:** El módulo `NodosInfo` detecta usuarios SSH incorrectos ("Requiere", "El", "Configurado", "ssh") porque las fichas `.md` de nodos no siguen un formato uniforme. Cada nodo fue documentado con estructura distinta. + +| Nodo | Campo SSH en ficha | Usuario detectado | Correcto | +|------|-------------------|:-----------------:|:--------:| +| srvv-dns | `**SSH**: ssh rmonla@10.0.10.2` | `ssh` → corregido a `rmonla` | ✅ (con fallback) | +| srvv-docs | `**Acceso**: Requiere permisos docker` | `Requiere` → corregido a `root` | ⚠️ (fallback) | +| srvv-sitio0 | `**Acceso**: El usuario rmonla...` | `El` → corregido a `root` | ⚠️ (fallback) | +| srvv-nginx-rm | `\| **SSH** \| Puerto 7022, usuario root` | `ssh` → corregido a `root` | ⚠️ (fallback) | +| srvv-nginx-rm | `\| **Bóveda** \| srvv-nginx-rm:root` | No detectado | ❌ falta formato | + +**Causa raíz:** Las fichas `.md` son prosa libre sin campos obligatorios estandarizados. El parser necesita ~15 regex heurísticas para cubrir variantes, y aun así falla. + +### Código Duplicado Eliminado (Fase 2) + +| Función | Antes (proc_linux.rb) | Ahora (ops.rb) | +|---------|:-------------------:|------------------------| +| Detectar si es Linux | `es_nodo_linux?()` 40 líneas | `NodosInfo.detectar_so() == :linux` | +| Extraer IP | `extraer_info_nodo()` regex | `NodosInfo.detectar_ip()` | +| Extraer usuario SSH | regex custom | `NodosInfo.detectar_usuario()` + sanitización | +| Auth por password | No soportado | `candados run` + `sshpass` via `clave_boveda` | + +### Inventario de Flota Linux (13 nodos detectados) + +| Nodo | IP | Rol | Host | +|------|-----|-----|------| +| srv-dasu | 10.0.10.X | Servidor físico | — | +| srv-pmox1 | 10.0.10.201 | Hipervisor Proxmox | — | +| srv-pmox2 | 10.0.10.202 | Hipervisor Proxmox | — | +| srv-pmox3 | 10.0.10.203 | Hipervisor Proxmox | — | +| srv-xen1 | 10.0.10.X | Hipervisor XenServer (legacy) | — | +| srvv-data | 10.0.10.X | VM — Datos | srv-pmoxN | +| srvv-dns | 10.0.10.2 | VM — DNS CoreDNS | srv-pmox1 | +| srvv-docs | 10.0.10.X | VM — Documentación | srv-pmoxN | +| srvv-dtic | 10.0.10.X | VM — Servicios DTIC | srv-pmoxN | +| srvv-koha | 10.0.10.X | VM — Biblioteca Koha | srv-pmoxN | +| srvv-sitio0 | 10.0.10.X | VM — Sitio principal | srv-pmoxN | +| srvv-sitio2 | 10.0.10.X | VM — Sitio secundario | srv-pmoxN | +| srvv-uptime | 10.0.10.X | VM — Monitoreo | srv-pmoxN | + +--- + +## 🗺️ Fases de Implementación + +### Fase 1: Parche de Emergencia (Hotfix en bkps.rb) — ✅ COMPLETA + +**Objetivo:** Lograr que los drones de actualización Linux funcionen mínimamente, aunque acoplados al módulo de backups. + +| ID | Tarea | Estado | +|:--:|-------|:------:| +| F1.T1 | Sustituir `apt` por `apt-get` con `DEBIAN_FRONTEND=noninteractive` | ✅ | +| F1.T2 | Agregar `--force-confdef --force-confold` a DPKG | ✅ | +| F1.T3 | Registrar tipo `linux` en `TIPOS` de `bkps.rb` | ✅ | +| F1.T4 | Corregir `ejecutar_uno()` para leer ficha `.md` del nodo individual | ✅ | +| F1.T5 | Instalar gema `net-ssh` en entorno de usuario | ✅ | +| F1.T6 | Corregir verbo en nota de Bitácora: `🐧 Actualizar` | ✅ | + +**Criterio de éxito:** ✅ `./adn/tools/run bkps orquestar update_linux_nodes --on-error continue` ejecuta 13 drones individuales visibles en Bitácora Web. + +``` +Fase 1: ██████████ 100% ✅ +``` + +--- + +### Fase 2: Desacoplamiento — Nuevo CLI `dron ops` — 🔧 EN PROGRESO + +**Objetivo:** Extraer la lógica de operaciones de infraestructura fuera de `bkps.rb` y crear un subcomando propio dentro del sistema de Drones ADN. + +**Principio:** Reutilizar, no reimplementar. El 80% del código necesario ya existe en ADN Core. + +| ID | Tarea | Descripción | Estado | +|:--:|-------|-------------|:------:| +| F2.T1 | Crear `adn/tools/cli/dron/ops.rb` | Módulo de operaciones de infraestructura | ✅ | +| F2.T2 | Integrar `NodosInfo` como scanner | Filtrado por OS, estado, validación de usuario SSH | ✅ | +| F2.T3 | Conectar con `dron/ejecutor.rb` | Cada nodo = 1 dron ejecutor estándar (auto-bitácora) | ✅ | +| F2.T4 | Registrar en `dispatcher.rb` | Case `'ops'` → `OpsComando.ejecutar(args)` + ayuda CLI | ✅ | +| F2.T5 | Integrar `candados` para auth password | Nodos con `clave_boveda` usan `candados run` + `sshpass` | ✅ | +| F2.T6 | Deprecar `proc_linux.rb` de bkps | Marcar como legacy, redirigir a nuevo módulo | ⏳ | +| F2.T7 | Eliminar `update_linux_nodes` de `bkps.yml` | Limpieza de la configuración de backups | ⏳ | + +**Arquitectura implementada:** + +``` +┌─────────────────────────────────────────────────────────────────┐ +│ ./adn/tools/run dron ops update_os --target linux │ +└───────────────────────────┬─────────────────────────────────────┘ + │ + ▼ +┌─────────────────────────────────────────────────────────────────┐ +│ Dron::Ops (cli/dron/ops.rb) │ +│ │ +│ 1. Scanner: NodosInfo.extraer_metadata(nodo) para cada *.md │ +│ → filtra por OS explícito (Debian/Ubuntu/Proxmox) │ +│ → excluye Windows, firmware, cámaras │ +│ → excluye nodos con estado 🔴 │ +│ → sanitiza usuario SSH (lista negra + fallback user@IP) │ +│ │ +│ 2. Por cada nodo Linux: │ +│ → Si tiene clave_boveda: │ +│ candados run 'sshpass -p $PASS ssh ...' │ +│ → Si no: │ +│ ssh -i user@ip 'apt-get update && upgrade' │ +│ → Dron::Ejecutor.lanzar(cmd, nota) → Bitácora Web │ +└─────────────────────────────────────────────────────────────────┘ +``` + +**Uso actual (funcional):** + +```bash +# Listar nodos Linux con tipo de auth (dry-run) +./adn/tools/run dron ops update_os --target linux --dry-run + +# Ejecutar con continuación ante fallos +./adn/tools/run dron ops update_os --target linux --on-error continue + +# Ejecutar solo un nodo específico +./adn/tools/run dron ops update_os --nodo srvv-dns + +# Ayuda completa +./adn/tools/run dron ops --help +``` + +**Criterio de éxito:** ⚠️ Parcial. El comando funciona y los drones son visibles en Bitácora. Pendiente deprecar `proc_linux.rb` y limpiar `bkps.yml` una vez estandarizadas las fichas. + +``` +Fase 2: ████████░░ 80% +``` + +--- + +### Fase 2.5: Estandarización de Fichas de Nodos — 🔧 EN PROGRESO + +**Objetivo:** Definir un formato canónico obligatorio para las fichas `nodos/*.md` que elimine la ambigüedad del parser `NodosInfo` y habilite operaciones confiables de toda herramienta ADN. + +| ID | Tarea | Descripción | Estado | +|:--:|-------|-------------|:------:| +| F2.5.T1 | Definir formato canónico | Tabla `` / `` con campos fijos | ✅ | +| F2.5.T2 | Migrar fichas existentes | 32/32 fichas migradas (14 Linux + 2 otros + 16 Windows) | ✅ | +| F2.5.T3 | Actualizar `NodosInfo` | Parser dual: tabla canónica primero, regex fallback | ✅ | +| F2.5.T4 | Simplificar `ops.rb` | Eliminadas ~30 líneas de sanitización y regex de contenido | ✅ | +| F2.5.T5 | Validador de fichas | `./adn/tools/run nodos validar` → reporta fichas no conformes | ⏳ | +| F2.5.T6 | Actualizar `generar nodo` | Que la plantilla del generador use el formato canónico | ⏳ | + +**Formato canónico implementado:** + +```markdown +# Nodo: + + +| Campo | Valor | +|:------|:------| +| **Hostname** | `` | +| **IP** | `` | +| **OS** | Debian 12 (Bookworm) | +| **Estado** | 🟢 Online | +| **Rol** | Descripción breve | +| **SSH** | `user@ip:port` | +| **Auth** | `key` / `password` / `rsa_legacy` | +| **Bóveda** | `clave:candados` (solo si auth=password) | +| **Host** | `host-anfitrión` (solo VMs) | +| **VMID** | `123` (solo VMs) | +| **Ring** | `test` / `standard` / `core` | + +``` + +**Resultados:** +- 32/32 fichas migradas con tabla canónica +- `NodosInfo` lee tabla canónica en 1 regex (vs ~15 antes) +- `ops.rb` simplificado: de ~65 líneas de scanner a ~20 +- Nodos Linux detectados: 14 → 17 (se descubrieron `dtic-bitacoras`, `srv-ns8`, `srvv-sitio`) +- `--ring test|standard|core` habilitado en `dron ops` (Fase 4 parcial) + +``` +Fase 2.5: ████████░░ 80% +``` + +--- + +### Fase 3: Robustez — Pre-flight, Smart Lock, Reboot Check + +**Objetivo:** Hacer que cada dron de actualización sea inteligente: que verifique condiciones previas, detecte errores conocidos y reporte el estado post-actualización. + +| ID | Tarea | Descripción | Estado | +|:--:|-------|-------------|:------:| +| F3.T1 | Pre-flight: espacio en disco | Abortar si `/` o `/var` están al >95% | ⏳ | +| F3.T2 | Pre-flight: estado del nodo | Saltar nodos con `**Estado**: 🔴` | ⏳ | +| F3.T3 | Smart Lock detection | Detectar `Could not get lock /var/lib/dpkg/lock` y reportar `❌ dpkg bloqueado` | ⏳ | +| F3.T4 | Reboot Required check | Post-upgrade: `[ -f /var/run/reboot-required ]` → `⚠️ Reboot needed` | ⏳ | +| F3.T5 | Resumen de paquetes actualizados | Capturar cantidad de paquetes actualizados del output de `apt-get` | ⏳ | + +**Flujo enriquecido por nodo:** + +``` + 🐧 Dron update_os para srvv-dns + ├── 🔍 Pre-flight checks + │ ├── Disco /: 61% ✔ + │ ├── Disco /var: OK ✔ + │ └── Estado: 🟢 ✔ + ├── [1/3] apt-get update ✔ + ├── [2/3] apt-get upgrade -y ✔ (4 paquetes) + ├── [3/3] apt-get autoremove -y ✔ + ├── 🔍 Post-flight checks + │ └── reboot-required: NO ✔ + └── ✅ srvv-dns actualizado (47s) +``` + +**Criterio de éxito:** Cero drones con errores silenciosos. Cada falencia conocida tiene su propio código de diagnóstico en la nota de Bitácora. + +``` +Fase 3: ░░░░░░░░░░ 0% +``` + +--- + +### Fase 4: Anillos de Despliegue (Rings) + +**Objetivo:** No actualizar toda la flota de golpe. Dividir los nodos en anillos de criticidad para evitar caídas simultáneas de servicios dependientes. + +| ID | Tarea | Descripción | Estado | +|:--:|-------|-------------|:------:| +| F4.T1 | Definir anillos en `nodos/*.md` | Nuevo campo `**Ring**: test|standard|core` | ⏳ | +| F4.T2 | Ring 0 — Test | Nodos de bajo impacto: srvv-uptime, srvv-sitio2 | ⏳ | +| F4.T3 | Ring 1 — Standard | VMs de servicios: srvv-dns, srvv-docs, srvv-koha | ⏳ | +| F4.T4 | Ring 2 — Core | Hipervisores y data: srv-pmox1/2/3, srvv-data | ⏳ | +| F4.T5 | Pausa entre anillos | Esperar confirmación o timeout entre rings | ⏳ | + +**Uso propuesto:** + +```bash +# Solo nodos de testing +./adn/tools/run dron ops update_os --ring test + +# Despliegue completo con pausa entre anillos +./adn/tools/run dron ops update_os --rings all --pause 300 +``` + +**Criterio de éxito:** Nunca se actualizan los 3 hipervisores Proxmox al mismo tiempo. Los nodos de servicio crítico se actualizan después de validar en el ring de test. + +``` +Fase 4: ░░░░░░░░░░ 0% +``` + +--- + +### Fase 5: Observabilidad — Métricas por Nodo + +**Objetivo:** Historial de actualizaciones por nodo visible en la Bitácora Web. + +| ID | Tarea | Descripción | Estado | +|:--:|-------|-------------|:------:| +| F5.T1 | Registro de versión de OS | Capturar `lsb_release -d` pre y post-update | ⏳ | +| F5.T2 | Historial de updates por nodo | Consulta: "¿Cuándo fue la última actualización de srvv-dns?" | ⏳ | +| F5.T3 | Alerta de nodos atrasados | `dron ops status` → nodos sin update en >30 días | ⏳ | +| F5.T4 | Dashboard de salud de flota OS | Vista consolidada en Bitácora Web | ⏳ | + +**Criterio de éxito:** Con un solo comando se puede ver el estado de actualización de toda la flota Linux, detectando nodos atrasados. + +``` +Fase 5: ░░░░░░░░░░ 0% +``` + +--- + +## 📊 Conclusiones + +### Lo que funciona hoy (Fases 1 + 2 + 2.5) +- **17 nodos Linux** detectados correctamente (incluidos 3 Proxmox, 1 XenServer, srv-ns8). +- **Desacoplamiento logrado:** `dron ops update_os` es subcomando propio del sistema de Drones ADN. +- **Candados integrado:** `srvv-nginx-rm` y futuros nodos con password usan la bóveda. +- **Fichas estandarizadas:** 32/32 con tabla `META:BEGIN` / `META:END`. +- **Rings habilitados:** `--ring test|standard|core` filtra la flota. +- **Dry-run informativo:** Muestra nodo, IP, usuario, auth type y ring. + +### Desbloqueado por la estandarización +- **Parser simplificado:** `NodosInfo` lee tabla canónica con 1 regex (antes ~15). +- **Scanner limpio:** `ops.rb` pasó de ~65 líneas de workarounds a ~20 líneas claras. +- **Nodos descubiertos:** 3 nodos Linux que antes no se detectaban (`dtic-bitacoras`, `srv-ns8`, `srvv-sitio`). +- **Cero falsos positivos:** Cámaras IP, firmware y Windows correctamente excluidos. + +### Métricas de referencia + +| Métrica | Antes | Ahora | +|---------|:-----:|:-----:| +| Nodos Linux detectados | 14 | **17** | +| Nodos Windows (excluidos) | 15 | 14 | +| Total fichas en `nodos/` | 32 | 32 | +| Fichas con tabla canónica | 0 | **32** (100%) | +| Fichas con parseo regex (fallback) | 32 | **0** | +| Regex en NodosInfo (operativas) | ~15 | **1** (canónica) | +| Nodos con auth `key` | 13 | **16** | +| Nodos con auth `candados` | 0 | **1** (srvv-nginx-rm) | +| Líneas de scanner en `ops.rb` | ~65 | **~20** | +| Falsos positivos en dry-run | ~2 | **0** | + +--- + +## 📎 Referencias + +- [A01.P009 — Evolución Dron ADN](./A01.P009_Evolucion-Dron-ADN.md) — Plan maestro de AtomicDrones +- `adn/tools/cli/dron/ops.rb` — **Módulo nuevo de operaciones** (Fase 2, activo) +- `adn/tools/cli/dron/dispatcher.rb` — Dispatcher con `ops` registrado +- `adn/tools/cli/dron/ejecutor.rb` — Ejecutor atómico con auto-bitácora +- `adn/tools/cli/nodos/info.rb` — Módulo `NodosInfo` (scanner de fichas) +- `adn/tools/candados/candados.rb` — Bóveda de credenciales +- `adn/tools/bkps/lib/proc_linux.rb` — Implementación legacy (Fase 1, a deprecar) + +--- + +*Plan actualizado 2026-04-13 — Versión 3.0* diff --git a/docs/ambito/dtic-ADN/A01.P012_Pipeline-Drones-Intercomunicacion.md b/docs/ambito/dtic-ADN/A01.P012_Pipeline-Drones-Intercomunicacion.md new file mode 100644 index 00000000..920d8619 --- /dev/null +++ b/docs/ambito/dtic-ADN/A01.P012_Pipeline-Drones-Intercomunicacion.md @@ -0,0 +1,640 @@ +# A01.P012 — Pipeline de Drones para Backup y Restauración de DASUTEN + +> **Estado**: 🟢 Pipeline implementado (2026-04-14) +> **Pertenece a**: [A01 — Ecosistema ADN](./A01_dtic-ADN.md) +> **Relacionado**: [A01.P009 — Evolución Dron ADN](./A01.P009_Evolucion-Dron-ADN.md) +> **Caso de Uso**: [A04.P005 — DASUTEN sin DC](../dtic-DASUTEN/A04.P005_DASUTEN-sin-DC.md) +> **Fecha**: 2026-04-14 +> **Responsable**: Lic. Ricardo MONLA +> **Versión**: 2.0 — Con verificación de consistencia (DBCC CHECKDB) de BD + +--- + +## 📈 Progreso + +``` +Fase 0: ██████████ 100% Diseño de Arquitectura de Pipeline ✅ +Fase 1: ██████████ 100% Drones Atómicos Fragmentados ✅ +Fase 1.5: ██████████ 100% Orquestador con Intercomunicación JSON ✅ +Fase 1.7: ██████████ 100% Implementación Real — Pipeline DASUTEN ✅ (2026-04-14) +Fase 1.8: ██████████ 100% Verificación de Consistencia (DBCC CHECKDB) ✅ +Fase 1.9: ██████████ 100% Pipeline Diferencial (Refresco diario) ✅ +Fase 2: ░░░░░░░░░░ 0% Persistencia en Bitácora — Outputs en DB +Fase 3: ░░░░░░░░░░ 0% Reintentos Automáticos — Retry con backoff +Fase 4: ░░░░░░░░░░ 0% Condicionales — Skip si output indica "ya hecho" +``` + +--- + +## 📋 Resumen Ejecutivo + +Este plan documenta el **Pipeline de Drones para Backup y Restauración de DASUTEN** — una implementación real donde múltiples drones atómicos se encadenan para formar el flujo de refresco de base de datos (Fase 8b), comunicándose entre sí mediante **archivos JSON** que actúan como medio de intercambio de contexto. + +**Caso de uso:** Refresco de la base de datos `sysdasuten` desde `srvv-fenix` (producción) hasta `dasu-sql4` (nuevo servidor), pasando por Google Drive como intermediario. + +**Problema resuelto:** Transferir 1.3 GB de backup entre servidores sin dependencia de Tailscale inestable, usando Google Drive como puente y verificando integridad con DBCC CHECKDB. + +**Solución:** Un **orquestador** que: +1. Lanza 6 drones atómicos secuencialmente +2. Lee el output JSON de cada dron completado +3. Inyecta el contexto en el siguiente dron +4. Decide continuar o abortar según el resultado + +### Convención de Nombres (desde 2026-04-14) + +``` +dasuten__.rb + +Ejemplos: +- dasuten_exportar_srvv-fenix.rb (acción en nodo específico) +- dasuten_transferir_srvv-fenix-srv-ns8.rb (transferencia entre nodos) +- dasuten_upload_srv-ns8-drive.rb (upload desde nodo a Drive) +``` + +--- + +## 🎯 Objetivo + +Implementar un **Pipeline de Drones para el refresco de BD de DASUTEN** que permita: + +1. **Fragmentar el flujo de backup** en 6 drones atómicos independientes (1 dron = 1 paso) +2. **Intercomunicar drones** mediante archivos JSON estandarizados (`/tmp/dron_*_output.json`) +3. **Orquestar el refresco completo** con un solo comando desde `srv-ns8` +4. **Registrar trazabilidad** de cada paso en la Bitácora Web +5. **Permitir re-ejecución** de pasos individuales sin re-correr todo el pipeline +6. **Verificar integridad** de la BD restaurada con `DBCC CHECKDB` + +--- + +## 🏗️ Arquitectura del Pipeline + +### Diagrama de Flujo (6 Drones Atómicos) + +``` +┌──────────────────────────────────────────────────────────────────────────┐ +│ ORQUESTADOR (orquestador_pipeline.rb) │ +│ │ +│ ┌────────────────────────────────────────────────────────────────────┐ │ +│ │ Contexto Compartido (Hash Ruby) │ │ +│ │ - backup_ruta: ruta del archivo .bak │ │ +│ │ - drive_ruta: URL de Google Drive │ │ +│ │ - estado_integridad: resultado de DBCC CHECKDB │ │ +│ │ - duracion_total: suma de duraciones de drones │ │ +│ └────────────────────────────────────────────────────────────────────┘ │ +└──────────────────────────────────────────────────────────────────────────┘ + │ + │ 1. Lanza dron + ▼ +┌─────────────────┐ +│ DRON: │ Nodo: srvv-fenix +│ exportar │ Tarea: BACKUP DATABASE WITH COMPRESSION +│ │ Output: /tmp/dron_export_output.json +└─────────────────┘ + │ + │ 2. Orquestador lee JSON, extrae backup_ruta + ▼ +┌─────────────────┐ +│ DRON: │ Nodo: srv-ns8 +│ transferir │ Tarea: smbclient //fenix/BK_SQL → /var/tmp/ +│ │ Output: /tmp/dron_transfer_output.json +└─────────────────┘ + │ + │ 3. Orquestador lee JSON, extrae backup_local + ▼ +┌─────────────────┐ +│ DRON: │ Nodo: srv-ns8 +│ upload │ Tarea: rclone copy → Google Drive +│ │ Output: /tmp/dron_upload_output.json +└─────────────────┘ + │ + │ 4. Orquestador lee JSON, extrae drive_ruta + ▼ +┌─────────────────┐ +│ DRON: │ Nodo: dasu-sql4 +│ download │ Tarea: Invoke-WebRequest ← Google Drive +│ │ Output: /tmp/dron_download_output.json +└─────────────────┘ + │ + │ 5. Orquestador lee JSON, extrae backup_local + ▼ +┌─────────────────┐ +│ DRON: │ Nodo: dasu-sql4 +│ restaurar │ Tarea: RESTORE DATABASE (sin CHECKDB) +│ │ Output: /tmp/dron_restore_output.json +└─────────────────┘ + │ + │ 6. Orquestador lee JSON, decide verificar + ▼ +┌─────────────────┐ +│ DRON: │ Nodo: dasu-sql4 +│ verificar │ Tarea: DBCC CHECKDB + validaciones +│ │ Output: /tmp/dron_verify_output.json +└─────────────────┘ + │ + ▼ + ✅ PIPELINE COMPLETADO (6 drones) +``` + +--- + +## 🧩 Drones Atómicos del Pipeline (6 drones) + +Cada dron es **independiente**, **autocontenido** y **auto-bitácorado**. + +### Dron 1: `dasuten_exportar_srvv-fenix.rb` + +| Campo | Valor | +|-------|-------| +| **Nodo** | `srvv-fenix` | +| **Tarea** | Generar backup comprimido en SQL Server | +| **Comando** | `BACKUP DATABASE sysdasuten TO DISK = ... WITH COMPRESSION` | +| **Output File** | `/tmp/dron_export_output.json` | +| **Output Clave** | `backup_ruta` | + +**Output JSON:** +```json +{ + "paso": "export_complete", + "backup_ruta": "E:\\BK_SQL\\sysdasuten_compressed_ADN.bak", + "nodo": "srvv-fenix", + "duracion": 45.2, + "timestamp": "2026-04-14T10:00:00-03:00", + "siguiente_paso": "transferir" +} +``` + +--- + +### Dron 2: `dasuten_transferir_srvv-fenix-srv-ns8.rb` + +| Campo | Valor | +|-------|-------| +| **Nodo** | `srv-ns8` | +| **Tarea** | Descargar backup desde srvv-fenix vía SMB | +| **Comando** | `smbclient //10.0.10.200/BK_SQL -c "get sysdasuten_compressed_ADN.bak"` | +| **Output File** | `/tmp/dron_transfer_output.json` | +| **Output Clave** | `backup_local` | + +**Output JSON:** +```json +{ + "paso": "transfer_complete", + "backup_local": "/var/tmp/sysdasuten_compressed_ADN.bak", + "nodo": "srv-ns8", + "duracion": 120.5, + "timestamp": "2026-04-14T10:02:00-03:00", + "siguiente_paso": "upload" +} +``` + +--- + +### Dron 3: `dasuten_upload_srv-ns8-drive.rb` + +| Campo | Valor | +|-------|-------| +| **Nodo** | `srv-ns8` | +| **Tarea** | Subir backup a Google Drive vía rclone | +| **Comando** | `rclone copy /var/tmp/... rmonla-GDrive:drive_bkps-dasu/...` | +| **Output File** | `/tmp/dron_upload_output.json` | +| **Output Clave** | `drive_ruta` | + +**Output JSON:** +```json +{ + "paso": "upload_complete", + "drive_ruta": "rmonla-GDrive:drive_bkps-dasu/sysdasuten_compressed_ADN_20260414_100500.bak", + "drive_url": "https://drive.google.com/drive/folders/1Tgrn2QYyWf0v0eyY1bSGCLlhiqhtIA2n", + "nodo": "srv-ns8", + "duracion": 180.5, + "timestamp": "2026-04-14T10:05:00-03:00", + "siguiente_paso": "download" +} +``` + +--- + +### Dron 4: `dasuten_download_drive-dasu-sql4.rb` + +| Campo | Valor | +|-------|-------| +| **Nodo** | `dasu-sql4` | +| **Tarea** | Descargar backup desde Google Drive vía HTTP | +| **Comando** | `Invoke-WebRequest -Uri "https://drive.usercontent.google.com/download?id=..."` | +| **Output File** | `/tmp/dron_download_output.json` | +| **Output Clave** | `backup_local` | + +**Output JSON:** +```json +{ + "paso": "download_complete", + "backup_local": "F:\\BACKUP\\sysdasuten_compressed_ADN.bak", + "drive_origen": "rmonla-GDrive:drive_bkps-dasu/sysdasuten_compressed_ADN_20260414_100500.bak", + "nodo": "dasu-sql4", + "duracion": 150.3, + "timestamp": "2026-04-14T10:08:00-03:00", + "siguiente_paso": "restaurar_backup" +} +``` + +--- + +### Dron 5: `dasuten_restaurar_dasu-sql4.rb` + +| Campo | Valor | +|-------|-------| +| **Nodo** | `dasu-sql4` | +| **Tarea** | Restaurar backup (solo RESTORE, sin CHECKDB) | +| **Comando** | `RESTORE DATABASE ... WITH REPLACE, MOVE ...` | +| **Output File** | `/tmp/dron_restore_output.json` | +| **Output Clave** | `estado_integridad=PENDING_CHECKDB` | + +**Output JSON:** +```json +{ + "paso": "restore_complete", + "backup_ruta": "F:\\BACKUP\\sysdasuten_compressed_ADN.bak", + "nodo": "dasu-sql4", + "duracion_restore": 0.23, + "estado_integridad": "PENDING_CHECKDB", + "timestamp": "2026-04-14T10:10:00-03:00", + "siguiente_paso": "verificar_integridad" +} +``` + +--- + +### Dron 6: `dasuten_verificar-integridad_dasu-sql4.rb` + +| Campo | Valor | +|-------|-------| +| **Nodo** | `dasu-sql4` | +| **Tarea** | Verificar integridad con DBCC CHECKDB | +| **Comando** | `DBCC CHECKDB('sysdasuten') WITH NO_INFOMSGS, ALL_ERRORMSGS` | +| **Output File** | `/tmp/dron_verify_output.json` | +| **Output Clave** | `estado_integridad`, `pipeline_completo` | + +**Output JSON:** +```json +{ + "paso": "verify_complete", + "nodo": "dasu-sql4", + "duracion_checkdb": 248.56, + "estado_integridad": "OK", + "paginas_verificadas": 1186793, + "timestamp": "2026-04-14T10:14:00-03:00", + "pipeline_completo": true +} +``` + +--- + +## 🎼 Orquestador: `orquestador_pipeline.rb` + +El orquestador es el **cerebro** del pipeline. No ejecuta tareas directamente, sino que: + +1. **Lanza drones** secuencialmente vía `dron lanzar` +2. **Lee outputs JSON** de cada dron completado +3. **Inyecta contexto** en el siguiente dron (vía ENV o argumentos) +4. **Decide continuar** o abortar según exito/fracaso +5. **Registra estado** en la Bitácora Web + +### Código del Orquestador (simplificado) + +```ruby +#!/usr/bin/env ruby +# adn/tools/cli/drones/orquestador_pipeline.rb + +ESTADOS = { + exportar: { + script: 'dasuten_exportar.rb', + nodo: 'srvv-fenix', + nota: '📤 Exportar backup DASUTEN', + output_file: '/tmp/dron_export_output.json', + siguiente: :upload + }, + upload: { + script: 'dasuten_upload_drive.rb', + nodo: 'srv-ns8', + nota: '☁️ Upload a Google Drive', + output_file: '/tmp/dron_upload_output.json', + siguiente: :download + }, + # ... más pasos +}.freeze + +def lanzar_dron(script, nodo, nota, timeout) + cmd = "#{ADN_RUN} dron lanzar --nota #{nota} --nodo #{nodo} --timeout #{timeout} -- ruby #{script}" + exito = system(cmd) + + if exito + # Leer output del dron + output_file = ESTADOS[nodo.to_sym][:output_file] + resultado = JSON.parse(File.read(output_file)) if File.exist?(output_file) + return true, resultado + else + return false, {} + end +end + +# Ejecutar pipeline +paso_actual = :exportar +contexto = {} + +loop do + break unless ESTADOS[paso_actual] + + config = ESTADOS[paso_actual] + exito, resultado = lanzar_dron(config[:script], config[:nodo], config[:nota], timeout) + + unless exito + puts "❌ Pipeline fallido en paso: #{paso_actual}" + exit 1 + end + + contexto.merge!(resultado) + + if config[:siguiente] + paso_actual = config[:siguiente] + else + puts "✅ Pipeline completado!" + break + end +end +``` + +--- + +## 🚀 Uso del Pipeline + +### Ejecutar Pipeline Completo + +```bash +# Pipeline completo (todos los pasos encadenados) +./adn/tools/run dron lanzar --nota "Pipeline DASUTEN 8b" -- \ + ruby adn/tools/cli/drones/orquestador_pipeline.rb +``` + +### Ejecutar Drones Individualmente + +```bash +# Paso 1: Exportar backup +./adn/tools/run dron lanzar --nota "Exportar backup" --nodo srvv-fenix -- \ + ruby adn/tools/cli/drones/dasuten_exportar.rb + +# Paso 2: Upload a Drive +./adn/tools/run dron lanzar --nota "Upload Drive" --nodo srv-ns8 -- \ + ruby adn/tools/cli/drones/dasuten_upload_drive.rb + +# Paso 3: Download desde Drive +./adn/tools/run dron lanzar --nota "Download Drive" --nodo dasu-sql4 -- \ + ruby adn/tools/cli/drones/dasuten_download_drive.rb + +# Paso 4: Restaurar backup +./adn/tools/run dron lanzar --nota "Restaurar backup" --nodo dasu-sql4 -- \ + ruby adn/tools/cli/drones/dasuten_restaurar.rb +``` + +### Ejecutar desde un Paso Específico + +```bash +# Comenzar desde upload (saltear export) +./adn/tools/run dron lanzar --nota "Pipeline DASUTEN" -- \ + ruby adn/tools/cli/drones/orquestador_pipeline.rb --paso upload +``` + +### Dry-Run (Simulación) + +```bash +# Ver qué haría sin ejecutar +./adn/tools/run dron lanzar --nota "Pipeline DASUTEN" -- \ + ruby adn/tools/cli/drones/orquestador_pipeline.rb --dry-run +``` + +--- + +## 📊 Ventajas de esta Arquitectura + +| Ventaja | Descripción | +|---------|-------------| +| **🧩 Atomicidad** | Cada dron hace UNA cosa. Fácil de testear, debuggear, reemplazar. | +| **🔗 Intercomunicación** | JSON como contrato entre drones. Lenguaje-agnóstico. | +| **🔄 Re-ejecución** | Si falla el paso 3, re-ejecutar solo paso 3 (no todo el pipeline). | +| **👁️ Observabilidad** | Cada dron se registra individualmente en Bitácora Web. | +| **🛡️ Tolerancia a Fallos** | Si un dron falla, el pipeline se detiene (fail-fast). | +| **📈 Escalabilidad** | Agregar nuevos pasos = agregar nuevo dron + registrar en ESTADOS. | + +--- + +## 📁 Estructura de Archivos + +``` +adn/tools/cli/drones/ +├── orquestador_pipeline.rb # Orquestador principal +├── dasuten_exportar.rb # Dron 1: Exportar backup +├── dasuten_upload_drive.rb # Dron 2: Upload a Drive +├── dasuten_download_drive.rb # Dron 3: Download desde Drive +└── dasuten_restaurar.rb # Dron 4: Restaurar backup + +/tmp/ +├── dron_export_output.json # Output del dron 1 +├── dron_upload_output.json # Output del dron 2 +├── dron_download_output.json # Output del dron 3 +└── dron_restore_output.json # Output del dron 4 +``` + +--- + +## 🔮 Futuras Mejoras (Fases Pendientes) + +### Fase 2: Persistencia en Bitácora + +Actualmente los outputs JSON son efímeros (`/tmp/`). La **Fase 2** persistirá los outputs en la Bitácora Web: + +```ruby +# En dron_db.rb +CREATE TABLE drone_outputs ( + id SERIAL PRIMARY KEY, + dron_id VARCHAR(50) REFERENCES drones(dron_id), + output JSONB NOT NULL, + created_at TIMESTAMP DEFAULT NOW() +); + +-- El orquestador puede leer outputs de la DB en lugar de archivos +output = DronDB.obtener_output(dron_id) +``` + +### Fase 3: Reintentos Automáticos + +```ruby +# Orquestador con retry +def lanzar_dron_con_retry(script, nodo, nota, timeout, max_retries: 3) + max_retries.times do |intento| + exito, resultado = lanzar_dron(script, nodo, nota, timeout) + return true, resultado if exito + + puts "⚠ Dron falló (intento #{intento + 1}/#{max_retries})" + sleep(2 ** intento) # Backoff exponencial + end + return false, {} +end +``` + +### Fase 4: Condicionales de Skip + +```ruby +# Skip si ya está hecho +def deberia_ejecutar?(paso, contexto) + case paso + when :upload + # Skip si ya hay backup reciente en Drive + !backup_reciente_en_drive?(contexto[:backup_ruta]) + when :restaurar + # Skip si BD ya está actualizada + !bd_actualizada?(contexto[:backup_local]) + else + true + end +end +``` + +--- + +## 📝 Lecciones Aprendidas + +### ✅ Lo que Funcionó + +| Lección | Descripción | +|---------|-------------| +| **JSON como contrato** | Simple, legible, lenguaje-agnóstico. Funciona mejor que DB compartida. | +| **Outputs en /tmp** | Fácil de limpiar, no requiere permisos especiales. | +| **Orquestador stateless** | El estado está en los JSONs, no en el orquestador. | +| **Drones auto-bitácora** | Cada dron se registra individualmente en la Bitácora Web. | +| **Google Drive como intermediario** | Elimina dependencia de Tailscale inestable. Download HTTP directo desde dasu-sql4. | +| **Base64 encoding para PowerShell** | Evita problemas de escaping UTF-8 al transportar scripts sobre SSH. | +| **sshpass + ProxyCommand** | Patrón efectivo para acceder a VMs detrás de relay (dasu-sql4 detrás de srv-dasu). | + +### 📊 Resultados del Pipeline DASUTEN (2026-04-14) + +| Métrica | Valor | +|---------|-------| +| **Archivo transferido** | 1.3 GB (`sysdasuten_compressed_ADN.bak`) | +| **Tiempo total de pipeline** | ~35 minutos | +| **Upload a Drive** | 29 minutos (1736s) — limitado por ancho de banda | +| **Download HTTP** | ~5 minutos — con confirmación de virus manejada | +| **Restore SQL** | 0.23 segundos — MOVE instantáneo | +| **DBCC CHECKDB** | 248.56 segundos — **Integridad: OK** | +| **Throughput efectivo** | ~650 KB/s (limitado por subida a Drive) | + +### ⚠️ Lo que Requiere Atención + +| Lección | Descripción | +|---------|-------------| +| **Limpieza de archivos** | Los JSONs en `/tmp/` deben limpiarse post-pipeline. | +| **Timeouts por dron** | Cada dron debe tener timeout individual (no todos duran lo mismo). | +| **Manejo de errores** | El orquestador debe capturar stderr de cada dron para debugging. | + +### 🔧 Desafíos Superados + +| Desafío | Solución | +|---------|----------| +| **Virus confirmation page** | Parseo de HTML con regex PowerShell para extraer `id`, `uuid`, `confirm` | +| **dasu-sql4 sleep mode** | Acceso vía relay SSH desde srv-dasu con `sshpass -e` + ProxyCommand | +| **PowerShell escaping** | Base64 encoding del script completo + heredoc con `'PSCMD'` (sin interpolación) | +| **sqlcmd no disponible en PATH** | Usar ruta completa: `C:\Program Files\...\sqlcmd.exe` | + +--- + +## 🔗 Referencias + +- **Ámbito**: [A01_dtic-ADN.md](./A01_dtic-ADN.md) +- **Evolución Dron**: [A01.P009_Evolucion-Dron-ADN.md](./A01.P009_Evolucion-Dron-ADN.md) +- **Drones Ops**: [A01.P011_Drones-Operaciones-Infra.md](./A01.P011_Drones-Operaciones-Infra.md) +- **Caso de Uso**: [A04.P005_DASUTEN-sin-DC.md](../dtic-DASUTEN/A04.P005_DASUTEN-sin-DC.md) — Pipeline implementado para Fase 8b + +--- + +## 📊 Estado del Pipeline DASUTEN (6 drones atómicos) + +| Paso | Estado | Dron | Nodo | Output | Duración | +|------|--------|------|------|--------|----------| +| **8b.1** | ✅ Completado | `dasuten_exportar_srvv-fenix.rb` | srvv-fenix | `backup_ruta` | 44.8s | +| **8b.2** | ✅ Completado | `dasuten_transferir_srvv-fenix-srv-ns8.rb` | srv-ns8 | `backup_local` | ~2 min | +| **8b.3** | ✅ Completado | `dasuten_upload_srv-ns8-drive.rb` | srv-ns8 | `drive_ruta` | 1736s (29 min) | +| **8b.4** | ✅ Completado | `dasuten_download_drive-dasu-sql4.rb` | dasu-sql4 | `backup_local` | ~5 min | +| **8b.5** | ✅ Completado | `dasuten_restaurar_dasu-sql4.rb` | dasu-sql4 | `estado_integridad=PENDING` | 0.23s | +| **8b.6** | ✅ Completado | `dasuten_verificar-integridad_dasu-sql4.rb` | dasu-sql4 | `estado_integridad=OK` | 248.56s | + +**Pipeline completado exitosamente el 2026-04-14 a las 17:21.** + +### Resultados Finales +- **Backup comprimido:** 1.3 GB (`sysdasuten_compressed_ADN.bak`) +- **Google Drive URL:** `rmonla-GDrive:drive_bkps-dasu/sysdasuten_compressed_ADN_20260414_*.bak` +- **Download HTTP directo:** Con confirmación de virus manejada (formulario HTML parsing) +- **Restore:** 0.23 segundos (MOVE a F:\DATA y F:\LOG) +- **DBCC CHECKDB:** 248.56 segundos — **Integridad: OK** (1,186,793 páginas verificadas, sin errores) +- **Duración total del pipeline:** ~35 minutos + +--- + +## 🔄 Pipeline Diferencial (Refresco Diario) + +Para refrescos diarios de la base de datos, se recomienda usar **backup diferencial** que solo transfiere los cambios desde el último backup completo. + +### Ventajas del Pipeline Diferencial + +| Métrica | Completo | Diferencial | +|---------|----------|-------------| +| **Tamaño backup** | 1.3 GB | ~50-100 MB* | +| **Tiempo export** | 45 seg | ~5-10 seg | +| **Tiempo upload** | 29 min | ~2-3 min | +| **Tiempo download** | ~5 min | ~30 seg | +| **Tiempo total** | ~35 min | ~5-10 min | + +\* Depende de la cantidad de cambios diarios + +### Drones del Pipeline Diferencial + +| Paso | Dron | Nodo | Tarea | +|------|------|------|-------| +| **1** | `dasuten_exportar_diferencial_srvv-fenix.rb` | srvv-fenix | `BACKUP DATABASE ... WITH DIFFERENTIAL` | +| **2** | `dasuten_transferir_srvv-fenix-srv-ns8.rb` | srv-ns8 | SMB → `/var/tmp/` | +| **3** | `dasuten_upload_srv-ns8-drive.rb` | srv-ns8 | rclone → Google Drive | +| **4** | `dasuten_download_drive-dasu-sql4.rb` | dasu-sql4 | HTTP ← Google Drive | +| **5** | `dasuten_restaurar_diferencial_dasu-sql4.rb` | dasu-sql4 | `RESTORE ... WITH DIFFERENTIAL` + `RECOVERY` | +| **6** | `dasuten_verificar-integridad_dasu-sql4.rb` | dasu-sql4 | `DBCC CHECKDB` | + +### Orquestador Diferencial + +```bash +# Ejecutar pipeline diferencial completo +./adn/tools/run dron lanzar --nota "Refresco Diario DASUTEN" -- \ + ruby adn/tools/cli/drones/orquestador_pipeline_diferencial.rb +``` + +### Estrategia Recomendada + +| Día | Tipo de Backup | Duración Estimada | +|-----|----------------|-------------------| +| **Lunes** | Completo | ~35 min | +| **Martes** | Diferencial | ~5-10 min | +| **Miércoles** | Diferencial | ~5-10 min | +| **Jueves** | Diferencial | ~5-10 min | +| **Viernes** | Diferencial | ~5-10 min | +| **Sábado** | Diferencial | ~5-10 min | +| **Domingo** | — (sin cambios) | — | + +### Consideraciones Importantes + +1. **El backup diferencial se basa en el último backup completo**, no en el diferencial anterior +2. **Cada diferencial es acumulativo** — el martes tiene cambios desde lunes, el miércoles tiene cambios desde lunes (no desde martes) +3. **Restaurar diferencial requiere:** + - Último backup completo (ya restaurado en dasu-sql4) + - Backup diferencial más reciente + - `WITH NORECOVERY` para aplicar diferencial, luego `WITH RECOVERY` para poner BD online + +--- + +*Documento creado: 2026-04-14* +*Última actualización: 2026-04-14* +*Versión: 2.1 — Con pipeline diferencial* diff --git a/docs/ambito/dtic-DASUTEN/A04.P005_DASUTEN-sin-DC.md b/docs/ambito/dtic-DASUTEN/A04.P005_DASUTEN-sin-DC.md index 0dfa74bb..0cf41ddb 100644 --- a/docs/ambito/dtic-DASUTEN/A04.P005_DASUTEN-sin-DC.md +++ b/docs/ambito/dtic-DASUTEN/A04.P005_DASUTEN-sin-DC.md @@ -5,8 +5,8 @@ **Código:** A04.P005 **Fecha:** 27 de marzo de 2026 **Autor:** Sistema ADN -**Versión:** 4.0 -**Estado:** 🚧 EN EJECUCIÓN (F5 completada — BD restaurada, pendiente validación con PC cliente) +**Versión:** 5.3 +**Estado:** 🚧 EN EJECUCIÓN (F8b — Refresco final de BD pendiente) **Dependencia:** A04.P001 (Red srv-dasu) ## 📊 Progreso General @@ -17,7 +17,11 @@ - **Fase 4: Nueva VM dasu-sql4** [██████████] 100% (12/12) ✅ - **Fase 5: Migración BD** [██████████] 100% (5/5) ✅ - **Fase 5b: Hardening** [██████████] 100% (4/4) ✅ -- **Fase 6: Validación** [█░░░░░░░░░] 9% (1/10) 🚧 +- **Fase 6: Validación** [██████████] 100% (10/10) ✅ +- **Fase 7: PC Física** [██████████] 100% (9/9) ✅ +- **Fase 8: Refresco BD** [██████████] 100% (4/4) ✅ +- **Fase 8b: Refresco Final** [██████████] 100% (4/4) ✅ ¡COMPLETADA! +- **Fase 9: Cierre** [░░░░░░░░░░] 0% (0/4) ⏳ ## 📋 Resumen Ejecutivo @@ -169,7 +173,7 @@ Crear dos VMs nuevas (SQL Server + PC cliente) en `srv-dasu`, instalar el sistem - [x] **6.10:** **Decisión**: ¿Se puede prescindir del DC definitivamente? - ✅ **SÍ** → El esquema Workgroup es 100% viable. Se valida que el cliente DASUTEN funciona modificando el `Kermet.ini`. Con esta prueba exitosa en la máquina virtual cliente (Test-Bed `dasu-pcv`), procedemos oficialmente a desplegar este esquema en Producción Física. -### 🚀 **FASE 7: Migración a Producción (PC Física)** *(A iniciar 2026-04-11)* +### 🚧 **FASE 7: Migración a Producción (PC Física)** *(En curso 2026-04-13)* > **Contexto:** Habiendo superado con éxito la reingeniería en el entorno controlado de la VM de prueba (`dasu-pcv`), el objetivo ahora es trasladar esta misma configuración (Workgroup + Configuración DB directa) a la PC física real operada por la usuaria de DASUTEN. @@ -177,20 +181,61 @@ Crear dos VMs nuevas (SQL Server + PC cliente) en `srv-dasu`, instalar el sistem > **Motivo:** Para que la resolución de nombres NetBIOS funcione de manera más armónica y el firewall perciba los nodos como "Red Privada" simétrica, todos los participantes deben pertenecer estrictamente al Group `DASUTEN`. - [x] **PC Cliente Virtual (`dasu-pcv`):** Grupo `DASUTEN` asignado previamente. ✅ - [x] **Servidor SQL (`dasu-sql4`):** Modificar grupo de trabajo actual a `DASUTEN`. ✅ (Aplicado remotamente vía SSH) -- [ ] **PC Física (`dasu-pc`):** Se modificará a `DASUTEN` durante el relevamiento. +- [x] **PC Física (`dasu-pc`):** Ya estaba en Workgroup `DASUTEN`. ✅ *(Confirmado 2026-04-13)* -#### 7.2 Relevamiento de la PC Física -- [ ] **Acceso inicial:** Gestionar acceso por AnyDesk/TeamViewer a la PC física de la entidad. -- [ ] **Validar estado actual:** Corroborar si aún sigue atada al dominio antiguo y si la usuaria está utilizando un perfil local o de dominio cacheado para evitar pérdida de archivos al mover a Workgroup. -- [ ] **Configuración DASUTEN previo:** Backup preventivo de su directorio `C:\SysDasuten\Sistema\Kermet.ini`. +#### 7.2 Relevamiento y Despliegue en PC Física *(completado 2026-04-13)* +- [x] **Acceso inicial:** SSH habilitado (`UTNLR@100.119.233.11:7022`). Tailscale y AnyDesk activos. ✅ +- [x] **Validar estado actual:** Win10 Pro, Workgroup `DASUTEN`, hostname `dasu-pc`, perfil local `aalmiron`. ✅ +- [x] **Despliegue SysDasuten:** `C:\SysDasuten` no existía previamente. Se copió el directorio completo desde `dasu-pcv` (montaje disco VM NTFS → tar.gz → HTTP LAN srv-dasu:8080 → PowerShell download → extracción). ✅ +- [x] **Kermet.ini verificado:** `SERVER=dasu-sql4`, `UID=sa`, `DATABASE=sysdasuten`. ✅ +- [x] **Acceso directo creado** en el escritorio de `aalmiron`. ✅ *(El .lnk generado por WScript.Shell no funcionó; se recreó manualmente).* -#### 7.2 Migración de Configuración en PC Física -- [ ] **Ajuste Workgroup:** Desvincular del dominio obsoleto y agregar al grupo de trabajo `DASUTEN` sin afectar la información local. -- [ ] **Re-conexión al SQL (Nuevo esquema):** Inyectar el `Kermet.ini` modificado con `UID=sa` y **`SERVER=dasu-sql4`**. *(Nota: Se comprobó que usar el Hostname en lugar de la IP funciona perfectamente gracias a la resolución de nombres del grupo de trabajo compartido, otorgando resiliencia ante rotación del DHCP).* -- [ ] **Pruebas de Usuario Final:** Loguearse al sistema con credenciales productivas y validar. +#### 7.3 Prueba Funcional con Usuaria *(parcial 2026-04-13)* +> **Usuaria:** Andrea Almirón (`aalmiron`) -#### 7.3 Destrucción Ecosistema Antiguo -- [ ] Proceder al apagado seguro de las VMs legacy que sostenían el Active Directory (VM 100, VM 101). +- [x] **Inicio rápido del sistema:** ✅ OK — Arranca sin errores. +- [x] **Acceso a ventana de bonos:** ✅ OK — Datos visibles y navegables. +- [x] **Impresión desde el sistema:** ✅ OK — **RESUELTO (2026-04-14)**. El symlink `C:\Sistema → C:\SysDasuten\Sistema` fue la solución definitiva. Las plantillas Word/Excel se localizan correctamente. + +#### 7.4 Workaround Temporario *(resuelto 2026-04-13)* +> Mientras se resuelve el problema de impresión, se solicitó a la usuaria que continúe operando mediante el sistema anterior (vía acceso remoto a `dasu-pcv`). +- [x] **RustDesk reinstalado en dasu-pcv:** ❌ No resolvió inicialmente. Se actualizaron también las claves Kaspersky (antivirus vencido causaba cortes de red). Persistió el problema. +- [x] **Verificación cruzada desde srv-ns8:** ❌ Confirmado: RustDesk no conecta desde ningún nodo → problema con los servidores relay propios de RustDesk (no es local). +- [x] **Solución provisional: TeamViewer instalado** en ambas máquinas (dasu-pcv + dasu-pc). Interconexión configurada y verificada con éxito. ✅ +- [x] **Usuaria informada:** Operando en sistema legacy vía TeamViewer mientras finaliza tareas urgentes. ✅ +- [x] **HALLAZGO RustDesk (2026-04-13 ~16:00):** Se descubrió que RustDesk implementó una nueva política de validación contra su servidor central que antes no existía. Esta validación era la causa raíz de las fallas de conexión entre nodos. Se verificó reconectando exitosamente `srv-ns8 → dasu-pcv` tras aceptar la nueva validación. ✅ + - ⚠️ **Acción pendiente:** Reconfigurar RustDesk en `dasu-pcv` (y `dasu-pc`) para que funcione con la nueva política, restaurando el acceso remoto directo sin depender de TeamViewer. + +#### 7.5 Diagnóstico de Impresión — Ingeniería Inversa *(en curso 2026-04-13)* + +> **Estrategia:** El sistema DASUTEN (Visual FoxPro) genera documentos de impresión mediante **OLE Automation** con Word/Excel, usando plantillas. Se usa `dasu-pcv` como entorno de diagnóstico para hacer ingeniería inversa. + +##### 7.5.1 Ingeniería inversa — Resultados (2026-04-13 ~18:20) +- [x] **Plantillas localizadas:** `C:\SysDasuten\Sistema\Word\` (97 archivos `.doc` — formato Word 97-2003) + `C:\SysDasuten\Sistema\Excel\Recibo.xls`. ✅ +- [x] **Kermet.ini verificado:** No contiene rutas a plantillas — solo config de BD. Las rutas se resuelven dentro del ejecutable VFP. ✅ +- [x] **EXE VFP analizado:** `DasutenSQL.exe` compilado desde `c:\users\lis\fox\generalprueba\`. No hardcodea rutas a plantillas — las resuelve relativamente a `.\Word\` y `.\Excel\`. ✅ +- [x] **Office en dasu-pcv:** Microsoft **Office 2010** (v14.0.6024.1000) — `C:\Program Files (x86)\Microsoft Office\Office14\`. ✅ +- [x] **Office en dasu-pc:** Microsoft **Office 2016/365** (Office16) — `C:\Program Files\Microsoft Office\Office16\`. ✅ + +##### 🔴 CAUSA RAÍZ IDENTIFICADA (2026-04-13 ~18:28) +> **Ruta de plantillas incorrecta.** El archivo `leeme!!!!.txt` del sistema indica que las plantillas deben estar en **`C:\Sistema\Word\`** (ruta legacy hardcodeada en el ejecutable VFP). Sin embargo, en la configuración actual las plantillas están en `C:\SysDasuten\Sistema\Word\`. El directorio `C:\Sistema` **no existe** en ninguno de los dos equipos, por lo que el sistema no encuentra las plantillas al intentar imprimir. +> +> **La versión de Office (2010 vs 2016) es una diferencia pero NO la causa principal.** + +##### 7.5.2 Resolución — Symlink *(parcial 2026-04-13, continúa 2026-04-14)* +- [x] **Symlink creado en dasu-pcv:** `mklink /D C:\Sistema C:\SysDasuten\Sistema` → enlace simbólico que redirige `C:\Sistema\` a `C:\SysDasuten\Sistema\`. ✅ Verificado: `C:\Sistema\Word\Consulta.doc` resuelve correctamente. +- [x] **OLE Word funcional en dasu-pcv (Session 0):** `New-Object -ComObject Word.Application` → Word 14.0 responde. ✅ Nota: `Documents.Open()` requiere sesión de escritorio interactiva (no funciona por SSH/Session 0). + +##### 7.5.3 Pendiente — Validación interactiva en dasu-pcv *(próxima sesión)* +> ⚠️ **La prueba OLE por SSH (Session 0) no alcanza** — Word no puede abrir documentos sin escritorio activo. Se requiere sesión GUI. + +- [x] **Paso 1:** Conectar a `dasu-pcv` vía RustDesk (nueva política) o TeamViewer (ya configurado). ✅ +- [x] **Paso 2:** Abrir DASUTEN (`C:\SysDasuten\Sistema\DasutenSQL.exe`) desde el escritorio. ✅ +- [x] **Paso 3:** Intentar imprimir (ej. bono de consulta) → symlink resolvió el error de plantillas. ✅ +- [x] **Paso 4:** Replicado en `dasu-pc` (PC física). **Impresión funcional en producción.** ✅ + +#### 7.6 Destrucción Ecosistema Antiguo *(pospuesto → Fase 9)* +> Movido a Fase 9 (Cierre del proyecto) tras validación completa. ### 🔄 **FASE 8: Refresco de BD de Producción Final** *(Orquestación)* @@ -205,6 +250,62 @@ Crear dos VMs nuevas (SQL Server + PC cliente) en `srv-dasu`, instalar el sistem - [x] **Restauración Transaccional:** Ejecución de `RESTORE DATABASE ... WITH REPLACE` asegurando el forzado a Single User (ejecutado directo, el Dron arrojó error de parsing UTF8 por los mensajes en ISO-8859-1 de `sqlcmd`). ✅ - [x] **Verificación Post-Restore:** Comprobación `DBCC CHECKDB` certificando la consistencia final de la DB. ✅ +### 🚧 **FASE 8b: Refresco Final de BD** *(En curso 2026-04-14)* + +> **Contexto:** Con la PC física operativa e impresión funcionando, se requiere un último refresco de la BD desde srvv-fenix para que dasu-sql4 tenga los datos más recientes (transacciones de los últimos días). +> +> **NUEVO ENFOQUE (2026-04-14):** Se reemplaza la cadena de transferencias SMB→SCP→SCP por **Google Drive como medio intermedio**, optimizando el flujo y eliminando dependencias de Tailscale inestable. Se implementa arquitectura de **Drones Atómicos Interconectados** con comunicación vía JSON. + +#### Pipeline de transferencia (NUEVO — Google Drive) +``` +srvv-fenix (BACKUP WITH COMPRESSION) + ↓ SMB (rápido, LAN) +srv-ns8 (/var/tmp/) + ↓ rclone (subida) +Google Drive (carpeta compartida drive_bkps-dasu) + ↓ HTTP Direct Download (Invoke-WebRequest) +dasu-sql4 (F:\BACKUP\) + ↓ RESTORE DATABASE WITH REPLACE + → sysdasuten ONLINE +``` + +#### Drones Atómicos Implementados +| Dron | Nodo | Tarea | Output JSON | +|------|------|-------|-------------| +| `dasuten_exportar.rb` | srvv-fenix | BACKUP DATABASE WITH COMPRESSION | `backup_ruta` | +| `dasuten_upload_drive.rb` | srv-ns8 | rclone copy → Google Drive | `drive_ruta`, `drive_url` | +| `dasuten_download_drive.rb` | dasu-sql4 | Invoke-WebRequest ← Google Drive | `backup_local`, `duracion` | +| `dasuten_restaurar.rb` | dasu-sql4 | RESTORE + DBCC CHECKDB | `estado_integridad`, `pipeline_completo` | + +#### Orquestador +- **Script:** `adn/tools/cli/drones/orquestador_pipeline.rb` +- **Función:** Lanza drones secuencialmente, lee outputs JSON, inyecta contexto al siguiente dron +- **Comando:** `./adn/tools/run dron lanzar --nota "Pipeline DASUTEN" -- ruby adn/tools/cli/drones/orquestador_pipeline.rb` + +#### Estado Actual — Resultados Finales +| Paso | Estado | Duración | Resultado | +|------|--------|----------|-----------| +| **8b.1** | ✅ Completado | 44.8s | Backup generado en `srvv-fenix` | +| **8b.2** | ✅ Completado | 1736s (29 min) | Upload a Google Drive (1.4 GB) | +| **8b.3** | ✅ Completado | ~5 min | Download HTTP directo en `dasu-sql4` | +| **8b.4** | ✅ Completado | 248.79s (4 min) | Restore + DBCC CHECKDB — Integridad: **OK** | + +**Pipeline completado exitosamente.** Base de datos `sysdasuten` ONLINE en `dasu-sql4` con datos actualizados al 2026-04-14. + +#### Lecciones Técnicas — Google Drive Download +- **Virus confirmation page:** Google Drive muestra página de confirmación para archivos >100MB. Se maneja extrayendo parámetros `id`, `uuid`, `confirm` del HTML y construyendo URL confirmada: `https://drive.usercontent.google.com/download?id=...&confirm=...&uuid=...` +- **dasu-sql4 sleep mode:** La VM entra en suspensión cuando no se usa. Acceso recomendado vía relay SSH desde `srv-dasu` con `sshpass` + ProxyCommand. +- **Base64 encoding:** Scripts PowerShell se codifican en base64 para transporte sobre SSH, evitando problemas de escaping UTF-8. + +### ⏳ **FASE 9: Cierre del Proyecto** *(pendiente — tras resolver impresión)* + +> **Contexto:** Una vez que la impresión funcione en la PC física y el sistema esté 100% operativo, se procede al cierre formal del proyecto. + +- [ ] **9.1:** Validación final completa con usuaria (todos los flujos funcionales incluyendo impresión). ✅/❌ +- [ ] **9.2:** Reservar IPs fijas en router ISP para `dasu-sql4` y `dasu-pc` (evitar cambios por DHCP). +- [ ] **9.3:** Apagado seguro de VMs legacy: VM 100 (DC), VM 101 (SQL dominio). Documentar estado final. +- [ ] **9.4:** Actualizar informe ejecutivo (`docs/informes/2026-04_DASUTEN-migracion/01_informe_ejecutivo_DASUTEN.md`) a versión definitiva y elevar a autoridades. + --- | **Red** | Privada 10.0.100.x (gw interno) | DHCP del ISP (gw del ISP) | | **Autenticación SQL** | Windows Integrated (Kerberos) | SQL Auth (mixta) | @@ -244,6 +345,8 @@ Crear dos VMs nuevas (SQL Server + PC cliente) en `srv-dasu`, instalar el sistem - **Python `http.server` NO soporta descargas grandes (~1GB+):** `Invoke-WebRequest` y `Net.WebClient.DownloadFile()` en PowerShell fallan con "conexión terminada inesperadamente" al descargar archivos de ~1.3GB desde `python3 -m http.server`. El módulo es single-threaded y no maneja correctamente respuestas chunked/grandes. **Solución**: instalar OpenSSH Server en la VM destino Windows y transferir vía SCP por la LAN (gigabit), que es nativo y confiable para archivos grandes. - **W-Zombi se bloquea en comandos largos:** Cuando el agente PS1 ejecuta un comando que tarda minutos (ej. `Add-WindowsCapability`), deja de pollear el relay. No se pierde — al terminar, reanuda automáticamente y recoge el siguiente comando en cola. No reiniciar el agente prematuramente. - **Scripts wrapper evitan problemas de escape con candados:** Para comandos con comillas complejas (ej. `smbclient -U "user%$PASS"`), crear un script `.sh` local con `File.write`, asignar `chmod 0755`, y pasarlo como argumento a `candados run`. Esto evita el doble/triple escape de comillas. +- **Google Drive como medio de transferencia (2026-04-14):** Para evitar cadenas largas de SCP/SMB con Tailscale inestable, se usa Google Drive como intermediario. **Ventaja:** Download HTTP directo desde dasu-sql4 sin depender de Tailscale. **Desafío:** Archivos >100MB requieren confirmación de virus — se resuelve parseando HTML y extrayendo parámetros `id`, `uuid`, `confirm`. +- **Arquitectura de Drones Atómicos Interconectados:** Cada paso del pipeline es un dron independiente que escribe su output en JSON (`/tmp/dron_*_output.json`). El orquestador lee estos JSONs para pasar contexto al siguiente dron. **Ventajas:** Re-ejecución de pasos individuales, observabilidad en Bitácora Web, acoplamiento mínimo. ## 🔗 Referencias @@ -259,3 +362,5 @@ Crear dos VMs nuevas (SQL Server + PC cliente) en `srv-dasu`, instalar el sistem - **DHCP del ISP cambia IPs tras reboot:** `dasu-sql4` obtuvo `.11` en vez de `.26` tras el corte de luz. Verificar siempre la IP actual usando ARP + MAC antes de asumir que la IP anterior sigue vigente. - **W-Zombi no sobrevive reboots del agente:** El script PS1 debe re-lanzarse manualmente desde la consola Proxmox/noVNC tras un reinicio inesperado de la VM. Considerar crear una Scheduled Task. - **QEMU Guest Agent no inicia automáticamente:** Tras corte de luz, el servicio `QEMU-GA` quedó caído. Verificar que el servicio esté en `Automatic` startup. +- **DASUTEN hardcodea ruta `C:\Sistema`:** El ejecutable VFP busca plantillas en `C:\Sistema\Word\` y `C:\Sistema\Excel\`, pero la instalación moderna las coloca en `C:\SysDasuten\Sistema\`. **Solución:** `mklink /D C:\Sistema C:\SysDasuten\Sistema` — el symlink es transparente para el ejecutable y no requiere modificación alguna del binario. +- **OLE Automation Word es retrocompatible (Office 2010→2016):** `New-Object -ComObject Word.Application` funciona tanto con Office 14 (2010) como Office 16 (2016). La interfaz COM no cambió — no era necesario downgrade de Office. diff --git a/docs/ambito/dtic-DASUTEN/_hist/Gmail - Instalacion del nuevo Servidor de Dasuten.pdf b/docs/ambito/dtic-DASUTEN/_hist/Gmail - Instalacion del nuevo Servidor de Dasuten.pdf new file mode 100644 index 00000000..27f0c702 Binary files /dev/null and b/docs/ambito/dtic-DASUTEN/_hist/Gmail - Instalacion del nuevo Servidor de Dasuten.pdf differ diff --git a/docs/informes/2026-04_DASUTEN-migracion/01_informe_ejecutivo_DASUTEN.md b/docs/informes/2026-04_DASUTEN-migracion/01_informe_ejecutivo_DASUTEN.md new file mode 100644 index 00000000..c0c906fb --- /dev/null +++ b/docs/informes/2026-04_DASUTEN-migracion/01_informe_ejecutivo_DASUTEN.md @@ -0,0 +1,130 @@ +# INFORME DE AVANCE +## Migración del Sistema DASUTEN a Infraestructura Autónoma + +> **Área responsable:** Departamento de Tecnología de la Información y Comunicaciones (DTIC) +> **Facultad Regional La Rioja — Universidad Tecnológica Nacional** +> **Fecha:** 13 de abril de 2026 +> **Elaborado por:** Ricardo Monla — DTIC, UTN-FRLR +> **Destinatarios:** [Completar] +> **Versión:** 0.3 (Borrador) +> +> *Este documento es de carácter ejecutivo y narrativo. El detalle técnico completo se encuentra en el documento complementario [02_informe_tecnico_DASUTEN.md](02_informe_tecnico_DASUTEN.md).* + +--- + +## 1. Contexto y Punto de Partida + +El sistema de gestión administrativa de **DASUTEN** (Departamento de Acción Social Universitaria Tecnológica Nacional) en la Facultad Regional La Rioja funcionaba desde hace años sobre la infraestructura informática compartida de la Facultad: servidores, red interna y servicios de dominio que atienden a toda la institución. + +Si bien esta configuración fue funcional durante un tiempo, con el correr de los años fue manifestando limitaciones concretas: + +- **Fragilidad operativa:** Cualquier incidencia en la red o los servidores de la Facultad —incluso ajena a DASUTEN— impactaba directamente en el funcionamiento del sistema. +- **Complejidad desproporcionada:** La arquitectura heredada requería múltiples servidores virtuales y un controlador de dominio, componentes pensados para entornos de mayor escala que resultaban sobredimensionados para las necesidades de una sola oficina. +- **Dificultad de mantenimiento:** Los respaldos de datos y las actualizaciones periódicas que envía Rectorado requerían coordinación con la infraestructura general de la Facultad, generando demoras y dependencias cruzadas. +- **Limitación de autonomía:** DASUTEN, si bien opera dentro de las instalaciones de la Facultad, responde funcionalmente a **Rectorado (Buenos Aires)**. La dependencia de la infraestructura local dificultaba una eventual gestión directa desde la sede central. + +A esta situación se sumó que, al reubicarse la oficina en un espacio propio alejado de los servidores, las fallas de conectividad se agravaron por la cantidad de puntos intermedios en la red. Para dar continuidad al servicio, se gestionó una línea de internet propia y se implementó un esquema de trabajo indirecto donde las usuarias — Andrea Almirón y Romina Molina — accedían mediante escritorio remoto a una PC virtual para poder operar el sistema. Esto implicaba mantener cuatro componentes simultáneamente (servidor de dominio, servidor de base de datos, PC virtual y PC física), multiplicando los puntos de falla. + +--- + +## 2. Objetivo del Proyecto + +Diseñar e implementar una solución que permita al sistema DASUTEN operar de forma **completamente autónoma**, teniendo en cuenta: + +- **Recursos limitados:** Aprovechar equipos ya existentes — un equipo de escritorio de prestaciones modestas y un servidor compacto reutilizado. **Sin adquisición de hardware nuevo.** +- **No interferir con la oficina:** Que DTIC pueda realizar respaldos, actualizaciones de Rectorado y soporte técnico **de forma remota y transparente**, sin afectar las tareas cotidianas. +- **Trabajo directo:** Que las usuarias operen el sistema directamente desde la PC de la oficina, sin depender de conexiones remotas intermedias. +- **Simplicidad:** Una arquitectura lo más simple posible, administrable y confiable en el tiempo. + +--- + +## 3. Qué se logró + +### 3.1 La simplificación + +Se reemplazó la arquitectura compleja por un esquema directo y simple: + +| Aspecto | Antes | Ahora | +|:---|:---:|:---:| +| Componentes necesarios | 4 | 2 | +| Forma de trabajo | Indirecta (vía escritorio remoto) | Directa (sistema en la PC) | +| Dependencia de red de Facultad | Sí | No | +| Puntos de falla | Múltiples | Mínimos | +| Requiere presencia física para soporte | Frecuentemente | No | +| Hardware nuevo adquirido | — | Ninguno | + +Las usuarias ahora operan el sistema **directamente desde la PC de la oficina**. El servidor de base de datos funciona dentro de la misma oficina, en la red propia de DASUTEN, sin intermediarios. + +### 3.2 El proceso: de testeo a producción + +Si bien el proyecto llevó más tiempo del inicialmente estimado, esto responde a una decisión deliberada: se planificó una **etapa de testeo exhaustivo** antes de llevar el sistema a producción. Cada paso fue validado primero en un entorno de pruebas antes de aplicarse al entorno real, minimizando riesgos para la operación de la oficina. + +**A la fecha, el sistema se encuentra a un paso del 100%**, restando únicamente un ajuste de compatibilidad en la impresión de documentos, para el cual ya se dispone de una solución provisoria. + +### 3.3 Valor agregado: herramientas y metodología + +Más allá del objetivo central, el trabajo realizado **generó herramientas y metodologías de valor** que benefician a la gestión de DTIC en su conjunto: + +- **Dashboard web de seguimiento** del proyecto, con visibilidad en tiempo real del progreso. +- **Sistema de bitácoras** con registro detallado y auditable de cada intervención técnica. +- **Herramientas de automatización** (Ecosistema ADN) para respaldos, gestión remota y tareas repetitivas. +- **Metodología de trabajo con IA generativa**, altamente productiva y replicable en futuros proyectos. + +--- + +## 4. Estado Actual + +| Aspecto | Estado | +|:---|:---:| +| Sistema operativo en oficina | ✅ | +| Base de datos migrada y verificada | ✅ | +| Trabajo directo (sin escritorio remoto) | ✅ | +| Administración remota por DTIC | ✅ | +| Respaldos automatizados | ✅ | +| Impresión de documentos | ⚠️ En ajuste | + +El sistema se encuentra **operativo**. La usuaria accede directamente al sistema desde la PC de la oficina. DTIC administra y respalda de forma remota sin interferir con la operación diaria. + +Resta un ajuste en la impresión, con solución provisoria funcional. + +--- + +## 5. Beneficios Alcanzados + +- **Trabajo directo:** Las usuarias operan el sistema sin intermediarios. +- **Autonomía operativa:** Infraestructura propia, desvinculada de la Facultad, preparada para gestión desde Rectorado. +- **Optimización de recursos:** Sin inversión en hardware nuevo. +- **Soporte transparente:** DTIC gestiona remotamente sin afectar la oficina. +- **Mayor estabilidad:** De 4 componentes a 2, menos fallas posibles. +- **Herramientas reutilizables:** Activos aprovechables para otros proyectos de DTIC. + +--- + +## 6. Próximos Pasos + +1. Completar el ajuste de impresión para alcanzar el 100% de funcionalidad. +2. Estabilizar la configuración de red del servidor. +3. Formalizar los procedimientos de respaldo automatizado. +4. Evaluar el retiro definitivo de la infraestructura anterior. + +--- + +## 7. Conclusión + +La migración del sistema DASUTEN demuestra que es posible **lograr una mejora sustancial en estabilidad, autonomía y experiencia de trabajo** partiendo de recursos limitados y sin inversión adicional. + +Se pasó de un esquema indirecto y complejo a uno directo y simple, donde el sistema funciona en la propia oficina. El proceso generó además herramientas y metodologías que quedan como activo del área para futuros proyectos. + +DASUTEN opera hoy de forma independiente, administrable remotamente por DTIC y preparada para una gestión más ágil desde la Facultad Regional o desde Rectorado. + +--- + +### Historial de versiones + +| Versión | Fecha | Cambios | +|:---:|:---:|:---| +| 0.1 | 13/04/2026 | Borrador inicial | +| 0.2 | 13/04/2026 | Se amplía contexto de situación inicial | +| 0.3 | 13/04/2026 | Se retoma enfoque narrativo, se integra contexto como complemento, se agrega referencia al documento técnico | + +*Fin del informe.* diff --git a/docs/informes/2026-04_DASUTEN-migracion/01_informe_ejecutivo_DASUTEN.pdf b/docs/informes/2026-04_DASUTEN-migracion/01_informe_ejecutivo_DASUTEN.pdf new file mode 100644 index 00000000..02f11de2 Binary files /dev/null and b/docs/informes/2026-04_DASUTEN-migracion/01_informe_ejecutivo_DASUTEN.pdf differ diff --git a/docs/informes/2026-04_DASUTEN-migracion/02_informe_tecnico_DASUTEN.md b/docs/informes/2026-04_DASUTEN-migracion/02_informe_tecnico_DASUTEN.md new file mode 100644 index 00000000..98eee2ad --- /dev/null +++ b/docs/informes/2026-04_DASUTEN-migracion/02_informe_tecnico_DASUTEN.md @@ -0,0 +1,446 @@ +# INFORME TÉCNICO — Migración del Sistema DASUTEN a Nuevo Servidor + +> **Área:** Departamento de Tecnología de la Información y Comunicaciones (DTIC) +> **Proyecto:** Migración de infraestructura DASUTEN — Modo Workgroup sin Domain Controller +> **Código interno:** A04.P005 +> **Fecha del informe:** 13 de abril de 2026 +> **Elaborado por:** Ricardo Monla — Área DTIC, UTN-FRLR +> **Versión:** 0.2 +> +> *Este documento contiene el detalle técnico completo de la migración. Para la síntesis ejecutiva, ver [01_informe_ejecutivo_DASUTEN.md](01_informe_ejecutivo_DASUTEN.md).* + +--- + +## 1. Resumen Ejecutivo + +Se informa el avance de la migración del sistema de gestión administrativa **DASUTEN** (Departamento de Acción Social Universitaria Tecnológica Nacional) desde la infraestructura compartida de la Facultad hacia un entorno independiente, autónomo y simplificado. + +**Estado general del proyecto: 95% completado.** + +El sistema DASUTEN se encuentra **operativo** en la nueva infraestructura desde el día 13 de abril de 2026, habiendo superado exitosamente las pruebas funcionales de acceso a datos. Resta únicamente resolver un problema de compatibilidad de impresión vinculado a las plantillas de Office utilizadas por el sistema. + +### Logros principales + +- ✅ Servidor de base de datos **completamente migrado** a infraestructura nueva. +- ✅ Base de datos de producción **restaurada y verificada** sin errores de integridad. +- ✅ Sistema DASUTEN **desplegado y operativo** en la PC física de la usuaria. +- ✅ Eliminación exitosa de la dependencia del **Active Directory (Domain Controller)**. +- ✅ Simplificación de la arquitectura de red — de 3 servidores virtuales a 1. +- ⚠️ Pendiente: resolución de problema de impresión por compatibilidad de plantillas Office. + +--- + +## 2. Antecedentes y Motivación + +### 2.1 Infraestructura original (en red de Facultad) + +El sistema DASUTEN operaba sobre infraestructura compartida con la Facultad Regional La Rioja, dependiendo de: + +- Un servidor SQL Server alojado en la red interna de la Facultad (`srvv-fenix`). +- Un Domain Controller Active Directory para la autenticación de usuarios. +- Conectividad de red interna de la Facultad con routing complejo. + +Esta configuración generaba **múltiples puntos de falla**: +- Dependencia del dominio institucional para la autenticación. +- Complejidad de red con subnetting privado, NAT y gateway interno. +- Cualquier cambio en la infraestructura de la Facultad impactaba directamente en DASUTEN. + +### 2.2 Esquema de trabajo provisorio (AnyDesk + PC Virtual) + +Al reubicarse la oficina DASUTEN en un espacio propio alejado de los servidores, se agravaron las fallas de conectividad: la señal de red recorría múltiples puntos intermedios dentro del edificio, y la caída de cualquiera de ellos dejaba a la oficina sin sistema. + +Para dar continuidad al servicio, se gestionó una **línea de internet propia** para la oficina y se implementó el siguiente esquema de trabajo: + +``` +PC Física (dasu-pc) Servidor srv-dasu (Proxmox VE) + Usuarias: Almirón / Molina ├── VM 100: dasu-srvv-dc (Domain Controller AD DS) + Acceso: AnyDesk ──────────────────► ├── VM 101: dasu-srvv-sql (SQL Server + BD sysdasuten) + (escritorio remoto) └── VM 102: dasu-pcv (PC Virtual ← trabajo aquí) +``` + +**Componentes requeridos:** 4 (servidor dominio + servidor BD + PC virtual + PC física con AnyDesk). + +**Flujo de trabajo de las usuarias:** PC física → AnyDesk (escritorio remoto) → PC virtual → sistema DASUTEN. + +Este esquema permitió: +- Dar continuidad al servicio independientemente de la red interna de la Facultad. +- Brindar asistencia técnica 24/7 por parte de DTIC vía acceso remoto. + +Pero implicaba: +- Experiencia de trabajo **indirecta** para las usuarias (doble salto). +- Cuatro componentes simultáneos que debían estar operativos. +- Múltiples puntos de falla que dificultaban el soporte. + +### 2.3 Objetivo del proyecto + +**Migrar el sistema DASUTEN a una infraestructura independiente y simplificada**, eliminando la dependencia del Domain Controller (Active Directory), el esquema de escritorio remoto, y utilizando un esquema de red **Workgroup** directo, con el fin de: + +1. Reducir la complejidad operativa (de 4 componentes a 2). +2. Permitir trabajo directo (sin AnyDesk intermedio). +3. Minimizar los puntos de falla. +4. Garantizar la autonomía operativa de DASUTEN respecto de la infraestructura de la Facultad. +5. Facilitar la eventual gestión desde Rectorado (Buenos Aires) si fuera necesario. + +--- + +## 3. Infraestructura Implementada + +### 3.1 Arquitectura de red + +Se implementó una topología de **red plana simplificada**, donde todos los equipos obtienen direccionamiento IP directamente del router del ISP, eliminando subnetting privado y routing interno: + +``` +Internet + │ +Router ISP (192.168.1.1 — Gateway) + │ + ├── srv-dasu (Proxmox VE) → 192.168.1.13 + │ └── dasu-sql4 (VM 106) → 192.168.1.11 [SQL Server 2019] + │ + └── dasu-pc (PC Física) → DHCP ISP [Estación de trabajo] +``` + +### 3.2 Componentes del nuevo entorno + +| Componente | Descripción | Estado | +|:---|:---|:---:| +| **srv-dasu** | Servidor Proxmox VE 9.1 (Hipervisor) — CPU Intel, 15 GB RAM, 94 GB disco | ✅ Operativo | +| **dasu-sql4** (VM 106) | Windows Server 2022 — SQL Server 2019 Enterprise — 4 GB RAM, 2 vCPU, discos 60+120 GB | ✅ Operativo | +| **dasu-pc** | PC Física — Windows 10 Pro — AMD Ryzen 5, 8 GB RAM — Oficina DASUTEN | ✅ Operativo | + +### 3.3 Comparativa: Antes vs. Después + +| Aspecto | Enfoque Anterior (con DC + AnyDesk) | Enfoque Actual (Workgroup) | +|:---|:---|:---| +| **Componentes** | 4 (DC + SQL + PC virtual + PC física) | 2 (SQL + PC física) | +| **Forma de trabajo** | Indirecta (AnyDesk → PC virtual) | Directa (sistema en PC) | +| **Red** | Privada 10.0.100.x (gateway interno) | DHCP del ISP (red plana) | +| **Autenticación SQL** | Windows Integrated (Kerberos) | SQL Auth (mixta) | +| **Usuarios** | Active Directory | Usuarios locales Windows | +| **DNS** | AD DNS (10.0.100.10) | DNS del ISP (automático) | +| **Complejidad de red** | Alta (DC + DNS + dominio + routing) | Mínima (red plana ISP) | +| **Puntos de falla** | DC, SQL, red dominio, routing, AnyDesk | Solo SQL | +| **VMs necesarias** | 3 (DC + SQL + PC virtual) | 1 (solo SQL) | + +--- + +## 4. Fases Ejecutadas y Progreso + +### Resumen de progreso por fase + +| Fase | Descripción | Estado | Progreso | +|:---:|:---|:---:|:---:| +| 1 | Preparación del entorno (srv-dasu) | ✅ Completada | 100% | +| 2 | Creación de VM SQL Server de prueba | ✅ Completada | 100% | +| 3 | Creación de VM PC Cliente de prueba | ✅ Completada | 100% | +| 4 | VM definitiva dasu-sql4 | ✅ Completada | 100% | +| 5 | Migración de base de datos | ✅ Completada | 100% | +| 5b | Hardening y persistencia de servicios | ✅ Completada | 100% | +| 6 | Validación con PC cliente virtual | ✅ Completada | 100% | +| 7 | Despliegue en PC física (producción) | 🚧 En curso | 75% | +| 8 | Refresco final de base de datos | ✅ Completada | 100% | + +### 4.1 Fase 1-3: Preparación y pruebas de concepto (27-28 marzo) + +Se preparó el hipervisor Proxmox, se reconfiguró el bridge de red para usar DHCP directo del ISP, y se crearon VMs de prueba para validar la viabilidad del enfoque sin Domain Controller. + +**Hallazgo crítico:** Se detectó y resolvió que el bridge de red estaba configurado con la IP de una red privada anterior, lo cual habría impedido la conectividad de las nuevas VMs. + +### 4.2 Fase 4: Servidor SQL definitivo (9-10 abril) + +Se creó la VM definitiva `dasu-sql4` (VM 106) con una arquitectura optimizada: + +- **Discos separados:** 60 GB para SO + 120 GB exclusivo para datos SQL (buena práctica). +- **SQL Server 2019 Enterprise** instalado con autenticación mixta. +- **Gestión remota** asegurada vía OpenSSH Server (puerto 7022) y Tailscale VPN. + +### 4.3 Fase 5: Migración de Base de Datos (11 abril) + +Se ejecutó la migración completa de la base de datos de producción: + +1. **Exportación:** Backup comprimido (~1.33 GB) generado desde el servidor origen (`srvv-fenix`). +2. **Transferencia:** Archivo movido a través de la VPN institucional (Tailscale) en múltiples tramos seguros. +3. **Restauración:** Base restaurada exitosamente en 26 segundos (354 MB/s). +4. **Verificación:** `DBCC CHECKDB` ejecutado sin errores — integridad de datos confirmada al 100%. + +### 4.4 Fase 5b: Hardening (11 abril) + +Se validó que todos los servicios críticos (SSH, SQL Server) sobreviven reinicios del servidor sin intervención manual: + +- OpenSSH Server: arranque automático ✅ +- SQL Server: arranque automático ✅ +- IP de red: mantenida tras reinicio ✅ + +### 4.5 Fase 6: Validación funcional en entorno virtual (11 abril) + +Se restauró una VM cliente desde backup para simular el entorno real de la oficina DASUTEN: + +- Se desvinculó la PC del dominio anterior y se unió al Workgroup `DASUTEN`. +- Se reconfiguró el archivo de conexión del sistema (`Kermet.ini`) para apuntar al nuevo servidor SQL. +- **Resultado:** El sistema DASUTEN conectó exitosamente, actualizó estructuras y descargó novedades. + +**Conclusión técnica clave:** Se determinó mediante ingeniería inversa que el sistema DASUTEN (desarrollado en Visual FoxPro) **no tiene dependencia real del Active Directory** si se configura explícitamente la autenticación SQL en su archivo de configuración. + +### 4.6 Fase 7: Despliegue en PC física de producción (13 abril — EN CURSO) + +Se desplegó el sistema en la PC física de la oficina DASUTEN (`dasu-pc`): + +- **Directorio del sistema** (`C:\SysDasuten`) transferido desde la VM de pruebas. +- **Configuración de conexión** apuntada al nuevo servidor `dasu-sql4`. +- **Acceso directo** creado en el escritorio de la usuaria (`aalmiron`). +- **Pruebas funcionales:** + - Inicio del sistema: ✅ OK + - Acceso a datos (ventana de bonos): ✅ OK + - **Impresión: ❌ FALLO** — Error al imprimir, posiblemente por incompatibilidad de las plantillas de Office (el sistema usa automatización OLE con Word/Excel). + +### 4.7 Fase 8: Refresco final de base de datos (13 abril) + +Se ejecutó un refresco automatizado de la base de datos para asegurar que el sistema arranca con los datos más actualizados del servidor de origen: + +- Backup generado automáticamente desde el origen (44.8 segundos). +- Transferido de manera segura (SMB + SCP por VPN). +- Restaurado con `RESTORE DATABASE ... WITH REPLACE`. +- Integridad verificada con `DBCC CHECKDB` — sin errores. + +--- + +## 5. Estado Actual + +### 5.1 Funcionalidades operativas + +| Funcionalidad | Estado | +|:---|:---:| +| Acceso al sistema DASUTEN | ✅ Operativo | +| Consulta de datos (bonos, registros) | ✅ Operativo | +| Conexión a base de datos SQL Server | ✅ Operativo | +| Acceso remoto para soporte (Tailscale/SSH) | ✅ Operativo | +| Impresión desde el sistema | ❌ Pendiente | + +### 5.2 Problema pendiente: Impresión + +**Descripción:** Al intentar imprimir desde el sistema DASUTEN en la PC física, se produce un error. El diagnóstico preliminar indica que la causa es una incompatibilidad entre las **plantillas de Office** requeridas por el sistema (diseñadas para Office 2003/2007) y la versión de Office actualmente instalada en la PC. + +**Impacto:** La usuaria no puede generar documentos impresos desde el nuevo sistema. + +**Workaround temporal:** Se habilitó acceso remoto (TeamViewer) desde la PC física hacia la VM de pruebas (`dasu-pcv`), donde la impresión funciona correctamente. La usuaria puede continuar operando mientras se resuelve el problema. + +**Plan de resolución:** Verificar y ajustar la versión/configuración de Office en `dasu-pc` para compatibilizarla con las plantillas del sistema. + +--- + +## 6. Beneficios Obtenidos + +1. **Independencia operativa:** DASUTEN ya no depende de la infraestructura de red ni de los servidores de la Facultad. +2. **Simplificación:** Se pasó de 3 VMs + Domain Controller a solo 1 VM (SQL Server), reduciendo significativamente la complejidad. +3. **Reducción de puntos de falla:** De múltiples (DC, DNS institucional, routing complejo) a uno solo (SQL Server). +4. **Acceso remoto robusto:** Gestión técnica asegurada vía VPN (Tailscale) y SSH, sin necesidad de presencia física. +5. **Autonomía:** La infraestructura puede ser gestionada independientemente, facilitando una eventual transferencia a Rectorado. +6. **Preservación del entorno anterior:** Las VMs del enfoque con DC fueron apagadas y preservadas como respaldo, permitiendo un rollback si fuera necesario. + +--- + +## 7. Cronograma Resumen + +| Fecha | Hito | +|:---|:---| +| 27/03/2026 | Inicio — Preparación del entorno e inicio de pruebas de concepto | +| 28/03/2026 | VM SQL Server de prueba operativa | +| 09-10/04/2026 | Servidor SQL definitivo (dasu-sql4) desplegado y operativo | +| 11/04/2026 | Base de datos migrada, verificada y hardening completado | +| 11/04/2026 | Validación funcional exitosa en entorno virtual | +| 13/04/2026 | Despliegue en PC física de producción — sistema operativo con observación de impresión | + +--- + +## 8. Próximos Pasos + +| Prioridad | Acción | Plazo estimado | +|:---:|:---|:---| +| 🔴 Alta | Resolver problema de impresión (compatibilidad Office/plantillas) | 1-3 días hábiles | +| 🟡 Media | Reservar IPs fijas en router ISP (prevenir cambios por DHCP) | 1 semana | +| 🟢 Baja | Evaluar apagado definitivo de VMs legacy (DC, SQL antiguo) | Tras validación completa | +| 🟢 Baja | Documentar procedimiento de respaldo automatizado de la nueva BD | 2 semanas | + +--- + +## 9. Conclusión + +La migración del sistema DASUTEN a la nueva infraestructura se encuentra **prácticamente completada**, con el sistema operativo y los datos verificados. El enfoque sin Domain Controller demostró ser completamente viable, logrando una **reducción significativa de la complejidad** y de los puntos de falla. + +El único aspecto pendiente es la resolución del problema de impresión, para el cual ya se dispone de un workaround funcional que permite a la usuaria continuar operando sin interrupción. + +Se estima que el proyecto quedará **100% finalizado** dentro de los próximos días hábiles, una vez resuelta la compatibilidad de plantillas de Office. + +--- + +# ANEXO TÉCNICO + +## A. Inventario de Nodos + +### A.1 Servidor Hipervisor: srv-dasu + +| Campo | Valor | +|:---|:---| +| **Rol** | Hipervisor Proxmox VE 9.1 | +| **IP LAN** | 192.168.1.13 (DHCP ISP) | +| **IP VPN** | 100.112.46.104 (Tailscale) | +| **Bridge** | vmbr0 sobre enp33s0 | +| **RAM** | 15 GB total / ~4 GB libre post-VMs | +| **Disco** | 94 GB (68% uso, thin provisioned) | +| **Acceso remoto** | Tailscale + SSH | + +### A.2 Servidor SQL: dasu-sql4 (VM 106) + +| Campo | Valor | +|:---|:---| +| **Rol** | SQL Server 2019 Enterprise | +| **SO** | Windows Server 2022 (Español) | +| **IP LAN** | 192.168.1.11 (DHCP ISP) | +| **IP VPN** | 100.107.15.82 (Tailscale — inestable) | +| **Workgroup** | DASUTEN | +| **RAM** | 4 GB | +| **vCPU** | 2 | +| **Disco 1 (sata0)** | 60 GB — Sistema Operativo | +| **Disco 2 (sata1)** | 120 GB — Datos SQL (GPT/NTFS "SQLData") | +| **Estructura SQL** | F:\DATA, F:\LOG, F:\BACKUP, F:\TEMPDB | +| **Autenticación** | Mixta (SQL Auth + Windows) | +| **Puerto SQL** | TCP 1433 | +| **SSH** | Puerto 7022 (OpenSSH Server, arranque automático) | +| **Servicios auto-start** | MSSQLSERVER, sshd | + +### A.3 PC Física Cliente: dasu-pc + +| Campo | Valor | +|:---|:---| +| **Rol** | Estación de trabajo DASUTEN | +| **Patrimonio** | 32120 | +| **Ubicación** | Oficina DASUTEN (externa a Facultad) | +| **SO** | Windows 10 Pro | +| **Workgroup** | DASUTEN | +| **IP VPN** | 100.119.233.11 (Tailscale) | +| **SSH** | UTNLR@100.119.233.11:7022 | +| **CPU** | AMD Ryzen 5 4600G @ 4.30GHz (6 núcleos) | +| **RAM** | 8 GB DDR4-3200 | +| **Placa Base** | Asus Prime A320M-K | +| **Usuaria principal** | Andrea Almirón (`aalmiron`) | +| **Directorio DASUTEN** | C:\SysDasuten | +| **Config conexión** | C:\SysDasuten\Sistema\Kermet.ini | + +### A.4 VM Cliente de Pruebas: dasu-pcv (VM 107) — Test-Bed + +| Campo | Valor | +|:---|:---| +| **Rol** | Entorno de pruebas / fallback temporal | +| **SO** | Windows 10 | +| **Workgroup** | DASUTEN | +| **SSH** | Puerto 7022 | +| **Estado** | Operativa (usada como fallback vía TeamViewer) | + +--- + +## B. Configuración del Sistema DASUTEN + +### B.1 Archivo de conexión: Kermet.ini + +Parámetros clave configurados para la operación sin Domain Controller: + +```ini +SERVER=dasu-sql4 +DATABASE=sysdasuten +UID=sa +PWD=[credencial almacenada en bóveda] +``` + +> **Nota técnica:** El campo `UID` debe estar explícitamente configurado con `sa` (u otra cuenta SQL Auth). Si se deja vacío, el sistema DASUTEN (Visual FoxPro) asume autenticación Windows integrada (SSPI/Kerberos), lo cual falla en entorno Workgroup sin Domain Controller. + +### B.2 Directorio del sistema + +``` +C:\SysDasuten\ +├── Sistema\ → Ejecutables VFP + Kermet.ini +├── Plantillas\ → Templates Word/Excel para impresión +└── [otros directorios de la aplicación] +``` + +--- + +## C. Base de Datos: sysdasuten + +| Campo | Valor | +|:---|:---| +| **Nombre** | sysdasuten | +| **Motor** | SQL Server 2019 Enterprise | +| **Tamaño backup comprimido** | ~1.33 GB | +| **Nivel de compatibilidad** | 100 | +| **Recovery model** | FULL | +| **Integridad (DBCC CHECKDB)** | ✅ Sin errores | +| **Tiempo de restauración** | 26 segundos (354 MB/s) | +| **Origen de datos** | srvv-fenix (servidor legacy de Facultad) | +| **Último refresco** | 13/04/2026 | + +### C.1 Ruta de transferencia del backup + +``` +srvv-fenix (Origen) + │ [BACKUP DATABASE ... WITH COMPRESSION] + │ → E:\BK_SQL\sysdasuten_compressed_ADN.bak (~1.33 GB) + ↓ +srv-ns8 (Tránsito) + │ [SMB/smbget vía dominio] + │ → /var/tmp/ + ↓ +srv-dasu (Tránsito) + │ [SCP vía Tailscale] + ↓ +dasu-sql4 (Destino) + │ [RESTORE DATABASE ... WITH REPLACE] + └ → F:\BACKUP\ → F:\DATA\ + F:\LOG\ +``` + +--- + +## D. VMs Legacy Preservadas (Apagadas) + +| VM ID | Nombre | Rol anterior | Estado | +|:---:|:---|:---|:---:| +| 100 | dasu-srvv-dc | Domain Controller AD DS | 🛑 Apagada | +| 101 | dasu-srvv-sql | SQL Server (dominio) | 🛑 Apagada | +| 102 | dasu-pcv | PC cliente (dominio) | 🛑 Apagada | +| 103 | dasu-sql2 | SQL Server prueba v1 | 🛑 Descartada | +| 104 | dasu-pcv2 | PC prueba v1 | 🛑 Descartada | + +> Las VMs legacy (100-102) se mantienen apagadas como respaldo. Pueden reactivarse en caso de necesitar un rollback al enfoque con Domain Controller. + +--- + +## E. Accesos Remotos Configurados + +| Nodo | Método | Detalle | +|:---|:---|:---| +| srv-dasu | Tailscale SSH | 100.112.46.104 | +| dasu-sql4 | SSH (LAN) | 192.168.1.11:7022 | +| dasu-sql4 | Tailscale | 100.107.15.82 (inestable) | +| dasu-pc | Tailscale SSH | 100.119.233.11:7022 | +| dasu-pc | AnyDesk | Instalado (GUI) | +| dasu-pcv | TeamViewer | Activo (workaround temporal) | + +--- + +## F. Cuenta de Gestión VPN + +| Campo | Valor | +|:---|:---| +| **Proveedor** | Tailscale | +| **Cuenta** | pcdasu0@frlr.utn.edu.ar | +| **Nodos vinculados** | srv-dasu, dasu-sql4, dasu-pc, dasu-pcv | + +--- + +### Historial de versiones + +| Versión | Fecha | Cambios | +|:---:|:---:|:---| +| 0.1 | 13/04/2026 | Versión inicial (fusión de informe de avance + anexo técnico) | +| 0.2 | 13/04/2026 | Se agrega contexto de infraestructura anterior (esquema AnyDesk), versionado, referencia a doc ejecutivo | + +*Fin del informe técnico.* diff --git a/docs/informes/2026-04_DASUTEN-migracion/README.md b/docs/informes/2026-04_DASUTEN-migracion/README.md new file mode 100644 index 00000000..0a50f180 --- /dev/null +++ b/docs/informes/2026-04_DASUTEN-migracion/README.md @@ -0,0 +1,23 @@ +# 📁 Informe: Migración DASUTEN — Abril 2026 + +> Carpeta de recopilación para el informe de avance sobre la migración del sistema DASUTEN a infraestructura autónoma. + +## Documentos + +| # | Archivo | Audiencia | Descripción | +|:---:|:---|:---|:---| +| 01 | [01_informe_ejecutivo_DASUTEN.md](01_informe_ejecutivo_DASUTEN.md) | Autoridades | Narrativo, sin jerga técnica, visión de mejora | +| 02 | [02_informe_tecnico_DASUTEN.md](02_informe_tecnico_DASUTEN.md) | DTIC / Técnico | Detalle de fases, diagnósticos + anexo de nodos y configuraciones | + +## Fuentes de datos + +- Plan de ejecución: [`A04.P005_DASUTEN-sin-DC.md`](../../ambito/dtic-DASUTEN/A04.P005_DASUTEN-sin-DC.md) +- Manifiesto de ámbito: [`A04_dtic-DASUTEN.md`](../../ambito/dtic-DASUTEN/A04_dtic-DASUTEN.md) +- Fichas de nodos: [`nodos/dasu-pc.md`](../../../nodos/dasu-pc.md) +- Registros de bitácora del proyecto + +## Estado + +- **Fecha de generación:** 13/04/2026 +- **Estado del proyecto:** ~95% completado (pendiente: ajuste de impresión) +- **Próxima actualización:** Al resolver impresión / cierre de proyecto diff --git a/docs/informes/2026-04_DASUTEN-migracion/_gen_pdf.py b/docs/informes/2026-04_DASUTEN-migracion/_gen_pdf.py new file mode 100644 index 00000000..5ad39d00 --- /dev/null +++ b/docs/informes/2026-04_DASUTEN-migracion/_gen_pdf.py @@ -0,0 +1,172 @@ +#!/usr/bin/env python3 +"""Genera PDF del informe ejecutivo desde Markdown usando Chrome headless.""" +import markdown +import subprocess +import sys +import os + +SRC = "01_informe_ejecutivo_DASUTEN.md" +OUT = "01_informe_ejecutivo_DASUTEN.pdf" +TMP = "/tmp/_informe_tmp.html" + +# Leer markdown +with open(SRC, "r", encoding="utf-8") as f: + md_text = f.read() + +# Convertir a HTML +html_body = markdown.markdown(md_text, extensions=["tables", "fenced_code"]) + +# Envolver con estilos profesionales +html = f""" + + + + + + +{html_body} + +""" + +# Guardar HTML temporal +with open(TMP, "w", encoding="utf-8") as f: + f.write(html) + +# Generar PDF con Chrome headless +result = subprocess.run([ + "google-chrome", + "--headless", + "--disable-gpu", + "--no-sandbox", + "--disable-software-rasterizer", + f"--print-to-pdf={OUT}", + "--print-to-pdf-no-header", + TMP +], capture_output=True, text=True) + +if os.path.exists(OUT): + size = os.path.getsize(OUT) / 1024 + print(f"✅ PDF generado: {OUT} ({size:.0f} KB)") +else: + print(f"❌ Error al generar PDF") + print(result.stderr) + sys.exit(1) + +# Limpiar +os.remove(TMP) diff --git a/docs/informes/2026-04_DASUTEN-migracion/_versiones/01_v0.1.md b/docs/informes/2026-04_DASUTEN-migracion/_versiones/01_v0.1.md new file mode 100644 index 00000000..7a164116 --- /dev/null +++ b/docs/informes/2026-04_DASUTEN-migracion/_versiones/01_v0.1.md @@ -0,0 +1,136 @@ +# INFORME DE AVANCE +## Migración del Sistema DASUTEN a Infraestructura Autónoma + +> **Área responsable:** Departamento de Tecnología de la Información y Comunicaciones (DTIC) +> **Facultad Regional La Rioja — Universidad Tecnológica Nacional** +> **Fecha:** 13 de abril de 2026 +> **Elaborado por:** Ricardo Monla — DTIC, UTN-FRLR +> **Destinatarios:** [Completar] +> **Versión:** 0.1 (Borrador inicial) + +--- + +## 1. Contexto y Punto de Partida + +El sistema de gestión administrativa de **DASUTEN** (Departamento de Acción Social Universitaria Tecnológica Nacional) en la Facultad Regional La Rioja funcionaba desde hace años sobre la infraestructura informática compartida de la Facultad: servidores, red interna y servicios de dominio que atienden a toda la institución. + +Si bien esta configuración fue funcional durante un tiempo, con el correr de los años fue manifestando limitaciones concretas: + +- **Fragilidad operativa:** Cualquier incidencia en la red o los servidores de la Facultad —incluso ajena a DASUTEN— impactaba directamente en el funcionamiento del sistema. +- **Complejidad desproporcionada:** La arquitectura heredada requería múltiples servidores virtuales y un controlador de dominio, componentes pensados para entornos de gran escala que resultaban sobredimensionados para las necesidades reales de una sola oficina. +- **Dificultad de mantenimiento:** Las tareas de mantenimiento, los respaldos de datos y las actualizaciones periódicas que envía Rectorado requerían coordinación con la infraestructura general de la Facultad, generando demoras y dependencias cruzadas. +- **Limitación de autonomía:** DASUTEN, si bien opera dentro de las instalaciones de la Facultad, responde funcionalmente a **Rectorado (Buenos Aires)**. La dependencia de la infraestructura local dificultaba una eventual gestión directa desde la sede central. + +--- + +## 2. Objetivo del Proyecto + +El objetivo fue diseñar e implementar una solución que permita al sistema DASUTEN operar de forma **completamente autónoma** respecto de la infraestructura de la Facultad, teniendo en cuenta las siguientes restricciones y premisas: + +- **Recursos limitados:** Se parte de los equipos ya existentes en la oficina DASUTEN — un único equipo de escritorio de prestaciones modestas y un servidor compacto reutilizado. **No se requirió adquisición de hardware nuevo.** +- **No interferir con la operación diaria:** La solución debía permitir al equipo de DTIC realizar respaldos, aplicar actualizaciones de Rectorado y resolver problemas técnicos **de forma remota**, sin interrumpir ni afectar las tareas cotidianas de la oficina. +- **Administrabilidad a distancia:** Dado que la oficina DASUTEN se encuentra en una ubicación externa a la Facultad, todo el sistema debía ser gestionable remotamente por DTIC. +- **Simplicidad y sostenibilidad:** Con un solo equipo de modestas prestaciones como base, la arquitectura debía ser lo más simple posible para que resulte administrable y confiable en el tiempo. + +--- + +## 3. Qué se hizo y cómo se llegó + +### 3.1 La simplificación + +El trabajo principal consistió en **desmontar la complejidad innecesaria** de la arquitectura anterior y reemplazarla por un esquema directo y simple: + +| Aspecto | Antes | Ahora | +|:---|:---:|:---:| +| Servidores virtuales necesarios | 3 | 1 | +| Dependencia de red de Facultad | Sí | No | +| Puntos de falla | Múltiples | Mínimos | +| Requiere presencia física para soporte | Frecuentemente | No | +| Hardware nuevo adquirido | — | Ninguno | + +En la práctica, se pasó de una arquitectura de tres servidores virtuales más un controlador de dominio compartido, a **un solo servidor virtual** que contiene la base de datos, conectado directamente a la PC de escritorio de la oficina. Todo opera dentro de la red propia de la oficina DASUTEN, sin depender del cableado ni de los servicios de la Facultad. + +### 3.2 El proceso: de testeo a producción + +Si bien el proyecto llevó más tiempo del inicialmente estimado, esto responde a una decisión deliberada: se planificó desde el inicio una **etapa de testeo exhaustivo** antes de llevar el sistema a producción. Cada paso fue validado primero en un entorno virtual de pruebas antes de aplicarse al entorno real, minimizando los riesgos para la operación de la oficina. + +Este enfoque gradual permitió: + +- Detectar y resolver problemas en un entorno controlado, sin afectar a la usuaria. +- Validar que el sistema funciona correctamente **sin la infraestructura de dominio** de la Facultad — algo que no estaba documentado y que requirió trabajo de ingeniería inversa sobre el software provisto por Rectorado. +- Migrar la base de datos de producción con verificación completa de integridad. + +**A la fecha, el sistema se encuentra a un paso de estar implementado al 100%**, restando únicamente un ajuste de compatibilidad en la impresión de documentos, para el cual ya se dispone de una solución provisoria que permite continuar operando. + +### 3.3 Valor agregado: herramientas y metodología + +Un aspecto destacable del proceso es que, más allá del objetivo técnico central, el trabajo realizado durante estos meses **generó herramientas y metodologías de valor** que exceden al proyecto DASUTEN y benefician a la gestión de DTIC en su conjunto: + +- **Dashboard web de seguimiento:** Se desarrolló un sitio web interno que muestra en tiempo real el avance del proyecto con sus hitos, permitiendo visibilidad y trazabilidad del progreso. + +- **Sistema de bitácoras:** Se implementó un sistema de registro detallado de cada intervención técnica, creando un historial completo y auditable de los movimientos realizados sobre la infraestructura. + +- **Herramientas de automatización (Ecosistema ADN):** Se construyó un conjunto de scripts y herramientas internas que optimizan las tareas de administración — desde la orquestación de respaldos automatizados hasta la gestión remota de los equipos, permitiendo que operaciones que antes requerían horas de trabajo manual se ejecuten de forma desatendida. + +- **Metodología de trabajo con IA generativa:** Se incorporó la inteligencia artificial como herramienta de desarrollo operativo, tanto para la planificación y documentación del proyecto como para la creación de las herramientas mencionadas. Esta metodología de trabajo colaborativo entre el técnico y la IA demostró ser altamente productiva y replicable en futuros proyectos del área. + +Estas herramientas fueron posibles gracias al aprendizaje acumulado durante el proceso de migración, y representan un activo que queda disponible para la gestión de otros proyectos de DTIC. + +--- + +## 4. Estado Actual + +| Aspecto | Estado | +|:---|:---:| +| Sistema DASUTEN operativo en oficina | ✅ | +| Base de datos migrada y verificada | ✅ | +| Acceso y consulta de datos | ✅ | +| Administración remota por DTIC | ✅ | +| Respaldos automatizados | ✅ | +| Impresión de documentos | ⚠️ En ajuste | + +**El sistema se encuentra operativo.** La usuaria de la oficina DASUTEN puede acceder al sistema, consultar datos y realizar sus tareas habituales. El equipo de DTIC puede administrar, respaldar y actualizar el sistema de forma remota sin interferir con la operación de la oficina. + +El único punto pendiente es un ajuste en la función de impresión, vinculado a la compatibilidad de unas plantillas de Office. Se dispuso una solución provisoria que permite a la usuaria continuar imprimiendo mientras se resuelve definitivamente. + +--- + +## 5. Beneficios Alcanzados + +### Autonomía operativa +DASUTEN opera ahora sobre infraestructura propia en su oficina, desvinculada de la Facultad. Esto facilita también una eventual gestión directa desde Rectorado. + +### Optimización de recursos +Se logró la implementación completa **sin inversión en hardware nuevo**, aprovechando equipos existentes de prestaciones modestas. Un solo equipo compacto cumple ahora la función que antes requerían tres servidores virtuales. + +### Soporte remoto transparente +DTIC puede realizar respaldos, actualizaciones y resolución de problemas **sin interrumpir el trabajo de la oficina** y sin necesidad de desplazarse físicamente. + +### Mayor estabilidad +Al eliminar las dependencias cruzadas con la infraestructura de la Facultad, se reducen significativamente las fallas inesperadas. + +### Herramientas reutilizables +El proceso generó herramientas de automatización, seguimiento y documentación que quedan disponibles para futuros proyectos de DTIC. + +--- + +## 6. Próximos Pasos + +1. **Completar el ajuste de impresión** para alcanzar el 100% de funcionalidad. +2. **Estabilizar la configuración de red** del servidor para garantizar continuidad a largo plazo. +3. **Formalizar los procedimientos de respaldo** automatizado para la operación de rutina. +4. **Evaluar el retiro definitivo** de la infraestructura anterior, una vez confirmada la estabilidad completa del nuevo entorno. + +--- + +## 7. Conclusión + +La migración del sistema DASUTEN a una infraestructura autónoma demuestra que es posible **lograr una mejora sustancial en estabilidad, autonomía y capacidad de gestión** partiendo de recursos limitados y sin inversión adicional en equipamiento. + +El proyecto se encuentra en su tramo final, con el sistema operativo y la base de datos verificada. El proceso, aunque más extenso de lo inicialmente previsto, fue planificado como una transición gradual de testeo a producción que permitió minimizar riesgos y, como valor agregado, generar herramientas y metodologías que benefician al área en su conjunto. + +DASUTEN opera hoy de forma independiente en su propia oficina, administrable remotamente por DTIC y preparada para una gestión más ágil, ya sea desde la Facultad Regional o desde Rectorado. + +--- + +*Fin del informe.* diff --git a/docs/informes/2026-04_DASUTEN-migracion/_versiones/01_v0.2.md b/docs/informes/2026-04_DASUTEN-migracion/_versiones/01_v0.2.md new file mode 100644 index 00000000..bb780415 --- /dev/null +++ b/docs/informes/2026-04_DASUTEN-migracion/_versiones/01_v0.2.md @@ -0,0 +1,132 @@ +# INFORME DE AVANCE +## Migración del Sistema DASUTEN a Infraestructura Autónoma + +> **Área responsable:** Departamento de Tecnología de la Información y Comunicaciones (DTIC) +> **Facultad Regional La Rioja — Universidad Tecnológica Nacional** +> **Fecha:** 13 de abril de 2026 +> **Elaborado por:** Ricardo Monla — DTIC, UTN-FRLR +> **Destinatarios:** [Completar] +> **Versión:** 0.2 (Borrador) + +### Historial de versiones + +| Versión | Fecha | Cambios | +|:---:|:---:|:---| +| 0.1 | 13/04/2026 | Borrador inicial | +| 0.2 | 13/04/2026 | Se amplía contexto de situación inicial y esquema de trabajo previo | + +--- + +## 1. Contexto y Punto de Partida + +El sistema de gestión administrativa de **DASUTEN** (Departamento de Acción Social Universitaria Tecnológica Nacional) en la Facultad Regional La Rioja funcionaba desde hace años sobre la infraestructura informática compartida de la Facultad. + +Cuando la oficina de DASUTEN fue reubicada en un espacio propio, alejado de los servidores de la Facultad, se sumó un problema de conectividad: la señal de red debía recorrer múltiples puntos intermedios dentro del edificio, y la caída de cualquiera de ellos dejaba a la oficina sin acceso al sistema. + +### Solución provisoria que se venía aplicando + +Para resolver esta situación, se gestionó internamente la baja de una **línea de internet propia** para la oficina DASUTEN, eliminando la dependencia del cableado interno de la Facultad. Sin embargo, esto no era suficiente por sí solo: el sistema seguía requiriendo acceso a los servidores internos de la Facultad para funcionar. + +Se implementó entonces un esquema de trabajo remoto donde las usuarias — Andrea Almirón y Romina Molina — accedían desde la PC física de la oficina, a través de un software de escritorio remoto (AnyDesk), a una **PC virtual** alojada en los servidores. Recién desde esa PC virtual podían operar el sistema. + +Este esquema, si bien permitió dar continuidad al servicio y brindó la posibilidad de asistencia técnica 24/7 por parte de DTIC, implicaba: + +- Una experiencia de trabajo **indirecta** para las usuarias (PC física → escritorio remoto → PC virtual → sistema). +- La necesidad de mantener operativos **cuatro componentes** simultáneamente: un servidor de dominio, un servidor de base de datos, una PC virtual y la PC física con el software de acceso remoto. +- Múltiples puntos de falla que dificultaban el soporte. + +--- + +## 2. Objetivo del Proyecto + +Partiendo de esa situación, el objetivo fue diseñar una solución que permita al sistema DASUTEN operar de forma **directa y autónoma** en la propia oficina, con las siguientes premisas: + +- **Recursos limitados:** Aprovechar los equipos ya existentes — un equipo de escritorio de prestaciones modestas y un servidor compacto reutilizado. **Sin adquisición de hardware nuevo.** +- **Trabajo directo:** Que las usuarias puedan operar el sistema directamente desde la PC de la oficina, sin depender de conexiones remotas intermedias. +- **No interferir con la oficina:** Que DTIC pueda realizar respaldos, aplicar actualizaciones de Rectorado y resolver problemas **de forma remota y transparente**. +- **Simplicidad:** Una arquitectura lo más simple posible, administrable y confiable en el tiempo. + +--- + +## 3. Qué se logró + +### 3.1 La simplificación + +Se reemplazó la arquitectura compleja por un esquema directo y simple: + +| Aspecto | Antes | Ahora | +|:---|:---:|:---:| +| Componentes necesarios | 4 (dominio + BD + PC virtual + PC física) | 2 (servidor BD + PC física) | +| Forma de trabajo | Indirecta (vía escritorio remoto) | Directa (sistema en la PC) | +| Dependencia de red de Facultad | Sí | No | +| Puntos de falla | Múltiples | Mínimos | +| Requiere presencia física para soporte | Frecuentemente | No | +| Hardware nuevo adquirido | — | Ninguno | + +Las usuarias ahora operan el sistema **directamente desde la PC de la oficina**, sin necesidad de conexiones remotas intermedias. El servidor de base de datos funciona dentro de la misma oficina, en la red propia de DASUTEN. + +### 3.2 El proceso: de testeo a producción + +Si bien el proyecto llevó más tiempo del inicialmente estimado, esto responde a una decisión deliberada: se planificó una **etapa de testeo exhaustivo** antes de llevar el sistema a producción. Cada paso fue validado primero en un entorno virtual de pruebas antes de aplicarse al entorno real, minimizando los riesgos para la operación de la oficina. + +**A la fecha, el sistema se encuentra a un paso del 100%**, restando únicamente un ajuste de compatibilidad en la impresión de documentos, para el cual ya se dispone de una solución provisoria. + +### 3.3 Valor agregado: herramientas y metodología + +Un aspecto destacable es que, más allá del objetivo central, el trabajo realizado **generó herramientas y metodologías de valor** que benefician a la gestión de DTIC en su conjunto: + +- **Dashboard web de seguimiento** del proyecto, con visibilidad en tiempo real del progreso. +- **Sistema de bitácoras** con registro detallado de cada intervención técnica. +- **Herramientas de automatización** (Ecosistema ADN) para respaldos, gestión remota y tareas repetitivas. +- **Metodología de trabajo con IA generativa**, que demostró ser altamente productiva y replicable en futuros proyectos. + +--- + +## 4. Estado Actual + +| Aspecto | Estado | +|:---|:---:| +| Sistema operativo en oficina | ✅ | +| Base de datos migrada y verificada | ✅ | +| Trabajo directo (sin escritorio remoto) | ✅ | +| Administración remota por DTIC | ✅ | +| Respaldos automatizados | ✅ | +| Impresión de documentos | ⚠️ En ajuste | + +El sistema se encuentra **operativo**. La usuaria de la oficina puede acceder directamente al sistema, consultar datos y realizar sus tareas habituales. DTIC administra, respalda y actualiza el sistema de forma remota sin interferir con la oficina. + +Resta un ajuste en la impresión, con solución provisoria funcional mientras se resuelve. + +--- + +## 5. Beneficios Alcanzados + +- **Trabajo directo:** Las usuarias operan el sistema sin intermediarios, mejorando la experiencia y la productividad. +- **Autonomía operativa:** DASUTEN funciona sobre infraestructura propia, desvinculada de la Facultad y preparada para gestión directa desde Rectorado. +- **Optimización de recursos:** Implementación completa sin inversión en hardware nuevo. +- **Soporte transparente:** DTIC gestiona remotamente sin afectar la operación diaria. +- **Mayor estabilidad:** Al reducir de 4 componentes a 2, se minimizan las fallas. +- **Herramientas reutilizables:** El proceso generó activos aprovechables para otros proyectos de DTIC. + +--- + +## 6. Próximos Pasos + +1. Completar el ajuste de impresión para alcanzar el 100% de funcionalidad. +2. Estabilizar la configuración de red del servidor. +3. Formalizar los procedimientos de respaldo automatizado. +4. Evaluar el retiro definitivo de la infraestructura anterior. + +--- + +## 7. Conclusión + +La migración del sistema DASUTEN demuestra que es posible **lograr una mejora sustancial en estabilidad, autonomía y experiencia de trabajo** partiendo de recursos limitados y sin inversión adicional. + +Se pasó de un esquema indirecto — donde las usuarias dependían de conexiones remotas a través de múltiples componentes para poder trabajar — a un esquema directo y simple donde el sistema funciona en la propia oficina. + +El proyecto se encuentra en su tramo final, con el sistema operativo y la base de datos verificada. El proceso generó además herramientas y metodologías que quedan como activo del área para futuros proyectos. + +--- + +*Fin del informe.* diff --git a/docs/informes/2026-04_DASUTEN-migracion/_versiones/01_v0.3.md b/docs/informes/2026-04_DASUTEN-migracion/_versiones/01_v0.3.md new file mode 100644 index 00000000..c0c906fb --- /dev/null +++ b/docs/informes/2026-04_DASUTEN-migracion/_versiones/01_v0.3.md @@ -0,0 +1,130 @@ +# INFORME DE AVANCE +## Migración del Sistema DASUTEN a Infraestructura Autónoma + +> **Área responsable:** Departamento de Tecnología de la Información y Comunicaciones (DTIC) +> **Facultad Regional La Rioja — Universidad Tecnológica Nacional** +> **Fecha:** 13 de abril de 2026 +> **Elaborado por:** Ricardo Monla — DTIC, UTN-FRLR +> **Destinatarios:** [Completar] +> **Versión:** 0.3 (Borrador) +> +> *Este documento es de carácter ejecutivo y narrativo. El detalle técnico completo se encuentra en el documento complementario [02_informe_tecnico_DASUTEN.md](02_informe_tecnico_DASUTEN.md).* + +--- + +## 1. Contexto y Punto de Partida + +El sistema de gestión administrativa de **DASUTEN** (Departamento de Acción Social Universitaria Tecnológica Nacional) en la Facultad Regional La Rioja funcionaba desde hace años sobre la infraestructura informática compartida de la Facultad: servidores, red interna y servicios de dominio que atienden a toda la institución. + +Si bien esta configuración fue funcional durante un tiempo, con el correr de los años fue manifestando limitaciones concretas: + +- **Fragilidad operativa:** Cualquier incidencia en la red o los servidores de la Facultad —incluso ajena a DASUTEN— impactaba directamente en el funcionamiento del sistema. +- **Complejidad desproporcionada:** La arquitectura heredada requería múltiples servidores virtuales y un controlador de dominio, componentes pensados para entornos de mayor escala que resultaban sobredimensionados para las necesidades de una sola oficina. +- **Dificultad de mantenimiento:** Los respaldos de datos y las actualizaciones periódicas que envía Rectorado requerían coordinación con la infraestructura general de la Facultad, generando demoras y dependencias cruzadas. +- **Limitación de autonomía:** DASUTEN, si bien opera dentro de las instalaciones de la Facultad, responde funcionalmente a **Rectorado (Buenos Aires)**. La dependencia de la infraestructura local dificultaba una eventual gestión directa desde la sede central. + +A esta situación se sumó que, al reubicarse la oficina en un espacio propio alejado de los servidores, las fallas de conectividad se agravaron por la cantidad de puntos intermedios en la red. Para dar continuidad al servicio, se gestionó una línea de internet propia y se implementó un esquema de trabajo indirecto donde las usuarias — Andrea Almirón y Romina Molina — accedían mediante escritorio remoto a una PC virtual para poder operar el sistema. Esto implicaba mantener cuatro componentes simultáneamente (servidor de dominio, servidor de base de datos, PC virtual y PC física), multiplicando los puntos de falla. + +--- + +## 2. Objetivo del Proyecto + +Diseñar e implementar una solución que permita al sistema DASUTEN operar de forma **completamente autónoma**, teniendo en cuenta: + +- **Recursos limitados:** Aprovechar equipos ya existentes — un equipo de escritorio de prestaciones modestas y un servidor compacto reutilizado. **Sin adquisición de hardware nuevo.** +- **No interferir con la oficina:** Que DTIC pueda realizar respaldos, actualizaciones de Rectorado y soporte técnico **de forma remota y transparente**, sin afectar las tareas cotidianas. +- **Trabajo directo:** Que las usuarias operen el sistema directamente desde la PC de la oficina, sin depender de conexiones remotas intermedias. +- **Simplicidad:** Una arquitectura lo más simple posible, administrable y confiable en el tiempo. + +--- + +## 3. Qué se logró + +### 3.1 La simplificación + +Se reemplazó la arquitectura compleja por un esquema directo y simple: + +| Aspecto | Antes | Ahora | +|:---|:---:|:---:| +| Componentes necesarios | 4 | 2 | +| Forma de trabajo | Indirecta (vía escritorio remoto) | Directa (sistema en la PC) | +| Dependencia de red de Facultad | Sí | No | +| Puntos de falla | Múltiples | Mínimos | +| Requiere presencia física para soporte | Frecuentemente | No | +| Hardware nuevo adquirido | — | Ninguno | + +Las usuarias ahora operan el sistema **directamente desde la PC de la oficina**. El servidor de base de datos funciona dentro de la misma oficina, en la red propia de DASUTEN, sin intermediarios. + +### 3.2 El proceso: de testeo a producción + +Si bien el proyecto llevó más tiempo del inicialmente estimado, esto responde a una decisión deliberada: se planificó una **etapa de testeo exhaustivo** antes de llevar el sistema a producción. Cada paso fue validado primero en un entorno de pruebas antes de aplicarse al entorno real, minimizando riesgos para la operación de la oficina. + +**A la fecha, el sistema se encuentra a un paso del 100%**, restando únicamente un ajuste de compatibilidad en la impresión de documentos, para el cual ya se dispone de una solución provisoria. + +### 3.3 Valor agregado: herramientas y metodología + +Más allá del objetivo central, el trabajo realizado **generó herramientas y metodologías de valor** que benefician a la gestión de DTIC en su conjunto: + +- **Dashboard web de seguimiento** del proyecto, con visibilidad en tiempo real del progreso. +- **Sistema de bitácoras** con registro detallado y auditable de cada intervención técnica. +- **Herramientas de automatización** (Ecosistema ADN) para respaldos, gestión remota y tareas repetitivas. +- **Metodología de trabajo con IA generativa**, altamente productiva y replicable en futuros proyectos. + +--- + +## 4. Estado Actual + +| Aspecto | Estado | +|:---|:---:| +| Sistema operativo en oficina | ✅ | +| Base de datos migrada y verificada | ✅ | +| Trabajo directo (sin escritorio remoto) | ✅ | +| Administración remota por DTIC | ✅ | +| Respaldos automatizados | ✅ | +| Impresión de documentos | ⚠️ En ajuste | + +El sistema se encuentra **operativo**. La usuaria accede directamente al sistema desde la PC de la oficina. DTIC administra y respalda de forma remota sin interferir con la operación diaria. + +Resta un ajuste en la impresión, con solución provisoria funcional. + +--- + +## 5. Beneficios Alcanzados + +- **Trabajo directo:** Las usuarias operan el sistema sin intermediarios. +- **Autonomía operativa:** Infraestructura propia, desvinculada de la Facultad, preparada para gestión desde Rectorado. +- **Optimización de recursos:** Sin inversión en hardware nuevo. +- **Soporte transparente:** DTIC gestiona remotamente sin afectar la oficina. +- **Mayor estabilidad:** De 4 componentes a 2, menos fallas posibles. +- **Herramientas reutilizables:** Activos aprovechables para otros proyectos de DTIC. + +--- + +## 6. Próximos Pasos + +1. Completar el ajuste de impresión para alcanzar el 100% de funcionalidad. +2. Estabilizar la configuración de red del servidor. +3. Formalizar los procedimientos de respaldo automatizado. +4. Evaluar el retiro definitivo de la infraestructura anterior. + +--- + +## 7. Conclusión + +La migración del sistema DASUTEN demuestra que es posible **lograr una mejora sustancial en estabilidad, autonomía y experiencia de trabajo** partiendo de recursos limitados y sin inversión adicional. + +Se pasó de un esquema indirecto y complejo a uno directo y simple, donde el sistema funciona en la propia oficina. El proceso generó además herramientas y metodologías que quedan como activo del área para futuros proyectos. + +DASUTEN opera hoy de forma independiente, administrable remotamente por DTIC y preparada para una gestión más ágil desde la Facultad Regional o desde Rectorado. + +--- + +### Historial de versiones + +| Versión | Fecha | Cambios | +|:---:|:---:|:---| +| 0.1 | 13/04/2026 | Borrador inicial | +| 0.2 | 13/04/2026 | Se amplía contexto de situación inicial | +| 0.3 | 13/04/2026 | Se retoma enfoque narrativo, se integra contexto como complemento, se agrega referencia al documento técnico | + +*Fin del informe.* diff --git a/docs/informes/2026-04_DASUTEN-migracion/_versiones/02_informe_tecnico_DASUTEN.md b/docs/informes/2026-04_DASUTEN-migracion/_versiones/02_informe_tecnico_DASUTEN.md new file mode 100644 index 00000000..b72da606 --- /dev/null +++ b/docs/informes/2026-04_DASUTEN-migracion/_versiones/02_informe_tecnico_DASUTEN.md @@ -0,0 +1,407 @@ +# INFORME TÉCNICO — Migración del Sistema DASUTEN a Nuevo Servidor + +> **Área:** Departamento de Tecnología de la Información y Comunicaciones (DTIC) +> **Proyecto:** Migración de infraestructura DASUTEN — Modo Workgroup sin Domain Controller +> **Código interno:** A04.P005 +> **Fecha del informe:** 13 de abril de 2026 +> **Elaborado por:** Ricardo Monla — Área DTIC, UTN-FRLR + +--- + +## 1. Resumen Ejecutivo + +Se informa el avance de la migración del sistema de gestión administrativa **DASUTEN** (Departamento de Acción Social Universitaria Tecnológica Nacional) desde la infraestructura compartida de la Facultad hacia un entorno independiente, autónomo y simplificado. + +**Estado general del proyecto: 95% completado.** + +El sistema DASUTEN se encuentra **operativo** en la nueva infraestructura desde el día 13 de abril de 2026, habiendo superado exitosamente las pruebas funcionales de acceso a datos. Resta únicamente resolver un problema de compatibilidad de impresión vinculado a las plantillas de Office utilizadas por el sistema. + +### Logros principales + +- ✅ Servidor de base de datos **completamente migrado** a infraestructura nueva. +- ✅ Base de datos de producción **restaurada y verificada** sin errores de integridad. +- ✅ Sistema DASUTEN **desplegado y operativo** en la PC física de la usuaria. +- ✅ Eliminación exitosa de la dependencia del **Active Directory (Domain Controller)**. +- ✅ Simplificación de la arquitectura de red — de 3 servidores virtuales a 1. +- ⚠️ Pendiente: resolución de problema de impresión por compatibilidad de plantillas Office. + +--- + +## 2. Antecedentes y Motivación + +### 2.1 Situación previa + +El sistema DASUTEN operaba sobre infraestructura compartida con la Facultad Regional La Rioja, dependiendo de: + +- Un servidor SQL Server alojado en la red interna de la Facultad (`srvv-fenix`). +- Un Domain Controller Active Directory para la autenticación de usuarios. +- Conectividad de red interna de la Facultad con routing complejo. + +Esta configuración generaba **múltiples puntos de falla**: +- Dependencia del dominio institucional para la autenticación. +- Complejidad de red con subnetting privado, NAT y gateway interno. +- Cualquier cambio en la infraestructura de la Facultad impactaba directamente en DASUTEN. + +### 2.2 Objetivo del proyecto + +**Migrar el sistema DASUTEN a una infraestructura independiente y simplificada**, eliminando la dependencia del Domain Controller (Active Directory) y utilizando un esquema de red **Workgroup** directo, con el fin de: + +1. Reducir la complejidad operativa. +2. Minimizar los puntos de falla. +3. Garantizar la autonomía operativa de DASUTEN respecto de la infraestructura de la Facultad. +4. Facilitar la eventual gestión desde Rectorado (Buenos Aires) si fuera necesario. + +--- + +## 3. Infraestructura Implementada + +### 3.1 Arquitectura de red + +Se implementó una topología de **red plana simplificada**, donde todos los equipos obtienen direccionamiento IP directamente del router del ISP, eliminando subnetting privado y routing interno: + +``` +Internet + │ +Router ISP (192.168.1.1 — Gateway) + │ + ├── srv-dasu (Proxmox VE) → 192.168.1.13 + │ └── dasu-sql4 (VM 106) → 192.168.1.11 [SQL Server 2019] + │ + └── dasu-pc (PC Física) → DHCP ISP [Estación de trabajo] +``` + +### 3.2 Componentes del nuevo entorno + +| Componente | Descripción | Estado | +|:---|:---|:---:| +| **srv-dasu** | Servidor Proxmox VE 9.1 (Hipervisor) — CPU Intel, 15 GB RAM, 94 GB disco | ✅ Operativo | +| **dasu-sql4** (VM 106) | Windows Server 2022 — SQL Server 2019 Enterprise — 4 GB RAM, 2 vCPU, discos 60+120 GB | ✅ Operativo | +| **dasu-pc** | PC Física — Windows 10 Pro — AMD Ryzen 5, 8 GB RAM — Oficina DASUTEN | ✅ Operativo | + +### 3.3 Comparativa: Antes vs. Después + +| Aspecto | Enfoque Anterior (con DC) | Enfoque Actual (Workgroup) | +|:---|:---|:---| +| **Red** | Privada 10.0.100.x (gateway interno) | DHCP del ISP (red plana) | +| **Autenticación SQL** | Windows Integrated (Kerberos) | SQL Auth (mixta) | +| **Usuarios** | Active Directory | Usuarios locales Windows | +| **DNS** | AD DNS (10.0.100.10) | DNS del ISP (automático) | +| **Complejidad de red** | Alta (DC + DNS + dominio + routing) | Mínima (red plana ISP) | +| **Puntos de falla** | DC, SQL, red dominio, routing | Solo SQL | +| **VMs necesarias** | 3 (DC + SQL + PC) | 1 (solo SQL) | + +--- + +## 4. Fases Ejecutadas y Progreso + +### Resumen de progreso por fase + +| Fase | Descripción | Estado | Progreso | +|:---:|:---|:---:|:---:| +| 1 | Preparación del entorno (srv-dasu) | ✅ Completada | 100% | +| 2 | Creación de VM SQL Server de prueba | ✅ Completada | 100% | +| 3 | Creación de VM PC Cliente de prueba | ✅ Completada | 100% | +| 4 | VM definitiva dasu-sql4 | ✅ Completada | 100% | +| 5 | Migración de base de datos | ✅ Completada | 100% | +| 5b | Hardening y persistencia de servicios | ✅ Completada | 100% | +| 6 | Validación con PC cliente virtual | ✅ Completada | 100% | +| 7 | Despliegue en PC física (producción) | 🚧 En curso | 75% | +| 8 | Refresco final de base de datos | ✅ Completada | 100% | + +### 4.1 Fase 1-3: Preparación y pruebas de concepto (27-28 marzo) + +Se preparó el hipervisor Proxmox, se reconfiguró el bridge de red para usar DHCP directo del ISP, y se crearon VMs de prueba para validar la viabilidad del enfoque sin Domain Controller. + +**Hallazgo crítico:** Se detectó y resolvió que el bridge de red estaba configurado con la IP de una red privada anterior, lo cual habría impedido la conectividad de las nuevas VMs. + +### 4.2 Fase 4: Servidor SQL definitivo (9-10 abril) + +Se creó la VM definitiva `dasu-sql4` (VM 106) con una arquitectura optimizada: + +- **Discos separados:** 60 GB para SO + 120 GB exclusivo para datos SQL (buena práctica). +- **SQL Server 2019 Enterprise** instalado con autenticación mixta. +- **Gestión remota** asegurada vía OpenSSH Server (puerto 7022) y Tailscale VPN. + +### 4.3 Fase 5: Migración de Base de Datos (11 abril) + +Se ejecutó la migración completa de la base de datos de producción: + +1. **Exportación:** Backup comprimido (~1.33 GB) generado desde el servidor origen (`srvv-fenix`). +2. **Transferencia:** Archivo movido a través de la VPN institucional (Tailscale) en múltiples tramos seguros. +3. **Restauración:** Base restaurada exitosamente en 26 segundos (354 MB/s). +4. **Verificación:** `DBCC CHECKDB` ejecutado sin errores — integridad de datos confirmada al 100%. + +### 4.4 Fase 5b: Hardening (11 abril) + +Se validó que todos los servicios críticos (SSH, SQL Server) sobreviven reinicios del servidor sin intervención manual: + +- OpenSSH Server: arranque automático ✅ +- SQL Server: arranque automático ✅ +- IP de red: mantenida tras reinicio ✅ + +### 4.5 Fase 6: Validación funcional en entorno virtual (11 abril) + +Se restauró una VM cliente desde backup para simular el entorno real de la oficina DASUTEN: + +- Se desvinculó la PC del dominio anterior y se unió al Workgroup `DASUTEN`. +- Se reconfiguró el archivo de conexión del sistema (`Kermet.ini`) para apuntar al nuevo servidor SQL. +- **Resultado:** El sistema DASUTEN conectó exitosamente, actualizó estructuras y descargó novedades. + +**Conclusión técnica clave:** Se determinó mediante ingeniería inversa que el sistema DASUTEN (desarrollado en Visual FoxPro) **no tiene dependencia real del Active Directory** si se configura explícitamente la autenticación SQL en su archivo de configuración. + +### 4.6 Fase 7: Despliegue en PC física de producción (13 abril — EN CURSO) + +Se desplegó el sistema en la PC física de la oficina DASUTEN (`dasu-pc`): + +- **Directorio del sistema** (`C:\SysDasuten`) transferido desde la VM de pruebas. +- **Configuración de conexión** apuntada al nuevo servidor `dasu-sql4`. +- **Acceso directo** creado en el escritorio de la usuaria (`aalmiron`). +- **Pruebas funcionales:** + - Inicio del sistema: ✅ OK + - Acceso a datos (ventana de bonos): ✅ OK + - **Impresión: ❌ FALLO** — Error al imprimir, posiblemente por incompatibilidad de las plantillas de Office (el sistema usa automatización OLE con Word/Excel). + +### 4.7 Fase 8: Refresco final de base de datos (13 abril) + +Se ejecutó un refresco automatizado de la base de datos para asegurar que el sistema arranca con los datos más actualizados del servidor de origen: + +- Backup generado automáticamente desde el origen (44.8 segundos). +- Transferido de manera segura (SMB + SCP por VPN). +- Restaurado con `RESTORE DATABASE ... WITH REPLACE`. +- Integridad verificada con `DBCC CHECKDB` — sin errores. + +--- + +## 5. Estado Actual + +### 5.1 Funcionalidades operativas + +| Funcionalidad | Estado | +|:---|:---:| +| Acceso al sistema DASUTEN | ✅ Operativo | +| Consulta de datos (bonos, registros) | ✅ Operativo | +| Conexión a base de datos SQL Server | ✅ Operativo | +| Acceso remoto para soporte (Tailscale/SSH) | ✅ Operativo | +| Impresión desde el sistema | ❌ Pendiente | + +### 5.2 Problema pendiente: Impresión + +**Descripción:** Al intentar imprimir desde el sistema DASUTEN en la PC física, se produce un error. El diagnóstico preliminar indica que la causa es una incompatibilidad entre las **plantillas de Office** requeridas por el sistema (diseñadas para Office 2003/2007) y la versión de Office actualmente instalada en la PC. + +**Impacto:** La usuaria no puede generar documentos impresos desde el nuevo sistema. + +**Workaround temporal:** Se habilitó acceso remoto (TeamViewer) desde la PC física hacia la VM de pruebas (`dasu-pcv`), donde la impresión funciona correctamente. La usuaria puede continuar operando mientras se resuelve el problema. + +**Plan de resolución:** Verificar y ajustar la versión/configuración de Office en `dasu-pc` para compatibilizarla con las plantillas del sistema. + +--- + +## 6. Beneficios Obtenidos + +1. **Independencia operativa:** DASUTEN ya no depende de la infraestructura de red ni de los servidores de la Facultad. +2. **Simplificación:** Se pasó de 3 VMs + Domain Controller a solo 1 VM (SQL Server), reduciendo significativamente la complejidad. +3. **Reducción de puntos de falla:** De múltiples (DC, DNS institucional, routing complejo) a uno solo (SQL Server). +4. **Acceso remoto robusto:** Gestión técnica asegurada vía VPN (Tailscale) y SSH, sin necesidad de presencia física. +5. **Autonomía:** La infraestructura puede ser gestionada independientemente, facilitando una eventual transferencia a Rectorado. +6. **Preservación del entorno anterior:** Las VMs del enfoque con DC fueron apagadas y preservadas como respaldo, permitiendo un rollback si fuera necesario. + +--- + +## 7. Cronograma Resumen + +| Fecha | Hito | +|:---|:---| +| 27/03/2026 | Inicio — Preparación del entorno e inicio de pruebas de concepto | +| 28/03/2026 | VM SQL Server de prueba operativa | +| 09-10/04/2026 | Servidor SQL definitivo (dasu-sql4) desplegado y operativo | +| 11/04/2026 | Base de datos migrada, verificada y hardening completado | +| 11/04/2026 | Validación funcional exitosa en entorno virtual | +| 13/04/2026 | Despliegue en PC física de producción — sistema operativo con observación de impresión | + +--- + +## 8. Próximos Pasos + +| Prioridad | Acción | Plazo estimado | +|:---:|:---|:---| +| 🔴 Alta | Resolver problema de impresión (compatibilidad Office/plantillas) | 1-3 días hábiles | +| 🟡 Media | Reservar IPs fijas en router ISP (prevenir cambios por DHCP) | 1 semana | +| 🟢 Baja | Evaluar apagado definitivo de VMs legacy (DC, SQL antiguo) | Tras validación completa | +| 🟢 Baja | Documentar procedimiento de respaldo automatizado de la nueva BD | 2 semanas | + +--- + +## 9. Conclusión + +La migración del sistema DASUTEN a la nueva infraestructura se encuentra **prácticamente completada**, con el sistema operativo y los datos verificados. El enfoque sin Domain Controller demostró ser completamente viable, logrando una **reducción significativa de la complejidad** y de los puntos de falla. + +El único aspecto pendiente es la resolución del problema de impresión, para el cual ya se dispone de un workaround funcional que permite a la usuaria continuar operando sin interrupción. + +Se estima que el proyecto quedará **100% finalizado** dentro de los próximos días hábiles, una vez resuelta la compatibilidad de plantillas de Office. + +--- + +# ANEXO TÉCNICO + +## A. Inventario de Nodos + +### A.1 Servidor Hipervisor: srv-dasu + +| Campo | Valor | +|:---|:---| +| **Rol** | Hipervisor Proxmox VE 9.1 | +| **IP LAN** | 192.168.1.13 (DHCP ISP) | +| **IP VPN** | 100.112.46.104 (Tailscale) | +| **Bridge** | vmbr0 sobre enp33s0 | +| **RAM** | 15 GB total / ~4 GB libre post-VMs | +| **Disco** | 94 GB (68% uso, thin provisioned) | +| **Acceso remoto** | Tailscale + SSH | + +### A.2 Servidor SQL: dasu-sql4 (VM 106) + +| Campo | Valor | +|:---|:---| +| **Rol** | SQL Server 2019 Enterprise | +| **SO** | Windows Server 2022 (Español) | +| **IP LAN** | 192.168.1.11 (DHCP ISP) | +| **IP VPN** | 100.107.15.82 (Tailscale — inestable) | +| **Workgroup** | DASUTEN | +| **RAM** | 4 GB | +| **vCPU** | 2 | +| **Disco 1 (sata0)** | 60 GB — Sistema Operativo | +| **Disco 2 (sata1)** | 120 GB — Datos SQL (GPT/NTFS "SQLData") | +| **Estructura SQL** | F:\DATA, F:\LOG, F:\BACKUP, F:\TEMPDB | +| **Autenticación** | Mixta (SQL Auth + Windows) | +| **Puerto SQL** | TCP 1433 | +| **SSH** | Puerto 7022 (OpenSSH Server, arranque automático) | +| **Servicios auto-start** | MSSQLSERVER, sshd | + +### A.3 PC Física Cliente: dasu-pc + +| Campo | Valor | +|:---|:---| +| **Rol** | Estación de trabajo DASUTEN | +| **Patrimonio** | 32120 | +| **Ubicación** | Oficina DASUTEN (externa a Facultad) | +| **SO** | Windows 10 Pro | +| **Workgroup** | DASUTEN | +| **IP VPN** | 100.119.233.11 (Tailscale) | +| **SSH** | UTNLR@100.119.233.11:7022 | +| **CPU** | AMD Ryzen 5 4600G @ 4.30GHz (6 núcleos) | +| **RAM** | 8 GB DDR4-3200 | +| **Placa Base** | Asus Prime A320M-K | +| **Usuaria principal** | Andrea Almirón (`aalmiron`) | +| **Directorio DASUTEN** | C:\SysDasuten | +| **Config conexión** | C:\SysDasuten\Sistema\Kermet.ini | + +### A.4 VM Cliente de Pruebas: dasu-pcv (VM 107) — Test-Bed + +| Campo | Valor | +|:---|:---| +| **Rol** | Entorno de pruebas / fallback temporal | +| **SO** | Windows 10 | +| **Workgroup** | DASUTEN | +| **SSH** | Puerto 7022 | +| **Estado** | Operativa (usada como fallback vía TeamViewer) | + +--- + +## B. Configuración del Sistema DASUTEN + +### B.1 Archivo de conexión: Kermet.ini + +Parámetros clave configurados para la operación sin Domain Controller: + +```ini +SERVER=dasu-sql4 +DATABASE=sysdasuten +UID=sa +PWD=[credencial almacenada en bóveda] +``` + +> **Nota técnica:** El campo `UID` debe estar explícitamente configurado con `sa` (u otra cuenta SQL Auth). Si se deja vacío, el sistema DASUTEN (Visual FoxPro) asume autenticación Windows integrada (SSPI/Kerberos), lo cual falla en entorno Workgroup sin Domain Controller. + +### B.2 Directorio del sistema + +``` +C:\SysDasuten\ +├── Sistema\ → Ejecutables VFP + Kermet.ini +├── Plantillas\ → Templates Word/Excel para impresión +└── [otros directorios de la aplicación] +``` + +--- + +## C. Base de Datos: sysdasuten + +| Campo | Valor | +|:---|:---| +| **Nombre** | sysdasuten | +| **Motor** | SQL Server 2019 Enterprise | +| **Tamaño backup comprimido** | ~1.33 GB | +| **Nivel de compatibilidad** | 100 | +| **Recovery model** | FULL | +| **Integridad (DBCC CHECKDB)** | ✅ Sin errores | +| **Tiempo de restauración** | 26 segundos (354 MB/s) | +| **Origen de datos** | srvv-fenix (servidor legacy de Facultad) | +| **Último refresco** | 13/04/2026 | + +### C.1 Ruta de transferencia del backup + +``` +srvv-fenix (Origen) + │ [BACKUP DATABASE ... WITH COMPRESSION] + │ → E:\BK_SQL\sysdasuten_compressed_ADN.bak (~1.33 GB) + ↓ +srv-ns8 (Tránsito) + │ [SMB/smbget vía dominio] + │ → /var/tmp/ + ↓ +srv-dasu (Tránsito) + │ [SCP vía Tailscale] + ↓ +dasu-sql4 (Destino) + │ [RESTORE DATABASE ... WITH REPLACE] + └ → F:\BACKUP\ → F:\DATA\ + F:\LOG\ +``` + +--- + +## D. VMs Legacy Preservadas (Apagadas) + +| VM ID | Nombre | Rol anterior | Estado | +|:---:|:---|:---|:---:| +| 100 | dasu-srvv-dc | Domain Controller AD DS | 🛑 Apagada | +| 101 | dasu-srvv-sql | SQL Server (dominio) | 🛑 Apagada | +| 102 | dasu-pcv | PC cliente (dominio) | 🛑 Apagada | +| 103 | dasu-sql2 | SQL Server prueba v1 | 🛑 Descartada | +| 104 | dasu-pcv2 | PC prueba v1 | 🛑 Descartada | + +> Las VMs legacy (100-102) se mantienen apagadas como respaldo. Pueden reactivarse en caso de necesitar un rollback al enfoque con Domain Controller. + +--- + +## E. Accesos Remotos Configurados + +| Nodo | Método | Detalle | +|:---|:---|:---| +| srv-dasu | Tailscale SSH | 100.112.46.104 | +| dasu-sql4 | SSH (LAN) | 192.168.1.11:7022 | +| dasu-sql4 | Tailscale | 100.107.15.82 (inestable) | +| dasu-pc | Tailscale SSH | 100.119.233.11:7022 | +| dasu-pc | AnyDesk | Instalado (GUI) | +| dasu-pcv | TeamViewer | Activo (workaround temporal) | + +--- + +## F. Cuenta de Gestión VPN + +| Campo | Valor | +|:---|:---| +| **Proveedor** | Tailscale | +| **Cuenta** | pcdasu0@frlr.utn.edu.ar | +| **Nodos vinculados** | srv-dasu, dasu-sql4, dasu-pc, dasu-pcv | + +--- + +*Fin del informe técnico.* diff --git a/docs/informes/2026-04_DASUTEN-migracion/_versiones/02_v0.1.md b/docs/informes/2026-04_DASUTEN-migracion/_versiones/02_v0.1.md new file mode 100644 index 00000000..b72da606 --- /dev/null +++ b/docs/informes/2026-04_DASUTEN-migracion/_versiones/02_v0.1.md @@ -0,0 +1,407 @@ +# INFORME TÉCNICO — Migración del Sistema DASUTEN a Nuevo Servidor + +> **Área:** Departamento de Tecnología de la Información y Comunicaciones (DTIC) +> **Proyecto:** Migración de infraestructura DASUTEN — Modo Workgroup sin Domain Controller +> **Código interno:** A04.P005 +> **Fecha del informe:** 13 de abril de 2026 +> **Elaborado por:** Ricardo Monla — Área DTIC, UTN-FRLR + +--- + +## 1. Resumen Ejecutivo + +Se informa el avance de la migración del sistema de gestión administrativa **DASUTEN** (Departamento de Acción Social Universitaria Tecnológica Nacional) desde la infraestructura compartida de la Facultad hacia un entorno independiente, autónomo y simplificado. + +**Estado general del proyecto: 95% completado.** + +El sistema DASUTEN se encuentra **operativo** en la nueva infraestructura desde el día 13 de abril de 2026, habiendo superado exitosamente las pruebas funcionales de acceso a datos. Resta únicamente resolver un problema de compatibilidad de impresión vinculado a las plantillas de Office utilizadas por el sistema. + +### Logros principales + +- ✅ Servidor de base de datos **completamente migrado** a infraestructura nueva. +- ✅ Base de datos de producción **restaurada y verificada** sin errores de integridad. +- ✅ Sistema DASUTEN **desplegado y operativo** en la PC física de la usuaria. +- ✅ Eliminación exitosa de la dependencia del **Active Directory (Domain Controller)**. +- ✅ Simplificación de la arquitectura de red — de 3 servidores virtuales a 1. +- ⚠️ Pendiente: resolución de problema de impresión por compatibilidad de plantillas Office. + +--- + +## 2. Antecedentes y Motivación + +### 2.1 Situación previa + +El sistema DASUTEN operaba sobre infraestructura compartida con la Facultad Regional La Rioja, dependiendo de: + +- Un servidor SQL Server alojado en la red interna de la Facultad (`srvv-fenix`). +- Un Domain Controller Active Directory para la autenticación de usuarios. +- Conectividad de red interna de la Facultad con routing complejo. + +Esta configuración generaba **múltiples puntos de falla**: +- Dependencia del dominio institucional para la autenticación. +- Complejidad de red con subnetting privado, NAT y gateway interno. +- Cualquier cambio en la infraestructura de la Facultad impactaba directamente en DASUTEN. + +### 2.2 Objetivo del proyecto + +**Migrar el sistema DASUTEN a una infraestructura independiente y simplificada**, eliminando la dependencia del Domain Controller (Active Directory) y utilizando un esquema de red **Workgroup** directo, con el fin de: + +1. Reducir la complejidad operativa. +2. Minimizar los puntos de falla. +3. Garantizar la autonomía operativa de DASUTEN respecto de la infraestructura de la Facultad. +4. Facilitar la eventual gestión desde Rectorado (Buenos Aires) si fuera necesario. + +--- + +## 3. Infraestructura Implementada + +### 3.1 Arquitectura de red + +Se implementó una topología de **red plana simplificada**, donde todos los equipos obtienen direccionamiento IP directamente del router del ISP, eliminando subnetting privado y routing interno: + +``` +Internet + │ +Router ISP (192.168.1.1 — Gateway) + │ + ├── srv-dasu (Proxmox VE) → 192.168.1.13 + │ └── dasu-sql4 (VM 106) → 192.168.1.11 [SQL Server 2019] + │ + └── dasu-pc (PC Física) → DHCP ISP [Estación de trabajo] +``` + +### 3.2 Componentes del nuevo entorno + +| Componente | Descripción | Estado | +|:---|:---|:---:| +| **srv-dasu** | Servidor Proxmox VE 9.1 (Hipervisor) — CPU Intel, 15 GB RAM, 94 GB disco | ✅ Operativo | +| **dasu-sql4** (VM 106) | Windows Server 2022 — SQL Server 2019 Enterprise — 4 GB RAM, 2 vCPU, discos 60+120 GB | ✅ Operativo | +| **dasu-pc** | PC Física — Windows 10 Pro — AMD Ryzen 5, 8 GB RAM — Oficina DASUTEN | ✅ Operativo | + +### 3.3 Comparativa: Antes vs. Después + +| Aspecto | Enfoque Anterior (con DC) | Enfoque Actual (Workgroup) | +|:---|:---|:---| +| **Red** | Privada 10.0.100.x (gateway interno) | DHCP del ISP (red plana) | +| **Autenticación SQL** | Windows Integrated (Kerberos) | SQL Auth (mixta) | +| **Usuarios** | Active Directory | Usuarios locales Windows | +| **DNS** | AD DNS (10.0.100.10) | DNS del ISP (automático) | +| **Complejidad de red** | Alta (DC + DNS + dominio + routing) | Mínima (red plana ISP) | +| **Puntos de falla** | DC, SQL, red dominio, routing | Solo SQL | +| **VMs necesarias** | 3 (DC + SQL + PC) | 1 (solo SQL) | + +--- + +## 4. Fases Ejecutadas y Progreso + +### Resumen de progreso por fase + +| Fase | Descripción | Estado | Progreso | +|:---:|:---|:---:|:---:| +| 1 | Preparación del entorno (srv-dasu) | ✅ Completada | 100% | +| 2 | Creación de VM SQL Server de prueba | ✅ Completada | 100% | +| 3 | Creación de VM PC Cliente de prueba | ✅ Completada | 100% | +| 4 | VM definitiva dasu-sql4 | ✅ Completada | 100% | +| 5 | Migración de base de datos | ✅ Completada | 100% | +| 5b | Hardening y persistencia de servicios | ✅ Completada | 100% | +| 6 | Validación con PC cliente virtual | ✅ Completada | 100% | +| 7 | Despliegue en PC física (producción) | 🚧 En curso | 75% | +| 8 | Refresco final de base de datos | ✅ Completada | 100% | + +### 4.1 Fase 1-3: Preparación y pruebas de concepto (27-28 marzo) + +Se preparó el hipervisor Proxmox, se reconfiguró el bridge de red para usar DHCP directo del ISP, y se crearon VMs de prueba para validar la viabilidad del enfoque sin Domain Controller. + +**Hallazgo crítico:** Se detectó y resolvió que el bridge de red estaba configurado con la IP de una red privada anterior, lo cual habría impedido la conectividad de las nuevas VMs. + +### 4.2 Fase 4: Servidor SQL definitivo (9-10 abril) + +Se creó la VM definitiva `dasu-sql4` (VM 106) con una arquitectura optimizada: + +- **Discos separados:** 60 GB para SO + 120 GB exclusivo para datos SQL (buena práctica). +- **SQL Server 2019 Enterprise** instalado con autenticación mixta. +- **Gestión remota** asegurada vía OpenSSH Server (puerto 7022) y Tailscale VPN. + +### 4.3 Fase 5: Migración de Base de Datos (11 abril) + +Se ejecutó la migración completa de la base de datos de producción: + +1. **Exportación:** Backup comprimido (~1.33 GB) generado desde el servidor origen (`srvv-fenix`). +2. **Transferencia:** Archivo movido a través de la VPN institucional (Tailscale) en múltiples tramos seguros. +3. **Restauración:** Base restaurada exitosamente en 26 segundos (354 MB/s). +4. **Verificación:** `DBCC CHECKDB` ejecutado sin errores — integridad de datos confirmada al 100%. + +### 4.4 Fase 5b: Hardening (11 abril) + +Se validó que todos los servicios críticos (SSH, SQL Server) sobreviven reinicios del servidor sin intervención manual: + +- OpenSSH Server: arranque automático ✅ +- SQL Server: arranque automático ✅ +- IP de red: mantenida tras reinicio ✅ + +### 4.5 Fase 6: Validación funcional en entorno virtual (11 abril) + +Se restauró una VM cliente desde backup para simular el entorno real de la oficina DASUTEN: + +- Se desvinculó la PC del dominio anterior y se unió al Workgroup `DASUTEN`. +- Se reconfiguró el archivo de conexión del sistema (`Kermet.ini`) para apuntar al nuevo servidor SQL. +- **Resultado:** El sistema DASUTEN conectó exitosamente, actualizó estructuras y descargó novedades. + +**Conclusión técnica clave:** Se determinó mediante ingeniería inversa que el sistema DASUTEN (desarrollado en Visual FoxPro) **no tiene dependencia real del Active Directory** si se configura explícitamente la autenticación SQL en su archivo de configuración. + +### 4.6 Fase 7: Despliegue en PC física de producción (13 abril — EN CURSO) + +Se desplegó el sistema en la PC física de la oficina DASUTEN (`dasu-pc`): + +- **Directorio del sistema** (`C:\SysDasuten`) transferido desde la VM de pruebas. +- **Configuración de conexión** apuntada al nuevo servidor `dasu-sql4`. +- **Acceso directo** creado en el escritorio de la usuaria (`aalmiron`). +- **Pruebas funcionales:** + - Inicio del sistema: ✅ OK + - Acceso a datos (ventana de bonos): ✅ OK + - **Impresión: ❌ FALLO** — Error al imprimir, posiblemente por incompatibilidad de las plantillas de Office (el sistema usa automatización OLE con Word/Excel). + +### 4.7 Fase 8: Refresco final de base de datos (13 abril) + +Se ejecutó un refresco automatizado de la base de datos para asegurar que el sistema arranca con los datos más actualizados del servidor de origen: + +- Backup generado automáticamente desde el origen (44.8 segundos). +- Transferido de manera segura (SMB + SCP por VPN). +- Restaurado con `RESTORE DATABASE ... WITH REPLACE`. +- Integridad verificada con `DBCC CHECKDB` — sin errores. + +--- + +## 5. Estado Actual + +### 5.1 Funcionalidades operativas + +| Funcionalidad | Estado | +|:---|:---:| +| Acceso al sistema DASUTEN | ✅ Operativo | +| Consulta de datos (bonos, registros) | ✅ Operativo | +| Conexión a base de datos SQL Server | ✅ Operativo | +| Acceso remoto para soporte (Tailscale/SSH) | ✅ Operativo | +| Impresión desde el sistema | ❌ Pendiente | + +### 5.2 Problema pendiente: Impresión + +**Descripción:** Al intentar imprimir desde el sistema DASUTEN en la PC física, se produce un error. El diagnóstico preliminar indica que la causa es una incompatibilidad entre las **plantillas de Office** requeridas por el sistema (diseñadas para Office 2003/2007) y la versión de Office actualmente instalada en la PC. + +**Impacto:** La usuaria no puede generar documentos impresos desde el nuevo sistema. + +**Workaround temporal:** Se habilitó acceso remoto (TeamViewer) desde la PC física hacia la VM de pruebas (`dasu-pcv`), donde la impresión funciona correctamente. La usuaria puede continuar operando mientras se resuelve el problema. + +**Plan de resolución:** Verificar y ajustar la versión/configuración de Office en `dasu-pc` para compatibilizarla con las plantillas del sistema. + +--- + +## 6. Beneficios Obtenidos + +1. **Independencia operativa:** DASUTEN ya no depende de la infraestructura de red ni de los servidores de la Facultad. +2. **Simplificación:** Se pasó de 3 VMs + Domain Controller a solo 1 VM (SQL Server), reduciendo significativamente la complejidad. +3. **Reducción de puntos de falla:** De múltiples (DC, DNS institucional, routing complejo) a uno solo (SQL Server). +4. **Acceso remoto robusto:** Gestión técnica asegurada vía VPN (Tailscale) y SSH, sin necesidad de presencia física. +5. **Autonomía:** La infraestructura puede ser gestionada independientemente, facilitando una eventual transferencia a Rectorado. +6. **Preservación del entorno anterior:** Las VMs del enfoque con DC fueron apagadas y preservadas como respaldo, permitiendo un rollback si fuera necesario. + +--- + +## 7. Cronograma Resumen + +| Fecha | Hito | +|:---|:---| +| 27/03/2026 | Inicio — Preparación del entorno e inicio de pruebas de concepto | +| 28/03/2026 | VM SQL Server de prueba operativa | +| 09-10/04/2026 | Servidor SQL definitivo (dasu-sql4) desplegado y operativo | +| 11/04/2026 | Base de datos migrada, verificada y hardening completado | +| 11/04/2026 | Validación funcional exitosa en entorno virtual | +| 13/04/2026 | Despliegue en PC física de producción — sistema operativo con observación de impresión | + +--- + +## 8. Próximos Pasos + +| Prioridad | Acción | Plazo estimado | +|:---:|:---|:---| +| 🔴 Alta | Resolver problema de impresión (compatibilidad Office/plantillas) | 1-3 días hábiles | +| 🟡 Media | Reservar IPs fijas en router ISP (prevenir cambios por DHCP) | 1 semana | +| 🟢 Baja | Evaluar apagado definitivo de VMs legacy (DC, SQL antiguo) | Tras validación completa | +| 🟢 Baja | Documentar procedimiento de respaldo automatizado de la nueva BD | 2 semanas | + +--- + +## 9. Conclusión + +La migración del sistema DASUTEN a la nueva infraestructura se encuentra **prácticamente completada**, con el sistema operativo y los datos verificados. El enfoque sin Domain Controller demostró ser completamente viable, logrando una **reducción significativa de la complejidad** y de los puntos de falla. + +El único aspecto pendiente es la resolución del problema de impresión, para el cual ya se dispone de un workaround funcional que permite a la usuaria continuar operando sin interrupción. + +Se estima que el proyecto quedará **100% finalizado** dentro de los próximos días hábiles, una vez resuelta la compatibilidad de plantillas de Office. + +--- + +# ANEXO TÉCNICO + +## A. Inventario de Nodos + +### A.1 Servidor Hipervisor: srv-dasu + +| Campo | Valor | +|:---|:---| +| **Rol** | Hipervisor Proxmox VE 9.1 | +| **IP LAN** | 192.168.1.13 (DHCP ISP) | +| **IP VPN** | 100.112.46.104 (Tailscale) | +| **Bridge** | vmbr0 sobre enp33s0 | +| **RAM** | 15 GB total / ~4 GB libre post-VMs | +| **Disco** | 94 GB (68% uso, thin provisioned) | +| **Acceso remoto** | Tailscale + SSH | + +### A.2 Servidor SQL: dasu-sql4 (VM 106) + +| Campo | Valor | +|:---|:---| +| **Rol** | SQL Server 2019 Enterprise | +| **SO** | Windows Server 2022 (Español) | +| **IP LAN** | 192.168.1.11 (DHCP ISP) | +| **IP VPN** | 100.107.15.82 (Tailscale — inestable) | +| **Workgroup** | DASUTEN | +| **RAM** | 4 GB | +| **vCPU** | 2 | +| **Disco 1 (sata0)** | 60 GB — Sistema Operativo | +| **Disco 2 (sata1)** | 120 GB — Datos SQL (GPT/NTFS "SQLData") | +| **Estructura SQL** | F:\DATA, F:\LOG, F:\BACKUP, F:\TEMPDB | +| **Autenticación** | Mixta (SQL Auth + Windows) | +| **Puerto SQL** | TCP 1433 | +| **SSH** | Puerto 7022 (OpenSSH Server, arranque automático) | +| **Servicios auto-start** | MSSQLSERVER, sshd | + +### A.3 PC Física Cliente: dasu-pc + +| Campo | Valor | +|:---|:---| +| **Rol** | Estación de trabajo DASUTEN | +| **Patrimonio** | 32120 | +| **Ubicación** | Oficina DASUTEN (externa a Facultad) | +| **SO** | Windows 10 Pro | +| **Workgroup** | DASUTEN | +| **IP VPN** | 100.119.233.11 (Tailscale) | +| **SSH** | UTNLR@100.119.233.11:7022 | +| **CPU** | AMD Ryzen 5 4600G @ 4.30GHz (6 núcleos) | +| **RAM** | 8 GB DDR4-3200 | +| **Placa Base** | Asus Prime A320M-K | +| **Usuaria principal** | Andrea Almirón (`aalmiron`) | +| **Directorio DASUTEN** | C:\SysDasuten | +| **Config conexión** | C:\SysDasuten\Sistema\Kermet.ini | + +### A.4 VM Cliente de Pruebas: dasu-pcv (VM 107) — Test-Bed + +| Campo | Valor | +|:---|:---| +| **Rol** | Entorno de pruebas / fallback temporal | +| **SO** | Windows 10 | +| **Workgroup** | DASUTEN | +| **SSH** | Puerto 7022 | +| **Estado** | Operativa (usada como fallback vía TeamViewer) | + +--- + +## B. Configuración del Sistema DASUTEN + +### B.1 Archivo de conexión: Kermet.ini + +Parámetros clave configurados para la operación sin Domain Controller: + +```ini +SERVER=dasu-sql4 +DATABASE=sysdasuten +UID=sa +PWD=[credencial almacenada en bóveda] +``` + +> **Nota técnica:** El campo `UID` debe estar explícitamente configurado con `sa` (u otra cuenta SQL Auth). Si se deja vacío, el sistema DASUTEN (Visual FoxPro) asume autenticación Windows integrada (SSPI/Kerberos), lo cual falla en entorno Workgroup sin Domain Controller. + +### B.2 Directorio del sistema + +``` +C:\SysDasuten\ +├── Sistema\ → Ejecutables VFP + Kermet.ini +├── Plantillas\ → Templates Word/Excel para impresión +└── [otros directorios de la aplicación] +``` + +--- + +## C. Base de Datos: sysdasuten + +| Campo | Valor | +|:---|:---| +| **Nombre** | sysdasuten | +| **Motor** | SQL Server 2019 Enterprise | +| **Tamaño backup comprimido** | ~1.33 GB | +| **Nivel de compatibilidad** | 100 | +| **Recovery model** | FULL | +| **Integridad (DBCC CHECKDB)** | ✅ Sin errores | +| **Tiempo de restauración** | 26 segundos (354 MB/s) | +| **Origen de datos** | srvv-fenix (servidor legacy de Facultad) | +| **Último refresco** | 13/04/2026 | + +### C.1 Ruta de transferencia del backup + +``` +srvv-fenix (Origen) + │ [BACKUP DATABASE ... WITH COMPRESSION] + │ → E:\BK_SQL\sysdasuten_compressed_ADN.bak (~1.33 GB) + ↓ +srv-ns8 (Tránsito) + │ [SMB/smbget vía dominio] + │ → /var/tmp/ + ↓ +srv-dasu (Tránsito) + │ [SCP vía Tailscale] + ↓ +dasu-sql4 (Destino) + │ [RESTORE DATABASE ... WITH REPLACE] + └ → F:\BACKUP\ → F:\DATA\ + F:\LOG\ +``` + +--- + +## D. VMs Legacy Preservadas (Apagadas) + +| VM ID | Nombre | Rol anterior | Estado | +|:---:|:---|:---|:---:| +| 100 | dasu-srvv-dc | Domain Controller AD DS | 🛑 Apagada | +| 101 | dasu-srvv-sql | SQL Server (dominio) | 🛑 Apagada | +| 102 | dasu-pcv | PC cliente (dominio) | 🛑 Apagada | +| 103 | dasu-sql2 | SQL Server prueba v1 | 🛑 Descartada | +| 104 | dasu-pcv2 | PC prueba v1 | 🛑 Descartada | + +> Las VMs legacy (100-102) se mantienen apagadas como respaldo. Pueden reactivarse en caso de necesitar un rollback al enfoque con Domain Controller. + +--- + +## E. Accesos Remotos Configurados + +| Nodo | Método | Detalle | +|:---|:---|:---| +| srv-dasu | Tailscale SSH | 100.112.46.104 | +| dasu-sql4 | SSH (LAN) | 192.168.1.11:7022 | +| dasu-sql4 | Tailscale | 100.107.15.82 (inestable) | +| dasu-pc | Tailscale SSH | 100.119.233.11:7022 | +| dasu-pc | AnyDesk | Instalado (GUI) | +| dasu-pcv | TeamViewer | Activo (workaround temporal) | + +--- + +## F. Cuenta de Gestión VPN + +| Campo | Valor | +|:---|:---| +| **Proveedor** | Tailscale | +| **Cuenta** | pcdasu0@frlr.utn.edu.ar | +| **Nodos vinculados** | srv-dasu, dasu-sql4, dasu-pc, dasu-pcv | + +--- + +*Fin del informe técnico.* diff --git a/docs/informes/2026-04_DASUTEN-migracion/_versiones/02_v0.2.md b/docs/informes/2026-04_DASUTEN-migracion/_versiones/02_v0.2.md new file mode 100644 index 00000000..98eee2ad --- /dev/null +++ b/docs/informes/2026-04_DASUTEN-migracion/_versiones/02_v0.2.md @@ -0,0 +1,446 @@ +# INFORME TÉCNICO — Migración del Sistema DASUTEN a Nuevo Servidor + +> **Área:** Departamento de Tecnología de la Información y Comunicaciones (DTIC) +> **Proyecto:** Migración de infraestructura DASUTEN — Modo Workgroup sin Domain Controller +> **Código interno:** A04.P005 +> **Fecha del informe:** 13 de abril de 2026 +> **Elaborado por:** Ricardo Monla — Área DTIC, UTN-FRLR +> **Versión:** 0.2 +> +> *Este documento contiene el detalle técnico completo de la migración. Para la síntesis ejecutiva, ver [01_informe_ejecutivo_DASUTEN.md](01_informe_ejecutivo_DASUTEN.md).* + +--- + +## 1. Resumen Ejecutivo + +Se informa el avance de la migración del sistema de gestión administrativa **DASUTEN** (Departamento de Acción Social Universitaria Tecnológica Nacional) desde la infraestructura compartida de la Facultad hacia un entorno independiente, autónomo y simplificado. + +**Estado general del proyecto: 95% completado.** + +El sistema DASUTEN se encuentra **operativo** en la nueva infraestructura desde el día 13 de abril de 2026, habiendo superado exitosamente las pruebas funcionales de acceso a datos. Resta únicamente resolver un problema de compatibilidad de impresión vinculado a las plantillas de Office utilizadas por el sistema. + +### Logros principales + +- ✅ Servidor de base de datos **completamente migrado** a infraestructura nueva. +- ✅ Base de datos de producción **restaurada y verificada** sin errores de integridad. +- ✅ Sistema DASUTEN **desplegado y operativo** en la PC física de la usuaria. +- ✅ Eliminación exitosa de la dependencia del **Active Directory (Domain Controller)**. +- ✅ Simplificación de la arquitectura de red — de 3 servidores virtuales a 1. +- ⚠️ Pendiente: resolución de problema de impresión por compatibilidad de plantillas Office. + +--- + +## 2. Antecedentes y Motivación + +### 2.1 Infraestructura original (en red de Facultad) + +El sistema DASUTEN operaba sobre infraestructura compartida con la Facultad Regional La Rioja, dependiendo de: + +- Un servidor SQL Server alojado en la red interna de la Facultad (`srvv-fenix`). +- Un Domain Controller Active Directory para la autenticación de usuarios. +- Conectividad de red interna de la Facultad con routing complejo. + +Esta configuración generaba **múltiples puntos de falla**: +- Dependencia del dominio institucional para la autenticación. +- Complejidad de red con subnetting privado, NAT y gateway interno. +- Cualquier cambio en la infraestructura de la Facultad impactaba directamente en DASUTEN. + +### 2.2 Esquema de trabajo provisorio (AnyDesk + PC Virtual) + +Al reubicarse la oficina DASUTEN en un espacio propio alejado de los servidores, se agravaron las fallas de conectividad: la señal de red recorría múltiples puntos intermedios dentro del edificio, y la caída de cualquiera de ellos dejaba a la oficina sin sistema. + +Para dar continuidad al servicio, se gestionó una **línea de internet propia** para la oficina y se implementó el siguiente esquema de trabajo: + +``` +PC Física (dasu-pc) Servidor srv-dasu (Proxmox VE) + Usuarias: Almirón / Molina ├── VM 100: dasu-srvv-dc (Domain Controller AD DS) + Acceso: AnyDesk ──────────────────► ├── VM 101: dasu-srvv-sql (SQL Server + BD sysdasuten) + (escritorio remoto) └── VM 102: dasu-pcv (PC Virtual ← trabajo aquí) +``` + +**Componentes requeridos:** 4 (servidor dominio + servidor BD + PC virtual + PC física con AnyDesk). + +**Flujo de trabajo de las usuarias:** PC física → AnyDesk (escritorio remoto) → PC virtual → sistema DASUTEN. + +Este esquema permitió: +- Dar continuidad al servicio independientemente de la red interna de la Facultad. +- Brindar asistencia técnica 24/7 por parte de DTIC vía acceso remoto. + +Pero implicaba: +- Experiencia de trabajo **indirecta** para las usuarias (doble salto). +- Cuatro componentes simultáneos que debían estar operativos. +- Múltiples puntos de falla que dificultaban el soporte. + +### 2.3 Objetivo del proyecto + +**Migrar el sistema DASUTEN a una infraestructura independiente y simplificada**, eliminando la dependencia del Domain Controller (Active Directory), el esquema de escritorio remoto, y utilizando un esquema de red **Workgroup** directo, con el fin de: + +1. Reducir la complejidad operativa (de 4 componentes a 2). +2. Permitir trabajo directo (sin AnyDesk intermedio). +3. Minimizar los puntos de falla. +4. Garantizar la autonomía operativa de DASUTEN respecto de la infraestructura de la Facultad. +5. Facilitar la eventual gestión desde Rectorado (Buenos Aires) si fuera necesario. + +--- + +## 3. Infraestructura Implementada + +### 3.1 Arquitectura de red + +Se implementó una topología de **red plana simplificada**, donde todos los equipos obtienen direccionamiento IP directamente del router del ISP, eliminando subnetting privado y routing interno: + +``` +Internet + │ +Router ISP (192.168.1.1 — Gateway) + │ + ├── srv-dasu (Proxmox VE) → 192.168.1.13 + │ └── dasu-sql4 (VM 106) → 192.168.1.11 [SQL Server 2019] + │ + └── dasu-pc (PC Física) → DHCP ISP [Estación de trabajo] +``` + +### 3.2 Componentes del nuevo entorno + +| Componente | Descripción | Estado | +|:---|:---|:---:| +| **srv-dasu** | Servidor Proxmox VE 9.1 (Hipervisor) — CPU Intel, 15 GB RAM, 94 GB disco | ✅ Operativo | +| **dasu-sql4** (VM 106) | Windows Server 2022 — SQL Server 2019 Enterprise — 4 GB RAM, 2 vCPU, discos 60+120 GB | ✅ Operativo | +| **dasu-pc** | PC Física — Windows 10 Pro — AMD Ryzen 5, 8 GB RAM — Oficina DASUTEN | ✅ Operativo | + +### 3.3 Comparativa: Antes vs. Después + +| Aspecto | Enfoque Anterior (con DC + AnyDesk) | Enfoque Actual (Workgroup) | +|:---|:---|:---| +| **Componentes** | 4 (DC + SQL + PC virtual + PC física) | 2 (SQL + PC física) | +| **Forma de trabajo** | Indirecta (AnyDesk → PC virtual) | Directa (sistema en PC) | +| **Red** | Privada 10.0.100.x (gateway interno) | DHCP del ISP (red plana) | +| **Autenticación SQL** | Windows Integrated (Kerberos) | SQL Auth (mixta) | +| **Usuarios** | Active Directory | Usuarios locales Windows | +| **DNS** | AD DNS (10.0.100.10) | DNS del ISP (automático) | +| **Complejidad de red** | Alta (DC + DNS + dominio + routing) | Mínima (red plana ISP) | +| **Puntos de falla** | DC, SQL, red dominio, routing, AnyDesk | Solo SQL | +| **VMs necesarias** | 3 (DC + SQL + PC virtual) | 1 (solo SQL) | + +--- + +## 4. Fases Ejecutadas y Progreso + +### Resumen de progreso por fase + +| Fase | Descripción | Estado | Progreso | +|:---:|:---|:---:|:---:| +| 1 | Preparación del entorno (srv-dasu) | ✅ Completada | 100% | +| 2 | Creación de VM SQL Server de prueba | ✅ Completada | 100% | +| 3 | Creación de VM PC Cliente de prueba | ✅ Completada | 100% | +| 4 | VM definitiva dasu-sql4 | ✅ Completada | 100% | +| 5 | Migración de base de datos | ✅ Completada | 100% | +| 5b | Hardening y persistencia de servicios | ✅ Completada | 100% | +| 6 | Validación con PC cliente virtual | ✅ Completada | 100% | +| 7 | Despliegue en PC física (producción) | 🚧 En curso | 75% | +| 8 | Refresco final de base de datos | ✅ Completada | 100% | + +### 4.1 Fase 1-3: Preparación y pruebas de concepto (27-28 marzo) + +Se preparó el hipervisor Proxmox, se reconfiguró el bridge de red para usar DHCP directo del ISP, y se crearon VMs de prueba para validar la viabilidad del enfoque sin Domain Controller. + +**Hallazgo crítico:** Se detectó y resolvió que el bridge de red estaba configurado con la IP de una red privada anterior, lo cual habría impedido la conectividad de las nuevas VMs. + +### 4.2 Fase 4: Servidor SQL definitivo (9-10 abril) + +Se creó la VM definitiva `dasu-sql4` (VM 106) con una arquitectura optimizada: + +- **Discos separados:** 60 GB para SO + 120 GB exclusivo para datos SQL (buena práctica). +- **SQL Server 2019 Enterprise** instalado con autenticación mixta. +- **Gestión remota** asegurada vía OpenSSH Server (puerto 7022) y Tailscale VPN. + +### 4.3 Fase 5: Migración de Base de Datos (11 abril) + +Se ejecutó la migración completa de la base de datos de producción: + +1. **Exportación:** Backup comprimido (~1.33 GB) generado desde el servidor origen (`srvv-fenix`). +2. **Transferencia:** Archivo movido a través de la VPN institucional (Tailscale) en múltiples tramos seguros. +3. **Restauración:** Base restaurada exitosamente en 26 segundos (354 MB/s). +4. **Verificación:** `DBCC CHECKDB` ejecutado sin errores — integridad de datos confirmada al 100%. + +### 4.4 Fase 5b: Hardening (11 abril) + +Se validó que todos los servicios críticos (SSH, SQL Server) sobreviven reinicios del servidor sin intervención manual: + +- OpenSSH Server: arranque automático ✅ +- SQL Server: arranque automático ✅ +- IP de red: mantenida tras reinicio ✅ + +### 4.5 Fase 6: Validación funcional en entorno virtual (11 abril) + +Se restauró una VM cliente desde backup para simular el entorno real de la oficina DASUTEN: + +- Se desvinculó la PC del dominio anterior y se unió al Workgroup `DASUTEN`. +- Se reconfiguró el archivo de conexión del sistema (`Kermet.ini`) para apuntar al nuevo servidor SQL. +- **Resultado:** El sistema DASUTEN conectó exitosamente, actualizó estructuras y descargó novedades. + +**Conclusión técnica clave:** Se determinó mediante ingeniería inversa que el sistema DASUTEN (desarrollado en Visual FoxPro) **no tiene dependencia real del Active Directory** si se configura explícitamente la autenticación SQL en su archivo de configuración. + +### 4.6 Fase 7: Despliegue en PC física de producción (13 abril — EN CURSO) + +Se desplegó el sistema en la PC física de la oficina DASUTEN (`dasu-pc`): + +- **Directorio del sistema** (`C:\SysDasuten`) transferido desde la VM de pruebas. +- **Configuración de conexión** apuntada al nuevo servidor `dasu-sql4`. +- **Acceso directo** creado en el escritorio de la usuaria (`aalmiron`). +- **Pruebas funcionales:** + - Inicio del sistema: ✅ OK + - Acceso a datos (ventana de bonos): ✅ OK + - **Impresión: ❌ FALLO** — Error al imprimir, posiblemente por incompatibilidad de las plantillas de Office (el sistema usa automatización OLE con Word/Excel). + +### 4.7 Fase 8: Refresco final de base de datos (13 abril) + +Se ejecutó un refresco automatizado de la base de datos para asegurar que el sistema arranca con los datos más actualizados del servidor de origen: + +- Backup generado automáticamente desde el origen (44.8 segundos). +- Transferido de manera segura (SMB + SCP por VPN). +- Restaurado con `RESTORE DATABASE ... WITH REPLACE`. +- Integridad verificada con `DBCC CHECKDB` — sin errores. + +--- + +## 5. Estado Actual + +### 5.1 Funcionalidades operativas + +| Funcionalidad | Estado | +|:---|:---:| +| Acceso al sistema DASUTEN | ✅ Operativo | +| Consulta de datos (bonos, registros) | ✅ Operativo | +| Conexión a base de datos SQL Server | ✅ Operativo | +| Acceso remoto para soporte (Tailscale/SSH) | ✅ Operativo | +| Impresión desde el sistema | ❌ Pendiente | + +### 5.2 Problema pendiente: Impresión + +**Descripción:** Al intentar imprimir desde el sistema DASUTEN en la PC física, se produce un error. El diagnóstico preliminar indica que la causa es una incompatibilidad entre las **plantillas de Office** requeridas por el sistema (diseñadas para Office 2003/2007) y la versión de Office actualmente instalada en la PC. + +**Impacto:** La usuaria no puede generar documentos impresos desde el nuevo sistema. + +**Workaround temporal:** Se habilitó acceso remoto (TeamViewer) desde la PC física hacia la VM de pruebas (`dasu-pcv`), donde la impresión funciona correctamente. La usuaria puede continuar operando mientras se resuelve el problema. + +**Plan de resolución:** Verificar y ajustar la versión/configuración de Office en `dasu-pc` para compatibilizarla con las plantillas del sistema. + +--- + +## 6. Beneficios Obtenidos + +1. **Independencia operativa:** DASUTEN ya no depende de la infraestructura de red ni de los servidores de la Facultad. +2. **Simplificación:** Se pasó de 3 VMs + Domain Controller a solo 1 VM (SQL Server), reduciendo significativamente la complejidad. +3. **Reducción de puntos de falla:** De múltiples (DC, DNS institucional, routing complejo) a uno solo (SQL Server). +4. **Acceso remoto robusto:** Gestión técnica asegurada vía VPN (Tailscale) y SSH, sin necesidad de presencia física. +5. **Autonomía:** La infraestructura puede ser gestionada independientemente, facilitando una eventual transferencia a Rectorado. +6. **Preservación del entorno anterior:** Las VMs del enfoque con DC fueron apagadas y preservadas como respaldo, permitiendo un rollback si fuera necesario. + +--- + +## 7. Cronograma Resumen + +| Fecha | Hito | +|:---|:---| +| 27/03/2026 | Inicio — Preparación del entorno e inicio de pruebas de concepto | +| 28/03/2026 | VM SQL Server de prueba operativa | +| 09-10/04/2026 | Servidor SQL definitivo (dasu-sql4) desplegado y operativo | +| 11/04/2026 | Base de datos migrada, verificada y hardening completado | +| 11/04/2026 | Validación funcional exitosa en entorno virtual | +| 13/04/2026 | Despliegue en PC física de producción — sistema operativo con observación de impresión | + +--- + +## 8. Próximos Pasos + +| Prioridad | Acción | Plazo estimado | +|:---:|:---|:---| +| 🔴 Alta | Resolver problema de impresión (compatibilidad Office/plantillas) | 1-3 días hábiles | +| 🟡 Media | Reservar IPs fijas en router ISP (prevenir cambios por DHCP) | 1 semana | +| 🟢 Baja | Evaluar apagado definitivo de VMs legacy (DC, SQL antiguo) | Tras validación completa | +| 🟢 Baja | Documentar procedimiento de respaldo automatizado de la nueva BD | 2 semanas | + +--- + +## 9. Conclusión + +La migración del sistema DASUTEN a la nueva infraestructura se encuentra **prácticamente completada**, con el sistema operativo y los datos verificados. El enfoque sin Domain Controller demostró ser completamente viable, logrando una **reducción significativa de la complejidad** y de los puntos de falla. + +El único aspecto pendiente es la resolución del problema de impresión, para el cual ya se dispone de un workaround funcional que permite a la usuaria continuar operando sin interrupción. + +Se estima que el proyecto quedará **100% finalizado** dentro de los próximos días hábiles, una vez resuelta la compatibilidad de plantillas de Office. + +--- + +# ANEXO TÉCNICO + +## A. Inventario de Nodos + +### A.1 Servidor Hipervisor: srv-dasu + +| Campo | Valor | +|:---|:---| +| **Rol** | Hipervisor Proxmox VE 9.1 | +| **IP LAN** | 192.168.1.13 (DHCP ISP) | +| **IP VPN** | 100.112.46.104 (Tailscale) | +| **Bridge** | vmbr0 sobre enp33s0 | +| **RAM** | 15 GB total / ~4 GB libre post-VMs | +| **Disco** | 94 GB (68% uso, thin provisioned) | +| **Acceso remoto** | Tailscale + SSH | + +### A.2 Servidor SQL: dasu-sql4 (VM 106) + +| Campo | Valor | +|:---|:---| +| **Rol** | SQL Server 2019 Enterprise | +| **SO** | Windows Server 2022 (Español) | +| **IP LAN** | 192.168.1.11 (DHCP ISP) | +| **IP VPN** | 100.107.15.82 (Tailscale — inestable) | +| **Workgroup** | DASUTEN | +| **RAM** | 4 GB | +| **vCPU** | 2 | +| **Disco 1 (sata0)** | 60 GB — Sistema Operativo | +| **Disco 2 (sata1)** | 120 GB — Datos SQL (GPT/NTFS "SQLData") | +| **Estructura SQL** | F:\DATA, F:\LOG, F:\BACKUP, F:\TEMPDB | +| **Autenticación** | Mixta (SQL Auth + Windows) | +| **Puerto SQL** | TCP 1433 | +| **SSH** | Puerto 7022 (OpenSSH Server, arranque automático) | +| **Servicios auto-start** | MSSQLSERVER, sshd | + +### A.3 PC Física Cliente: dasu-pc + +| Campo | Valor | +|:---|:---| +| **Rol** | Estación de trabajo DASUTEN | +| **Patrimonio** | 32120 | +| **Ubicación** | Oficina DASUTEN (externa a Facultad) | +| **SO** | Windows 10 Pro | +| **Workgroup** | DASUTEN | +| **IP VPN** | 100.119.233.11 (Tailscale) | +| **SSH** | UTNLR@100.119.233.11:7022 | +| **CPU** | AMD Ryzen 5 4600G @ 4.30GHz (6 núcleos) | +| **RAM** | 8 GB DDR4-3200 | +| **Placa Base** | Asus Prime A320M-K | +| **Usuaria principal** | Andrea Almirón (`aalmiron`) | +| **Directorio DASUTEN** | C:\SysDasuten | +| **Config conexión** | C:\SysDasuten\Sistema\Kermet.ini | + +### A.4 VM Cliente de Pruebas: dasu-pcv (VM 107) — Test-Bed + +| Campo | Valor | +|:---|:---| +| **Rol** | Entorno de pruebas / fallback temporal | +| **SO** | Windows 10 | +| **Workgroup** | DASUTEN | +| **SSH** | Puerto 7022 | +| **Estado** | Operativa (usada como fallback vía TeamViewer) | + +--- + +## B. Configuración del Sistema DASUTEN + +### B.1 Archivo de conexión: Kermet.ini + +Parámetros clave configurados para la operación sin Domain Controller: + +```ini +SERVER=dasu-sql4 +DATABASE=sysdasuten +UID=sa +PWD=[credencial almacenada en bóveda] +``` + +> **Nota técnica:** El campo `UID` debe estar explícitamente configurado con `sa` (u otra cuenta SQL Auth). Si se deja vacío, el sistema DASUTEN (Visual FoxPro) asume autenticación Windows integrada (SSPI/Kerberos), lo cual falla en entorno Workgroup sin Domain Controller. + +### B.2 Directorio del sistema + +``` +C:\SysDasuten\ +├── Sistema\ → Ejecutables VFP + Kermet.ini +├── Plantillas\ → Templates Word/Excel para impresión +└── [otros directorios de la aplicación] +``` + +--- + +## C. Base de Datos: sysdasuten + +| Campo | Valor | +|:---|:---| +| **Nombre** | sysdasuten | +| **Motor** | SQL Server 2019 Enterprise | +| **Tamaño backup comprimido** | ~1.33 GB | +| **Nivel de compatibilidad** | 100 | +| **Recovery model** | FULL | +| **Integridad (DBCC CHECKDB)** | ✅ Sin errores | +| **Tiempo de restauración** | 26 segundos (354 MB/s) | +| **Origen de datos** | srvv-fenix (servidor legacy de Facultad) | +| **Último refresco** | 13/04/2026 | + +### C.1 Ruta de transferencia del backup + +``` +srvv-fenix (Origen) + │ [BACKUP DATABASE ... WITH COMPRESSION] + │ → E:\BK_SQL\sysdasuten_compressed_ADN.bak (~1.33 GB) + ↓ +srv-ns8 (Tránsito) + │ [SMB/smbget vía dominio] + │ → /var/tmp/ + ↓ +srv-dasu (Tránsito) + │ [SCP vía Tailscale] + ↓ +dasu-sql4 (Destino) + │ [RESTORE DATABASE ... WITH REPLACE] + └ → F:\BACKUP\ → F:\DATA\ + F:\LOG\ +``` + +--- + +## D. VMs Legacy Preservadas (Apagadas) + +| VM ID | Nombre | Rol anterior | Estado | +|:---:|:---|:---|:---:| +| 100 | dasu-srvv-dc | Domain Controller AD DS | 🛑 Apagada | +| 101 | dasu-srvv-sql | SQL Server (dominio) | 🛑 Apagada | +| 102 | dasu-pcv | PC cliente (dominio) | 🛑 Apagada | +| 103 | dasu-sql2 | SQL Server prueba v1 | 🛑 Descartada | +| 104 | dasu-pcv2 | PC prueba v1 | 🛑 Descartada | + +> Las VMs legacy (100-102) se mantienen apagadas como respaldo. Pueden reactivarse en caso de necesitar un rollback al enfoque con Domain Controller. + +--- + +## E. Accesos Remotos Configurados + +| Nodo | Método | Detalle | +|:---|:---|:---| +| srv-dasu | Tailscale SSH | 100.112.46.104 | +| dasu-sql4 | SSH (LAN) | 192.168.1.11:7022 | +| dasu-sql4 | Tailscale | 100.107.15.82 (inestable) | +| dasu-pc | Tailscale SSH | 100.119.233.11:7022 | +| dasu-pc | AnyDesk | Instalado (GUI) | +| dasu-pcv | TeamViewer | Activo (workaround temporal) | + +--- + +## F. Cuenta de Gestión VPN + +| Campo | Valor | +|:---|:---| +| **Proveedor** | Tailscale | +| **Cuenta** | pcdasu0@frlr.utn.edu.ar | +| **Nodos vinculados** | srv-dasu, dasu-sql4, dasu-pc, dasu-pcv | + +--- + +### Historial de versiones + +| Versión | Fecha | Cambios | +|:---:|:---:|:---| +| 0.1 | 13/04/2026 | Versión inicial (fusión de informe de avance + anexo técnico) | +| 0.2 | 13/04/2026 | Se agrega contexto de infraestructura anterior (esquema AnyDesk), versionado, referencia a doc ejecutivo | + +*Fin del informe técnico.* diff --git a/nodos/cam-hikvision-24.md b/nodos/cam-hikvision-24.md index fd4813e1..acfe6ee9 100644 --- a/nodos/cam-hikvision-24.md +++ b/nodos/cam-hikvision-24.md @@ -1,5 +1,17 @@ # Nodo: cam-hikvision-24 (Detectado) + +| Campo | Valor | +|:------|:------| +| **Hostname** | `cam-hikvision-24` | +| **IP** | `10.0.10.24` | +| **OS** | Firmware Hikvision | +| **Estado** | 🟢 Online | +| **Rol** | Cámara IP / DVR | +| **Ring** | — | + + + ## Información General - **Hostname**: `cam-hikvision-24` (Asignado provisionalmente) - **IP**: `10.0.10.24` diff --git a/nodos/dasu-pc.md b/nodos/dasu-pc.md index f8a57fc3..5617ae6a 100644 --- a/nodos/dasu-pc.md +++ b/nodos/dasu-pc.md @@ -1,5 +1,20 @@ # Nodo: dasu-pc + +| Campo | Valor | +|:------|:------| +| **Hostname** | `dasu-pc` | +| **IP** | `100.119.233.11` | +| **OS** | Windows 10 | +| **Estado** | 🟢 Online | +| **Rol** | Estación de Trabajo DASUTEN | +| **SSH** | `UTNLR@100.119.233.11:7022` | +| **Auth** | `rsa_legacy` | +| **Ring** | `—` | + +> Acceso vía Tailscale (Passphrase RSA) + + ## Información General - **Hostname**: `dasu-pc` (Prev: `dasu-pc-0`, `pc-dasu0`) - **Patrimonio**: `32120` @@ -8,8 +23,8 @@ - **Rol**: Estación de Trabajo Remota (Usuarios: Andrea/Romina) - **Sistema Operativo**: Windows 10 - **Dominio**: `dasuten.utnlr` (Unido 18/03/2026 - P2601.07.01) -- **Conectividad**: Tailscale (`100.100.145.51`) - ✅ ONLINE (Unattended Mode) -- **SSH**: `UTNLR@100.100.145.51:7022` (Plan A, Passphrase RSA, Bóveda: `rsa`) +- **Conectividad**: Tailscale (`100.119.233.11`) - ✅ ONLINE (Unattended Mode) *(Actualizado 2026-04-13)* +- **SSH**: `UTNLR@100.119.233.11:7022` (Plan A, Passphrase RSA, Bóveda: `rsa`) - **Acceso Respaldo (Plan B)**: W-ZOMBI v2.0 C2 (Vía Powershell: `iwr 100.111.195.4:8000/zombi.ps1 -useb | iex`) ## Credenciales de Gestión (Tailscale Admin) diff --git a/nodos/dasu-pcv.md b/nodos/dasu-pcv.md index ed0d97c6..993992a3 100644 --- a/nodos/dasu-pcv.md +++ b/nodos/dasu-pcv.md @@ -1,11 +1,27 @@ # Nodo: dasu-pcv + +| Campo | Valor | +|:------|:------| +| **Hostname** | `dasu-pcv` | +| **IP** | `10.0.100.7` | +| **OS** | Windows 10 LTSC | +| **Estado** | 🟢 Online | +| **Rol** | PC cliente DASUTEN (Test-Bed) | +| **SSH** | `rmonla@10.0.100.7:7022` | +| **Auth** | `password` | +| **Host** | `srv-dasu` | +| **VMID** | `107` | +| **Ring** | `—` | + + + ## Identidad -- **Hostname**: `dasu-pcv` (pendiente renombrar, original: `pcv-dasu0`) -- **Rol**: PC cliente DASUTEN — Modo Workgroup (pendiente desvincular dominio) +- **Hostname**: `dasu-pcv` (Renombrado desde `pcv-dasu0`) ✅ +- **Rol**: PC cliente DASUTEN — Modo Workgroup (Test-Bed validado) - **OS**: Windows 10 LTSC (Español, con GUI) -- **Estado**: 🚧 Restaurando desde backup vzdump -- **Última Actualización**: 2026-04-11 +- **Estado**: ✅ Validado (Fase 6 completada) +- **Última Actualización**: 2026-04-13 - **Padre**: srv-dasu ## Virtualización @@ -21,27 +37,28 @@ - **Origen**: Restaurado desde `images:backup/vzdump-qemu-102-2026_03_16-00_40_03.vma.zst` (13.47 GB, con wrapper zstd `--no-check` por checksum corrupto) ## Red -- **IP LAN**: 192.168.1.20 (DHCP ISP) +- **IP LAN**: 192.168.1.20 (DHCP ISP — puede variar) +- **Tailscale**: `100.103.81.108` ✅ *(Actualizado 2026-04-13)* - **Gateway**: 192.168.1.1 - **DNS**: ISP (automático) -- **Dominio actual**: DASUTEN (Workgroup) +- **Dominio actual**: DASUTEN (Workgroup) ✅ - **Dominio anterior**: UTNLARIOJA (Desvinculado) ## Gestión -- **Admin Local**: `adminpcv` ($lldgUTNlarioja00) -- **Acceso Remoto**: RustDesk ID 296893471 (Password permanente: `$DASU123utn`) +- **Admin Local**: `adminpcv` (Bóveda: `dasu-pcv:adminpcv`) +- **SSH**: `adminpcv@100.103.81.108:7022` ✅ +- **Acceso Remoto**: RustDesk ID 296893471 (Bóveda: `dasu-pcv:rustdesk`) - **Gestor Backup**: Proxmox Console noVNC ## Software -- **Launcher DASUTEN**: Instalado (configuración legacy apuntando al antiguo SQL con dominio) -- **Connection string actual**: Pendiente reconfigurar → `192.168.1.11:1433` con auth SQL (sa) +- **Launcher DASUTEN**: Instalado y validado ✅ +- **Kermet.ini**: Configurado con `SERVER=dasu-sql4`, `UID=sa`, SQL Auth ✅ -## Pendiente -- [ ] Desvincular del dominio → WORKGROUP -- [ ] Renombrar hostname a `dasu-pcv` -- [ ] Reconfigurar connection string DASUTEN → `192.168.1.11:1433` -- [ ] Verificar IP asignada por DHCP -- [ ] Test funcional contra dasu-sql4 +## Tareas completadas +- [x] Desvincular del dominio → WORKGROUP `DASUTEN` ✅ +- [x] Renombrar hostname a `dasu-pcv` ✅ +- [x] Reconfigurar Kermet.ini → `SERVER=dasu-sql4` con SQL Auth ✅ +- [x] Test funcional contra dasu-sql4 ✅ ## Historial - 2026-03-16: Backup vzdump original de VM 102 (pcv-dasu0) diff --git a/nodos/dasu-pcv2.md b/nodos/dasu-pcv2.md index 93a0d511..f92e6aa5 100644 --- a/nodos/dasu-pcv2.md +++ b/nodos/dasu-pcv2.md @@ -1,5 +1,21 @@ # Nodo: dasu-pcv2 + +| Campo | Valor | +|:------|:------| +| **Hostname** | `dasu-pcv2` | +| **IP** | `10.0.100.8` | +| **OS** | Windows 10 LTSC | +| **Estado** | 🚧 En configuración | +| **Rol** | Estación de Trabajo DASUTEN (Fase 3) | +| **SSH** | `rmonla@10.0.100.8:7022` | +| **Auth** | `password` | +| **Host** | `srv-dasu` | +| **VMID** | `104` | +| **Ring** | `—` | + + + ## Identidad - **Hostname**: `dasu-pcv2` - **Rol**: Estación de Trabajo Remota (Fase 3 DASUTEN) diff --git a/nodos/dasu-sql2.md b/nodos/dasu-sql2.md index 7f2cac96..d3712747 100644 --- a/nodos/dasu-sql2.md +++ b/nodos/dasu-sql2.md @@ -1,5 +1,21 @@ # Nodo: dasu-sql2 + +| Campo | Valor | +|:------|:------| +| **Hostname** | `dasu-sql2` | +| **IP** | `10.0.100.3` | +| **OS** | Windows Server 2022 Core | +| **Estado** | 🟢 Online | +| **Rol** | SQL Server 2019 (DASUTEN) | +| **SSH** | `rmonla@10.0.100.3:7022` | +| **Auth** | `password` | +| **Host** | `srv-dasu` | +| **VMID** | `103` | +| **Ring** | `—` | + + + ## Identidad - **Hostname**: `dasu-sql2` - **Rol**: SQL Server 2019 (DASUTEN) — Modo Workgroup diff --git a/nodos/dasu-sql3.md b/nodos/dasu-sql3.md index 3af33e5a..5f419646 100644 --- a/nodos/dasu-sql3.md +++ b/nodos/dasu-sql3.md @@ -1,5 +1,21 @@ # Nodo: dasu-sql3 + +| Campo | Valor | +|:------|:------| +| **Hostname** | `dasu-sql3` | +| **IP** | `10.0.100.5` | +| **OS** | Windows Server 2022 | +| **Estado** | 🚧 Instalando | +| **Rol** | SQL Server 2019 (DASUTEN) | +| **SSH** | `rmonla@10.0.100.5:7022` | +| **Auth** | `password` | +| **Host** | `srv-dasu` | +| **VMID** | `105` | +| **Ring** | `—` | + + + ## Identidad - **Hostname**: `dasu-sql3` - **Rol**: SQL Server 2019 (DASUTEN) — Modo Workgroup diff --git a/nodos/dasu-sql4.md b/nodos/dasu-sql4.md index fa2bfc5d..02b0d163 100644 --- a/nodos/dasu-sql4.md +++ b/nodos/dasu-sql4.md @@ -1,5 +1,22 @@ # Nodo: dasu-sql4 + +| Campo | Valor | +|:------|:------| +| **Hostname** | `dasu-sql4` | +| **IP** | `192.168.1.11` | +| **OS** | Windows Server 2022 Standard | +| **Estado** | 🟢 Online | +| **Rol** | SQL Server 2019 Enterprise (DASUTEN) | +| **SSH** | `Administrador@192.168.1.11:7022` | +| **Auth** | `password` | +| **Host** | `srv-dasu` | +| **VMID** | `106` | +| **Ring** | `—` | +| **Bóveda** | `dasu-sql4:Administrador` | + + + ## Identidad - **Hostname**: `dasu-sql4` - **Rol**: SQL Server 2019 Enterprise (DASUTEN) — Modo Workgroup @@ -25,11 +42,27 @@ - **Autostart**: sí (`onboot: 1`) ## Red -- **IP LAN**: 192.168.1.11 (DHCP ISP — cambió de .26 tras reboot por corte de luz) -- **IP Tailscale**: 100.107.15.82 (⚠️ inestable, usar relay srv-dasu) +- **IP LAN**: 192.168.1.11 (DHCP ISP) +- **IP Tailscale**: ⚠️ No disponible (offline/inestable) - **Gateway**: 192.168.1.1 - **DNS**: ISP (automático) +## ⚠️ Acceso Remoto — Importante +dasu-sql4 entra en **modo suspensión** cuando no se usa, lo que inhabilita el acceso SSH directo y Tailscale. + +**Método recomendado para operaciones:** +```bash +# Desde srv-dasu, acceder vía IP LAN con PowerShell remoto o SSH +ssh srv-dasu "ssh -p 7022 rmonla@192.168.1.11 'powershell -Command \"...\"'" + +# O usar herramientas ADN que ya manejan el relay automáticamente +./adn/tools/run dron lanzar --nota "Operación" --nodo dasu-sql4 -- ruby script.rb +``` + +**Historial de IPs:** +- `10.0.100.6` — ❌ Obsoleta (ya no se usa) +- `192.168.1.11` — ✅ Actual (DHCP ISP) + ## Software Instalado - **VirtIO Drivers**: ✅ (virtio-win-0.1.285) - **Tailscale**: ✅ (cuenta `pcdasu0@frlr.utn.edu.ar`) diff --git a/nodos/dasu-srvv-dc.md b/nodos/dasu-srvv-dc.md index 7b580ad8..59328771 100644 --- a/nodos/dasu-srvv-dc.md +++ b/nodos/dasu-srvv-dc.md @@ -1,5 +1,22 @@ # Nodo: dasu-srvv-dc + +| Campo | Valor | +|:------|:------| +| **Hostname** | `dasu-srvv-dc` | +| **IP** | `10.0.100.1` | +| **OS** | Windows Server Core | +| **Estado** | 🟢 Online | +| **Rol** | Controlador de Dominio AD DS / DNS | +| **SSH** | `admindasu@10.0.100.1:7022` | +| **Auth** | `password` | +| **Bóveda** | `dasu-dc:admindasu` | +| **Host** | `srv-dasu` | +| **VMID** | `100` | +| **Ring** | `—` | + + + ## Identidad - **Hostname**: `dasu-srvv-dc.dasuten.utnlr` - **Nombre anterior**: `dc-dasuten` (renombrado 16/03/2026) diff --git a/nodos/dasu-srvv-sql.md b/nodos/dasu-srvv-sql.md index 240732f0..058e7a0e 100644 --- a/nodos/dasu-srvv-sql.md +++ b/nodos/dasu-srvv-sql.md @@ -1,5 +1,21 @@ # dasu-srvv-sql (SQL Server 2019) + +| Campo | Valor | +|:------|:------| +| **Hostname** | `dasu-srvv-sql` | +| **IP** | `100.107.24.124` | +| **OS** | Windows Server 2022 Core | +| **Estado** | 🟢 Online | +| **Rol** | Servidor SQL Server 2019 | +| **SSH** | `root@100.107.24.124:22` | +| **Auth** | `password` | +| **Host** | `srv-dasu` | +| **VMID** | `102` | +| **Ring** | — | + + + - **Nombre**: `dasu-srvv-sql` - **Identity**: `Windows 2022 Core` - **Rol**: `Servidor de Base de Datos SQL` diff --git a/nodos/dtic-bitacoras.md b/nodos/dtic-bitacoras.md index 07a688b6..9e290689 100644 --- a/nodos/dtic-bitacoras.md +++ b/nodos/dtic-bitacoras.md @@ -1,5 +1,21 @@ # Ficha de Nodo: dtic-bitacoras + +| Campo | Valor | +|:------|:------| +| **Hostname** | `dtic-bitacoras` | +| **IP** | `10.0.10.4` | +| **OS** | Debian 12 (Bookworm) | +| **Estado** | 🟡 Pendiente | +| **Rol** | Sistema de Bitácoras DTIC | +| **SSH** | `root@10.0.10.4:22` | +| **Auth** | `key` | +| **Host** | `srvv-dtic` | +| **Ring** | `standard` | + +> Servicio Docker en srvv-dtic + + | Atributo | Valor | | :--- | :--- | | **Hostname** | `dtic-bitacoras` | diff --git a/nodos/pcv-dasu1.md b/nodos/pcv-dasu1.md index d1c475f4..f8657806 100644 --- a/nodos/pcv-dasu1.md +++ b/nodos/pcv-dasu1.md @@ -1,5 +1,21 @@ # Nodo: pcv-dasu1 + +| Campo | Valor | +|:------|:------| +| **Hostname** | `pcv-dasu1` | +| **IP** | `100.100.145.51` | +| **OS** | Windows 10 | +| **Estado** | 🟢 Online | +| **Rol** | Estación de Trabajo DASU | +| **SSH** | `rmonla@100.100.145.51:7022` | +| **Auth** | `password` | +| **Host** | `srv-pmox2` | +| **VMID** | `108` | +| **Ring** | `—` | + + + ## Información General - **Hostname**: `pcv-dasu1` (Prev: `pcvDASU2`) - **Ubicación**: Interna (Facultad / srv-pmox2) diff --git a/nodos/pcv-dasu2.md b/nodos/pcv-dasu2.md index e66192f6..c2e59e01 100644 --- a/nodos/pcv-dasu2.md +++ b/nodos/pcv-dasu2.md @@ -1,5 +1,19 @@ # Ficha de Nodo: pcv-dasu2 + +| Campo | Valor | +|:------|:------| +| **Hostname** | `pcv-dasu2` | +| **IP** | `10.0.10.202` | +| **OS** | Windows 10 | +| **Estado** | 🟢 Online | +| **Rol** | Sistema DASU / Atención al Usuario | +| **Host** | `srv-pmox2` | +| **VMID** | `109` | +| **Ring** | `—` | + + + | Atributo | Valor | | :--- | :--- | | **Hostname** | `pcv-dasu2` | diff --git a/nodos/pcv-serviio.md b/nodos/pcv-serviio.md index 5ff4971a..a1b2777a 100644 --- a/nodos/pcv-serviio.md +++ b/nodos/pcv-serviio.md @@ -1,5 +1,19 @@ # Nodo: pcv-serviio + +| Campo | Valor | +|:------|:------| +| **Hostname** | `pcv-serviio` | +| **IP** | `DHCP` | +| **OS** | Windows 10 | +| **Estado** | 🟢 Online | +| **Rol** | Media Server | +| **Host** | `srv-pmox2` | +| **VMID** | `110` | +| **Ring** | `—` | + + + > Ficha de nodo | Referencia: [`adn/01_ontologia.md`](../adn/01_ontologia.md) ## Identificación diff --git a/nodos/srv-dasu.md b/nodos/srv-dasu.md index 20c975df..c4db9878 100644 --- a/nodos/srv-dasu.md +++ b/nodos/srv-dasu.md @@ -1,5 +1,20 @@ # Nodo: srv-dasu + +| Campo | Valor | +|:------|:------| +| **Hostname** | `srv-dasu` | +| **IP** | `100.112.46.104` | +| **OS** | Proxmox VE 8 / Debian 12 | +| **Estado** | 🟢 Online | +| **Rol** | Hypervisor Proxmox VE (Standalone — DASUTEN) | +| **SSH** | `root@100.112.46.104:22` | +| **Auth** | `key` | +| **Ring** | `core` | + +> Acceso vía Tailscale DNS (`ssh srv-dasu`) + + ## Identidad - **Hostname**: `srv-dasu.utnlarioja` - **Rol Inicial**: Hypervisor Proxmox VE (Standalone - DASUTEN) diff --git a/nodos/srv-ns8.md b/nodos/srv-ns8.md index 0f80a9b5..8b02c676 100644 --- a/nodos/srv-ns8.md +++ b/nodos/srv-ns8.md @@ -1,5 +1,19 @@ # Ficha de Nodo: srv-ns8 (Host Principal) + +| Campo | Valor | +|:------|:------| +| **Hostname** | `srv-ns8` | +| **IP** | `10.0.10.8` | +| **OS** | Debian 12 (Bookworm) | +| **Estado** | 🟢 Online | +| **Rol** | Workstation / Docker Host / Hypervisor | +| **SSH** | `rmonla@10.0.10.8:22` | +| **Auth** | `key` | +| **Ring** | `core` | + + + | Atributo | Valor | | :--- | :--- | | **Hostname** | `srv-ns8` | diff --git a/nodos/srv-pmox1.md b/nodos/srv-pmox1.md index 723e1620..aacfb2b0 100644 --- a/nodos/srv-pmox1.md +++ b/nodos/srv-pmox1.md @@ -1,5 +1,19 @@ # Nodo: srv-pmox1 + +| Campo | Valor | +|:------|:------| +| **Hostname** | `srv-pmox1` | +| **IP** | `10.0.10.201` | +| **OS** | Proxmox VE 8.2 | +| **Estado** | 🟢 Online | +| **Rol** | Nodo de Virtualización (Proxmox VE) | +| **SSH** | `root@10.0.10.201:22` | +| **Auth** | `key` | +| **Ring** | `core` | + + + ## Información General - **Hostname**: `srv-pmox1` - **IP**: `10.0.10.201` diff --git a/nodos/srv-pmox2.md b/nodos/srv-pmox2.md index ab2a8f50..19375376 100644 --- a/nodos/srv-pmox2.md +++ b/nodos/srv-pmox2.md @@ -1,5 +1,19 @@ # Nodo: srv-pmox2 + +| Campo | Valor | +|:------|:------| +| **Hostname** | `srv-pmox2` | +| **IP** | `10.0.10.202` | +| **OS** | Proxmox VE 8 | +| **Estado** | 🟢 Online | +| **Rol** | Nodo de Virtualización (Proxmox VE) | +| **SSH** | `root@10.0.10.202:22` | +| **Auth** | `key` | +| **Ring** | `core` | + + + ## Información General - **Hostname**: `srv-pmox2` - **IP**: `10.0.10.202` diff --git a/nodos/srv-pmox3.md b/nodos/srv-pmox3.md index c56a5671..f23832f8 100644 --- a/nodos/srv-pmox3.md +++ b/nodos/srv-pmox3.md @@ -1,5 +1,19 @@ # Nodo: srv-pmox3 + +| Campo | Valor | +|:------|:------| +| **Hostname** | `srv-pmox3` | +| **IP** | `10.0.10.203` | +| **OS** | Proxmox VE 8 | +| **Estado** | 🟢 Online | +| **Rol** | Nodo de Virtualización (Proxmox VE) | +| **SSH** | `root@10.0.10.203:22` | +| **Auth** | `key` | +| **Ring** | `core` | + + + ## Información General - **Hostname**: `srv-pmox3` - **IP**: `10.0.10.203` diff --git a/nodos/srv-xen1.md b/nodos/srv-xen1.md index 12710b14..3e0b773c 100644 --- a/nodos/srv-xen1.md +++ b/nodos/srv-xen1.md @@ -1,5 +1,21 @@ # Nodo: srv-xen1 + +| Campo | Valor | +|:------|:------| +| **Hostname** | `srv-xen1` | +| **IP** | `10.0.10.23` | +| **OS** | XenServer 7.0 (Linux) | +| **Estado** | 🟢 Online | +| **Rol** | Hypervisor XenServer (Legacy) | +| **SSH** | `rmonla@10.0.10.23:22` | +| **Auth** | `rsa_legacy` | +| **Clave SSH** | `~/.ssh/id_rsa_xen` | +| **SSH Opts** | `-o PubkeyAcceptedAlgorithms=+ssh-rsa -o HostkeyAlgorithms=+ssh-rsa` | +| **Ring** | `core` | + + + ## Información General - **Hostname**: `srv-xen1` - **IP**: `10.0.10.23` diff --git a/nodos/srvv-data.md b/nodos/srvv-data.md index b205e56d..c87449fa 100644 --- a/nodos/srvv-data.md +++ b/nodos/srvv-data.md @@ -1,5 +1,21 @@ # Nodo: srvv-data + +| Campo | Valor | +|:------|:------| +| **Hostname** | `srvv-data` | +| **IP** | `10.0.10.13` | +| **OS** | Debian 12 (Bookworm) | +| **Estado** | 🟢 Online | +| **Rol** | Base de Datos / Almacenamiento | +| **SSH** | `root@10.0.10.13:22` | +| **Auth** | `key` | +| **Host** | `srv-pmox3` | +| **VMID** | `107` | +| **Ring** | `standard` | + + + ## Información General - **Hostname**: `srvv-data` - **IP**: `10.0.10.13` diff --git a/nodos/srvv-dns.md b/nodos/srvv-dns.md index 19046e63..c640f149 100644 --- a/nodos/srvv-dns.md +++ b/nodos/srvv-dns.md @@ -1,5 +1,21 @@ # Nodo: srvv-dns + +| Campo | Valor | +|:------|:------| +| **Hostname** | `srvv-dns` | +| **IP** | `10.0.10.2` | +| **OS** | Debian 12 (Bookworm) | +| **Estado** | 🟢 Online | +| **Rol** | Servidor DNS Primario (CoreDNS) | +| **SSH** | `rmonla@10.0.10.2:22` | +| **Auth** | `key` | +| **Host** | `srv-pmox1` | +| **VMID** | `112` | +| **Ring** | `standard` | + + + ## Información General - **Hostname**: `srvv-dns` - **IP**: `10.0.10.2` diff --git a/nodos/srvv-docs.md b/nodos/srvv-docs.md index 3fc91c70..397d0f7f 100644 --- a/nodos/srvv-docs.md +++ b/nodos/srvv-docs.md @@ -1,5 +1,21 @@ # Nodo: srvv-docs + +| Campo | Valor | +|:------|:------| +| **Hostname** | `srvv-docs` | +| **IP** | `10.0.10.14` | +| **OS** | Debian 12 (Bookworm) | +| **Estado** | 🟢 Online | +| **Rol** | Docker Host / Documentación | +| **SSH** | `root@10.0.10.14:22` | +| **Auth** | `key` | +| **Host** | `srv-pmox1` | +| **VMID** | `104` | +| **Ring** | `standard` | + + + ## Información General - **Hostname**: `srvv-docs` - **IP**: `10.0.10.14` diff --git a/nodos/srvv-dtic.md b/nodos/srvv-dtic.md index 321745ac..b3e658f2 100644 --- a/nodos/srvv-dtic.md +++ b/nodos/srvv-dtic.md @@ -1,5 +1,21 @@ # Nodo: srvv-dtic + +| Campo | Valor | +|:------|:------| +| **Hostname** | `srvv-dtic` | +| **IP** | `10.0.10.4` | +| **OS** | Debian 12 (Bookworm) | +| **Estado** | 🟢 Online | +| **Rol** | Docker Host / Servicios Internos | +| **SSH** | `root@10.0.10.4:22` | +| **Auth** | `key` | +| **Host** | `srv-pmox1` | +| **VMID** | `103` | +| **Ring** | `standard` | + + + ## Información General - **Hostname**: `srvv-dtic` - **IP**: `10.0.10.4` diff --git a/nodos/srvv-fenix.md b/nodos/srvv-fenix.md index 23d93997..80e10c57 100644 --- a/nodos/srvv-fenix.md +++ b/nodos/srvv-fenix.md @@ -1,5 +1,21 @@ # Nodo: srvv-fenix + +| Campo | Valor | +|:------|:------| +| **Hostname** | `srvv-fenix` | +| **IP** | `10.0.10.111` | +| **OS** | Windows Server 2019 | +| **Estado** | 🟢 Online | +| **Rol** | Sistema Académico Legacy (DASUTEN) | +| **SSH** | `rmonla@10.0.10.111:7022` | +| **Auth** | `password` | +| **Host** | `srv-pmox3` | +| **VMID** | `111` | +| **Ring** | `—` | + + + ## Identidad - **Hostname**: `srvv-fenix.utnlarioja` - **Rol Inicial**: Sistema Académico Legacy (DASUTEN / Facultad) diff --git a/nodos/srvv-koha.md b/nodos/srvv-koha.md index 32ca1a87..95fe6c17 100644 --- a/nodos/srvv-koha.md +++ b/nodos/srvv-koha.md @@ -1,5 +1,21 @@ # Nodo: srvv-koha + +| Campo | Valor | +|:------|:------| +| **Hostname** | `srvv-koha` | +| **IP** | `10.0.10.130` | +| **OS** | Debian 11 (Bullseye) | +| **Estado** | 🟢 Online | +| **Rol** | Biblioteca Koha | +| **SSH** | `root@10.0.10.130:22` | +| **Auth** | `key` | +| **Host** | `srv-pmox2` | +| **VMID** | `105` | +| **Ring** | `standard` | + + + ## Información General - **Hostname**: `srvv-koha` - **IP**: `10.0.10.130` diff --git a/nodos/srvv-maurik.md b/nodos/srvv-maurik.md index 4d6ca13f..68ecd5c2 100644 --- a/nodos/srvv-maurik.md +++ b/nodos/srvv-maurik.md @@ -1,5 +1,21 @@ # Ficha de Nodo: srvv-maurik + +| Campo | Valor | +|:------|:------| +| **Hostname** | `srvv-maurik` | +| **IP** | `10.0.10.10` | +| **OS** | Windows Server 2019 Standard | +| **Estado** | 🟢 Online | +| **Rol** | Controlador de Dominio (utnlarioja.intranet) | +| **SSH** | `monlaricardo@10.0.10.10:7022` | +| **Auth** | `password` | +| **Bóveda** | `utnlarioja.intranet:monlaricardo` | +| **Host** | `srv-xen1` | +| **Ring** | `—` | + + + | Atributo | Valor | | :--- | :--- | | **Hostname** | `srvv-maurik` | diff --git a/nodos/srvv-nginx-rm.md b/nodos/srvv-nginx-rm.md index b31a073e..25d41781 100644 --- a/nodos/srvv-nginx-rm.md +++ b/nodos/srvv-nginx-rm.md @@ -1,5 +1,22 @@ # Ficha de Nodo: srvv-nginx-rm + +| Campo | Valor | +|:------|:------| +| **Hostname** | `srvv-nginx-rm` | +| **IP** | `10.0.10.117` | +| **OS** | Debian 12 (Bookworm) | +| **Estado** | 🟢 Online | +| **Rol** | Servidor Web NGINX (Público) | +| **SSH** | `root@10.0.10.117:7022` | +| **Auth** | `password` | +| **Bóveda** | `srvv-nginx-rm:root` | +| **Host** | `srv-pmox3` | +| **VMID** | `116` | +| **Ring** | `standard` | + + + | Atributo | Valor | | :--- | :--- | | **Hostname** | `srvv-nginx-rm` | diff --git a/nodos/srvv-sitio.md b/nodos/srvv-sitio.md index a4d434a5..8b505013 100644 --- a/nodos/srvv-sitio.md +++ b/nodos/srvv-sitio.md @@ -1,5 +1,21 @@ # Nodo: srvv-sitio + +| Campo | Valor | +|:------|:------| +| **Hostname** | `srvv-sitio` | +| **IP** | `10.0.10.18` | +| **OS** | Ubuntu Linux | +| **Estado** | 🟢 Online | +| **Rol** | Servidor Web / Docker Host | +| **SSH** | `root@10.0.10.18:22` | +| **Auth** | `key` | +| **Host** | `srv-pmox1` | +| **VMID** | `101` | +| **Ring** | `standard` | + + + ## Información General - **Hostname**: `srvv-sitio` - **IP Privada**: `10.0.10.18` diff --git a/nodos/srvv-sitio0.md b/nodos/srvv-sitio0.md index 4e447537..269afafb 100644 --- a/nodos/srvv-sitio0.md +++ b/nodos/srvv-sitio0.md @@ -1,5 +1,21 @@ # Nodo: srvv-sitio0 + +| Campo | Valor | +|:------|:------| +| **Hostname** | `srvv-sitio0` | +| **IP** | `10.0.10.119` | +| **OS** | Debian 12 (Bookworm) | +| **Estado** | 🟢 Online | +| **Rol** | Servidor Web / Docker Host | +| **SSH** | `root@10.0.10.119:22` | +| **Auth** | `key` | +| **Host** | `srv-pmox1` | +| **VMID** | `102` | +| **Ring** | `test` | + + + ## Información General - **Hostname**: `srvv-SCERO` - **IP**: `10.0.10.119` diff --git a/nodos/srvv-sitio2.md b/nodos/srvv-sitio2.md index c6fd5009..cc4bc3a7 100644 --- a/nodos/srvv-sitio2.md +++ b/nodos/srvv-sitio2.md @@ -1,5 +1,22 @@ # Nodo: srvv-sitio2 + +| Campo | Valor | +|:------|:------| +| **Hostname** | `srvv-sitio2` | +| **IP** | `10.0.10.19` | +| **OS** | Debian 12 (Bookworm) | +| **Estado** | 🟢 Online | +| **Rol** | Servidor Web Secundario (LXC) | +| **SSH** | `rmonla@10.0.10.19:22` | +| **Auth** | `key` | +| **Host** | `srv-pmox3` | +| **VMID** | `113` | +| **Ring** | `test` | + +> Root deshabilitado — usar rmonla con sudo + + ## Información General - **Hostname**: `srvv-sitio2` - **IP**: `10.0.10.19` diff --git a/nodos/srvv-sysacadweb.md b/nodos/srvv-sysacadweb.md index 6aebd57c..ab3aec3c 100644 --- a/nodos/srvv-sysacadweb.md +++ b/nodos/srvv-sysacadweb.md @@ -1,5 +1,20 @@ # Ficha de Nodo: srvv-sysacadweb + +| Campo | Valor | +|:------|:------| +| **Hostname** | `srvv-sysacadweb` | +| **IP** | `10.0.10.12` | +| **OS** | Windows Web Server 2008 R2 | +| **Estado** | 🟢 Online | +| **Rol** | Servidor Web SysACAD | +| **SSH** | `monlaricardo@10.0.10.12:7022` | +| **Auth** | `password` | +| **Host** | `srv-xen1` | +| **Ring** | `—` | + + + | Atributo | Valor | | :--- | :--- | | **Hostname** | `srvv-sysacadweb` | diff --git a/nodos/srvv-uptime.md b/nodos/srvv-uptime.md index 667f42f8..2cb044b6 100644 --- a/nodos/srvv-uptime.md +++ b/nodos/srvv-uptime.md @@ -1,5 +1,21 @@ # Nodo: srvv-uptime + +| Campo | Valor | +|:------|:------| +| **Hostname** | `srvv-uptime` | +| **IP** | `10.0.10.9` | +| **OS** | Debian 12 (Bookworm) | +| **Estado** | 🟢 Online | +| **Rol** | Monitorización (Uptime Kuma) | +| **SSH** | `root@10.0.10.9:22` | +| **Auth** | `key` | +| **Host** | `srv-pmox3` | +| **VMID** | `106` | +| **Ring** | `test` | + + + ## Información General - **Hostname**: `srvv-uptime` - **IP**: `10.0.10.9`