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:
@@ -1,347 +1,51 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
#######################################
|
# --- CONFIGURACIÓN ---
|
||||||
# SIAX Agent - Script de Despliegue
|
BINARY_NAME="siax_monitor"
|
||||||
# Instalación automática production-ready
|
TARGET="x86_64-unknown-linux-gnu"
|
||||||
#######################################
|
LOCAL_PATH="target/$TARGET/release/$BINARY_NAME"
|
||||||
|
|
||||||
set -e # Salir si hay errores
|
# 1. Preguntar método de transferencia
|
||||||
|
echo "Selecciona el método de transferencia:"
|
||||||
|
select METODO in "scp" "rsync"; do
|
||||||
|
case $METODO in
|
||||||
|
scp|rsync) break ;;
|
||||||
|
*) echo "Opción inválida, elige 1 o 2." ;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
# Colores para output
|
# 2. Compilar
|
||||||
RED='\033[0;31m'
|
echo "📦 Compilando..."
|
||||||
GREEN='\033[0;32m'
|
cargo build --release --target $TARGET
|
||||||
YELLOW='\033[1;33m'
|
if [ $? -ne 0 ]; then echo "❌ Error en compilación"; exit 1; fi
|
||||||
BLUE='\033[0;34m'
|
|
||||||
NC='\033[0m' # No Color
|
|
||||||
|
|
||||||
# Variables
|
# --- FUNCIÓN DE SUBIDA ---
|
||||||
INSTALL_DIR="/opt/siax-agent"
|
upload_file() {
|
||||||
SERVICE_USER="siax-agent"
|
local IP=$1
|
||||||
BACKUP_DIR="/tmp/siax-agent-backup-$(date +%s)"
|
local USER=$2
|
||||||
|
local DEST=$3
|
||||||
|
|
||||||
#######################################
|
echo "🚀 Subiendo a $USER@$IP vía $METODO..."
|
||||||
# Funciones
|
|
||||||
#######################################
|
|
||||||
|
|
||||||
print_header() {
|
if [ "$METODO" = "scp" ]; then
|
||||||
echo -e "${BLUE}"
|
scp "$LOCAL_PATH" "$USER@$IP:$DEST/"
|
||||||
echo "============================================"
|
|
||||||
echo " SIAX Agent - Deployment Script"
|
|
||||||
echo "============================================"
|
|
||||||
echo -e "${NC}"
|
|
||||||
}
|
|
||||||
|
|
||||||
print_success() {
|
|
||||||
echo -e "${GREEN}✅ $1${NC}"
|
|
||||||
}
|
|
||||||
|
|
||||||
print_error() {
|
|
||||||
echo -e "${RED}❌ $1${NC}"
|
|
||||||
}
|
|
||||||
|
|
||||||
print_warning() {
|
|
||||||
echo -e "${YELLOW}⚠️ $1${NC}"
|
|
||||||
}
|
|
||||||
|
|
||||||
print_info() {
|
|
||||||
echo -e "${BLUE}ℹ️ $1${NC}"
|
|
||||||
}
|
|
||||||
|
|
||||||
check_root() {
|
|
||||||
if [ "$EUID" -ne 0 ]; then
|
|
||||||
print_error "Este script debe ejecutarse como root"
|
|
||||||
echo "Usa: sudo ./desplegar_agent.sh"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
check_dependencies() {
|
|
||||||
print_info "Verificando dependencias..."
|
|
||||||
|
|
||||||
local deps=("systemctl" "cargo" "rustc")
|
|
||||||
local missing=()
|
|
||||||
|
|
||||||
for dep in "${deps[@]}"; do
|
|
||||||
if ! command -v $dep &> /dev/null; then
|
|
||||||
missing+=($dep)
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
|
|
||||||
if [ ${#missing[@]} -ne 0 ]; then
|
|
||||||
print_error "Faltan dependencias: ${missing[*]}"
|
|
||||||
echo ""
|
|
||||||
echo "Instalación de Rust:"
|
|
||||||
echo " curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh"
|
|
||||||
echo ""
|
|
||||||
echo "Instalación de systemd (debería estar instalado por defecto):"
|
|
||||||
echo " sudo apt-get install systemd # Debian/Ubuntu"
|
|
||||||
echo " sudo yum install systemd # RedHat/CentOS"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
print_success "Todas las dependencias están instaladas"
|
|
||||||
}
|
|
||||||
|
|
||||||
backup_existing() {
|
|
||||||
if [ -d "$INSTALL_DIR" ]; then
|
|
||||||
print_warning "Instalación existente detectada"
|
|
||||||
print_info "Creando backup en: $BACKUP_DIR"
|
|
||||||
mkdir -p "$BACKUP_DIR"
|
|
||||||
cp -r "$INSTALL_DIR" "$BACKUP_DIR/"
|
|
||||||
print_success "Backup creado"
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
compile_release() {
|
|
||||||
print_info "Compilando SIAX Agent en modo release..."
|
|
||||||
|
|
||||||
if cargo build --release; then
|
|
||||||
print_success "Compilación exitosa"
|
|
||||||
else
|
else
|
||||||
print_error "Error en la compilación"
|
# rsync -avz: a (archivo/permisos), v (visual), z (comprimido)
|
||||||
rollback
|
rsync -avz "$LOCAL_PATH" "$USER@$IP:$DEST/"
|
||||||
exit 1
|
|
||||||
fi
|
fi
|
||||||
}
|
|
||||||
|
|
||||||
create_user() {
|
if [ $? -eq 0 ]; then
|
||||||
if id "$SERVICE_USER" &>/dev/null; then
|
echo "✅ $IP: Completado."
|
||||||
print_info "Usuario $SERVICE_USER ya existe"
|
|
||||||
else
|
else
|
||||||
print_info "Creando usuario del sistema: $SERVICE_USER"
|
echo "❌ $IP: Falló la subida."
|
||||||
useradd --system --no-create-home --shell /bin/false "$SERVICE_USER"
|
|
||||||
print_success "Usuario creado"
|
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
install_binary() {
|
# --- LISTA DE SERVIDORES ---
|
||||||
print_info "Instalando binario en $INSTALL_DIR..."
|
# Formato: upload_file "IP" "USUARIO" "RUTA_DESTINO"
|
||||||
|
upload_file "192.168.10.145" "root" "/root/app"
|
||||||
|
upload_file "192.168.10.150" "pablinux" "/home/pablinux/app"
|
||||||
|
upload_file "192.168.10.160" "user_apps" "/home/user_apps/apps"
|
||||||
|
|
||||||
mkdir -p "$INSTALL_DIR"
|
echo "------------------------------------------------"
|
||||||
mkdir -p "$INSTALL_DIR/config"
|
echo "Done!"
|
||||||
mkdir -p "$INSTALL_DIR/logs"
|
|
||||||
|
|
||||||
cp target/release/siax_monitor "$INSTALL_DIR/siax-agent"
|
|
||||||
chmod +x "$INSTALL_DIR/siax-agent"
|
|
||||||
|
|
||||||
# Copiar archivos de configuración si existen
|
|
||||||
if [ -f "config/monitored_apps.json" ]; then
|
|
||||||
cp config/monitored_apps.json "$INSTALL_DIR/config/"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Copiar archivos web
|
|
||||||
if [ -d "web" ]; then
|
|
||||||
cp -r web "$INSTALL_DIR/"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Permisos
|
|
||||||
chown -R $SERVICE_USER:$SERVICE_USER "$INSTALL_DIR"
|
|
||||||
|
|
||||||
print_success "Binario instalado"
|
|
||||||
}
|
|
||||||
|
|
||||||
configure_sudoers() {
|
|
||||||
print_info "Configurando permisos sudo para systemctl..."
|
|
||||||
|
|
||||||
local sudoers_file="/etc/sudoers.d/siax-agent"
|
|
||||||
|
|
||||||
cat > "$sudoers_file" << EOF
|
|
||||||
# SIAX Agent - Permisos para gestionar servicios systemd
|
|
||||||
$SERVICE_USER ALL=(ALL) NOPASSWD: /bin/systemctl start *
|
|
||||||
$SERVICE_USER ALL=(ALL) NOPASSWD: /bin/systemctl stop *
|
|
||||||
$SERVICE_USER ALL=(ALL) NOPASSWD: /bin/systemctl restart *
|
|
||||||
$SERVICE_USER ALL=(ALL) NOPASSWD: /bin/systemctl status *
|
|
||||||
$SERVICE_USER ALL=(ALL) NOPASSWD: /bin/systemctl enable *
|
|
||||||
$SERVICE_USER ALL=(ALL) NOPASSWD: /bin/systemctl disable *
|
|
||||||
$SERVICE_USER ALL=(ALL) NOPASSWD: /bin/systemctl daemon-reload
|
|
||||||
$SERVICE_USER ALL=(ALL) NOPASSWD: /bin/systemctl is-active *
|
|
||||||
$SERVICE_USER ALL=(ALL) NOPASSWD: /bin/systemctl list-unit-files *
|
|
||||||
$SERVICE_USER ALL=(ALL) NOPASSWD: /bin/journalctl *
|
|
||||||
EOF
|
|
||||||
|
|
||||||
chmod 0440 "$sudoers_file"
|
|
||||||
|
|
||||||
# Validar sintaxis
|
|
||||||
if visudo -c -f "$sudoers_file" &>/dev/null; then
|
|
||||||
print_success "Configuración de sudoers creada"
|
|
||||||
else
|
|
||||||
print_error "Error en configuración de sudoers"
|
|
||||||
rm -f "$sudoers_file"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
create_systemd_service() {
|
|
||||||
print_info "Creando servicio systemd para SIAX Agent..."
|
|
||||||
|
|
||||||
cat > /etc/systemd/system/siax-agent.service << EOF
|
|
||||||
[Unit]
|
|
||||||
Description=SIAX Agent - Process Monitor and Manager
|
|
||||||
After=network.target
|
|
||||||
|
|
||||||
[Service]
|
|
||||||
Type=simple
|
|
||||||
User=$SERVICE_USER
|
|
||||||
WorkingDirectory=$INSTALL_DIR
|
|
||||||
ExecStart=$INSTALL_DIR/siax-agent
|
|
||||||
Restart=always
|
|
||||||
RestartSec=10
|
|
||||||
StandardOutput=journal
|
|
||||||
StandardError=journal
|
|
||||||
|
|
||||||
# Security hardening
|
|
||||||
NoNewPrivileges=true
|
|
||||||
PrivateTmp=true
|
|
||||||
ProtectSystem=strict
|
|
||||||
ReadWritePaths=$INSTALL_DIR/config $INSTALL_DIR/logs /etc/systemd/system
|
|
||||||
ProtectHome=true
|
|
||||||
|
|
||||||
[Install]
|
|
||||||
WantedBy=multi-user.target
|
|
||||||
EOF
|
|
||||||
|
|
||||||
systemctl daemon-reload
|
|
||||||
systemctl enable siax-agent.service
|
|
||||||
|
|
||||||
print_success "Servicio systemd creado y habilitado"
|
|
||||||
}
|
|
||||||
|
|
||||||
verify_installation() {
|
|
||||||
print_info "Verificando instalación..."
|
|
||||||
|
|
||||||
local errors=0
|
|
||||||
|
|
||||||
# Verificar binario
|
|
||||||
if [ ! -f "$INSTALL_DIR/siax-agent" ]; then
|
|
||||||
print_error "Binario no encontrado"
|
|
||||||
((errors++))
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Verificar permisos
|
|
||||||
if [ ! -r "$INSTALL_DIR/siax-agent" ]; then
|
|
||||||
print_error "Permisos incorrectos en binario"
|
|
||||||
((errors++))
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Verificar servicio
|
|
||||||
if ! systemctl is-enabled siax-agent.service &>/dev/null; then
|
|
||||||
print_error "Servicio no habilitado"
|
|
||||||
((errors++))
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Verificar sudoers
|
|
||||||
if [ ! -f "/etc/sudoers.d/siax-agent" ]; then
|
|
||||||
print_warning "Configuración de sudoers no encontrada"
|
|
||||||
echo " El agente podría tener problemas para gestionar servicios"
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ $errors -eq 0 ]; then
|
|
||||||
print_success "Verificación exitosa"
|
|
||||||
return 0
|
|
||||||
else
|
|
||||||
print_error "Verificación falló con $errors errores"
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
start_service() {
|
|
||||||
print_info "Iniciando SIAX Agent..."
|
|
||||||
|
|
||||||
if systemctl start siax-agent.service; then
|
|
||||||
sleep 2
|
|
||||||
if systemctl is-active siax-agent.service &>/dev/null; then
|
|
||||||
print_success "SIAX Agent iniciado correctamente"
|
|
||||||
return 0
|
|
||||||
else
|
|
||||||
print_error "SIAX Agent no pudo iniciarse"
|
|
||||||
echo ""
|
|
||||||
echo "Ver logs con: journalctl -u siax-agent.service -n 50"
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
print_error "Error al iniciar el servicio"
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
rollback() {
|
|
||||||
print_warning "Ejecutando rollback..."
|
|
||||||
|
|
||||||
systemctl stop siax-agent.service 2>/dev/null || true
|
|
||||||
systemctl disable siax-agent.service 2>/dev/null || true
|
|
||||||
|
|
||||||
if [ -d "$BACKUP_DIR" ]; then
|
|
||||||
rm -rf "$INSTALL_DIR"
|
|
||||||
cp -r "$BACKUP_DIR/siax-agent" "$INSTALL_DIR"
|
|
||||||
systemctl start siax-agent.service 2>/dev/null || true
|
|
||||||
print_success "Rollback completado"
|
|
||||||
else
|
|
||||||
print_warning "No hay backup disponible para rollback"
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
print_summary() {
|
|
||||||
echo ""
|
|
||||||
echo -e "${GREEN}============================================${NC}"
|
|
||||||
echo -e "${GREEN} ✅ SIAX Agent instalado exitosamente${NC}"
|
|
||||||
echo -e "${GREEN}============================================${NC}"
|
|
||||||
echo ""
|
|
||||||
echo "📊 Interface Web: http://localhost:8080"
|
|
||||||
echo "🔌 API REST: http://localhost:8081/api"
|
|
||||||
echo "📡 WebSocket: ws://localhost:8081/ws/logs/:app_name"
|
|
||||||
echo ""
|
|
||||||
echo "Comandos útiles:"
|
|
||||||
echo " Estado: sudo systemctl status siax-agent"
|
|
||||||
echo " Logs: sudo journalctl -u siax-agent -f"
|
|
||||||
echo " Reiniciar: sudo systemctl restart siax-agent"
|
|
||||||
echo " Detener: sudo systemctl stop siax-agent"
|
|
||||||
echo ""
|
|
||||||
echo "Directorio de instalación: $INSTALL_DIR"
|
|
||||||
echo "Configuración: $INSTALL_DIR/config/monitored_apps.json"
|
|
||||||
echo ""
|
|
||||||
}
|
|
||||||
|
|
||||||
#######################################
|
|
||||||
# Main
|
|
||||||
#######################################
|
|
||||||
|
|
||||||
main() {
|
|
||||||
print_header
|
|
||||||
|
|
||||||
check_root
|
|
||||||
check_dependencies
|
|
||||||
backup_existing
|
|
||||||
compile_release
|
|
||||||
create_user
|
|
||||||
install_binary
|
|
||||||
configure_sudoers
|
|
||||||
create_systemd_service
|
|
||||||
|
|
||||||
if verify_installation; then
|
|
||||||
if start_service; then
|
|
||||||
print_summary
|
|
||||||
exit 0
|
|
||||||
else
|
|
||||||
print_error "El servicio no pudo iniciarse correctamente"
|
|
||||||
print_info "Revisa los logs: journalctl -u siax-agent -n 50"
|
|
||||||
echo ""
|
|
||||||
echo "¿Deseas hacer rollback? (y/n)"
|
|
||||||
read -r response
|
|
||||||
if [[ "$response" =~ ^[Yy]$ ]]; then
|
|
||||||
rollback
|
|
||||||
fi
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
print_error "La verificación falló"
|
|
||||||
echo ""
|
|
||||||
echo "¿Deseas hacer rollback? (y/n)"
|
|
||||||
read -r response
|
|
||||||
if [[ "$response" =~ ^[Yy]$ ]]; then
|
|
||||||
rollback
|
|
||||||
fi
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
main
|
|
||||||
|
|||||||
347
instalador.sh
Executable file
347
instalador.sh
Executable file
@@ -0,0 +1,347 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
#######################################
|
||||||
|
# SIAX Agent - Script de Despliegue
|
||||||
|
# Instalación automática production-ready
|
||||||
|
#######################################
|
||||||
|
|
||||||
|
set -e # Salir si hay errores
|
||||||
|
|
||||||
|
# Colores para output
|
||||||
|
RED='\033[0;31m'
|
||||||
|
GREEN='\033[0;32m'
|
||||||
|
YELLOW='\033[1;33m'
|
||||||
|
BLUE='\033[0;34m'
|
||||||
|
NC='\033[0m' # No Color
|
||||||
|
|
||||||
|
# Variables
|
||||||
|
INSTALL_DIR="/opt/siax-agent"
|
||||||
|
SERVICE_USER="siax-agent"
|
||||||
|
BACKUP_DIR="/tmp/siax-agent-backup-$(date +%s)"
|
||||||
|
|
||||||
|
#######################################
|
||||||
|
# Funciones
|
||||||
|
#######################################
|
||||||
|
|
||||||
|
print_header() {
|
||||||
|
echo -e "${BLUE}"
|
||||||
|
echo "============================================"
|
||||||
|
echo " SIAX Agent - Deployment Script"
|
||||||
|
echo "============================================"
|
||||||
|
echo -e "${NC}"
|
||||||
|
}
|
||||||
|
|
||||||
|
print_success() {
|
||||||
|
echo -e "${GREEN}✅ $1${NC}"
|
||||||
|
}
|
||||||
|
|
||||||
|
print_error() {
|
||||||
|
echo -e "${RED}❌ $1${NC}"
|
||||||
|
}
|
||||||
|
|
||||||
|
print_warning() {
|
||||||
|
echo -e "${YELLOW}⚠️ $1${NC}"
|
||||||
|
}
|
||||||
|
|
||||||
|
print_info() {
|
||||||
|
echo -e "${BLUE}ℹ️ $1${NC}"
|
||||||
|
}
|
||||||
|
|
||||||
|
check_root() {
|
||||||
|
if [ "$EUID" -ne 0 ]; then
|
||||||
|
print_error "Este script debe ejecutarse como root"
|
||||||
|
echo "Usa: sudo ./desplegar_agent.sh"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
check_dependencies() {
|
||||||
|
print_info "Verificando dependencias..."
|
||||||
|
|
||||||
|
local deps=("systemctl" "cargo" "rustc")
|
||||||
|
local missing=()
|
||||||
|
|
||||||
|
for dep in "${deps[@]}"; do
|
||||||
|
if ! command -v $dep &> /dev/null; then
|
||||||
|
missing+=($dep)
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
if [ ${#missing[@]} -ne 0 ]; then
|
||||||
|
print_error "Faltan dependencias: ${missing[*]}"
|
||||||
|
echo ""
|
||||||
|
echo "Instalación de Rust:"
|
||||||
|
echo " curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh"
|
||||||
|
echo ""
|
||||||
|
echo "Instalación de systemd (debería estar instalado por defecto):"
|
||||||
|
echo " sudo apt-get install systemd # Debian/Ubuntu"
|
||||||
|
echo " sudo yum install systemd # RedHat/CentOS"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
print_success "Todas las dependencias están instaladas"
|
||||||
|
}
|
||||||
|
|
||||||
|
backup_existing() {
|
||||||
|
if [ -d "$INSTALL_DIR" ]; then
|
||||||
|
print_warning "Instalación existente detectada"
|
||||||
|
print_info "Creando backup en: $BACKUP_DIR"
|
||||||
|
mkdir -p "$BACKUP_DIR"
|
||||||
|
cp -r "$INSTALL_DIR" "$BACKUP_DIR/"
|
||||||
|
print_success "Backup creado"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
compile_release() {
|
||||||
|
print_info "Compilando SIAX Agent en modo release..."
|
||||||
|
|
||||||
|
if cargo build --release; then
|
||||||
|
print_success "Compilación exitosa"
|
||||||
|
else
|
||||||
|
print_error "Error en la compilación"
|
||||||
|
rollback
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
create_user() {
|
||||||
|
if id "$SERVICE_USER" &>/dev/null; then
|
||||||
|
print_info "Usuario $SERVICE_USER ya existe"
|
||||||
|
else
|
||||||
|
print_info "Creando usuario del sistema: $SERVICE_USER"
|
||||||
|
useradd --system --no-create-home --shell /bin/false "$SERVICE_USER"
|
||||||
|
print_success "Usuario creado"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
install_binary() {
|
||||||
|
print_info "Instalando binario en $INSTALL_DIR..."
|
||||||
|
|
||||||
|
mkdir -p "$INSTALL_DIR"
|
||||||
|
mkdir -p "$INSTALL_DIR/config"
|
||||||
|
mkdir -p "$INSTALL_DIR/logs"
|
||||||
|
|
||||||
|
cp target/release/siax_monitor "$INSTALL_DIR/siax-agent"
|
||||||
|
chmod +x "$INSTALL_DIR/siax-agent"
|
||||||
|
|
||||||
|
# Copiar archivos de configuración si existen
|
||||||
|
if [ -f "config/monitored_apps.json" ]; then
|
||||||
|
cp config/monitored_apps.json "$INSTALL_DIR/config/"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Copiar archivos web
|
||||||
|
if [ -d "web" ]; then
|
||||||
|
cp -r web "$INSTALL_DIR/"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Permisos
|
||||||
|
chown -R $SERVICE_USER:$SERVICE_USER "$INSTALL_DIR"
|
||||||
|
|
||||||
|
print_success "Binario instalado"
|
||||||
|
}
|
||||||
|
|
||||||
|
configure_sudoers() {
|
||||||
|
print_info "Configurando permisos sudo para systemctl..."
|
||||||
|
|
||||||
|
local sudoers_file="/etc/sudoers.d/siax-agent"
|
||||||
|
|
||||||
|
cat > "$sudoers_file" << EOF
|
||||||
|
# SIAX Agent - Permisos para gestionar servicios systemd
|
||||||
|
$SERVICE_USER ALL=(ALL) NOPASSWD: /bin/systemctl start *
|
||||||
|
$SERVICE_USER ALL=(ALL) NOPASSWD: /bin/systemctl stop *
|
||||||
|
$SERVICE_USER ALL=(ALL) NOPASSWD: /bin/systemctl restart *
|
||||||
|
$SERVICE_USER ALL=(ALL) NOPASSWD: /bin/systemctl status *
|
||||||
|
$SERVICE_USER ALL=(ALL) NOPASSWD: /bin/systemctl enable *
|
||||||
|
$SERVICE_USER ALL=(ALL) NOPASSWD: /bin/systemctl disable *
|
||||||
|
$SERVICE_USER ALL=(ALL) NOPASSWD: /bin/systemctl daemon-reload
|
||||||
|
$SERVICE_USER ALL=(ALL) NOPASSWD: /bin/systemctl is-active *
|
||||||
|
$SERVICE_USER ALL=(ALL) NOPASSWD: /bin/systemctl list-unit-files *
|
||||||
|
$SERVICE_USER ALL=(ALL) NOPASSWD: /bin/journalctl *
|
||||||
|
EOF
|
||||||
|
|
||||||
|
chmod 0440 "$sudoers_file"
|
||||||
|
|
||||||
|
# Validar sintaxis
|
||||||
|
if visudo -c -f "$sudoers_file" &>/dev/null; then
|
||||||
|
print_success "Configuración de sudoers creada"
|
||||||
|
else
|
||||||
|
print_error "Error en configuración de sudoers"
|
||||||
|
rm -f "$sudoers_file"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
create_systemd_service() {
|
||||||
|
print_info "Creando servicio systemd para SIAX Agent..."
|
||||||
|
|
||||||
|
cat > /etc/systemd/system/siax-agent.service << EOF
|
||||||
|
[Unit]
|
||||||
|
Description=SIAX Agent - Process Monitor and Manager
|
||||||
|
After=network.target
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
Type=simple
|
||||||
|
User=$SERVICE_USER
|
||||||
|
WorkingDirectory=$INSTALL_DIR
|
||||||
|
ExecStart=$INSTALL_DIR/siax-agent
|
||||||
|
Restart=always
|
||||||
|
RestartSec=10
|
||||||
|
StandardOutput=journal
|
||||||
|
StandardError=journal
|
||||||
|
|
||||||
|
# Security hardening
|
||||||
|
NoNewPrivileges=true
|
||||||
|
PrivateTmp=true
|
||||||
|
ProtectSystem=strict
|
||||||
|
ReadWritePaths=$INSTALL_DIR/config $INSTALL_DIR/logs /etc/systemd/system
|
||||||
|
ProtectHome=true
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=multi-user.target
|
||||||
|
EOF
|
||||||
|
|
||||||
|
systemctl daemon-reload
|
||||||
|
systemctl enable siax-agent.service
|
||||||
|
|
||||||
|
print_success "Servicio systemd creado y habilitado"
|
||||||
|
}
|
||||||
|
|
||||||
|
verify_installation() {
|
||||||
|
print_info "Verificando instalación..."
|
||||||
|
|
||||||
|
local errors=0
|
||||||
|
|
||||||
|
# Verificar binario
|
||||||
|
if [ ! -f "$INSTALL_DIR/siax-agent" ]; then
|
||||||
|
print_error "Binario no encontrado"
|
||||||
|
((errors++))
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Verificar permisos
|
||||||
|
if [ ! -r "$INSTALL_DIR/siax-agent" ]; then
|
||||||
|
print_error "Permisos incorrectos en binario"
|
||||||
|
((errors++))
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Verificar servicio
|
||||||
|
if ! systemctl is-enabled siax-agent.service &>/dev/null; then
|
||||||
|
print_error "Servicio no habilitado"
|
||||||
|
((errors++))
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Verificar sudoers
|
||||||
|
if [ ! -f "/etc/sudoers.d/siax-agent" ]; then
|
||||||
|
print_warning "Configuración de sudoers no encontrada"
|
||||||
|
echo " El agente podría tener problemas para gestionar servicios"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ $errors -eq 0 ]; then
|
||||||
|
print_success "Verificación exitosa"
|
||||||
|
return 0
|
||||||
|
else
|
||||||
|
print_error "Verificación falló con $errors errores"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
start_service() {
|
||||||
|
print_info "Iniciando SIAX Agent..."
|
||||||
|
|
||||||
|
if systemctl start siax-agent.service; then
|
||||||
|
sleep 2
|
||||||
|
if systemctl is-active siax-agent.service &>/dev/null; then
|
||||||
|
print_success "SIAX Agent iniciado correctamente"
|
||||||
|
return 0
|
||||||
|
else
|
||||||
|
print_error "SIAX Agent no pudo iniciarse"
|
||||||
|
echo ""
|
||||||
|
echo "Ver logs con: journalctl -u siax-agent.service -n 50"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
print_error "Error al iniciar el servicio"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
rollback() {
|
||||||
|
print_warning "Ejecutando rollback..."
|
||||||
|
|
||||||
|
systemctl stop siax-agent.service 2>/dev/null || true
|
||||||
|
systemctl disable siax-agent.service 2>/dev/null || true
|
||||||
|
|
||||||
|
if [ -d "$BACKUP_DIR" ]; then
|
||||||
|
rm -rf "$INSTALL_DIR"
|
||||||
|
cp -r "$BACKUP_DIR/siax-agent" "$INSTALL_DIR"
|
||||||
|
systemctl start siax-agent.service 2>/dev/null || true
|
||||||
|
print_success "Rollback completado"
|
||||||
|
else
|
||||||
|
print_warning "No hay backup disponible para rollback"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
print_summary() {
|
||||||
|
echo ""
|
||||||
|
echo -e "${GREEN}============================================${NC}"
|
||||||
|
echo -e "${GREEN} ✅ SIAX Agent instalado exitosamente${NC}"
|
||||||
|
echo -e "${GREEN}============================================${NC}"
|
||||||
|
echo ""
|
||||||
|
echo "📊 Interface Web: http://localhost:8080"
|
||||||
|
echo "🔌 API REST: http://localhost:8081/api"
|
||||||
|
echo "📡 WebSocket: ws://localhost:8081/ws/logs/:app_name"
|
||||||
|
echo ""
|
||||||
|
echo "Comandos útiles:"
|
||||||
|
echo " Estado: sudo systemctl status siax-agent"
|
||||||
|
echo " Logs: sudo journalctl -u siax-agent -f"
|
||||||
|
echo " Reiniciar: sudo systemctl restart siax-agent"
|
||||||
|
echo " Detener: sudo systemctl stop siax-agent"
|
||||||
|
echo ""
|
||||||
|
echo "Directorio de instalación: $INSTALL_DIR"
|
||||||
|
echo "Configuración: $INSTALL_DIR/config/monitored_apps.json"
|
||||||
|
echo ""
|
||||||
|
}
|
||||||
|
|
||||||
|
#######################################
|
||||||
|
# Main
|
||||||
|
#######################################
|
||||||
|
|
||||||
|
main() {
|
||||||
|
print_header
|
||||||
|
|
||||||
|
check_root
|
||||||
|
check_dependencies
|
||||||
|
backup_existing
|
||||||
|
compile_release
|
||||||
|
create_user
|
||||||
|
install_binary
|
||||||
|
configure_sudoers
|
||||||
|
create_systemd_service
|
||||||
|
|
||||||
|
if verify_installation; then
|
||||||
|
if start_service; then
|
||||||
|
print_summary
|
||||||
|
exit 0
|
||||||
|
else
|
||||||
|
print_error "El servicio no pudo iniciarse correctamente"
|
||||||
|
print_info "Revisa los logs: journalctl -u siax-agent -n 50"
|
||||||
|
echo ""
|
||||||
|
echo "¿Deseas hacer rollback? (y/n)"
|
||||||
|
read -r response
|
||||||
|
if [[ "$response" =~ ^[Yy]$ ]]; then
|
||||||
|
rollback
|
||||||
|
fi
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
print_error "La verificación falló"
|
||||||
|
echo ""
|
||||||
|
echo "¿Deseas hacer rollback? (y/n)"
|
||||||
|
read -r response
|
||||||
|
if [[ "$response" =~ ^[Yy]$ ]]; then
|
||||||
|
rollback
|
||||||
|
fi
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
main
|
||||||
315
install-remote.sh
Normal file
315
install-remote.sh
Normal file
@@ -0,0 +1,315 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
#######################################
|
||||||
|
# SIAX Agent - Script de Instalación Remota
|
||||||
|
# Descarga e instala SIAX Agent desde servidor central
|
||||||
|
#######################################
|
||||||
|
|
||||||
|
set -e # Salir si hay errores
|
||||||
|
|
||||||
|
# Variables (CONFIGURAR AQUÍ)
|
||||||
|
CENTRAL_SERVER="${SIAX_SERVER:-localhost:8080}" # Servidor central
|
||||||
|
INSTALL_DIR="/opt/siax-agent"
|
||||||
|
SERVICE_USER="siax-agent"
|
||||||
|
BACKUP_DIR="/tmp/siax-agent-backup-$(date +%s)"
|
||||||
|
DOWNLOAD_DIR="/tmp/siax-agent-download-$(date +%s)"
|
||||||
|
|
||||||
|
# Colores para output
|
||||||
|
RED='\033[0;31m'
|
||||||
|
GREEN='\033[0;32m'
|
||||||
|
YELLOW='\033[1;33m'
|
||||||
|
BLUE='\033[0;34m'
|
||||||
|
NC='\033[0m' # No Color
|
||||||
|
|
||||||
|
#######################################
|
||||||
|
# Funciones
|
||||||
|
#######################################
|
||||||
|
|
||||||
|
print_header() {
|
||||||
|
echo -e "${BLUE}"
|
||||||
|
echo "============================================"
|
||||||
|
echo " SIAX Agent - Remote Installation"
|
||||||
|
echo " Server: $CENTRAL_SERVER"
|
||||||
|
echo "============================================"
|
||||||
|
echo -e "${NC}"
|
||||||
|
}
|
||||||
|
|
||||||
|
print_success() {
|
||||||
|
echo -e "${GREEN}✅ $1${NC}"
|
||||||
|
}
|
||||||
|
|
||||||
|
print_error() {
|
||||||
|
echo -e "${RED}❌ $1${NC}"
|
||||||
|
}
|
||||||
|
|
||||||
|
print_warning() {
|
||||||
|
echo -e "${YELLOW}⚠️ $1${NC}"
|
||||||
|
}
|
||||||
|
|
||||||
|
print_info() {
|
||||||
|
echo -e "${BLUE}ℹ️ $1${NC}"
|
||||||
|
}
|
||||||
|
|
||||||
|
check_root() {
|
||||||
|
if [ "$EUID" -ne 0 ]; then
|
||||||
|
print_error "Este script debe ejecutarse como root"
|
||||||
|
echo "Usa: curl -sSL http://$CENTRAL_SERVER/install.sh | sudo bash"
|
||||||
|
echo "O con variable: curl -sSL http://$CENTRAL_SERVER/install.sh | sudo SIAX_SERVER=tu-servidor:8080 bash"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
check_dependencies() {
|
||||||
|
print_info "Verificando dependencias..."
|
||||||
|
|
||||||
|
local deps=("systemctl" "curl")
|
||||||
|
local missing=()
|
||||||
|
|
||||||
|
for dep in "${deps[@]}"; do
|
||||||
|
if ! command -v $dep &> /dev/null; then
|
||||||
|
missing+=($dep)
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
if [ ${#missing[@]} -ne 0 ]; then
|
||||||
|
print_error "Faltan dependencias: ${missing[*]}"
|
||||||
|
echo ""
|
||||||
|
echo "Instalación en Debian/Ubuntu:"
|
||||||
|
echo " sudo apt-get update && sudo apt-get install -y curl systemd"
|
||||||
|
echo ""
|
||||||
|
echo "Instalación en RedHat/CentOS:"
|
||||||
|
echo " sudo yum install -y curl systemd"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
print_success "Todas las dependencias están instaladas"
|
||||||
|
}
|
||||||
|
|
||||||
|
download_binary() {
|
||||||
|
print_info "Descargando binario desde $CENTRAL_SERVER..."
|
||||||
|
|
||||||
|
mkdir -p "$DOWNLOAD_DIR"
|
||||||
|
|
||||||
|
# Intentar descargar el binario pre-compilado
|
||||||
|
if curl -f -L -o "$DOWNLOAD_DIR/siax-agent" "http://$CENTRAL_SERVER/static/binary/siax-agent"; then
|
||||||
|
chmod +x "$DOWNLOAD_DIR/siax-agent"
|
||||||
|
print_success "Binario descargado"
|
||||||
|
else
|
||||||
|
print_error "No se pudo descargar el binario desde http://$CENTRAL_SERVER/static/binary/siax-agent"
|
||||||
|
echo ""
|
||||||
|
echo "Asegúrate de que:"
|
||||||
|
echo " 1. El servidor $CENTRAL_SERVER está accesible"
|
||||||
|
echo " 2. El binario está en web/static/binary/siax-agent"
|
||||||
|
echo " 3. Compilaste con: cargo build --release && cp target/release/siax_monitor web/static/binary/siax-agent"
|
||||||
|
rm -rf "$DOWNLOAD_DIR"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
download_web_files() {
|
||||||
|
print_info "Descargando archivos web..."
|
||||||
|
|
||||||
|
mkdir -p "$DOWNLOAD_DIR/web"
|
||||||
|
|
||||||
|
# Descargar archivos HTML principales (opcional, solo si quieres que cada agente tenga su propia interfaz)
|
||||||
|
# Para agentes worker, probablemente no necesites esto
|
||||||
|
print_info "Archivos web no necesarios para worker nodes (omitiendo)"
|
||||||
|
}
|
||||||
|
|
||||||
|
backup_existing() {
|
||||||
|
if [ -d "$INSTALL_DIR" ]; then
|
||||||
|
print_warning "Instalación existente detectada"
|
||||||
|
print_info "Creando backup en: $BACKUP_DIR"
|
||||||
|
mkdir -p "$BACKUP_DIR"
|
||||||
|
cp -r "$INSTALL_DIR" "$BACKUP_DIR/"
|
||||||
|
print_success "Backup creado"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
create_user() {
|
||||||
|
if id "$SERVICE_USER" &>/dev/null; then
|
||||||
|
print_info "Usuario $SERVICE_USER ya existe"
|
||||||
|
else
|
||||||
|
print_info "Creando usuario del sistema: $SERVICE_USER"
|
||||||
|
useradd --system --no-create-home --shell /bin/false "$SERVICE_USER"
|
||||||
|
print_success "Usuario creado"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
install_binary() {
|
||||||
|
print_info "Instalando binario en $INSTALL_DIR..."
|
||||||
|
|
||||||
|
mkdir -p "$INSTALL_DIR"
|
||||||
|
mkdir -p "$INSTALL_DIR/config"
|
||||||
|
mkdir -p "$INSTALL_DIR/logs"
|
||||||
|
mkdir -p "$INSTALL_DIR/web/static"
|
||||||
|
|
||||||
|
# Copiar binario
|
||||||
|
cp "$DOWNLOAD_DIR/siax-agent" "$INSTALL_DIR/siax-agent"
|
||||||
|
chmod +x "$INSTALL_DIR/siax-agent"
|
||||||
|
|
||||||
|
# Crear configuración inicial vacía si no existe
|
||||||
|
if [ ! -f "$INSTALL_DIR/config/monitored_apps.json" ]; then
|
||||||
|
echo '{"apps":[]}' > "$INSTALL_DIR/config/monitored_apps.json"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Permisos
|
||||||
|
chown -R $SERVICE_USER:$SERVICE_USER "$INSTALL_DIR"
|
||||||
|
|
||||||
|
print_success "Binario instalado"
|
||||||
|
}
|
||||||
|
|
||||||
|
configure_sudoers() {
|
||||||
|
print_info "Configurando permisos sudo para systemctl..."
|
||||||
|
|
||||||
|
local sudoers_file="/etc/sudoers.d/siax-agent"
|
||||||
|
|
||||||
|
cat > "$sudoers_file" << 'EOF'
|
||||||
|
# SIAX Agent - Permisos para gestionar servicios systemd
|
||||||
|
siax-agent ALL=(ALL) NOPASSWD: /bin/systemctl start *
|
||||||
|
siax-agent ALL=(ALL) NOPASSWD: /bin/systemctl stop *
|
||||||
|
siax-agent ALL=(ALL) NOPASSWD: /bin/systemctl restart *
|
||||||
|
siax-agent ALL=(ALL) NOPASSWD: /bin/systemctl status *
|
||||||
|
siax-agent ALL=(ALL) NOPASSWD: /bin/systemctl enable *
|
||||||
|
siax-agent ALL=(ALL) NOPASSWD: /bin/systemctl disable *
|
||||||
|
siax-agent ALL=(ALL) NOPASSWD: /bin/systemctl daemon-reload
|
||||||
|
siax-agent ALL=(ALL) NOPASSWD: /bin/systemctl is-active *
|
||||||
|
siax-agent ALL=(ALL) NOPASSWD: /bin/systemctl list-unit-files *
|
||||||
|
siax-agent ALL=(ALL) NOPASSWD: /bin/journalctl *
|
||||||
|
siax-agent ALL=(ALL) NOPASSWD: /usr/bin/systemctl start *
|
||||||
|
siax-agent ALL=(ALL) NOPASSWD: /usr/bin/systemctl stop *
|
||||||
|
siax-agent ALL=(ALL) NOPASSWD: /usr/bin/systemctl restart *
|
||||||
|
siax-agent ALL=(ALL) NOPASSWD: /usr/bin/systemctl status *
|
||||||
|
siax-agent ALL=(ALL) NOPASSWD: /usr/bin/systemctl enable *
|
||||||
|
siax-agent ALL=(ALL) NOPASSWD: /usr/bin/systemctl disable *
|
||||||
|
siax-agent ALL=(ALL) NOPASSWD: /usr/bin/systemctl daemon-reload
|
||||||
|
siax-agent ALL=(ALL) NOPASSWD: /usr/bin/systemctl is-active *
|
||||||
|
siax-agent ALL=(ALL) NOPASSWD: /usr/bin/systemctl list-unit-files *
|
||||||
|
siax-agent ALL=(ALL) NOPASSWD: /usr/bin/journalctl *
|
||||||
|
EOF
|
||||||
|
|
||||||
|
chmod 0440 "$sudoers_file"
|
||||||
|
|
||||||
|
# Validar sintaxis
|
||||||
|
if visudo -c -f "$sudoers_file" &>/dev/null; then
|
||||||
|
print_success "Configuración de sudoers creada"
|
||||||
|
else
|
||||||
|
print_error "Error en configuración de sudoers"
|
||||||
|
rm -f "$sudoers_file"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
create_systemd_service() {
|
||||||
|
print_info "Creando servicio systemd para SIAX Agent..."
|
||||||
|
|
||||||
|
cat > /etc/systemd/system/siax-agent.service << EOF
|
||||||
|
[Unit]
|
||||||
|
Description=SIAX Agent - Process Monitor and Manager
|
||||||
|
After=network.target
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
Type=simple
|
||||||
|
User=$SERVICE_USER
|
||||||
|
WorkingDirectory=$INSTALL_DIR
|
||||||
|
ExecStart=$INSTALL_DIR/siax-agent
|
||||||
|
Restart=always
|
||||||
|
RestartSec=10
|
||||||
|
StandardOutput=journal
|
||||||
|
StandardError=journal
|
||||||
|
|
||||||
|
# Security hardening
|
||||||
|
NoNewPrivileges=true
|
||||||
|
PrivateTmp=true
|
||||||
|
ProtectSystem=strict
|
||||||
|
ReadWritePaths=$INSTALL_DIR/config $INSTALL_DIR/logs /etc/systemd/system
|
||||||
|
ProtectHome=true
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=multi-user.target
|
||||||
|
EOF
|
||||||
|
|
||||||
|
systemctl daemon-reload
|
||||||
|
systemctl enable siax-agent.service
|
||||||
|
|
||||||
|
print_success "Servicio systemd creado y habilitado"
|
||||||
|
}
|
||||||
|
|
||||||
|
start_service() {
|
||||||
|
print_info "Iniciando SIAX Agent..."
|
||||||
|
|
||||||
|
if systemctl start siax-agent.service; then
|
||||||
|
sleep 2
|
||||||
|
if systemctl is-active siax-agent.service &>/dev/null; then
|
||||||
|
print_success "SIAX Agent iniciado correctamente"
|
||||||
|
return 0
|
||||||
|
else
|
||||||
|
print_error "SIAX Agent no pudo iniciarse"
|
||||||
|
echo ""
|
||||||
|
echo "Ver logs con: journalctl -u siax-agent.service -n 50"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
print_error "Error al iniciar el servicio"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
cleanup() {
|
||||||
|
print_info "Limpiando archivos temporales..."
|
||||||
|
rm -rf "$DOWNLOAD_DIR"
|
||||||
|
print_success "Limpieza completada"
|
||||||
|
}
|
||||||
|
|
||||||
|
print_summary() {
|
||||||
|
echo ""
|
||||||
|
echo -e "${GREEN}============================================${NC}"
|
||||||
|
echo -e "${GREEN} ✅ SIAX Agent instalado exitosamente${NC}"
|
||||||
|
echo -e "${GREEN}============================================${NC}"
|
||||||
|
echo ""
|
||||||
|
echo "📊 Interface Web: http://localhost:8080"
|
||||||
|
echo "🔌 API REST: http://localhost:8080/api"
|
||||||
|
echo "📡 WebSocket: ws://localhost:8080/api/apps/:name/logs"
|
||||||
|
echo ""
|
||||||
|
echo "Comandos útiles:"
|
||||||
|
echo " Estado: sudo systemctl status siax-agent"
|
||||||
|
echo " Logs: sudo journalctl -u siax-agent -f"
|
||||||
|
echo " Reiniciar: sudo systemctl restart siax-agent"
|
||||||
|
echo " Detener: sudo systemctl stop siax-agent"
|
||||||
|
echo ""
|
||||||
|
echo "Directorio de instalación: $INSTALL_DIR"
|
||||||
|
echo "Configuración: $INSTALL_DIR/config/monitored_apps.json"
|
||||||
|
echo ""
|
||||||
|
echo "🌐 Servidor Central: $CENTRAL_SERVER"
|
||||||
|
echo ""
|
||||||
|
}
|
||||||
|
|
||||||
|
#######################################
|
||||||
|
# Main
|
||||||
|
#######################################
|
||||||
|
|
||||||
|
main() {
|
||||||
|
print_header
|
||||||
|
|
||||||
|
check_root
|
||||||
|
check_dependencies
|
||||||
|
backup_existing
|
||||||
|
download_binary
|
||||||
|
create_user
|
||||||
|
install_binary
|
||||||
|
configure_sudoers
|
||||||
|
create_systemd_service
|
||||||
|
|
||||||
|
if start_service; then
|
||||||
|
cleanup
|
||||||
|
print_summary
|
||||||
|
exit 0
|
||||||
|
else
|
||||||
|
print_error "El servicio no pudo iniciarse correctamente"
|
||||||
|
print_info "Revisa los logs: journalctl -u siax-agent -n 50"
|
||||||
|
cleanup
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
main
|
||||||
240
logs/errors.log
240
logs/errors.log
@@ -117,3 +117,243 @@
|
|||||||
[2026-01-13 08:16:16] [INFO] [Sistema] Iniciando servidor unificado en puerto 8080
|
[2026-01-13 08:16:16] [INFO] [Sistema] Iniciando servidor unificado en puerto 8080
|
||||||
[2026-01-13 08:16:16] [INFO] [Sistema] Sistema SIAX completamente operativo en puerto 8080
|
[2026-01-13 08:16:16] [INFO] [Sistema] Sistema SIAX completamente operativo en puerto 8080
|
||||||
[2026-01-13 08:16:16] [INFO] [Monitor] Vigilando procesos para siax-intel [SIAX-Agent/0.1.0 (linux/x86_64; Rust-Monitor)]
|
[2026-01-13 08:16:16] [INFO] [Monitor] Vigilando procesos para siax-intel [SIAX-Agent/0.1.0 (linux/x86_64; Rust-Monitor)]
|
||||||
|
[2026-01-13 11:34:33] [INFO] [Sistema] Iniciando SIAX Agent
|
||||||
|
[2026-01-13 11:34:33] [INFO] [Sistema] Iniciando servidor unificado en puerto 8080
|
||||||
|
[2026-01-13 11:34:33] [INFO] [Sistema] Sistema SIAX completamente operativo en puerto 8080
|
||||||
|
[2026-01-13 11:34:33] [INFO] [Monitor] Vigilando procesos para siax-intel [SIAX-Agent/0.1.0 (linux/x86_64; Rust-Monitor)]
|
||||||
|
[2026-01-13 11:37:28] [INFO] [Sistema] Iniciando SIAX Agent
|
||||||
|
[2026-01-13 11:37:28] [INFO] [Sistema] Iniciando servidor unificado en puerto 8080
|
||||||
|
[2026-01-13 11:37:28] [INFO] [Sistema] Sistema SIAX completamente operativo en puerto 8080
|
||||||
|
[2026-01-13 11:37:28] [INFO] [Monitor] Vigilando procesos para siax-intel [SIAX-Agent/0.1.0 (linux/x86_64; Rust-Monitor)]
|
||||||
|
[2026-01-13 11:43:43] [ERROR] [Monitor] Error enviando app_tareas | error sending request for url (https://api.siax-system.net/api/apps_servcs/apps): operation timed out
|
||||||
|
[2026-01-13 11:43:54] [ERROR] [Monitor] Error enviando fidelizacion | error sending request for url (https://api.siax-system.net/api/apps_servcs/apps): operation timed out
|
||||||
|
[2026-01-13 11:48:54] [INFO] [Sistema] Iniciando SIAX Agent
|
||||||
|
[2026-01-13 11:48:54] [INFO] [Sistema] Iniciando servidor unificado en puerto 8080
|
||||||
|
[2026-01-13 11:48:54] [INFO] [Sistema] Sistema SIAX completamente operativo en puerto 8080
|
||||||
|
[2026-01-13 11:48:54] [INFO] [Monitor] Vigilando procesos para siax-intel [SIAX-Agent/0.1.0 (linux/x86_64; Rust-Monitor)]
|
||||||
|
[2026-01-13 11:54:16] [INFO] [Sistema] Iniciando SIAX Agent
|
||||||
|
[2026-01-13 11:54:16] [INFO] [Sistema] Iniciando servidor unificado en puerto 8080
|
||||||
|
[2026-01-13 11:54:16] [INFO] [Sistema] Sistema SIAX completamente operativo en puerto 8080
|
||||||
|
[2026-01-13 11:54:16] [INFO] [Monitor] Vigilando procesos para siax-intel [SIAX-Agent/0.1.0 (linux/x86_64; Rust-Monitor)]
|
||||||
|
[2026-01-13 11:57:20] [INFO] [Sistema] Iniciando SIAX Agent
|
||||||
|
[2026-01-13 11:57:20] [INFO] [Sistema] Iniciando servidor unificado en puerto 8080
|
||||||
|
[2026-01-13 11:57:20] [INFO] [Sistema] Sistema SIAX completamente operativo en puerto 8080
|
||||||
|
[2026-01-13 11:57:20] [INFO] [Monitor] Vigilando procesos para siax-intel [SIAX-Agent/0.1.0 (linux/x86_64; Rust-Monitor)]
|
||||||
|
[2026-01-13 11:58:31] [INFO] [Sistema] Iniciando SIAX Agent
|
||||||
|
[2026-01-13 11:58:31] [INFO] [Sistema] Iniciando servidor unificado en puerto 8080
|
||||||
|
[2026-01-13 11:58:31] [INFO] [Sistema] Sistema SIAX completamente operativo en puerto 8080
|
||||||
|
[2026-01-13 11:58:31] [INFO] [Monitor] Vigilando procesos para siax-intel [SIAX-Agent/0.1.0 (linux/x86_64; Rust-Monitor)]
|
||||||
|
[2026-01-13 12:01:28] [INFO] [Sistema] Iniciando SIAX Agent
|
||||||
|
[2026-01-13 12:01:28] [INFO] [Sistema] Iniciando servidor unificado en puerto 8080
|
||||||
|
[2026-01-13 12:01:28] [INFO] [Sistema] Sistema SIAX completamente operativo en puerto 8080
|
||||||
|
[2026-01-13 12:01:28] [INFO] [Monitor] Vigilando procesos para siax-intel [SIAX-Agent/0.1.0 (linux/x86_64; Rust-Monitor)]
|
||||||
|
[2026-01-13 12:02:46] [INFO] [Sistema] Iniciando SIAX Agent
|
||||||
|
[2026-01-13 12:02:46] [INFO] [Sistema] Iniciando servidor unificado en puerto 8080
|
||||||
|
[2026-01-13 12:02:46] [INFO] [Sistema] Sistema SIAX completamente operativo en puerto 8080
|
||||||
|
[2026-01-13 12:02:46] [INFO] [Monitor] Vigilando procesos para siax-intel [SIAX-Agent/0.1.0 (linux/x86_64; Rust-Monitor)]
|
||||||
|
[2026-01-13 12:03:45] [INFO] [Sistema] Iniciando SIAX Agent
|
||||||
|
[2026-01-13 12:03:45] [INFO] [Sistema] Iniciando servidor unificado en puerto 8080
|
||||||
|
[2026-01-13 12:03:45] [INFO] [Sistema] Sistema SIAX completamente operativo en puerto 8080
|
||||||
|
[2026-01-13 12:03:46] [INFO] [Monitor] Vigilando procesos para siax-intel [SIAX-Agent/0.1.0 (linux/x86_64; Rust-Monitor)]
|
||||||
|
[2026-01-13 12:06:23] [INFO] [Sistema] Iniciando SIAX Agent
|
||||||
|
[2026-01-13 12:06:23] [INFO] [Sistema] Iniciando servidor unificado en puerto 8080
|
||||||
|
[2026-01-13 12:06:23] [INFO] [Sistema] Sistema SIAX completamente operativo en puerto 8080
|
||||||
|
[2026-01-13 12:06:23] [INFO] [Monitor] Vigilando procesos para siax-intel [SIAX-Agent/0.1.0 (linux/x86_64; Rust-Monitor)]
|
||||||
|
[2026-01-13 12:07:35] [INFO] [Sistema] Iniciando SIAX Agent
|
||||||
|
[2026-01-13 12:07:35] [INFO] [Sistema] Iniciando servidor unificado en puerto 8080
|
||||||
|
[2026-01-13 12:07:35] [INFO] [Sistema] Sistema SIAX completamente operativo en puerto 8080
|
||||||
|
[2026-01-13 12:07:35] [INFO] [Monitor] Vigilando procesos para siax-intel [SIAX-Agent/0.1.0 (linux/x86_64; Rust-Monitor)]
|
||||||
|
[2026-01-13 12:09:36] [INFO] [Sistema] Iniciando SIAX Agent
|
||||||
|
[2026-01-13 12:09:36] [INFO] [Sistema] Iniciando servidor unificado en puerto 8080
|
||||||
|
[2026-01-13 12:09:36] [INFO] [Sistema] Sistema SIAX completamente operativo en puerto 8080
|
||||||
|
[2026-01-13 12:09:36] [INFO] [Monitor] Vigilando procesos para siax-intel [SIAX-Agent/0.1.0 (linux/x86_64; Rust-Monitor)]
|
||||||
|
[2026-01-13 12:12:40] [INFO] [Sistema] Iniciando SIAX Agent
|
||||||
|
[2026-01-13 12:12:40] [INFO] [Sistema] Iniciando servidor unificado en puerto 8080
|
||||||
|
[2026-01-13 12:12:40] [INFO] [Sistema] Sistema SIAX completamente operativo en puerto 8080
|
||||||
|
[2026-01-13 12:12:41] [INFO] [Monitor] Vigilando procesos para siax-intel [SIAX-Agent/0.1.0 (linux/x86_64; Rust-Monitor)]
|
||||||
|
[2026-01-13 12:14:45] [INFO] [Sistema] Iniciando SIAX Agent
|
||||||
|
[2026-01-13 12:14:45] [INFO] [Sistema] Iniciando servidor unificado en puerto 8080
|
||||||
|
[2026-01-13 12:14:45] [INFO] [Sistema] Sistema SIAX completamente operativo en puerto 8080
|
||||||
|
[2026-01-13 12:14:45] [INFO] [Monitor] Vigilando procesos para siax-intel [SIAX-Agent/0.1.0 (linux/x86_64; Rust-Monitor)]
|
||||||
|
[2026-01-13 12:16:41] [INFO] [Sistema] Iniciando SIAX Agent
|
||||||
|
[2026-01-13 12:16:41] [INFO] [Sistema] Iniciando servidor unificado en puerto 8080
|
||||||
|
[2026-01-13 12:16:41] [INFO] [Sistema] Sistema SIAX completamente operativo en puerto 8080
|
||||||
|
[2026-01-13 12:16:41] [INFO] [Monitor] Vigilando procesos para siax-intel [SIAX-Agent/0.1.0 (linux/x86_64; Rust-Monitor)]
|
||||||
|
[2026-01-13 12:16:58] [INFO] [Sistema] Iniciando SIAX Agent
|
||||||
|
[2026-01-13 12:16:58] [INFO] [Sistema] Iniciando servidor unificado en puerto 8080
|
||||||
|
[2026-01-13 12:16:58] [INFO] [Sistema] Sistema SIAX completamente operativo en puerto 8080
|
||||||
|
[2026-01-13 12:16:58] [INFO] [Monitor] Vigilando procesos para siax-intel [SIAX-Agent/0.1.0 (linux/x86_64; Rust-Monitor)]
|
||||||
|
[2026-01-13 12:18:26] [INFO] [Sistema] Iniciando SIAX Agent
|
||||||
|
[2026-01-13 12:18:26] [INFO] [Sistema] Iniciando servidor unificado en puerto 8080
|
||||||
|
[2026-01-13 12:18:26] [INFO] [Sistema] Sistema SIAX completamente operativo en puerto 8080
|
||||||
|
[2026-01-13 12:18:26] [INFO] [Monitor] Vigilando procesos para siax-intel [SIAX-Agent/0.1.0 (linux/x86_64; Rust-Monitor)]
|
||||||
|
[2026-01-13 12:21:10] [INFO] [Sistema] Iniciando SIAX Agent
|
||||||
|
[2026-01-13 12:21:10] [INFO] [Sistema] Iniciando servidor unificado en puerto 8080
|
||||||
|
[2026-01-13 12:21:10] [INFO] [Sistema] Sistema SIAX completamente operativo en puerto 8080
|
||||||
|
[2026-01-13 12:21:10] [INFO] [Monitor] Vigilando procesos para siax-intel [SIAX-Agent/0.1.0 (linux/x86_64; Rust-Monitor)]
|
||||||
|
[2026-01-13 12:24:50] [INFO] [Sistema] Iniciando SIAX Agent
|
||||||
|
[2026-01-13 12:24:50] [INFO] [Sistema] Iniciando servidor unificado en puerto 8080
|
||||||
|
[2026-01-13 12:24:50] [INFO] [Sistema] Sistema SIAX completamente operativo en puerto 8080
|
||||||
|
[2026-01-13 12:24:50] [INFO] [Monitor] Vigilando procesos para siax-intel [SIAX-Agent/0.1.0 (linux/x86_64; Rust-Monitor)]
|
||||||
|
[2026-01-13 12:30:18] [INFO] [Sistema] Iniciando SIAX Agent
|
||||||
|
[2026-01-13 12:30:18] [INFO] [Sistema] Iniciando servidor unificado en puerto 8080
|
||||||
|
[2026-01-13 12:30:18] [INFO] [Sistema] Sistema SIAX completamente operativo en puerto 8080
|
||||||
|
[2026-01-13 12:30:18] [INFO] [Monitor] Vigilando procesos para siax-intel [SIAX-Agent/0.1.0 (linux/x86_64; Rust-Monitor)]
|
||||||
|
[2026-01-13 12:32:13] [INFO] [Sistema] Iniciando SIAX Agent
|
||||||
|
[2026-01-13 12:32:13] [INFO] [Sistema] Iniciando servidor unificado en puerto 8080
|
||||||
|
[2026-01-13 12:32:13] [INFO] [Sistema] Sistema SIAX completamente operativo en puerto 8080
|
||||||
|
[2026-01-13 12:32:13] [INFO] [Monitor] Vigilando procesos para siax-intel [SIAX-Agent/0.1.0 (linux/x86_64; Rust-Monitor)]
|
||||||
|
[2026-01-13 12:36:39] [INFO] [Sistema] Iniciando SIAX Agent
|
||||||
|
[2026-01-13 12:36:39] [INFO] [Sistema] Iniciando servidor unificado en puerto 8080
|
||||||
|
[2026-01-13 12:36:39] [INFO] [Sistema] Sistema SIAX completamente operativo en puerto 8080
|
||||||
|
[2026-01-13 12:36:39] [INFO] [Monitor] Vigilando procesos para siax-intel [SIAX-Agent/0.1.0 (linux/x86_64; Rust-Monitor)]
|
||||||
|
[2026-01-13 20:54:14] [INFO] [Sistema] Iniciando SIAX Agent
|
||||||
|
[2026-01-13 20:54:14] [INFO] [Sistema] Iniciando servidor unificado en puerto 8080
|
||||||
|
[2026-01-13 20:54:14] [INFO] [Sistema] Sistema SIAX completamente operativo en puerto 8080
|
||||||
|
[2026-01-13 20:54:14] [INFO] [Monitor] Vigilando procesos para siax-intel [SIAX-Agent/0.1.0 (linux/x86_64; Rust-Monitor)]
|
||||||
|
[2026-01-13 21:24:19] [INFO] [Sistema] Iniciando SIAX Agent
|
||||||
|
[2026-01-13 21:24:19] [INFO] [Sistema] Iniciando servidor unificado en puerto 8080
|
||||||
|
[2026-01-13 21:24:19] [INFO] [Sistema] Sistema SIAX completamente operativo en puerto 8080
|
||||||
|
[2026-01-13 21:24:19] [INFO] [Monitor] Vigilando procesos para siax-intel [SIAX-Agent/0.1.0 (linux/x86_64; Rust-Monitor)]
|
||||||
|
[2026-01-13 21:26:58] [INFO] [Sistema] Iniciando SIAX Agent
|
||||||
|
[2026-01-13 21:26:58] [INFO] [Sistema] Iniciando servidor unificado en puerto 8080
|
||||||
|
[2026-01-13 21:26:58] [INFO] [Sistema] Sistema SIAX completamente operativo en puerto 8080
|
||||||
|
[2026-01-13 21:26:59] [INFO] [Monitor] Vigilando procesos para siax-intel [SIAX-Agent/0.1.0 (linux/x86_64; Rust-Monitor)]
|
||||||
|
[2026-01-13 21:44:25] [INFO] [Sistema] Iniciando SIAX Agent
|
||||||
|
[2026-01-13 21:44:25] [INFO] [Sistema] Iniciando servidor unificado en puerto 8080
|
||||||
|
[2026-01-13 21:44:25] [INFO] [Sistema] Sistema SIAX completamente operativo en puerto 8080
|
||||||
|
[2026-01-13 21:44:25] [INFO] [Monitor] Vigilando procesos para siax-intel [SIAX-Agent/0.1.0 (linux/x86_64; Rust-Monitor)]
|
||||||
|
[2026-01-13 22:15:29] [INFO] [Sistema] Iniciando SIAX Agent
|
||||||
|
[2026-01-13 22:15:29] [INFO] [Sistema] Iniciando servidor unificado en puerto 8080
|
||||||
|
[2026-01-13 22:15:29] [INFO] [Sistema] Sistema SIAX completamente operativo en puerto 8080
|
||||||
|
[2026-01-13 22:15:29] [INFO] [Monitor] Vigilando procesos para siax-intel [SIAX-Agent/0.1.0 (linux/x86_64; Rust-Monitor)]
|
||||||
|
[2026-01-13 23:10:54] [INFO] [Sistema] Iniciando SIAX Agent
|
||||||
|
[2026-01-13 23:10:54] [INFO] [Sistema] Iniciando servidor unificado en puerto 8080
|
||||||
|
[2026-01-13 23:10:54] [INFO] [Sistema] Sistema SIAX completamente operativo en puerto 8080
|
||||||
|
[2026-01-13 23:10:54] [INFO] [Monitor] Vigilando procesos para siax-intel [SIAX-Agent/0.1.0 (linux/x86_64; Rust-Monitor)]
|
||||||
|
[2026-01-14 00:04:25] [INFO] [Sistema] Iniciando SIAX Agent
|
||||||
|
[2026-01-14 00:04:25] [INFO] [Config] ✅ Configuración cargada: 2 apps desde config/monitored_apps.json
|
||||||
|
[2026-01-14 00:04:25] [INFO] [Sistema] Iniciando servidor unificado en puerto 8080
|
||||||
|
[2026-01-14 00:04:25] [INFO] [Sistema] Sistema SIAX completamente operativo en puerto 8080
|
||||||
|
[2026-01-14 00:04:25] [INFO] [Monitor] Vigilando procesos para siax-intel [SIAX-Agent/0.1.0 (linux/x86_64; Rust-Monitor)]
|
||||||
|
[2026-01-14 00:13:17] [INFO] [Sistema] Iniciando SIAX Agent
|
||||||
|
[2026-01-14 00:13:17] [INFO] [Config] ✅ Configuración cargada: 2 apps desde config/monitored_apps.json
|
||||||
|
[2026-01-14 00:13:17] [INFO] [Sistema] Iniciando servidor unificado en puerto 8080
|
||||||
|
[2026-01-14 00:13:17] [INFO] [Sistema] Sistema SIAX completamente operativo en puerto 8080
|
||||||
|
[2026-01-14 00:13:17] [INFO] [Monitor] Vigilando procesos para siax-intel [SIAX-Agent/0.1.0 (linux/x86_64; Rust-Monitor)]
|
||||||
|
[2026-01-14 00:20:19] [INFO] [Sistema] Iniciando SIAX Agent
|
||||||
|
[2026-01-14 00:20:19] [INFO] [Config] ✅ Configuración cargada: 2 apps desde config/monitored_apps.json
|
||||||
|
[2026-01-14 00:20:19] [INFO] [Sistema] Iniciando servidor unificado en puerto 8080
|
||||||
|
[2026-01-14 00:20:19] [INFO] [Sistema] Sistema SIAX completamente operativo en puerto 8080
|
||||||
|
[2026-01-14 00:20:19] [INFO] [Monitor] Vigilando procesos para siax-intel [SIAX-Agent/0.1.0 (linux/x86_64; Rust-Monitor)]
|
||||||
|
[2026-01-14 00:26:24] [INFO] [Sistema] Iniciando SIAX Agent
|
||||||
|
[2026-01-14 00:26:24] [INFO] [Config] ✅ Configuración cargada: 2 apps desde config/monitored_apps.json
|
||||||
|
[2026-01-14 00:26:24] [INFO] [Sistema] Iniciando servidor unificado en puerto 8080
|
||||||
|
[2026-01-14 00:26:24] [INFO] [Sistema] Sistema SIAX completamente operativo en puerto 8080
|
||||||
|
[2026-01-14 00:26:24] [INFO] [Monitor] Vigilando procesos para siax-intel [SIAX-Agent/0.1.0 (linux/x86_64; Rust-Monitor)]
|
||||||
|
[2026-01-14 00:26:31] [INFO] [Sistema] Iniciando SIAX Agent
|
||||||
|
[2026-01-14 00:26:31] [INFO] [Config] ✅ Configuración cargada: 2 apps desde config/monitored_apps.json
|
||||||
|
[2026-01-14 00:26:31] [INFO] [Sistema] Iniciando servidor unificado en puerto 8080
|
||||||
|
[2026-01-14 00:26:31] [INFO] [Sistema] Sistema SIAX completamente operativo en puerto 8080
|
||||||
|
[2026-01-14 00:26:31] [INFO] [Monitor] Vigilando procesos para siax-intel [SIAX-Agent/0.1.0 (linux/x86_64; Rust-Monitor)]
|
||||||
|
[2026-01-14 00:27:52] [INFO] [Sistema] Iniciando SIAX Agent
|
||||||
|
[2026-01-14 00:27:52] [INFO] [Config] ✅ Configuración cargada: 2 apps desde config/monitored_apps.json
|
||||||
|
[2026-01-14 00:27:52] [INFO] [Sistema] Iniciando servidor unificado en puerto 8080
|
||||||
|
[2026-01-14 00:27:52] [INFO] [Sistema] Sistema SIAX completamente operativo en puerto 8080
|
||||||
|
[2026-01-14 00:27:52] [INFO] [Monitor] Vigilando procesos para siax-intel [SIAX-Agent/0.1.0 (linux/x86_64; Rust-Monitor)]
|
||||||
|
[2026-01-14 00:29:23] [INFO] [Sistema] Iniciando SIAX Agent
|
||||||
|
[2026-01-14 00:29:23] [INFO] [Config] ✅ Configuración cargada: 2 apps desde config/monitored_apps.json
|
||||||
|
[2026-01-14 00:29:23] [INFO] [Sistema] Iniciando servidor unificado en puerto 8080
|
||||||
|
[2026-01-14 00:29:23] [INFO] [Sistema] Sistema SIAX completamente operativo en puerto 8080
|
||||||
|
[2026-01-14 00:29:23] [INFO] [Monitor] Vigilando procesos para siax-intel [SIAX-Agent/0.1.0 (linux/x86_64; Rust-Monitor)]
|
||||||
|
[2026-01-14 00:32:59] [INFO] [Sistema] Iniciando SIAX Agent
|
||||||
|
[2026-01-14 00:32:59] [INFO] [Config] ✅ Configuración cargada: 2 apps desde config/monitored_apps.json
|
||||||
|
[2026-01-14 00:32:59] [INFO] [Sistema] Iniciando servidor unificado en puerto 8080
|
||||||
|
[2026-01-14 00:32:59] [INFO] [Sistema] Sistema SIAX completamente operativo en puerto 8080
|
||||||
|
[2026-01-14 00:32:59] [INFO] [Monitor] Vigilando procesos para siax-intel [SIAX-Agent/0.1.0 (linux/x86_64; Rust-Monitor)]
|
||||||
|
[2026-01-14 00:34:44] [INFO] [Sistema] Iniciando SIAX Agent
|
||||||
|
[2026-01-14 00:34:44] [INFO] [Config] ✅ Configuración cargada: 2 apps desde config/monitored_apps.json
|
||||||
|
[2026-01-14 00:34:44] [INFO] [Sistema] Iniciando servidor unificado en puerto 8080
|
||||||
|
[2026-01-14 00:34:44] [INFO] [Sistema] Sistema SIAX completamente operativo en puerto 8080
|
||||||
|
[2026-01-14 00:34:44] [INFO] [Monitor] Vigilando procesos para siax-intel [SIAX-Agent/0.1.0 (linux/x86_64; Rust-Monitor)]
|
||||||
|
[2026-01-14 00:35:49] [INFO] [Sistema] Iniciando SIAX Agent
|
||||||
|
[2026-01-14 00:35:49] [INFO] [Config] ✅ Configuración cargada: 2 apps desde config/monitored_apps.json
|
||||||
|
[2026-01-14 00:35:49] [INFO] [Sistema] Iniciando servidor unificado en puerto 8080
|
||||||
|
[2026-01-14 00:35:49] [INFO] [Sistema] Sistema SIAX completamente operativo en puerto 8080
|
||||||
|
[2026-01-14 00:35:49] [INFO] [Monitor] Vigilando procesos para siax-intel [SIAX-Agent/0.1.0 (linux/x86_64; Rust-Monitor)]
|
||||||
|
[2026-01-14 00:39:01] [INFO] [Sistema] Iniciando SIAX Agent
|
||||||
|
[2026-01-14 00:39:01] [INFO] [Config] ✅ Configuración cargada: 2 apps desde config/monitored_apps.json
|
||||||
|
[2026-01-14 00:39:01] [INFO] [Sistema] Iniciando servidor unificado en puerto 8080
|
||||||
|
[2026-01-14 00:39:01] [INFO] [Sistema] Sistema SIAX completamente operativo en puerto 8080
|
||||||
|
[2026-01-14 00:39:01] [INFO] [Monitor] Vigilando procesos para siax-intel [SIAX-Agent/0.1.0 (linux/x86_64; Rust-Monitor)]
|
||||||
|
[2026-01-14 00:42:49] [INFO] [Sistema] Iniciando SIAX Agent
|
||||||
|
[2026-01-14 00:42:49] [INFO] [Config] ✅ Configuración cargada: 2 apps desde config/monitored_apps.json
|
||||||
|
[2026-01-14 00:42:49] [INFO] [Sistema] Iniciando servidor unificado en puerto 8080
|
||||||
|
[2026-01-14 00:42:49] [INFO] [Sistema] Sistema SIAX completamente operativo en puerto 8080
|
||||||
|
[2026-01-14 00:42:49] [INFO] [Monitor] Vigilando procesos para siax-intel [SIAX-Agent/0.1.0 (linux/x86_64; Rust-Monitor)]
|
||||||
|
[2026-01-14 00:43:09] [INFO] [Sistema] Iniciando SIAX Agent
|
||||||
|
[2026-01-14 00:43:09] [INFO] [Config] ✅ Configuración cargada: 2 apps desde config/monitored_apps.json
|
||||||
|
[2026-01-14 00:43:09] [INFO] [Sistema] Iniciando servidor unificado en puerto 8080
|
||||||
|
[2026-01-14 00:43:09] [INFO] [Sistema] Sistema SIAX completamente operativo en puerto 8080
|
||||||
|
[2026-01-14 00:43:09] [INFO] [Monitor] Vigilando procesos para siax-intel [SIAX-Agent/0.1.0 (linux/x86_64; Rust-Monitor)]
|
||||||
|
[2026-01-14 00:50:38] [INFO] [Sistema] Iniciando SIAX Agent
|
||||||
|
[2026-01-14 00:50:38] [INFO] [Config] ✅ Configuración cargada: 2 apps desde config/monitored_apps.json
|
||||||
|
[2026-01-14 00:50:38] [INFO] [Sistema] Iniciando servidor unificado en puerto 8080
|
||||||
|
[2026-01-14 00:50:38] [INFO] [Sistema] Sistema SIAX completamente operativo en puerto 8080
|
||||||
|
[2026-01-14 00:50:38] [INFO] [Monitor] Vigilando procesos para siax-intel [SIAX-Agent/0.1.0 (linux/x86_64; Rust-Monitor)]
|
||||||
|
[2026-01-14 00:51:57] [INFO] [Sistema] Iniciando SIAX Agent
|
||||||
|
[2026-01-14 00:51:57] [INFO] [Config] ✅ Configuración cargada: 2 apps desde config/monitored_apps.json
|
||||||
|
[2026-01-14 00:51:57] [INFO] [Sistema] Iniciando servidor unificado en puerto 8080
|
||||||
|
[2026-01-14 00:51:57] [INFO] [Sistema] Sistema SIAX completamente operativo en puerto 8080
|
||||||
|
[2026-01-14 00:51:57] [INFO] [Monitor] Vigilando procesos para siax-intel [SIAX-Agent/0.1.0 (linux/x86_64; Rust-Monitor)]
|
||||||
|
[2026-01-14 01:13:51] [INFO] [Sistema] Iniciando SIAX Agent
|
||||||
|
[2026-01-14 01:13:51] [INFO] [Config] ✅ Configuración cargada: 2 apps desde config/monitored_apps.json
|
||||||
|
[2026-01-14 01:13:51] [INFO] [Sistema] Iniciando servidor unificado en puerto 8080
|
||||||
|
[2026-01-14 01:13:51] [INFO] [Sistema] Sistema SIAX completamente operativo en puerto 8080
|
||||||
|
[2026-01-14 01:13:51] [INFO] [Monitor] Vigilando procesos para siax-intel [SIAX-Agent/0.1.0 (linux/x86_64; Rust-Monitor)]
|
||||||
|
[2026-01-14 01:14:41] [INFO] [Sistema] Iniciando SIAX Agent
|
||||||
|
[2026-01-14 01:14:41] [INFO] [Config] ✅ Configuración cargada: 2 apps desde config/monitored_apps.json
|
||||||
|
[2026-01-14 01:14:41] [INFO] [Sistema] Iniciando servidor unificado en puerto 8080
|
||||||
|
[2026-01-14 01:14:41] [INFO] [Sistema] Sistema SIAX completamente operativo en puerto 8080
|
||||||
|
[2026-01-14 01:14:41] [INFO] [Monitor] Vigilando procesos para siax-intel [SIAX-Agent/0.1.0 (linux/x86_64; Rust-Monitor)]
|
||||||
|
[2026-01-14 01:16:36] [INFO] [Sistema] Iniciando SIAX Agent
|
||||||
|
[2026-01-14 01:16:36] [INFO] [Config] ✅ Configuración cargada: 2 apps desde config/monitored_apps.json
|
||||||
|
[2026-01-14 01:16:36] [INFO] [Sistema] Iniciando servidor unificado en puerto 8080
|
||||||
|
[2026-01-14 01:16:36] [INFO] [Sistema] Sistema SIAX completamente operativo en puerto 8080
|
||||||
|
[2026-01-14 01:16:36] [INFO] [Monitor] Vigilando procesos para siax-intel [SIAX-Agent/0.1.0 (linux/x86_64; Rust-Monitor)]
|
||||||
|
[2026-01-14 01:19:24] [INFO] [Sistema] Iniciando SIAX Agent
|
||||||
|
[2026-01-14 01:19:24] [INFO] [Config] ✅ Configuración cargada: 2 apps desde config/monitored_apps.json
|
||||||
|
[2026-01-14 01:19:24] [INFO] [Sistema] Iniciando servidor unificado en puerto 8080
|
||||||
|
[2026-01-14 01:19:24] [INFO] [Sistema] Sistema SIAX completamente operativo en puerto 8080
|
||||||
|
[2026-01-14 01:19:24] [INFO] [Monitor] Vigilando procesos para siax-intel [SIAX-Agent/0.1.0 (linux/x86_64; Rust-Monitor)]
|
||||||
|
[2026-01-14 01:19:52] [INFO] [Sistema] Iniciando SIAX Agent
|
||||||
|
[2026-01-14 01:19:52] [INFO] [Config] ✅ Configuración cargada: 2 apps desde config/monitored_apps.json
|
||||||
|
[2026-01-14 01:19:52] [INFO] [Sistema] Iniciando servidor unificado en puerto 8080
|
||||||
|
[2026-01-14 01:19:52] [INFO] [Sistema] Sistema SIAX completamente operativo en puerto 8080
|
||||||
|
[2026-01-14 01:19:52] [INFO] [Monitor] Vigilando procesos para siax-intel [SIAX-Agent/0.1.0 (linux/x86_64; Rust-Monitor)]
|
||||||
|
[2026-01-14 01:20:03] [INFO] [Sistema] Iniciando SIAX Agent
|
||||||
|
[2026-01-14 01:20:03] [INFO] [Config] ✅ Configuración cargada: 2 apps desde config/monitored_apps.json
|
||||||
|
[2026-01-14 01:20:03] [INFO] [Sistema] Iniciando servidor unificado en puerto 8080
|
||||||
|
[2026-01-14 01:20:03] [INFO] [Sistema] Sistema SIAX completamente operativo en puerto 8080
|
||||||
|
[2026-01-14 01:20:03] [INFO] [Monitor] Vigilando procesos para siax-intel [SIAX-Agent/0.1.0 (linux/x86_64; Rust-Monitor)]
|
||||||
|
[2026-01-15 02:36:15] [INFO] [Sistema] Iniciando SIAX Agent
|
||||||
|
[2026-01-15 02:36:15] [INFO] [Config] ✅ Configuración cargada: 2 apps desde config/monitored_apps.json
|
||||||
|
[2026-01-15 02:36:15] [INFO] [Sistema] Iniciando servidor unificado en puerto 8080
|
||||||
|
[2026-01-15 02:36:15] [INFO] [Sistema] Sistema SIAX completamente operativo en puerto 8080
|
||||||
|
[2026-01-15 02:36:15] [INFO] [Monitor] Vigilando procesos para siax-intel [SIAX-Agent/0.1.0 (linux/x86_64; Rust-Monitor)]
|
||||||
|
[2026-01-18 03:26:07] [INFO] [Sistema] Iniciando SIAX Agent
|
||||||
|
[2026-01-18 03:26:07] [INFO] [Sistema] Escaneando servicios systemd existentes...
|
||||||
|
[2026-01-18 03:26:07] [INFO] [Discovery] Escaneando servicios systemd existentes...
|
||||||
|
[2026-01-18 03:26:07] [INFO] [Discovery] ✅ Descubiertos 0 servicios
|
||||||
|
[2026-01-18 03:26:07] [INFO] [Config] Usando archivo de configuración: config/monitored_apps.json
|
||||||
|
[2026-01-18 03:26:07] [INFO] [Config] ✅ Configuración cargada: 2 apps desde config/monitored_apps.json
|
||||||
|
[2026-01-18 03:26:07] [INFO] [Sistema] Servidor detectado: siax-intel
|
||||||
|
[2026-01-18 03:26:07] [INFO] [Sistema] Iniciando servidor unificado en puerto 8080
|
||||||
|
[2026-01-18 03:26:07] [INFO] [Sistema] Sistema SIAX completamente operativo en puerto 8080
|
||||||
|
[2026-01-18 03:26:07] [INFO] [Monitor] Vigilando procesos para siax-intel [SIAX-Agent/0.1.0 (linux/x86_64; Rust-Monitor)]
|
||||||
|
[2026-01-18 03:26:07] [INFO] [Monitor] Buscando app app_tareas en API central...
|
||||||
|
[2026-01-18 03:26:07] [INFO] [Monitor] App app_tareas encontrada en cloud (ID: 3)
|
||||||
|
[2026-01-18 03:26:07] [ERROR] [Monitor] Error sincronizando app_tareas | HTTP 500 Internal Server Error: {"success":false,"message":"Error al actualizar el estado","error":"Table 'webControl.app_service_history' doesn't exist"}
|
||||||
|
[2026-01-18 03:26:07] [INFO] [Monitor] Buscando app fidelizacion en API central...
|
||||||
|
[2026-01-18 03:26:07] [INFO] [Monitor] App fidelizacion encontrada en cloud (ID: 4)
|
||||||
|
[2026-01-18 03:26:07] [ERROR] [Monitor] Error sincronizando fidelizacion | HTTP 500 Internal Server Error: {"success":false,"message":"Error al actualizar el estado","error":"Table 'webControl.app_service_history' doesn't exist"}
|
||||||
|
|||||||
66
preparar_binario.sh
Executable file
66
preparar_binario.sh
Executable file
@@ -0,0 +1,66 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
#######################################
|
||||||
|
# SIAX Agent - Preparar Binario para Distribución
|
||||||
|
# Compila y copia el binario a web/static/binary/
|
||||||
|
#######################################
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
GREEN='\033[0;32m'
|
||||||
|
BLUE='\033[0;34m'
|
||||||
|
RED='\033[0;31m'
|
||||||
|
NC='\033[0m'
|
||||||
|
|
||||||
|
echo -e "${BLUE}============================================${NC}"
|
||||||
|
echo -e "${BLUE} Preparando SIAX Agent para Distribución${NC}"
|
||||||
|
echo -e "${BLUE}============================================${NC}"
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# Compilar en release
|
||||||
|
echo -e "${BLUE}📦 Compilando en modo release...${NC}"
|
||||||
|
cargo build --release
|
||||||
|
|
||||||
|
if [ ! -f "target/release/siax_monitor" ]; then
|
||||||
|
echo -e "${RED}❌ Error: No se pudo compilar el binario${NC}"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo -e "${GREEN}✅ Compilación exitosa${NC}"
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# Crear directorio para binarios
|
||||||
|
echo -e "${BLUE}📁 Creando directorio web/static/binary/${NC}"
|
||||||
|
mkdir -p web/static/binary
|
||||||
|
|
||||||
|
# Copiar binario
|
||||||
|
echo -e "${BLUE}📋 Copiando binario...${NC}"
|
||||||
|
cp target/release/siax_monitor web/static/binary/siax-agent
|
||||||
|
chmod +x web/static/binary/siax-agent
|
||||||
|
|
||||||
|
echo -e "${GREEN}✅ Binario copiado a web/static/binary/siax-agent${NC}"
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# Mostrar información
|
||||||
|
BINARY_SIZE=$(du -h web/static/binary/siax-agent | cut -f1)
|
||||||
|
echo -e "${GREEN}============================================${NC}"
|
||||||
|
echo -e "${GREEN} ✅ Preparación completada${NC}"
|
||||||
|
echo -e "${GREEN}============================================${NC}"
|
||||||
|
echo ""
|
||||||
|
echo "📊 Tamaño del binario: $BINARY_SIZE"
|
||||||
|
echo "📂 Ubicación: web/static/binary/siax-agent"
|
||||||
|
echo ""
|
||||||
|
echo "🚀 Ahora puedes:"
|
||||||
|
echo ""
|
||||||
|
echo " 1. Iniciar el servidor:"
|
||||||
|
echo " cargo run --release"
|
||||||
|
echo ""
|
||||||
|
echo " 2. Desde otro servidor, instalar con:"
|
||||||
|
echo " curl -sSL http://TU-SERVIDOR:8080/install.sh | sudo bash"
|
||||||
|
echo ""
|
||||||
|
echo " O especificar el servidor:"
|
||||||
|
echo " curl -sSL http://TU-SERVIDOR:8080/install.sh | sudo SIAX_SERVER=TU-SERVIDOR:8080 bash"
|
||||||
|
echo ""
|
||||||
|
echo "Ejemplo VPN:"
|
||||||
|
echo " curl -sSL http://10.8.0.1:8080/install.sh | sudo SIAX_SERVER=10.8.0.1:8080 bash"
|
||||||
|
echo ""
|
||||||
@@ -6,14 +6,51 @@ use crate::logger::get_logger;
|
|||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
pub struct MonitoredApp {
|
pub struct MonitoredApp {
|
||||||
|
/// Nombre de la aplicación
|
||||||
pub name: String,
|
pub name: String,
|
||||||
|
|
||||||
|
/// Nombre del servicio systemd (ej: siax-app-TAREAS.service)
|
||||||
|
#[serde(default)]
|
||||||
|
pub service_name: String,
|
||||||
|
|
||||||
|
/// Ruta completa al directorio de la aplicación (WorkingDirectory)
|
||||||
|
#[serde(default)]
|
||||||
|
pub path: String,
|
||||||
|
|
||||||
|
/// Puerto donde escucha la aplicación
|
||||||
pub port: i32,
|
pub port: i32,
|
||||||
|
|
||||||
|
/// Archivo de entrada (ej: server.js, app.js)
|
||||||
|
#[serde(default)]
|
||||||
|
pub entry_point: String,
|
||||||
|
|
||||||
|
/// Ruta completa al binario de node/python
|
||||||
|
#[serde(default)]
|
||||||
|
pub node_bin: String,
|
||||||
|
|
||||||
|
/// Modo de ejecución (production, development, test)
|
||||||
|
#[serde(default = "default_mode")]
|
||||||
|
pub mode: String,
|
||||||
|
|
||||||
|
/// Ruta completa al archivo .service de systemd
|
||||||
|
#[serde(default)]
|
||||||
|
pub service_file_path: String,
|
||||||
|
|
||||||
|
/// Fecha de registro (ISO 8601)
|
||||||
|
#[serde(default, skip_serializing_if = "String::is_empty", rename = "reg")]
|
||||||
|
pub registered_at: String,
|
||||||
|
|
||||||
|
// DEPRECATED: Mantener por compatibilidad con versiones antiguas
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub systemd_service: Option<String>,
|
pub systemd_service: Option<String>,
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub created_at: Option<String>,
|
pub created_at: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn default_mode() -> String {
|
||||||
|
"production".to_string()
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
pub struct AppConfig {
|
pub struct AppConfig {
|
||||||
pub apps: Vec<MonitoredApp>,
|
pub apps: Vec<MonitoredApp>,
|
||||||
@@ -99,23 +136,16 @@ impl ConfigManager {
|
|||||||
config.apps.clone()
|
config.apps.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_app(&self, name: String, port: i32) -> Result<(), String> {
|
/// Agrega una app con información completa
|
||||||
|
pub fn add_app_full(&self, app: MonitoredApp) -> Result<(), String> {
|
||||||
let mut config = self.config.write().unwrap();
|
let mut config = self.config.write().unwrap();
|
||||||
|
|
||||||
// Verificar si ya existe
|
// Verificar si ya existe
|
||||||
if config.apps.iter().any(|app| app.name == name) {
|
if config.apps.iter().any(|a| a.name == app.name) {
|
||||||
return Err(format!("La app '{}' ya está siendo monitoreada", name));
|
return Err(format!("La app '{}' ya está siendo monitoreada", app.name));
|
||||||
}
|
}
|
||||||
|
|
||||||
let systemd_service = format!("siax-app-{}.service", name);
|
config.apps.push(app);
|
||||||
let created_at = chrono::Local::now().to_rfc3339();
|
|
||||||
|
|
||||||
config.apps.push(MonitoredApp {
|
|
||||||
name,
|
|
||||||
port,
|
|
||||||
systemd_service: Some(systemd_service),
|
|
||||||
created_at: Some(created_at),
|
|
||||||
});
|
|
||||||
|
|
||||||
// Guardar en disco
|
// Guardar en disco
|
||||||
match Self::save_config_to_file(&self.config_path, &config) {
|
match Self::save_config_to_file(&self.config_path, &config) {
|
||||||
@@ -124,6 +154,29 @@ impl ConfigManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Método simplificado para compatibilidad (DEPRECATED)
|
||||||
|
#[deprecated(note = "Usar add_app_full() con MonitoredApp completo")]
|
||||||
|
pub fn add_app(&self, name: String, port: i32) -> Result<(), String> {
|
||||||
|
let service_name = format!("siax-app-{}.service", name);
|
||||||
|
let registered_at = chrono::Local::now().to_rfc3339();
|
||||||
|
|
||||||
|
let app = MonitoredApp {
|
||||||
|
name,
|
||||||
|
service_name,
|
||||||
|
path: String::new(),
|
||||||
|
port,
|
||||||
|
entry_point: String::new(),
|
||||||
|
node_bin: String::new(),
|
||||||
|
mode: "production".to_string(),
|
||||||
|
service_file_path: String::new(),
|
||||||
|
registered_at,
|
||||||
|
systemd_service: None,
|
||||||
|
created_at: None,
|
||||||
|
};
|
||||||
|
|
||||||
|
self.add_app_full(app)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn remove_app(&self, name: &str) -> Result<(), String> {
|
pub fn remove_app(&self, name: &str) -> Result<(), String> {
|
||||||
let mut config = self.config.write().unwrap();
|
let mut config = self.config.write().unwrap();
|
||||||
|
|
||||||
|
|||||||
@@ -67,9 +67,12 @@ pub struct DiscoveredService {
|
|||||||
pub user: Option<String>,
|
pub user: Option<String>,
|
||||||
pub exec_start: Option<String>,
|
pub exec_start: Option<String>,
|
||||||
pub port: Option<i32>,
|
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> {
|
fn parse_service_file(path: &Path, app_name: &str) -> Option<DiscoveredService> {
|
||||||
let logger = get_logger();
|
let logger = get_logger();
|
||||||
|
|
||||||
@@ -88,6 +91,9 @@ fn parse_service_file(path: &Path, app_name: &str) -> Option<DiscoveredService>
|
|||||||
user: None,
|
user: None,
|
||||||
exec_start: None,
|
exec_start: None,
|
||||||
port: None,
|
port: None,
|
||||||
|
node_env: String::from("production"),
|
||||||
|
entry_point: None,
|
||||||
|
node_bin: None,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Parsear líneas del archivo
|
// Parsear líneas del archivo
|
||||||
@@ -106,7 +112,24 @@ fn parse_service_file(path: &Path, app_name: &str) -> Option<DiscoveredService>
|
|||||||
|
|
||||||
// ExecStart
|
// ExecStart
|
||||||
if line.starts_with("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
|
// Environment con PORT
|
||||||
@@ -115,12 +138,21 @@ fn parse_service_file(path: &Path, app_name: &str) -> Option<DiscoveredService>
|
|||||||
service.port = Some(port);
|
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.app_name,
|
||||||
service.user,
|
service.user,
|
||||||
service.working_directory
|
service.working_directory,
|
||||||
|
service.node_env,
|
||||||
|
service.entry_point
|
||||||
));
|
));
|
||||||
|
|
||||||
Some(service)
|
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
|
/// Sincroniza los servicios descubiertos con monitored_apps.json
|
||||||
pub fn sync_discovered_services(services: Vec<DiscoveredService>) {
|
pub fn sync_discovered_services(services: Vec<DiscoveredService>) {
|
||||||
let logger = get_logger();
|
let logger = get_logger();
|
||||||
@@ -156,7 +209,6 @@ pub fn sync_discovered_services(services: Vec<DiscoveredService>) {
|
|||||||
for service in services {
|
for service in services {
|
||||||
// Intentar detectar el puerto si no se encontró en Environment
|
// Intentar detectar el puerto si no se encontró en Environment
|
||||||
let port = service.port.unwrap_or_else(|| {
|
let port = service.port.unwrap_or_else(|| {
|
||||||
// Intentar extraer del nombre o usar puerto por defecto
|
|
||||||
detect_port_from_name(&service.app_name)
|
detect_port_from_name(&service.app_name)
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -170,10 +222,29 @@ pub fn sync_discovered_services(services: Vec<DiscoveredService>) {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Agregar a monitored_apps.json
|
// Crear MonitoredApp con información completa
|
||||||
logger.info("Discovery", &format!("➕ Agregando {} (puerto: {})", service.app_name, port));
|
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(_) => {
|
Ok(_) => {
|
||||||
logger.info("Discovery", &format!("✅ {} agregado exitosamente", service.app_name));
|
logger.info("Discovery", &format!("✅ {} agregado exitosamente", service.app_name));
|
||||||
added_count += 1;
|
added_count += 1;
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ use super::{Result, OrchestratorError};
|
|||||||
use crate::models::{ServiceConfig, ManagedApp, AppStatus};
|
use crate::models::{ServiceConfig, ManagedApp, AppStatus};
|
||||||
use crate::systemd::{ServiceGenerator, SystemCtl};
|
use crate::systemd::{ServiceGenerator, SystemCtl};
|
||||||
use crate::logger::get_logger;
|
use crate::logger::get_logger;
|
||||||
|
use crate::config::{get_config_manager, MonitoredApp};
|
||||||
use dashmap::DashMap;
|
use dashmap::DashMap;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
@@ -52,6 +53,49 @@ impl AppManager {
|
|||||||
// Guardar en memoria
|
// Guardar en memoria
|
||||||
self.apps.insert(config.app_name.clone(), config.clone());
|
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));
|
logger.info("AppManager", &format!("Aplicación {} registrada exitosamente", config.app_name));
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
@@ -84,6 +128,12 @@ impl AppManager {
|
|||||||
// Eliminar de memoria
|
// Eliminar de memoria
|
||||||
self.apps.remove(app_name);
|
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));
|
logger.info("AppManager", &format!("Aplicación {} desregistrada exitosamente", app_name));
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
<meta charset="utf-8" />
|
<meta charset="utf-8" />
|
||||||
<meta content="width=device-width, initial-scale=1.0" name="viewport" />
|
<meta content="width=device-width, initial-scale=1.0" name="viewport" />
|
||||||
<title>Documentación API - SIAX Monitor</title>
|
<title>Documentación API - SIAX Monitor</title>
|
||||||
|
<link rel="icon" type="image/svg+xml" href="/static/icon/favicon.svg" />
|
||||||
<script src="https://cdn.tailwindcss.com?plugins=forms,container-queries"></script>
|
<script src="https://cdn.tailwindcss.com?plugins=forms,container-queries"></script>
|
||||||
<link
|
<link
|
||||||
href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap"
|
href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap"
|
||||||
@@ -112,17 +113,47 @@
|
|||||||
|
|
||||||
<div class="flex-1 flex max-w-[1400px] mx-auto w-full">
|
<div class="flex-1 flex max-w-[1400px] mx-auto w-full">
|
||||||
<!-- Sidebar - Table of Contents -->
|
<!-- Sidebar - Table of Contents -->
|
||||||
<aside class="w-64 border-r border-[#283039] bg-[#161f2a] p-6 space-y-6 overflow-y-auto">
|
<aside
|
||||||
|
class="w-64 border-r border-[#283039] bg-[#161f2a] p-6 space-y-6 overflow-y-auto"
|
||||||
|
>
|
||||||
<div>
|
<div>
|
||||||
<h3 class="text-white font-bold text-sm mb-3">CONTENIDO</h3>
|
<h3 class="text-white font-bold text-sm mb-3">CONTENIDO</h3>
|
||||||
<nav class="space-y-2">
|
<nav class="space-y-2">
|
||||||
<a href="#intro" class="block text-[#9dabb9] text-sm hover:text-primary transition-colors">Introducción</a>
|
<a
|
||||||
<a href="#auth" class="block text-[#9dabb9] text-sm hover:text-primary transition-colors">Autenticación</a>
|
href="#intro"
|
||||||
<a href="#apps" class="block text-[#9dabb9] text-sm hover:text-primary transition-colors">Gestión de Apps</a>
|
class="block text-[#9dabb9] text-sm hover:text-primary transition-colors"
|
||||||
<a href="#scan" class="block text-[#9dabb9] text-sm hover:text-primary transition-colors">Escaneo</a>
|
>Introducción</a
|
||||||
<a href="#lifecycle" class="block text-[#9dabb9] text-sm hover:text-primary transition-colors">Ciclo de Vida</a>
|
>
|
||||||
<a href="#websocket" class="block text-[#9dabb9] text-sm hover:text-primary transition-colors">WebSocket</a>
|
<a
|
||||||
<a href="#errors" class="block text-[#9dabb9] text-sm hover:text-primary transition-colors">Códigos de Error</a>
|
href="#auth"
|
||||||
|
class="block text-[#9dabb9] text-sm hover:text-primary transition-colors"
|
||||||
|
>Autenticación</a
|
||||||
|
>
|
||||||
|
<a
|
||||||
|
href="#apps"
|
||||||
|
class="block text-[#9dabb9] text-sm hover:text-primary transition-colors"
|
||||||
|
>Gestión de Apps</a
|
||||||
|
>
|
||||||
|
<a
|
||||||
|
href="#scan"
|
||||||
|
class="block text-[#9dabb9] text-sm hover:text-primary transition-colors"
|
||||||
|
>Escaneo</a
|
||||||
|
>
|
||||||
|
<a
|
||||||
|
href="#lifecycle"
|
||||||
|
class="block text-[#9dabb9] text-sm hover:text-primary transition-colors"
|
||||||
|
>Ciclo de Vida</a
|
||||||
|
>
|
||||||
|
<a
|
||||||
|
href="#websocket"
|
||||||
|
class="block text-[#9dabb9] text-sm hover:text-primary transition-colors"
|
||||||
|
>WebSocket</a
|
||||||
|
>
|
||||||
|
<a
|
||||||
|
href="#errors"
|
||||||
|
class="block text-[#9dabb9] text-sm hover:text-primary transition-colors"
|
||||||
|
>Códigos de Error</a
|
||||||
|
>
|
||||||
</nav>
|
</nav>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -135,7 +166,9 @@
|
|||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<span class="text-[#9dabb9]">Base URL:</span>
|
<span class="text-[#9dabb9]">Base URL:</span>
|
||||||
<span class="text-white font-mono">localhost:8080</span>
|
<span class="text-white font-mono"
|
||||||
|
>localhost:8080</span
|
||||||
|
>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<span class="text-[#9dabb9]">Protocolo:</span>
|
<span class="text-[#9dabb9]">Protocolo:</span>
|
||||||
@@ -149,35 +182,70 @@
|
|||||||
<main class="flex-1 p-8 overflow-y-auto">
|
<main class="flex-1 p-8 overflow-y-auto">
|
||||||
<!-- Introduction -->
|
<!-- Introduction -->
|
||||||
<section id="intro" class="mb-12">
|
<section id="intro" class="mb-12">
|
||||||
<h1 class="text-white text-4xl font-black mb-4">Documentación API REST</h1>
|
<h1 class="text-white text-4xl font-black mb-4">
|
||||||
|
Documentación API REST
|
||||||
|
</h1>
|
||||||
<p class="text-[#9dabb9] text-lg mb-6">
|
<p class="text-[#9dabb9] text-lg mb-6">
|
||||||
API para gestión y monitoreo de aplicaciones Node.js y Python con systemd.
|
API para gestión y monitoreo de aplicaciones Node.js y
|
||||||
|
Python con systemd.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<div class="rounded-xl border border-primary/30 bg-primary/10 p-4 mb-6">
|
<div
|
||||||
|
class="rounded-xl border border-primary/30 bg-primary/10 p-4 mb-6"
|
||||||
|
>
|
||||||
<div class="flex items-start gap-3">
|
<div class="flex items-start gap-3">
|
||||||
<span class="material-symbols-outlined text-primary mt-0.5">info</span>
|
<span
|
||||||
|
class="material-symbols-outlined text-primary mt-0.5"
|
||||||
|
>info</span
|
||||||
|
>
|
||||||
<div>
|
<div>
|
||||||
<p class="text-white font-semibold mb-1">Endpoint Base</p>
|
<p class="text-white font-semibold mb-1">
|
||||||
<code class="text-primary font-mono text-sm">http://localhost:8080/api</code>
|
Endpoint Base
|
||||||
|
</p>
|
||||||
|
<code class="text-primary font-mono text-sm"
|
||||||
|
>/api</code
|
||||||
|
>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="grid grid-cols-1 md:grid-cols-3 gap-4">
|
<div class="grid grid-cols-1 md:grid-cols-3 gap-4">
|
||||||
<div class="rounded-xl border border-[#283039] bg-[#161f2a] p-4">
|
<div
|
||||||
<span class="material-symbols-outlined text-green-400 mb-2">check_circle</span>
|
class="rounded-xl border border-[#283039] bg-[#161f2a] p-4"
|
||||||
<p class="text-white font-semibold text-sm">REST API</p>
|
>
|
||||||
|
<span
|
||||||
|
class="material-symbols-outlined text-green-400 mb-2"
|
||||||
|
>check_circle</span
|
||||||
|
>
|
||||||
|
<p class="text-white font-semibold text-sm">
|
||||||
|
REST API
|
||||||
|
</p>
|
||||||
<p class="text-[#9dabb9] text-xs">JSON responses</p>
|
<p class="text-[#9dabb9] text-xs">JSON responses</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="rounded-xl border border-[#283039] bg-[#161f2a] p-4">
|
<div
|
||||||
<span class="material-symbols-outlined text-blue-400 mb-2">bolt</span>
|
class="rounded-xl border border-[#283039] bg-[#161f2a] p-4"
|
||||||
<p class="text-white font-semibold text-sm">WebSocket</p>
|
>
|
||||||
<p class="text-[#9dabb9] text-xs">Logs en tiempo real</p>
|
<span
|
||||||
|
class="material-symbols-outlined text-blue-400 mb-2"
|
||||||
|
>bolt</span
|
||||||
|
>
|
||||||
|
<p class="text-white font-semibold text-sm">
|
||||||
|
WebSocket
|
||||||
|
</p>
|
||||||
|
<p class="text-[#9dabb9] text-xs">
|
||||||
|
Logs en tiempo real
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="rounded-xl border border-[#283039] bg-[#161f2a] p-4">
|
<div
|
||||||
<span class="material-symbols-outlined text-purple-400 mb-2">schedule</span>
|
class="rounded-xl border border-[#283039] bg-[#161f2a] p-4"
|
||||||
<p class="text-white font-semibold text-sm">Rate Limiting</p>
|
>
|
||||||
|
<span
|
||||||
|
class="material-symbols-outlined text-purple-400 mb-2"
|
||||||
|
>schedule</span
|
||||||
|
>
|
||||||
|
<p class="text-white font-semibold text-sm">
|
||||||
|
Rate Limiting
|
||||||
|
</p>
|
||||||
<p class="text-[#9dabb9] text-xs">1 op/segundo</p>
|
<p class="text-[#9dabb9] text-xs">1 op/segundo</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -185,19 +253,34 @@
|
|||||||
|
|
||||||
<!-- Authentication -->
|
<!-- Authentication -->
|
||||||
<section id="auth" class="mb-12">
|
<section id="auth" class="mb-12">
|
||||||
<h2 class="text-white text-2xl font-bold mb-4 flex items-center gap-2">
|
<h2
|
||||||
<span class="material-symbols-outlined text-primary">lock</span>
|
class="text-white text-2xl font-bold mb-4 flex items-center gap-2"
|
||||||
|
>
|
||||||
|
<span class="material-symbols-outlined text-primary"
|
||||||
|
>lock</span
|
||||||
|
>
|
||||||
Autenticación
|
Autenticación
|
||||||
</h2>
|
</h2>
|
||||||
<p class="text-[#9dabb9] mb-4">
|
<p class="text-[#9dabb9] mb-4">
|
||||||
Actualmente la API no requiere autenticación ya que está diseñada para acceso local vía VPN.
|
Actualmente la API no requiere autenticación ya que está
|
||||||
|
diseñada para acceso local vía VPN.
|
||||||
</p>
|
</p>
|
||||||
<div class="rounded-xl border border-yellow-500/30 bg-yellow-500/10 p-4">
|
<div
|
||||||
|
class="rounded-xl border border-yellow-500/30 bg-yellow-500/10 p-4"
|
||||||
|
>
|
||||||
<div class="flex items-start gap-3">
|
<div class="flex items-start gap-3">
|
||||||
<span class="material-symbols-outlined text-yellow-400">warning</span>
|
<span
|
||||||
|
class="material-symbols-outlined text-yellow-400"
|
||||||
|
>warning</span
|
||||||
|
>
|
||||||
<div>
|
<div>
|
||||||
<p class="text-yellow-400 font-semibold">Nota de Seguridad</p>
|
<p class="text-yellow-400 font-semibold">
|
||||||
<p class="text-[#9dabb9] text-sm">Esta API debe ser accesible solo desde redes privadas o VPN.</p>
|
Nota de Seguridad
|
||||||
|
</p>
|
||||||
|
<p class="text-[#9dabb9] text-sm">
|
||||||
|
Esta API debe ser accesible solo desde redes
|
||||||
|
privadas o VPN.
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -205,52 +288,98 @@
|
|||||||
|
|
||||||
<!-- Apps Management -->
|
<!-- Apps Management -->
|
||||||
<section id="apps" class="mb-12">
|
<section id="apps" class="mb-12">
|
||||||
<h2 class="text-white text-2xl font-bold mb-6 flex items-center gap-2">
|
<h2
|
||||||
<span class="material-symbols-outlined text-primary">apps</span>
|
class="text-white text-2xl font-bold mb-6 flex items-center gap-2"
|
||||||
|
>
|
||||||
|
<span class="material-symbols-outlined text-primary"
|
||||||
|
>apps</span
|
||||||
|
>
|
||||||
Gestión de Aplicaciones
|
Gestión de Aplicaciones
|
||||||
</h2>
|
</h2>
|
||||||
|
|
||||||
<!-- List Apps -->
|
<!-- List Apps -->
|
||||||
<div class="mb-8 rounded-xl border border-[#283039] bg-[#161f2a] overflow-hidden">
|
<div
|
||||||
<div class="bg-[#1c2730] px-6 py-4 border-b border-[#283039]">
|
class="mb-8 rounded-xl border border-[#283039] bg-[#161f2a] overflow-hidden"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="bg-[#1c2730] px-6 py-4 border-b border-[#283039]"
|
||||||
|
>
|
||||||
<div class="flex items-center gap-3">
|
<div class="flex items-center gap-3">
|
||||||
<span class="px-2 py-1 rounded bg-green-500/20 text-green-400 text-xs font-bold font-mono">GET</span>
|
<span
|
||||||
<code class="text-white font-mono text-sm">/api/apps</code>
|
class="px-2 py-1 rounded bg-green-500/20 text-green-400 text-xs font-bold font-mono"
|
||||||
|
>GET</span
|
||||||
|
>
|
||||||
|
<code class="text-white font-mono text-sm"
|
||||||
|
>/api/apps</code
|
||||||
|
>
|
||||||
</div>
|
</div>
|
||||||
<p class="text-[#9dabb9] text-sm mt-2">Listar todas las aplicaciones registradas</p>
|
<p class="text-[#9dabb9] text-sm mt-2">
|
||||||
|
Listar todas las aplicaciones registradas
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="p-6 space-y-4">
|
<div class="p-6 space-y-4">
|
||||||
<div>
|
<div>
|
||||||
<p class="text-white font-semibold text-sm mb-2">Respuesta exitosa (200)</p>
|
<p
|
||||||
<pre class="code-block bg-[#0a0f16] p-4 rounded-lg text-sm text-green-400 overflow-x-auto">{
|
class="text-white font-semibold text-sm mb-2"
|
||||||
|
>
|
||||||
|
Respuesta exitosa (200)
|
||||||
|
</p>
|
||||||
|
<pre
|
||||||
|
class="code-block bg-[#0a0f16] p-4 rounded-lg text-sm text-green-400 overflow-x-auto"
|
||||||
|
>
|
||||||
|
{
|
||||||
"success": true,
|
"success": true,
|
||||||
"data": {
|
"data": {
|
||||||
"apps": ["app_tareas", "fidelizacion"],
|
"apps": ["app_tareas", "fidelizacion"],
|
||||||
"total": 2
|
"total": 2
|
||||||
},
|
},
|
||||||
"error": null
|
"error": null
|
||||||
}</pre>
|
}</pre
|
||||||
|
>
|
||||||
</div>
|
</div>
|
||||||
<button onclick="tryEndpoint('GET', '/api/apps')" class="flex items-center gap-2 px-4 py-2 bg-primary hover:brightness-110 rounded-lg text-white text-sm font-medium transition-all">
|
<button
|
||||||
<span class="material-symbols-outlined text-sm">play_arrow</span>
|
onclick="tryEndpoint('GET', '/api/apps')"
|
||||||
|
class="flex items-center gap-2 px-4 py-2 bg-primary hover:brightness-110 rounded-lg text-white text-sm font-medium transition-all"
|
||||||
|
>
|
||||||
|
<span class="material-symbols-outlined text-sm"
|
||||||
|
>play_arrow</span
|
||||||
|
>
|
||||||
Probar endpoint
|
Probar endpoint
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Register App -->
|
<!-- Register App -->
|
||||||
<div class="mb-8 rounded-xl border border-[#283039] bg-[#161f2a] overflow-hidden">
|
<div
|
||||||
<div class="bg-[#1c2730] px-6 py-4 border-b border-[#283039]">
|
class="mb-8 rounded-xl border border-[#283039] bg-[#161f2a] overflow-hidden"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="bg-[#1c2730] px-6 py-4 border-b border-[#283039]"
|
||||||
|
>
|
||||||
<div class="flex items-center gap-3">
|
<div class="flex items-center gap-3">
|
||||||
<span class="px-2 py-1 rounded bg-blue-500/20 text-blue-400 text-xs font-bold font-mono">POST</span>
|
<span
|
||||||
<code class="text-white font-mono text-sm">/api/apps</code>
|
class="px-2 py-1 rounded bg-blue-500/20 text-blue-400 text-xs font-bold font-mono"
|
||||||
|
>POST</span
|
||||||
|
>
|
||||||
|
<code class="text-white font-mono text-sm"
|
||||||
|
>/api/apps</code
|
||||||
|
>
|
||||||
</div>
|
</div>
|
||||||
<p class="text-[#9dabb9] text-sm mt-2">Registrar una nueva aplicación</p>
|
<p class="text-[#9dabb9] text-sm mt-2">
|
||||||
|
Registrar una nueva aplicación
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="p-6 space-y-4">
|
<div class="p-6 space-y-4">
|
||||||
<div>
|
<div>
|
||||||
<p class="text-white font-semibold text-sm mb-2">Body (JSON)</p>
|
<p
|
||||||
<pre class="code-block bg-[#0a0f16] p-4 rounded-lg text-sm text-blue-400 overflow-x-auto">{
|
class="text-white font-semibold text-sm mb-2"
|
||||||
|
>
|
||||||
|
Body (JSON)
|
||||||
|
</p>
|
||||||
|
<pre
|
||||||
|
class="code-block bg-[#0a0f16] p-4 rounded-lg text-sm text-blue-400 overflow-x-auto"
|
||||||
|
>
|
||||||
|
{
|
||||||
"app_name": "mi-app",
|
"app_name": "mi-app",
|
||||||
"script_path": "/opt/apps/mi-app/index.js",
|
"script_path": "/opt/apps/mi-app/index.js",
|
||||||
"working_directory": "/opt/apps/mi-app",
|
"working_directory": "/opt/apps/mi-app",
|
||||||
@@ -262,11 +391,19 @@
|
|||||||
"restart_policy": "always",
|
"restart_policy": "always",
|
||||||
"app_type": "nodejs",
|
"app_type": "nodejs",
|
||||||
"description": "Mi aplicación Node.js"
|
"description": "Mi aplicación Node.js"
|
||||||
}</pre>
|
}</pre
|
||||||
|
>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<p class="text-white font-semibold text-sm mb-2">Respuesta exitosa (200)</p>
|
<p
|
||||||
<pre class="code-block bg-[#0a0f16] p-4 rounded-lg text-sm text-green-400 overflow-x-auto">{
|
class="text-white font-semibold text-sm mb-2"
|
||||||
|
>
|
||||||
|
Respuesta exitosa (200)
|
||||||
|
</p>
|
||||||
|
<pre
|
||||||
|
class="code-block bg-[#0a0f16] p-4 rounded-lg text-sm text-green-400 overflow-x-auto"
|
||||||
|
>
|
||||||
|
{
|
||||||
"success": true,
|
"success": true,
|
||||||
"data": {
|
"data": {
|
||||||
"app_name": "mi-app",
|
"app_name": "mi-app",
|
||||||
@@ -275,27 +412,48 @@
|
|||||||
"message": "Aplicación registrada exitosamente"
|
"message": "Aplicación registrada exitosamente"
|
||||||
},
|
},
|
||||||
"error": null
|
"error": null
|
||||||
}</pre>
|
}</pre
|
||||||
|
>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Delete App -->
|
<!-- Delete App -->
|
||||||
<div class="mb-8 rounded-xl border border-[#283039] bg-[#161f2a] overflow-hidden">
|
<div
|
||||||
<div class="bg-[#1c2730] px-6 py-4 border-b border-[#283039]">
|
class="mb-8 rounded-xl border border-[#283039] bg-[#161f2a] overflow-hidden"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="bg-[#1c2730] px-6 py-4 border-b border-[#283039]"
|
||||||
|
>
|
||||||
<div class="flex items-center gap-3">
|
<div class="flex items-center gap-3">
|
||||||
<span class="px-2 py-1 rounded bg-red-500/20 text-red-400 text-xs font-bold font-mono">DELETE</span>
|
<span
|
||||||
<code class="text-white font-mono text-sm">/api/apps/:name</code>
|
class="px-2 py-1 rounded bg-red-500/20 text-red-400 text-xs font-bold font-mono"
|
||||||
|
>DELETE</span
|
||||||
|
>
|
||||||
|
<code class="text-white font-mono text-sm"
|
||||||
|
>/api/apps/:name</code
|
||||||
|
>
|
||||||
</div>
|
</div>
|
||||||
<p class="text-[#9dabb9] text-sm mt-2">Eliminar una aplicación registrada</p>
|
<p class="text-[#9dabb9] text-sm mt-2">
|
||||||
|
Eliminar una aplicación registrada
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="p-6 space-y-4">
|
<div class="p-6 space-y-4">
|
||||||
<div>
|
<div>
|
||||||
<p class="text-white font-semibold text-sm mb-2">Parámetros</p>
|
<p
|
||||||
|
class="text-white font-semibold text-sm mb-2"
|
||||||
|
>
|
||||||
|
Parámetros
|
||||||
|
</p>
|
||||||
<ul class="space-y-2">
|
<ul class="space-y-2">
|
||||||
<li class="flex items-start gap-2">
|
<li class="flex items-start gap-2">
|
||||||
<code class="text-primary font-mono text-sm">name</code>
|
<code
|
||||||
<span class="text-[#9dabb9] text-sm">- Nombre de la aplicación</span>
|
class="text-primary font-mono text-sm"
|
||||||
|
>name</code
|
||||||
|
>
|
||||||
|
<span class="text-[#9dabb9] text-sm"
|
||||||
|
>- Nombre de la aplicación</span
|
||||||
|
>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
@@ -303,18 +461,36 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Get Status -->
|
<!-- Get Status -->
|
||||||
<div class="mb-8 rounded-xl border border-[#283039] bg-[#161f2a] overflow-hidden">
|
<div
|
||||||
<div class="bg-[#1c2730] px-6 py-4 border-b border-[#283039]">
|
class="mb-8 rounded-xl border border-[#283039] bg-[#161f2a] overflow-hidden"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="bg-[#1c2730] px-6 py-4 border-b border-[#283039]"
|
||||||
|
>
|
||||||
<div class="flex items-center gap-3">
|
<div class="flex items-center gap-3">
|
||||||
<span class="px-2 py-1 rounded bg-green-500/20 text-green-400 text-xs font-bold font-mono">GET</span>
|
<span
|
||||||
<code class="text-white font-mono text-sm">/api/apps/:name/status</code>
|
class="px-2 py-1 rounded bg-green-500/20 text-green-400 text-xs font-bold font-mono"
|
||||||
|
>GET</span
|
||||||
|
>
|
||||||
|
<code class="text-white font-mono text-sm"
|
||||||
|
>/api/apps/:name/status</code
|
||||||
|
>
|
||||||
</div>
|
</div>
|
||||||
<p class="text-[#9dabb9] text-sm mt-2">Obtener estado de una aplicación</p>
|
<p class="text-[#9dabb9] text-sm mt-2">
|
||||||
|
Obtener estado de una aplicación
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="p-6 space-y-4">
|
<div class="p-6 space-y-4">
|
||||||
<div>
|
<div>
|
||||||
<p class="text-white font-semibold text-sm mb-2">Respuesta exitosa (200)</p>
|
<p
|
||||||
<pre class="code-block bg-[#0a0f16] p-4 rounded-lg text-sm text-green-400 overflow-x-auto">{
|
class="text-white font-semibold text-sm mb-2"
|
||||||
|
>
|
||||||
|
Respuesta exitosa (200)
|
||||||
|
</p>
|
||||||
|
<pre
|
||||||
|
class="code-block bg-[#0a0f16] p-4 rounded-lg text-sm text-green-400 overflow-x-auto"
|
||||||
|
>
|
||||||
|
{
|
||||||
"success": true,
|
"success": true,
|
||||||
"data": {
|
"data": {
|
||||||
"name": "mi-app",
|
"name": "mi-app",
|
||||||
@@ -325,7 +501,8 @@
|
|||||||
"systemd_status": "active",
|
"systemd_status": "active",
|
||||||
"last_updated": "2026-01-13T12:34:56"
|
"last_updated": "2026-01-13T12:34:56"
|
||||||
}
|
}
|
||||||
}</pre>
|
}</pre
|
||||||
|
>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -333,23 +510,45 @@
|
|||||||
|
|
||||||
<!-- Scan -->
|
<!-- Scan -->
|
||||||
<section id="scan" class="mb-12">
|
<section id="scan" class="mb-12">
|
||||||
<h2 class="text-white text-2xl font-bold mb-6 flex items-center gap-2">
|
<h2
|
||||||
<span class="material-symbols-outlined text-primary">search</span>
|
class="text-white text-2xl font-bold mb-6 flex items-center gap-2"
|
||||||
|
>
|
||||||
|
<span class="material-symbols-outlined text-primary"
|
||||||
|
>search</span
|
||||||
|
>
|
||||||
Escaneo de Procesos
|
Escaneo de Procesos
|
||||||
</h2>
|
</h2>
|
||||||
|
|
||||||
<div class="mb-8 rounded-xl border border-[#283039] bg-[#161f2a] overflow-hidden">
|
<div
|
||||||
<div class="bg-[#1c2730] px-6 py-4 border-b border-[#283039]">
|
class="mb-8 rounded-xl border border-[#283039] bg-[#161f2a] overflow-hidden"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="bg-[#1c2730] px-6 py-4 border-b border-[#283039]"
|
||||||
|
>
|
||||||
<div class="flex items-center gap-3">
|
<div class="flex items-center gap-3">
|
||||||
<span class="px-2 py-1 rounded bg-green-500/20 text-green-400 text-xs font-bold font-mono">GET</span>
|
<span
|
||||||
<code class="text-white font-mono text-sm">/api/scan</code>
|
class="px-2 py-1 rounded bg-green-500/20 text-green-400 text-xs font-bold font-mono"
|
||||||
|
>GET</span
|
||||||
|
>
|
||||||
|
<code class="text-white font-mono text-sm"
|
||||||
|
>/api/scan</code
|
||||||
|
>
|
||||||
</div>
|
</div>
|
||||||
<p class="text-[#9dabb9] text-sm mt-2">Escanear procesos Node.js y Python en ejecución</p>
|
<p class="text-[#9dabb9] text-sm mt-2">
|
||||||
|
Escanear procesos Node.js y Python en ejecución
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="p-6 space-y-4">
|
<div class="p-6 space-y-4">
|
||||||
<div>
|
<div>
|
||||||
<p class="text-white font-semibold text-sm mb-2">Respuesta exitosa (200)</p>
|
<p
|
||||||
<pre class="code-block bg-[#0a0f16] p-4 rounded-lg text-sm text-green-400 overflow-x-auto">{
|
class="text-white font-semibold text-sm mb-2"
|
||||||
|
>
|
||||||
|
Respuesta exitosa (200)
|
||||||
|
</p>
|
||||||
|
<pre
|
||||||
|
class="code-block bg-[#0a0f16] p-4 rounded-lg text-sm text-green-400 overflow-x-auto"
|
||||||
|
>
|
||||||
|
{
|
||||||
"success": true,
|
"success": true,
|
||||||
"data": {
|
"data": {
|
||||||
"processes": [
|
"processes": [
|
||||||
@@ -364,10 +563,16 @@
|
|||||||
],
|
],
|
||||||
"total": 1
|
"total": 1
|
||||||
}
|
}
|
||||||
}</pre>
|
}</pre
|
||||||
|
>
|
||||||
</div>
|
</div>
|
||||||
<button onclick="tryEndpoint('GET', '/api/scan')" class="flex items-center gap-2 px-4 py-2 bg-primary hover:brightness-110 rounded-lg text-white text-sm font-medium transition-all">
|
<button
|
||||||
<span class="material-symbols-outlined text-sm">play_arrow</span>
|
onclick="tryEndpoint('GET', '/api/scan')"
|
||||||
|
class="flex items-center gap-2 px-4 py-2 bg-primary hover:brightness-110 rounded-lg text-white text-sm font-medium transition-all"
|
||||||
|
>
|
||||||
|
<span class="material-symbols-outlined text-sm"
|
||||||
|
>play_arrow</span
|
||||||
|
>
|
||||||
Probar endpoint
|
Probar endpoint
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
@@ -376,50 +581,97 @@
|
|||||||
|
|
||||||
<!-- Lifecycle -->
|
<!-- Lifecycle -->
|
||||||
<section id="lifecycle" class="mb-12">
|
<section id="lifecycle" class="mb-12">
|
||||||
<h2 class="text-white text-2xl font-bold mb-6 flex items-center gap-2">
|
<h2
|
||||||
<span class="material-symbols-outlined text-primary">settings_power</span>
|
class="text-white text-2xl font-bold mb-6 flex items-center gap-2"
|
||||||
|
>
|
||||||
|
<span class="material-symbols-outlined text-primary"
|
||||||
|
>settings_power</span
|
||||||
|
>
|
||||||
Ciclo de Vida
|
Ciclo de Vida
|
||||||
</h2>
|
</h2>
|
||||||
|
|
||||||
<!-- Start -->
|
<!-- Start -->
|
||||||
<div class="mb-8 rounded-xl border border-[#283039] bg-[#161f2a] overflow-hidden">
|
<div
|
||||||
<div class="bg-[#1c2730] px-6 py-4 border-b border-[#283039]">
|
class="mb-8 rounded-xl border border-[#283039] bg-[#161f2a] overflow-hidden"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="bg-[#1c2730] px-6 py-4 border-b border-[#283039]"
|
||||||
|
>
|
||||||
<div class="flex items-center gap-3">
|
<div class="flex items-center gap-3">
|
||||||
<span class="px-2 py-1 rounded bg-blue-500/20 text-blue-400 text-xs font-bold font-mono">POST</span>
|
<span
|
||||||
<code class="text-white font-mono text-sm">/api/apps/:name/start</code>
|
class="px-2 py-1 rounded bg-blue-500/20 text-blue-400 text-xs font-bold font-mono"
|
||||||
|
>POST</span
|
||||||
|
>
|
||||||
|
<code class="text-white font-mono text-sm"
|
||||||
|
>/api/apps/:name/start</code
|
||||||
|
>
|
||||||
</div>
|
</div>
|
||||||
<p class="text-[#9dabb9] text-sm mt-2">Iniciar una aplicación</p>
|
<p class="text-[#9dabb9] text-sm mt-2">
|
||||||
|
Iniciar una aplicación
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Stop -->
|
<!-- Stop -->
|
||||||
<div class="mb-8 rounded-xl border border-[#283039] bg-[#161f2a] overflow-hidden">
|
<div
|
||||||
<div class="bg-[#1c2730] px-6 py-4 border-b border-[#283039]">
|
class="mb-8 rounded-xl border border-[#283039] bg-[#161f2a] overflow-hidden"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="bg-[#1c2730] px-6 py-4 border-b border-[#283039]"
|
||||||
|
>
|
||||||
<div class="flex items-center gap-3">
|
<div class="flex items-center gap-3">
|
||||||
<span class="px-2 py-1 rounded bg-blue-500/20 text-blue-400 text-xs font-bold font-mono">POST</span>
|
<span
|
||||||
<code class="text-white font-mono text-sm">/api/apps/:name/stop</code>
|
class="px-2 py-1 rounded bg-blue-500/20 text-blue-400 text-xs font-bold font-mono"
|
||||||
|
>POST</span
|
||||||
|
>
|
||||||
|
<code class="text-white font-mono text-sm"
|
||||||
|
>/api/apps/:name/stop</code
|
||||||
|
>
|
||||||
</div>
|
</div>
|
||||||
<p class="text-[#9dabb9] text-sm mt-2">Detener una aplicación</p>
|
<p class="text-[#9dabb9] text-sm mt-2">
|
||||||
|
Detener una aplicación
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Restart -->
|
<!-- Restart -->
|
||||||
<div class="mb-8 rounded-xl border border-[#283039] bg-[#161f2a] overflow-hidden">
|
<div
|
||||||
<div class="bg-[#1c2730] px-6 py-4 border-b border-[#283039]">
|
class="mb-8 rounded-xl border border-[#283039] bg-[#161f2a] overflow-hidden"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="bg-[#1c2730] px-6 py-4 border-b border-[#283039]"
|
||||||
|
>
|
||||||
<div class="flex items-center gap-3">
|
<div class="flex items-center gap-3">
|
||||||
<span class="px-2 py-1 rounded bg-blue-500/20 text-blue-400 text-xs font-bold font-mono">POST</span>
|
<span
|
||||||
<code class="text-white font-mono text-sm">/api/apps/:name/restart</code>
|
class="px-2 py-1 rounded bg-blue-500/20 text-blue-400 text-xs font-bold font-mono"
|
||||||
|
>POST</span
|
||||||
|
>
|
||||||
|
<code class="text-white font-mono text-sm"
|
||||||
|
>/api/apps/:name/restart</code
|
||||||
|
>
|
||||||
</div>
|
</div>
|
||||||
<p class="text-[#9dabb9] text-sm mt-2">Reiniciar una aplicación</p>
|
<p class="text-[#9dabb9] text-sm mt-2">
|
||||||
|
Reiniciar una aplicación
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="rounded-xl border border-yellow-500/30 bg-yellow-500/10 p-4">
|
<div
|
||||||
|
class="rounded-xl border border-yellow-500/30 bg-yellow-500/10 p-4"
|
||||||
|
>
|
||||||
<div class="flex items-start gap-3">
|
<div class="flex items-start gap-3">
|
||||||
<span class="material-symbols-outlined text-yellow-400">schedule</span>
|
<span
|
||||||
|
class="material-symbols-outlined text-yellow-400"
|
||||||
|
>schedule</span
|
||||||
|
>
|
||||||
<div>
|
<div>
|
||||||
<p class="text-yellow-400 font-semibold">Rate Limiting</p>
|
<p class="text-yellow-400 font-semibold">
|
||||||
<p class="text-[#9dabb9] text-sm">Las operaciones están limitadas a 1 por segundo por aplicación.</p>
|
Rate Limiting
|
||||||
|
</p>
|
||||||
|
<p class="text-[#9dabb9] text-sm">
|
||||||
|
Las operaciones están limitadas a 1 por
|
||||||
|
segundo por aplicación.
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -427,23 +679,45 @@
|
|||||||
|
|
||||||
<!-- WebSocket -->
|
<!-- WebSocket -->
|
||||||
<section id="websocket" class="mb-12">
|
<section id="websocket" class="mb-12">
|
||||||
<h2 class="text-white text-2xl font-bold mb-6 flex items-center gap-2">
|
<h2
|
||||||
<span class="material-symbols-outlined text-primary">cable</span>
|
class="text-white text-2xl font-bold mb-6 flex items-center gap-2"
|
||||||
|
>
|
||||||
|
<span class="material-symbols-outlined text-primary"
|
||||||
|
>cable</span
|
||||||
|
>
|
||||||
WebSocket (Logs en tiempo real)
|
WebSocket (Logs en tiempo real)
|
||||||
</h2>
|
</h2>
|
||||||
|
|
||||||
<div class="mb-8 rounded-xl border border-[#283039] bg-[#161f2a] overflow-hidden">
|
<div
|
||||||
<div class="bg-[#1c2730] px-6 py-4 border-b border-[#283039]">
|
class="mb-8 rounded-xl border border-[#283039] bg-[#161f2a] overflow-hidden"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="bg-[#1c2730] px-6 py-4 border-b border-[#283039]"
|
||||||
|
>
|
||||||
<div class="flex items-center gap-3">
|
<div class="flex items-center gap-3">
|
||||||
<span class="px-2 py-1 rounded bg-purple-500/20 text-purple-400 text-xs font-bold font-mono">WS</span>
|
<span
|
||||||
<code class="text-white font-mono text-sm">ws://localhost:8080/api/apps/:name/logs</code>
|
class="px-2 py-1 rounded bg-purple-500/20 text-purple-400 text-xs font-bold font-mono"
|
||||||
|
>WS</span
|
||||||
|
>
|
||||||
|
<code class="text-white font-mono text-sm"
|
||||||
|
>ws://localhost:8080/api/apps/:name/logs</code
|
||||||
|
>
|
||||||
</div>
|
</div>
|
||||||
<p class="text-[#9dabb9] text-sm mt-2">Stream de logs en tiempo real desde journalctl</p>
|
<p class="text-[#9dabb9] text-sm mt-2">
|
||||||
|
Stream de logs en tiempo real desde journalctl
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="p-6 space-y-4">
|
<div class="p-6 space-y-4">
|
||||||
<div>
|
<div>
|
||||||
<p class="text-white font-semibold text-sm mb-2">Ejemplo JavaScript</p>
|
<p
|
||||||
<pre class="code-block bg-[#0a0f16] p-4 rounded-lg text-sm text-purple-400 overflow-x-auto">const ws = new WebSocket('ws://localhost:8080/api/apps/mi-app/logs');
|
class="text-white font-semibold text-sm mb-2"
|
||||||
|
>
|
||||||
|
Ejemplo JavaScript
|
||||||
|
</p>
|
||||||
|
<pre
|
||||||
|
class="code-block bg-[#0a0f16] p-4 rounded-lg text-sm text-purple-400 overflow-x-auto"
|
||||||
|
>
|
||||||
|
const ws = new WebSocket('ws://localhost:8080/api/apps/mi-app/logs');
|
||||||
|
|
||||||
ws.onopen = () => {
|
ws.onopen = () => {
|
||||||
console.log('Conectado a logs');
|
console.log('Conectado a logs');
|
||||||
@@ -460,18 +734,35 @@ ws.onerror = (error) => {
|
|||||||
|
|
||||||
ws.onclose = () => {
|
ws.onclose = () => {
|
||||||
console.log('Desconectado');
|
console.log('Desconectado');
|
||||||
};</pre>
|
};</pre
|
||||||
|
>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<p class="text-white font-semibold text-sm mb-2">Límites</p>
|
<p
|
||||||
|
class="text-white font-semibold text-sm mb-2"
|
||||||
|
>
|
||||||
|
Límites
|
||||||
|
</p>
|
||||||
<ul class="space-y-2">
|
<ul class="space-y-2">
|
||||||
<li class="flex items-start gap-2">
|
<li class="flex items-start gap-2">
|
||||||
<span class="material-symbols-outlined text-primary text-sm">check</span>
|
<span
|
||||||
<span class="text-[#9dabb9] text-sm">Máximo 5 conexiones concurrentes por aplicación</span>
|
class="material-symbols-outlined text-primary text-sm"
|
||||||
|
>check</span
|
||||||
|
>
|
||||||
|
<span class="text-[#9dabb9] text-sm"
|
||||||
|
>Máximo 5 conexiones concurrentes
|
||||||
|
por aplicación</span
|
||||||
|
>
|
||||||
</li>
|
</li>
|
||||||
<li class="flex items-start gap-2">
|
<li class="flex items-start gap-2">
|
||||||
<span class="material-symbols-outlined text-primary text-sm">check</span>
|
<span
|
||||||
<span class="text-[#9dabb9] text-sm">Formato JSON desde systemd journalctl</span>
|
class="material-symbols-outlined text-primary text-sm"
|
||||||
|
>check</span
|
||||||
|
>
|
||||||
|
<span class="text-[#9dabb9] text-sm"
|
||||||
|
>Formato JSON desde systemd
|
||||||
|
journalctl</span
|
||||||
|
>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
@@ -481,52 +772,98 @@ ws.onclose = () => {
|
|||||||
|
|
||||||
<!-- Error Codes -->
|
<!-- Error Codes -->
|
||||||
<section id="errors" class="mb-12">
|
<section id="errors" class="mb-12">
|
||||||
<h2 class="text-white text-2xl font-bold mb-6 flex items-center gap-2">
|
<h2
|
||||||
<span class="material-symbols-outlined text-primary">error</span>
|
class="text-white text-2xl font-bold mb-6 flex items-center gap-2"
|
||||||
|
>
|
||||||
|
<span class="material-symbols-outlined text-primary"
|
||||||
|
>error</span
|
||||||
|
>
|
||||||
Códigos de Error
|
Códigos de Error
|
||||||
</h2>
|
</h2>
|
||||||
|
|
||||||
<div class="space-y-4">
|
<div class="space-y-4">
|
||||||
<div class="rounded-xl border border-[#283039] bg-[#161f2a] p-4">
|
<div
|
||||||
|
class="rounded-xl border border-[#283039] bg-[#161f2a] p-4"
|
||||||
|
>
|
||||||
<div class="flex items-center gap-3 mb-2">
|
<div class="flex items-center gap-3 mb-2">
|
||||||
<span class="px-2 py-1 rounded bg-red-500/20 text-red-400 text-xs font-bold font-mono">400</span>
|
<span
|
||||||
<p class="text-white font-semibold">Bad Request</p>
|
class="px-2 py-1 rounded bg-red-500/20 text-red-400 text-xs font-bold font-mono"
|
||||||
|
>400</span
|
||||||
|
>
|
||||||
|
<p class="text-white font-semibold">
|
||||||
|
Bad Request
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<p class="text-[#9dabb9] text-sm">Datos de entrada inválidos o faltantes</p>
|
<p class="text-[#9dabb9] text-sm">
|
||||||
|
Datos de entrada inválidos o faltantes
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="rounded-xl border border-[#283039] bg-[#161f2a] p-4">
|
<div
|
||||||
|
class="rounded-xl border border-[#283039] bg-[#161f2a] p-4"
|
||||||
|
>
|
||||||
<div class="flex items-center gap-3 mb-2">
|
<div class="flex items-center gap-3 mb-2">
|
||||||
<span class="px-2 py-1 rounded bg-red-500/20 text-red-400 text-xs font-bold font-mono">404</span>
|
<span
|
||||||
<p class="text-white font-semibold">Not Found</p>
|
class="px-2 py-1 rounded bg-red-500/20 text-red-400 text-xs font-bold font-mono"
|
||||||
|
>404</span
|
||||||
|
>
|
||||||
|
<p class="text-white font-semibold">
|
||||||
|
Not Found
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<p class="text-[#9dabb9] text-sm">Aplicación no encontrada</p>
|
<p class="text-[#9dabb9] text-sm">
|
||||||
|
Aplicación no encontrada
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="rounded-xl border border-[#283039] bg-[#161f2a] p-4">
|
<div
|
||||||
|
class="rounded-xl border border-[#283039] bg-[#161f2a] p-4"
|
||||||
|
>
|
||||||
<div class="flex items-center gap-3 mb-2">
|
<div class="flex items-center gap-3 mb-2">
|
||||||
<span class="px-2 py-1 rounded bg-red-500/20 text-red-400 text-xs font-bold font-mono">429</span>
|
<span
|
||||||
<p class="text-white font-semibold">Too Many Requests</p>
|
class="px-2 py-1 rounded bg-red-500/20 text-red-400 text-xs font-bold font-mono"
|
||||||
|
>429</span
|
||||||
|
>
|
||||||
|
<p class="text-white font-semibold">
|
||||||
|
Too Many Requests
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<p class="text-[#9dabb9] text-sm">Rate limit excedido (1 operación/segundo)</p>
|
<p class="text-[#9dabb9] text-sm">
|
||||||
|
Rate limit excedido (1 operación/segundo)
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="rounded-xl border border-[#283039] bg-[#161f2a] p-4">
|
<div
|
||||||
|
class="rounded-xl border border-[#283039] bg-[#161f2a] p-4"
|
||||||
|
>
|
||||||
<div class="flex items-center gap-3 mb-2">
|
<div class="flex items-center gap-3 mb-2">
|
||||||
<span class="px-2 py-1 rounded bg-red-500/20 text-red-400 text-xs font-bold font-mono">500</span>
|
<span
|
||||||
<p class="text-white font-semibold">Internal Server Error</p>
|
class="px-2 py-1 rounded bg-red-500/20 text-red-400 text-xs font-bold font-mono"
|
||||||
|
>500</span
|
||||||
|
>
|
||||||
|
<p class="text-white font-semibold">
|
||||||
|
Internal Server Error
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<p class="text-[#9dabb9] text-sm">Error interno del servidor</p>
|
<p class="text-[#9dabb9] text-sm">
|
||||||
|
Error interno del servidor
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="mt-6">
|
<div class="mt-6">
|
||||||
<p class="text-white font-semibold text-sm mb-2">Estructura de error</p>
|
<p class="text-white font-semibold text-sm mb-2">
|
||||||
<pre class="code-block bg-[#0a0f16] p-4 rounded-lg text-sm text-red-400 overflow-x-auto">{
|
Estructura de error
|
||||||
|
</p>
|
||||||
|
<pre
|
||||||
|
class="code-block bg-[#0a0f16] p-4 rounded-lg text-sm text-red-400 overflow-x-auto"
|
||||||
|
>
|
||||||
|
{
|
||||||
"success": false,
|
"success": false,
|
||||||
"data": null,
|
"data": null,
|
||||||
"error": "Descripción del error"
|
"error": "Descripción del error"
|
||||||
}</pre>
|
}</pre
|
||||||
|
>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
</main>
|
</main>
|
||||||
@@ -534,14 +871,18 @@ ws.onclose = () => {
|
|||||||
|
|
||||||
<script>
|
<script>
|
||||||
async function tryEndpoint(method, path) {
|
async function tryEndpoint(method, path) {
|
||||||
const resultDiv = event.target.parentElement.querySelector('.result') ||
|
const resultDiv =
|
||||||
event.target.parentElement.appendChild(document.createElement('div'));
|
event.target.parentElement.querySelector(".result") ||
|
||||||
resultDiv.className = 'result mt-4 code-block bg-[#0a0f16] p-4 rounded-lg text-sm overflow-x-auto';
|
event.target.parentElement.appendChild(
|
||||||
resultDiv.textContent = 'Ejecutando...';
|
document.createElement("div"),
|
||||||
|
);
|
||||||
|
resultDiv.className =
|
||||||
|
"result mt-4 code-block bg-[#0a0f16] p-4 rounded-lg text-sm overflow-x-auto";
|
||||||
|
resultDiv.textContent = "Ejecutando...";
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const response = await fetch(`http://localhost:8080${path}`, {
|
const response = await fetch(path, {
|
||||||
method: method
|
method: method,
|
||||||
});
|
});
|
||||||
const data = await response.json();
|
const data = await response.json();
|
||||||
resultDiv.innerHTML = `<pre class="text-green-400">${JSON.stringify(data, null, 2)}</pre>`;
|
resultDiv.innerHTML = `<pre class="text-green-400">${JSON.stringify(data, null, 2)}</pre>`;
|
||||||
@@ -551,12 +892,17 @@ ws.onclose = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Smooth scroll for anchor links
|
// Smooth scroll for anchor links
|
||||||
document.querySelectorAll('a[href^="#"]').forEach(anchor => {
|
document.querySelectorAll('a[href^="#"]').forEach((anchor) => {
|
||||||
anchor.addEventListener('click', function (e) {
|
anchor.addEventListener("click", function (e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
const target = document.querySelector(this.getAttribute('href'));
|
const target = document.querySelector(
|
||||||
|
this.getAttribute("href"),
|
||||||
|
);
|
||||||
if (target) {
|
if (target) {
|
||||||
target.scrollIntoView({ behavior: 'smooth', block: 'start' });
|
target.scrollIntoView({
|
||||||
|
behavior: "smooth",
|
||||||
|
block: "start",
|
||||||
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
764
web/blog.html
Normal file
764
web/blog.html
Normal file
@@ -0,0 +1,764 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html class="dark" lang="es" dir="ltr">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<meta content="width=device-width, initial-scale=1.0" name="viewport" />
|
||||||
|
<title>
|
||||||
|
SIAX Monitor: Sistema de Monitoreo de Aplicaciones en Rust - Blog
|
||||||
|
Telcotronics
|
||||||
|
</title>
|
||||||
|
<link rel="icon" type="image/svg+xml" href="/static/icon/favicon.svg" />
|
||||||
|
<script src="https://cdn.tailwindcss.com?plugins=forms,container-queries"></script>
|
||||||
|
<link
|
||||||
|
href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800;900&display=swap"
|
||||||
|
rel="stylesheet"
|
||||||
|
/>
|
||||||
|
<link
|
||||||
|
href="https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;500;600&display=swap"
|
||||||
|
rel="stylesheet"
|
||||||
|
/>
|
||||||
|
<link
|
||||||
|
href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:wght,FILL@100..700,0..1&display=swap"
|
||||||
|
rel="stylesheet"
|
||||||
|
/>
|
||||||
|
<script>
|
||||||
|
tailwind.config = {
|
||||||
|
darkMode: "class",
|
||||||
|
theme: {
|
||||||
|
extend: {
|
||||||
|
colors: {
|
||||||
|
primary: "#137fec",
|
||||||
|
"background-light": "#f6f7f8",
|
||||||
|
"background-dark": "#101922",
|
||||||
|
},
|
||||||
|
fontFamily: {
|
||||||
|
display: ["Inter", "sans-serif"],
|
||||||
|
mono: ["JetBrains Mono", "monospace"],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
<style>
|
||||||
|
body {
|
||||||
|
font-family: "Inter", sans-serif;
|
||||||
|
}
|
||||||
|
.material-symbols-outlined {
|
||||||
|
font-variation-settings:
|
||||||
|
"FILL" 0,
|
||||||
|
"wght" 400,
|
||||||
|
"GRAD" 0,
|
||||||
|
"opsz" 24;
|
||||||
|
}
|
||||||
|
.blog-content h2 {
|
||||||
|
font-size: 2rem;
|
||||||
|
font-weight: 800;
|
||||||
|
margin-top: 3rem;
|
||||||
|
margin-bottom: 1.5rem;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
.blog-content h3 {
|
||||||
|
font-size: 1.5rem;
|
||||||
|
font-weight: 700;
|
||||||
|
margin-top: 2rem;
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
color: #e2e8f0;
|
||||||
|
}
|
||||||
|
.blog-content p {
|
||||||
|
margin-bottom: 1.25rem;
|
||||||
|
line-height: 1.75;
|
||||||
|
color: #cbd5e1;
|
||||||
|
}
|
||||||
|
.blog-content ul,
|
||||||
|
.blog-content ol {
|
||||||
|
margin-bottom: 1.5rem;
|
||||||
|
padding-left: 1.5rem;
|
||||||
|
}
|
||||||
|
.blog-content li {
|
||||||
|
margin-bottom: 0.75rem;
|
||||||
|
line-height: 1.75;
|
||||||
|
color: #cbd5e1;
|
||||||
|
}
|
||||||
|
.blog-content ul li {
|
||||||
|
list-style-type: disc;
|
||||||
|
}
|
||||||
|
.blog-content ol li {
|
||||||
|
list-style-type: decimal;
|
||||||
|
}
|
||||||
|
.blog-content strong {
|
||||||
|
color: white;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
.blog-content code {
|
||||||
|
background: #1e293b;
|
||||||
|
padding: 0.2rem 0.4rem;
|
||||||
|
border-radius: 0.25rem;
|
||||||
|
font-size: 0.9em;
|
||||||
|
color: #60a5fa;
|
||||||
|
}
|
||||||
|
.blog-content pre {
|
||||||
|
background: #0f172a;
|
||||||
|
padding: 1.5rem;
|
||||||
|
border-radius: 0.5rem;
|
||||||
|
overflow-x: auto;
|
||||||
|
margin-bottom: 1.5rem;
|
||||||
|
border: 1px solid #334155;
|
||||||
|
}
|
||||||
|
.blog-content pre code {
|
||||||
|
background: none;
|
||||||
|
padding: 0;
|
||||||
|
color: #94a3b8;
|
||||||
|
}
|
||||||
|
.blog-content blockquote {
|
||||||
|
border-left: 4px solid #137fec;
|
||||||
|
padding-left: 1.5rem;
|
||||||
|
margin: 1.5rem 0;
|
||||||
|
font-style: italic;
|
||||||
|
color: #94a3b8;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body class="bg-background-dark text-slate-300">
|
||||||
|
<!-- Header -->
|
||||||
|
<header class="border-b border-slate-800 bg-[#0a0f16]">
|
||||||
|
<div class="max-w-4xl mx-auto px-4 sm:px-6 lg:px-8 py-6">
|
||||||
|
<div class="flex items-center justify-between">
|
||||||
|
<a
|
||||||
|
href="/"
|
||||||
|
class="text-2xl font-black text-white hover:text-primary transition-colors"
|
||||||
|
>
|
||||||
|
SIAX Monitor
|
||||||
|
</a>
|
||||||
|
<nav class="flex items-center gap-6">
|
||||||
|
<a
|
||||||
|
href="/"
|
||||||
|
class="text-slate-400 hover:text-white transition-colors"
|
||||||
|
>Dashboard</a
|
||||||
|
>
|
||||||
|
<a
|
||||||
|
href="/api-docs"
|
||||||
|
class="text-slate-400 hover:text-white transition-colors"
|
||||||
|
>API</a
|
||||||
|
>
|
||||||
|
<a
|
||||||
|
href="https://git.telcotronics.net/pablinux/SIAX-MONITOR"
|
||||||
|
target="_blank"
|
||||||
|
class="text-slate-400 hover:text-primary transition-colors flex items-center gap-1"
|
||||||
|
>
|
||||||
|
<span class="material-symbols-outlined text-sm"
|
||||||
|
>code</span
|
||||||
|
>
|
||||||
|
Git
|
||||||
|
</a>
|
||||||
|
</nav>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<!-- Article Container -->
|
||||||
|
<article class="max-w-4xl mx-auto px-4 sm:px-6 lg:px-8 py-12">
|
||||||
|
<!-- Article Header -->
|
||||||
|
<header class="mb-12">
|
||||||
|
<!-- Categories -->
|
||||||
|
<div class="flex flex-wrap gap-2 mb-6">
|
||||||
|
<span
|
||||||
|
class="inline-flex items-center gap-1 px-3 py-1 rounded-full bg-primary/20 text-primary text-sm font-semibold"
|
||||||
|
>
|
||||||
|
<span class="material-symbols-outlined text-xs"
|
||||||
|
>folder</span
|
||||||
|
>
|
||||||
|
DevOps
|
||||||
|
</span>
|
||||||
|
<span
|
||||||
|
class="inline-flex items-center gap-1 px-3 py-1 rounded-full bg-green-500/20 text-green-400 text-sm font-semibold"
|
||||||
|
>
|
||||||
|
<span class="material-symbols-outlined text-xs"
|
||||||
|
>code</span
|
||||||
|
>
|
||||||
|
Rust
|
||||||
|
</span>
|
||||||
|
<span
|
||||||
|
class="inline-flex items-center gap-1 px-3 py-1 rounded-full bg-blue-500/20 text-blue-400 text-sm font-semibold"
|
||||||
|
>
|
||||||
|
<span class="material-symbols-outlined text-xs"
|
||||||
|
>monitoring</span
|
||||||
|
>
|
||||||
|
Monitoring
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Title -->
|
||||||
|
<h1
|
||||||
|
class="text-4xl md:text-5xl font-black text-white mb-6 leading-tight"
|
||||||
|
>
|
||||||
|
SIAX Monitor: Sistema de Monitoreo y Gestión de Aplicaciones
|
||||||
|
Node.js y Python
|
||||||
|
</h1>
|
||||||
|
|
||||||
|
<!-- Meta info -->
|
||||||
|
<div
|
||||||
|
class="flex flex-wrap items-center gap-4 text-slate-400 text-sm"
|
||||||
|
>
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<div
|
||||||
|
class="w-10 h-10 rounded-full bg-primary/20 flex items-center justify-center"
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
class="material-symbols-outlined text-primary text-lg"
|
||||||
|
>person</span
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
<span
|
||||||
|
>Por
|
||||||
|
<strong class="text-white">pablinux</strong></span
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center gap-1">
|
||||||
|
<span class="material-symbols-outlined text-sm"
|
||||||
|
>calendar_today</span
|
||||||
|
>
|
||||||
|
<time datetime="2026-01-13">13 de enero, 2026</time>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center gap-1">
|
||||||
|
<span class="material-symbols-outlined text-sm"
|
||||||
|
>schedule</span
|
||||||
|
>
|
||||||
|
<span>10 min de lectura</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<!-- Featured Image -->
|
||||||
|
<div
|
||||||
|
class="mb-12 rounded-2xl overflow-hidden border border-slate-800 bg-gradient-to-br from-primary/20 via-background-dark to-background-dark p-12"
|
||||||
|
>
|
||||||
|
<div class="flex items-center justify-center">
|
||||||
|
<div class="text-center">
|
||||||
|
<div
|
||||||
|
class="inline-flex items-center justify-center w-24 h-24 rounded-2xl bg-primary/20 border-2 border-primary/30 mb-4"
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
class="material-symbols-outlined text-primary"
|
||||||
|
style="font-size: 3rem"
|
||||||
|
>monitoring</span
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
<p class="text-slate-400 text-lg">
|
||||||
|
Monitoreo inteligente con Rust + Systemd
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Article Content -->
|
||||||
|
<div class="blog-content">
|
||||||
|
<p class="text-xl text-slate-300 mb-8 leading-relaxed">
|
||||||
|
En el mundo del desarrollo moderno, gestionar múltiples
|
||||||
|
aplicaciones Node.js y Python en servidores de producción
|
||||||
|
puede convertirse rápidamente en un dolor de cabeza. SIAX
|
||||||
|
Monitor nace como una solución elegante, ligera y poderosa
|
||||||
|
para este problema, aprovechando la velocidad y seguridad de
|
||||||
|
Rust.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<h2>¿Qué es SIAX Monitor?</h2>
|
||||||
|
<p>
|
||||||
|
SIAX Monitor es un
|
||||||
|
<strong>agente de monitoreo inteligente</strong> diseñado
|
||||||
|
específicamente para entornos Linux con systemd. A
|
||||||
|
diferencia de soluciones enterprise como Prometheus o
|
||||||
|
Grafana que pueden resultar excesivas para equipos pequeños,
|
||||||
|
SIAX Monitor ofrece exactamente lo que necesitas sin
|
||||||
|
complicaciones innecesarias.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
Desarrollado completamente en Rust, combina alto rendimiento
|
||||||
|
con un consumo mínimo de recursos. El proyecto utiliza
|
||||||
|
tecnologías modernas como Tokio para async runtime, Axum
|
||||||
|
para el servidor web, y se integra nativamente con systemd y
|
||||||
|
journalctl.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<h2>Características Principales</h2>
|
||||||
|
|
||||||
|
<h3>🔍 Escaneo Automático de Procesos</h3>
|
||||||
|
<p>
|
||||||
|
El sistema detecta automáticamente procesos Node.js y Python
|
||||||
|
en ejecución, recopilando información detallada como:
|
||||||
|
</p>
|
||||||
|
<ul>
|
||||||
|
<li>PID y nombre del proceso</li>
|
||||||
|
<li>Usuario propietario</li>
|
||||||
|
<li>Uso de CPU en tiempo real</li>
|
||||||
|
<li>Consumo de memoria RAM</li>
|
||||||
|
<li>Comando completo de ejecución</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<h3>⚙️ Gestión de Ciclo de Vida</h3>
|
||||||
|
<p>
|
||||||
|
Control total sobre tus aplicaciones mediante la API REST:
|
||||||
|
</p>
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
<code>POST /api/apps</code> - Registrar nueva aplicación
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<code>POST /api/apps/:name/start</code> - Iniciar
|
||||||
|
servicio
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<code>POST /api/apps/:name/stop</code> - Detener
|
||||||
|
servicio
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<code>POST /api/apps/:name/restart</code> - Reiniciar
|
||||||
|
servicio
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<code>GET /api/apps/:name/status</code> - Consultar
|
||||||
|
estado
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
<p>
|
||||||
|
El sistema incluye <strong>rate limiting</strong> (1
|
||||||
|
operación/segundo por app) para evitar abusos y validaciones
|
||||||
|
de seguridad en todos los endpoints.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<h3>📝 Logs en Tiempo Real</h3>
|
||||||
|
<p>
|
||||||
|
Uno de los puntos más fuertes es el streaming de logs vía
|
||||||
|
WebSocket. Conectándote al endpoint
|
||||||
|
<code>ws://localhost:8080/api/apps/:name/logs</code>,
|
||||||
|
recibes logs en tiempo real desde journalctl sin necesidad
|
||||||
|
de SSH al servidor.
|
||||||
|
</p>
|
||||||
|
<p>La interfaz web incluye un visor tipo terminal con:</p>
|
||||||
|
<ul>
|
||||||
|
<li>Auto-scroll inteligente</li>
|
||||||
|
<li>Colores para niveles de log (ERROR, WARN, INFO)</li>
|
||||||
|
<li>Timestamps formateados</li>
|
||||||
|
<li>Botón para pausar/reanudar</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<h3>🛡️ Seguridad y Validaciones</h3>
|
||||||
|
<p>SIAX Monitor toma la seguridad en serio:</p>
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
Validación estricta de paths de trabajo (previene
|
||||||
|
directory traversal)
|
||||||
|
</li>
|
||||||
|
<li>Lista blanca de usuarios permitidos</li>
|
||||||
|
<li>
|
||||||
|
Configuración automatizada de sudoers para systemctl
|
||||||
|
</li>
|
||||||
|
<li>Hardening de servicios systemd generados</li>
|
||||||
|
<li>Rate limiting en operaciones críticas</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<h3>🎨 Dashboard Moderno</h3>
|
||||||
|
<p>
|
||||||
|
La interfaz web está construida con
|
||||||
|
<strong>Tailwind CSS</strong> en tema oscuro (#101922 de
|
||||||
|
fondo, #137fec como color primario). Incluye:
|
||||||
|
</p>
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
<strong>/</strong> - Dashboard con estadísticas y lista
|
||||||
|
de apps
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<strong>/scan</strong> - Escaneo de procesos activos
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<strong>/select</strong> - Selección de procesos para
|
||||||
|
registrar
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<strong>/register</strong> - Formulario de registro
|
||||||
|
manual
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<strong>/logs</strong> - Visor de logs en tiempo real
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<strong>/api-docs</strong> - Documentación completa de
|
||||||
|
la API
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<h2>¿Cómo Funciona?</h2>
|
||||||
|
|
||||||
|
<h3>Arquitectura Multi-Threaded</h3>
|
||||||
|
<p>
|
||||||
|
SIAX Monitor utiliza una arquitectura basada en tres
|
||||||
|
componentes principales:
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p><strong>1. Monitor en Background</strong></p>
|
||||||
|
<p>Un thread dedicado ejecuta cada 60 segundos para:</p>
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
Recopilar métricas de CPU y RAM usando
|
||||||
|
<code>sysinfo</code>
|
||||||
|
</li>
|
||||||
|
<li>Reconciliar estados entre sysinfo y systemd</li>
|
||||||
|
<li>Reportar al cloud API de SIAX (opcional)</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<p><strong>2. Servidor Web Unificado</strong></p>
|
||||||
|
<p>Un servidor HTTP en puerto 8080 que fusiona:</p>
|
||||||
|
<ul>
|
||||||
|
<li>API REST (JSON responses)</li>
|
||||||
|
<li>WebSocket para logs</li>
|
||||||
|
<li>Interfaz web HTML estática</li>
|
||||||
|
<li>Archivos estáticos (favicon, logos)</li>
|
||||||
|
</ul>
|
||||||
|
<p>
|
||||||
|
Esto elimina problemas de CORS al servir todo desde el mismo
|
||||||
|
origen.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p><strong>3. Integración Systemd</strong></p>
|
||||||
|
<p>
|
||||||
|
El módulo <code>systemd_manager</code> genera archivos
|
||||||
|
<code>.service</code> automáticamente con:
|
||||||
|
</p>
|
||||||
|
<pre><code>[Unit]
|
||||||
|
Description=App gestionada por SIAX Monitor
|
||||||
|
After=network.target
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
Type=simple
|
||||||
|
User=app-user
|
||||||
|
WorkingDirectory=/opt/app
|
||||||
|
ExecStart=/usr/bin/node server.js
|
||||||
|
Restart=always
|
||||||
|
RestartSec=10
|
||||||
|
StandardOutput=journal
|
||||||
|
StandardError=journal
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=multi-user.target</code></pre>
|
||||||
|
|
||||||
|
<h2>Stack Tecnológico</h2>
|
||||||
|
<p>
|
||||||
|
El proyecto está construido sobre tecnologías modernas y
|
||||||
|
probadas:
|
||||||
|
</p>
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
<strong>Rust</strong> - Lenguaje core (seguridad de
|
||||||
|
memoria, velocidad)
|
||||||
|
</li>
|
||||||
|
<li><strong>Tokio</strong> - Runtime asíncrono</li>
|
||||||
|
<li><strong>Axum 0.7</strong> - Framework web moderno</li>
|
||||||
|
<li><strong>Serde</strong> - Serialización JSON</li>
|
||||||
|
<li><strong>Sysinfo</strong> - Información del sistema</li>
|
||||||
|
<li>
|
||||||
|
<strong>Tower-HTTP</strong> - Middleware (CORS, static
|
||||||
|
files)
|
||||||
|
</li>
|
||||||
|
<li><strong>DashMap</strong> - HashMap thread-safe</li>
|
||||||
|
<li>
|
||||||
|
<strong>Tailwind CSS</strong> - Estilos del frontend
|
||||||
|
</li>
|
||||||
|
<li><strong>Material Symbols</strong> - Iconos</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<h2>Ventajas y Consideraciones</h2>
|
||||||
|
|
||||||
|
<h3>✅ Ventajas</h3>
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
<strong>Alto Rendimiento</strong>: Rust ofrece velocidad
|
||||||
|
cercana a C con seguridad de memoria garantizada
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<strong>Ligero</strong>: Binario compilado de ~15MB,
|
||||||
|
consumo mínimo de RAM
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<strong>Sin Dependencias</strong>: No requiere Node.js,
|
||||||
|
Python o base de datos
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<strong>Integración Nativa</strong>: Aprovecha systemd y
|
||||||
|
journalctl del sistema
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<strong>Fácil Despliegue</strong>: Single binary +
|
||||||
|
script de instalación
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<strong>Open Source</strong>: Código auditable y
|
||||||
|
personalizable
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<h3>⚠️ Consideraciones</h3>
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
<strong>Solo Linux + Systemd</strong>: Requiere
|
||||||
|
distribuciones con systemd (no macOS/Windows)
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<strong>Permisos Sudo</strong>: Necesita configurar
|
||||||
|
sudoers para systemctl
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<strong>Sin Métricas Históricas</strong>: No almacena
|
||||||
|
histórico, solo tiempo real
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<strong>Solo Node.js y Python</strong>: Otros lenguajes
|
||||||
|
requieren extensión del código
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<strong>Sin Autenticación</strong>: Diseñado para acceso
|
||||||
|
local/VPN, no exponer públicamente
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<h2>Casos de Uso</h2>
|
||||||
|
|
||||||
|
<h3>👔 Equipos DevOps</h3>
|
||||||
|
<p>
|
||||||
|
Gestión centralizada de microservicios en múltiples
|
||||||
|
servidores. El monitor actúa como worker node que reporta al
|
||||||
|
cloud API central, permitiendo visibilidad de toda la
|
||||||
|
infraestructura desde un solo panel.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<h3>💻 Desarrolladores</h3>
|
||||||
|
<p>
|
||||||
|
Monitoreo de aplicaciones en entornos de desarrollo y
|
||||||
|
staging sin la complejidad de herramientas enterprise.
|
||||||
|
Perfecto para proyectos pequeños a medianos que necesitan
|
||||||
|
control básico de servicios.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<h3>🖥️ Administradores de Sistemas</h3>
|
||||||
|
<p>
|
||||||
|
Control de servicios systemd con una interfaz web moderna.
|
||||||
|
Alternativa visual a comandos
|
||||||
|
<code>systemctl</code> repetitivos, con la ventaja de logs
|
||||||
|
centralizados y accesibles desde el navegador.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<h2>Instalación Rápida</h2>
|
||||||
|
<p>El proceso de instalación es extremadamente simple:</p>
|
||||||
|
<pre><code># Clonar el repositorio
|
||||||
|
git clone https://git.telcotronics.net/pablinux/SIAX-MONITOR.git
|
||||||
|
cd SIAX-MONITOR
|
||||||
|
|
||||||
|
# Compilar en modo release
|
||||||
|
cargo build --release
|
||||||
|
|
||||||
|
# Ejecutar instalador (crea usuario, configura sudoers, instala servicio)
|
||||||
|
sudo ./instalador.sh
|
||||||
|
|
||||||
|
# El servicio estará disponible en http://localhost:8080
|
||||||
|
</code></pre>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
El script <code>instalador.sh</code> realiza
|
||||||
|
automáticamente:
|
||||||
|
</p>
|
||||||
|
<ul>
|
||||||
|
<li>Crear usuario del sistema <code>siax-agent</code></li>
|
||||||
|
<li>Configurar permisos sudoers para systemctl</li>
|
||||||
|
<li>Copiar binario a <code>/opt/siax-agent/</code></li>
|
||||||
|
<li>Instalar y habilitar servicio systemd</li>
|
||||||
|
<li>Verificar salud del servicio</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<h2>Arquitectura de Despliegue</h2>
|
||||||
|
<p>
|
||||||
|
SIAX Monitor fue diseñado pensando en una arquitectura
|
||||||
|
distribuida:
|
||||||
|
</p>
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
<strong>Cloud API</strong>:
|
||||||
|
<code>https://api.siax-system.net</code> - Panel central
|
||||||
|
de control
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<strong>Worker Nodes</strong>: Agentes SIAX Monitor en
|
||||||
|
cada servidor
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<strong>Comunicación</strong>: VPN segura entre workers
|
||||||
|
y cloud API
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
<p>
|
||||||
|
Cada worker reporta cada 60 segundos su estado, permitiendo
|
||||||
|
monitoreo centralizado de toda la infraestructura sin
|
||||||
|
exponer puertos públicamente.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<h2>Conclusión</h2>
|
||||||
|
<p>
|
||||||
|
SIAX Monitor demuestra que no siempre necesitas soluciones
|
||||||
|
enterprise complejas para problemas simples. Con menos de
|
||||||
|
2,000 líneas de código Rust bien estructurado, ofrece
|
||||||
|
exactamente lo necesario para gestionar aplicaciones Node.js
|
||||||
|
y Python en producción.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
La combinación de Rust + Systemd + WebSocket resulta en una
|
||||||
|
herramienta rápida, confiable y fácil de mantener. Es
|
||||||
|
perfecta para equipos pequeños o medianos que buscan
|
||||||
|
simplicidad sin sacrificar funcionalidad.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
Si administras servidores Linux con aplicaciones Node.js o
|
||||||
|
Python, definitivamente vale la pena darle una oportunidad.
|
||||||
|
El código está disponible en
|
||||||
|
<a
|
||||||
|
href="https://git.telcotronics.net/pablinux/SIAX-MONITOR"
|
||||||
|
target="_blank"
|
||||||
|
class="text-primary hover:underline"
|
||||||
|
>Git Telcotronics</a
|
||||||
|
>
|
||||||
|
bajo licencia open source.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<blockquote>
|
||||||
|
"A veces la mejor solución no es la más compleja, sino la
|
||||||
|
que resuelve tu problema específico de la manera más
|
||||||
|
elegante posible." - Filosofía detrás de SIAX Monitor
|
||||||
|
</blockquote>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Article Footer -->
|
||||||
|
<footer class="mt-16 pt-8 border-t border-slate-800">
|
||||||
|
<div class="flex flex-wrap items-center justify-between gap-4">
|
||||||
|
<div class="flex items-center gap-3">
|
||||||
|
<div
|
||||||
|
class="w-12 h-12 rounded-full bg-primary/20 flex items-center justify-center"
|
||||||
|
>
|
||||||
|
<span class="material-symbols-outlined text-primary"
|
||||||
|
>person</span
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<p class="text-white font-semibold">pablinux</p>
|
||||||
|
<p class="text-slate-400 text-sm">
|
||||||
|
DevOps Engineer · Rust Enthusiast
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="flex gap-3">
|
||||||
|
<a
|
||||||
|
href="https://git.telcotronics.net/pablinux/SIAX-MONITOR"
|
||||||
|
target="_blank"
|
||||||
|
class="inline-flex items-center gap-2 px-6 py-3 bg-primary hover:brightness-110 rounded-lg text-white font-semibold transition-all"
|
||||||
|
>
|
||||||
|
<span class="material-symbols-outlined text-sm"
|
||||||
|
>code</span
|
||||||
|
>
|
||||||
|
Ver en Git
|
||||||
|
</a>
|
||||||
|
<a
|
||||||
|
href="/api-docs"
|
||||||
|
class="inline-flex items-center gap-2 px-6 py-3 bg-slate-800 hover:bg-slate-700 rounded-lg text-white font-semibold transition-all"
|
||||||
|
>
|
||||||
|
<span class="material-symbols-outlined text-sm"
|
||||||
|
>description</span
|
||||||
|
>
|
||||||
|
Documentación
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</footer>
|
||||||
|
|
||||||
|
<!-- Related Articles / Tags -->
|
||||||
|
<div
|
||||||
|
class="mt-12 p-6 rounded-2xl border border-slate-800 bg-[#0a0f16]"
|
||||||
|
>
|
||||||
|
<h3 class="text-lg font-bold text-white mb-4">Etiquetas</h3>
|
||||||
|
<div class="flex flex-wrap gap-2">
|
||||||
|
<span
|
||||||
|
class="px-3 py-1 rounded-full bg-slate-800 text-slate-300 text-sm hover:bg-slate-700 transition-colors cursor-pointer"
|
||||||
|
>rust</span
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
class="px-3 py-1 rounded-full bg-slate-800 text-slate-300 text-sm hover:bg-slate-700 transition-colors cursor-pointer"
|
||||||
|
>systemd</span
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
class="px-3 py-1 rounded-full bg-slate-800 text-slate-300 text-sm hover:bg-slate-700 transition-colors cursor-pointer"
|
||||||
|
>monitoring</span
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
class="px-3 py-1 rounded-full bg-slate-800 text-slate-300 text-sm hover:bg-slate-700 transition-colors cursor-pointer"
|
||||||
|
>devops</span
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
class="px-3 py-1 rounded-full bg-slate-800 text-slate-300 text-sm hover:bg-slate-700 transition-colors cursor-pointer"
|
||||||
|
>nodejs</span
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
class="px-3 py-1 rounded-full bg-slate-800 text-slate-300 text-sm hover:bg-slate-700 transition-colors cursor-pointer"
|
||||||
|
>python</span
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
class="px-3 py-1 rounded-full bg-slate-800 text-slate-300 text-sm hover:bg-slate-700 transition-colors cursor-pointer"
|
||||||
|
>websocket</span
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
class="px-3 py-1 rounded-full bg-slate-800 text-slate-300 text-sm hover:bg-slate-700 transition-colors cursor-pointer"
|
||||||
|
>axum</span
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
class="px-3 py-1 rounded-full bg-slate-800 text-slate-300 text-sm hover:bg-slate-700 transition-colors cursor-pointer"
|
||||||
|
>tokio</span
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
class="px-3 py-1 rounded-full bg-slate-800 text-slate-300 text-sm hover:bg-slate-700 transition-colors cursor-pointer"
|
||||||
|
>linux</span
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</article>
|
||||||
|
|
||||||
|
<!-- Footer -->
|
||||||
|
<footer class="bg-[#0a0f16] border-t border-slate-800 mt-20 py-12">
|
||||||
|
<div class="max-w-4xl mx-auto px-4 sm:px-6 lg:px-8">
|
||||||
|
<div class="text-center mb-6">
|
||||||
|
<h3 class="text-2xl font-bold text-white mb-2">
|
||||||
|
SIAX Monitor
|
||||||
|
</h3>
|
||||||
|
<p class="text-slate-400">
|
||||||
|
Sistema de Monitoreo y Gestión de Aplicaciones
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div class="flex justify-center gap-8 mb-6">
|
||||||
|
<a
|
||||||
|
href="https://git.telcotronics.net/pablinux/SIAX-MONITOR"
|
||||||
|
target="_blank"
|
||||||
|
class="text-slate-400 hover:text-primary transition-colors"
|
||||||
|
>Git</a
|
||||||
|
>
|
||||||
|
<a
|
||||||
|
href="/api-docs"
|
||||||
|
class="text-slate-400 hover:text-primary transition-colors"
|
||||||
|
>API Docs</a
|
||||||
|
>
|
||||||
|
<a
|
||||||
|
href="/"
|
||||||
|
class="text-slate-400 hover:text-primary transition-colors"
|
||||||
|
>Dashboard</a
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
<p class="text-slate-500 text-sm text-center">
|
||||||
|
© 2026 SIAX Monitor. Desarrollado con 🦀 Rust y ❤️ por la
|
||||||
|
comunidad
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</footer>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
563
web/health.html
Normal file
563
web/health.html
Normal file
@@ -0,0 +1,563 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html class="dark" lang="es" dir="ltr">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<meta content="width=device-width, initial-scale=1.0" name="viewport" />
|
||||||
|
<title>System Health - SIAX Monitor</title>
|
||||||
|
<link rel="icon" type="image/svg+xml" href="/static/icon/favicon.svg" />
|
||||||
|
<script src="https://cdn.tailwindcss.com?plugins=forms,container-queries"></script>
|
||||||
|
<link
|
||||||
|
href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800;900&display=swap"
|
||||||
|
rel="stylesheet"
|
||||||
|
/>
|
||||||
|
<link
|
||||||
|
href="https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;500;600&display=swap"
|
||||||
|
rel="stylesheet"
|
||||||
|
/>
|
||||||
|
<link
|
||||||
|
href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:wght,FILL@100..700,0..1&display=swap"
|
||||||
|
rel="stylesheet"
|
||||||
|
/>
|
||||||
|
<script>
|
||||||
|
tailwind.config = {
|
||||||
|
darkMode: "class",
|
||||||
|
theme: {
|
||||||
|
extend: {
|
||||||
|
colors: {
|
||||||
|
primary: "#137fec",
|
||||||
|
"background-light": "#f6f7f8",
|
||||||
|
"background-dark": "#101922",
|
||||||
|
},
|
||||||
|
fontFamily: {
|
||||||
|
display: ["Inter", "sans-serif"],
|
||||||
|
mono: ["JetBrains Mono", "monospace"],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
<style>
|
||||||
|
body {
|
||||||
|
font-family: "Inter", sans-serif;
|
||||||
|
}
|
||||||
|
.material-symbols-outlined {
|
||||||
|
font-variation-settings:
|
||||||
|
"FILL" 0,
|
||||||
|
"wght" 400,
|
||||||
|
"GRAD" 0,
|
||||||
|
"opsz" 24;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body class="bg-background-dark text-white min-h-screen">
|
||||||
|
<!-- Header -->
|
||||||
|
<header class="border-b border-[#283039] bg-[#0a0f16]">
|
||||||
|
<div class="container mx-auto px-4 py-4">
|
||||||
|
<div class="flex items-center justify-between">
|
||||||
|
<div class="flex items-center gap-4">
|
||||||
|
<div
|
||||||
|
class="rounded-full size-9 border-2 border-slate-700 overflow-hidden"
|
||||||
|
>
|
||||||
|
<img
|
||||||
|
src="/static/icon/logo.png"
|
||||||
|
alt="Logo"
|
||||||
|
class="w-full h-full object-cover"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<h1 class="text-xl font-bold">SIAX Monitor</h1>
|
||||||
|
<p class="text-xs text-slate-400">System Health</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- Desktop Navigation -->
|
||||||
|
<nav class="hidden md:flex items-center gap-2">
|
||||||
|
<a
|
||||||
|
href="/scan"
|
||||||
|
class="px-4 py-2 rounded-lg text-slate-300 hover:bg-[#161f2a] transition-colors flex items-center gap-2"
|
||||||
|
>
|
||||||
|
<span class="material-symbols-outlined text-lg"
|
||||||
|
>search</span
|
||||||
|
>
|
||||||
|
<span>Escanear</span>
|
||||||
|
</a>
|
||||||
|
<a
|
||||||
|
href="/logs"
|
||||||
|
class="px-4 py-2 rounded-lg text-slate-300 hover:bg-[#161f2a] transition-colors flex items-center gap-2"
|
||||||
|
>
|
||||||
|
<span class="material-symbols-outlined text-lg"
|
||||||
|
>article</span
|
||||||
|
>
|
||||||
|
<span>Logs</span>
|
||||||
|
</a>
|
||||||
|
<a
|
||||||
|
href="/register"
|
||||||
|
class="px-4 py-2 rounded-lg text-slate-300 hover:bg-[#161f2a] transition-colors flex items-center gap-2"
|
||||||
|
>
|
||||||
|
<span class="material-symbols-outlined text-lg"
|
||||||
|
>app_registration</span
|
||||||
|
>
|
||||||
|
<span>Registrar</span>
|
||||||
|
</a>
|
||||||
|
<a
|
||||||
|
href="/"
|
||||||
|
class="px-4 py-2 rounded-lg text-slate-300 hover:bg-[#161f2a] transition-colors flex items-center gap-2"
|
||||||
|
>
|
||||||
|
<span class="material-symbols-outlined text-lg"
|
||||||
|
>dashboard</span
|
||||||
|
>
|
||||||
|
<span>Dashboard</span>
|
||||||
|
</a>
|
||||||
|
</nav>
|
||||||
|
|
||||||
|
<!-- Mobile Menu Button -->
|
||||||
|
<button
|
||||||
|
onclick="toggleMenu()"
|
||||||
|
class="md:hidden px-3 py-2 rounded-lg text-slate-300 hover:bg-[#161f2a] transition-colors"
|
||||||
|
>
|
||||||
|
<span class="material-symbols-outlined text-2xl"
|
||||||
|
>menu</span
|
||||||
|
>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Mobile Menu Dropdown -->
|
||||||
|
<div
|
||||||
|
id="mobile-menu"
|
||||||
|
class="hidden md:hidden mt-4 pb-4 space-y-2"
|
||||||
|
>
|
||||||
|
<a
|
||||||
|
href="/health"
|
||||||
|
class="block px-4 py-3 rounded-lg bg-[#161f2a] text-primary transition-colors flex items-center gap-3"
|
||||||
|
>
|
||||||
|
<span class="material-symbols-outlined"
|
||||||
|
>monitor_heart</span
|
||||||
|
>
|
||||||
|
<span>Health</span>
|
||||||
|
</a>
|
||||||
|
<a
|
||||||
|
href="/scan"
|
||||||
|
class="block px-4 py-3 rounded-lg text-slate-300 hover:bg-[#161f2a] transition-colors flex items-center gap-3"
|
||||||
|
>
|
||||||
|
<span class="material-symbols-outlined">search</span>
|
||||||
|
<span>Escanear</span>
|
||||||
|
</a>
|
||||||
|
<a
|
||||||
|
href="/logs"
|
||||||
|
class="block px-4 py-3 rounded-lg text-slate-300 hover:bg-[#161f2a] transition-colors flex items-center gap-3"
|
||||||
|
>
|
||||||
|
<span class="material-symbols-outlined">article</span>
|
||||||
|
<span>Logs</span>
|
||||||
|
</a>
|
||||||
|
<a
|
||||||
|
href="/"
|
||||||
|
class="block px-4 py-3 rounded-lg text-slate-300 hover:bg-[#161f2a] transition-colors flex items-center gap-3"
|
||||||
|
>
|
||||||
|
<span class="material-symbols-outlined">dashboard</span>
|
||||||
|
<span>Dashboard</span>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<!-- Main Content -->
|
||||||
|
<main class="container mx-auto px-4 py-8">
|
||||||
|
<!-- Page Header -->
|
||||||
|
<div class="mb-8">
|
||||||
|
<div class="flex items-center justify-between">
|
||||||
|
<div>
|
||||||
|
<h2 class="text-3xl font-black mb-2">System Health</h2>
|
||||||
|
<p class="text-slate-400">
|
||||||
|
Diagnóstico y estado del sistema de monitoreo
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<button
|
||||||
|
onclick="refreshHealth()"
|
||||||
|
class="px-4 py-2 rounded-lg bg-primary hover:brightness-110 transition-all flex items-center gap-2"
|
||||||
|
>
|
||||||
|
<span class="material-symbols-outlined text-sm"
|
||||||
|
>refresh</span
|
||||||
|
>
|
||||||
|
<span>Actualizar</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Loading State -->
|
||||||
|
<div id="loading-state" class="text-center py-12">
|
||||||
|
<div
|
||||||
|
class="inline-block animate-spin rounded-full h-12 w-12 border-4 border-primary border-t-transparent"
|
||||||
|
></div>
|
||||||
|
<p class="mt-4 text-slate-400">
|
||||||
|
Cargando estado del sistema...
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Health Cards Container -->
|
||||||
|
<div id="health-content" class="hidden">
|
||||||
|
<!-- Status Overview -->
|
||||||
|
<div class="grid grid-cols-1 md:grid-cols-4 gap-4 mb-8">
|
||||||
|
<!-- Overall Status -->
|
||||||
|
<div
|
||||||
|
class="rounded-2xl border border-[#283039] bg-[#161f2a] p-6"
|
||||||
|
>
|
||||||
|
<div class="flex items-center justify-between mb-2">
|
||||||
|
<span class="text-slate-400">Estado General</span>
|
||||||
|
<span
|
||||||
|
class="material-symbols-outlined text-green-400"
|
||||||
|
id="status-icon"
|
||||||
|
>check_circle</span
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
<div class="text-2xl font-bold" id="overall-status">
|
||||||
|
OK
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Config Status -->
|
||||||
|
<div
|
||||||
|
class="rounded-2xl border border-[#283039] bg-[#161f2a] p-6"
|
||||||
|
>
|
||||||
|
<div class="flex items-center justify-between mb-2">
|
||||||
|
<span class="text-slate-400">Configuración</span>
|
||||||
|
<span
|
||||||
|
class="material-symbols-outlined text-blue-400"
|
||||||
|
>settings</span
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
<div class="text-2xl font-bold" id="config-status">
|
||||||
|
Cargada
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Apps Count -->
|
||||||
|
<div
|
||||||
|
class="rounded-2xl border border-[#283039] bg-[#161f2a] p-6"
|
||||||
|
>
|
||||||
|
<div class="flex items-center justify-between mb-2">
|
||||||
|
<span class="text-slate-400">Apps Registradas</span>
|
||||||
|
<span
|
||||||
|
class="material-symbols-outlined text-purple-400"
|
||||||
|
>apps</span
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
<div class="text-2xl font-bold" id="apps-count">0</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Version -->
|
||||||
|
<div
|
||||||
|
class="rounded-2xl border border-[#283039] bg-[#161f2a] p-6"
|
||||||
|
>
|
||||||
|
<div class="flex items-center justify-between mb-2">
|
||||||
|
<span class="text-slate-400">Versión</span>
|
||||||
|
<span
|
||||||
|
class="material-symbols-outlined text-yellow-400"
|
||||||
|
>info</span
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
<div class="text-2xl font-bold font-mono" id="version">
|
||||||
|
-
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Detailed Information -->
|
||||||
|
<div class="grid grid-cols-1 lg:grid-cols-2 gap-6">
|
||||||
|
<!-- Configuration Details -->
|
||||||
|
<div
|
||||||
|
class="rounded-2xl border border-[#283039] bg-[#161f2a] p-6"
|
||||||
|
>
|
||||||
|
<div class="flex items-center gap-3 mb-6">
|
||||||
|
<div
|
||||||
|
class="w-10 h-10 rounded-xl bg-blue-500/20 flex items-center justify-center"
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
class="material-symbols-outlined text-blue-400"
|
||||||
|
>folder</span
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<h3 class="text-lg font-bold">Configuración</h3>
|
||||||
|
<p class="text-sm text-slate-400">
|
||||||
|
Detalles del archivo de configuración
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="space-y-4">
|
||||||
|
<div
|
||||||
|
class="flex items-start justify-between py-3 border-b border-[#283039]"
|
||||||
|
>
|
||||||
|
<div>
|
||||||
|
<p class="text-sm text-slate-400">
|
||||||
|
Ruta del archivo
|
||||||
|
</p>
|
||||||
|
<p
|
||||||
|
class="font-mono text-sm text-primary"
|
||||||
|
id="config-path"
|
||||||
|
>
|
||||||
|
-
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<span
|
||||||
|
class="material-symbols-outlined text-green-400"
|
||||||
|
id="config-loaded-icon"
|
||||||
|
>check_circle</span
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div
|
||||||
|
class="flex items-start justify-between py-3 border-b border-[#283039]"
|
||||||
|
>
|
||||||
|
<div>
|
||||||
|
<p class="text-sm text-slate-400">Estado</p>
|
||||||
|
<p
|
||||||
|
class="font-semibold"
|
||||||
|
id="config-loaded-text"
|
||||||
|
>
|
||||||
|
Archivo cargado correctamente
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="flex items-start justify-between py-3">
|
||||||
|
<div>
|
||||||
|
<p class="text-sm text-slate-400">
|
||||||
|
Aplicaciones en config
|
||||||
|
</p>
|
||||||
|
<p
|
||||||
|
class="text-2xl font-bold"
|
||||||
|
id="config-apps-count"
|
||||||
|
>
|
||||||
|
0
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Systemd Services -->
|
||||||
|
<div
|
||||||
|
class="rounded-2xl border border-[#283039] bg-[#161f2a] p-6"
|
||||||
|
>
|
||||||
|
<div class="flex items-center gap-3 mb-6">
|
||||||
|
<div
|
||||||
|
class="w-10 h-10 rounded-xl bg-green-500/20 flex items-center justify-center"
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
class="material-symbols-outlined text-green-400"
|
||||||
|
>settings_system_daydream</span
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<h3 class="text-lg font-bold">
|
||||||
|
Servicios Systemd
|
||||||
|
</h3>
|
||||||
|
<p class="text-sm text-slate-400">
|
||||||
|
Servicios creados por SIAX Monitor
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div
|
||||||
|
id="systemd-services-list"
|
||||||
|
class="space-y-2 max-h-80 overflow-y-auto"
|
||||||
|
>
|
||||||
|
<!-- Services will be injected here -->
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div
|
||||||
|
id="no-services"
|
||||||
|
class="hidden text-center py-8 text-slate-400"
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
class="material-symbols-outlined text-4xl mb-2 opacity-50"
|
||||||
|
>info</span
|
||||||
|
>
|
||||||
|
<p>No hay servicios systemd registrados</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- System Commands -->
|
||||||
|
<div
|
||||||
|
class="mt-6 rounded-2xl border border-[#283039] bg-[#161f2a] p-6"
|
||||||
|
>
|
||||||
|
<div class="flex items-center gap-3 mb-6">
|
||||||
|
<div
|
||||||
|
class="w-10 h-10 rounded-xl bg-purple-500/20 flex items-center justify-center"
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
class="material-symbols-outlined text-purple-400"
|
||||||
|
>terminal</span
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<h3 class="text-lg font-bold">Comandos Útiles</h3>
|
||||||
|
<p class="text-sm text-slate-400">
|
||||||
|
Comandos para gestionar servicios systemd
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||||||
|
<div class="rounded-lg bg-[#0a0f16] p-4">
|
||||||
|
<p class="text-xs text-slate-400 mb-2">
|
||||||
|
Listar servicios SIAX
|
||||||
|
</p>
|
||||||
|
<code class="text-sm text-primary font-mono"
|
||||||
|
>systemctl list-units 'siax-app-*'</code
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="rounded-lg bg-[#0a0f16] p-4">
|
||||||
|
<p class="text-xs text-slate-400 mb-2">
|
||||||
|
Ver estado de un servicio
|
||||||
|
</p>
|
||||||
|
<code class="text-sm text-primary font-mono"
|
||||||
|
>systemctl status siax-app-nombre.service</code
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="rounded-lg bg-[#0a0f16] p-4">
|
||||||
|
<p class="text-xs text-slate-400 mb-2">
|
||||||
|
Ver logs de un servicio
|
||||||
|
</p>
|
||||||
|
<code class="text-sm text-primary font-mono"
|
||||||
|
>journalctl -u siax-app-nombre -f</code
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="rounded-lg bg-[#0a0f16] p-4">
|
||||||
|
<p class="text-xs text-slate-400 mb-2">
|
||||||
|
Recargar daemon de systemd
|
||||||
|
</p>
|
||||||
|
<code class="text-sm text-primary font-mono"
|
||||||
|
>systemctl daemon-reload</code
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</main>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
async function loadHealth() {
|
||||||
|
const loading = document.getElementById("loading-state");
|
||||||
|
const content = document.getElementById("health-content");
|
||||||
|
|
||||||
|
try {
|
||||||
|
loading.classList.remove("hidden");
|
||||||
|
content.classList.add("hidden");
|
||||||
|
|
||||||
|
const response = await fetch("/api/health");
|
||||||
|
if (!response.ok) throw new Error("Failed to fetch health");
|
||||||
|
|
||||||
|
const result = await response.json();
|
||||||
|
const data = result.data;
|
||||||
|
|
||||||
|
loading.classList.add("hidden");
|
||||||
|
content.classList.remove("hidden");
|
||||||
|
|
||||||
|
// Update status cards
|
||||||
|
document.getElementById("overall-status").textContent =
|
||||||
|
data.status.toUpperCase();
|
||||||
|
document.getElementById("config-status").textContent =
|
||||||
|
data.config_loaded ? "Cargada" : "No encontrada";
|
||||||
|
document.getElementById("apps-count").textContent =
|
||||||
|
data.apps_count;
|
||||||
|
document.getElementById("version").textContent =
|
||||||
|
"v" + data.version;
|
||||||
|
|
||||||
|
// Update config details
|
||||||
|
document.getElementById("config-path").textContent =
|
||||||
|
data.config_path;
|
||||||
|
document.getElementById("config-apps-count").textContent =
|
||||||
|
data.apps_count;
|
||||||
|
|
||||||
|
const configIcon =
|
||||||
|
document.getElementById("config-loaded-icon");
|
||||||
|
const configText =
|
||||||
|
document.getElementById("config-loaded-text");
|
||||||
|
|
||||||
|
if (data.config_loaded) {
|
||||||
|
configIcon.textContent = "check_circle";
|
||||||
|
configIcon.className =
|
||||||
|
"material-symbols-outlined text-green-400";
|
||||||
|
configText.textContent =
|
||||||
|
"Archivo cargado correctamente";
|
||||||
|
} else {
|
||||||
|
configIcon.textContent = "error";
|
||||||
|
configIcon.className =
|
||||||
|
"material-symbols-outlined text-yellow-400";
|
||||||
|
configText.textContent =
|
||||||
|
"Archivo no encontrado (se creará automáticamente)";
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update systemd services list
|
||||||
|
const servicesList = document.getElementById(
|
||||||
|
"systemd-services-list",
|
||||||
|
);
|
||||||
|
const noServices = document.getElementById("no-services");
|
||||||
|
|
||||||
|
if (
|
||||||
|
data.systemd_services &&
|
||||||
|
data.systemd_services.length > 0
|
||||||
|
) {
|
||||||
|
servicesList.innerHTML = data.systemd_services
|
||||||
|
.map(
|
||||||
|
(service) => `
|
||||||
|
<div class="flex items-center justify-between p-3 rounded-lg bg-[#0a0f16] hover:bg-[#0d1218] transition-colors">
|
||||||
|
<div class="flex items-center gap-3">
|
||||||
|
<span class="material-symbols-outlined text-green-400 text-sm">check_circle</span>
|
||||||
|
<span class="font-mono text-sm">${service}</span>
|
||||||
|
</div>
|
||||||
|
<button onclick="copyToClipboard('${service}')" class="text-slate-400 hover:text-primary transition-colors">
|
||||||
|
<span class="material-symbols-outlined text-sm">content_copy</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
`,
|
||||||
|
)
|
||||||
|
.join("");
|
||||||
|
noServices.classList.add("hidden");
|
||||||
|
} else {
|
||||||
|
servicesList.innerHTML = "";
|
||||||
|
noServices.classList.remove("hidden");
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Error loading health:", error);
|
||||||
|
loading.classList.add("hidden");
|
||||||
|
content.innerHTML = `
|
||||||
|
<div class="text-center py-12 text-red-400">
|
||||||
|
<span class="material-symbols-outlined text-6xl mb-4">error</span>
|
||||||
|
<p class="text-xl font-bold mb-2">Error al cargar el estado del sistema</p>
|
||||||
|
<p class="text-slate-400">${error.message}</p>
|
||||||
|
<button onclick="loadHealth()" class="mt-4 px-6 py-2 bg-primary rounded-lg hover:brightness-110">
|
||||||
|
Reintentar
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
content.classList.remove("hidden");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function refreshHealth() {
|
||||||
|
loadHealth();
|
||||||
|
}
|
||||||
|
|
||||||
|
function copyToClipboard(text) {
|
||||||
|
navigator.clipboard.writeText(text).then(() => {
|
||||||
|
// Simple feedback - you could add a toast notification here
|
||||||
|
console.log("Copied:", text);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function toggleMenu() {
|
||||||
|
const menu = document.getElementById("mobile-menu");
|
||||||
|
menu.classList.toggle("hidden");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load on page load
|
||||||
|
document.addEventListener("DOMContentLoaded", loadHealth);
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
171
web/index.html
171
web/index.html
@@ -4,6 +4,7 @@
|
|||||||
<meta charset="utf-8" />
|
<meta charset="utf-8" />
|
||||||
<meta content="width=device-width, initial-scale=1.0" name="viewport" />
|
<meta content="width=device-width, initial-scale=1.0" name="viewport" />
|
||||||
<title>Panel de Monitoreo</title>
|
<title>Panel de Monitoreo</title>
|
||||||
|
<link rel="icon" type="image/svg+xml" href="/static/icon/favicon.svg" />
|
||||||
<script src="https://cdn.tailwindcss.com?plugins=forms,container-queries"></script>
|
<script src="https://cdn.tailwindcss.com?plugins=forms,container-queries"></script>
|
||||||
<link
|
<link
|
||||||
href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800;900&display=swap"
|
href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800;900&display=swap"
|
||||||
@@ -54,90 +55,117 @@
|
|||||||
>
|
>
|
||||||
<div class="flex h-full grow flex-col">
|
<div class="flex h-full grow flex-col">
|
||||||
<!-- Sticky Top Navigation -->
|
<!-- Sticky Top Navigation -->
|
||||||
<header
|
<header class="border-b border-[#283039] bg-[#0a0f16]">
|
||||||
class="sticky top-0 z-50 w-full border-b border-slate-200 dark:border-slate-800 bg-background-light/80 dark:bg-background-dark/80 backdrop-blur-md"
|
<div class="container mx-auto px-4 py-4">
|
||||||
>
|
<div class="flex items-center justify-between">
|
||||||
|
<div class="flex items-center gap-4">
|
||||||
<div
|
<div
|
||||||
class="max-w-[1200px] mx-auto px-4 lg:px-10 py-3 flex items-center justify-between"
|
class="rounded-full size-9 border-2 border-slate-700 overflow-hidden"
|
||||||
>
|
|
||||||
<div class="flex items-center gap-8">
|
|
||||||
<div class="flex items-center gap-3 text-primary">
|
|
||||||
<div
|
|
||||||
class="size-8 bg-primary rounded-lg flex items-center justify-center text-white"
|
|
||||||
>
|
|
||||||
<span class="material-symbols-outlined"
|
|
||||||
>monitoring</span
|
|
||||||
>
|
>
|
||||||
|
<img
|
||||||
|
src="/static/icon/logo.png"
|
||||||
|
alt="Logo"
|
||||||
|
class="w-full h-full object-cover"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<h2
|
<div>
|
||||||
class="text-white text-lg font-bold leading-tight tracking-[-0.015em]"
|
<h1 class="text-xl font-bold">SIAX Monitor</h1>
|
||||||
>
|
<p class="text-xs text-slate-400">Dashboard</p>
|
||||||
SIAX Monitor
|
|
||||||
</h2>
|
|
||||||
</div>
|
</div>
|
||||||
<nav class="hidden md:flex items-center gap-6">
|
</div>
|
||||||
|
|
||||||
|
<!-- Desktop Navigation -->
|
||||||
|
<nav class="hidden md:flex items-center gap-2">
|
||||||
<a
|
<a
|
||||||
class="text-primary text-sm font-semibold leading-normal"
|
href="/health"
|
||||||
href="/"
|
class="px-4 py-2 rounded-lg text-slate-300 hover:bg-[#161f2a] transition-colors flex items-center gap-2"
|
||||||
>Inicio</a
|
|
||||||
>
|
>
|
||||||
|
<span class="material-symbols-outlined text-lg"
|
||||||
|
>monitor_heart</span
|
||||||
|
>
|
||||||
|
<span>Health</span>
|
||||||
|
</a>
|
||||||
<a
|
<a
|
||||||
class="text-slate-600 dark:text-slate-400 hover:text-white text-sm font-medium transition-colors"
|
|
||||||
href="/scan"
|
href="/scan"
|
||||||
|
class="px-4 py-2 rounded-lg text-slate-300 hover:bg-[#161f2a] transition-colors flex items-center gap-2"
|
||||||
>
|
>
|
||||||
Escanear
|
<span class="material-symbols-outlined text-lg"
|
||||||
|
>search</span
|
||||||
|
>
|
||||||
|
<span>Escanear</span>
|
||||||
</a>
|
</a>
|
||||||
<a
|
<a
|
||||||
class="text-slate-600 dark:text-slate-400 hover:text-white text-sm font-medium transition-colors"
|
|
||||||
href="/select"
|
|
||||||
>
|
|
||||||
Agregar
|
|
||||||
</a>
|
|
||||||
<a
|
|
||||||
class="text-slate-600 dark:text-slate-400 hover:text-white text-sm font-medium transition-colors"
|
|
||||||
href="/register"
|
|
||||||
>
|
|
||||||
Nueva App
|
|
||||||
</a>
|
|
||||||
<a
|
|
||||||
class="text-slate-600 dark:text-slate-400 hover:text-white text-sm font-medium transition-colors"
|
|
||||||
href="/logs"
|
href="/logs"
|
||||||
|
class="px-4 py-2 rounded-lg text-slate-300 hover:bg-[#161f2a] transition-colors flex items-center gap-2"
|
||||||
>
|
>
|
||||||
Registros
|
<span class="material-symbols-outlined text-lg"
|
||||||
|
>article</span
|
||||||
|
>
|
||||||
|
<span>Logs</span>
|
||||||
|
</a>
|
||||||
|
<a
|
||||||
|
href="/register"
|
||||||
|
class="px-4 py-2 rounded-lg text-slate-300 hover:bg-[#161f2a] transition-colors flex items-center gap-2"
|
||||||
|
>
|
||||||
|
<span class="material-symbols-outlined text-lg"
|
||||||
|
>app_registration</span
|
||||||
|
>
|
||||||
|
<span>Registrar</span>
|
||||||
</a>
|
</a>
|
||||||
</nav>
|
</nav>
|
||||||
</div>
|
|
||||||
<div class="flex items-center gap-4">
|
<!-- Mobile Menu Button -->
|
||||||
<div class="hidden sm:block">
|
|
||||||
<label class="relative block">
|
|
||||||
<span
|
|
||||||
class="absolute inset-y-0 left-0 flex items-center pl-3 text-slate-500"
|
|
||||||
>
|
|
||||||
<span
|
|
||||||
class="material-symbols-outlined text-sm"
|
|
||||||
>
|
|
||||||
search
|
|
||||||
</span>
|
|
||||||
</span>
|
|
||||||
<input
|
|
||||||
class="form-input w-64 rounded-lg border-none bg-slate-200 dark:bg-slate-800 text-sm py-2 pl-10 pr-4 placeholder:text-slate-500 focus:ring-1 focus:ring-primary"
|
|
||||||
placeholder="Buscar..."
|
|
||||||
type="text"
|
|
||||||
/>
|
|
||||||
</label>
|
|
||||||
</div>
|
|
||||||
<button
|
<button
|
||||||
class="hidden lg:flex cursor-pointer items-center justify-center rounded-lg h-9 px-4 bg-primary text-white text-sm font-bold transition-opacity hover:opacity-90"
|
onclick="toggleMenu()"
|
||||||
onclick="window.location.href = '/register'"
|
class="md:hidden px-3 py-2 rounded-lg text-slate-300 hover:bg-[#161f2a] transition-colors"
|
||||||
|
>
|
||||||
|
<span class="material-symbols-outlined text-2xl"
|
||||||
|
>menu</span
|
||||||
>
|
>
|
||||||
<span>Registrar App</span>
|
|
||||||
</button>
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Mobile Menu Dropdown -->
|
||||||
<div
|
<div
|
||||||
class="bg-center bg-no-repeat aspect-square bg-cover rounded-full size-9 border-2 border-slate-700"
|
id="mobile-menu"
|
||||||
style="
|
class="hidden md:hidden mt-4 pb-4 space-y-2"
|
||||||
background-image: url("https://lh3.googleusercontent.com/aida-public/AB6AXuCT0iINTncUFHp353HCJXRR5C0OKbSp_7IBOVNoDU07yuF2aToQQdnXNOeGI9RLUjVBsVNcU--ZoTMY90FFJvrQvYvRzKvq-CFCzBlVkCeoi5AgG84cB71wW0NIMg626M_sCjmDjxqmAJwIbkAcSmSlAg3TUThW1U2A3StNVgqFXEpgFbpJcU5nxLs6vuRkfYR1kIXcV44TQpgOosbsjSB1Pk1UTOQJ_OEcQtY-5c3FJw7gXBDxlp6y3jsY3rBm0xWGJi8NWnrUrhpl");
|
>
|
||||||
"
|
<a
|
||||||
></div>
|
href="/health"
|
||||||
|
class="block px-4 py-3 rounded-lg text-slate-300 hover:bg-[#161f2a] transition-colors flex items-center gap-3"
|
||||||
|
>
|
||||||
|
<span class="material-symbols-outlined"
|
||||||
|
>monitor_heart</span
|
||||||
|
>
|
||||||
|
<span>Health</span>
|
||||||
|
</a>
|
||||||
|
<a
|
||||||
|
href="/scan"
|
||||||
|
class="block px-4 py-3 rounded-lg text-slate-300 hover:bg-[#161f2a] transition-colors flex items-center gap-3"
|
||||||
|
>
|
||||||
|
<span class="material-symbols-outlined"
|
||||||
|
>search</span
|
||||||
|
>
|
||||||
|
<span>Escanear</span>
|
||||||
|
</a>
|
||||||
|
<a
|
||||||
|
href="/logs"
|
||||||
|
class="block px-4 py-3 rounded-lg text-slate-300 hover:bg-[#161f2a] transition-colors flex items-center gap-3"
|
||||||
|
>
|
||||||
|
<span class="material-symbols-outlined"
|
||||||
|
>article</span
|
||||||
|
>
|
||||||
|
<span>Logs</span>
|
||||||
|
</a>
|
||||||
|
<a
|
||||||
|
href="/register"
|
||||||
|
class="block px-4 py-3 rounded-lg text-slate-300 hover:bg-[#161f2a] transition-colors flex items-center gap-3"
|
||||||
|
>
|
||||||
|
<span class="material-symbols-outlined"
|
||||||
|
>app_registration</span
|
||||||
|
>
|
||||||
|
<span>Registrar</span>
|
||||||
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</header>
|
</header>
|
||||||
@@ -150,7 +178,7 @@
|
|||||||
<h1
|
<h1
|
||||||
class="text-slate-900 dark:text-white text-3xl font-black tracking-tight"
|
class="text-slate-900 dark:text-white text-3xl font-black tracking-tight"
|
||||||
>
|
>
|
||||||
Dashboard Index
|
Panel de Control
|
||||||
</h1>
|
</h1>
|
||||||
<p class="text-slate-500 text-sm mt-1">
|
<p class="text-slate-500 text-sm mt-1">
|
||||||
Monitoreo de salud del sistema y procesos en tiempo
|
Monitoreo de salud del sistema y procesos en tiempo
|
||||||
@@ -436,7 +464,7 @@
|
|||||||
<a class="hover:text-primary" href="#"
|
<a class="hover:text-primary" href="#"
|
||||||
>Política de Privacidad</a
|
>Política de Privacidad</a
|
||||||
>
|
>
|
||||||
<a class="hover:text-primary" href="#"
|
<a class="hover:text-primary" href="/api-docs"
|
||||||
>Documentación de API</a
|
>Documentación de API</a
|
||||||
>
|
>
|
||||||
</div>
|
</div>
|
||||||
@@ -446,9 +474,7 @@
|
|||||||
<script>
|
<script>
|
||||||
async function loadApps() {
|
async function loadApps() {
|
||||||
try {
|
try {
|
||||||
const response = await fetch(
|
const response = await fetch("/api/apps");
|
||||||
"http://localhost:8080/api/apps",
|
|
||||||
);
|
|
||||||
const result = await response.json();
|
const result = await response.json();
|
||||||
|
|
||||||
if (result.success && result.data && result.data.apps) {
|
if (result.success && result.data && result.data.apps) {
|
||||||
@@ -516,6 +542,11 @@
|
|||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function toggleMenu() {
|
||||||
|
const menu = document.getElementById("mobile-menu");
|
||||||
|
menu.classList.toggle("hidden");
|
||||||
|
}
|
||||||
|
|
||||||
window.addEventListener("DOMContentLoaded", loadApps);
|
window.addEventListener("DOMContentLoaded", loadApps);
|
||||||
</script>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
<meta charset="utf-8" />
|
<meta charset="utf-8" />
|
||||||
<meta content="width=device-width, initial-scale=1.0" name="viewport" />
|
<meta content="width=device-width, initial-scale=1.0" name="viewport" />
|
||||||
<title>Visor de Registros - SIAX Monitor</title>
|
<title>Visor de Registros - SIAX Monitor</title>
|
||||||
|
<link rel="icon" type="image/svg+xml" href="/static/icon/favicon.svg" />
|
||||||
<script src="https://cdn.tailwindcss.com?plugins=forms,container-queries"></script>
|
<script src="https://cdn.tailwindcss.com?plugins=forms,container-queries"></script>
|
||||||
<link
|
<link
|
||||||
href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap"
|
href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap"
|
||||||
@@ -69,9 +70,11 @@
|
|||||||
<div
|
<div
|
||||||
class="size-8 bg-primary rounded-lg flex items-center justify-center"
|
class="size-8 bg-primary rounded-lg flex items-center justify-center"
|
||||||
>
|
>
|
||||||
<span class="material-symbols-outlined text-white"
|
<img
|
||||||
>monitoring</span
|
src="/static/icon/logo.png"
|
||||||
>
|
alt="Logo"
|
||||||
|
class="w-full h-full object-cover"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<h2
|
<h2
|
||||||
class="text-white text-lg font-bold leading-tight tracking-[-0.015em]"
|
class="text-white text-lg font-bold leading-tight tracking-[-0.015em]"
|
||||||
@@ -95,12 +98,7 @@
|
|||||||
<a
|
<a
|
||||||
class="text-[#9dabb9] text-sm font-medium hover:text-white transition-colors"
|
class="text-[#9dabb9] text-sm font-medium hover:text-white transition-colors"
|
||||||
href="/select"
|
href="/select"
|
||||||
>Agregar Detectada</a
|
>Selecionar Detectada</a
|
||||||
>
|
|
||||||
<a
|
|
||||||
class="text-[#9dabb9] text-sm font-medium hover:text-white transition-colors"
|
|
||||||
href="/register"
|
|
||||||
>Nueva App</a
|
|
||||||
>
|
>
|
||||||
<a
|
<a
|
||||||
class="text-primary text-sm font-medium border-b-2 border-primary pb-1"
|
class="text-primary text-sm font-medium border-b-2 border-primary pb-1"
|
||||||
@@ -108,6 +106,12 @@
|
|||||||
>Registros</a
|
>Registros</a
|
||||||
>
|
>
|
||||||
</nav>
|
</nav>
|
||||||
|
<button
|
||||||
|
class="hidden lg:flex cursor-pointer items-center justify-center rounded-lg h-9 px-4 bg-primary text-white text-sm font-bold transition-opacity hover:opacity-90"
|
||||||
|
onclick="window.location.href = '/register'"
|
||||||
|
>
|
||||||
|
<span>Nueva App</span>
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</header>
|
</header>
|
||||||
@@ -238,9 +242,7 @@
|
|||||||
empty.classList.add("hidden");
|
empty.classList.add("hidden");
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const response = await fetch(
|
const response = await fetch("/api/apps");
|
||||||
"http://localhost:8080/api/apps",
|
|
||||||
);
|
|
||||||
const data = await response.json();
|
const data = await response.json();
|
||||||
|
|
||||||
loading.classList.add("hidden");
|
loading.classList.add("hidden");
|
||||||
@@ -321,9 +323,10 @@
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Connect WebSocket
|
// Connect WebSocket
|
||||||
ws = new WebSocket(
|
const protocol =
|
||||||
`ws://localhost:8080/api/apps/${appName}/logs`,
|
window.location.protocol === "https:" ? "wss:" : "ws:";
|
||||||
);
|
const wsUrl = `${protocol}//${window.location.host}/api/apps/${appName}/logs`;
|
||||||
|
ws = new WebSocket(wsUrl);
|
||||||
|
|
||||||
ws.onopen = () => {
|
ws.onopen = () => {
|
||||||
document.getElementById("connection-status").textContent =
|
document.getElementById("connection-status").textContent =
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
<meta charset="utf-8" />
|
<meta charset="utf-8" />
|
||||||
<meta content="width=device-width, initial-scale=1.0" name="viewport" />
|
<meta content="width=device-width, initial-scale=1.0" name="viewport" />
|
||||||
<title>Registrar Aplicación - SIAX Monitor</title>
|
<title>Registrar Aplicación - SIAX Monitor</title>
|
||||||
|
<link rel="icon" type="image/svg+xml" href="/static/icon/favicon.svg" />
|
||||||
<script src="https://cdn.tailwindcss.com?plugins=forms,container-queries"></script>
|
<script src="https://cdn.tailwindcss.com?plugins=forms,container-queries"></script>
|
||||||
<link
|
<link
|
||||||
href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap"
|
href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap"
|
||||||
@@ -62,9 +63,11 @@
|
|||||||
<div
|
<div
|
||||||
class="size-8 bg-primary rounded-lg flex items-center justify-center"
|
class="size-8 bg-primary rounded-lg flex items-center justify-center"
|
||||||
>
|
>
|
||||||
<span class="material-symbols-outlined text-white"
|
<img
|
||||||
>monitoring</span
|
src="/static/icon/logo.png"
|
||||||
>
|
alt="Logo"
|
||||||
|
class="w-full h-full object-cover"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<h2
|
<h2
|
||||||
class="text-white text-lg font-bold leading-tight tracking-[-0.015em]"
|
class="text-white text-lg font-bold leading-tight tracking-[-0.015em]"
|
||||||
@@ -88,12 +91,7 @@
|
|||||||
<a
|
<a
|
||||||
class="text-[#9dabb9] text-sm font-medium hover:text-white transition-colors"
|
class="text-[#9dabb9] text-sm font-medium hover:text-white transition-colors"
|
||||||
href="/select"
|
href="/select"
|
||||||
>Agregar Detectada</a
|
>Selecionar Detectada</a
|
||||||
>
|
|
||||||
<a
|
|
||||||
class="text-primary text-sm font-medium border-b-2 border-primary pb-1"
|
|
||||||
href="/register"
|
|
||||||
>Nueva App</a
|
|
||||||
>
|
>
|
||||||
<a
|
<a
|
||||||
class="text-[#9dabb9] text-sm font-medium hover:text-white transition-colors"
|
class="text-[#9dabb9] text-sm font-medium hover:text-white transition-colors"
|
||||||
@@ -101,6 +99,12 @@
|
|||||||
>Registros</a
|
>Registros</a
|
||||||
>
|
>
|
||||||
</nav>
|
</nav>
|
||||||
|
<button
|
||||||
|
class="hidden lg:flex cursor-pointer items-center justify-center rounded-lg h-9 px-4 bg-primary text-white text-sm font-bold transition-opacity hover:opacity-90"
|
||||||
|
onclick="window.location.href = '/register'"
|
||||||
|
>
|
||||||
|
<span>Nueva App</span>
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</header>
|
</header>
|
||||||
@@ -461,16 +465,13 @@
|
|||||||
});
|
});
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const response = await fetch(
|
const response = await fetch("/api/apps", {
|
||||||
"http://localhost:8080/api/apps",
|
|
||||||
{
|
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: {
|
headers: {
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
},
|
},
|
||||||
body: JSON.stringify(formData),
|
body: JSON.stringify(formData),
|
||||||
},
|
});
|
||||||
);
|
|
||||||
|
|
||||||
const result = await response.json();
|
const result = await response.json();
|
||||||
|
|
||||||
@@ -485,7 +486,7 @@
|
|||||||
confirm("¿Deseas iniciar la aplicación ahora?")
|
confirm("¿Deseas iniciar la aplicación ahora?")
|
||||||
) {
|
) {
|
||||||
const startResponse = await fetch(
|
const startResponse = await fetch(
|
||||||
`http://localhost:8080/api/apps/${formData.app_name}/start`,
|
`/api/apps/${formData.app_name}/start`,
|
||||||
{ method: "POST" },
|
{ method: "POST" },
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
<meta charset="utf-8" />
|
<meta charset="utf-8" />
|
||||||
<meta content="width=device-width, initial-scale=1.0" name="viewport" />
|
<meta content="width=device-width, initial-scale=1.0" name="viewport" />
|
||||||
<title>Escaneo de Procesos - SIAX Monitor</title>
|
<title>Escaneo de Procesos - SIAX Monitor</title>
|
||||||
|
<link rel="icon" type="image/svg+xml" href="/static/icon/favicon.svg" />
|
||||||
<script src="https://cdn.tailwindcss.com?plugins=forms,container-queries"></script>
|
<script src="https://cdn.tailwindcss.com?plugins=forms,container-queries"></script>
|
||||||
<link
|
<link
|
||||||
href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap"
|
href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap"
|
||||||
@@ -62,9 +63,7 @@
|
|||||||
<div
|
<div
|
||||||
class="size-8 bg-primary rounded-lg flex items-center justify-center"
|
class="size-8 bg-primary rounded-lg flex items-center justify-center"
|
||||||
>
|
>
|
||||||
<span class="material-symbols-outlined text-white"
|
<img src="/static/icon/logo.png" alt="Logo" class="w-full h-full object-cover">
|
||||||
>monitoring</span
|
|
||||||
>
|
|
||||||
</div>
|
</div>
|
||||||
<h2
|
<h2
|
||||||
class="text-white text-lg font-bold leading-tight tracking-[-0.015em]"
|
class="text-white text-lg font-bold leading-tight tracking-[-0.015em]"
|
||||||
@@ -88,19 +87,21 @@
|
|||||||
<a
|
<a
|
||||||
class="text-[#9dabb9] text-sm font-medium hover:text-white transition-colors"
|
class="text-[#9dabb9] text-sm font-medium hover:text-white transition-colors"
|
||||||
href="/select"
|
href="/select"
|
||||||
>Agregar Detectada</a
|
>Selecionar Detectada</a
|
||||||
>
|
|
||||||
<a
|
|
||||||
class="text-[#9dabb9] text-sm font-medium hover:text-white transition-colors"
|
|
||||||
href="/register"
|
|
||||||
>Registrar Nueva</a
|
|
||||||
>
|
>
|
||||||
|
|
||||||
<a
|
<a
|
||||||
class="text-[#9dabb9] text-sm font-medium hover:text-white transition-colors"
|
class="text-[#9dabb9] text-sm font-medium hover:text-white transition-colors"
|
||||||
href="/logs"
|
href="/logs"
|
||||||
>Registros</a
|
>Registros</a
|
||||||
>
|
>
|
||||||
</nav>
|
</nav>
|
||||||
|
<button
|
||||||
|
class="hidden lg:flex cursor-pointer items-center justify-center rounded-lg h-9 px-4 bg-primary text-white text-sm font-bold transition-opacity hover:opacity-90"
|
||||||
|
onclick="window.location.href = '/register'"
|
||||||
|
>
|
||||||
|
<span>Nueva App</span>
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</header>
|
</header>
|
||||||
@@ -112,7 +113,7 @@
|
|||||||
<h1
|
<h1
|
||||||
class="text-white text-4xl font-black leading-tight tracking-[-0.033em]"
|
class="text-white text-4xl font-black leading-tight tracking-[-0.033em]"
|
||||||
>
|
>
|
||||||
Process Scan View
|
Visualización de escaneo de procesos
|
||||||
</h1>
|
</h1>
|
||||||
<p class="text-[#9dabb9] text-base font-normal">
|
<p class="text-[#9dabb9] text-base font-normal">
|
||||||
Monitoreo activo de procesos Node.js y Python.
|
Monitoreo activo de procesos Node.js y Python.
|
||||||
@@ -253,7 +254,7 @@
|
|||||||
loadingState.classList.remove('hidden');
|
loadingState.classList.remove('hidden');
|
||||||
emptyState.classList.add('hidden');
|
emptyState.classList.add('hidden');
|
||||||
|
|
||||||
const response = await fetch('http://localhost:8080/api/scan');
|
const response = await fetch('/api/scan');
|
||||||
if (!response.ok) throw new Error('Failed to fetch processes');
|
if (!response.ok) throw new Error('Failed to fetch processes');
|
||||||
|
|
||||||
const data = await response.json();
|
const data = await response.json();
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
<meta charset="utf-8" />
|
<meta charset="utf-8" />
|
||||||
<meta content="width=device-width, initial-scale=1.0" name="viewport" />
|
<meta content="width=device-width, initial-scale=1.0" name="viewport" />
|
||||||
<title>Agregar App Detectada - SIAX Monitor</title>
|
<title>Agregar App Detectada - SIAX Monitor</title>
|
||||||
|
<link rel="icon" type="image/svg+xml" href="/static/icon/favicon.svg" />
|
||||||
<script src="https://cdn.tailwindcss.com?plugins=forms,container-queries"></script>
|
<script src="https://cdn.tailwindcss.com?plugins=forms,container-queries"></script>
|
||||||
<link
|
<link
|
||||||
href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap"
|
href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap"
|
||||||
@@ -62,9 +63,11 @@
|
|||||||
<div
|
<div
|
||||||
class="size-8 bg-primary rounded-lg flex items-center justify-center"
|
class="size-8 bg-primary rounded-lg flex items-center justify-center"
|
||||||
>
|
>
|
||||||
<span class="material-symbols-outlined text-white"
|
<img
|
||||||
>monitoring</span
|
src="/static/icon/logo.png"
|
||||||
>
|
alt="Logo"
|
||||||
|
class="w-full h-full object-cover"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<h2
|
<h2
|
||||||
class="text-white text-lg font-bold leading-tight tracking-[-0.015em]"
|
class="text-white text-lg font-bold leading-tight tracking-[-0.015em]"
|
||||||
@@ -88,12 +91,7 @@
|
|||||||
<a
|
<a
|
||||||
class="text-primary text-sm font-medium border-b-2 border-primary pb-1"
|
class="text-primary text-sm font-medium border-b-2 border-primary pb-1"
|
||||||
href="/select"
|
href="/select"
|
||||||
>Agregar Detectada</a
|
>Selecionar Detectada</a
|
||||||
>
|
|
||||||
<a
|
|
||||||
class="text-[#9dabb9] text-sm font-medium hover:text-white transition-colors"
|
|
||||||
href="/register"
|
|
||||||
>Nueva App</a
|
|
||||||
>
|
>
|
||||||
<a
|
<a
|
||||||
class="text-[#9dabb9] text-sm font-medium hover:text-white transition-colors"
|
class="text-[#9dabb9] text-sm font-medium hover:text-white transition-colors"
|
||||||
@@ -101,6 +99,12 @@
|
|||||||
>Registros</a
|
>Registros</a
|
||||||
>
|
>
|
||||||
</nav>
|
</nav>
|
||||||
|
<button
|
||||||
|
class="hidden lg:flex cursor-pointer items-center justify-center rounded-lg h-9 px-4 bg-primary text-white text-sm font-bold transition-opacity hover:opacity-90"
|
||||||
|
onclick="window.location.href = '/register'"
|
||||||
|
>
|
||||||
|
<span>Nueva App</span>
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</header>
|
</header>
|
||||||
@@ -111,7 +115,7 @@
|
|||||||
<h1
|
<h1
|
||||||
class="text-white text-4xl font-black leading-tight tracking-[-0.033em]"
|
class="text-white text-4xl font-black leading-tight tracking-[-0.033em]"
|
||||||
>
|
>
|
||||||
Add Detected Application
|
Agregar la aplicación detectada
|
||||||
</h1>
|
</h1>
|
||||||
<p class="text-[#9dabb9] text-base font-normal">
|
<p class="text-[#9dabb9] text-base font-normal">
|
||||||
Selecciona un proceso detectado y configúralo para
|
Selecciona un proceso detectado y configúralo para
|
||||||
@@ -280,9 +284,7 @@
|
|||||||
const empty = document.getElementById("empty-state");
|
const empty = document.getElementById("empty-state");
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const response = await fetch(
|
const response = await fetch("/api/scan");
|
||||||
"http://localhost:8080/api/scan",
|
|
||||||
);
|
|
||||||
if (!response.ok)
|
if (!response.ok)
|
||||||
throw new Error("Failed to fetch processes");
|
throw new Error("Failed to fetch processes");
|
||||||
|
|
||||||
|
|||||||
BIN
web/static/icon/favicon.ico
Normal file
BIN
web/static/icon/favicon.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 41 KiB |
44
web/static/icon/favicon.svg
Normal file
44
web/static/icon/favicon.svg
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
<?xml version="1.0" standalone="no"?>
|
||||||
|
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
|
||||||
|
"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
|
||||||
|
<svg version="1.0" xmlns="http://www.w3.org/2000/svg"
|
||||||
|
width="128.000000pt" height="128.000000pt" viewBox="0 0 128.000000 128.000000"
|
||||||
|
preserveAspectRatio="xMidYMid meet">
|
||||||
|
|
||||||
|
<g transform="translate(0.000000,128.000000) scale(0.100000,-0.100000)"
|
||||||
|
fill="#000000" stroke="none">
|
||||||
|
<path d="M518 1244 c-75 -18 -188 -75 -239 -121 l-40 -36 -39 38 c-22 21 -42
|
||||||
|
36 -46 32 -3 -3 3 -33 14 -66 20 -58 20 -61 3 -83 -66 -84 -105 -212 -105
|
||||||
|
-343 0 -166 49 -288 164 -408 55 -58 71 -70 81 -60 18 18 64 16 79 -2 9 -11
|
||||||
|
35 -15 106 -15 l94 0 0 165 0 166 -24 -18 c-23 -17 -25 -25 -28 -128 l-3 -110
|
||||||
|
-45 -3 c-24 -2 -50 -8 -57 -14 -9 -7 -17 -7 -28 2 -17 14 -18 20 -5 40 7 12
|
||||||
|
13 12 33 1 13 -7 37 -11 53 -9 l29 3 3 87 c2 74 0 88 -13 88 -12 0 -15 -13
|
||||||
|
-15 -65 l0 -65 -45 0 c-25 0 -54 -6 -65 -12 -23 -15 -46 1 -37 26 5 12 18 13
|
||||||
|
61 9 l56 -6 0 47 c0 25 -4 46 -10 46 -5 0 -10 -11 -10 -25 0 -24 -3 -25 -60
|
||||||
|
-25 -32 0 -71 -5 -85 -12 -21 -9 -29 -9 -42 4 -14 15 -13 17 6 27 15 8 27 9
|
||||||
|
40 1 31 -16 111 -13 111 5 0 11 -11 15 -38 15 -103 0 -207 61 -257 151 -26 47
|
||||||
|
-30 64 -30 129 1 112 50 201 137 246 29 15 30 15 86 -37 66 -60 72 -69 42 -69
|
||||||
|
-13 0 -37 -9 -55 -20 -93 -58 -84 -193 17 -246 59 -31 144 -6 184 53 l22 33
|
||||||
|
22 -52 c12 -28 33 -68 46 -88 24 -36 24 -42 22 -200 l-3 -163 -96 2 c-72 2
|
||||||
|
-99 -1 -107 -12 -10 -12 -4 -18 35 -35 48 -20 138 -42 173 -42 13 0 17 5 13
|
||||||
|
20 -3 11 0 20 6 20 8 0 11 51 11 170 0 107 4 170 10 170 6 0 10 -61 10 -164 0
|
||||||
|
-108 4 -167 11 -172 6 -3 8 -15 5 -26 -4 -19 -1 -20 54 -14 71 8 148 30 174
|
||||||
|
49 37 27 9 37 -105 37 l-109 0 0 159 c0 96 4 162 10 166 7 4 10 -48 10 -149
|
||||||
|
l0 -156 93 0 c65 1 98 5 111 15 23 18 67 20 83 4 16 -16 43 2 106 71 97 108
|
||||||
|
147 240 148 390 0 125 -27 227 -87 322 l-27 42 18 55 c10 31 20 62 22 69 9 23
|
||||||
|
-16 12 -51 -23 -20 -19 -38 -35 -42 -35 -3 0 -25 16 -47 36 -52 44 -163 99
|
||||||
|
-242 119 -72 18 -200 18 -277 -1z m310 -90 c72 -15 187 -56 205 -74 5 -4 -40
|
||||||
|
-31 -100 -60 -89 -44 -121 -65 -182 -126 -52 -53 -80 -74 -99 -74 -17 0 -48
|
||||||
|
23 -106 78 -66 63 -99 85 -178 122 -54 25 -98 48 -98 52 0 11 160 69 230 83
|
||||||
|
91 18 237 18 328 -1z m325 -253 c52 -48 81 -117 81 -196 -1 -82 -17 -126 -70
|
||||||
|
-185 -51 -56 -120 -89 -200 -97 -49 -4 -64 -9 -60 -19 3 -8 -1 -14 -9 -14 -8
|
||||||
|
0 -15 9 -15 19 0 10 -7 21 -15 25 -12 4 -15 -4 -15 -44 0 -50 0 -50 33 -50 18
|
||||||
|
0 38 5 44 11 13 13 33 4 33 -16 0 -20 -20 -29 -33 -16 -6 6 -30 11 -54 11
|
||||||
|
l-43 0 0 56 c0 42 -4 60 -17 70 -10 7 -21 14 -25 14 -5 0 -8 -45 -8 -100 l0
|
||||||
|
-100 34 0 c19 0 38 5 41 10 12 20 35 10 35 -14 0 -32 -19 -44 -35 -23 -8 11
|
||||||
|
-27 17 -54 17 l-41 0 0 120 c0 66 -4 120 -9 120 -22 0 -18 35 13 101 l33 71
|
||||||
|
21 -36 c78 -132 275 -81 275 71 0 56 -25 91 -88 122 l-49 25 59 53 c58 52 59
|
||||||
|
53 84 37 14 -9 39 -28 54 -43z m-103 -510 c0 -13 -27 -21 -45 -15 -25 10 -17
|
||||||
|
24 15 24 17 0 30 -4 30 -9z"/>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 2.8 KiB |
BIN
web/static/icon/logo.png
Normal file
BIN
web/static/icon/logo.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 11 KiB |
BIN
web/static/icon/logo_telco128.png
Normal file
BIN
web/static/icon/logo_telco128.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 5.7 KiB |
@@ -4,6 +4,7 @@
|
|||||||
<meta charset="utf-8" />
|
<meta charset="utf-8" />
|
||||||
<meta content="width=device-width, initial-scale=1.0" name="viewport" />
|
<meta content="width=device-width, initial-scale=1.0" name="viewport" />
|
||||||
<title>Éxito - SIAX Monitor</title>
|
<title>Éxito - SIAX Monitor</title>
|
||||||
|
<link rel="icon" type="image/svg+xml" href="/static/icon/favicon.svg" />
|
||||||
<script src="https://cdn.tailwindcss.com?plugins=forms,container-queries"></script>
|
<script src="https://cdn.tailwindcss.com?plugins=forms,container-queries"></script>
|
||||||
<link
|
<link
|
||||||
href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap"
|
href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap"
|
||||||
@@ -62,9 +63,11 @@
|
|||||||
<div
|
<div
|
||||||
class="size-8 bg-primary rounded-lg flex items-center justify-center"
|
class="size-8 bg-primary rounded-lg flex items-center justify-center"
|
||||||
>
|
>
|
||||||
<span class="material-symbols-outlined text-white"
|
<img
|
||||||
>monitoring</span
|
src="/static/icon/logo.png"
|
||||||
>
|
alt="Logo"
|
||||||
|
class="w-full h-full object-cover"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<h2
|
<h2
|
||||||
class="text-white text-lg font-bold leading-tight tracking-[-0.015em]"
|
class="text-white text-lg font-bold leading-tight tracking-[-0.015em]"
|
||||||
@@ -91,13 +94,7 @@
|
|||||||
class="text-[#9dabb9] text-sm font-medium hover:text-white transition-colors"
|
class="text-[#9dabb9] text-sm font-medium hover:text-white transition-colors"
|
||||||
href="/select"
|
href="/select"
|
||||||
>
|
>
|
||||||
Agregar Detectada
|
Selecionar Detectada
|
||||||
</a>
|
|
||||||
<a
|
|
||||||
class="text-[#9dabb9] text-sm font-medium hover:text-white transition-colors"
|
|
||||||
href="/register"
|
|
||||||
>
|
|
||||||
Nueva App
|
|
||||||
</a>
|
</a>
|
||||||
<a
|
<a
|
||||||
class="text-[#9dabb9] text-sm font-medium hover:text-white transition-colors"
|
class="text-[#9dabb9] text-sm font-medium hover:text-white transition-colors"
|
||||||
@@ -106,6 +103,12 @@
|
|||||||
Registros
|
Registros
|
||||||
</a>
|
</a>
|
||||||
</nav>
|
</nav>
|
||||||
|
<button
|
||||||
|
class="hidden lg:flex cursor-pointer items-center justify-center rounded-lg h-9 px-4 bg-primary text-white text-sm font-bold transition-opacity hover:opacity-90"
|
||||||
|
onclick="window.location.href = '/register'"
|
||||||
|
>
|
||||||
|
<span>Nueva App</span>
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</header>
|
</header>
|
||||||
|
|||||||
Reference in New Issue
Block a user