From af5f193fab6a6d0f453391041576377204c07746 Mon Sep 17 00:00:00 2001 From: Ricardo Monla Date: Mon, 9 Mar 2026 14:28:44 -0300 Subject: [PATCH] =?UTF-8?q?Feat(ADN):=20Implementado=20sistema=20de=20conf?= =?UTF-8?q?iguraci=C3=B3n=20persistente=20y=20subcomando=20'predeterminar'?= =?UTF-8?q?=20para=20backups?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- tools/adn/comando/backup.rb | 53 ++++++-- tools/adn/config/config.yml | 240 ++++++++++----------------------- tools/adn/core/configurador.rb | 50 +++++++ 3 files changed, 169 insertions(+), 174 deletions(-) create mode 100644 tools/adn/core/configurador.rb diff --git a/tools/adn/comando/backup.rb b/tools/adn/comando/backup.rb index f2d6c77a..9ba5d23a 100644 --- a/tools/adn/comando/backup.rb +++ b/tools/adn/comando/backup.rb @@ -3,13 +3,21 @@ require 'optparse' require 'fileutils' require 'date' +require_relative '../core/configurador' module ADN class SubcomandoBackup def initialize(args, logger) @args = args @logger = logger - @opciones = { modo: 'stop', storage: 'local', compress: 'gzip' } + + # Cargar valores predeterminados desde config.yml + defaults = Configurador.obtener('backup.defaults') || {} + @opciones = { + modo: defaults['modo'] || 'stop', + storage: defaults['storage'] || 'local', + compress: defaults['compress'] || 'gzip' + } end def ejecutar @@ -19,9 +27,12 @@ module ADN opts.separator "Ejecuta un backup remoto siguiendo el protocolo ADN" opts.separator "" opts.separator "Opciones:" - opts.on("--mode MODO", "Modo de backup (stop, snapshot, suspend. Default: stop)") do |m| + opts.on("--mode MODO", "Modo de backup (stop, snapshot, suspend. Default: #{@opciones[:modo]})") do |m| @opciones[:modo] = m end + opts.on("--storage STORAGE", "Nombre del storage en Proxmox (Default: #{@opciones[:storage]})") do |s| + @opciones[:storage] = s + end opts.on("-h", "--help", "Mostrar esta ayuda") do puts opts exit @@ -42,6 +53,11 @@ module ADN exit 1 end + if @args[0] == 'predeterminar' + comando_predeterminar(@args[1..-1]) + return + end + nodo = @args[0] ejecutar_backup(nodo) end @@ -100,13 +116,11 @@ module ADN end contenido = File.read(ruta_nodo) - # Buscamos VMID (puede decir "VM ID: 100" o "vmid: 100") - vmid = contenido.match(/(?:VM ID|vmid):\s*(\d+)/i)&.[](1) + # Buscamos VMID (puede decir "VM ID: 100" o "vmid: 100" o "- **VMID**: `100`") + vmid = contenido.match(/(?:VM ID|vmid|VMID)\*\*?:?\s*`?(\d+)`?/i)&.[](1) # Buscamos el host (especificamente el link o nombre entre backticks) - # Formato: - **Padre/Host**: `srv-dasu` - host_name = contenido.match(/Padre\/Host\*\*:?\s*`([^`]+)`/)&.[](1) - host_name ||= contenido.match(/Host\*\*:?\s*`([^`]+)`/)&.[](1) + host_name = contenido.match(/(?:Padre\/Host|Host Anfitrión|Anfitrión|Host)\*\*:?\s*`([^`]+)`/i)&.[](1) unless vmid && host_name @logger.error("Contexto incompleto en #{nombre_nodo}.md: VMID=#{vmid}, Host=#{host_name}") @@ -179,7 +193,7 @@ module ADN contenido = File.read(ruta) # Actualizar la línea de tiempo - linea_nueva = "| 08:31 | #{hora} | #{desc} | [R] #{estado} |" + linea_nueva = "| #{hora} (Fin) | | #{desc} | [R] #{estado} |" # Buscamos la tarea BKP-ADN nuevo_contenido = contenido.gsub(/#### ⏳ - BKP-ADN/, "#### #{estado} - BKP-ADN") @@ -187,5 +201,28 @@ module ADN File.write(ruta, nuevo_contenido) end + + def comando_predeterminar(args) + if args.length < 2 + puts "#{Color::YELLOW}Uso: adn backup predeterminar #{Color::RESET}" + puts "Ej: adn backup predeterminar modo snapshot" + exit 1 + end + + param = args[0].downcase + valor = args[1].downcase + + # Normalizar parámetro (ej: 'modo' -> 'modo', 'storage' -> 'storage') + param = 'modo' if param == 'mode' + + unless ['modo', 'storage', 'compress'].include?(param) + @logger.error("Parámetro no predeterminable: #{param}") + exit 1 + end + + Configurador.establecer("backup.defaults.#{param}", valor) + @logger.exito("Valor predeterminado establecido: backup.#{param} = #{valor}") + puts "#{Color::GREEN}✓ Se ha predeterminado el #{param} a '#{valor}' para futuros backups.#{Color::RESET}" + end end end diff --git a/tools/adn/config/config.yml b/tools/adn/config/config.yml index 90dce9f9..2e0d2855 100644 --- a/tools/adn/config/config.yml +++ b/tools/adn/config/config.yml @@ -1,198 +1,106 @@ -# config.yml — Configuración centralizada para el sistema ADN -# ============================================================= -# Este archivo define la configuración para todas las herramientas -# del sistema ADN. Todas las rutas son relativas al directorio -# raíz del proyecto (dtic-srv-NS8). -# -# 📅 Última actualización: 2026-03-07 (Fase 1: Núcleo Autónomo) -# 📚 Documentación: docs/plan/260307-1400_Plan_Mejoras_ADN.md - -# ─── Rutas del proyecto ───────────────────────────────────── +--- rutas: - # Directorio raíz del proyecto (se calcula automáticamente) proyecto: "../.." - - # Directorios de contenido adn: "../../adn" bitacoras: "../../bitacoras" nodos: "../../nodos" proyectos: "../../proyectos" logs: "../../logs/adn" tmp: "../../tmp" - - # Herramientas existentes ns8_candados: "../ns8-candados/ns8-candados.rb" - -# ─── Configuración del validador ──────────────────────────── validador: - # Modos de operación - watch_mode: false # Monitorear cambios en tiempo real (Fase 1) - strict_mode: true # Rechazar errores graves inmediatamente - - # Validaciones específicas - validar_formato_tiempo: true # Formato HH:MM (sin "hs") - validar_iconografia: true # Iconos de estado correctos - validar_metricas_hibridas: true # Presencia de [Físico/Remoto:] - validar_referencias_rollover: true # Hipervínculos bidireccionales - - # Hooks Git - pre_commit_hook: true # Rechazar commits con errores (Fase 1) - pre_push_hook: false # Validación antes de push (Fase 2) - - # Notificaciones - notificar_desktop: false # Notificaciones desktop (libnotify) - notificar_email: false # Notificaciones email (Fase 3) - -# ─── Sistema de triggers ──────────────────────────────────── + watch_mode: false + strict_mode: true + validar_formato_tiempo: true + validar_iconografia: true + validar_metricas_hibridas: true + validar_referencias_rollover: true + pre_commit_hook: true + pre_push_hook: false + notificar_desktop: false + notificar_email: false triggers: - enabled: false # Habilitado en Fase 2 - config_file: "triggers.yml" # Reglas de triggers (Fase 2) - - # Triggers predefinidos (se implementarán) - detectar_cambio_estado: true # Estado ⏳ → ✅ dispara resumen - detectar_nueva_bitacora: true # Crear bitácora dispara rollover - detectar_modificacion_nodo: true # Cambio en nodo actualiza ontología - - # Ejecución automática - ejecutar_en_cron: false # Tareas periódicas via cron (Fase 2) - intervalo_cron: "*/5 * * * *" # Cada 5 minutos - -# ─── Motor de contexto ────────────────────────────────────── + enabled: false + config_file: triggers.yml + detectar_cambio_estado: true + detectar_nueva_bitacora: true + detectar_modificacion_nodo: true + ejecutar_en_cron: false + intervalo_cron: "*/5 * * * *" contexto: - cache_habilitado: true # Cache de análisis topológico + cache_habilitado: true cache_ruta: "../../tmp/contexto-cache.json" - cache_ttl: 300 # Tiempo de vida en segundos (5 min) - - # Análisis automático - analizar_topologia: true # Analizar ontología y proyectos - sugerir_comandos_ssh: true # Generar comandos con ProxyJump - detectar_requisitos_acceso: true # Identificar saltos de red - -# ─── Dashboard web ────────────────────────────────────────── + cache_ttl: 300 + analizar_topologia: true + sugerir_comandos_ssh: true + detectar_requisitos_acceso: true dashboard: - enabled: false # Habilitado en Fase 3 - port: 4567 # Puerto del servidor Sinatra - host: "localhost" # Host de acceso - auto_open: true # Abrir navegador automáticamente - - # Características - websockets: true # Actualizaciones en tiempo real - metricas_tiempo_real: true # Gráficos de métricas híbridas - alertas_visuales: true # Alertas de inconsistencias - - # Integración - api_json: true # API JSON para integración externa - integracion_dashboard_principal: true # Con dashboard/index.html - -# ─── Sistema de logging ───────────────────────────────────── + enabled: false + port: 4567 + host: localhost + auto_open: true + websockets: true + metricas_tiempo_real: true + alertas_visuales: true + api_json: true + integracion_dashboard_principal: true logging: - nivel: "INFO" # DEBUG, INFO, EXITO, ADVERTENCIA, ERROR + nivel: INFO directorio: "../../logs/adn" - - # Formatos - formato_archivo: "json" # JSON estructurado - formato_terminal: "color" # color, texto, none - - # Rotación - rotacion_diaria: true # Nuevo archivo cada día - retencion_dias: 30 # Conservar logs por 30 días - - # Depuración - debug_detallado: false # Backtraces completos (ADN_DEBUG=1) - -# ─── Sistema de backup y versionado ───────────────────────── + formato_archivo: json + formato_terminal: color + rotacion_diaria: true + retencion_dias: 30 + debug_detallado: false backup: - enabled: false # Habilitado en Fase 3 + enabled: false directorio_destino: "../../dtic-BKPs/adn" - - # Versionado semántico - versionado_semantico: true # adn-1.2.3.tar.gz - formato_version: "major.features.fixes" - - # Frecuencia - automatico: false # Backup automático - frecuencia: "daily" # daily, weekly, monthly - - # Cifrado - cifrar: true # Integrar con ns8-candados - comprimir: true # Comprimir en .tar.gz - -# ─── Proceso de evolución del ADN ─────────────────────────── + versionado_semantico: true + formato_version: major.features.fixes + automatico: false + frecuencia: daily + cifrar: true + comprimir: true + defaults: + modo: stop evolucion: - # Flujo de trabajo formal propuestas_directorio: "../../docs/plan" - periodo_revision_horas: 48 # 48 horas para revisión - - # Control de versiones - tag_commits: true # Tag [ADN-EVOL] en commits - requerir_aprobacion: true # Requerir aprobación explícita - - # Comunicación - notificar_bitacoras: true # Comunicar a bitácoras activas - actualizar_indice: true # Actualizar 00_indice.md automáticamente - -# ─── Seguridad e integración ──────────────────────────────── + periodo_revision_horas: 48 + tag_commits: true + requerir_aprobacion: true + notificar_bitacoras: true + actualizar_indice: true seguridad: - # Integración con ns8-candados - usar_ns8_candados: true # Usar bóveda de secretos - evitar_texto_plano: true # Nunca mostrar secretos - - # Auditoría - auditar_uso_secretos: false # Log de uso de secretos (Fase 3) - log_accesos: true # Registrar accesos a herramientas - - # Permisos - verificar_permisos_archivos: true # Verificar chmod 0600 en configs - -# ─── Configuración de desarrollo ──────────────────────────── + usar_ns8_candados: true + evitar_texto_plano: true + auditar_uso_secretos: false + log_accesos: true + verificar_permisos_archivos: true desarrollo: - # Pruebas - ejecutar_pruebas: false # Ejecutar spec/ al desarrollar - cobertura_minima: 80 # % mínimo de cobertura - - # Debug - modo_verbose: false # Salida detallada - simular_errores: false # Simular errores para testing - - # Métricas - reportar_metricas_desempeno: false # Tiempos de ejecución, etc. - -# ─── Integración con dtic-BITACORAs ────────────────────────── + ejecutar_pruebas: false + cobertura_minima: 80 + modo_verbose: false + simular_errores: false + reportar_metricas_desempeno: false dtic_bitacoras: - # Configuración de API - api_url: "http://localhost:3002" # URL base de la API - api_timeout: 30 # Timeout en segundos - - # Sincronización automática - sincronizacion_automatica: false # Sincronizar .md → DB automáticamente - sincronizar_al_iniciar: true # Sincronizar al iniciar herramientas - - # Endpoints principales + api_url: http://localhost:3002 + api_timeout: 30 + sincronizacion_automatica: false + sincronizar_al_iniciar: true endpoints: salud: "/health" nodos: "/api/nodos" bitacoras: "/api/bitacoras" entradas: "/api/entradas" proyectos: "/api/proyectos" - - # Formato de datos formato_estado_default: "⏳" - formato_modo_default: "P" - - # Cache + formato_modo_default: P cache_habilitado: true - cache_ttl: 300 # 5 minutos - -# ─── Reducción de dependencia de IA ───────────────────────── + cache_ttl: 300 autonomia: - # KPIs objetivo (8 semanas) - kpi_acciones_ia_dia: 2 # Meta: <2 acciones IA/día - kpi_triggers_automaticos: 90 # Meta: 90% triggers automáticos - kpi_scripts_sin_ia: 85 # Meta: 85% scripts sin IA - - # Transición - fase_actual: 1 # 1-4 según plan - modo_transicion: "coexistencia" # coexistencia, transferencia, autonomia - - # Monitoreo - reportar_metricas_autonomia: true # Generar reportes periódicos + kpi_acciones_ia_dia: 2 + kpi_triggers_automaticos: 90 + kpi_scripts_sin_ia: 85 + fase_actual: 1 + modo_transicion: coexistencia + reportar_metricas_autonomia: true diff --git a/tools/adn/core/configurador.rb b/tools/adn/core/configurador.rb new file mode 100644 index 00000000..a34d0c96 --- /dev/null +++ b/tools/adn/core/configurador.rb @@ -0,0 +1,50 @@ +# frozen_string_literal: true + +require 'yaml' +require 'fileutils' + +module ADN + class Configurador + CONFIG_PATH = File.join(__dir__, '..', 'config', 'config.yml') + + def self.leer + return {} unless File.exist?(CONFIG_PATH) + YAML.load_file(CONFIG_PATH) || {} + rescue StandardError => e + warn "Error leyendo configuración: #{e.message}" + {} + end + + def self.guardar(config) + FileUtils.mkdir_p(File.dirname(CONFIG_PATH)) + File.write(CONFIG_PATH, config.to_yaml) + true + rescue StandardError => e + warn "Error guardando configuración: #{e.message}" + false + end + + def self.obtener(ruta_punto, default = nil) + config = leer + partes = ruta_punto.split('.') + valor = config + partes.each do |p| + valor = valor[p] if valor.is_a?(Hash) + return default if valor.nil? + end + valor + end + + def self.establecer(ruta_punto, nuevo_valor) + config = leer + partes = ruta_punto.split('.') + temp = config + partes[0...-1].each do |p| + temp[p] ||= {} + temp = temp[p] + end + temp[partes.last] = nuevo_valor + guardar(config) + end + end +end