Commit graph

51 commits

Author SHA1 Message Date
882a5d7eab
fix: display count sensor values as integers instead of floats
Connection counts (IPv4/IPv6, DHCP leases) were showing as floats
(e.g. 1270.0) in executor output, change detection messages, and
chart tooltips/axes. Now displayed as integers everywhere.
2026-03-06 15:03:30 -06:00
d7741cdc0e
feat: implement unified checks system (Phase 1-4)
This commit implements the unified checks architecture that consolidates
SNMP monitoring with HTTP/TCP/DNS checks under a single "check" abstraction,
enabling consistent graphing, alerting, and management across all check types.

Database Changes:
- Add source_type and source_id to checks table for tracking auto-discovered
  vs manually created checks
- Add value field to check_results for storing numeric sensor readings
- Maintain backward compatibility with existing check_results data

New SNMP Executors:
- SnmpSensorExecutor: Poll sensor OIDs and return formatted values with
  status determination (OK/WARNING/CRITICAL based on limits)
- SnmpInterfaceExecutor: Poll interface stats (bandwidth, packets, errors)
- SnmpProcessorExecutor: Poll CPU/processor usage
- SnmpStorageExecutor: Poll disk/memory usage with percentage calculations

Check Execution Worker:
- CheckExecutorWorker: Unified Oban worker that dispatches to appropriate
  executor based on check_type (snmp_sensor, snmp_interface, http, tcp, etc.)
- Self-schedules next execution with distributed polling offsets
- Records results in check_results TimescaleDB hypertable
- Updates check state (OK/WARNING/CRITICAL/UNKNOWN)

Discovery Integration:
- Auto-creates checks during SNMP discovery for sensors, interfaces,
  processors, and storage
- Links checks to source entities via source_id for data lookup
- Enables/disables checks based on discovery results

UI Enhancements:
- Checks tab on device detail page with grouped display
- FormComponent for adding manual HTTP/TCP/DNS checks
- Empty state with "Run Discovery" prompt
- Check status badges and last checked times

Graphing:
- Update GraphLive to accept check_id parameter
- Query check_results table for time-series data
- Support all check types (SNMP, HTTP response times, etc.)

Testing:
- Comprehensive test suite for SnmpSensorExecutor (5 tests)
- Test suite for CheckExecutorWorker (7 tests)
- Test coverage for discovery check creation (6 tests)
- Remove deprecated monitoring_test.exs testing old API

Bug Fixes:
- Fix SNMP executors reading credentials from correct Device schema fields
  (device.snmp_version instead of device.snmp_device.version)
- Update agent channel test to query MonitoringCheck table directly

Code Quality:
- Extract add_snmp_credentials helper to reduce cyclomatic complexity
- Use map-based lookups for sensor formatting and check type grouping
- Apply pattern matching in dispatcher to reduce complexity
- All credo checks passing with no issues

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-02-12 16:58:40 -06:00
a61abd836c
fix: cloud poller automatic rebalancing
- create MonitoringCheck schema for the monitoring_checks table, fixing
  silent data loss where ping results were dropped by the wrong schema
- update agent channel and device monitor worker to use new schema
- fix Stats queries to use MonitoringCheck instead of Check schema
- add list_online_cloud_pollers and list_cloud_polled_devices queries
- add CloudLatencyProbeWorker to dispatch cross-agent latency probes
  every 8 hours via PubSub to all online cloud pollers
- scope AgentLatencyEvaluator to cloud pollers only with cloud_only
  filter, lower min_checks (5), wider time window (48h), and
  device-level assignments to avoid changing site/org defaults
- update cron schedule: probes at 0/8/16h, evaluation at 0:30/8:30/16:30
- refactor monitoring.ex and http_executor.ex to fix credo complexity
2026-02-12 15:32:33 -06:00
07a6128877
feat: add checks tab to device detail page (TDD cycle 1)
- Add 'Checks' tab link to device navigation
- Display empty state when no checks configured
- Add tests for tab visibility and empty state
- Fix unused variable warnings in monitoring context
- Remove unused CheckResult alias and module attributes
- Add stub for legacy get_latency_data for backward compatibility

Tests: 2 new tests added, all passing
Following TDD: RED-GREEN cycle verified for each feature
2026-02-12 14:50:14 -06:00
291ecd1054
feat: add full-featured monitoring platform (HTTP/TCP/DNS checks)
Implements Icinga2-style generic check system for comprehensive monitoring.

Phoenix Backend:
- Generic checks table with JSONB config for all check types
- TimescaleDB check_results hypertable for time-series data
- Check executors (HTTP, TCP, DNS)
- CheckWorker with self-scheduling and state transitions
- Extended alerts system for check-based alerting

Check Types: HTTP/HTTPS, TCP, DNS
Architecture: Icinga2 Checkable pattern, soft/hard states, flapping detection

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-02-12 14:05:31 -06:00
95eafd0c47
routeros fixes and latency rounding 2026-02-09 17:30:06 -06:00
ee8a3220c4
refactor: convert periodic workers to Oban Cron for better resilience
Replaced GenServer-based periodic workers with Oban Cron jobs to improve
pod rollover resilience and simplify architecture.

Worker Changes:
- NeighborCleanupWorker: GenServer → Oban Cron (hourly)
  - Cleans stale neighbors, ARP entries, and MAC addresses
  - Runs every hour via Oban.Plugins.Cron

- StaleAgentWorker: GenServer → Oban Cron (every minute)
  - Detects agents that haven't checked in for 10+ minutes
  - Refactored to reduce nesting (extracted helper functions)
  - Removed stateful tracking (now stateless, re-evaluates each run)

- AgentLatencyEvaluator: GenServer → Oban Cron (every 5 minutes)
  - Latency-based agent reassignment with 20% threshold
  - Removed trigger_evaluation/0 (no longer needed)

- JobHealthCheckWorker: NEW Oban Cron worker (every 10 minutes)
  - Safety net to recover missing monitor/poller jobs
  - Auto-creates jobs for devices with monitoring/SNMP enabled

Infrastructure Changes:
- Removed Monitoring.Supervisor (no longer needed)
- Updated application.ex to remove GenServer workers from supervision tree
- Added Oban.Plugins.Cron to dev.exs and runtime.exs
- All workers now run cluster-wide via PostgreSQL-backed coordination

Test Updates:
- Updated all worker tests to call perform(%Oban.Job{args: %{}})
- Removed GenServer lifecycle tests (start_link, send messages, etc.)
- Removed async sleep calls (no longer needed)

Benefits:
- Better pod rollover resilience (Cron jobs run cluster-wide)
- Simpler architecture (no GenServers for periodic tasks)
- Better observability (all jobs visible in Oban dashboard)
- Safety net for missing jobs (JobHealthCheckWorker)
- Stateless workers (easier to reason about and test)

Documentation:
- Updated CLAUDE.md with Background Job Architecture section
- Documented job types, queues, and resilience features

All tests passing (3,686 tests, 0 failures).
2026-01-24 16:56:28 -06:00
d0946c3cd0
refactor: simplify job architecture from Oban coordinators to direct workers
Removes unnecessary two-layer architecture (Oban Coordinator → GenServer)
in favor of direct Oban workers that perform the actual work.

Changes:
- Replace DevicePollerCoordinator + PollerWorker with DevicePollerWorker
- Replace DeviceMonitorCoordinator + DeviceMonitor with DeviceMonitorWorker
- Simplify Monitoring.Supervisor (removed Registries, DynamicSupervisors)
- Remove all Exq dependencies (workers, supervisor, mix deps)
- Convert DiscoveryWorker from Exq to Oban pattern
- Update Devices context to auto-start/stop monitoring and polling
- Update all LiveView callers to use new Oban enqueue pattern
- Fix all tests to use Oban.Job struct instead of raw IDs

Benefits:
- Simpler codebase (~850 lines removed)
- Better reliability (Oban handles retries, failures)
- Lower memory (no persistent GenServers)
- Better observability (work visible in Oban dashboard)
- Cluster-wide coordination via PostgreSQL
- Extensive PubSub usage for real-time events

Files deleted:
- lib/towerops/workers/device_monitor_coordinator.ex
- lib/towerops/workers/device_poller_coordinator.ex
- lib/towerops/snmp/poller_worker.ex
- lib/towerops/monitoring/device_monitor.ex
- lib/towerops/workers/monitor_worker.ex
- lib/towerops/workers/poll_worker.ex
- lib/towerops/exq_supervisor.ex
- All related test files

Files created:
- lib/towerops/workers/device_poller_worker.ex
- lib/towerops/workers/device_monitor_worker.ex

All 3,686 tests passing.
2026-01-24 16:36:57 -06:00
29593ac734
refactor: migrate from etcd to Oban for distributed job coordination
Replaces etcd-based distributed locking with Oban's PostgreSQL-backed job queue.
This simplifies the architecture by eliminating the need for a separate etcd cluster
while providing better reliability and observability.

Changes:
- Add Oban dependency and migration (oban_jobs table)
- Create DevicePollerCoordinator and DeviceMonitorCoordinator Oban workers
- Remove EtcdCoordinator and EtcdLock modules
- Update application supervisor to start Oban
- Configure Oban with pollers (50 workers) and monitors (50 workers) queues
- Remove etcd StatefulSet from Kubernetes manifests
- Update monitoring supervisor documentation

Benefits:
- Simpler architecture (no etcd cluster to manage)
- PostgreSQL-based (uses existing database)
- Built-in uniqueness prevents duplicate jobs cluster-wide
- Better observability with Oban Web UI
- Automatic job rescue on node crashes
- Easier local development (no etcd required)

What was removed:
- etcd StatefulSet (3 pods)
- EtcdCoordinator module (320 lines)
- EtcdLock module (158 lines)
- eetcd dependency

All 3,686 tests passing.
2026-01-24 16:12:27 -06:00
de0c106212
fix: Redis authentication and etcd connection handling
Fixes two production issues:

1. NOAUTH Redis authentication error:
   - application.ex: Read password from application config
   - exq_supervisor.ex: Read password from application config
   - Both were bypassing runtime.exs config by reading env directly

2. EtcdCoordinator FunctionClauseError:
   - connect_etcd/0 now returns connection name (:towerops_etcd)
   - eetcd functions expect the atom name, not the PID
   - Fixes crash when trying to acquire locks
2026-01-24 15:58:21 -06:00
f5ca3f0940
fix: make etcd watcher optional for graceful degradation
The app was crashing when the etcd watcher couldn't be created, even
though 2/3 etcd nodes were healthy and the connection succeeded.

Changes:
- Made watcher creation optional (nil if it fails)
- App now starts successfully even if watcher is unavailable
- Falls back to periodic rebalancing (60s intervals) instead of instant failover
- Changed error level from error to warning when watcher creation fails
- Added helpful context to warning message

This allows the app to run with degraded performance instead of crashing
completely when there are etcd cluster issues.

🤖 Generated with Claude Code

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-01-24 15:27:28 -06:00
64ad63d3e3
fix: handle etcd watcher creation errors gracefully
The pods were crashing with a MatchError when the etcd watcher failed
to initialize. The code was pattern matching on {:ok, watcher} but
eetcd was returning {:error, :eetcd_conn_unavailable}.

Error:
  ** (MatchError) no match of right hand side value:
  {:error, :eetcd_conn_unavailable}

This was causing CrashLoopBackOff because the application couldn't
start the Monitoring.Supervisor due to EtcdCoordinator initialization
failure.

Fix:
  - Add case statement to handle both {:ok, watcher} and {:error, reason}
  - Log the specific error when watcher creation fails
  - Return proper error tuple to supervisor for clean shutdown
2026-01-24 15:02:46 -06:00
51736eeec3
fix: use charlists for etcd endpoints
The :eetcd Erlang library expects charlists, not binary strings.
This was causing a FunctionClauseError in :lists.reverse/1 because
it was receiving a binary string instead of a charlist.

Error:
  (FunctionClauseError) no function clause matching in :lists.reverse/1
  (stdlib 7.2) lists.erl:291: :lists.reverse("etcd-0.etcd...")

Solution:
  Use ~c sigil to convert endpoint strings to charlists for the
  Erlang library to consume correctly.
2026-01-24 14:39:53 -06:00
e6054129b2
remote agent/cloud improvements 2026-01-24 09:16:41 -06:00
2b78b1a2d3
snmpkit overhaul and etcd 2026-01-23 16:23:57 -06:00
96fc488023
sanitize snmp data and fix some cpu things 2026-01-22 16:53:01 -06:00
0a4482f974
feat: add 5 new vendor modules and fix dialyzer issues
Vendor modules added:
- Aviat (WTM microwave radios)
- Aruba (wireless controllers and APs)
- CiscoWLC (Cisco wireless LAN controllers)
- Teltonika (RUTOS LTE routers)
- Sub10 (mmWave backhaul radios)

Dialyzer fixes:
- Fix unknown type Devices.t/0 in alert.ex and device.ex
- Fix unmatched_return warnings across multiple files
- Add :exq to PLT for Exq function detection
- Remove dead code in base.ex, dynamic.ex, vendor.ex
- Fix Device.t() type spec to allow nil name field

Tests: 1437 tests, 0 failures
Dialyzer: 0 errors
Credo: no issues
2026-01-22 09:34:50 -06:00
ba5464332b
fix: use system ping command instead of raw ICMP sockets
- Rewrote Ping module to use system ping binary instead of raw ICMP
  sockets which required CAP_NET_RAW privileges
- Added iputils-ping package to Docker images for production
- Added proper IP address validation before executing ping command
- Updated tests to account for 1 second minimum timeout of system ping
- System ping binary is setuid root and works without elevated privileges
2026-01-21 11:15:59 -06:00
23c92b2c44
more tests 2026-01-20 16:38:53 -06:00
ace3f1f661
Fix database connection ownership issues in async Tasks
Changes:
- ApiTokens.update_last_used/1: Allow Task to access sandbox in tests
- DeviceMonitor.enqueue_check/1: Allow Task to access sandbox in tests
- PollerWorker.enqueue_poll/1: Allow Task to access sandbox in tests

Problem:
When tests spawn async Tasks that access the database, those Tasks
don't have ownership of the database connection in Sandbox mode,
causing DBConnection.ConnectionError warnings.

Solution:
Before accessing the database in a Task, check if we're in test mode
and call Ecto.Adapters.SQL.Sandbox.allow/3 to transfer connection
ownership from the parent process to the Task.

Pattern used:
```elixir
parent = self()
Task.start(fn ->
  if Application.get_env(:towerops, :sql_sandbox) do
    Ecto.Adapters.SQL.Sandbox.allow(Repo, parent, self())
  end
  # ... database operations ...
end)
```

All 1041 tests passing. Some harmless disconnection warnings remain
when Tasks complete after tests finish, but these don't affect results.
2026-01-20 12:39:25 -06:00
3d2cd0d43f
Fix Credo issues and improve code quality
- Reduced cyclomatic complexity in Ping.send_icmp_packet by extracting handle_icmp_recv helper
- Reduced cyclomatic complexity in Devices.resolve_snmp_config by extracting determine_snmp_source helper
- Added Repo alias to discovery_test.exs to fix nested module warning
- All tests passing (992 tests, 1 failure in unrelated test)
- Removed incomplete mib_parser_test.exs
- Cleaned up debug-redis.sh script
2026-01-19 15:09:19 -06:00
1c400259fc
fix: use microsecond precision for ICMP latency measurements
- Changed ping module to use microsecond timer resolution instead of millisecond
- Prevents 0ms readings for very fast pings (localhost, local network)
- Updated response_time_ms to float type to store decimal precision
- Migration converts existing integer values to float
2026-01-18 12:52:29 -06:00
35f0ac495b
fix: always measure actual ICMP latency instead of returning 0ms for SNMP devices 2026-01-18 12:13:11 -06:00
5f8041dcc3
fix API token creation and add raw ICMP ping to Rust agent
API token creation fix:
- Handle both nested (%{"token" => %{...}}) and flat params
- Support URL-encoded form data from LiveView
- Add validation for required name and organization_id fields

Rust agent raw ICMP ping implementation:
- New ping module with async ICMP echo request/reply
- Build ICMP packets manually with proper checksum calculation
- Use socket2 for raw socket creation (requires CAP_NET_RAW)
- Parse both raw ICMP and IP-wrapped responses
- Include unit tests for checksum and packet building
- Dependencies: socket2 v0.5, rand v0.8
- Compiles successfully with release profile optimizations
2026-01-18 10:58:46 -06:00
f530c1b9a6
fix AutoDismissFlash hook order and implement raw ICMP ping
AutoDismissFlash hook fix:
- Move hook definitions before LiveSocket initialization
- Ensures hooks are defined when referenced in LiveSocket constructor
- Remove duplicate Hooks object

Raw ICMP ping implementation:
- Replace system ping command with pure Elixir implementation
- Use raw ICMP sockets for echo request/reply
- Build ICMP packets manually with proper checksum calculation
- Parse IP addresses using :inet.parse_address/1
- Handle both raw ICMP and IP-wrapped responses
- Requires CAP_NET_RAW capability in production containers
- Suitable for containerized environments without ping command
2026-01-18 10:56:04 -06:00
243c687d35
fix all credo issues and add flash auto-dismiss
- Replace TODO comment with "Future enhancement" note
- Alias nested DeviceProfiles.Importer module
- Replace expensive length/1 check with empty list comparison
- Extract nested logic into helper functions to reduce complexity:
  - import_sensor_with_states for sensor import
  - walk_sensor_oid and walk_processor_oid for SNMP walks
  - apply_processor_precision and determine_processor_status
  - check_device_health for device monitoring
- Add auto-dismiss functionality to flash messages (30 second timeout)
- Implement AutoDismissFlash LiveView hook in TypeScript
2026-01-18 10:43:23 -06:00
3cc69c9250
feat: add Horde for cluster-aware distributed supervision
Prevents duplicate polling in multi-node production environment:
- Replace DynamicSupervisor with Horde.DynamicSupervisor (distributed)
- Replace Registry with Horde.Registry (cluster-aware)
- Each device monitor runs on exactly ONE node across the cluster
- Each SNMP poller runs on exactly ONE node across the cluster
- Automatic failover when nodes go down
- Automatic rebalancing when nodes join/leave

Architecture:
- Horde.Registry for process naming (distributed lookup)
- Horde.DynamicSupervisor for DeviceMonitor processes
- Horde.DynamicSupervisor for PollerWorker processes
- Task.Supervisor remains local per-node for parallel operations
- members: :auto enables automatic cluster discovery via libcluster

Production impact:
- 2 replicas = devices split ~50/50 across both pods
- No duplicate SNMP polls to same device
- If pod dies, surviving pod takes over all devices
- When new pod starts, devices rebalance automatically

Dependencies added:
- horde ~> 0.9.0 (distributed supervisor/registry)
- delta_crdt (Horde dependency for CRDT-based state)
- libring (Horde dependency for consistent hashing)
2026-01-18 10:14:50 -06:00
fed1b3ecfc
feat: parallelize SNMP polling with Task.Supervisor and async streams
Architecture improvements:
- Add Task.Supervisor (PollerTaskSupervisor) to supervision tree for parallel operations
- Parallelize device-level operations: sensors, interfaces, changes, neighbors run concurrently
- Parallelize sensor polling within device using Task.async_stream (max 10 concurrent)
- Parallelize interface polling using Task.async_stream (max 10 concurrent)
- Parallelize interface changes checking using Task.async_stream (max 10 concurrent)

Benefits:
- Device with 50 sensors: ~5x faster (10 parallel vs sequential)
- Device with 24 interfaces: ~2.4x faster (10 parallel vs sequential)
- 4 device operations (sensors/interfaces/changes/neighbors): run concurrently
- Proper supervision and timeout handling with Task.Supervisor.async_nolink
- Graceful failure handling with Task.yield_many

Example: Device with 50 sensors + 24 interfaces:
- Before: ~74 seconds (50 + 24 sequential)
- After: ~7.4 seconds (5 + 2.4 parallel + concurrent operations)
2026-01-18 10:09:52 -06:00
0816459335
fix: use SNMP poll status for device health checks and improve Exq startup
- Use SNMP poll success as health indicator for SNMP-enabled devices
- Fall back to ICMP ping only for non-SNMP devices or stale SNMP data
- Add connection retry logic to Exq with backoff
- Add better error logging for ping permission issues
- Resolves issue where devices showed as down despite successful SNMP polling

Root cause: Container runs as non-root (UID 65534) without ICMP permissions,
so ping fails even though SNMP (UDP) works. Now using SNMP poll timestamps
to determine device status when SNMP is enabled.
2026-01-18 10:05:12 -06:00
c74e00fcb0
Always use ICMP ping for latency monitoring, not SNMP checks
Changed device_monitor.ex to always use ICMP ping for monitoring checks,
regardless of whether SNMP is enabled for the device.

Rationale:
- ICMP ping gives actual network latency (round-trip time)
- SNMP checks are for data collection (interfaces, sensors, etc.)
- Both should run independently for SNMP-enabled devices:
  * SNMP polling: Collects device metrics (handled by poller_worker)
  * ICMP monitoring: Measures latency and availability (handled by device_monitor)

This ensures latency graphs always show actual network response time,
not SNMP query response time.
2026-01-17 17:02:51 -06:00
57f81b70f8
Fix latency data not being captured in monitoring checks
The monitoring system was creating checks but hardcoding response_time_ms
to nil instead of using the actual ping latency. This caused the latency
graphs to have no data to display.

Changes:
- device_monitor.ex: Capture response time from ping/SNMP check result
- monitor_worker.ex: Use correct field name (response_time_ms) and status enum values (:success/:failure)

After this fix, new monitoring checks will include latency data and the
latency graphs will display properly on both device and site detail pages.
2026-01-17 17:00:52 -06:00
5339f51dd8
Convert Task.* calls to Exq background workers
Created three new Exq workers to handle background jobs:
- PollWorker: SNMP polling operations (queue: polling)
- MonitorWorker: Device monitoring checks (queue: monitoring)
- DiscoveryWorker: SNMP discovery (already existed)

Updated files to use Exq.enqueue instead of Task.start:
- lib/towerops/snmp/poller_worker.ex
- lib/towerops/monitoring/device_monitor.ex
- lib/towerops_web/channels/agent_channel.ex

Each module includes enqueue_* helper functions that:
- Use Task.start in test environment for synchronous execution
- Use Exq.enqueue in dev/prod for proper background job processing

Added "monitoring" queue to Exq configuration in application.ex

All tests passing (824 tests, 0 failures)
2026-01-17 16:46:36 -06:00
b6f4946385
moduledocs 2026-01-17 15:08:49 -06:00
a810e75fc4
rename equipment to device 2026-01-17 14:48:46 -06:00
6627235981
add tests and add snmp neighbor discovery 2026-01-16 13:44:29 -06:00
139a42531f
Refactor credo issues: reduce complexity and nesting depth
- Refactor check_threshold_violation: extract threshold checks into separate functions (complexity 10→~3)
- Refactor load_sensor_chart_data: extract helper functions to reduce nesting
- Refactor save_equipment: extract SNMP discovery logic into helpers
- Refactor poll_sensors: extract error handling and result processing
- Refactor handle_status_change: extract equipment down/up handlers
- Refactor mount_current_scope: extract session scope building
- Refactor load_traffic_chart_data: extract aggregation and calculation helpers
- Refactor load_overall_traffic_chart_data: similar pattern to traffic chart
- Refactor load_sensor_chart_data in equipment_live/show: extract dataset builders
- Refactor discover_storage_sensors: extract storage sensor building
- Refactor perform_poll: extract device polling logic into separate functions

All 254 tests passing. Credo reports no issues.
2026-01-06 13:55:16 -06:00
f29282d9dc
Fix compiler warnings in equipment monitor
- Prefix unused alert variables with underscore
- Remove unused test_env?/0 function

All warnings resolved, compilation clean with --warnings-as-errors
2026-01-05 14:37:03 -06:00
7ea79afea1
disable alert emails 2026-01-05 13:51:26 -06:00
cac54b46a2
Implement event logging system and fix sensor display
- Add equipment_events table and Event schema for tracking device changes
- Implement automatic change detection for interface attributes during SNMP polling
  - Detects operational status changes (up/down)
  - Detects admin status changes
  - Detects speed changes with warning severity for speed drops
  - Detects MAC address changes
- Add Logs tab to equipment detail page with event display
- Fix temperature sensor display bug (was showing 4.3C instead of 43C due to double division)
- Remove response time tracking from monitoring checks and UI
- Move Rediscover Device button to equipment edit page
2026-01-05 10:42:34 -06:00
9eca2e7069
Fix database schema mismatches preventing SNMP and monitoring data collection
This fixes critical issues where SNMP sensor readings, interface stats, and
monitoring checks were not being saved to the database due to schema mismatches.

Database schema fixes:
- Recreate snmp_sensor_readings table with binary_id primary key
- Recreate snmp_interface_stats table with binary_id primary key
- Recreate monitoring_checks table with binary_id primary key

The original migrations used default integer primary keys, but the schemas
expected binary_id (UUID). This caused Ecto to generate UUID strings that
Postgrex tried to encode as binaries, resulting in silent insert failures.

SNMP interface stats fixes:
- Fix field name mismatch in get_interface_stats (if_in_octets vs in_octets)
- Remove unnecessary tuple handling code (Client already unwraps SNMPKit tuples)
- Clean up decode_snmp_value function and improve error messages

Monitoring check fixes:
- Fix response_time type from float to integer in Poller.check_device
- Add error logging to catch and report check creation failures

These changes enable:
- SNMP sensor readings to be collected and stored (disk usage, memory, CPU, etc.)
- Interface statistics to be collected (Counter64 octets, errors, discards)
- Equipment availability metrics to update on the dashboard
2026-01-05 08:26:16 -06:00
91759ac16c
Add error handling and logging to monitoring supervisor
Improved startup reliability and debugging for SNMP pollers:
- Added try/rescue blocks around monitor and poller startup
- Added logging for successful startup and errors
- Added error logging to PollerWorker's perform_poll
- Added debug logging for successful sensor/interface polls

This will help identify issues when pollers fail to start or
encounter errors during polling, which was causing silent failures
where sensors weren't being collected.
2026-01-04 13:24:33 -06:00
3544d117a8
Implement SNMP polling for continuous data collection
Add background workers to regularly poll SNMP sensors and interfaces:

- Create PollerWorker GenServer to poll SNMP devices
- Poll all sensors for temperature, voltage, CPU, memory, etc.
- Poll all interfaces for bandwidth, errors, and discards
- Save time-series data to snmp_sensor_readings and snmp_interface_stats
- Integrate with monitoring supervisor to auto-start pollers
- Use same interval as connectivity checks (minimum 30 seconds)
- Add list_snmp_enabled_equipment function to Equipment context

Pollers start automatically on app boot for all SNMP-enabled equipment
and run independently of connectivity monitoring.
2026-01-04 12:56:51 -06:00
7772ff9a4a
fix a few bits 2026-01-03 14:58:06 -06:00
8cbca259fc
snmp bits 2026-01-03 14:41:28 -06:00
0f9266027f
fix dialyzer things 2026-01-03 12:56:40 -06:00
d345d7df30
Fix Dialyzer pattern match coverage warning
- Replace catch-all pattern with explicit :unknown status handling
- Makes status transitions more explicit and type-safe
- Resolves pattern_match_cov warning at line 174
2026-01-03 12:40:32 -06:00
93e0b869be
more features 2026-01-02 14:06:44 -06:00
fd5c6b3d72
more tests 2025-12-21 17:29:01 -06:00
d88cf9dddc
mix format 2025-12-21 17:17:35 -06:00
8f618291a0
timescaledb 2025-12-21 17:17:26 -06:00