✨ Nuevas funcionalidades: - API REST unificada en puerto 8080 (eliminado CORS) - WebSocket para logs en tiempo real desde journalctl - Integración completa con systemd para gestión de servicios - Escaneo automático de procesos Node.js y Python - Rate limiting (1 operación/segundo por app) - Interface web moderna con Tailwind CSS (tema oscuro) - Documentación API estilo Swagger completamente en español 🎨 Interface Web (todas las páginas en español): - Dashboard con estadísticas en tiempo real - Visor de escaneo de procesos con filtros - Formulario de registro de aplicaciones con variables de entorno - Visor de logs en tiempo real con WebSocket y sidebar - Página de selección de apps detectadas - Documentación completa de API REST 🏗️ Arquitectura: - Módulo models: ServiceConfig, ManagedApp, AppStatus - Módulo systemd: wrapper de systemctl, generador de .service, parser - Módulo orchestrator: AppManager, LifecycleManager con validaciones - Módulo api: handlers REST, WebSocket manager, DTOs - Servidor unificado en puerto 8080 (Web + API + WS) 🔧 Mejoras técnicas: - Eliminación de CORS mediante servidor unificado - Separación clara frontend/backend con carga dinámica - Thread-safe con Arc<DashMap> para estado compartido - Reconciliación de estados: sysinfo vs systemd - Validaciones de paths, usuarios y configuraciones - Manejo robusto de errores con thiserror 📝 Documentación: - README.md actualizado con arquitectura completa - EJEMPLOS.md con casos de uso detallados - ESTADO_PROYECTO.md con progreso de Fase 4 - API docs interactiva en /api-docs - Script de despliegue mejorado con health checks 🚀 Producción: - Deployment script con validaciones - Health checks y rollback capability - Configuración de sudoers para systemctl - Hardening de seguridad en servicios systemd
505 lines
11 KiB
Markdown
505 lines
11 KiB
Markdown
# Ejemplos Prácticos de Uso - SIAX Monitor
|
|
|
|
## Tabla de Contenidos
|
|
|
|
1. [Instalación](#instalación)
|
|
2. [Gestión de Aplicaciones Node.js](#nodejs)
|
|
3. [Gestión de Aplicaciones Python](#python)
|
|
4. [Monitoreo y Logs](#monitoreo)
|
|
5. [Casos de Uso Reales](#casos-de-uso)
|
|
6. [Troubleshooting](#troubleshooting)
|
|
|
|
---
|
|
|
|
## Instalación
|
|
|
|
### Instalación Completa
|
|
|
|
```bash
|
|
# Clonar el proyecto
|
|
git clone <repo-url>
|
|
cd siax_monitor
|
|
|
|
# Ejecutar script de deployment
|
|
sudo ./desplegar_agent.sh
|
|
|
|
# Verificar instalación
|
|
sudo systemctl status siax-agent
|
|
```
|
|
|
|
### Verificar que todo funciona
|
|
|
|
```bash
|
|
# Verificar servicio
|
|
curl http://localhost:8081/api/apps
|
|
|
|
# Debe responder:
|
|
# {"success":true,"data":{"apps":[],"total":0}}
|
|
```
|
|
|
|
---
|
|
|
|
## <a name="nodejs"></a>Gestión de Aplicaciones Node.js
|
|
|
|
### Ejemplo 1: API Express Básica
|
|
|
|
```bash
|
|
# Registrar aplicación
|
|
curl -X POST http://localhost:8081/api/apps \
|
|
-H "Content-Type: application/json" \
|
|
-d '{
|
|
"app_name": "api-express",
|
|
"script_path": "/home/nodejs/api-express/server.js",
|
|
"working_directory": "/home/nodejs/api-express",
|
|
"user": "nodejs",
|
|
"environment": {
|
|
"PORT": "3000",
|
|
"NODE_ENV": "production"
|
|
},
|
|
"restart_policy": "always",
|
|
"app_type": "nodejs",
|
|
"description": "API REST con Express"
|
|
}'
|
|
|
|
# Iniciar aplicación
|
|
curl -X POST http://localhost:8081/api/apps/api-express/start
|
|
|
|
# Ver estado
|
|
curl http://localhost:8081/api/apps/api-express/status | jq
|
|
```
|
|
|
|
### Ejemplo 2: Aplicación Next.js
|
|
|
|
```bash
|
|
curl -X POST http://localhost:8081/api/apps \
|
|
-H "Content-Type: application/json" \
|
|
-d '{
|
|
"app_name": "frontend-nextjs",
|
|
"script_path": "/var/www/frontend/.next/standalone/server.js",
|
|
"working_directory": "/var/www/frontend",
|
|
"user": "www-data",
|
|
"environment": {
|
|
"PORT": "3000",
|
|
"NODE_ENV": "production",
|
|
"HOSTNAME": "0.0.0.0"
|
|
},
|
|
"restart_policy": "always",
|
|
"app_type": "nodejs"
|
|
}'
|
|
|
|
curl -X POST http://localhost:8081/api/apps/frontend-nextjs/start
|
|
```
|
|
|
|
### Ejemplo 3: Worker de Background (Bull Queue)
|
|
|
|
```bash
|
|
curl -X POST http://localhost:8081/api/apps \
|
|
-H "Content-Type: application/json" \
|
|
-d '{
|
|
"app_name": "queue-worker",
|
|
"script_path": "/opt/workers/queue-worker/index.js",
|
|
"working_directory": "/opt/workers/queue-worker",
|
|
"user": "workers",
|
|
"environment": {
|
|
"REDIS_URL": "redis://localhost:6379",
|
|
"CONCURRENCY": "5"
|
|
},
|
|
"restart_policy": "on-failure",
|
|
"app_type": "nodejs",
|
|
"description": "Worker de procesamiento de colas"
|
|
}'
|
|
```
|
|
|
|
---
|
|
|
|
## <a name="python"></a>Gestión de Aplicaciones Python
|
|
|
|
### Ejemplo 1: API FastAPI
|
|
|
|
```bash
|
|
curl -X POST http://localhost:8081/api/apps \
|
|
-H "Content-Type: application/json" \
|
|
-d '{
|
|
"app_name": "ml-api",
|
|
"script_path": "/home/python/ml-api/main.py",
|
|
"working_directory": "/home/python/ml-api",
|
|
"user": "python",
|
|
"environment": {
|
|
"PORT": "8000",
|
|
"WORKERS": "4",
|
|
"PYTHONUNBUFFERED": "1"
|
|
},
|
|
"restart_policy": "always",
|
|
"app_type": "python",
|
|
"description": "API de Machine Learning"
|
|
}'
|
|
|
|
curl -X POST http://localhost:8081/api/apps/ml-api/start
|
|
```
|
|
|
|
**Nota:** Asegúrate de que tu `main.py` tiene un servidor ASGI:
|
|
|
|
```python
|
|
# main.py
|
|
from fastapi import FastAPI
|
|
import uvicorn
|
|
|
|
app = FastAPI()
|
|
|
|
@app.get("/")
|
|
def read_root():
|
|
return {"Hello": "World"}
|
|
|
|
if __name__ == "__main__":
|
|
import os
|
|
port = int(os.getenv("PORT", 8000))
|
|
workers = int(os.getenv("WORKERS", 4))
|
|
uvicorn.run("main:app", host="0.0.0.0", port=port, workers=workers)
|
|
```
|
|
|
|
### Ejemplo 2: Script de Data Processing
|
|
|
|
```bash
|
|
curl -X POST http://localhost:8081/api/apps \
|
|
-H "Content-Type: application/json" \
|
|
-d '{
|
|
"app_name": "data-processor",
|
|
"script_path": "/opt/scripts/data-processor/processor.py",
|
|
"working_directory": "/opt/scripts/data-processor",
|
|
"user": "dataops",
|
|
"environment": {
|
|
"DB_HOST": "localhost",
|
|
"DB_PORT": "5432",
|
|
"LOG_LEVEL": "INFO"
|
|
},
|
|
"restart_policy": "on-failure",
|
|
"app_type": "python"
|
|
}'
|
|
```
|
|
|
|
---
|
|
|
|
## <a name="monitoreo"></a>Monitoreo y Logs
|
|
|
|
### Ver logs en tiempo real con WebSocket
|
|
|
|
#### Opción 1: JavaScript (Browser)
|
|
|
|
```javascript
|
|
// Conectar a logs
|
|
const ws = new WebSocket('ws://localhost:8081/ws/logs/api-express');
|
|
|
|
ws.onopen = () => {
|
|
console.log('Conectado a logs de api-express');
|
|
};
|
|
|
|
ws.onmessage = (event) => {
|
|
console.log('LOG:', event.data);
|
|
// Mostrar en UI
|
|
document.getElementById('logs').innerHTML += event.data + '<br>';
|
|
};
|
|
|
|
ws.onerror = (error) => {
|
|
console.error('Error:', error);
|
|
};
|
|
|
|
ws.onclose = () => {
|
|
console.log('Desconectado');
|
|
};
|
|
```
|
|
|
|
#### Opción 2: wscat (CLI)
|
|
|
|
```bash
|
|
# Instalar wscat
|
|
npm install -g wscat
|
|
|
|
# Conectar a logs
|
|
wscat -c ws://localhost:8081/ws/logs/api-express
|
|
```
|
|
|
|
#### Opción 3: Python
|
|
|
|
```python
|
|
import websocket
|
|
import json
|
|
|
|
def on_message(ws, message):
|
|
try:
|
|
data = json.loads(message)
|
|
print(f"[{data.get('timestamp', 'N/A')}] {data.get('MESSAGE', message)}")
|
|
except:
|
|
print(message)
|
|
|
|
def on_error(ws, error):
|
|
print(f"Error: {error}")
|
|
|
|
def on_close(ws, close_status_code, close_msg):
|
|
print("Conexión cerrada")
|
|
|
|
def on_open(ws):
|
|
print("Conectado a logs")
|
|
|
|
ws = websocket.WebSocketApp(
|
|
"ws://localhost:8081/ws/logs/api-express",
|
|
on_open=on_open,
|
|
on_message=on_message,
|
|
on_error=on_error,
|
|
on_close=on_close
|
|
)
|
|
|
|
ws.run_forever()
|
|
```
|
|
|
|
### Verificar estado de múltiples apps
|
|
|
|
```bash
|
|
#!/bin/bash
|
|
# check-all-apps.sh
|
|
|
|
echo "Estado de todas las aplicaciones:"
|
|
echo "=================================="
|
|
|
|
# Obtener lista de apps
|
|
apps=$(curl -s http://localhost:8081/api/apps | jq -r '.data.apps[]')
|
|
|
|
for app in $apps; do
|
|
status=$(curl -s http://localhost:8081/api/apps/$app/status | jq -r '.data.status')
|
|
pid=$(curl -s http://localhost:8081/api/apps/$app/status | jq -r '.data.pid')
|
|
cpu=$(curl -s http://localhost:8081/api/apps/$app/status | jq -r '.data.cpu_usage')
|
|
mem=$(curl -s http://localhost:8081/api/apps/$app/status | jq -r '.data.memory_usage')
|
|
|
|
printf "%-20s [%s] PID: %-6s CPU: %-6s RAM: %s\n" "$app" "$status" "$pid" "$cpu" "$mem"
|
|
done
|
|
```
|
|
|
|
---
|
|
|
|
## <a name="casos-de-uso"></a>Casos de Uso Reales
|
|
|
|
### Caso 1: Microservicios
|
|
|
|
```bash
|
|
# Registrar todos los microservicios
|
|
|
|
# Auth Service
|
|
curl -X POST http://localhost:8081/api/apps -H "Content-Type: application/json" -d '{
|
|
"app_name": "auth-service",
|
|
"script_path": "/services/auth/index.js",
|
|
"working_directory": "/services/auth",
|
|
"user": "services",
|
|
"environment": {"PORT": "3001", "NODE_ENV": "production"},
|
|
"restart_policy": "always",
|
|
"app_type": "nodejs"
|
|
}'
|
|
|
|
# Users Service
|
|
curl -X POST http://localhost:8081/api/apps -H "Content-Type: application/json" -d '{
|
|
"app_name": "users-service",
|
|
"script_path": "/services/users/index.js",
|
|
"working_directory": "/services/users",
|
|
"user": "services",
|
|
"environment": {"PORT": "3002", "NODE_ENV": "production"},
|
|
"restart_policy": "always",
|
|
"app_type": "nodejs"
|
|
}'
|
|
|
|
# Orders Service
|
|
curl -X POST http://localhost:8081/api/apps -H "Content-Type: application/json" -d '{
|
|
"app_name": "orders-service",
|
|
"script_path": "/services/orders/index.js",
|
|
"working_directory": "/services/orders",
|
|
"user": "services",
|
|
"environment": {"PORT": "3003", "NODE_ENV": "production"},
|
|
"restart_policy": "always",
|
|
"app_type": "nodejs"
|
|
}'
|
|
|
|
# Iniciar todos
|
|
for service in auth-service users-service orders-service; do
|
|
curl -X POST http://localhost:8081/api/apps/$service/start
|
|
echo "Iniciado: $service"
|
|
done
|
|
```
|
|
|
|
### Caso 2: Deployment con Script
|
|
|
|
```bash
|
|
#!/bin/bash
|
|
# deploy-app.sh
|
|
|
|
APP_NAME=$1
|
|
APP_PATH=$2
|
|
PORT=$3
|
|
|
|
if [ -z "$APP_NAME" ] || [ -z "$APP_PATH" ] || [ -z "$PORT" ]; then
|
|
echo "Uso: ./deploy-app.sh <nombre> <path> <puerto>"
|
|
exit 1
|
|
fi
|
|
|
|
echo "Desplegando $APP_NAME..."
|
|
|
|
# Registrar app
|
|
curl -X POST http://localhost:8081/api/apps \
|
|
-H "Content-Type: application/json" \
|
|
-d "{
|
|
\"app_name\": \"$APP_NAME\",
|
|
\"script_path\": \"$APP_PATH/index.js\",
|
|
\"working_directory\": \"$APP_PATH\",
|
|
\"user\": \"nodejs\",
|
|
\"environment\": {\"PORT\": \"$PORT\", \"NODE_ENV\": \"production\"},
|
|
\"restart_policy\": \"always\",
|
|
\"app_type\": \"nodejs\"
|
|
}"
|
|
|
|
echo ""
|
|
echo "Iniciando $APP_NAME..."
|
|
curl -X POST http://localhost:8081/api/apps/$APP_NAME/start
|
|
|
|
echo ""
|
|
echo "Estado de $APP_NAME:"
|
|
curl http://localhost:8081/api/apps/$APP_NAME/status | jq
|
|
```
|
|
|
|
**Uso:**
|
|
```bash
|
|
./deploy-app.sh mi-nueva-app /opt/apps/mi-nueva-app 3004
|
|
```
|
|
|
|
### Caso 3: Rolling Restart
|
|
|
|
```bash
|
|
#!/bin/bash
|
|
# rolling-restart.sh - Reinicia servicios uno por uno
|
|
|
|
APPS=("auth-service" "users-service" "orders-service")
|
|
|
|
for app in "${APPS[@]}"; do
|
|
echo "Reiniciando $app..."
|
|
curl -X POST http://localhost:8081/api/apps/$app/restart
|
|
|
|
# Esperar que esté activo
|
|
sleep 5
|
|
|
|
status=$(curl -s http://localhost:8081/api/apps/$app/status | jq -r '.data.status')
|
|
if [ "$status" = "running" ]; then
|
|
echo "✅ $app reiniciado correctamente"
|
|
else
|
|
echo "❌ ERROR: $app no está corriendo"
|
|
exit 1
|
|
fi
|
|
|
|
# Delay entre reinici os
|
|
sleep 10
|
|
done
|
|
|
|
echo "✅ Rolling restart completado"
|
|
```
|
|
|
|
---
|
|
|
|
## <a name="troubleshooting"></a>Troubleshooting
|
|
|
|
### Problema: App no inicia
|
|
|
|
```bash
|
|
# 1. Ver estado en systemd
|
|
sudo systemctl status mi-app.service
|
|
|
|
# 2. Ver logs de systemd
|
|
sudo journalctl -u mi-app.service -n 100
|
|
|
|
# 3. Ver logs en tiempo real
|
|
wscat -c ws://localhost:8081/ws/logs/mi-app
|
|
|
|
# 4. Verificar permisos del archivo
|
|
ls -la /path/to/script.js
|
|
|
|
# 5. Probar ejecución manual
|
|
sudo -u nodejs node /path/to/script.js
|
|
```
|
|
|
|
### Problema: Rate limit excedido
|
|
|
|
```bash
|
|
# Error: "Rate limit excedido para: mi-app"
|
|
# Solución: Esperar 1 segundo entre operaciones
|
|
|
|
curl -X POST http://localhost:8081/api/apps/mi-app/restart
|
|
sleep 2 # Esperar antes de la siguiente operación
|
|
curl -X POST http://localhost:8081/api/apps/otra-app/restart
|
|
```
|
|
|
|
### Problema: WebSocket no conecta
|
|
|
|
```bash
|
|
# Verificar que el puerto está abierto
|
|
sudo netstat -tlnp | grep 8081
|
|
|
|
# Verificar que hay menos de 5 conexiones activas
|
|
# (límite por app)
|
|
|
|
# Probar con curl primero
|
|
curl http://localhost:8081/api/apps
|
|
```
|
|
|
|
### Problema: Permisos sudo
|
|
|
|
```bash
|
|
# Verificar configuración
|
|
sudo cat /etc/sudoers.d/siax-agent
|
|
|
|
# Probar manualmente
|
|
sudo -u siax-agent sudo systemctl status siax-agent
|
|
|
|
# Si falla, re-ejecutar deployment
|
|
sudo ./desplegar_agent.sh
|
|
```
|
|
|
|
---
|
|
|
|
## Scripts Útiles
|
|
|
|
### Monitor Dashboard (Bash)
|
|
|
|
```bash
|
|
#!/bin/bash
|
|
# dashboard.sh - Dashboard simple en terminal
|
|
|
|
watch -n 2 '
|
|
echo "=== SIAX Monitor Dashboard ==="
|
|
echo ""
|
|
curl -s http://localhost:8081/api/apps | jq -r ".data.apps[]" | while read app; do
|
|
status=$(curl -s http://localhost:8081/api/apps/$app/status)
|
|
echo "$status" | jq -r "\"[\(.data.status)] \(.data.name) - PID: \(.data.pid) CPU: \(.data.cpu_usage) RAM: \(.data.memory_usage)\""
|
|
done
|
|
'
|
|
```
|
|
|
|
### Auto-Restart on Crash
|
|
|
|
```bash
|
|
#!/bin/bash
|
|
# auto-restart.sh - Reinicia apps crasheadas automáticamente
|
|
|
|
while true; do
|
|
apps=$(curl -s http://localhost:8081/api/apps | jq -r '.data.apps[]')
|
|
|
|
for app in $apps; do
|
|
status=$(curl -s http://localhost:8081/api/apps/$app/status | jq -r '.data.status')
|
|
|
|
if [ "$status" = "crashed" ] || [ "$status" = "failed" ]; then
|
|
echo "[$(date)] Detectado $app en estado $status, reiniciando..."
|
|
curl -X POST http://localhost:8081/api/apps/$app/restart
|
|
sleep 2
|
|
fi
|
|
done
|
|
|
|
sleep 30
|
|
done
|
|
```
|
|
|
|
---
|
|
|
|
¡Estos ejemplos cubren los casos de uso más comunes! Para más información, consulta el `README.md`.
|