Commit graph

289 commits

Author SHA1 Message Date
45ddcdac80
feat: add physical inventory discovery (Phase 1.4)
- Create snmp_physical_entities table with migration
- Add PhysicalEntity schema with entity_class validation
- Support parent/child hierarchy via parent_entity_id
- Implement discover_physical_entities/1 in Base profile
- Discover chassis, modules, PSUs, fans from ENTITY-MIB
- Map entity class integers to string names
- Add 10 schema tests and 4 discovery tests
- Fix flaky AlertNotifier test with unique names and mailbox clearing
2026-01-21 10:46:27 -06:00
1cf6f327ea
feat: add IP address discovery (Phase 1.3)
- Create snmp_ip_addresses table with migration
- Add IpAddress schema with ip_type validation (ipv4/ipv6)
- Add prefix_length validation based on ip_type
- Implement discover_ip_addresses/1 in Base profile
- Extract IP addresses from IP-MIB ipAdEntTable
- Support multiple IPs per interface with subnet masks
- Add 12 schema tests and 4 discovery tests
2026-01-21 10:36:19 -06:00
579a7bac21
add VLAN schema, migration, and discovery 2026-01-21 10:31:21 -06:00
c3e26a44d6
add state sensor schema, migration, and discovery 2026-01-21 10:25:01 -06:00
7c660169b7
better mib handling and tests 2026-01-21 10:07:07 -06:00
3abd70e133
use password for user regi 2026-01-21 09:13:08 -06:00
1d45699240
discovery no longer deletes historical data 2026-01-20 17:29:58 -06:00
c54b5d81bb
more dark mode 2026-01-20 17:23:11 -06:00
fbad8c64b2
dark mode 2026-01-20 16:56:49 -06:00
23c92b2c44
more tests 2026-01-20 16:38:53 -06:00
a0c6889a22
refactor: improve code quality in ApiTokens.update_last_used
Reduced nesting and extracted helper functions to address credo
warnings. The logic remains the same:
- Test environment: synchronous update
- Production: async Task with sandbox support

Fixes credo warnings:
- Reduced function body nesting (was 3, now 2)
- Extracted spawn_async_update and helper functions
2026-01-20 15:38:07 -06:00
a32a50a5fd
fix: make ApiTokens.update_last_used synchronous in test env
The async Task.start pattern was causing DBConnection.Ownership errors
when tests finished before the spawned Task could complete its database
update. By making the update synchronous in test environment, we ensure
the database connection is properly managed within the test process.

In production, we still use the async Task.start to avoid blocking
requests when updating last_used_at timestamps.

Fixes all "owner #PID<...> exited" errors in test suite.
2026-01-20 15:30:14 -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
fcc1fbbe73
Refactor MonitorWorker to use ping adapter and eliminate real network traffic from tests
Changes:
- Updated MonitorWorker to use configured ping_module adapter instead of System.cmd
- Removed direct ping command execution and regex parsing
- Simplified ping_device/1 to use adapter.ping/2 (mockable in tests)
- Added PingMock expectations to all MonitorWorker tests
- Removed @tag :integration from unreachable host test (now mocked)
- All ping calls now use mocked responses in tests

Benefits:
- MonitorWorker tests now run in 0.2s instead of 5+ seconds
- No real ICMP network traffic during test runs
- Tests are deterministic and don't depend on network conditions
- Follows same adapter pattern as SNMP (testable, configurable)

All 1041 tests passing with no real network operations.
2026-01-20 12:29:12 -06:00
dc7db8ce39
Fix all remaining worker test failures
- Add 'error' to valid sensor reading status values
  - SensorReading changeset was rejecting 'error' status
  - PollWorker creates error readings when SNMP fails
  - Fixed validation to include: ok, warning, critical, error

- Replace log capture tests with functional assertions
  - ExUnit.CaptureLog not reliably capturing worker logs
  - Changed to verify actual behavior instead of log messages
  - Tests now check created records and state changes

- Add debug assertions to sensor error test
  - Verify SNMP device exists and has sensors
  - Better error messages for test failures

All 1045 tests now passing (0 failures, 2 skipped)
2026-01-20 12:20:04 -06:00
795ab8a041
Add Redix connection resilience options to Exq config
Configures Redix (Exq's Redis client) with better connection handling:
- sync_connect: true - fail fast if Redis unavailable at startup
- exit_on_disconnection: false - don't crash process on disconnect
- backoff_initial: 500ms, backoff_max: 30s - retry with exponential backoff

This helps Exq survive temporary Redis disconnections without crashing,
reducing the frequency of Protocol.UndefinedError crashes in Exq.Node.Server.
2026-01-20 11:42:02 -06:00
8ff0c44e7b
Add Redis health checks and improved error handling for Exq
Fixes crashes in Exq.Node.Server when Redis connections fail by adding
health checks before startup and wrapping Exq in a custom supervisor
with better resilience.

Problem:
- Valkey pod restarting frequently (24 times in 28h) due to K8s Flannel CNI issues
- When Redis disconnects, Exq.Node.Server crashes trying to process_signals/2
- Gets nil from Redis instead of expected list, crashes on Enum.each/2
- Rapid crash/restart cycles reduce application stability

Changes:

1. RedisHealthCheck module (lib/towerops/redis_health_check.ex)
   - Waits for Redis availability with exponential backoff before starting Exq
   - Prevents Exq from starting when Redis is unavailable
   - Handles connection errors gracefully without crashing caller processes
   - Supports configurable retry attempts, timeouts, and backoff intervals

2. ExqSupervisor module (lib/towerops/exq_supervisor.ex)
   - Custom supervisor that wraps Exq with health checks
   - Uses one_for_one strategy with limited restarts (3 per 60s)
   - Prevents rapid crash loops when Redis is unstable
   - Increased Exq retry/backoff settings for better Redis recovery
   - Allows application to continue functioning without background jobs if Redis unavailable

3. Updated Application.ex
   - Replaced direct Exq start with ExqSupervisor
   - Removed inline exq_config/0 function (moved to supervisor)

4. Tests
   - Comprehensive tests for RedisHealthCheck (health checks, retries, timeouts)
   - Tests for ExqSupervisor (configuration, restart strategy)
   - All 1006 tests passing

Benefits:
- Prevents Exq crashes from propagating when Redis fails
- Application continues running even when Redis is temporarily unavailable
- Better logging of Redis connection issues
- More graceful degradation during infrastructure problems

Infrastructure Issue (to be addressed separately):
- K8s Flannel CNI plugin failing: /run/flannel/subnet.env not found
- Causing Valkey pod network issues and restarts
- Needs investigation of Flannel daemonset and node configuration

🤖 Generated with Claude Code
2026-01-19 15:38:19 -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
00f704cd83
updated agent code 2026-01-19 14:10:54 -06:00
028f2600a2
Auto-expand MIB directories to include subdirectories
- Update MibTranslator to automatically expand configured MIB directories
- snmptranslate doesn't search recursively, so we explicitly list all subdirs
- Simplify config to only specify root priv/mibs directory
- Update both config.exs (production) and dev.exs (development)
- Subdirectories like mikrotik/, cisco/, net-snmp/ are auto-discovered
2026-01-19 14:06:51 -06:00
b4f8b40b7f
Include MIB files in Docker image instead of using PVC
- Remove PVC volume mount from k8s/deployment.yaml
- Delete k8s/mib-pvc.yaml (no longer needed)
- Update .gitignore to commit MIB files to git
- Add mix import_mibs task to copy MIBs from LibreNMS
- Add all MIB files from priv/mibs/ to git

This fixes the multi-attach volume error in Kubernetes where new pods
couldn't start because the RWO (ReadWriteOnce) PVC was attached to the
old pod. MIBs are now part of the Docker image and can be used by all
pods simultaneously.
2026-01-19 14:01:03 -06:00
f497de4474
Add ICMP monitoring support to Phoenix agent channel
- Add monitoring_enabled and check_interval_seconds fields to Device and SnmpDevice protobuf messages
- Add MonitoringCheck protobuf message for ping results
- Update AgentChannel to handle monitoring_check events from agents
- Configure monitoring settings in job payloads sent to agents
2026-01-19 13:46:20 -06:00
ceded37d9c
improve agent 2026-01-19 13:38:43 -06:00
77d4b25da7
test cleanup 2026-01-19 13:29:38 -06:00
fe7a44e5e2
test improvements 2026-01-19 12:08:48 -06:00
49bc320a89
better mib handling 2026-01-19 09:01:56 -06:00
d78c42c8f4
test improvements 2026-01-18 17:15:44 -06:00
9f59e7661a
add universoal import 2026-01-18 16:59:34 -06:00
50d8b27447
handle mib uploading 2026-01-18 16:29:24 -06:00
1f123bbeb9
add honeybadger and snmp overhaul 2026-01-18 16:16:08 -06:00
adec4b134f
snmp overhaul 2026-01-18 16:00:01 -06:00
94311a48aa
discovery fix and favicon 2026-01-18 13:47:19 -06:00
2324b75e47
fix device identification 2026-01-18 13:35:33 -06:00
8e1703cf28
higher snmp timeout 2026-01-18 13:25:15 -06:00
55fa754a25
add force rediscovery per site 2026-01-18 13:22:17 -06:00
b325b253f1
add texas footer 2026-01-18 13:16:20 -06:00
6706613f24
add texas footer 2026-01-18 13:15:27 -06:00
212744365f
fix: add timezone attribute to form layouts 2026-01-18 13:07:07 -06:00
9c2f08317f
feat: remove organization slug from sites and devices URLs
- Created new on_mount hook :load_default_organization that automatically loads user's first organization
- Moved sites and devices routes to root path (/ sites, /devices) instead of /orgs/:org_slug
- Updated all navigation links and route references throughout the app
- Dashboard, alerts, and agents still use org-specific routes (/orgs/:org_slug)
- Users can still switch organizations via org selector for other pages
2026-01-18 13:06:23 -06:00
592b99d739
fix: use correct device_id for neighbor discovery
The neighbor discovery was using snmp_device.id instead of the actual
Equipment device.id when creating neighbor records. This caused all
neighbor inserts to fail because the foreign key constraint expected
the Equipment ID, not the SNMP Device ID.

Fixed in two places:
- Discovery: Use snmp_device.device_id (FK to Equipment)
- PollerWorker: Use device.id (Equipment ID) instead of snmp_device.id

Neighbors should now be properly discovered and saved during both
initial discovery and ongoing polling.
2026-01-18 13:00:31 -06:00
dc9400e6ae
fix: adjust graph x-axis range based on selected time period
- Pass range parameter to SensorChart hook via data-range attribute
- Calculate x-axis min/max dynamically based on selected range (1h, 6h, 12h, 24h, 7d, 30d)
- Show date + time on x-axis labels for ranges > 24 hours
- Show time only for ranges <= 24 hours
- Fixes issue where 7d and 30d graphs showed incorrect time range
2026-01-18 12:56:44 -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
16bfd7667d
fix: pass timezone attribute to all layout components 2026-01-18 12:49:01 -06:00
9d667ac162
fix: use Map.get for timezone in layouts to handle missing assigns 2026-01-18 12:46:27 -06:00
d8ee0320dc
fix: use @timezone instead of assigns[:timezone] in footer calls 2026-01-18 12:43:35 -06:00
442a79baa7
fix: use proper function head for default values with multiple clauses 2026-01-18 12:41:39 -06:00
139eb3b147
fix: display deploy timestamp in user's timezone in footer 2026-01-18 12:24:52 -06:00
3dc22b118d
fix: display deploy timestamp in user's timezone in footer 2026-01-18 12:20:59 -06:00
d2e38e351e
feat: display all timestamps in user's timezone
- Add timezone to socket assigns in mount_current_scope
- Detect user timezone from browser using Intl.DateTimeFormat
- Auto-save detected timezone to user profile on first connection
- Update all templates to use TimeHelpers with timezone parameter
- Update agent helper functions to accept timezone parameter
- Templates updated:
  - Alert list (triggered, acknowledged, resolved)
  - Device list (last checked)
  - Agent list and show (created, last seen, updated)
  - Admin dashboard (impersonation logs)
  - Admin org/user lists (created/joined dates)
  - Main dashboard (alert times)
2026-01-18 12:19:17 -06:00
35f0ac495b
fix: always measure actual ICMP latency instead of returning 0ms for SNMP devices 2026-01-18 12:13:11 -06:00