Implemented all critical and nice-to-have Arista sensor improvements identified
in LibreNMS parity audit. Upgrades Arista EOS support from 85% to 100% parity.
Files Changed:
- lib/towerops/snmp/profiles/vendors/arista.ex (enhanced)
Added 4 major enhancements:
1. DOM power conversion (watts→dBm): Detects optical power sensors via regex,
converts using formula dBm = 10*log10(watts*1000), preserves original value
in metadata
2. Arista threshold discovery: Walks ARISTA-ENTITY-SENSOR-MIB threshold table
(OID 1.3.6.1.4.1.30065.3.3.1.1.1), applies 4 threshold types (low_critical,
low_warn, high_warn, high_critical), converts thresholds to dBm for optical
sensors
3. Smart grouping: Organizes sensors by SFPs, PSUs, Platform (chipsets), Power
Connectors, System for better UX
4. Description cleanup: Removes redundant "sensor" text, simplifies PSU naming,
cleans whitespace
- lib/towerops/snmp/profiles/dynamic.ex (integration)
Added apply_vendor_post_processing/3 to call Arista enhancements after sensor
discovery. Applies to both arista_eos and arista-mos profiles.
- test/towerops/snmp/profiles/vendors/arista_test.exs (comprehensive tests)
Added 23 new tests covering:
- DOM conversion (6 tests): Rx/Tx power, Xcvr power, non-DOM sensors, edge cases
- Threshold discovery (4 tests): Basic thresholds, dBm conversion, no thresholds,
SNMP failures
- Smart grouping (6 tests): SFPs, Xcvr, PSUs, power connectors, platform, system
- Description cleanup (5 tests): Trailing sensor, duplicate Sensor strings, PSU
naming, hotspot, whitespace
- End-to-end post-processing (1 test): All enhancements in correct order
All tests passing (30/30 in arista_test.exs, 6367/6367 total).
Result: Arista EOS support upgraded from 85% to 100% LibreNMS parity. All critical
gaps closed: optical power now displayed correctly in dBm, alerting enabled via
thresholds, sensors organized for better UX, descriptions cleaned up.
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
181 lines
12 KiB
Text
181 lines
12 KiB
Text
CHANGELOG - towerops-web
|
|
========================
|
|
|
|
2026-02-11 - feat: implement Arista EOS sensor enhancements (DOM power, thresholds, grouping)
|
|
- Files: lib/towerops/snmp/profiles/vendors/arista.ex (enhanced)
|
|
Implemented all critical and nice-to-have Arista sensor improvements identified in audit:
|
|
1. DOM power conversion (watts→dBm): Detects optical power sensors via regex, converts
|
|
using formula dBm = 10*log10(watts*1000), preserves original value in metadata
|
|
2. Arista threshold discovery: Walks ARISTA-ENTITY-SENSOR-MIB::aristaEntSensorThresholdTable,
|
|
applies 4 threshold types (low_critical, low_warn, high_warn, high_critical), converts
|
|
thresholds to dBm for optical sensors
|
|
3. Smart grouping: Organizes sensors by SFPs, PSUs, Platform (chipsets), Power Connectors, System
|
|
4. Description cleanup: Removes redundant "sensor" text, simplifies PSU naming, cleans whitespace
|
|
- Files: lib/towerops/snmp/profiles/dynamic.ex (integration)
|
|
Added apply_vendor_post_processing/3 to call Arista enhancements after sensor discovery.
|
|
Applies to both arista_eos and arista-mos profiles.
|
|
- Files: test/towerops/snmp/profiles/vendors/arista_test.exs (comprehensive tests)
|
|
Added 23 new tests covering DOM conversion (6 tests), threshold discovery (4 tests),
|
|
smart grouping (6 tests), description cleanup (5 tests), and end-to-end post-processing (1 test).
|
|
All tests passing (30/30 in arista_test.exs, 6367/6367 total).
|
|
- Result: Arista EOS support upgraded from 85% to 100% LibreNMS parity. All critical gaps closed:
|
|
optical power now displayed correctly in dBm, alerting enabled via thresholds, sensors
|
|
organized for better UX, descriptions cleaned up.
|
|
|
|
2026-02-11 - audit: Phase 2 - complete top vendor sensor analysis (Cisco, Juniper, Arista)
|
|
- Files: docs/librenms-audit/sensors/*.md, PHASE2-VENDOR-ANALYSIS.md (new)
|
|
Completed comprehensive sensor discovery analysis for top 3 enterprise vendors:
|
|
- cisco-ios-comparison.md: Cisco IOS/XE/XR/NX-OS analysis (95% parity, production ready)
|
|
- juniper-junos-comparison.md: JunOS analysis (100% IDENTICAL - perfect parity)
|
|
- arista-eos-comparison.md: Arista EOS analysis (85% parity, gaps identified)
|
|
- PHASE2-VENDOR-ANALYSIS.md: Comprehensive summary and recommendations
|
|
- Key findings:
|
|
- Cisco: All critical sensors covered, YAML-based discovery, minor cellular gaps (rare devices)
|
|
- Juniper: junos.yaml byte-for-byte identical (30+ sensor types, 38+ OIDs, 10 MIBs)
|
|
- Arista: Missing DOM power conversion (watts→dBm) and ARISTA-ENTITY-SENSOR-MIB thresholds
|
|
- Identified actionable fixes for Arista (2 critical, 2 minor):
|
|
1. DOM Rx/Tx power conversion (2-3 hours, enables proper optical monitoring)
|
|
2. Arista threshold discovery (4-6 hours, enables alerting)
|
|
3. Smart grouping (2-3 hours, UX improvement)
|
|
4. Description cleanup (1-2 hours, cosmetic)
|
|
- Towerops advantages: CPU/Memory/Uptime sensors (Arista), PSU/Fan state (Arista),
|
|
cleaner YAML architecture, index templates, pre-resolved MIB cache
|
|
|
|
2026-02-11 - audit: complete LibreNMS parity audit and add missing OS detection profiles
|
|
- Files: docs/librenms-audit/*.md (new)
|
|
Completed comprehensive audit comparing Towerops device detection and sensor discovery
|
|
against LibreNMS. Created detailed documentation:
|
|
- detection-algorithm.md: LibreNMS 2-pass detection system analysis
|
|
- towerops-detection.md: Towerops 4-phase detection system analysis
|
|
- vendor-detection-comparison.csv: Priority vendor comparison (MikroTik, Ubiquiti)
|
|
- librenms-sensors.md: LibreNMS sensor discovery architecture (360+ modules, 24 types)
|
|
- EXECUTIVE-SUMMARY.md: Overall findings (99.5% detection parity, 95%+ sensor parity)
|
|
- IMPLEMENTATION-STATUS.md: Phase 1 completion status
|
|
- Files: priv/profiles/os_detection/conteg-pdu.yaml, microsens-g6.yaml (new)
|
|
Added 2 missing OS detection profiles from LibreNMS to achieve 100% profile parity
|
|
(786 profiles total). Conteg PDU for power monitoring devices, MICROSENS G6 for
|
|
network switches.
|
|
- Key findings: Towerops has full detection parity with LibreNMS plus architectural
|
|
enhancements (4-phase matching, Rust NIF MIB resolution, ETS caching, index templates).
|
|
MikroTik coverage verified: all 22 sensor tables discovered identically. Ubiquiti
|
|
coverage: 8 of 9 profiles identical (airos-af has additional fallback in Towerops).
|
|
|
|
2026-02-11 - test: add 100% coverage for ExpiredBanCleanupWorker
|
|
- File: test/towerops/workers/expired_ban_cleanup_worker_test.exs (new)
|
|
Added 7 tests covering perform/1: expired ban deletion, active ban preservation,
|
|
permanent ban preservation, mixed scenarios, empty database, PubSub broadcast
|
|
on deletion, and no broadcast when nothing deleted.
|
|
|
|
2026-02-11 - fix: handle "null" string values in SNMP parsing
|
|
- File: lib/towerops/snmp/profiles/base.ex (parse_integer/1, parse_float/1)
|
|
Added explicit handling for "null" string values before attempting integer/float
|
|
conversion. Some devices (e.g., AirOS 8.7.14) return the literal string "null"
|
|
for unavailable metrics like UCD CPU stats, which caused ArgumentError when
|
|
parse_integer/parse_float tried to convert them. Now returns nil, which gets
|
|
coerced to 0 by the || 0 fallback in the calling code.
|
|
|
|
2026-02-11 - fix: deduplicate sensors with leading-dot OID differences
|
|
- File: lib/towerops/snmp/profiles/dynamic.ex (deduplicate_by_oid/1)
|
|
Normalized OIDs by stripping leading dots when grouping for deduplication.
|
|
gosnmp (agent) returns OIDs with leading dots (.1.3.6.1...) but vendor
|
|
modules and YAML profiles define them without. Without normalization,
|
|
the same sensor appeared twice (e.g. "DHCP Leases" and "DHCP Lease Count").
|
|
- File: lib/towerops/snmp/discovery.ex (deduplicate_sensors_by_oid/1)
|
|
Same leading-dot normalization applied to the discovery-level deduplication.
|
|
- File: lib/towerops/snmp/profiles/vendors/routeros.ex (wireless_oid_defs/0)
|
|
Removed DHCP Leases entry (mtxrDHCPLeaseCount) since the routeros.yaml
|
|
YAML profile already defines it in count_sensor_oids. Eliminates the
|
|
source of duplication for MikroTik devices.
|
|
- Tests updated in dynamic_test.exs and routeros_test.exs
|
|
|
|
2026-02-11 - fix: agent discovery and polling improvements
|
|
- File: lib/towerops_web/channels/agent_channel.ex (build_polling_queries/1, process_interface_stats/3)
|
|
Changed interface traffic OIDs from 32-bit counters (ifInOctets/ifOutOctets) to 64-bit
|
|
HC counters (ifHCInOctets/ifHCOutOctets). 32-bit counters wrap at ~4.3GB which causes
|
|
wildly inaccurate readings on gigabit+ links.
|
|
- File: lib/towerops/snmp/adapters/replay.ex (parse_value/1)
|
|
Fixed negative integer parsing regex from ^\d+$ to ^-?\d+$ so values like
|
|
entPhySensorScale=-3 are parsed as integers. Previously fell through to string,
|
|
causing sensor divisor calculation to silently return 1 instead of 1000.
|
|
- File: lib/towerops_web/channels/agent_channel.ex (build_discovery_queries/0)
|
|
Replaced walking entire Cisco enterprise tree (1.3.6.1.4.1.9) with targeted subtrees
|
|
for CPU, ENVMON, CDP, and WAP to avoid 50k+ OID responses and timeouts. Added Juniper,
|
|
HP/H3C, Fortinet, and Cambium vendor OIDs for broader device support.
|
|
- File: lib/towerops_web/channels/agent_channel.ex (build_discovery_queries/0)
|
|
Added missing discovery OIDs: ENTITY-STATE-MIB for state sensors, HOST-RESOURCES-MIB
|
|
tables for processors/storage/devices, and UCD-SNMP-MIB for Linux CPU stats fallback.
|
|
- Tests added in replay_test.exs and agent_channel_test.exs
|
|
|
|
2026-02-11 - fix: handle RouterOS version returned as list of integers
|
|
- File: lib/towerops/snmp/profiles/vendors/routeros.ex (detect_version/1)
|
|
Added pattern match to handle case where SNMP version OID returns list
|
|
of integers [7, 20, 6] instead of binary string "7.20.6". Converts list
|
|
to dotted string format using Enum.join/2.
|
|
- File: test/towerops/snmp/profiles/vendors/routeros_test.exs
|
|
Added two test cases for list-formatted versions with and without license level.
|
|
- Bug: Warning logged "Failed to detect version: {:ok, [7, 20, 6]}" even though
|
|
version was successfully retrieved, just in wrong format.
|
|
|
|
2026-02-11 - fix: normalize OIDs so agent-polled sensors match regardless of leading dot
|
|
- File: lib/towerops_web/channels/agent_channel.ex
|
|
Agent (gosnmp) returns OIDs with leading dots (e.g. ".1.3.6.1.4.1.41112...")
|
|
but sensor OIDs stored in DB may omit the dot. process_sensor_reading used
|
|
direct Map.get which silently missed wireless/vendor sensors on Ubiquiti airOS.
|
|
- Fix: Added normalize_oid_keys/1 to strip leading dots from all oid_values keys,
|
|
and normalize sensor.sensor_oid too. Both sides now match without leading dot.
|
|
- File: test/towerops/snmp/sensor_change_detector_test.exs
|
|
Fixed flaky refute_receive tests that subscribed to global "device:events" topic
|
|
and caught unrelated device_discovered events from concurrent async tests.
|
|
Changed to device-specific topic "device:#{device.id}" instead.
|
|
|
|
2026-02-11 - feat: add sensor value change events for all sensor types
|
|
- New file: lib/towerops/snmp/sensor_change_detector.ex
|
|
Extracted shared sensor change detection logic from DevicePollerWorker.
|
|
Detects threshold violations, spike/drop for % sensors, and new
|
|
sensor_value_changed events for all non-% sensors when value changes.
|
|
- File: lib/towerops/devices/event.ex
|
|
Added "sensor_value_changed" to allowed event types.
|
|
- File: lib/towerops/workers/device_poller_worker.ex
|
|
Replaced inline detect_sensor_changes with SensorChangeDetector module.
|
|
Removed ~240 lines of private functions now in shared module.
|
|
- File: lib/towerops_web/channels/agent_channel.ex
|
|
Added change detection and last_value/last_checked_at update to
|
|
process_sensor_reading/3 so agent-polled devices get same events
|
|
as Phoenix-polled devices.
|
|
- New file: test/towerops/snmp/sensor_change_detector_test.exs
|
|
11 tests covering value changes, spike/drop, thresholds, nil handling.
|
|
|
|
2026-02-11 - fix: live polling uses effective agent from site/org cascade
|
|
- File: lib/towerops_web/live/graph_live/show.ex
|
|
- Bug: Live poll mode used Agents.get_device_assignment/1 which only checks
|
|
direct device-level assignments. Devices with agent assigned at site or
|
|
org level fell through to direct Phoenix SNMP instead of routing to agent.
|
|
- Fix: Replaced with Agents.get_effective_agent_token/1 which walks the
|
|
device → site → org cascade, matching how regular polling resolves agents.
|
|
Also simplified request_agent_live_poll_and_wait to accept token_id directly.
|
|
|
|
2026-02-11 - fix: round sensor values to 1 decimal place
|
|
- Files: lib/towerops/workers/device_poller_worker.ex (poll_simple_sensor/2),
|
|
lib/towerops_web/channels/agent_channel.ex (process_sensor_reading/3)
|
|
- Bug: Division by sensor_divisor produced full float precision (e.g. 34.09999999)
|
|
- Fix: Wrap division result with Float.round(..., 1) in both Phoenix and agent paths
|
|
|
|
2026-02-11 - fix: update device status from agent monitoring checks
|
|
- File: lib/towerops_web/channels/agent_channel.ex (store_monitoring_check/2)
|
|
- Bug: Devices polled by remote agents stayed in "unknown" state because
|
|
store_monitoring_check saved the ping result but never called
|
|
Devices.update_device_status/2. The DeviceMonitorWorker (Phoenix-side)
|
|
skips agent-assigned devices entirely, so nothing ever updated status.
|
|
- Fix: Added update_device_status_from_check/2 and handle_agent_status_change/3
|
|
to derive :up/:down from check status, update device, create alerts on
|
|
transitions, and broadcast via PubSub — matching DeviceMonitorWorker behavior
|
|
- Also added alias Towerops.Alerts to the channel module
|
|
|
|
2026-02-11 - fix: update last_snmp_poll_at for agent-polled devices
|
|
- File: lib/towerops_web/channels/agent_channel.ex (process_polling_result/3)
|
|
- Bug: Devices polled by remote agents showed "Last Polled: Never" because
|
|
process_polling_result never called Devices.update_snmp_poll_time/1
|
|
- The Phoenix-side DevicePollerWorker already had this call (line 172),
|
|
but the agent channel path was missing it
|
|
- Fix: Added Devices.update_snmp_poll_time(device) at the top of
|
|
process_polling_result/3, matching the DevicePollerWorker pattern
|