Versión: 1.6 Última actualización: 25-08-2026 Componentes: Local Agent 2.21.2 + SaaS v1.85.2
1. Resumen
Sentinel Mode extiende el CreaRack Local Agent con monitoreo continuo 24/7 desde el equipo local del ingeniero, independientemente de si la aplicación SaaS está abierta. Los datos se almacenan localmente en SQLite y se sincronizan con VictoriaMetrics en el SaaS cuando hay conectividad.
Valor para el usuario: Datos de monitoreo completos sin interrupciones — el ingeniero puede irse a comer, a casa o de vacaciones y al volver encuentra datos continuos de todo el periodo.
Cadencia por target (v1.42.0 · Agent 2.13.0, task #175): desde julio 2026 los intervalos de sondeo NO son globales. Cada MonitoringTarget tiene su interval_seconds (dial “Polling cadence” en la Edit Card: 15 s / 30 s / 1 min / 5 min, default 60 s) y los loops del Sentinel lo respetan por target, con suelos por protocolo (ver §4.2).
2. Arquitectura
2.1 Diagrama General
┌──────────────────────────────────────────────────────────────────┐
│ EQUIPO LOCAL DEL INGENIERO │
│ │
│ CreaRackAgent.exe (servicio Windows / auto-start) │
│ ┌────────────────────────────────────────────────────────────┐ │
│ │ SentinelScheduler (tick 5s · due_targets por cadencia) │ │
│ │ ├── Ping loop (cadencia del target, clamp 15-30s) │ │
│ │ ├── SNMP bandwidth (cadencia del target, suelo 15s) │ │
│ │ ├── SNMP fast (cadencia del target, suelo 15s) │ │
│ │ └── SNMP extras (CPU/mem/temp — suelo 60s) │ │
│ ├────────────────────────────────────────────────────────────┤ │
│ │ Store (SQLite WAL) │ │
│ │ ├── metrics.db (~500 MB/mes para 50 targets) │ │
│ │ ├── Retención: 30 días (auto-purge) │ │
│ │ └── 3 tablas: metrics, targets, config │ │
│ ├────────────────────────────────────────────────────────────┤ │
│ │ SyncManager │ │
│ │ ├── Online → push tiempo real + buffer local │ │
│ │ ├── Offline → solo buffer local │ │
│ │ └── Reconexión → bulk drain acumulado │ │
│ └────────────────────────────────────────────────────────────┘ │
└──────────────────┬───────────────────────────────────────────────┘
│ REST (push metrics, pull targets)
▼
┌──────────────────────────────────────────────────────────────────┐
│ SAAS (CreaRack Cloud) │
│ │
│ ┌─────────────────────┐ ┌──────────────────────────────────┐│
│ │ Django API │ │ VictoriaMetrics ││
│ │ ├── /agent/metrics/ │───▶│ (almacén definitivo) ││
│ │ │ bulk │ │ Retención: 180 días ││
│ │ ├── /agent/register │ └──────────────────────────────────┘│
│ │ ├── /agent/auth │ │
│ │ └── sentinel-config │ ┌──────────────────────────────────┐│
│ └─────────────────────┘ │ Observatory UI ││
│ │ ├── Header dot (estado) ││
│ ┌─────────────────────┐ │ ├── Mode label + Change ││
│ │ Valkey │ │ ├── Recovery protocol ││
│ │ └── sentinel config │ │ └── Health polling 10s ││
│ └─────────────────────┘ └──────────────────────────────────┘│
└──────────────────────────────────────────────────────────────────┘
2.2 Flujo de Datos
┌──────────────┐
│ Targets list │ (del SaaS al conectar, o push desde Observatory)
└──────┬───────┘
▼
┌──────────────┐
│ Loops │ ping / SNMP (bandwidth · fast · extras)
└──────┬───────┘
▼
┌──────────────┐
┌────▶│ SQLite local │ (siempre escribe)
│ └──────────────┘
│ │
¿Conectado? │ Reconexión detectada
│ ▼
│ ┌──────────────┐
└────▶│ SyncManager │
└──────┬───────┘
│ POST /agent/metrics/bulk (batches de 1000)
▼
┌──────────────┐
│ VictoriaM. │
└──────────────┘
Los checks HTTP ya no corren en el Agente: los tipos
http_status/http_latencyse conservan en el Store solo para purgar datos legacy.
3. Modos de Operación
3.1 Elección del Usuario
El usuario elige el modo desde el Observatory sidebar. La configuración se persiste en Valkey (sentinel_mode_{org_id}). El cambio requiere confirmación explícita en ambas direcciones.
| Modo | Nombre UI | Comportamiento | Almacenamiento |
|---|---|---|---|
| cloud | “Cloud Only” | Solo monitorea cuando la app está abierta | Solo VM en SaaS |
| sentinel | “24/7 Sentinel” | El agente monitorea siempre, sincroniza cuando puede | SQLite local + sync a VM |
3.2 Transición entre Modos
- Cloud → Sentinel:
confirm()obligatorio → config guardada en Valkey → agente recibe targets vía/sentinel/start→ scheduler inicia → auto-link SaaS silencioso - Aviso de estabilidad (v1.49.0): antes del
confirm()de Cloud→Sentinel,requestModeChange(ObservatorySentinel.js) consultaGET /api/agent/fleet; si el Primary acumula ≥3 desconexiones largas en ~7 días (disconnects_7d, ver §10.1), el confirm añade la advertencia con el conteo (“lost connection N times in the last 7 days… install on a machine that stays on”). Sin permisofleet:viewo sin datos, degrada en silencio al confirm de siempre. - Sentinel → Cloud:
confirm()obligatorio → agente detiene scheduler vía/sentinel/stop→ último sync → vuelve a Cloud Only - Sin pérdida de datos: Los datos en SQLite local se mantienen independientemente del cambio de modo
3.3 Indicadores UI
Header Dot (siempre visible, incluso con panel colapsado)
| Modo | Agente | Sync | Color | Significado |
|---|---|---|---|---|
| Cloud | cualquier | — | Verde | Cloud mode OK |
| Sentinel | online | online | Verde | Todo perfecto |
| Sentinel | online | offline | Naranja | Buffering (sync pendiente) |
| Sentinel | offline | — | Rojo pulsante | Agente caído, monitoreo parado |
Panel Sentinel (sidebar colapsable)
- Mode label: Etiqueta de solo lectura (“Cloud Only” azul / “24/7 Sentinel” verde)
- Botón “Change”: Abre
confirm()para cambiar de modo - Status rows: Monitoring (Active/Inactive) + Sync (Online/Offline/—)
- Recovery panel: Se muestra cuando
mode=sentinel && agent offline - Auto-expand: El panel se expande automáticamente cuando el modo es sentinel o cuando el agente cae
Toast de Recuperación
Cuando el agente cae en modo Sentinel, aparece un toast persistente con:
- Mensaje: “Agent offline — Sentinel monitoring paused”
- Botón “Dismiss”: Cierra solo el toast
- Botón “Download Agent”: Lanza el protocolo de recuperación
- Se auto-cierra cuando el agente vuelve online
Guía de instalación (v1.49.0)
Los puntos de descarga “fríos” del Agent (sidebar del Terminal, dropdown Local Agent del header, botón Install Guide del Fleet Manager, enlace en el banner just-in-time de onboarding) abren el modal global “Local Agent — Where to Install It” (agent-install-guide-modal en base.html, openAgentInstallGuide() en base.js): dos tarjetas (máquina siempre encendida → Sentinel · PC propio → discovery/terminal) + nota de flota, con la descarga dentro. El flujo de recovery (agente caído) NO pasa por el modal: mantiene la descarga directa.
4. Componentes del Agente
4.1 Store (SQLite WAL)
Archivo: terminal/agent/core/store.py
CREATE TABLE metrics (
id INTEGER PRIMARY KEY AUTOINCREMENT,
timestamp INTEGER NOT NULL,
target_id INTEGER NOT NULL,
target_ip TEXT NOT NULL,
metric_type TEXT NOT NULL, -- 'ping_latency', 'ping_loss', 'snmp_in', 'snmp_out', ...
value REAL NOT NULL,
synced INTEGER DEFAULT 0,
UNIQUE(timestamp, target_id, metric_type)
);
CREATE TABLE targets (
target_id INTEGER PRIMARY KEY,
ip TEXT NOT NULL,
hostname TEXT,
monitor_types TEXT, -- JSON array: ["ping", "snmp", "http"]
snmp_community TEXT,
snmp_port INTEGER DEFAULT 161,
snmp_interface INTEGER DEFAULT 1,
snmp_version TEXT DEFAULT 'v2c', -- 'v2c' or 'v3'
snmp_v3_username TEXT DEFAULT '', -- SNMPv3 USM username
snmp_v3_auth_protocol TEXT DEFAULT '', -- MD5, SHA, SHA224, SHA256, SHA384, SHA512
snmp_v3_auth_key TEXT DEFAULT '', -- Auth passphrase
snmp_v3_priv_protocol TEXT DEFAULT '', -- DES, AES128, AES192, AES256
snmp_v3_priv_key TEXT DEFAULT '', -- Privacy passphrase
monitoring_oids TEXT DEFAULT '{}', -- JSON: vendor-specific OIDs
fast_poll_oids TEXT DEFAULT '{}', -- JSON: fast-poll OIDs
http_url TEXT,
http_method TEXT DEFAULT 'GET',
interval_seconds INTEGER DEFAULT 30, -- cadencia por target (el SaaS empuja el valor real)
updated_at INTEGER
);
CREATE TABLE config (
key TEXT PRIMARY KEY,
value TEXT
);
Estimación de espacio: 50 targets × 3 métricas × 1/min = ~500 MB/mes. Retención 30 días con VACUUM automático tras purge.
API principal: write_metric(), write_metrics_batch(), get_unsynced(limit), mark_synced(ids), purge_old(days), upsert_target(), min_target_interval(), prune_targets(keep_ids) (Agent 2.21.2)
Poda de targets fantasma (Agent 2.21.2, 24-08-2026, auditoría #261 punto A05): update_targets() del scheduler solo hacía upsert — nunca borraba del SQLite lo que el SaaS dejaba de mandar. Targets eliminados en el SaaS (o de una organización anterior de ese mismo Agent) resucitaban al reiniciar el servicio y se sondeaban para siempre: la auditoría encontró 316 targets en el cache local frente a 183 reales. Store.prune_targets(keep_ids) borra ahora todo target_id que no esté en la lista completa que manda el SaaS en cada update_targets() — un lote vacío legítimo (organización sin targets) vacía la tabla, que es el estado correcto.
4.2 SentinelScheduler — cadencia por target
Archivos: terminal/agent/sentinel/scheduler.py + loops en sentinel/ping.py, sentinel/snmp_bandwidth.py, sentinel/snmp_fast.py, sentinel/snmp_extras.py
Scheduler autónomo con loops asyncio y tick de 5 s: en cada tick, due_targets() devuelve solo los targets cuya cadencia (interval_seconds, reloj monotónico por target) ha vencido. Concurrencia controlada por semáforos.
| Loop | Cadencia efectiva | Constante (config.py) |
|---|---|---|
| Ping | clamp(interval_seconds, 15, 30) — sigue el dial hacia abajo, pero nunca más lento de 30 s (detección de caídas) | PING_FLOOR=15, PING_CAP=30 |
| SNMP bandwidth | max(interval_seconds, 15) | SNMP_FLOOR=15 |
| SNMP fast (OIDs fast-poll) | max(interval_seconds, 15) | FAST_SNMP_FLOOR=15 |
| SNMP extras (CPU/mem/temp vendor) | max(interval_seconds, 60) — queries pesadas, nunca <60 s | EXTRAS_FLOOR=60 |
| Purge | 3600 s | — |
El dial de la Edit Card (Polling cadence: 15 s / 30 s / 1 min / 5 min) escribe MonitoringTarget.interval_seconds vía PUT /api/network/auto-provision/profiles/{id}/config (campo polling_interval, validación 15–86400 en monitoring/api/schemas.py) y notify_agents() re-empuja los targets al Agente en caliente — el cambio de cadencia aplica sin reiniciar nada. Migración monitoring 0026: default honesto 60 s + backfill de la flota.
Tope duro por petición SNMP (Agent 2.21.2, 24-08-2026): el timeout de pysnmp (SNMP_TIMEOUT) no cubre todos los modos de fallo — una petición puede no volver NUNCA (transporte corrupto, o el engine recreado por recreate_snmp_engine() con peticiones ya en vuelo). Sin protección extra, asyncio.gather() del lote se queda esperando esa única petición para siempre y el loop entero (bandwidth, fast o extras) para. Hasta el 2.21.0 lo tapaba el cortacircuitos alimentado por el ping (saltaba los hosts inalcanzables antes de que el loop SNMP los tocara); al desacoplarse ping y SNMP quedó al descubierto — incidente del 24-08-2026: tras publicar 2.21.1 el Agente del CCIB hizo SNMP el primer minuto y luego nada (/sentinel/status a los 12 min: ciclos ping 41, snmp 2, extras 1, fast 1). Fix: cada petición SNMP de los tres loops lleva asyncio.wait_for(..., timeout=SNMP_HARD_TIMEOUT) con SNMP_HARD_TIMEOUT=20 s (config.py); el cuelgue se captura como TimeoutError, cuenta como fallo vía SentinelScheduler.note_snmp_hang() (incrementa _snmp_errors, alimenta el circuit breaker, y queda registrado en snmp_last_error de /sentinel/status), pero el lote siempre termina. Test de regresión: tests/agent/test_snmp_hard_timeout_and_prune.py.
Estado de los productores por target (A19 · Agent 2.24.0, 28-08-2026): cada bucle SNMP anota, por target, si produjo dato y si no POR QUÉ — SentinelScheduler.note_producer(target_id, loop, ok, reason) alimenta _producer_state = {tid: {loop: {ok_ts, reason, since}}}. snmp_poll_bandwidth(..., state=dict) deja el motivo en state["reason"]: no_response (sin respuesta SNMP), malformed, no_counters (ningún OID de octetos en esa interfaz → ifIndex equivocado), all_zero, baseline (primera muestra; cuenta como ok), wrap, spike (>10 Gbps descartado), y desde el lote hang (tope duro) / error; extras y fast anotan no_response/hang/error. producer_issues() devuelve SOLO los targets con algún bucle fallando (compacto) → sale en /sentinel/status (producers) y viaja en el heartbeat (payload["producers"], SaaSConnector._collect_producers). En el SaaS, AgentConsumer.sanitize_producers (bucles y motivos de lista cerrada, enteros) + _apply_producers guardan MonitoringTarget.producer_state (migración 0033) y ponen a NULL los targets que ya no vienen; MonitoringTargetOut.producer_state lo expone y ObservatoryTabs.getProducerNote pinta la nota “No bandwidth data: …” bajo la cabecera de la sección Bandwidth. Antes (≤2.23.1) el motivo vivía solo en logger.warning del Agente. Tests: tests/agent/test_agent_2240.py, tests/api/test_agent_2240_saas.py.
API principal: start(), stop(), update_targets(list), is_running(), note_snmp_hang(target_id, ip, loop_name) (Agent 2.21.2), note_producer() / producer_issues() (Agent 2.24.0)
4.3 SyncManager
Archivo: terminal/agent/core/sync.py
Sincronización REST en batches de 1000 métricas. Drain completo en reconexión. Backoff exponencial en fallos.
Protocolo:
- El ciclo de sync va acompasado al target más rápido (
min_target_interval()del Store, sueloMIN_SYNC_INTERVAL=15s) — con un target a 15 s el sync corre cada 15 s; con toda la flota a 5 min, se relaja. - Consulta
store.get_unsynced(limit=1000)y envía el batch viaPOST /api/agent/metrics/bulk - SaaS responde con IDs aceptados →
store.mark_synced(ids) - Si hay más de 1000 pendientes, repite inmediatamente (drain loop)
- Verifica conectividad REST via
/healthcuando WebSocket no está disponible
5. Endpoints SaaS
5.1 Bulk Metrics
POST /api/agent/metrics/bulk
Recibe hasta 5000 métricas por request. Escribe directamente en VictoriaMetrics. Idempotente por timestamp+target+metric.
class BulkMetricItem(Schema):
timestamp: int
target_id: int
metric_type: str
value: float
class BulkMetricsIn(Schema):
agent_id: str
metrics: list[BulkMetricItem] # Max 5000
class BulkMetricsResponse(Schema):
accepted: int
rejected: int
errors: list[str] = []
5.2 Sentinel Config
GET /api/monitoring/sentinel-config → { config: { mode: "cloud"|"sentinel", ... } }
PUT /api/monitoring/sentinel-config → Guarda en Valkey (sin expiración)
Gemelo agent-facing (terminal/api/sentinel.py):
GET /api/agent/sentinel-config/{agent_id}
PUT /api/agent/sentinel-config/{agent_id} → 200 | 401 | 403
A15 (auditoría #261, v1.85.2): PUT solo lo acepta si agent_id es el AgentInstance con role="primary" de la organización (403 a un secundario); y aunque lo acepte, nunca escribe mode — el modo cloud/sentinel es una decisión del usuario en la UI (endpoint §5.2), y un Agente comprometido podía forzar mode="cloud" para provocar sondas fabricadas desde otra máquina. Los intervalos que manda el Agente sí se aceptan y persisten (write-through a Organization.sentinel_config en PostgreSQL, además de Valkey).
5.3 Agent Auth (Silent Auto-Link)
POST /api/agent/register → { access_token, refresh_token }
POST /api/agent/auth → Validación de token
POST /api/agent/refresh → Refresco de JWT
El auto-link es transparente: _autoLinkAgent() verifica si el agente ya está autenticado, y si no, registra + envía tokens — sin intervención del usuario.
6. Observatory UI — Agent Health Polling
6.1 Polling Adaptativo
_agentHealthPoll() en observatory.js ejecuta un fetch a localhost:5050/info con velocidad adaptativa, independientemente del tab activo:
| Estado agente | Intervalo | Errores consola |
|---|---|---|
| Online | 10s | 0 (agente responde) |
| Offline | 30s | 1 cada 30s (necesario para detectar vuelta) |
| Init (primer check) | 2s delay | 0 si agente listo, 1 si no |
Transiciones automáticas:
- Online → Offline: 1 error de detección → polling baja a 30s → toast + recovery panel
- Offline → Online:
console.clear()limpia errores acumulados → polling sube a 10s → auto-link + push targets
Alimenta:
- Header dot (color según estado)
- Recovery panel (visible/oculto)
- Toast persistente (mostrar/cerrar)
- Status rows del sidebar (Monitoring/Sync)
6.2 Refresco de pestañas acompasado (v1.43.0/v1.43.1)
Las pestañas de device en Observatory (y los detalles de Wireless/UPS/Signage) refrescan sus charts a la cadencia del target (getRefreshInterval() en ObservatoryAutoRefresh.js, suelo 15 s). El selector de refresco por pestaña 5s/10s/20s y su copia en Chart Defaults se retiraron en v1.43.0. Al guardar el dial en la Edit Card, el evento devicecard:cadence-changed re-acompasa la página abierta en caliente (v1.43.1) — listeners en observatory.js, wireless.js (WirelessDetail.repace) y ups.js (UpsDetail.repace); Signage acompasa al abrir el detalle pero no escucha el evento (su Edit Card no se abre desde esa página).
6.3 Protocolo de Recuperación
startAgentRecovery()
1. Intenta crearack://start (por si está instalado pero parado)
2. Espera 1.5s → fetch localhost:5050/info
3. Si responde → _onAgentRecovered()
4. Si no → _downloadAndPollAgent():
a. Descarga /static/downloads/CreaRackAgent.exe
b. Toast: "Agent downloaded. Run the file to install."
c. Poll cada 2s hasta que responda
5. _onAgentRecovered():
a. Oculta panel recovery + cierra toast
b. Auto-link con SaaS
c. Push targets si sentinel activo
d. Toast: "Agent connected!"
Botón “Download Agent” disponible en:
- Panel recovery del sidebar Sentinel
- Widget Local Agent del Overview (cuando está offline)
- Toast persistente de alerta
7. Seguridad
| Aspecto | Implementación |
|---|---|
| Autenticación | JWT (registro automático vía /agent/register) |
| Rate limiting | Max 10 requests/min en /agent/metrics/bulk |
| Datos en reposo | SQLite en %APPDATA%\CreaRackAgent\metrics.db |
| Credenciales SNMP | v2c community en targets table; v3 keys en targets table (almacenados desde SaaS push) |
| Datos en tránsito | HTTPS (REST) |
| Datos preservados en reinstall | credentials.enc, offline_cache.db, metrics.db, agent.log |
| Config Sentinel por WS/API | Solo el Agente role="primary" puede escribir (A15, v1.85.2 — ver §5.2); nunca puede cambiar mode |
Difusión de targets_updated | Solo al Agente role="primary" (A53, v1.85.2): el lote lleva las credenciales SNMP en claro; un secundario las recibía y persistía sin usarlas (terminal/consumers.py) |
8. Recursos
Equipo Local (Agent)
| Recurso | Estimación |
|---|---|
| RAM | +10-20 MB sobre el agente base |
| CPU | < 2% (ping/SNMP son operaciones ligeras) |
| Disco | ~500 MB/mes (50 targets, retención 30 días) |
| Red | ~5 KB/min por target (a cadencia 1 min; escala con el dial) |
SaaS
| Recurso | Estimación |
|---|---|
| VM storage | Sin cambio (180 días de retención) |
| API load | +1 request por ciclo de sync (acompasado a la cadencia más rápida, suelo 15 s; burst en reconexión) |
| Valkey | +1 key por organización (config) |
9. Decisiones de Diseño
SQLite vs VictoriaMetrics local
SQLite es zero-config, un archivo, ya está en el agente. VM requeriría un proceso separado — demasiado pesado para un servicio residente. El SaaS VM sigue siendo el almacén definitivo.
Sync batch vs streaming
Batch es más resiliente a interrupciones de red, permite deduplicación natural, menor overhead de conexión. El ciclo acompasado a la cadencia más rápida (suelo 15 s) mantiene el “casi tiempo real” sin malgastar requests cuando toda la flota va lenta.
Cadencia por target vs global
El campo interval_seconds existía desde la migración 0001 pero era inerte (todo iba a 30/60 s fijos) — la task #175 lo hizo efectivo. Un único dial por equipo gobierna sondeo Y refresco de charts: sin dos fuentes de verdad, sin toggle cosmético. Los suelos por protocolo protegen a los dispositivos (SNMP pesado nunca <60 s) y el techo del ping protege la detección de caídas (nunca >30 s).
Opt-in vs default
Respetar la decisión del usuario sobre recursos de su equipo. Confirmación obligatoria en ambas direcciones. Cloud Only es más simple y suficiente para muchos usuarios.
Confirm en ambas direcciones
Previene cambios accidentales. Un clic erróneo en Cloud→Sentinel activa monitoreo 24/7 no deseado. Un clic erróneo en Sentinel→Cloud detiene el monitoreo silenciosamente.
Guía contextual, no modal de elección (v1.49.0)
Descartado un modal de “elige tu estrategia” en la primera ejecución del Agent: la elección sería ficticia (es el mismo .exe y la flota se auto-organiza) y el usuario nuevo no tiene contexto para decidir. En su lugar: guía informativa en el momento de la descarga (modal “Where to Install It”) + advertencia basada en datos en el momento de activar Sentinel (§3.2, §10.1).
Tope duro por petición, no solo el timeout de la librería (Agent 2.21.2)
El timeout interno de pysnmp asume que el transporte responde con error; no cubre el caso de una petición que se queda literalmente colgada tras una recreación de engine o una corrupción de transporte. Un asyncio.wait_for externo por petición es la única garantía real de que el gather() del lote termina siempre — el coste es que un cuelgue real se reporta como timeout genérico en vez de con la causa exacta, aceptable frente a parar el loop entero.
Solo el primary gobierna config y secretos (A15/A53, auditoría #261)
Con varios Agentes por organización (§10), cualquiera de ellos podía llamar a los endpoints agent-facing. Sin esta restricción, un secondary comprometido (o simplemente un bug de otro cliente) podía escribir configuración Sentinel de la org o acumular credenciales SNMP que nunca necesita para operar. Restringir a role="primary" reduce la superficie a la única instancia que de verdad ejecuta el scheduler.
10. Primary/Secondary Fleet (v6.5.0 — Implementado)
Cuando varios técnicos de una sede instalan el Agent en sus PCs, todos conectan al mismo tenant del SaaS. Sin control de roles, todos ejecutarían Sentinel simultáneamente, causando métricas duplicadas.
Solución: Primary/Secondary
┌─────────────────────────────────────────────────────┐
│ TENANT: Oficina Central │
│ │
│ PC-Admin (Primary) → Sentinel ACTIVO │
│ └── ping/SNMP a la cadencia de cada target │
│ │
│ PC-Tech1 (Secondary) → Solo SSH/Tools │
│ PC-Tech2 (Secondary) → Solo SSH/Tools │
│ │
│ Si PC-Admin se desconecta → PC-Tech1 se promueve │
│ automáticamente a Primary (failover) │
└─────────────────────────────────────────────────────┘
| Aspecto | Detalle |
|---|---|
| Modelo | AgentInstance en Django (agent_id, role, status, hostname, version) |
| Asignación | Automática: primer agent = Primary, resto = Secondary |
| Failover | Al desconectar Primary, el Secondary online más antiguo se promueve |
| Comando WS | set_role → el Agent inicia/detiene Sentinel según rol |
| API Fleet | GET /api/agent/fleet, POST .../promote, POST .../demote |
| UI | Widget “Agent Fleet” en Observatory Overview (tabla + badges) |
| Backwards compatible | Agent sin set_role handler funciona como antes |
10.1 Señal de estabilidad de la máquina (v1.49.0)
AgentInstance lleva un contador de desconexiones largas para detectar máquinas poco fiables como anfitrionas del Sentinel (el patrón “portátil que se apaga cada tarde”):
| Aspecto | Detalle |
|---|---|
| Campos | disconnect_count + disconnect_window_start (migración terminal 0004) |
| Conteo | Al reconectar en _register_and_assign_role (terminal/consumers.py), solo si el agente venía de estado offline (sin doble conteo) y el hueco superó DISCONNECT_GAP_MINUTES = 10 — los micro-cortes (deploy del SaaS, blips de red) reconectan en segundos y NO cuentan |
| Ventana | Rodante aproximada de DISCONNECT_WINDOW_DAYS = 7: si caducó, arranca ventana nueva con count=1 |
| Lectura | Property disconnects_7d (0 si la ventana caducó) · expuesta en GET /api/agent/fleet (AgentInstanceOut.disconnects_7d) |
| Consumidor | El aviso de estabilidad al activar Sentinel (§3.2): umbral UNSTABLE_DISCONNECTS_7D = 3 en ObservatorySentinel.js |
| Límite honesto | El contador arranca a 0 con la migración: necesita unos días de historial. La detección directa de portátil (batería reportada por el Agent) queda como mejora futura — requiere release del .exe |
11. Roadmap Futuro
Alertas Locales
El agente evalúa reglas de alerta localmente → Windows toast notifications para alertas críticas sin necesidad de tener el SaaS abierto.
Dashboard Local del Agente
Mini-Observatory en localhost:5050 con datos de SQLite local para emergencias sin acceso al SaaS.
Detección de portátil (batería)
El Agent podría reportar si su máquina tiene batería (= portátil) en el registro, para avisar desde el día 1 sin esperar historial de desconexiones. Requiere compilar y publicar un .exe nuevo — pendiente de acumularse con otro motivo de release.
Archivos clave del agente: core/store.py, core/sync.py, sentinel/scheduler.py, sentinel/ping.py, sentinel/snmp_bandwidth.py, sentinel/snmp_fast.py, sentinel/snmp_extras.py, config.py, saas_connector.py
Archivos clave del SaaS: terminal/models.py, terminal/consumers.py, terminal/api/fleet.py, terminal/api.py, monitoring/api/schemas.py, network/api/assign.py, observatory.js, ObservatorySentinel.js, ObservatoryAutoRefresh.js, ObservatoryOverview.js, observatory.html, observatory.css, base.html, base.js
Véase también
- [[crearack-tech—guides—sentinel-24-7-test]]
- [[crearack-tech—agents—dev-cns]]
- [[crearack—monitoring—cns-sentinel]]
- [[concept—monitoring—cns]]
- [[concept—monitoring—itsm]]
Referenciado desde
- Agente · dev-cns
- Agente 2.23.0 — restos de la auditoría #261 + sensor "Agente vivo pero mudo"
- Agente 2.24.0 — task #270: rotación de logs, timeout de insights, y por qué no hay bandwidth (A19)
- Agente 2.30.1: el contador de 32 bits de los Xirrus daba la vuelta y "AP Bandwidth" pintaba un cero (v1.166.1)
- Guía CNS — CreaRack Network Sentinel
- Hotfix 2.21.5: un walk SNMP vencido por timeout fabricaba un 0 (Regla 13) — 47 APs con dato falso 30 días
- Incidente 24-08-2026 · el cortacircuitos mixto silenció el SNMP vivo del CCIB 15 minutos
- Incidente 24-08-2026 · el motor SNMP quedaba corrupto tras cuelgues seguidos — timeout duro + autocuración (Agente 2.21.2→2.21.3)
- MonitoringTarget · Modelo monitoring
- Patrón Monitoring* — bases comunes + descriptor por dominio (serie F1, auditoría s187)
- Sentinel Mode: Prueba de Persistencia 24/7