[P2606] WebServer NGINX: plan actualizado, ficha nodo, HTTPS operativo

- P2606: Plan v1.1 EN EJECUCIÓN. Fases 1-3 completadas.
- Ficha nodo srvv-nginx-rm.md. P2606 en adn/07_proyectos.md.
- Incluye cambios acumulados de sesiones anteriores.
This commit is contained in:
Ricardo Monla
2026-03-28 12:18:42 -03:00
parent 97d9b777b4
commit 160da47f96
78 changed files with 6461 additions and 624 deletions
+256
View File
@@ -0,0 +1,256 @@
# frozen_string_literal: true
require 'optparse'
require_relative '../core/colores'
require_relative '../core/help_formatter'
require_relative '../db/core/bitacora_db'
module ADN
class SubcomandoAmbitos
def initialize(args, logger)
@args = args
@logger = logger
end
def ejecutar
if @args.empty? || ['help', '-h', '--help'].include?(@args[0])
mostrar_ayuda
return
end
subcomando = @args[0]
sub_args = @args[1..-1] || []
case subcomando
when 'listar'
comando_listar(sub_args)
when 'crear'
comando_crear(sub_args)
when 'info'
comando_info(sub_args)
when 'nodos'
comando_nodos(sub_args)
else
puts "#{Color::RED}✗ Subcomando desconocido: '#{subcomando}'#{Color::RESET}"
puts "\n"
mostrar_ayuda
exit 1
end
rescue Interrupt
puts "\n#{Color::YELLOW}⚠ Operación interrumpida por el usuario#{Color::RESET}"
exit 130
rescue => e
@logger.error("Error en operación de ámbitos: #{e.message}")
puts "#{Color::RED}✗ Error: #{e.message}#{Color::RESET}"
exit 1
end
private
def comando_listar(args)
opts = { activo: nil }
parser = OptionParser.new do |opt|
opt.on("--activo", "Mostrar solo ámbitos activos") { opts[:activo] = true }
opt.on("--inactivo", "Mostrar solo ámbitos inactivos") { opts[:activo] = false }
opt.on("-h", "--help", "Mostrar ayuda") do
puts HelpFormatter.generar_help(
titulo: "Listar Ámbitos",
descripcion: "Muestra la lista de ámbitos (agrupadores de nodos).",
uso: HelpFormatter.format_usage("adn ambitos listar", "[OPCIONES]"),
opciones: [
{ names: ["activo"], desc: "Mostrar solo ámbitos activos" },
{ names: ["inactivo"], desc: "Mostrar solo ámbitos inactivos" },
{ names: ["h", "help"], desc: "Mostrar esta ayuda" }
],
ejemplos: [{ cmd: "./adn/tools/run ambitos listar", desc: "Listar todos los ámbitos" }]
)
exit 0
end
end
parsear_argumentos!(parser, args)
puts "#{Color::CYAN}📋 Listando ámbitos...#{Color::RESET}\n\n"
BitacorasDB::BitacoraDB.with_connection do |db|
ambitos = db.list_ambitos(activo: opts[:activo])
if ambitos.empty?
puts "#{Color::YELLOW}⚠ No se encontraron ámbitos.#{Color::RESET}"
return
end
puts "#{Color::BOLD}#{"ID".ljust(5)} #{"Nombre".ljust(20)} #{"Nodos".ljust(7)} #{"Activo".ljust(6)} #{"Padre".ljust(20)}#{Color::RESET}"
puts "#{"" * 5} #{"" * 20} #{"" * 7} #{"" * 6} #{"" * 20}"
ambitos.each do |a|
id = a['id'].to_s.ljust(5)
nombre = a['nombre'].to_s.ljust(20)
count = a['count_nodos'].to_s.ljust(7)
activo = (a['activo'] ? '✅' : '❌').ljust(6)
padre = (a['parent_nombre'] || '-').ljust(20)
puts "#{id} #{nombre} #{count} #{activo} #{padre}"
end
puts "\nTotal: #{ambitos.length} ámbitos."
end
end
def comando_crear(args)
opts = { nombre: nil, descripcion: nil, activo: true }
parser = OptionParser.new do |opt|
opt.on("--nombre NOMBRE", "Nombre del ámbito") { |n| opts[:nombre] = n }
opt.on("--descripcion DESC", "Descripción del ámbito") { |d| opts[:descripcion] = d }
opt.on("-h", "--help", "Mostrar ayuda") do
puts HelpFormatter.generar_help(
titulo: "Crear Ámbito",
descripcion: "Genera un nuevo ámbito para agrupar nodos de infraestructura.",
uso: HelpFormatter.format_usage("adn ambitos crear", "--nombre NOMBRE [OPCIONES]"),
opciones: [
{ names: ["nombre NOMBRE"], desc: "Nombre único del ámbito (obligatorio)" },
{ names: ["descripcion DESC"], desc: "Descripción del propósito del ámbito" },
{ names: ["h", "help"], desc: "Mostrar esta ayuda" }
],
ejemplos: [{ cmd: "./adn/tools/run ambitos crear --nombre dtic-Pruebas", desc: "Crear un ámbito de pruebas" }]
)
exit 0
end
end
parsear_argumentos!(parser, args)
unless opts[:nombre]
puts "#{Color::RED}✗ Error: El parámetro --nombre es obligatorio.#{Color::RESET}"
exit 1
end
puts "#{Color::CYAN}📦 Creando ámbito '#{opts[:nombre]}'...#{Color::RESET}"
BitacorasDB::BitacoraDB.with_connection do |db|
begin
ambito = db.create_ambito(nombre: opts[:nombre], descripcion: opts[:descripcion])
puts "#{Color::GREEN}✅ Ámbito creado exitosamente. ID: #{ambito['id']}#{Color::RESET}"
rescue PG::UniqueViolation
puts "#{Color::RED}✗ Error: Ya existe un ámbito con el nombre '#{opts[:nombre]}'.#{Color::RESET}"
exit 1
end
end
end
def comando_info(args)
opts = {}
parser = OptionParser.new do |opt|
opt.on("-h", "--help", "Mostrar ayuda") do
puts HelpFormatter.generar_help(
titulo: "Info de Ámbito",
descripcion: "Muestra información y estadísticas detalladas de un ámbito.",
uso: HelpFormatter.format_usage("adn ambitos info", "<nombre_o_id>"),
opciones: [],
ejemplos: [{ cmd: "./adn/tools/run ambitos info dtic-DASUTEN", desc: "Ver detalles de dtic-DASUTEN" }]
)
exit 0
end
end
parsear_argumentos!(parser, args)
objetivo = args.first
if objetivo.nil? || objetivo.empty?
puts "#{Color::RED}✗ Error: Debes especificar el nombre o ID del ámbito.#{Color::RESET}"
exit 1
end
BitacorasDB::BitacoraDB.with_connection do |db|
ambito = db.get_ambito(objetivo)
if ambito.nil?
puts "#{Color::RED}✗ Error: Ámbito '#{objetivo}' no encontrado.#{Color::RESET}"
exit 1
end
puts "#{Color::CYAN} Info del Ámbito: #{ambito['nombre']}#{Color::RESET}\n\n"
puts " #{Color::BOLD}ID:#{Color::RESET} #{ambito['id']}"
puts " #{Color::BOLD}Nombre:#{Color::RESET} #{ambito['nombre']}"
puts " #{Color::BOLD}Descripción:#{Color::RESET} #{ambito['descripcion'] || '(sin descripción)'}"
puts " #{Color::BOLD}Padre:#{Color::RESET} #{ambito['parent_nombre'] || '(raíz)'}"
puts " #{Color::BOLD}Activo:#{Color::RESET} #{ambito['activo'] ? 'Sí' : 'No'}"
puts " #{Color::BOLD}Nodos:#{Color::RESET} #{ambito['count_nodos']}"
puts ""
end
end
def comando_nodos(args)
opts = {}
parser = OptionParser.new do |opt|
opt.on("-h", "--help", "Mostrar ayuda") do
puts HelpFormatter.generar_help(
titulo: "Nodos de Ámbito",
descripcion: "Lista todos los nodos pertenecientes a un ámbito.",
uso: HelpFormatter.format_usage("adn ambitos nodos", "<nombre_o_id>"),
opciones: [],
ejemplos: [{ cmd: "./adn/tools/run ambitos nodos dtic-DASUTEN", desc: "Ver componentes agrupados bajo dtic-DASUTEN" }]
)
exit 0
end
end
parsear_argumentos!(parser, args)
objetivo = args.first
if objetivo.nil? || objetivo.empty?
puts "#{Color::RED}✗ Error: Debes especificar el nombre o ID del ámbito.#{Color::RESET}"
exit 1
end
BitacorasDB::BitacoraDB.with_connection do |db|
ambito = db.get_ambito(objetivo)
if ambito.nil?
puts "#{Color::RED}✗ Error: Ámbito '#{objetivo}' no encontrado.#{Color::RESET}"
exit 1
end
puts "#{Color::CYAN}🖥️ Nodos del ámbito '#{ambito['nombre']}'...#{Color::RESET}\n\n"
nodos = db.get_nodos_by_ambito(ambito['id'])
if nodos.empty?
puts "#{Color::YELLOW}⚠ Este ámbito no tiene nodos asignados.#{Color::RESET}"
return
end
nodos.each do |n|
tipo = n['tipo'].to_s.ljust(10)
ip = (n['ip'] || '-').ljust(15)
estado = n['activo'] ? "#{Color::GREEN}ON#{Color::RESET}" : "#{Color::RED}OFF#{Color::RESET}"
puts " #{Color::DIM}#{Color::RESET} #{Color::BOLD}#{n['nombre'].to_s.ljust(20)}#{Color::RESET} [#{tipo}] IP: #{ip} (#{estado})"
end
end
end
def mostrar_ayuda
puts HelpFormatter.generar_help(
titulo: "Gestión de Ámbitos (Modelo DB-First)",
descripcion: "Los ámbitos agrupan lógicamente a los nodos correspondientes a áreas organizativas.",
uso: HelpFormatter.format_usage("adn ambitos", "<subcomando> [OPCIONES]"),
opciones: [
{ names: ["h", "help"], desc: "Mostrar esta ayuda" }
],
ejemplos: [
{ cmd: "./adn/tools/run ambitos listar", desc: "Listar ámbitos y cantidad de nodos" },
{ cmd: "./adn/tools/run ambitos info dtic-DIIAA", desc: "Ver detalle del ámbito DIIAA" },
{ cmd: "./adn/tools/run ambitos nodos dtic-DASUTEN", desc: "Listar hipervisores e infraestructura de DASUTEN" }
]
)
end
def parsear_argumentos!(parser, args)
begin
parser.parse!(args)
rescue OptionParser::InvalidOption => e
puts "#{Color::RED}✗ Error: #{e.message}#{Color::RESET}"
puts "\nEjecuta con --help para ver las opciones disponibles."
exit 1
end
end
end
end