#!/usr/bin/env ruby # frozen_string_literal: true # tools/actualizar_dashboard_p2601.rb — Herramienta para actualizar dashboard P2601 con hitos adicionales # ================================================================================ # Esta herramienta actualiza el dashboard P2601 (dashboard/index.html) agregando # hitos adicionales propuestos para la fase de implementación final del proyecto DASUTEN. # # Características: # • Lee el dashboard HTML actual # • Agrega hitos adicionales basados en análisis del proyecto # • Mantiene la estructura y estilo existentes # • Integra con herramientas ADN para seguimiento # • Crea backup del archivo original # # Uso: # ruby tools/actualizar_dashboard_p2601.rb [OPCIONES] # # Opciones: # --dry-run Mostrar cambios sin aplicar # --backup Crear backup antes de modificar # --hitos N Agregar solo N hitos (por defecto: todos) # --categoria CAT Filtrar por categoría (infraestructura, monitoreo, etc.) # --help Mostrar ayuda require 'nokogiri' require 'fileutils' require 'optparse' require 'date' class ActualizadorDashboardP2601 VERSION = "1.0.0" # Hitos adicionales propuestos para la fase de implementación HITOS_ADICIONALES = [ { id: "BKP02", fecha: "Pendiente", titulo: "Backup Automático de VMs en Proxmox", descripcion: "Configurar backups automáticos VZDump programados para DC y SQL Server. Establecer retención de 7 días, almacenamiento en NAS/SMB compartido.", tags: [ 'Remoto: ~2h', 'Requiere acceso físico' ], estado: "pending", # pending, active, done categoria: "infraestructura", prioridad: "alta", prerequisitos: ["FÍSICO"] }, { id: "MON01", fecha: "Pendiente", titulo: "Monitoreo de Recursos del Hipervisor", descripcion: "Implementar sistema de monitoreo básico para CPU, RAM, almacenamiento y red de srv-dasu. Alertas por email/Telegram para recursos críticos.", tags: [ 'Remoto: ~3h', 'Herramientas ADN' ], estado: "pending", categoria: "monitoreo", prioridad: "media", prerequisitos: ["FÍSICO"] }, { id: "DB02", fecha: "Pendiente", titulo: "Backup Automático de Base de Datos sysdasuten", descripcion: "Configurar jobs de SQL Server Agent para backup diario completo y log cada 15 minutos. Verificar restauración periódica en ambiente de pruebas.", tags: [ 'Remoto: ~2h', 'SQL Agent' ], estado: "pending", categoria: "base_datos", prioridad: "alta", prerequisitos: ["ADDOM"] }, { id: "SEC01", fecha: "Pendiente", titulo: "Auditoría de Seguridad del Dominio", descripcion: "Revisar y configurar políticas de auditoría en DC. Logs de acceso, cambios en AD, intentos fallidos. Centralización de logs en syslog server.", tags: [ 'Remoto: ~4h', 'Windows Event Log' ], estado: "pending", categoria: "seguridad", prioridad: "media", prerequisitos: ["GPO"] }, { id: "DOC01", fecha: "Pendiente", titulo: "Documentación Operativa del Sistema", descripcion: "Crear manual de operaciones: procedimientos de backup/restore, acceso remoto, resolución de problemas comunes, contactos de soporte, diagramas de red.", tags: [ 'Remoto: ~6h', 'Herramientas ADN', 'Git' ], estado: "pending", categoria: "documentacion", prioridad: "media", prerequisitos: ["UAT"] }, { id: "RED01", fecha: "Pendiente", titulo: "Optimización de Red y Firewall", descripcion: "Revisar reglas de firewall en todas las VMs. Optimizar rutas Tailscale. Configurar QoS para tráfico crítico. Documentar reglas de firewall.", tags: [ 'Remoto: ~3h', 'Tailscale', 'Windows Firewall' ], estado: "pending", categoria: "red", prioridad: "baja", prerequisitos: ["NET01"] }, { id: "PERF01", fecha: "Pendiente", titulo: "Pruebas de Rendimiento del Sistema", descripcion: "Realizar pruebas de carga simulada en sistema DASUTEN. Medir tiempos de respuesta, consumo de recursos, identificar cuellos de botella. Generar reporte de performance.", tags: [ 'Físico: 2h', 'Remoto: ~2h', 'SQL Profiler' ], estado: "pending", categoria: "performance", prioridad: "media", prerequisitos: ["CLI"] }, { id: "MIG02", fecha: "Pendiente", titulo: "Plan de Migración de Datos Final", descripcion: "Desarrollar script/procedimiento para migración incremental de datos desde sistema antiguo. Validar integridad de datos migrados. Crear rollback plan.", tags: [ 'Remoto: ~8h', 'SSIS', 'PowerShell' ], estado: "pending", categoria: "migracion", prioridad: "alta", prerequisitos: ["P02.APP"] } ].freeze def initialize(opciones = {}) @opciones = opciones @dashboard_path = '/home/rmonla/Documentos/GitHub/dtic-srv-NS8/dashboard/index.html' @backup_path = nil @cambios = [] @errores = [] end def ejecutar mostrar_encabezado unless validar_entorno puts "❌ No se puede continuar debido a errores en el entorno." exit 1 end if @opciones[:dry_run] puts "🔍 MODO SIMULACIÓN (dry-run) - No se aplicarán cambios reales" puts "-" * 50 end contenido_original = leer_dashboard return if contenido_original.nil? if @opciones[:backup] && !@opciones[:dry_run] crear_backup(contenido_original) end hitos_filtrados = filtrar_hitos puts "📋 Hitos a agregar: #{hitos_filtrados.size} de #{HITOS_ADICIONALES.size} disponibles" contenido_actualizado = agregar_hitos_al_dashboard(contenido_original, hitos_filtrados) if contenido_actualizado && !@opciones[:dry_run] guardar_dashboard(contenido_actualizado) elsif @opciones[:dry_run] mostrar_cambios_simulados(contenido_actualizado) end mostrar_resumen rescue => e puts "❌ Error fatal: #{e.message}" puts e.backtrace if @opciones[:debug] exit 1 end private def mostrar_encabezado puts "🔄 ACTUALIZADOR DE DASHBOARD P2601 - v#{VERSION}" puts "=" * 70 puts "Proyecto: DASUTEN (P2601)" puts "Fecha: #{Time.now.strftime('%Y-%m-%d %H:%M:%S')}" puts "Dashboard: #{@dashboard_path}" puts "" end def validar_entorno puts "🔍 Validando entorno..." # Verificar que el dashboard existe unless File.exist?(@dashboard_path) @errores << "Dashboard no encontrado en: #{@dashboard_path}" puts "❌ #{@errores.last}" return false end # Verificar permisos de escritura unless File.writable?(@dashboard_path) @errores << "Sin permisos de escritura en: #{@dashboard_path}" puts "❌ #{@errores.last}" return false end # Verificar que es un archivo HTML válido contenido = File.read(@dashboard_path, 500) unless contenido.include?('') || contenido.include?(' e @errores << "Error leyendo dashboard: #{e.message}" puts "❌ #{@errores.last}" nil end end def crear_backup(contenido) timestamp = Time.now.strftime('%Y%m%d_%H%M%S') @backup_path = "#{@dashboard_path}.backup_#{timestamp}" puts "💾 Creando backup en: #{@backup_path}" begin File.write(@backup_path, contenido) puts "✅ Backup creado exitosamente" rescue => e @errores << "Error creando backup: #{e.message}" puts "⚠️ #{@errores.last}" @backup_path = nil end end def filtrar_hitos hitos = HITOS_ADICIONALES.dup # Filtrar por categoría si se especificó if @opciones[:categoria] categoria = @opciones[:categoria].downcase hitos.select! { |h| h[:categoria] == categoria } puts " • Filtrado por categoría: #{categoria} (#{hitos.size} hitos)" end # Limitar número de hitos si se especificó if @opciones[:hitos] && @opciones[:hitos] > 0 limite = [@opciones[:hitos], hitos.size].min hitos = hitos.first(limite) puts " • Limitado a: #{limite} hitos" end # Ordenar por prioridad (alta -> media -> baja) orden_prioridad = { 'alta' => 1, 'media' => 2, 'baja' => 3 } hitos.sort_by! { |h| orden_prioridad[h[:prioridad]] } hitos end def agregar_hitos_al_dashboard(contenido, hitos) puts "✏️ Agregando hitos al dashboard..." return contenido if hitos.empty? # Buscar el final de la sección de timeline timeline_end_marker = '' unless contenido.include?(timeline_end_marker) timeline_end_marker = '' puts "⚠️ Marcador de timeline no encontrado, usando marcador genérico" end # Generar HTML para los nuevos hitos hitos_html = hitos.map { |hito| generar_html_hito(hito) }.join("\n\n") # Insertar los nuevos hitos antes del marcador de fin nuevo_contenido = contenido.gsub(timeline_end_marker) do |match| "#{hitos_html}\n\n#{match}" end @cambios = hitos.map { |h| h[:id] } puts "✅ #{hitos.size} hitos preparados para agregar: #{@cambios.join(', ')}" nuevo_contenido end def generar_html_hito(hito) clase_dot = case hito[:estado] when 'done' then 'tl-dot done' when 'active' then 'tl-dot active' else 'tl-dot pending' end <<~HTML