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:
@@ -67,9 +67,12 @@ pub struct DiscoveredService {
|
||||
pub user: Option<String>,
|
||||
pub exec_start: Option<String>,
|
||||
pub port: Option<i32>,
|
||||
pub node_env: String,
|
||||
pub entry_point: Option<String>,
|
||||
pub node_bin: Option<String>,
|
||||
}
|
||||
|
||||
/// Parsea un archivo .service para extraer configuración básica
|
||||
/// Parsea un archivo .service para extraer configuración completa
|
||||
fn parse_service_file(path: &Path, app_name: &str) -> Option<DiscoveredService> {
|
||||
let logger = get_logger();
|
||||
|
||||
@@ -88,6 +91,9 @@ fn parse_service_file(path: &Path, app_name: &str) -> Option<DiscoveredService>
|
||||
user: None,
|
||||
exec_start: None,
|
||||
port: None,
|
||||
node_env: String::from("production"),
|
||||
entry_point: None,
|
||||
node_bin: None,
|
||||
};
|
||||
|
||||
// Parsear líneas del archivo
|
||||
@@ -106,7 +112,24 @@ fn parse_service_file(path: &Path, app_name: &str) -> Option<DiscoveredService>
|
||||
|
||||
// ExecStart
|
||||
if line.starts_with("ExecStart=") {
|
||||
service.exec_start = Some(line.trim_start_matches("ExecStart=").to_string());
|
||||
let exec_start = line.trim_start_matches("ExecStart=").to_string();
|
||||
|
||||
// Extraer node_bin y entry_point del ExecStart
|
||||
// Ejemplo: /home/user/.nvm/versions/node/v24.12.0/bin/node server.js
|
||||
let parts: Vec<&str> = exec_start.split_whitespace().collect();
|
||||
if !parts.is_empty() {
|
||||
service.node_bin = Some(parts[0].to_string());
|
||||
|
||||
// Buscar el archivo .js como entry_point
|
||||
for part in &parts[1..] {
|
||||
if part.ends_with(".js") {
|
||||
service.entry_point = Some(part.to_string());
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
service.exec_start = Some(exec_start);
|
||||
}
|
||||
|
||||
// Environment con PORT
|
||||
@@ -115,12 +138,21 @@ fn parse_service_file(path: &Path, app_name: &str) -> Option<DiscoveredService>
|
||||
service.port = Some(port);
|
||||
}
|
||||
}
|
||||
|
||||
// Environment con NODE_ENV
|
||||
if line.starts_with("Environment=") && line.contains("NODE_ENV") {
|
||||
if let Some(env) = extract_env_value(line, "NODE_ENV") {
|
||||
service.node_env = env;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
logger.info("Discovery", &format!(" App: {}, User: {:?}, WorkDir: {:?}",
|
||||
logger.info("Discovery", &format!(" App: {}, User: {:?}, WorkDir: {:?}, Env: {}, EntryPoint: {:?}",
|
||||
service.app_name,
|
||||
service.user,
|
||||
service.working_directory
|
||||
service.working_directory,
|
||||
service.node_env,
|
||||
service.entry_point
|
||||
));
|
||||
|
||||
Some(service)
|
||||
@@ -143,6 +175,27 @@ fn extract_port_from_env(line: &str) -> Option<i32> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Extrae un valor de variable de entorno de una línea Environment
|
||||
/// Ejemplo: Environment="NODE_ENV=production" -> Some("production")
|
||||
fn extract_env_value(line: &str, var_name: &str) -> Option<String> {
|
||||
let pattern = format!("{}=", var_name);
|
||||
if let Some(start) = line.find(&pattern) {
|
||||
let after_var = &line[start + pattern.len()..];
|
||||
// Extraer hasta espacios, comillas o fin de línea
|
||||
let value: String = after_var.chars()
|
||||
.take_while(|c| !c.is_whitespace() && *c != '"')
|
||||
.collect();
|
||||
|
||||
if !value.is_empty() {
|
||||
Some(value)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// Sincroniza los servicios descubiertos con monitored_apps.json
|
||||
pub fn sync_discovered_services(services: Vec<DiscoveredService>) {
|
||||
let logger = get_logger();
|
||||
@@ -156,7 +209,6 @@ pub fn sync_discovered_services(services: Vec<DiscoveredService>) {
|
||||
for service in services {
|
||||
// Intentar detectar el puerto si no se encontró en Environment
|
||||
let port = service.port.unwrap_or_else(|| {
|
||||
// Intentar extraer del nombre o usar puerto por defecto
|
||||
detect_port_from_name(&service.app_name)
|
||||
});
|
||||
|
||||
@@ -170,10 +222,29 @@ pub fn sync_discovered_services(services: Vec<DiscoveredService>) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Agregar a monitored_apps.json
|
||||
logger.info("Discovery", &format!("➕ Agregando {} (puerto: {})", service.app_name, port));
|
||||
// Crear MonitoredApp con información completa
|
||||
let service_name = format!("siax-app-{}.service", service.app_name);
|
||||
let registered_at = chrono::Local::now().to_rfc3339();
|
||||
|
||||
match config_manager.add_app(service.app_name.clone(), port) {
|
||||
let app = MonitoredApp {
|
||||
name: service.app_name.clone(),
|
||||
service_name,
|
||||
path: service.working_directory.unwrap_or_default(),
|
||||
port,
|
||||
entry_point: service.entry_point.unwrap_or_default(),
|
||||
node_bin: service.node_bin.unwrap_or_default(),
|
||||
mode: service.node_env,
|
||||
service_file_path: service.service_file.clone(),
|
||||
registered_at,
|
||||
systemd_service: None,
|
||||
created_at: None,
|
||||
};
|
||||
|
||||
// Agregar a monitored_apps.json
|
||||
logger.info("Discovery", &format!("➕ Agregando {} (puerto: {}, entry: {})",
|
||||
app.name, app.port, app.entry_point));
|
||||
|
||||
match config_manager.add_app_full(app) {
|
||||
Ok(_) => {
|
||||
logger.info("Discovery", &format!("✅ {} agregado exitosamente", service.app_name));
|
||||
added_count += 1;
|
||||
|
||||
Reference in New Issue
Block a user