Volver a la wiki

Sonda TCP — Equipos que bloquean ICMP dejan de salir "down" falsos

Resumen

Desde v1.58.0, cada target de monitoreo puede llevar una sonda TCP opcional que prueba si un puerto específico acepta conexiones (SSH:22, HTTPS:443, etc.). Resuelve el problema de que servidores con ICMP bloqueado pero servicios TCP vivos aparecían como “caídos” en Observatory.

Impacto: Cierra la deuda DCIM — la disponibilidad de equipos endurecidos y firewalls ya no miente.

Estado: ✅ ACTIVA Y VALIDADA E2E en PROD (22-07-2026) — el loop del Agente viaja despierto desde Agent 2.16.0 (tanda #196/#197). Ver § Validación E2E. Los 3 flecos del click-test quedaron CERRADOS el 23-07-2026 (v1.63.4 server-side + Agent 2.16.3); task #205 done. Ver § Flecos.

Contexto de la deuda (DCIM, NEXT s90+)

Antes de esta feature:

Ahora:

Componentes de la feature

1. Modelo extendido: MonitoringTarget

Nuevos campos (migración 0028):

Nuevo método:

2. Servicio TCP: tcp_service.py

Resultado:

@dataclass
class TcpResult:
    status: str  # "up" | "down"
    latency_ms: float | None
    error: str | None = None

3. Endpoint: POST /api/monitoring/targets/{target_id}/tcp/check

Operación: tcp_check(request, target_id: int)

Lógica:

  1. Valida permiso (observatory:edit).
  2. Si target.tcp_port no está configurado → 400 Bad Request.
  3. Si IP es privada → retorna el último resultado conocido (evita probar la LAN desde el SaaS).
  4. Si IP es pública → ejecuta check_tcp(), persiste resultado en last_tcp_up/last_tcp_check, recalcula resolve_reachability().
  5. Emite métrica tcp_latency si UP.
  6. Notifica via WebSocket (broadcast_metrics_sync).

Respuesta:

{
  "status": "up" | "down",
  "port": 22,
  "latency_ms": 12.45,
  "error": null,
  "timestamp": "2026-07-17T10:51:06Z"
}

4. Loop Sentinel (Agente): sentinel/tcp_check.py

Estado: ✅ DESPIERTO desde Agent 2.16.0 (22-07-2026, tanda #196/#197). El código viajó dormido en 1.58.0 y se activó con el release del .exe.

Qué hace:

5. UI: Observatory Modal

Ubicación: sección Heartbeat, junto a SNMP/HTTP/Ping.

Elementos:

Comportamiento:

6. Sin falsas alarmas “total loss” para equipos solo-TCP (v1.63.4 + Agent 2.16.3)

Un equipo legítimamente solo-TCP (ICMP siempre bloqueado) hace que el check_ping del anomaly detector del Agente vea loss=100% en cada ciclo → dispararía la anomalía “packet_loss” cada 5 minutos de cooldown hasta comerse el rate limit de 10 insights/hora, sin emitir nunca recovery. Confirmado leyendo anomaly_detector.py; en el test E2E del 22-07 no se manifestó porque el rate limit estaba al tope.

Doble defensa, ambas desplegadas:

En ambas capas, una degradación parcial (loss<100%) NO se suprime aunque el TCP esté vivo (puede ser congestión real).

7. i18n

Strings nuevos traducibles en django.po y djangojs.po:

Refactor lateral: build_vendor_oids_lookup

Se movió de terminal/consumers.py (que superaba 500 LOC) a terminal/services.py, donde ya la invocaba terminal/api/sentinel.py (cruzando módulos). Ahora:

Testeo

Suite: tests/api/test_tcp_probe.py (18 tests desde v1.63.4) + tests/agent/test_anomaly_tcp_suppression.py (4 tests del detector, desde Agent 2.16.3).

Suites vecinas:

Validación E2E en PROD (22-07-2026)

Click-test real con Agent 2.16.2 (YogaEdu) sobre el target AU-Camerino-02 (192.168.230.4, LAN CCIB):

  1. Modal → Agente: al guardar el modal (checkbox + puerto 22), la config llegó al Agente por WS al instante (notify_agents) y last_tcp_up=True apareció en PROD en <1 minuto.
  2. Rescate verificado en vivo: se bloqueó el ICMP saliente hacia el target en el host del Agente (regla de firewall temporal) → PROD registró loss=100% y el target siguió “up” gracias a la sonda TCP fresca. La gráfica de Heartbeat mostró el pico de loss al 100% con el header en UP.
  3. Métricas: tcp_reachable/tcp_latency_ms fluyen a VictoriaMetrics con tenant y target correctos. (Nota: el Agente NO escribe MetricSample en Postgres — por diseño, su telemetría vive en VictoriaMetrics; MetricSample solo lo escribe el check manual server-side de IPs públicas.)
  4. Recuperación: al retirar el bloqueo, loss=0 y todo volvió a régimen sin intervención.

Flecos del click-test (task del Gestor #205) — CERRADOS

Los 3 resueltos el 23-07-2026 (task #205 done):

  1. ✅ Placeholder del puerto — RESUELTO (v1.63.4): campo vacío + sonda activada = 22 real (ver §5). Matiz honesto: el “no-op silencioso” que describía la task no se reproducía en el código de v1.58.0+ (las validaciones cliente/servidor ya existían); lo real era el default inexistente que el placeholder sugería.
  2. ✅ tcp_cycles en /info del Agente — RESUELTO (Agent 2.16.3): get_status() expone targets.tcp y cycles.tcp. Verificado en vivo tras el auto-update de la flota (YogaEdu: targets.tcp=2, cycles.tcp contando).
  3. ✅ Falsas alarmas “total loss” para equipos solo-TCP — CONFIRMADAS Y RESUELTAS en doble capa: supresión server-side (v1.63.4) + fix de raíz en el detector del Agente (2.16.3). Ver §6.

Cambios en comportamiento existente

Cronograma de activación

  1. ✅ v1.58.0 (17-07-2026): Feature completa en el SaaS (check manual, Modal, endpoint, ingest).
  2. ✅ Agent 2.16.0 (22-07-2026, tanda #196/#197): .exe del Agente con lógica TCP despierta.
  3. ✅ Validación E2E en PROD (22-07-2026): la LAN la sondea sentinel/tcp_check.py; el endpoint SaaS queda para destinos públicos y trigger manual.
  4. ✅ v1.63.4 (23-07-2026): flecos 1 y 3 del click-test resueltos server-side (default real 22 + supresión de falsos “total loss” en el CNS).
  5. ✅ Agent 2.16.3 (23-07-2026): fleco 2 (telemetría TCP en /info) + fix de raíz del detector (supresión en origen + recovery vía TCP). Flota auto-actualizada sin manos; task #205 CERRADA.

Véase también

Subir