Volver a la wiki

MonitoringTarget: Objetivo de Monitoreo

{“sources”: [{“type”:“code”,“ref”:“monitoring/models.py”},{“type”:“commit”,“ref”:“16220c3”},{“type”:“code”,“ref”:“monitoring/migrations/0023_encrypt_target_config.py”},{“type”:“commit”,“ref”:“bf2c645”}], “related”: [“entity—network—model—device-profile”,“entity—core—service—credential-manager”,“feature—security—t1-cifrado-snmp-reposo”,“entity—monitoring—model—metric-sample”,“concept—monitoring—target-scope”,“decision—20260717—target-state-freshness”,“entity—terminal—service—terminal-hosts”], “content”: ”## Propósito\n\nModelo central de monitoreo en CreaRack. Representa un target (equipo, switch, UPS, VM) que puede ser monitoreado via ICMP (ping), SNMP, HTTP y (desde v1.58.0) TCP.\n\nCampos de configuración, estado último conocido, métricas agregadas y helper methods para filtrar, validar y decidir up/down.\n\n## Campos principales\n\n### Identidad y organización\n- id: PK\n- organization: FK[Organization] — RLS: cada org solo ve sus targets.\n- name: str\n- ip_address: IPAddress — único por (org, ip); un target por host.\n- enabled: bool = True — si está deshabilitado, no se sondea.\n\n### Configuración de monitoreo\n- ping_enabled: bool = True — ICMP ping.\n- snmp_enabled: bool = True — SNMP bandwidth.\n- http_enabled: bool = True — HTTP health check.\n- tcp_enabled: bool = False (v1.58.0) — sonda TCP.\n- interval_seconds: int = 60 — cadencia de sondeo.\n- timeout_ms: int = 5000 — timeout de operación.\n\n### Puertos y configuración TCP\n- config: JSONField — credenciales SNMP, URL HTTP, etc. (encrypted).\n- tcp_port: PositiveIntegerField(null=True) (v1.58.0) — puerto a probar (1-65535).\n\n### Estado último conocido\n- last_status: str — “up”, “down”, “unknown”. Dato CRUDO: es el último valor escrito, sin caducidad propia — ver status_effective abajo.\n- last_packet_loss: float — porcentaje de pérdida ICMP (0-100).\n- last_latency_ms: float — ms del último ping.\n- last_check: DateTimeField — cuándo se hizo el último sondeo (cualquier tipo).\n- last_tcp_up: bool(null=True) (v1.58.0) — resultado del último TCP.\n- last_tcp_check: DateTimeField(null=True) (v1.58.0) — cuándo se hizo el último TCP.\n\n### Metadata\n- created_at: DateTimeField(auto_now_add=True)\n- updated_at: DateTimeField(auto_now=True)\n\n## Propiedades y métodos\n\n### monitor_types (propiedad)\nDevuelve lista de tipos activos: [\"ping\", \"snmp\", \"http\", \"tcp\"] según habilitación.\n\n### resolve_reachability(ping_loss: float) -> str (v1.58.0)\nSemántica combinada de up/down. Resuelve la deuda DCIM: equipos que bloquean ICMP pero tienen TCP vivo ya no salen “down” falsos.\n\nLógica:\n1. Si ping_loss < 100% → return “up” (al menos algunos pings pasan).\n2. Si ping_loss == 100% pero tcp_enabled y last_tcp_up es True:\n - Verifica que TCP sea “fresco”: now - last_tcp_check <= freshness_window.\n - Ventana = max(TCP_FRESHNESS_FLOOR_S=300, interval_seconds × 3).\n - Si fresco → return “up”.\n3. Default → return “down”.\n\nUso:\n- Endpoint TCP check (/targets/{id}/tcp/check).\n- Ingest del Agente (sentinel_ingest.py).\n\n### status_effective (propiedad, v1.119.0 · task #277)\nFrescura en LECTURA — generaliza a last_status el mismo criterio de ventana que resolve_reachability ya aplicaba solo a la sonda TCP. Complementa (no sustituye) la frescura en ESCRITURA de [[decision—20260717—target-state-freshness]]: aquella evita que un replay viejo del Agente SOBRESCRIBA el estado; esta evita que un estado que nadie ha vuelto a escribir (Agente mudo, sin lote nuevo) se siga presentando como si fuera de ahora mismo. En PROD, un target llegó a mostrar “up” con last_check de 131 horas atrás.\n\nLógica:\n1. Si last_check es None → return “unknown”.\n2. Ventana = max(TCP_FRESHNESS_FLOOR_S=300, interval_seconds × 3) — MISMA constante y criterio que resolve_reachability.\n3. Si now - last_check supera la ventana → return “unknown” (ya existía en STATUS_CHOICES, no es vocabulario nuevo).\n4. Si no → return last_status tal cual.\n\nConsumidores (migrados de last_status crudo en v1.119.0): MonitoringTargetOut.resolve_last_status (serializer — arrastra de un plumazo la lista de dispositivos, el anillo de salud y la cabecera de pestaña de Observatory), /api/monitoring/overview (conteos up/down/degraded/unknown, ahora agregados en Python porque status_effective no es expresable como aggregate de BD), Wireless/UPS/Signage (mismo serializer), y connectivity_status en Devices (ver [[entity—terminal—service—terminal-hosts]]).\n\nDeuda declarada: monitoring/services/ups_metrics.py::ups_status y signage_service.py::signage_status siguen leyendo last_status en crudo — mismo defecto con otro disfraz. Migración probada y revertida a propósito (rompía 4 tests con fixtures que siembran last_status sin last_check, estado que la ingesta real nunca produce); va en PR propio tras ajustar esos fixtures.\n\n### is_up (propiedad)\nAliás: last_status == \"up\".\n\n### monitor_type (propiedad, legacy)\nDevuelve el primer tipo activo (compatibilidad hacia atrás).\n\n### status_color (propiedad)\nMapea last_status → color UI (“green”, “red”, “gray”).\n\n### snmp_configured (propiedad)\nBooleano: ¿tiene config SNMP válida?\n\n### public_config, secret_config, sensitive_config\nMétodos para desencriptar y filtrar credenciales (RLS).\n\n### get_or_create_for_device(device, org) (classmethod)\nCrea o reutiliza target para un dispositivo.\n\n## Migración 0028\n\nAñade campos TCP en v1.58.0:\npython\noperations = [\n migrations.AddField(\n model_name=\"monitoringtarget\",\n name=\"tcp_enabled\",\n field=models.BooleanField(default=False, help_text=\"Enable TCP port probe\"),\n ),\n migrations.AddField(\n model_name=\"monitoringtarget\",\n name=\"tcp_port\",\n field=models.PositiveIntegerField(blank=True, null=True, help_text=\"TCP port to probe (e.g. 22)\"),\n ),\n migrations.AddField(\n model_name=\"monitoringtarget\",\n name=\"last_tcp_up\",\n field=models.BooleanField(blank=True, null=True, help_text=\"Result of the last TCP probe\"),\n ),\n migrations.AddField(\n model_name=\"monitoringtarget\",\n name=\"last_tcp_check\",\n field=models.DateTimeField(blank=True, null=True),\n ),\n]\n\n\n## Schemas Ninja (API)\n\n### MonitoringTargetIn (POST/PUT)\n- Campos básicos: name, ip_address, ping/snmp/http/tcp_enabled, tcp_port, interval_seconds, timeout_ms.\n- Validadores:\n - validate_ip(): IP válida.\n - validate_tcp() (nuevo): si tcp_enabled, requiere tcp_port (1-65535).\n - validate_interval(), validate_timeout().\n- Al menos un monitor type debe estar habilitado.\n\n### MonitoringTargetOut (GET)\n- Todos los campos anteriores + last_tcp_up (leído).\n- Includes: monitor_types, monitor_type (legacy), status_color.\n- last_status sirve status_effective, no el campo crudo (v1.119.0, resolve_last_status) — el cliente nunca ve un “up”/“down” añejo.\n\n## Casos de uso\n\n1. Crear target con TCP: POST con tcp_enabled=true, tcp_port=22.\n2. Habilitar TCP en target existente: PUT + toggle en modal Observatory.\n3. Ingest del Agente: Lee tcp_enabled y tcp_port, escribe last_tcp_up y last_tcp_check.\n4. Decidir up/down: Endpoint/ingest invoca resolve_reachability() tras cada check.\n5. Leer estado para pantalla: cualquier lector usa status_effective, nunca last_status directo (v1.119.0).\n\n## Tests\n\ntests/api/test_tcp_probe.py: validación, resolve_reachability, ingest con TCP.\ntests/monitoring/test_targets_reconcile_async.py y tests/api/test_monitoring.py: status_effective, caducidad, simulacro del camino de fallo (desactivar la comprobación de frescura pone 6 tests en rojo).\n\n## Véase también\n\n- [[entity—monitoring—service—tcp-service]] — función check_tcp() que sondea.\n- [[entity—monitoring—endpoint—tcp-check]] — endpoint POST /targets/{id}/tcp/check.\n- [[entity—terminal—service—sentinel-tcp-check]] — loop Agente (asyncio).\n- [[feature—monitoring—sonda-tcp]] — contexto general de la feature.\n- [[concept—monitoring—cns]] — observabilidad y Sentinel.\n- [[decision—20260717—target-state-freshness]] — frescura en ESCRITURA (guard de ingest ante replays), complementaria a status_effective.\n- [[entity—terminal—service—terminal-hosts]] — consumidor de status_effective vía connectivity_status en Devices.\n”}

Subir