Commit graph

924 commits

Author SHA1 Message Date
95eafd0c47
routeros fixes and latency rounding 2026-02-09 17:30:06 -06:00
4cfab3b1ee
Reliability improvements: agent channel, polling, discovery, batch ops
- Add Task.Supervisor for supervised background tasks in agent channel
- Discovery worker retries transient failures (max 3 attempts)
- Log silent polling timeouts with named task identification
- Track errors in batch ARP/MAC upserts instead of silently ignoring
- Discovery gracefully degrades on interface/sensor timeout (partial results)
- Synchronous job dispatch on agent join to prevent race condition
- Surface SNMP result, monitoring check, and backup processing errors
- Atomic delete-stale + upsert for neighbors/ARP/MAC (transaction)
- Discovery transaction timeout (60s) with duration logging
- Heartbeat timeout detection (5min) closes stale agent channels
- Live poll timeout (60s) notifies waiting LiveView on expiry
- Disconnect agent channel when token is disabled or deleted
- Debounce rapid assignment changes to prevent redundant job dispatches
- Sensor index deduplication via YAML index template substitution
2026-02-09 16:28:12 -06:00
3b8e1ea639
Reliability improvements: Task.Supervisor, discovery retries, polling visibility
- Add Towerops.TaskSupervisor to supervision tree, replace bare spawn/1
  in agent channel with supervised tasks for polling data processing
- Change DiscoveryWorker from max_attempts: 1 to 3 with retryable error
  classification (transient errors retry, permanent errors discard)
- Name all 9 parallel polling tasks and log timeouts/crashes instead of
  silently dropping results via Stream.run()
- Add tests for TaskSupervisor presence and error classification
2026-02-09 16:05:30 -06:00
2911a3c17d
test fixes 2026-02-09 15:30:52 -06:00
41594e5a96
fix bugs on agents screen 2026-02-09 14:03:40 -06:00
a50c8e6314
Use datestamp as agent version 2026-02-09 13:51:32 -06:00
ae9b393137
Fix agent page jumping by using streams for real-time updates
- Convert agent_tokens from assign to stream to prevent full page re-renders
- Update handle_info callbacks to only update the specific agent that changed
- Only update stats when agent status changes, not device counts
- Prevents IP address from temporarily disappearing during updates
2026-02-09 13:39:59 -06:00
39fa1c6e4e
use REDIS_URL if present 2026-02-09 13:16:41 -06:00
f8d2570bb3
no cluster unless in k8s, fix credo issues 2026-02-09 13:08:51 -06:00
94bcf8ac4e
fix bug on device add/edit page with mikrotik api fields showing 2026-02-09 13:01:47 -06:00
f7b5e63429
live update agent status 2026-02-09 12:58:54 -06:00
623fe07081
wip 2026-02-09 12:44:37 -06:00
2b4cb5c3f5
fix: handle duplicate MAC address entries gracefully
Problem: upsert_mac_address was using Repo.one() which crashes with
Ecto.MultipleResultsError when duplicate MAC address records exist
in the database.

Root Cause: Race condition or historical data corruption created
duplicate entries for the same (device_id, mac_address, vlan_id)
tuple, violating the unique constraint.

Fix:
- Changed Repo.one() to Repo.all() to handle duplicates gracefully
- When duplicates found: keep first entry, delete extras, log warning
- Includes device_id, mac_address, vlan_id, and duplicate IDs in log
- Auto-cleans corrupted data while maintaining service availability

Example Log Output:
  Found 1 duplicate MAC address entries, cleaning up
  device_id=f3ff19d5-b519-4327-9f7d-dc416e494cfa
  mac_address=78:9a:18:52:b1:c6
  vlan_id=nil
  duplicate_ids=[...]

Impact:
- Prevents polling crashes when duplicate MAC entries exist
- Self-healing: automatically cleans up database corruption
- Maintains data integrity while preserving service availability

Related: Issue 2.9 from bugs analysis (ARP/MAC parsing issues)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-02-09 09:20:08 -06:00
cedbc5abd1
fix: resolve critical data loss and protobuf schema bugs (Phase 1)
This commit addresses Phase 1 (CRITICAL - Data Loss Prevention) issues
from the comprehensive bugs and inconsistencies analysis.

CRITICAL FIXES:

1. Protobuf Schema Inconsistencies
   - Added missing job_id field (field 5) to SnmpResult message
   - Fixed AgentError message structure (job_id, message, timestamp)
   - Removed obsolete transport field from SnmpDevice struct
   - Regenerated protobuf code with protoc-gen-elixir
   - Prevents crashes when agent sends SNMP results or errors

2. Interface/Sensor Discovery Timeout Data Loss
   - Changed timeout behavior to return error instead of empty list
   - Prevents deletion of ALL existing interfaces/sensors on slow networks
   - Discovery fails gracefully instead of destroying historical data
   - Addresses commit 7a57f7c sensor discovery pipeline data loss issue

3. Polling Offset Schedule Mismatch
   - Fixed schedule_next_poll() to use offset only (not interval + offset)
   - Maintains consistent polling intervals across all executions
   - Prevents load bunching that offset was designed to prevent
   - Example: 300s interval with offset=94s now consistently polls every 5m

4. Always Reschedule Race Condition
   - Added should_continue_polling?() and should_continue_monitoring?()
   - Only reschedule if device is still enabled and should be polled by Phoenix
   - Prevents zombie jobs from continuing to poll disabled/deleted/reassigned devices
   - Stops race condition where stop_polling() is bypassed by in-flight jobs

Files Changed:
- priv/proto/agent.proto
- lib/towerops/proto/agent.pb.ex (regenerated)
- lib/towerops_web/channels/agent_channel.ex
- lib/towerops/snmp/discovery.ex
- lib/towerops/workers/device_poller_worker.ex
- lib/towerops/workers/device_monitor_worker.ex
- test/towerops/workers/device_poller_worker_test.exs

Test Results: All passing
- device_poller_worker_test.exs: 8 tests, 0 failures
- device_monitor_worker_test.exs: 3 tests, 0 failures
- discovery_test.exs: 13 tests, 0 failures

Remaining Phases:
- Phase 2 (HIGH): 8 data integrity issues
- Phase 3 (MEDIUM): 10 reliability issues
- Phase 4 (LOW): 3 cleanup issues

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-02-09 09:16:03 -06:00
b12a03b82f
update 2026-02-09 08:47:53 -06:00
7a57f7c9d2
fix: resolve critical sensor discovery pipeline data loss
Critical fixes to sensor discovery and display pipeline:

- Fix float value rejection: Change is_integer guards to is_number in
  vendor.ex, dynamic.ex to accept decimal sensor values (temperature,
  counters, etc.)
- Fix scale factor calculation: Rewrite base.ex divisor calculation
  using pure integer arithmetic to prevent rounding errors
- Add missing sensor type support: Current, power, fan, load, and
  signal quality sensor categories now filtered and assigned in UI
- Refactor resolve_snmp_community to reduce cyclomatic complexity

Impact:
- Sensors with float values (DHCP leases, connection counts, precise
  temperatures) no longer silently dropped before database
- ENTITY-SENSOR-MIB divisors calculated correctly without float errors
- UI coverage increased from ~35% to ~60% of discovered sensor types

Files modified:
- lib/towerops/snmp/profiles/vendors/vendor.ex
- lib/towerops/snmp/profiles/dynamic.ex
- lib/towerops/snmp/profiles/base.ex
- lib/towerops_web/live/device_live/show.ex
- lib/towerops/devices.ex

Documentation: SENSOR_PIPELINE_FIXES.md
2026-02-09 08:32:24 -06:00
9df53b1629
fix: suppress repetitive SNMP MIB resolution errors
Add logger filter to drop repetitive 'Cannot find module' errors
from net-snmp library. These errors occur when snmptranslate can't
find vendor-specific MIB modules but don't affect functionality
since the system falls back to numeric OIDs.

The errors were flooding production logs (hundreds of identical
messages) during polling of Morningstar devices that reference
TRISTAR MIB modules.

Changes:
- Add drop_snmp_mib_errors/2 filter to LoggerFilters module
- Register filter in production logger configuration
- Filter matches exact error format from snmptranslate stderr

The root cause (missing NIF binary) will be addressed separately
by compiling the towerops_nif.so during Docker build.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-02-08 14:09:26 -06:00
bc8e8a4261
feat: notify agents when devices are deleted
When a device is deleted, now broadcasts an assignment change event
to the agent (if assigned), causing the agent to receive an updated
job list without the deleted device. This ensures agents stop
processing any in-flight jobs for deleted devices.

Changes:
- Get agent assignment before deleting device
- Broadcast :device_deleted event to agent after deletion
- Agent channel receives broadcast and sends updated job list
- Agents naturally stop processing jobs for devices not in new list

Previously only cancelled Oban jobs but didn't notify agents,
leaving potential for agents to continue processing jobs for
deleted devices.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-02-08 14:06:09 -06:00
cbff651f83
fix: always redirect to /devices when stopping impersonation
Previously redirected to /dashboard or /orgs based on whether the
superuser had organizations. Now always goes to /devices for
consistency.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-02-08 14:01:15 -06:00
039bce3938
fix: add PING enum value to generated protobuf module
The protobuf Elixir module was missing the PING (value 4) enum
entry, causing encoding errors when building jobs for agents.

Manually added the field since protoc-gen-elixir has asdf version
issues. The generated module now matches the updated agent.proto
definition.

Fixes: ** (Protobuf.EncodeError) no function clause matching in
Towerops.Agent.JobType

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-02-08 13:49:07 -06:00
48dc4b852e
feat: add Phoenix support for agent-side ping monitoring
Enables Phoenix to send PING jobs to agents and receive monitoring
check results, fixing the "unknown" status for devices assigned to
local (non-cloud) agents.

Changes:
- Rename JobType::MONITOR to JobType::PING in protobuf for clarity
- Add validate_monitoring_check_message() to Validator module
- Add "monitoring_check" channel handler to receive ping results
- Implement store_monitoring_check() to save results to database
- Add build_ping_job() to generate PING jobs for agents
- Update build_jobs_for_device() to include ping jobs when
  monitoring_enabled=true

Phoenix now sends PING jobs alongside SNMP/MikroTik jobs, and agents
send back MonitoringCheck results that are stored in the
monitoring_checks table with proper agent_token_id tracking.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-02-08 13:44:21 -06:00
fb8ffde119
fix: prevent site assignment when sites are disabled for org
When an organization has sites disabled (use_sites=false), the API
now automatically removes any site_id from device creation requests,
ensuring devices are assigned directly to the organization instead.

This prevents Terraform (and other API clients) from creating devices
in sites when sites functionality is disabled for the organization.

Fixes issue where Terraform could bypass site restrictions via API.
2026-02-08 13:24:48 -06:00
b823b5e848
feat: display cloud poller name on device page
Show the specific cloud poller name (e.g., dfw, lon) alongside "Cloud"
when a device is assigned to a cloud poller. Displays as "Cloud (dfw)"
instead of just "Cloud" for better visibility of which poller is being used.

When no agent is assigned, continues to show just "Cloud".
2026-02-08 11:40:58 -06:00
10b1168044
refactor: round latency graph values to 1 decimal place
Display latency values with single decimal precision (e.g., 114.1ms)
for improved readability in graphs. This ensures consistency between
the raw chart data and tooltip formatting.
2026-02-08 11:13:39 -06:00
16b833d077
fix: correct LoggerFileBackend API usage to fix Oban startup
The previous commit (90e8964) introduced an incorrect LoggerBackends.add/2
call that prevented Oban from starting, causing all discovery jobs to remain
stuck in "available" state without being processed.

Root cause: LoggerBackends.add expects a tuple {module, id} as the first
argument, not the module alone with configuration options.

Fix: Use the correct API pattern:
1. Add backend with tuple identifier: {LoggerFileBackend, :file_log}
2. Configure separately with Logger.configure_backend/2

This resolves device discovery being completely broken - all background
jobs (discovery, polling, monitoring) now process correctly.
2026-02-08 11:07:45 -06:00
96c0254ab6
restore normal gitlab ci 2026-02-08 10:56:06 -06:00
90e89641b7
fix logging backend 2026-02-08 10:55:08 -06:00
6b4c098de8
fix warnings 2026-02-08 10:50:27 -06:00
631d03536e
security: add session inactivity timeout and comprehensive security documentation
Session Security Enhancements:
- Add 30-minute inactivity timeout to UpdateSessionActivity plug
- Automatic logout with user notification after inactivity
- Session timeout check happens on every request
- Graceful logout with flash message
- Refactored for Credo compliance (reduced nesting depth)

Security Documentation:
- Create comprehensive SECURITY.md covering all security features
- Document authentication, authorization, and encryption
- List OWASP Top 10 mitigations
- Include security checklist for developers
- Document recent security fixes and improvements

Verification:
- Password reset already rate-limited (confirmed)
- All 6,145 tests passing
- Zero Credo issues
- Zero security warnings

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-02-08 10:47:44 -06:00
fb1d4c564f
security: fix critical vulnerabilities and atom exhaustion risks
Critical fixes:
- Add [:safe] option to binary_to_term to prevent RCE attacks
- Implement whitelist validation for String.to_atom conversions
- Add input validation before String.to_existing_atom usage

Changes:
- MIB compiler and cache: Use safe binary deserialization
- SNMP contexts: Whitelist protocol, device type, and source atoms
- API controllers: Validate error message keys before atom conversion
- Reduce function nesting to comply with Credo standards

All 6,145 tests passing with zero Credo issues.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-02-08 10:30:30 -06:00
24236dbe30
update oban_web 2026-02-08 10:11:53 -06:00
d431931cfe
update hammer 2026-02-08 10:08:31 -06:00
f7d1757342
doc update 2026-02-08 09:52:26 -06:00
9194ebdd72
ci: migrate GitLab CI to Nix-based Docker builds
Replace Docker-based builds with Nix flakes for reproducible builds.

Changes:
- Use nixos/nix:latest image with `nix` tag requirement
- Build Docker image with `nix build .#dockerImage`
- Add optional Cachix integration for binary caching
- Load image with `docker load < result`
- Keep existing deploy stage unchanged

Benefits:
- Reproducible builds across all environments
- Binary caching via Cachix (faster subsequent builds)
- All dependencies pinned in flake.lock
- Image size similar to Docker builds (~507 MB compressed)

Requirements:
- GitLab Runner with Nix installed and `nix` tag
- Docker socket mounted for loading/pushing images
- Optional: CACHIX_AUTH_TOKEN for binary caching

See docs/gitlab-runner-nix-setup.md for runner setup instructions.

The old Docker-based config is available in git history if rollback needed.
2026-02-07 14:17:20 -06:00
af9537939b
fix: complete Nix Docker image build and untrack .claude/settings.local.json
Nix build fixes:
- Override beamPackages.elixir to use 1.19.5 instead of default 1.18.4
- Add explicit buildPhase to compile dependencies before application
- Remove postInstall phase (Mix automatically includes priv/ in release)
- Set HEX_OFFLINE=false to allow dependency fetching in Nix sandbox

Docker image build now succeeds (~507 MB compressed).

Also remove .claude/settings.local.json from git tracking (keep local).
File remains in working directory but is now properly ignored.
2026-02-07 14:14:26 -06:00
0c00e5ee16
fix: Add git and SSL certificates for git dependencies
Add git and cacert to nativeBuildInputs and set SSL certificate
environment variables. This fixes the SSL certificate verification
error when fetching heroicons from GitHub.
2026-02-07 12:52:31 -06:00
50ae09a1a9
fix: Add explicit deps.get in configure phase
Override configurePhase to explicitly run 'mix deps.get' before
compilation. This ensures hex dependencies (like ecto) are available
when vendored path dependencies (oban_met) are compiled.
2026-02-07 12:51:25 -06:00
8e60129b44
fix: Remove postUnpack step to preserve vendor dependencies
The postUnpack step was deleting deps directories which may have
been removing vendored dependencies. cleanSourceWith already handles
source filtering, so postUnpack is redundant and potentially harmful.
2026-02-07 12:50:26 -06:00
da288e955d
fix: Simplify source filter to include vendor properly
Remove buggy conditional that was always true. Now the filter
correctly excludes only build artifacts while including all
source files including vendor directory.
2026-02-07 12:48:31 -06:00
399a9571fd
fix: Use cleanSourceWith for better source filtering
Replace sourceFilesBySuffices with cleanSourceWith to ensure
vendor directory and all dependencies are properly included.
This fixes the oban_met compilation error.
2026-02-07 12:47:42 -06:00
3ce8c480f2
fix: Add OpenSSL to C NIF build inputs
net-snmp requires OpenSSL headers. Add openssl to buildInputs
to fix 'openssl/ossl_typ.h' file not found error.
2026-02-07 12:46:13 -06:00
f42e2b00c9
fix: Dynamically find Erlang erts include directory
Find the erts include path dynamically instead of relying on
erlang.version which may not match the actual erts version.
This fixes 'erl_nif.h' file not found error.
2026-02-07 12:45:34 -06:00
1ad737e010
fix: Allow unfree packages in Nix configuration
Set allowUnfree = true to allow building towerops packages
which are marked with unfree license.
2026-02-07 12:44:45 -06:00
44b5c204fa
fix: Use lib.licenses.unfree instead of proprietary
Change license from 'proprietary' (which doesn't exist in nixpkgs)
to 'unfree' which is the correct license type for closed-source
software in Nix.
2026-02-07 12:44:28 -06:00
d8a0a9ca4d
fix: Use dynamic path for release directory in postInstall
Instead of hardcoding the version in the path, find the release
directory dynamically. This fixes the 'undefined variable version'
error during Docker image build.
2026-02-07 12:42:46 -06:00
a980afa947
update 2026-02-07 12:40:40 -06:00
8fa79caccc
chore: Add Nix development state to gitignore
Ignore local Nix development directories and files:
- .nix-mix/ - Mix cache
- .nix-hex/ - Hex cache
- .nix-postgres/ - PostgreSQL data directory
- .nix-redis/ - Redis data directory
- .nix-services-started - Service flag file

These are created by the Nix dev shell and should not be
committed to the repository.
2026-02-07 12:40:18 -06:00
dfa334650f
fix: Improve service startup and Hex installation
- Check if PostgreSQL/Redis already running before starting
- Install Hex and Rebar3 non-interactively on shell entry
- Only run migrations if deps directory exists
- Better error messages with log file locations

This fixes issues when:
- Port 5432 is already in use (existing PostgreSQL)
- Port 6379 is already in use (existing Redis)
- Mix prompts for Hex installation interactively
2026-02-07 12:37:04 -06:00
38347eb571
fix: Correct pre-commit-hooks integration
Pass pre-commit-hooks.lib.${system} correctly from flake.nix
to shell.nix, fixing the 'attribute lib missing' error.
2026-02-07 12:34:58 -06:00
5c71205aa3
feat: Pin Elixir 1.19.5 and Erlang 28.3 in Nix flake
Add Nix overlay to pin specific versions matching .tool-versions:
- Erlang: OTP 28.3 (via erlang_28)
- Elixir: 1.19.5-otp-28 (via beam.packages.erlang_28.elixir_1_19)

This ensures the Nix build environment matches the asdf-based
development setup exactly, providing consistency across all
development and build environments.
2026-02-07 12:33:49 -06:00