Volver a la wiki

Los clientes WiFi que ves son los de ahora (task #225, v1.66.9)

Síntesis

La página Wireless presentaba como clientes actuales los datos de un análisis profundo (deep_snmp_data) realizado hace semanas. En PROD, de 3.219 clientes reportados, 3.203 eran de APs caídos desde el 30 de junio. El “Busiest AP” señalaba hace 6 semanas al mismo punto.

Ahora: solo cuentan los clientes de APs que el MonitoringTarget ve vivos (last_status == "up") en este momento. La cifra cae, pero la UI expresa “N of M APs reporting live” para dejar claro que no es avería.

Evolución v1.85.2 (ver sección más abajo): desde el 25-08-2026 el juez de “vivo” ya no depende solo del ping — también mira SNMP en vivo. Esta sección de Síntesis describe el mecanismo ORIGINAL (v1.66.9); sigue siendo el criterio de respaldo.


Cambio funcional

Nuevas funciones en monitoring/api/wireless.py

_has_current_clients(profile) → bool

_current_client_count(profile) → int

Lectores afectados (5)

Todos reemplazan la lectura directa de deep_snmp_data por _current_client_count(p) / _has_current_clients(p):

  1. get_wireless_summary(): endpoint /api/monitoring/wireless/summary

    • Nuevo: aps_reporting_clients, aps_without_current_data
    • avg_clients_per_ap se calcula sobre los que reportan, no sobre la flota entera
    • Busiest AP solo entre los vivos
  2. get_wireless_status_list(): /api/monitoring/wireless/status-list

    • Zeroing de client_count para APs sin datos vivos
    • Crítico porque el dashboard suma estos valores por su cuenta (WirelessDashboard.computeMetrics)
  3. get_wireless_report(): informe individual por AP

    • client_count: 0 si el AP está caído
  4. get_wireless_fleet_report(): /api/monitoring/wireless/fleet-report

    • Nuevo: aps_reporting_clients, aps_without_current_data
    • Cada AP en fleet trae clients: 0 si es stale
  5. get_wireless_group_summary() — cerrado el 23-08-2026 en task #255 (pieza 3, v1.82.5): la tarjeta de grupo se quedó fuera del arreglo original y seguía sumando la última foto como si fuera de ahora. Ahora usa el mismo juez que el resumen general; la agregación de SSIDs (_aggregate_ssids) también se salta a los APs sin dato vivo.

Frontend


Contrato de tests

5 tests en tests/api/test_monitoring.py::TestWirelessClientFreshness:

  1. test_summary_ignores_clients_of_dead_aps: AP up (5 clientes) + AP down (200 en foto) → total = 5
  2. test_busiest_ap_is_never_a_stale_photo: Busiest AP es siempre del que está vivo
  3. test_status_list_zeroes_stale_client_counts: status-list devuelve 0 para dead APs
  4. test_ap_without_monitoring_target_does_not_count: Sin target no hay señal de vida (huérfano → 0)
  5. test_fleet_report_excludes_stale_and_reports_how_many: Fleet report cuenta y expone stales

Deuda — CERRADA

La deuda original decía que deep_snmp_data no lleva fecha en ninguna parte (ni en el JSON del Agente, ni como campo del modelo, ni en last_updated) y que por eso el fix de esta página no podía decir cuándo era la foto, solo dejar de sumarla.

Esa deuda quedó cerrada por v1.66.16 (migración network/0060, campo DeviceProfile.deep_snmp_updated_at) — ver [[feature—wireless—deep-discovery-timestamp]]. El 23-08-2026 (task #255) se corrigió además el comentario del código que seguía afirmando la versión vieja (“no lleva fecha en ninguna parte”), que había quedado rancio desde v1.66.16 sin que nadie lo tocara.


Impacto en observabilidad


Evolución — v1.85.2 (ciclos 5 y 6 de la auditoría #261): el juez ahora también mira SNMP vivo

El juez original de esta página (_has_current_clients / _current_client_count) solo confiaba en MonitoringTarget.last_status == "up", es decir, en el ping. En el CCIB, donde la red filtra ICMP hacia los APs, eso hacía que 47 puntos de acceso con SNMP perfectamente vivo salieran en rojo y sin clientes (W-H1, W-H2).

WirelessLive (monitoring/api/wireless.py)

Nueva clase que hace una sola consulta instantánea a VictoriaMetrics por petición (last_over_time(...) sobre snmp_fast_station_count / snmp_extras_connected_clients / snmp_fast_connected_clients, ventana de 2× la cadencia del target + margen, mínimo 3 min) para saber qué targets tienen una muestra SNMP reciente y cuántos clientes reportan ahora mismo.

A42 · /wireless/deep-data con el mismo juez

Este endpoint tenía su PROPIO cálculo de client_count (sumaba clientsPerRadio de la foto sin mirar frescura) y el flujo “Deep Data” del frontend lo escribía en ap.client_count: una regresión de la #225 colándose por otra puerta. Ahora llama a _current_client_count(p, live), igual que el resumen.

Otros arreglos del mismo ciclo (misma familia de honestidad de datos)

Commit 1195434d (PR #439, v1.85.2). Tests: tests/monitoring/test_ciclos5_6_wireless_seguridad.py (9). Sin verificar en la red del CCIB hasta septiembre.


Evolución — v1.85.9 (deuda #274, B1-#12): el conteo por _count_clients_from_deep ya no sale multiplicado

_count_clients_from_deep() — la función que _current_client_count() llama cuando no hay SNMP fresco (ver la sección “Evolución v1.85.2” de arriba) — caía a contar la lista clients de la foto de deep discovery entrada por entrada cuando el AP no traía clientsPerRadio. Esa lista es plana: una fila por OID × cliente, no una fila por cliente. Con 8 OIDs de cliente declarados, el conteo salía ×8. Ahora cuenta index únicos dentro de clients, que sí es un cliente real por fila. Detalle completo de la tanda: [[feature—monitoring—deuda-274-tanda-a]].


Evolución — v1.164.5 (28-09-2026, visto en PROD durante FABCON26): la agregación de SSIDs también exige que la FOTO sea reciente

El arreglo de task #255 (sección “Lectores afectados” de arriba) hizo que get_wireless_group_summary() dejara fuera de la agregación de SSIDs a los APs sin dato vivo — pero un AP “vivo” (con SNMP o ping recientes) puede llevar semanas sin repetir su Deep Discovery, porque esa foto no se renueva sola. En el grupo “CCIB&Forum” (124 APs) esto dejaba colarse en la tabla de SSIDs redes de eventos ya terminados (MorganMoney, PXP26 WORLD TOUR) por delante de la red del evento en curso: el filtro miraba si el AP estaba vivo, no si la FOTO lo estaba, y 99 de las 124 fotos eran del 16-09.

_ssid_photo_is_recent(profile, now) añade ese segundo filtro: a la agregación solo entra un AP cuya deep_snmp_updated_at tenga menos de SSID_PHOTO_MAX_AGE (60 min, UNVERIFIED — elegido por criterio, no medido). La respuesta de get_wireless_group_summary suma ssids_from_aps (APs cuya foto entró), ssids_old_aps (APs vivos dejados fuera por foto vieja), ssids_as_of (la foto más vieja de las que sí cuentan) y ssids_max_age_minutes; WirelessGroupDetail.js los usa para decir de cuántos APs sale la tabla o, si ninguna foto es reciente, pedir que se relance Deep Discovery en vez de no mostrar nada.

El total de clientes del grupo (total_clients) no cambia — ya salía del dato en vivo desde v1.85.2; este filtro solo afecta a qué fotos entran en la tabla de SSIDs por nombre. Tests: tests/monitoring/test_wireless_grupo_ssids_foto.py (4). Commit 602638f7 (PR #623).


Véase también

Subir