feat: Mejorar estructura de monitored_apps.json con metadata completa

- Añadir campos al modelo MonitoredApp:
  * service_name: Nombre del servicio systemd
  * path: WorkingDirectory de la aplicación
  * entry_point: Archivo de entrada (server.js, app.js, etc.)
  * node_bin: Ruta completa al binario de node/python
  * mode: Modo de ejecución (production, development, test)
  * service_file_path: Ruta al archivo .service de systemd
  * registered_at: Timestamp de registro (ISO 8601)

- Actualizar discovery.rs para extraer toda la información:
  * Parsear ExecStart para obtener node_bin y entry_point
  * Extraer NODE_ENV para determinar el modo
  * Guardar ruta completa al archivo .service
  * Usar add_app_full() con información completa

- Integrar ConfigManager en AppManager:
  * Guardar automáticamente en monitored_apps.json al registrar apps
  * Eliminar del JSON al desregistrar apps
  * Extraer metadata desde ServiceConfig (puerto, entry_point, mode, etc.)

- Mantener retrocompatibilidad con JSON antiguo mediante campos deprecated
- Todos los nuevos campos usan #[serde(default)] para evitar errores de deserialización
This commit is contained in:
2026-01-18 03:26:42 -05:00
parent ad9b46bdc5
commit 8822e9e6b5
21 changed files with 3246 additions and 642 deletions

View File

@@ -2,6 +2,7 @@ use super::{Result, OrchestratorError};
use crate::models::{ServiceConfig, ManagedApp, AppStatus};
use crate::systemd::{ServiceGenerator, SystemCtl};
use crate::logger::get_logger;
use crate::config::{get_config_manager, MonitoredApp};
use dashmap::DashMap;
use std::sync::Arc;
@@ -52,6 +53,49 @@ impl AppManager {
// Guardar en memoria
self.apps.insert(config.app_name.clone(), config.clone());
// Guardar en monitored_apps.json con información completa
let config_manager = get_config_manager();
let service_file_path = format!("/etc/systemd/system/{}", config.service_name());
let registered_at = chrono::Local::now().to_rfc3339();
// Extraer el puerto del environment si existe
let port = config.environment.get("PORT")
.and_then(|p| p.parse::<i32>().ok())
.unwrap_or(8080);
// Determinar el entry_point desde script_path
let entry_point = std::path::Path::new(&config.script_path)
.file_name()
.and_then(|f| f.to_str())
.unwrap_or("server.js")
.to_string();
// Determinar node_bin (será resuelto por el ServiceGenerator)
let node_bin = config.custom_executable.clone().unwrap_or_default();
// Determinar mode desde NODE_ENV
let mode = config.environment.get("NODE_ENV")
.cloned()
.unwrap_or_else(|| "production".to_string());
let monitored_app = MonitoredApp {
name: config.app_name.clone(),
service_name: config.service_name(),
path: config.working_directory.clone(),
port,
entry_point,
node_bin,
mode,
service_file_path,
registered_at,
systemd_service: None,
created_at: None,
};
if let Err(e) = config_manager.add_app_full(monitored_app) {
logger.warning("AppManager", "No se pudo guardar en monitored_apps.json", Some(&e));
}
logger.info("AppManager", &format!("Aplicación {} registrada exitosamente", config.app_name));
Ok(())
@@ -84,6 +128,12 @@ impl AppManager {
// Eliminar de memoria
self.apps.remove(app_name);
// Eliminar de monitored_apps.json
let config_manager = get_config_manager();
if let Err(e) = config_manager.remove_app(app_name) {
logger.warning("AppManager", "No se pudo eliminar de monitored_apps.json", Some(&e));
}
logger.info("AppManager", &format!("Aplicación {} desregistrada exitosamente", app_name));
Ok(())