CreaRack-SL

Endpoint GET /api/agent/fleet — Listado de agentes en flota con estado de estabilidad

Entidaddraftcreado Mon Jul 13

Descripción

Endpoint REST que expone el estado completo de todos los Local Agents conectados a la organización actual. Retorna array de AgentInstanceOut con telemetría en tiempo real (heartbeat cada 30s).

Firma

GET /api/agent/fleet
Authorization: Bearer <token>

Respuesta 200 OK:
[
  {
    "agent_id": "abc123",
    "hostname": "OFICINA-PC",
    "ip_address": "192.168.1.100",
    "agent_version": "2.18.0",
    "role": "primary",
    "status": "online",
    "sentinel_active": true,
    "last_seen": "2026-07-31T10:15:22Z",
    "connected_at": "2026-07-20T08:00:00Z",
    "disconnected_at": null,
    "disconnects_7d": 1,
    "has_battery": false,
    "health": {
      "cpu_percent": 0.3,
      "mem_mb": 48,
      "db_mb": 2.1,
      "pending_rows": 0,
      "last_sync_age_s": 15
    }
  }
]

Respuesta 403 Forbidden (sin permiso fleet:view):
{ "detail": "Permission denied" }

Ubicación

  • Archivo: terminal/api/fleet.py
  • Auth: requiere JWT válido + permiso fleet:view

Campos de respuesta

De siempre (pre-2.18.0)

CampoTipoDescripción
agent_idstrUUID único del Agent en el SaaS.
hostnamestrNombre del equipo donde corre el Agent.
ip_addressstr | nullIP interna (LAN) del Agent, validada server-side en /api/agent/agent_status.
agent_versionstrVersión actual del binario (ej: “2.18.0”).
rolestr“primary” o “secondary” en la flota.
statusstr“online” u “offline”.
sentinel_activebool¿Hay un Sentinel monitor conectado?
last_seenstr | nullISO 8601 del último heartbeat.
connected_atstr | nullISO 8601 de la primera conexión en esta sesión.
disconnected_atstr | nullISO 8601 del último desconexión.
disconnects_7dintContador de desconexiones largas (gap ≥10 min) en los últimos 7 días.
has_batterybool | null¿El equipo corre en portátil? (reportado por agent_status v2.15+).

Nuevo en 2.18.0 (v1.65.0 · task #209)

CampoTipoDescripción
healthdict | nullSnapshot del bloque health del último heartbeat. NULL si Agent < 2.18.0 o sin heartbeat reciente.
└ cpu_percentfloatUso de CPU normalizado al total de la máquina (0–100).
└ mem_mbintMemoria residente (RSS) en MB.
└ db_mbfloatTamaño de metrics.db en MB.
└ pending_rowsintMétricas sin sincronizar al SaaS.
└ last_sync_age_sintSegundos desde el último sync exitoso.

Casos de uso

Fleet Manager (frontend)

  • Columna “Footprint”: renderiza ${health.cpu_percent}% CPU · ${Math.round(health.mem_mb)} MB si health existe y status === 'online'.
  • Fallback: ”—” si no hay telemetría.

Observatory (ficha del agente)

  • Variante SaaS-side: muestra CPU, RAM, DB Size, Pending Sync extrayendo de health.
  • Variante localhost: sigue consultando /health local si está disponible (arquitectura simétrica).

Dashboard home (línea marginal)

  • Refresco 30s: llama /api/agent/fleet, busca el primer agente online con health y renderiza:
    • Local Agent · <hostname>: <cpu>% CPU · <mb> MB RAM · <synced|metrics buffered>
  • Silenciosa: no se muestra si array vacío, sin permiso (error 403) o sin agentes con health.

Alertas operativas

  • Tendencia de DB: si db_mb crece sostenidamente (>10 MB en 1h) → indicador de degradación de sync.
  • Buffer alto: si pending_rows > 1000 y last_sync_age_s > 300 → alerta de desconexión del SaaS.

Notas de implementación

Consumer (WebSocket, terminal/consumers.py)

Cuando el Agent envía un heartbeat con bloque health:

  1. Extraer solo las claves conocidas (cpu_percent, mem_mb, db_mb, pending_rows, last_sync_age_s).
  2. Validar que todos los valores sean numéricos (float/int).
  3. Rechazar dicts arbitrarios o nodos de payload malformados.
  4. Persistir en AgentInstance.health (JSONField).

Esto implementa fail-closed: un payload roto no corrompe el modelo.

Serialización (Schema AgentInstanceOut, terminal/api/fleet.py)

El bloque health aparece en el schema como Optional[Dict[str, Union[int, float]]].

Retrocompatibilidad

  • Agents < 2.18.0: no envían health → el campo es NULL.
  • Clientes viejos: ignoran el nuevo campo si existe (backward-compatible).
  • Sin permiso: retorna 403 (igual que antes, ahora efectivamente).

Véase también

  • [[entity—terminal—model—agentinstance]] — modelo que persiste health en el campo JSONField
  • [[feature—terminal—agent-health-heartbeat]] — feature padre que introduce la telemetría
  • [[concept—saas—observability]] — principios de observabilidad del SaaS
  • [[entity—terminal—endpoint—agent-status]] — endpoint hermano que reporta estado del Agent local