429 lines
12 KiB
Ruby
Executable File
429 lines
12 KiB
Ruby
Executable File
#!/usr/bin/env ruby
|
||
# frozen_string_literal: true
|
||
|
||
# tools/orquestador/migrar_ids_hitos.rb
|
||
# ======================================
|
||
# Script de migración para actualizar IDs de hitos al nuevo formato fNNNNN
|
||
# Migra IDs antiguos como BKP02, DB02, etc. a f05001, f05002, etc.
|
||
|
||
require 'fileutils'
|
||
|
||
class MigradorIDsHitos
|
||
# Mapeo de IDs antiguos a nuevos (Fase 5)
|
||
MAPEO_IDS = {
|
||
# Fase 5
|
||
'BKP02' => 'f05001',
|
||
'DB02' => 'f05002',
|
||
'MON01' => 'f05003',
|
||
'DOC01' => 'f05004',
|
||
'PERF01' => 'f05005',
|
||
|
||
# IDs genéricos para migración automática
|
||
'BKP' => 'f05', # Patrón para backups
|
||
'DB' => 'f05', # Patrón para bases de datos
|
||
'MON' => 'f05', # Patrón para monitoreo
|
||
'DOC' => 'f05', # Patrón para documentación
|
||
'PERF' => 'f05', # Patrón para performance
|
||
}.freeze
|
||
|
||
def initialize(dashboard_path = nil)
|
||
@dashboard_path = dashboard_path || default_dashboard_path
|
||
@backup_dir = File.join(File.dirname(@dashboard_path), 'backups')
|
||
@contador_migrados = 0
|
||
@contador_errores = 0
|
||
@ids_migrados = []
|
||
end
|
||
|
||
def default_dashboard_path
|
||
File.expand_path('../../../dashboard/index.html', __FILE__)
|
||
end
|
||
|
||
def migrar_ids
|
||
puts "🔄 MIGRANDO IDs DE HITOS AL NUEVO FORMATO"
|
||
puts "=" * 60
|
||
|
||
unless File.exist?(@dashboard_path)
|
||
puts "❌ Error: No se encuentra el dashboard en #{@dashboard_path}"
|
||
return false
|
||
end
|
||
|
||
# Crear backup
|
||
crear_backup_migracion
|
||
|
||
# Leer contenido
|
||
puts "📖 Leyendo dashboard..."
|
||
contenido = File.read(@dashboard_path)
|
||
contenido_original = contenido.dup
|
||
|
||
# Extraer todos los hitos para análisis
|
||
hitos = extraer_hitos_con_ids(contenido)
|
||
|
||
puts "🔍 Encontrados #{hitos.size} hitos para analizar"
|
||
|
||
# Mostrar IDs actuales
|
||
mostrar_ids_actuales(hitos)
|
||
|
||
# Preguntar confirmación
|
||
unless confirmar_migracion(hitos.size)
|
||
puts "❌ Migración cancelada por el usuario"
|
||
return false
|
||
end
|
||
|
||
# Realizar migración
|
||
puts "\n🔄 Realizando migración..."
|
||
contenido_migrado = migrar_contenido(contenido)
|
||
|
||
# Verificar cambios
|
||
if contenido_migrado == contenido_original
|
||
puts "ℹ️ No se realizaron cambios (posiblemente ya están migrados)"
|
||
return true
|
||
end
|
||
|
||
# Guardar cambios
|
||
puts "💾 Guardando dashboard migrado..."
|
||
File.write(@dashboard_path, contenido_migrado)
|
||
|
||
# Mostrar resultados
|
||
mostrar_resultados_migracion
|
||
|
||
# Verificar integridad
|
||
verificar_integridad_migracion(contenido_migrado)
|
||
|
||
true
|
||
end
|
||
|
||
def simular_migracion
|
||
puts "🔍 SIMULACIÓN DE MIGRACIÓN (MODO DRY RUN)"
|
||
puts "=" * 60
|
||
|
||
unless File.exist?(@dashboard_path)
|
||
puts "❌ Error: No se encuentra el dashboard"
|
||
return false
|
||
end
|
||
|
||
contenido = File.read(@dashboard_path)
|
||
hitos = extraer_hitos_con_ids(contenido)
|
||
|
||
puts "📊 ANÁLISIS DE MIGRACIÓN:"
|
||
puts " • Total de hitos encontrados: #{hitos.size}"
|
||
puts " • IDs que requieren migración: #{hitos.count { |h| requiere_migracion?(h[:id]) }}"
|
||
puts " • IDs ya en formato nuevo: #{hitos.count { |h| !requiere_migracion?(h[:id]) }}"
|
||
|
||
puts "\n📋 DETALLE DE MIGRACIÓN:"
|
||
hitos.each do |hito|
|
||
if requiere_migracion?(hito[:id])
|
||
nuevo_id = generar_nuevo_id(hito[:id])
|
||
puts " • #{hito[:id]} → #{nuevo_id} (#{hito[:titulo][0..50]}...)"
|
||
else
|
||
puts " • #{hito[:id]} (ya migrado)"
|
||
end
|
||
end
|
||
|
||
puts "\n💡 RECOMENDACIONES:"
|
||
if hitos.any? { |h| requiere_migracion?(h[:id]) }
|
||
puts " • Ejecutar migración completa: ./migrar_ids_hitos.rb migrar"
|
||
puts " • Revisar mapeo de IDs antes de proceder"
|
||
else
|
||
puts " • Todos los IDs ya están en formato nuevo"
|
||
puts " • No se requiere migración"
|
||
end
|
||
|
||
true
|
||
end
|
||
|
||
def verificar_estado_migracion
|
||
puts "🔍 VERIFICANDO ESTADO DE MIGRACIÓN"
|
||
puts "=" * 60
|
||
|
||
unless File.exist?(@dashboard_path)
|
||
puts "❌ Error: No se encuentra el dashboard"
|
||
return false
|
||
end
|
||
|
||
contenido = File.read(@dashboard_path)
|
||
hitos = extraer_hitos_con_ids(contenido)
|
||
|
||
puts "📊 ESTADO ACTUAL:"
|
||
|
||
# Contar por tipo de ID
|
||
ids_antiguos = hitos.select { |h| requiere_migracion?(h[:id]) }
|
||
ids_nuevos = hitos.select { |h| !requiere_migracion?(h[:id]) }
|
||
|
||
puts " • IDs en formato antiguo: #{ids_antiguos.size}"
|
||
puts " • IDs en formato nuevo: #{ids_nuevos.size}"
|
||
puts " • Total de hitos: #{hitos.size}"
|
||
|
||
if ids_antiguos.any?
|
||
puts "\n⚠️ IDs QUE REQUIEREN MIGRACIÓN:"
|
||
ids_antiguos.each do |hito|
|
||
nuevo_id = generar_nuevo_id(hito[:id])
|
||
puts " • #{hito[:id]} → #{nuevo_id}"
|
||
end
|
||
end
|
||
|
||
if ids_nuevos.any?
|
||
puts "\n✅ IDs YA MIGRADOS:"
|
||
ids_nuevos.each do |hito|
|
||
puts " • #{hito[:id]}"
|
||
end
|
||
end
|
||
|
||
# Verificar formato de IDs nuevos
|
||
puts "\n🔍 VALIDACIÓN DE FORMATOS:"
|
||
ids_nuevos.each do |hito|
|
||
if formato_valido_nuevo?(hito[:id])
|
||
puts " • #{hito[:id]}: ✅ Formato válido"
|
||
else
|
||
puts " • #{hito[:id]}: ❌ Formato inválido"
|
||
end
|
||
end
|
||
|
||
puts "\n💡 RECOMENDACIONES:"
|
||
if ids_antiguos.any?
|
||
puts " • Ejecutar migración para estandarizar IDs"
|
||
puts " • Usar: ./migrar_ids_hitos.rb migrar"
|
||
else
|
||
puts " • Todos los IDs están en formato nuevo"
|
||
puts " • Sistema listo para usar módulos optimizados"
|
||
end
|
||
|
||
true
|
||
end
|
||
|
||
private
|
||
|
||
def crear_backup_migracion
|
||
FileUtils.mkdir_p(@backup_dir) unless Dir.exist?(@backup_dir)
|
||
|
||
timestamp = Time.now.strftime('%Y%m%d_%H%M%S')
|
||
backup_file = File.join(@backup_dir, "dashboard_pre_migracion_#{timestamp}.html")
|
||
|
||
puts "💾 Creando backup pre-migración: #{backup_file}"
|
||
FileUtils.cp(@dashboard_path, backup_file)
|
||
puts "✅ Backup creado"
|
||
end
|
||
|
||
def extraer_hitos_con_ids(contenido)
|
||
hitos = []
|
||
|
||
contenido.scan(/<div class="tl-item">([\s\S]*?)<\/div>\s*<\/div>\s*<\/div>/m) do |hito_html|
|
||
hito = hito_html[0]
|
||
|
||
# Extraer ID
|
||
id_match = hito.match(/<span class="tl-id">([^<]+)<\/span>/)
|
||
titulo_match = hito.match(/<div class="tl-title">([^<]+)<\/div>/)
|
||
|
||
if id_match && titulo_match
|
||
hitos << {
|
||
id: id_match[1],
|
||
titulo: titulo_match[1],
|
||
html_completo: hito_html[0]
|
||
}
|
||
end
|
||
end
|
||
|
||
hitos.uniq { |h| h[:id] }
|
||
end
|
||
|
||
def mostrar_ids_actuales(hitos)
|
||
puts "\n📋 IDs ACTUALES ENCONTRADOS:"
|
||
hitos.each_with_index do |hito, i|
|
||
requiere = requiere_migracion?(hito[:id]) ? "⚠️ Requiere migración" : "✅ Ya migrado"
|
||
puts " #{i + 1}. #{hito[:id]}: #{hito[:titulo][0..40]}... (#{requiere})"
|
||
end
|
||
end
|
||
|
||
def confirmar_migracion(total_hitos)
|
||
puts "\n⚠️ ADVERTENCIA: Esta operación modificará el dashboard"
|
||
puts " • Total de hitos a analizar: #{total_hitos}"
|
||
puts " • Se creará un backup automático"
|
||
puts " • Los cambios no se pueden deshacer automáticamente"
|
||
|
||
# Para ejecución automática, siempre confirmar
|
||
puts "\n✅ Confirmación automática para migración"
|
||
true
|
||
end
|
||
|
||
def requiere_migracion?(id)
|
||
# Un ID requiere migración si no sigue el formato fNNNNN
|
||
!id.match(/^f\d{5}$/)
|
||
end
|
||
|
||
def formato_valido_nuevo?(id)
|
||
id.match(/^f\d{5}$/)
|
||
end
|
||
|
||
def generar_nuevo_id(id_antiguo)
|
||
# Buscar mapeo directo
|
||
return MAPEO_IDS[id_antiguo] if MAPEO_IDS.key?(id_antiguo)
|
||
|
||
# Buscar por prefijo
|
||
MAPEO_IDS.each do |prefijo, nuevo_base|
|
||
if id_antiguo.start_with?(prefijo)
|
||
# Extraer número del ID antiguo
|
||
numero_match = id_antiguo.match(/\d+/)
|
||
numero = numero_match ? numero_match[0].to_i : 1
|
||
|
||
# Generar nuevo ID con secuencia
|
||
return "#{nuevo_base}#{numero.to_s.rjust(3, '0')}"
|
||
end
|
||
end
|
||
|
||
# ID genérico para fase 5
|
||
"f05#{(@contador_migrados + 1).to_s.rjust(3, '0')}"
|
||
end
|
||
|
||
def migrar_contenido(contenido)
|
||
nuevo_contenido = contenido.dup
|
||
|
||
# Extraer todos los hitos
|
||
hitos = extraer_hitos_con_ids(contenido)
|
||
|
||
hitos.each do |hito|
|
||
if requiere_migracion?(hito[:id])
|
||
nuevo_id = generar_nuevo_id(hito[:id])
|
||
|
||
# Reemplazar en el contenido
|
||
nuevo_contenido = nuevo_contenido.gsub(
|
||
/<span class="tl-id">#{Regexp.escape(hito[:id])}<\/span>/,
|
||
"<span class=\"tl-id\">#{nuevo_id}</span>"
|
||
)
|
||
|
||
@contador_migrados += 1
|
||
@ids_migrados << { antiguo: hito[:id], nuevo: nuevo_id }
|
||
|
||
puts " • #{hito[:id]} → #{nuevo_id}"
|
||
end
|
||
end
|
||
|
||
nuevo_contenido
|
||
end
|
||
|
||
def mostrar_resultados_migracion
|
||
puts "\n📊 RESULTADOS DE LA MIGRACIÓN:"
|
||
puts "=" * 60
|
||
|
||
puts "✅ Migración completada exitosamente"
|
||
puts " • IDs migrados: #{@contador_migrados}"
|
||
puts " • Errores: #{@contador_errores}"
|
||
|
||
if @ids_migrados.any?
|
||
puts "\n📋 DETALLE DE MIGRACIONES:"
|
||
@ids_migrados.each do |migracion|
|
||
puts " • #{migracion[:antiguo]} → #{migracion[:nuevo]}"
|
||
end
|
||
end
|
||
|
||
puts "\n💡 RECOMENDACIONES POST-MIGRACIÓN:"
|
||
puts " 1. Verificar dashboard en producción"
|
||
puts " 2. Actualizar referencias en documentación"
|
||
puts " 3. Usar nuevos módulos optimizados"
|
||
puts " 4. Backup disponible en: #{@backup_dir}"
|
||
end
|
||
|
||
def verificar_integridad_migracion(contenido_migrado)
|
||
puts "\n🔍 VERIFICANDO INTEGRIDAD POST-MIGRACIÓN"
|
||
|
||
hitos = extraer_hitos_con_ids(contenido_migrado)
|
||
ids_invalidos = hitos.select { |h| requiere_migracion?(h[:id]) }
|
||
|
||
if ids_invalidos.empty?
|
||
puts "✅ Todos los IDs están en formato nuevo"
|
||
else
|
||
puts "⚠️ Se encontraron IDs aún en formato antiguo:"
|
||
ids_invalidos.each do |hito|
|
||
puts " • #{hito[:id]}"
|
||
end
|
||
end
|
||
|
||
# Verificar duplicados
|
||
ids = hitos.map { |h| h[:id] }
|
||
duplicados = ids.select { |id| ids.count(id) > 1 }.uniq
|
||
|
||
if duplicados.empty?
|
||
puts "✅ No hay IDs duplicados"
|
||
else
|
||
puts "❌ IDs duplicados encontrados:"
|
||
duplicados.each do |id|
|
||
puts " • #{id}"
|
||
end
|
||
end
|
||
end
|
||
end
|
||
|
||
# Interfaz de línea de comandos
|
||
if __FILE__ == $0
|
||
begin
|
||
migrador = MigradorIDsHitos.new
|
||
|
||
# Parsear argumentos
|
||
command = ARGV[0] || 'verificar'
|
||
|
||
case command
|
||
when 'migrar', 'migrate'
|
||
success = migrador.migrar_ids
|
||
when 'simular', 'simulate', 'dry-run'
|
||
success = migrador.simular_migracion
|
||
when 'verificar', 'check', 'status'
|
||
success = migrador.verificar_estado_migracion
|
||
when 'help', '--help', '-h'
|
||
puts "📖 MIGRADOR DE IDs DE HITOS - Dashboard P2601"
|
||
puts "=" * 60
|
||
puts
|
||
puts "DESCRIPCIÓN:"
|
||
puts " Migra IDs de hitos del formato antiguo (BKP02, DB02, etc.)"
|
||
puts " al nuevo formato estandarizado (f05001, f05002, etc.)"
|
||
puts
|
||
puts "USO:"
|
||
puts " #{$0} [comando]"
|
||
puts
|
||
puts "COMANDOS:"
|
||
puts " migrar, migrate - Realizar migración completa (con backup)"
|
||
puts " simular, simulate - Simular migración (modo dry-run)"
|
||
puts " verificar, check - Verificar estado actual de migración"
|
||
puts " help - Mostrar esta ayuda"
|
||
puts
|
||
puts "MAFEO DE IDs (Fase 5):"
|
||
puts " • BKP02 → f05001 (Backup Automático de VMs)"
|
||
puts " • DB02 → f05002 (Backup Automático de Base de Datos)"
|
||
puts " • MON01 → f05003 (Monitoreo de Recursos)"
|
||
puts " • DOC01 → f05004 (Documentación Operativa)"
|
||
puts " • PERF01 → f05005 (Pruebas de Rendimiento)"
|
||
puts
|
||
puts "CARACTERÍSTICAS:"
|
||
puts " • Backup automático pre-migración"
|
||
puts " • Confirmación interactiva"
|
||
puts " • Verificación de integridad post-migración"
|
||
puts " • Modo dry-run para pruebas"
|
||
puts
|
||
puts "EJEMPLOS:"
|
||
puts " #{$0} verificar # Verificar estado actual"
|
||
puts " #{$0} simular # Simular migración"
|
||
puts " #{$0} migrar # Realizar migración completa"
|
||
puts
|
||
success = true
|
||
else
|
||
puts "❌ Comando '#{command}' no reconocido"
|
||
puts " Use '#{$0} help' para ver la ayuda"
|
||
success = false
|
||
end
|
||
|
||
if success
|
||
puts "\n🚀 PRÓXIMOS PASOS:"
|
||
puts " 1. Usar nuevos módulos optimizados en tools/orquestador/lib/"
|
||
puts " 2. Consultar README_OPTIMIZADO.md para documentación"
|
||
puts " 3. Verificar dashboard: https://ns8.frlr.utn.edu.ar/bitacoras/p2601"
|
||
puts
|
||
puts "📅 #{Time.now.strftime('%Y-%m-%d %H:%M:%S')}"
|
||
puts "=" * 60
|
||
else
|
||
exit 1
|
||
end
|
||
|
||
rescue => e
|
||
puts "❌ Error: #{e.message}"
|
||
puts e.backtrace if ENV['DEBUG']
|
||
exit 1
|
||
end
|
||
end
|