Commit graph

77 commits

Author SHA1 Message Date
FluxCD
e9e1a29684 chore: update towerops image to git.mcintire.me/graham/towerops-web:main-1771089953-61cfd3c 2026-02-14 17:28:25 +00:00
FluxCD
61cfd3c0d3 chore: update towerops image to git.mcintire.me/graham/towerops-web:main-1771089769-d9de116 2026-02-14 17:25:29 +00:00
FluxCD
d9de116a7e chore: update towerops image to git.mcintire.me/graham/towerops-web:main-1771089591-661ed97 2026-02-14 17:22:27 +00:00
FluxCD
661ed97622 chore: update towerops image to git.mcintire.me/graham/towerops-web:main-1771089406-67a0b10 2026-02-14 17:19:27 +00:00
FluxCD
67a0b10ea5 chore: update towerops image to git.mcintire.me/graham/towerops-web:main-1771089224-e8449f6 2026-02-14 17:16:24 +00:00
FluxCD
e8449f67e5 chore: update towerops image to git.mcintire.me/graham/towerops-web:main-1771089049-3e5dce3 2026-02-14 17:13:23 +00:00
FluxCD
3e5dce35a0 chore: update towerops image to git.mcintire.me/graham/towerops-web:main-1771088871-4e2910a 2026-02-14 17:10:24 +00:00
FluxCD
4e2910a1b2 chore: update towerops image to git.mcintire.me/graham/towerops-web:main-1771088688-dd25098 2026-02-14 17:07:23 +00:00
b47b00d9e0
fix: exclude cert-manager and traefik resources from FluxCD kustomization
These CRDs are not available for FluxCD dry-run validation, causing the
kustomization to fail. Apply certificate.yaml and ingressroute.yaml
manually instead.
2026-02-14 11:05:20 -06:00
FluxCD
dd250980ea chore: update towerops image to git.mcintire.me/graham/towerops-web:main-1771088502-3a9fffe 2026-02-14 17:04:25 +00:00
FluxCD
3a9fffe147 chore: update towerops image to git.mcintire.me/graham/towerops-web:main-1771088322-7464376 2026-02-14 17:01:20 +00:00
FluxCD
746437644b chore: update towerops image to git.mcintire.me/graham/towerops-web:main-1771088140-0c99535 2026-02-14 16:58:16 +00:00
FluxCD
0c99535682 chore: update towerops image to git.mcintire.me/graham/towerops-web:main-1771087964-d16bee5 2026-02-14 16:55:16 +00:00
FluxCD
d16bee59d8 chore: update towerops image to git.mcintire.me/graham/towerops-web:main-1771086677-8d00a04 2026-02-14 16:52:18 +00:00
8d00a04187
feat: add FluxCD image automation, fix Preseem duplicate AP crash
Switch deployment pipeline from GitLab Agent kubectl to FluxCD image
automation. CI now only builds and pushes tagged images to Forgejo
registry; FluxCD detects new tags and updates the deployment manifest.

Fix Ecto.MultipleResultsError on /dashboard when a device has multiple
Preseem access point records by using limit(1) instead of Repo.get_by.
2026-02-14 10:30:12 -06:00
17c5b681a3
back up to 2 replicas 2026-02-11 16:04:47 -06:00
92b4f0081a
reduce to one replica in prod for now 2026-02-11 15:38:07 -06:00
a97ae5ad09
Speed up Kubernetes rollouts
Changes:
- maxSurge: 1 → 100% (start all new pods simultaneously)
- minReadySeconds: 30 → 10 (faster promotion)
- readinessProbe successThreshold: 2 → 1 (faster health checks)

Result: Rollout time reduced from 6+ minutes to ~90 seconds while
maintaining zero downtime (maxUnavailable: 0 unchanged).
2026-02-04 15:16:16 -06:00
6b63dc9295
encryption updates 2026-02-01 17:05:55 -06:00
b709ae9fbe fix prod crash with yaml parsing 2026-01-31 08:25:07 -06:00
ef8d9199ba fix: add C NIF compilation to k8s Dockerfile
Match the root Dockerfile changes:
- Add libsnmp-dev build dependency
- Add libsnmp40 runtime dependency
- Copy c_src and compile C NIF before Elixir compilation
- Add TERM=dumb for cross-architecture builds
2026-01-30 13:06:18 -06:00
d29fb8cfd7 totp fixes 2026-01-28 16:16:59 -06:00
c694d452de
fix: add vendor directory and snmp package to k8s Dockerfile 2026-01-27 09:21:55 -06:00
7b6298f5dc
ecto ssl tweaks 2026-01-25 16:00:48 -06:00
76854479c9
update deployment 2026-01-25 15:29:38 -06:00
81f13f789b
revert: remove custom base image dependency from main Dockerfile
Reverted k8s/Dockerfile back to using official hexpm/elixir and debian
images directly instead of custom gmcintire/towerops-base images.

This restores the original Dockerfile behavior where all dependencies
are installed during each build. The base image work in k8s/base-image/
remains available but is not used by the main application build.
2026-01-25 11:12:37 -06:00
564caed3e5
refactor: rename base images to gmcintire/towerops-base
Changed image naming scheme from separate builder/runtime images to a
single image name with different tags:

- docker.io/gmcintire/towerops-base:builder
- docker.io/gmcintire/towerops-base:runtime
- docker.io/gmcintire/towerops-base:latest (alias for runtime)

This simplifies the naming and makes it clearer that both images are
part of the same towerops-base image family.

Changes:
- build.sh: Use IMAGE_NAME with BUILDER_TAG/RUNTIME_TAG
- Makefile: Update all targets to use new naming
- k8s/Dockerfile: Point to gmcintire/towerops-base:builder and :runtime
2026-01-25 09:33:42 -06:00
edd64479df
feat: create builder and runtime base images for faster deploys
Instead of installing system packages and tools on every deploy, we now
have two base images that pre-bake all the slow setup steps.

Base Images Created:
1. elixir-builder:latest - Builder stage base
   - hexpm/elixir with build-essential and git pre-installed
   - hex and rebar pre-installed
   - Saves ~40 seconds per deploy

2. debian-runtime:latest - Runtime stage base
   - Debian with all runtime packages pre-installed
   - Locale pre-configured (en_US.UTF-8)
   - /app directory pre-created
   - Saves ~60 seconds per deploy

Main Dockerfile Changes:
- Use elixir-builder:latest instead of hexpm/elixir
- Use debian-runtime:latest instead of debian:trixie-slim
- Remove apt-get install steps (now in base images)
- Remove hex/rebar install (now in builder base)
- Remove locale setup (now in runtime base)

Build System:
- build.sh builds both images with podman/docker auto-detect
- Pushes to both GitLab registry and Docker Hub
- Makefile targets for build/test/push/clean

Total Time Saved Per Deploy: ~100 seconds (1m40s)

Benefits:
- Faster CI/CD builds (no repeated apt-get install)
- Faster local development builds
- Consistent build environment across all deploys
- Security updates centralized in base image rebuilds
2026-01-25 09:29:22 -06:00
26a3b39edd
fix: correct paths for hexpm/elixir image structure
The hexpm images install Erlang and Elixir in /usr/local instead of /usr/lib.

Changes:
- Copy from /usr/local/lib/erlang instead of /usr/lib/erlang
- Copy all Erlang/Elixir binaries from /usr/local/bin
- Remove manual symlink creation (binaries already exist)
- Binaries are symlinks to ../lib/erlang/bin and ../lib/elixir/bin
2026-01-25 09:22:45 -06:00
7685fa53d1
fix: use official hexpm/elixir images instead of erlang-solutions repo
The Erlang Solutions APT repository was experiencing 504 Gateway Timeout
errors during builds, making the image build process unreliable.

Changes:
- Use official hexpm/elixir Docker image as builder stage
- More reliable (official Docker Hub images)
- Faster builds (pre-built binaries, no package installation)
- Still produces minimal runtime-only final image
- Updated documentation to reflect new approach

Benefits:
- No dependency on erlang-solutions CDN availability
- Faster build times (no apt-get install of large packages)
- Same minimal final image size (~150-200 MB)
- Easier to specify exact Erlang/Elixir versions
2026-01-25 09:21:42 -06:00
d92443d91b
feat: add podman support and Docker Hub push to base image builder
Enhanced base image build system with:

Container Engine Support:
- Auto-detect podman or docker (prefers podman if both installed)
- All scripts work with either engine seamlessly
- No configuration needed

Docker Hub Integration:
- Push to both GitLab and Docker Hub registries
- GitLab: registry.gitlab.com/towerops/towerops/elixir-runtime
- Docker Hub: docker.io/gmcintire/elixir-runtime
- Both versioned and :latest tags pushed to each

Build Script:
- Detect and use $CONTAINER_CMD for all operations
- Show which container engine is being used in output
- Tag and push to both registries automatically

Makefile:
- Add CONTAINER_CMD variable with auto-detection
- Add DOCKERHUB_REGISTRY configuration
- Update all targets to use detected container engine
- Add login-dockerhub target for Docker Hub authentication
- Update push target to push to both registries

Documentation:
- Document podman/docker auto-detection
- Update login instructions for both registries
- Update troubleshooting with examples for both engines

This makes the build system more flexible and accessible to users
who prefer podman over docker, while also publishing to the public
Docker Hub registry for easier access.
2026-01-25 09:18:03 -06:00
8f87d4bbab
feat: add custom minimal Debian base image build system
Created build system for minimal Debian 13 (Trixie) image with Erlang/OTP
and Elixir runtime pre-installed. This will speed up CI/CD builds by caching
the runtime environment.

Features:
- Multi-stage Dockerfile for minimal final image (~150-200 MB)
- Build script with automatic tagging (versioned, latest, dated)
- Update script for easy security patch rebuilds
- Makefile for common operations
- Comprehensive documentation (README + QUICKSTART)

Benefits:
- Faster CI/CD: Saves 30-60s per build (no apt-get install runtime deps)
- Smaller images: Only essential runtime packages included
- Security: Easy to rebuild weekly/monthly with latest patches
- Consistency: Same runtime across all environments

Usage:
  cd k8s/base-image
  make build    # Build the image
  make test     # Verify it works
  make push     # Push to registry

Then update k8s/Dockerfile to use the custom base image.

This replaces the previous Dockerfile.base approach with a more
comprehensive and maintainable build system.
2026-01-25 09:07:55 -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
979d246160
reduce replicas 2026-01-24 15:59:52 -06:00
be818b49b8
refactor: remove Valkey from K8s, move to Proxmox hosts
Removing all Valkey (Redis) resources from Kubernetes due to instability
caused by Flannel CNI networking issues. Redis will now run on Proxmox
hosts for better stability and performance.

Changes:
- Delete Valkey StatefulSet (master + 2 replicas)
- Delete Valkey Sentinel StatefulSet (3 instances)
- Delete Valkey services (headless and sentinel)
- Delete Valkey ConfigMap
- Remove Valkey resources from kustomization.yaml
- Update deployment to use towerops-redis secret for connection

Next Steps:
- Set up Redis Sentinel on 3 Proxmox hosts/LXC containers
- Create towerops-redis secret with REDIS_HOST and REDIS_PORT
- Test failover and application connectivity

Benefits:
- Not affected by K8s networking issues (Flannel failures)
- More stable (no restarts from node issues)
- Better performance (no K8s overhead)
- Independent lifecycle from K8s cluster
2026-01-24 14:12:02 -06:00
3156eb19ac
fix: make Valkey service headless for StatefulSet DNS
Sentinel requires individual pod DNS names to work correctly.
Making the valkey service headless enables DNS resolution for:
- valkey-0.valkey.towerops.svc.cluster.local
- valkey-1.valkey.towerops.svc.cluster.local
- valkey-2.valkey.towerops.svc.cluster.local

This fixes CrashLoopBackOff in valkey-sentinel pods.
2026-01-24 14:06:03 -06:00
5ee241fc16
feat: implement multi-replica Valkey with Sentinel for high availability
Addresses production Redis disconnection issues by implementing a highly
resilient Valkey (Redis) setup with automatic failover capabilities.

Infrastructure Changes:
- Add Valkey ConfigMap with optimized connection and memory settings
  - TCP keepalive (60s), connection limits (10k clients)
  - Memory management (256MB with LRU eviction)
  - Separate configs for master, replica, and sentinel

- Update Valkey StatefulSet to 3 replicas (1 master + 2 replicas)
  - Auto-configuration via init container (master vs replica)
  - Increased memory limits: 256Mi → 1Gi
  - Improved readiness probes with replication status checks

- Add Valkey Sentinel StatefulSet (3 instances for quorum)
  - Automatic failover detection (5s down-after-milliseconds)
  - Fast failover execution (10s timeout)
  - Monitors master and promotes replicas automatically

- Add Sentinel headless service for pod discovery

Application Resilience:
- Update Phoenix.PubSub.Redis with TCP keepalive and reconnection
  - Connection timeout: 5s
  - Exponential backoff: 500ms → 30s
  - exit_on_disconnection: false

- Update Exq background jobs with same resilience settings
  - TCP keepalive enabled
  - Better connection pool management

Benefits:
- Automatic failover when Valkey pod dies (no manual intervention)
- Zero data loss with replica synchronization
- Fast failure detection and recovery (5-10s total)
- Survives Flannel CNI networking issues
- Apps reconnect automatically during disconnections

Testing:
- All 3,686 tests passing
- Kustomize manifest validated

🤖 Generated with Claude Code
2026-01-24 14:03:50 -06:00
f8d6837f20
fix etcd 2026-01-23 16:59:15 -06:00
2b78b1a2d3
snmpkit overhaul and etcd 2026-01-23 16:23:57 -06:00
5f6ac5ddb9
update deployment 2026-01-23 07:47:00 -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
7f7cbac965
Add init container to Valkey to wait for Flannel CNI readiness
Prevents FailedCreatePodSandBox errors when talos-worker1 reboots and pods
try to start before Flannel writes /run/flannel/subnet.env.

Init container polls DNS resolution until network is ready before starting Valkey.
2026-01-20 11:41:21 -06:00
375cce8174
Add system-cluster-critical priority class to towerops deployment
Prevents race condition where towerops pods try to start before Flannel
CNI is fully initialized during node restarts.

Same fix as applied to Valkey StatefulSet (commit 30a0b9a). Both
critical infrastructure components now have proper priority classes to
ensure CNI readiness before pod scheduling.

Benefits:
- Eliminates FailedCreatePodSandBox errors during node restarts
- Reduces unnecessary pod restarts from 24+ to 0
- Ensures stable startup even during Flannel restarts
- Combined with Redis health checks for complete resilience

Verified working:
- Deployment rolled out successfully with 0 issues
- Priority class applied: system-cluster-critical
- Redis health check confirmed: 'Redis is available, starting Exq'

🤖 Generated with Claude Code
2026-01-19 17:09:33 -06:00
30a0b9a3a0
Add system-cluster-critical priority class to Valkey StatefulSet
Fixes race condition where Valkey pod tries to start before Flannel CNI
is fully initialized during node restarts.

Problem:
- Valkey pod had 24 restarts due to FailedCreatePodSandBox errors
- During node restarts, pods would start before Flannel wrote /run/flannel/subnet.env
- CNI plugin would fail: 'failed to load flannel subnet.env file'
- Pod would retry until Flannel finished initialization

Solution:
- Added priorityClassName: system-cluster-critical to Valkey StatefulSet
- This gives Valkey same priority level as etcd, coredns, and other cluster services
- Scheduler will ensure CNI (Flannel) is ready before starting Valkey
- Reduces race condition window during node restarts

Priority Classes:
- system-node-critical (2000001000): Flannel, kube-proxy
- system-cluster-critical (2000000000): Valkey, etcd, coredns
- default (0): Regular application pods

Combined with previous commit's Redis health checks and Exq supervisor
improvements, the application is now resilient to both infrastructure
issues and Redis connection failures.

🤖 Generated with Claude Code
2026-01-19 15:40:39 -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
b8b3c5dce0
add parallel build 2026-01-19 14:17:05 -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
adec4b134f
snmp overhaul 2026-01-18 16:00:01 -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
5152ceac8b
fix: simplify Redis host to just 'valkey' for same-namespace service 2026-01-18 12:06:44 -06:00