Panel de cron, logs y alertas (Dabra)¶
Implementa la sección 4 de ../RECOMENDACIONES_GLOBAL.md: estado de jobs, historial y tendencia, visor de logs, alertas con niveles configurables, reglas por patrón/código/job con escalado, cron (lectura y validación), destinatarios, ejecutar ahora con rango y bitácora de cambios.
Un solo contenedor: FastAPI + SQLite (WAL) + plantillas Jinja, sin JS externo ni CDN. El mismo docker-compose.yml sirve en Windows (Docker Desktop) y en Linux.
Probarlo en Windows (local)¶
cd <ruta de Windows>
copy .env.example .env # completar SECRET_KEY, ADMIN_PASSWORD y API_TOKEN (ver comentarios del archivo)
docker compose up -d --build
Abrir http://localhost:8080 e ingresar con ADMIN_USER / ADMIN_PASSWORD. Los jobs demo_ok (cada 2 min) y demo_error (cada 5 min) ya vienen activos para ver estado, logs y alertas; elimínelos o desactívelos cuando no hagan falta (job → Configuración, o activo desmarcado).
Comandos útiles: docker compose logs -f panel · docker compose down (conserva datos) · docker compose down -v (borra base y logs).
Pruebas automáticas (dentro de la imagen, 16 tests):
docker run --rm -v "${PWD}\tests:/app/tests:ro" -w /app dabra-panel:latest python -m pytest -q -p no:cacheprovider tests
Si
docker buildfalla conCERTIFICATE_VERIFY_FAILED: un antivirus o proxy inspecciona HTTPS (en esta PC es AVG Web/Mail Shield). Ponga la CA raíz en formato PEM comocerts/*.crty reconstruya: el Dockerfile la instala sin desactivar verificaciones. En el servidor Linux no hace falta (certs/queda vacía). No versione esos.crt.
Desplegar en el servidor Linux¶
- Copiar la carpeta (sin
.envnicerts/*.crt) o construir/subir la imagen:docker build -t dabra-panel .→docker save/ registry. - Crear
.enven el servidor con valores nuevos (chmod 600 .env).PANEL_PORT=8080,COOKIE_SECURE=truesi va tras HTTPS. - Si cron del host va a lanzar los jobs con el wrapper, comparta los logs:
LOGS_HOST_DIR=/var/log/dabraen.env(carpeta existente; el contenedor corre con UID 10001,chown 10001 /var/log/dabraochmod g+wsegún su política). docker compose up -d --build. El contenedor tienerestart: unless-stoppedy healthcheck.- Poner nginx delante (TLS y, si desean, SSO por proxy). El panel ya pide login propio con roles; no lo exponga sin HTTPS.
Antes de ir a producción: SECRET_KEY y API_TOKEN únicos, contraseña del admin cambiada desde Administración, y usuarios con el rol mínimo necesario.
Dos formas de ejecutar los jobs¶
| Modo | Cuándo | Cómo |
|---|---|---|
| Cron externo + wrapper (recomendado para los jobs reales) | Los scripts tienen dependencias propias (pandas, ODBC, SFTP…) y viven en el host o en su propio contenedor | clients/run_job.sh <job> desde /etc/cron.d/dabra: flock, timeout, log por corrida y reporte a POST /api/runs. El panel detecta corridas faltantes por la expresión cron cargada |
| Interno | Jobs livianos o de prueba | Marcar Lo ejecuta el panel y definir comando; el planificador del contenedor lo lanza, sin shell, con timeout y bloqueo por job |
Las dependencias de los scripts de negocio no están en esta imagen a propósito. Para ejecutarlos dentro del panel, derive una imagen (FROM dabra-panel, pip install ..., msodbcsql18 si usa ODBC) y monte el código en ./jobs (→ /opt/dabra/jobs).
Wrapper en Linux¶
/etc/dabra/panel.env # chmod 600
DABRA_PANEL_URL=http://127.0.0.1:8080
DABRA_PANEL_TOKEN=<API_TOKEN del panel>
DABRA_LOG_DIR=/var/log/dabra
/etc/dabra/jobs.d/nike.cmd # una línea: /opt/dabra/venv/bin/python /opt/dabra/nike/main.py
Instalar con install -m 755 clients/run_job.sh /opt/dabra/bin/. El nombre del job debe coincidir con el cargado en el panel (Cron): ahí se activa el control de corrida faltante.
Alertas desde los scripts¶
from dabra_alerts import alert # clients/dabra_alerts.py (solo librería estándar)
alert("SFTP_UPLOAD_FAILED", job="nike", detail="timeout tras 3 intentos", context={"fecha": "2026-10-06"})
El código es estable; el nivel lo decide Reglas (job+código → código → catálogo → intermedio). Un script sin modificar también genera alertas: por exit code, timeout, duración > 2× la mediana y reglas por patrón sobre su log.
Qué hace cada alerta¶
| Nivel | Notificación |
|---|---|
| crítico | Inmediata (mail/Telegram a los destinatarios con nivel ≤ crítico) y se repite cada CRITICAL_REPEAT_MIN hasta reconocer |
| urgente | Inmediata, una vez |
| intermedio | Resumen diario a las DIGEST_HOUR |
| bajo | Solo en el panel |
Sin SMTP_*/TELEGRAM_BOT_TOKEN las alertas igualmente se registran y se ven en el panel (el resultado de cada intento queda en la alerta). Silenciar suprime la notificación de nuevas alertas del mismo job+código durante el plazo; escalado: una regla con «N días» sube un nivel si el código ocurrió N días seguidos.
Códigos generados por el panel: EXIT_NONZERO, JOB_TIMEOUT, RUN_MISSING, RUN_INTERRUPTED, LOCK_HELD, DURATION_HIGH, AUDIT_MISSING, AUDIT_ERROR. El resto del catálogo (seed/alert_catalog.json) está pre-cargado desde los RECOMENDACIONES.md, y las reglas de ejemplo en seed/alert_rules.json. La carga inicial solo ocurre con tablas vacías; después se edita todo desde el panel.
Auditoría existente (ods.tbl_control_procesos)¶
Con AUDIT_DB_URL=mssql+pymssql://usuario:clave@servidor/base (usuario solo lectura), cada job con Prefijo de ID cargado:
- muestra las últimas filas en su detalle;
- si el job terminó OK y 10 min después no hay fila →
AUDIT_MISSING; si la fila tieneStatus=Error→AUDIT_ERROR.
Hoy solo nike trae el prefijo precargado; los demás IDs son inconsistentes (ver recomendaciones, ítem 25) y deben completarse a mano.
Seguridad¶
- Login con PBKDF2, sesión firmada (12 h,
SameSite=Lax), CSRF en todos los formularios, roles viewer/operator/admin. API de wrappers conX-API-Token(comparación en tiempo constante). - Los logs solo se leen bajo
LOG_DIR(lista blanca, rutas resueltas); los nombres de job y las fechas se validan; los comandos se ejecutan sin shell. - Editar el comando de un job equivale a ejecutar código en el contenedor: solo admin y queda en la bitácora. «Ejecutar ahora» exige operator.
- Un solo worker de uvicorn (el planificador vive en el proceso). No escale a varios workers/réplicas sin separar el planificador.
- El contenedor corre sin root. Los secretos van solo en
.env/variables de entorno; el token de Telegram nunca se escribe en los logs.
Límites conocidos de esta versión (MVP)¶
- Zona horaria única para todo el panel (
TZ). Cron solo en lectura: el panel no edita/etc/cron.d. - No hay SSO propio; use el login local o delegue en el proxy.
- Edición de reglas sin vista previa de regex contra logs reales (la sintaxis sí se valida al guardar).
- Si el planificador interno reinicia, las corridas en curso se cierran como
RUN_INTERRUPTED; no hay catch-up de ejecuciones perdidas (para eso estáRUN_MISSING). - Pendiente de validar con datos reales:
AUDIT_DB_URL(sin servidor de pruebas aquí) y el envío SMTP/Telegram (sin credenciales).
Estructura¶
app/ main, routers (ui, api), scheduler, alerts, logs, notify, audit_source, models, templates/
clients/ run_job.sh (wrapper de cron) · dabra_alerts.py
seed/ jobs, catálogo y reglas iniciales (JSON)
jobs_demo/ dos jobs de prueba
tests/ pytest (16 casos)
certs/ CAs extra opcionales para el build
Fuente: repositorio panel-cron-alertas, versión 8901ca2. Página generada con tools/publicar_docs.py.