#!/usr/bin/env ruby # frozen_string_literal: true # tools/orquestador/config.rb # ============================ # Archivo de configuración centralizado para los módulos optimizados # del orquestador del dashboard P2601 module DashboardConfig # ========================================================================== # CONFIGURACIÓN PRINCIPAL # ========================================================================== # Ruta al dashboard principal DASHBOARD_PATH = File.expand_path('../../../dashboard/index.html', __dir__) # Directorio de backups BACKUPS_DIR = File.expand_path('../../../dashboard/backups', __dir__) # URLs del dashboard URLS = { production: 'https://ns8.frlr.utn.edu.ar/bitacoras/p2601', static: 'https://ns8.frlr.utn.edu.ar/P2601/', staging: 'https://ns8.frlr.utn.edu.ar/P2601-staging/' }.freeze # ========================================================================== # CONFIGURACIÓN DE SINCRONIZACIÓN # ========================================================================== SINCRONIZACION = { local: { dashboard_dir: File.expand_path('../../../dashboard', __dir__), index_file: 'index.html', backups_dir: BACKUPS_DIR }, production: { dashboard_dir: '/var/www/html/P2601', index_file: 'index.html', backups_dir: '/var/www/html/P2601/backups' }, staging: { dashboard_dir: '/var/www/html/P2601-staging', index_file: 'index.html', backups_dir: '/var/www/html/P2601-staging/backups' } }.freeze # ========================================================================== # CONFIGURACIÓN DE ESTADOS # ========================================================================== ESTADOS = { 'pending' => { nombre: 'Pendiente', clase: 'pending', color: '#eab308', descripcion: 'Hito pendiente de iniciar' }, 'in-progress' => { nombre: 'En Progreso', clase: 'in-progress', color: '#3b82f6', descripcion: 'Hito en ejecución activa' }, 'completed' => { nombre: 'Completado', clase: 'completed', color: '#22c55e', descripcion: 'Hito finalizado exitosamente' }, 'blocked' => { nombre: 'Bloqueado', clase: 'blocked', color: '#ef4444', descripcion: 'Hito bloqueado por dependencias u obstáculos' }, 'on-hold' => { nombre: 'En Espera', clase: 'on-hold', color: '#8b5cf6', descripcion: 'Hito en espera por priorización o recursos' } }.freeze # ========================================================================== # CONFIGURACIÓN DE FASES Y HITOS # ========================================================================== # Hitos predefinidos por fase (con nuevo sistema de IDs) HITOS_POR_FASE = { 'fase5' => [ { id: 'f05001', 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: ['tag-remote', 'tag-phys'], esfuerzo: 'Remoto: ~2h', estado: 'pending' }, { id: 'f05002', 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: ['tag-remote', 'SQL Agent'], esfuerzo: 'Remoto: ~2h', estado: 'pending' }, { id: 'f05003', 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: ['tag-remote', 'Herramientas ADN'], esfuerzo: 'Remoto: ~3h', estado: 'pending' }, { id: 'f05004', 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: ['tag-remote', 'Herramientas ADN', 'Git'], esfuerzo: 'Remoto: ~6h', estado: 'pending' }, { id: 'f05005', 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: ['tag-phys', 'tag-remote', 'SQL Profiler'], esfuerzo: 'Físico: 2h, Remoto: ~2h', estado: 'pending' } ] }.freeze # ========================================================================== # CONFIGURACIÓN DE VALIDACIÓN # ========================================================================== # Reglas de validación para IDs de hitos ID_HITO_REGEX = /^f\d{5}$/ # Estados válidos ESTADOS_VALIDOS = ESTADOS.keys.freeze # Fases válidas FASES_VALIDAS = HITOS_POR_FASE.keys.freeze # ========================================================================== # CONFIGURACIÓN DE LOGGING # ========================================================================== LOGGING = { nivel: ENV['DEBUG'] == 'true' ? :debug : :info, directorio: File.expand_path('../../../logs', __dir__), archivo: 'orquestador.log', max_tamano: 10 * 1024 * 1024, # 10 MB max_archivos: 5 }.freeze # ========================================================================== # CONFIGURACIÓN DE BACKUPS # ========================================================================== BACKUP = { retencion_dias: 7, max_backups: 50, comprimir: false, incluir_timestamp: true }.freeze # ========================================================================== # CONFIGURACIÓN DE MÓDULOS # ========================================================================== MODULOS = { hitos: { cache_habilitado: true, cache_ttl: 300, # 5 minutos en segundos validar_ids: true }, estados: { historial_habilitado: true, max_historial: 100 }, verificacion: { niveles: { critico: ['estructura'], alto: ['hitos', 'timeline'], medio: ['estados'], bajo: ['metricas'] } }, vista_previa: { modos: { resumen: { lineas_max: 100 }, hitos: { max_hitos: 50 }, rapido: { compacto: true } } } }.freeze # ========================================================================== # MÉTODOS DE UTILIDAD # ========================================================================== # Obtener la ruta completa del dashboard def self.dashboard_path DASHBOARD_PATH end # Obtener el directorio de backups def self.backups_dir BACKUPS_DIR end # Obtener URL del dashboard en producción def self.production_url URLS[:production] end # Verificar si el modo debug está activado def self.debug? ENV['DEBUG'] == 'true' end # Obtener configuración de sincronización para un ambiente def self.sincronizacion_config(ambiente = :local) SINCRONIZACION[ambiente] || SINCRONIZACION[:local] end # Obtener información de un estado def self.estado_info(estado) ESTADOS[estado] || ESTADOS['pending'] end # Validar un ID de hito def self.id_hito_valido?(id) id.match?(ID_HITO_REGEX) end # Validar un estado def self.estado_valido?(estado) ESTADOS_VALIDOS.include?(estado) end # Validar una fase def self.fase_valida?(fase) FASES_VALIDAS.include?(fase) end # Obtener hitos de una fase def self.hitos_por_fase(fase) HITOS_POR_FASE[fase] || [] end # Obtener todas las fases disponibles def self.fases_disponibles FASES_VALIDAS end # Generar un nuevo ID de hito def self.generar_id_hito(fase_numero, secuencia) "f#{fase_numero.to_s.rjust(2, '0')}#{secuencia.to_s.rjust(3, '0')}" end # Parsear un ID de hito def self.parsear_id_hito(id) match = id.match(/^f(\d{2})(\d{3})$/) return nil unless match { fase: match[1].to_i, secuencia: match[2].to_i, id_completo: id } end # Obtener la ruta del archivo de log def self.log_file File.join(LOGGING[:directorio], LOGGING[:archivo]) end # Crear directorios necesarios def self.crear_directorios dirs = [ BACKUPS_DIR, LOGGING[:directorio], File.dirname(DASHBOARD_PATH) ] dirs.each do |dir| FileUtils.mkdir_p(dir) unless Dir.exist?(dir) end end # Cargar configuración desde variables de entorno def self.cargar_desde_env config = { debug: ENV['DEBUG'] == 'true', dashboard_path: ENV['DASHBOARD_PATH'] || DASHBOARD_PATH, backups_dir: ENV['BACKUPS_DIR'] || BACKUPS_DIR } # Sobrescribir configuración de sincronización si está en ENV if ENV['PRODUCTION_DIR'] SINCRONIZACION[:production][:dashboard_dir] = ENV['PRODUCTION_DIR'] end config end # Mostrar configuración actual def self.mostrar_configuracion puts "⚙️ CONFIGURACIÓN DEL ORQUESTADOR" puts "=" * 60 puts "📁 RUTAS:" puts " • Dashboard: #{DASHBOARD_PATH}" puts " • Backups: #{BACKUPS_DIR}" puts " • Logs: #{log_file}" puts "\n🌐 URLs:" URLS.each do |nombre, url| puts " • #{nombre.capitalize}: #{url}" end puts "\n🎯 HITOS PREDEFINIDOS:" HITOS_POR_FASE.each do |fase, hitos| puts " • #{fase}: #{hitos.size} hitos" end puts "\n📊 ESTADOS DISPONIBLES:" ESTADOS.each do |codigo, info| puts " • #{codigo}: #{info[:nombre]} (#{info[:color]})" end puts "\n🔧 MÓDULOS CONFIGURADOS:" MODULOS.each_key do |modulo| puts " • #{modulo}" end puts "\n🔍 VALIDACIONES:" puts " • Formato ID hito: #{ID_HITO_REGEX}" puts " • Estados válidos: #{ESTADOS_VALIDOS.join(', ')}" puts " • Fases válidas: #{FASES_VALIDAS.join(', ')}" puts "\n💾 BACKUP:" puts " • Retención: #{BACKUP[:retencion_dias]} días" puts " • Máximo backups: #{BACKUP[:max_backups]}" puts " • Comprimir: #{BACKUP[:comprimir] ? 'Sí' : 'No'}" puts "\n📝 LOGGING:" puts " • Nivel: #{LOGGING[:nivel]}" puts " • Tamaño máximo: #{LOGGING[:max_tamano] / (1024 * 1024)} MB" puts " • Archivos máximos: #{LOGGING[:max_archivos]}" puts "\n✅ Configuración cargada correctamente" end end # Inicializar directorios al cargar la configuración DashboardConfig.crear_directorios # Cargar configuración desde variables de entorno DashboardConfig.cargar_desde_env # Mostrar configuración si se ejecuta directamente if __FILE__ == $0 DashboardConfig.mostrar_configuracion end