diff --git a/AUTO_UPDATE_SETUP.md b/AUTO_UPDATE_SETUP.md deleted file mode 100644 index 48bb848..0000000 --- a/AUTO_UPDATE_SETUP.md +++ /dev/null @@ -1,447 +0,0 @@ -# Automatic Updates Setup - -## Overview - -The Towerops agent now supports **automatic updates** using **Watchtower**, eliminating the need for manual updates or self-update code in the agent. - -## How It Works - -``` -┌─────────────────┐ -│ Push to main │ -└────────┬────────┘ - │ - ↓ -┌─────────────────┐ -│ GitLab CI/CD │ ← Builds Docker image -│ builds image │ Tags: main, latest, timestamp -└────────┬────────┘ - │ - ↓ -┌─────────────────┐ -│ Docker Hub │ ← New image published -│ gmcintire/ │ Tag: main (updated) -│ towerops-agent │ -└────────┬────────┘ - │ - ↓ -┌─────────────────┐ -│ Watchtower │ ← Polls every 5 minutes -│ (on customer │ Detects new 'main' tag -│ network) │ Pulls new image -└────────┬────────┘ Restarts container - │ - ↓ -┌─────────────────┐ -│ Agent updated │ ← Zero downtime -│ automatically │ New version running -└─────────────────┘ -``` - -## Versioning Strategy - -### Git-Based Versioning - -The agent version is **automatically generated** from git: - -| Scenario | Version Format | Example | -|----------|----------------|---------| -| Exact tag | `X.Y.Z` | `0.2.0` | -| After tag | `X.Y.Z.N.hash` | `0.2.0.5.831588e` | -| No tags | `X.Y.Z.hash` | `0.1.0.831588e` | -| Dirty tree | `X.Y.Z-modified` | `0.2.0-modified` | - -**Generated by**: `git describe --tags --always --dirty=-modified` - -### Docker Image Tags - -Every push to `main` creates **multiple tags**: - -| Tag | Purpose | Updated On | -|-----|---------|------------| -| `main` | **Auto-update tracking** | Every push | -| `latest` | Stable/production | Every push | -| `0.1.0.5.831588e` | Specific version | Every push | -| `main-831588e` | Commit reference | Every push | -| `main-20260116-143022` | Timestamp | Every push | - -### Release Tags - -Git tags trigger **multi-arch releases**: - -```bash -git tag v0.2.0 -git push --tags -# CI builds: linux/amd64, linux/arm64 -# Tags: 0.2.0, v0.2.0, latest -``` - -## Setup Instructions - -### 1. Docker Compose (Recommended) - -Copy `docker-compose.example.yml` to `docker-compose.yml`: - -```yaml -services: - towerops-agent: - image: gmcintire/towerops-agent:main # ← Track main for auto-updates - # ... environment vars ... - labels: - - "com.centurylinklabs.watchtower.enable=true" - - watchtower: - image: containrrr/watchtower:latest - environment: - - WATCHTOWER_POLL_INTERVAL=300 # Check every 5 minutes - - WATCHTOWER_LABEL_ENABLE=true - - WATCHTOWER_CLEANUP=true - volumes: - - /var/run/docker.sock:/var/run/docker.sock -``` - -Start services: - -```bash -docker-compose up -d -``` - -### 2. Docker Run (Manual) - -**Agent**: -```bash -docker run -d \ - --name towerops-agent \ - --restart unless-stopped \ - --label com.centurylinklabs.watchtower.enable=true \ - -e TOWEROPS_API_URL=https://app.towerops.com \ - -e TOWEROPS_AGENT_TOKEN=your-token \ - -v $(pwd)/data:/data \ - gmcintire/towerops-agent:main -``` - -**Watchtower**: -```bash -docker run -d \ - --name watchtower \ - --restart unless-stopped \ - -e WATCHTOWER_POLL_INTERVAL=300 \ - -e WATCHTOWER_LABEL_ENABLE=true \ - -e WATCHTOWER_CLEANUP=true \ - -v /var/run/docker.sock:/var/run/docker.sock \ - containrrr/watchtower -``` - -### 3. Kubernetes - -Use a Kubernetes CronJob with a Docker image updater like: -- **Keel** (https://keel.sh/) -- **Flux** (https://fluxcd.io/) -- **ArgoCD Image Updater** (https://argocd-image-updater.readthedocs.io/) - -Example with Keel: - -```yaml -apiVersion: apps/v1 -kind: Deployment -metadata: - name: towerops-agent - labels: - keel.sh/policy: force - keel.sh/trigger: poll -spec: - template: - spec: - containers: - - name: agent - image: gmcintire/towerops-agent:main -``` - -## Watchtower Configuration - -### Update Frequency - -**Default**: Every 5 minutes (`WATCHTOWER_POLL_INTERVAL=300`) - -**Recommended settings**: -- **Aggressive**: 300s (5 min) - Get updates quickly -- **Balanced**: 1800s (30 min) - Reduce Docker Hub API calls -- **Conservative**: 3600s (1 hour) - Minimize load - -### Notifications - -Get notified when updates happen: - -#### Slack -```yaml -environment: - - WATCHTOWER_NOTIFICATIONS=slack - - WATCHTOWER_NOTIFICATION_SLACK_HOOK_URL=https://hooks.slack.com/services/YOUR/WEBHOOK/URL - - WATCHTOWER_NOTIFICATION_SLACK_IDENTIFIER=Towerops Agent -``` - -#### Email -```yaml -environment: - - WATCHTOWER_NOTIFICATIONS=email - - WATCHTOWER_NOTIFICATION_EMAIL_FROM=watchtower@yourdomain.com - - WATCHTOWER_NOTIFICATION_EMAIL_TO=alerts@yourdomain.com - - WATCHTOWER_NOTIFICATION_EMAIL_SERVER=smtp.gmail.com - - WATCHTOWER_NOTIFICATION_EMAIL_SERVER_PORT=587 - - WATCHTOWER_NOTIFICATION_EMAIL_SERVER_USER=your-email@gmail.com - - WATCHTOWER_NOTIFICATION_EMAIL_SERVER_PASSWORD=your-app-password -``` - -#### Discord, Telegram, etc. -See: https://containrrr.dev/watchtower/notifications/ - -### Update Scheduling - -Run updates at specific times (cron format): - -```yaml -environment: - # Daily at 4am - - WATCHTOWER_SCHEDULE=0 0 4 * * * - - # Every Sunday at 2am - - WATCHTOWER_SCHEDULE=0 0 2 * * 0 -``` - -### Rolling Updates - -Update only specific containers: - -```yaml -environment: - - WATCHTOWER_SCOPE=towerops # Only update containers with this scope label - -# On agent: -labels: - - "com.centurylinklabs.watchtower.scope=towerops" -``` - -## Tag Selection Strategy - -### Production (Stable) - -Use **`latest`** tag for stable releases only: - -```yaml -image: gmcintire/towerops-agent:latest -``` - -- Updated only on git tags (`v0.2.0`, `v0.3.0`, etc.) -- Tested releases -- Manual version control - -### Auto-Updates (Continuous) - -Use **`main`** tag for automatic updates: - -```yaml -image: gmcintire/towerops-agent:main -``` - -- Updated on every push to main branch -- Latest features and bug fixes -- Automated deployment -- **Recommended for most users** - -### Pinned Version - -Use **specific version** to prevent updates: - -```yaml -image: gmcintire/towerops-agent:0.2.0.5.831588e -``` - -- Never updates automatically -- Full control over upgrades -- Use when stability is critical - -## Monitoring Updates - -### Check Watchtower Logs - -```bash -# Docker Compose -docker-compose logs -f watchtower - -# Docker -docker logs -f watchtower -``` - -### Check Agent Version - -```bash -# View agent logs for version on startup -docker logs towerops-agent | grep "Current version" - -# Output: Current version: 0.2.0.5.831588e -``` - -### Manual Update Check - -Force Watchtower to check immediately: - -```bash -# Send SIGUSR1 to Watchtower -docker kill --signal=SIGUSR1 watchtower -``` - -## Rollback - -### To Previous Version - -Find previous image: - -```bash -# List available tags -docker image ls gmcintire/towerops-agent - -# Use timestamp tag for specific build -docker pull gmcintire/towerops-agent:main-20260116-143022 -``` - -Update docker-compose.yml: - -```yaml -image: gmcintire/towerops-agent:main-20260116-143022 -``` - -Restart: - -```bash -docker-compose up -d --force-recreate towerops-agent -``` - -### Disable Auto-Updates - -Remove or comment out Watchtower: - -```yaml -# watchtower: -# image: containrrr/watchtower:latest -# ... -``` - -Or disable for specific container: - -```yaml -labels: - - "com.centurylinklabs.watchtower.enable=false" -``` - -## Comparison: Self-Update vs Watchtower - -| Feature | Self-Update (Old) | Watchtower (New) | -|---------|-------------------|------------------| -| **Complexity** | Agent pulls images | External service | -| **Docker socket** | Required in agent | Only in Watchtower | -| **Update trigger** | Agent checks hourly | Watchtower polls | -| **Rollback** | Exit code 0 | Standard Docker | -| **Notifications** | None | Slack, email, etc. | -| **Multi-container** | One agent only | All containers | -| **Scheduling** | Fixed interval | Cron expressions | -| **Security** | Agent has Docker access | Isolated service | - -**Winner**: Watchtower - More flexible, secure, and featureful - -## Security Considerations - -### Docker Socket Access - -Watchtower needs access to Docker socket (`/var/run/docker.sock`). This gives it full Docker API access. - -**Mitigation**: -- Run Watchtower in separate namespace -- Use label filtering to limit scope -- Monitor Watchtower logs -- Use official Watchtower image only - -### Image Verification - -Watchtower pulls images without signature verification by default. - -**Options**: -- Use Docker Content Trust: `export DOCKER_CONTENT_TRUST=1` -- Verify image checksums manually -- Use private registry with access controls - -### Update Testing - -Test updates in staging before production: - -1. **Staging**: Use `main` tag, auto-update -2. **Production**: Use `latest` tag, manual update after staging validation - -## Troubleshooting - -### Watchtower Not Updating - -**Check**: -1. Watchtower is running: `docker ps | grep watchtower` -2. Labels are correct: `docker inspect towerops-agent | grep watchtower` -3. Network access: `docker exec watchtower ping -c 1 docker.io` -4. Logs for errors: `docker logs watchtower` - -### Update Loop - -If agent keeps restarting after update: - -1. Check agent logs: `docker logs towerops-agent` -2. Pin to previous version (see Rollback) -3. Report issue on GitHub - -### High Resource Usage - -Watchtower using too much memory: - -```yaml -deploy: - resources: - limits: - memory: 64M # Reduce from 128M -``` - -## CI/CD Pipeline - -### Automatic Builds - -**On every push to main**: -1. GitLab CI builds Docker image -2. Tags with multiple identifiers -3. Pushes to Docker Hub -4. Watchtower detects within 5 minutes -5. Agent updates automatically - -**View pipeline**: https://gitlab.com/towerops/towerops-agent/-/pipelines - -### Build Time - -- **Main branch** (amd64 only): ~5 minutes -- **Git tags** (multi-arch): ~20 minutes - -## Best Practices - -1. **Use `main` tag** for automatic updates -2. **Enable notifications** to track updates -3. **Set reasonable poll interval** (300-1800s) -4. **Monitor Watchtower logs** regularly -5. **Test in staging** before production -6. **Keep Watchtower updated** (`docker pull containrrr/watchtower:latest`) -7. **Use Docker Compose** for easier management - -## Resources - -- **Watchtower Docs**: https://containrrr.dev/watchtower/ -- **Docker Hub**: https://hub.docker.com/r/gmcintire/towerops-agent -- **GitLab CI**: https://gitlab.com/towerops/towerops-agent/-/blob/main/.gitlab-ci.yml -- **Issue Tracker**: https://github.com/towerops/towerops-agent/issues - ---- - -**Status**: ✅ Complete -**Date**: January 16, 2026 -**Impact**: Fully automated zero-touch updates for all deployments diff --git a/DEPLOYMENT.md b/DEPLOYMENT.md deleted file mode 100644 index 19be28f..0000000 --- a/DEPLOYMENT.md +++ /dev/null @@ -1,408 +0,0 @@ -# Towerops Agent - Deployment Guide - -## GitLab CI/CD Pipeline - -The agent uses GitLab CI/CD to automatically build and publish Docker images to the GitLab Container Registry. - -### Pipeline Stages - -1. **Test** - Compile, format check, and lint -2. **Build** - Build Docker image -3. **Release** - Tag and publish versioned releases - -### Image Tags - -| Git Action | Image Tags | Example | -|------------|------------|---------| -| Push to branch | ``, `` | `feat-snmp`, `abc123` | -| Push to main | `latest`, `main-` | `latest`, `main-abc123` | -| Create tag | ``, ``, `latest` | `0.1.0`, `v0.1.0`, `latest` | - -### Registry Location - -All images are pushed to: -``` -registry.gitlab.com/towerops/towerops-agent -``` - -## Creating a Release - -### 1. Update Version - -**In `Cargo.toml`**: -```toml -[package] -name = "towerops-agent" -version = "0.2.0" # ← Update this -edition = "2021" -``` - -### 2. Commit and Tag - -```bash -git add Cargo.toml -git commit -m "Release v0.2.0" -git tag v0.2.0 -git push origin main --tags -``` - -### 3. CI Pipeline Runs - -GitLab CI will automatically: -- Run tests (cargo check, fmt, clippy) -- Build Docker image -- Tag as: `0.2.0`, `v0.2.0`, `latest` -- Push to registry - -### 4. Verify Release - -Check the Container Registry: -``` -https://gitlab.com/towerops/towerops-agent/container_registry -``` - -You should see: -- `latest` (updated) -- `0.2.0` (new) -- `v0.2.0` (new) - -## Using the Images - -### Pull Latest - -```bash -docker pull registry.gitlab.com/towerops/towerops-agent:latest -``` - -### Pull Specific Version - -```bash -docker pull registry.gitlab.com/towerops/towerops-agent:0.1.0 -``` - -### Docker Compose - -Update `docker-compose.yml`: -```yaml -services: - towerops-agent: - image: registry.gitlab.com/towerops/towerops-agent:latest - # Or pin to specific version: - # image: registry.gitlab.com/towerops/towerops-agent:0.1.0 - environment: - - TOWEROPS_API_URL=https://app.towerops.com - - TOWEROPS_AGENT_TOKEN=${AGENT_TOKEN} - volumes: - - ./data:/data -``` - -## Customer Deployment - -### Provide to Customers - -**Option 1: Docker Compose (Recommended)** - -Create `docker-compose.yml`: -```yaml -version: '3.8' -services: - towerops-agent: - image: registry.gitlab.com/towerops/towerops-agent:latest - container_name: towerops-agent - restart: unless-stopped - environment: - - TOWEROPS_API_URL=https://app.towerops.com - - TOWEROPS_AGENT_TOKEN= - volumes: - - ./data:/data -``` - -Instructions for customer: -```bash -# 1. Get agent token from Towerops UI -# 2. Replace in docker-compose.yml -# 3. Start agent -docker-compose up -d - -# 4. Check logs -docker-compose logs -f - -# 5. Check status -docker-compose ps -``` - -**Option 2: Docker Run** - -```bash -docker run -d \ - --name towerops-agent \ - --restart unless-stopped \ - -e TOWEROPS_API_URL=https://app.towerops.com \ - -e TOWEROPS_AGENT_TOKEN= \ - -v $(pwd)/data:/data \ - registry.gitlab.com/towerops/towerops-agent:latest -``` - -## CI/CD Configuration - -### Required GitLab Variables - -No additional CI/CD variables needed. GitLab provides these automatically: -- `CI_REGISTRY` - GitLab Container Registry URL -- `CI_REGISTRY_USER` - Username for registry login -- `CI_REGISTRY_PASSWORD` - Password for registry login - -These are automatically available in all GitLab CI/CD pipelines. - -### Pipeline Triggers - -**Automatic**: -- Push to any branch → test + build with branch tag -- Push to main → test + build + tag as `latest` -- Create tag (e.g., `v0.1.0`) → test + build + release - -**Manual**: No manual triggers configured (all automatic) - -### Viewing Pipeline Status - -1. Go to: https://gitlab.com/towerops/towerops-agent/-/pipelines -2. Click on a pipeline to see detailed logs -3. Check job logs if build fails - -## Local Development - -### Build Locally - -```bash -# Development build -cargo build - -# Release build (optimized) -cargo build --release - -# Build Docker image locally -docker build -t towerops-agent:local . - -# Test local image -docker run --rm \ - -e TOWEROPS_API_URL=http://host.docker.internal:4000 \ - -e TOWEROPS_AGENT_TOKEN=test-token \ - -v $(pwd)/test-data:/data \ - towerops-agent:local -``` - -### Test Before Pushing - -**Prerequisites**: Rust 1.83+ (required by dependencies) - -```bash -# Check Rust version -rustc --version # Should be 1.83.0 or later - -# Check compilation -cargo check --release - -# Format check -cargo fmt -- --check - -# Lint check -cargo clippy -- -D warnings - -# All together (what CI runs) -cargo check --release && \ -cargo fmt -- --check && \ -cargo clippy -- -D warnings -``` - -## Rollback Procedure - -### If Latest Version Has Issues - -**Option 1: Revert Tag** -```bash -# Find previous working version -git tag -l - -# Delete bad tag locally and remotely -git tag -d v0.2.0 -git push origin :refs/tags/v0.2.0 - -# Customers can use previous version -docker pull registry.gitlab.com/towerops/towerops-agent:0.1.0 -``` - -**Option 2: Quick Fix** -```bash -# Fix the issue -git commit -m "Hotfix: fix critical bug" - -# Create patch version -git tag v0.2.1 -git push origin main --tags - -# New pipeline builds v0.2.1 and updates latest -``` - -**Option 3: Pin Customers to Known Good Version** - -Update customer docker-compose.yml: -```yaml -image: registry.gitlab.com/towerops/towerops-agent:0.1.0 # Pin to working version -``` - -## Multi-Architecture Support (Optional) - -To support ARM devices (Raspberry Pi, etc.), uncomment the multi-arch section in `.gitlab-ci.yml`. - -This will build for: -- `linux/amd64` (x86_64 servers) -- `linux/arm64` (ARM servers, Raspberry Pi 4+) - -**Note**: Multi-arch builds take longer (~2x build time). - -## Monitoring Deployments - -### Check Image Size - -```bash -docker images registry.gitlab.com/towerops/towerops-agent -``` - -Expected size: 10-20 MB - -### Check Registry Usage - -GitLab provides 10 GB of free registry storage. Monitor usage at: -``` -https://gitlab.com/towerops/towerops-agent/-/packages -``` - -### Cleanup Old Images - -GitLab has automatic cleanup policies. Configure at: -``` -Settings → Packages & Registries → Container Registry → Cleanup policies -``` - -Recommended settings: -- Keep most recent: 10 tags -- Keep tags matching: `^v\d+\.\d+\.\d+$` (versions) -- Remove tags older than: 90 days - -## Troubleshooting - -### Pipeline Fails with "lock file version not understood" - -**Symptom**: -``` -error: failed to parse lock file at: /builds/towerops/towerops-agent/Cargo.lock -Caused by: - lock file version `4` was found, but this version of Cargo does not understand this lock file -``` - -**Cause**: Dependencies require Rust 1.83+ - -**Fix**: The CI configuration uses Rust 1.83. If you see this error: -1. Update `.gitlab-ci.yml` to use `rust:1.83-alpine` or later -2. Update `Dockerfile` to use `rust:1.83-alpine` or later -3. Local development: Update Rust with `rustup update stable` - -### Pipeline Fails at Test Stage - -**Symptom**: `cargo check` or `cargo clippy` fails - -**Fix**: -```bash -# Run locally to see errors -cargo check --release -cargo clippy -- -D warnings - -# Fix issues and push -git add . -git commit -m "Fix clippy warnings" -git push -``` - -### Pipeline Fails at Build Stage - -**Symptom**: Docker build fails - -**Fix**: -```bash -# Test Docker build locally -docker build -t test . - -# Check Dockerfile syntax -# Check .dockerignore isn't excluding needed files -``` - -### Image Too Large - -**Symptom**: Image is >50 MB - -**Fix**: -- Check release profile in Cargo.toml (should have `strip = true`) -- Verify multi-stage build is working -- Check for large files in context (review .dockerignore) - -### Can't Pull Image - -**Symptom**: `docker pull` fails with authentication error - -**Fix**: -```bash -# Login to GitLab registry -docker login registry.gitlab.com -# Username: your GitLab username -# Password: personal access token with read_registry scope - -# Or use deploy token (for customers) -# Create at: Settings → Repository → Deploy tokens -``` - -## Security - -### Container Scanning (Optional) - -Add to `.gitlab-ci.yml` for security scanning: - -```yaml -include: - - template: Security/Container-Scanning.gitlab-ci.yml - -container_scanning: - stage: test - variables: - CS_IMAGE: $REGISTRY/$IMAGE_NAME:$CI_COMMIT_SHORT_SHA -``` - -### Private Registry Access - -For customers needing private access: - -1. Create deploy token: - - Go to: Settings → Repository → Deploy tokens - - Name: `customer-deploy-token` - - Scopes: `read_registry` - - Copy username and token - -2. Provide to customer: -```bash -docker login registry.gitlab.com -# Username: -# Password: -``` - -## Support - -For issues with deployment: -1. Check pipeline logs in GitLab -2. Review CLAUDE.md for architecture details -3. Test locally with `docker build` -4. Check GitLab registry status page - ---- - -**Last Updated**: January 9, 2026 -**Registry**: registry.gitlab.com/towerops/towerops-agent -**Current Version**: 0.1.0 (pre-release) diff --git a/INTEGRATION_TEST_PLAN.md b/INTEGRATION_TEST_PLAN.md deleted file mode 100644 index 50a880d..0000000 --- a/INTEGRATION_TEST_PLAN.md +++ /dev/null @@ -1,507 +0,0 @@ -# Agent Integration Test Plan - -This document provides a complete plan for integration testing the Towerops agent with the Phoenix backend. - -## Prerequisites - -- Phoenix backend running locally (`mix phx.server`) -- Docker or podman installed -- Agent Docker image built (`localhost/towerops-agent:latest`) -- Access to SNMP test device OR SNMP simulator running - -## Test Environment Options - -### Option 1: Using Real SNMP Device (Recommended for Complete Testing) - -The existing integration test file references a MikroTik device at `10.0.19.254`. - -**Requirements**: -- Network access to SNMP device -- Valid SNMP community string -- Device must support SNMPv2c - -### Option 2: Using SNMP Simulator (Better for CI/CD) - -Use `snmpsim` to simulate SNMP devices: - -```bash -# Install snmpsim -pip install snmpsim - -# Create simulation data directory -mkdir -p ~/snmpsim-data - -# Create a simple device simulation file -cat > ~/snmpsim-data/public.snmprec << 'EOF' -1.3.6.1.2.1.1.1.0|4|Test Router v1.0 -1.3.6.1.2.1.1.2.0|6|1.3.6.1.4.1.9.1.1 -1.3.6.1.2.1.1.3.0|67|12345678 -1.3.6.1.2.1.1.4.0|4|admin@test.local -1.3.6.1.2.1.1.5.0|4|test-router -1.3.6.1.2.1.1.6.0|4|Test Lab -# Temperature sensor -1.3.6.1.4.1.9.9.91.1.1.1.1.1.1000|2|8 -1.3.6.1.4.1.9.9.91.1.1.1.1.4.1000|2|450 -# Interface ifIndex -1.3.6.1.2.1.2.2.1.1.1|2|1 -1.3.6.1.2.1.2.2.1.2.1|4|GigabitEthernet0/1 -1.3.6.1.2.1.2.2.1.10.1|65|1234567890 -1.3.6.1.2.1.2.2.1.16.1|65|9876543210 -EOF - -# Start simulator -snmpsimd.py \ - --data-dir=~/snmpsim-data \ - --agent-udpv4-endpoint=127.0.0.1:1161 \ - --v2c-arch -``` - -**Test against simulator**: -```bash -# Verify simulator works -snmpget -v2c -c public localhost:1161 1.3.6.1.2.1.1.1.0 -# Should return: SNMPv2-MIB::sysDescr.0 = STRING: Test Router v1.0 -``` - -## Integration Test Procedure - -### Phase 1: Backend Setup - -1. **Start Phoenix Server**: -```bash -cd /Users/graham/dev/towerops -mix phx.server -# Access at http://localhost:4000 -``` - -2. **Create Organization and User** (if not exists): -- Register a test user via UI -- Create organization "Test Org" - -3. **Create Test Equipment**: -- Navigate to Sites → Create Site "Test Site" -- Add Equipment "Test Router" - - IP Address: `127.0.0.1:1161` (if using simulator) or `10.0.19.254` (real device) - - SNMP Enabled: Yes - - SNMP Version: 2c - - SNMP Community: `public` (simulator) or `kdyyJrT0Mm` (real device) - - Poll Interval: 60 seconds - -4. **Run SNMP Discovery**: -- Click "Discover SNMP" on equipment page -- Verify sensors and interfaces are discovered -- Expected sensors: Temperature sensors (Cisco) or system sensors (MikroTik) -- Expected interfaces: At least 1 network interface - -5. **Create Agent Token**: -- Navigate to `/orgs/:slug/agents` -- Click "Create New Agent" -- Name: "Test Agent" -- Copy the token (shown only once) - save it for next steps - -6. **Assign Equipment to Agent**: -- On equipment page, under "Agent Assignment" section -- Select "Test Agent" -- Click "Assign Agent" -- Or set as site/organization default - -### Phase 2: Agent Setup & Deployment - -#### Option A: Run with Docker/Podman - -1. **Create agent configuration**: -```bash -cd /Users/graham/dev/towerops/towerops-agent - -# Create data directory -mkdir -p data - -# Run agent -podman run --rm -it \ - --network=host \ - -e TOWEROPS_API_URL=http://localhost:4000 \ - -e TOWEROPS_AGENT_TOKEN= \ - -e RUST_LOG=info \ - -v $(pwd)/data:/data \ - localhost/towerops-agent:latest -``` - -**For simulator on different machine**: -```bash -# Use host.docker.internal for Mac/Windows -podman run --rm -it \ - --add-host=host.docker.internal:host-gateway \ - -e TOWEROPS_API_URL=http://host.docker.internal:4000 \ - -e TOWEROPS_AGENT_TOKEN= \ - -e RUST_LOG=debug \ - -v $(pwd)/data:/data \ - localhost/towerops-agent:latest -``` - -#### Option B: Run with Cargo (Development) - -```bash -cd /Users/graham/dev/towerops/towerops-agent - -RUST_LOG=debug cargo run -- \ - --api-url http://localhost:4000 \ - --token \ - --database-path ./test-agent.db -``` - -### Phase 3: Verification Tests - -#### Test 1: Agent Authentication ✅ - -**Expected Logs (Agent)**: -``` -INFO towerops_agent: Starting Towerops Agent v0.1.0 -INFO towerops_agent::api_client: Testing API connection... -INFO towerops_agent::api_client: API connection successful -``` - -**Verification (Phoenix)**: -- Check agent appears in UI at `/orgs/:slug/agents` -- Status shows "Online" (green dot) -- "Last Seen" shows current timestamp -- Hostname and version populated - -**Database Check**: -```sql -SELECT name, enabled, last_seen_at, metadata -FROM agent_tokens -WHERE name = 'Test Agent'; -``` - -#### Test 2: Configuration Fetch ✅ - -**Expected Logs (Agent)**: -``` -INFO towerops_agent::poller::scheduler: Fetching configuration from API... -INFO towerops_agent::api_client: Configuration fetched successfully -INFO towerops_agent::poller::scheduler: Configuration updated: 1 equipment -``` - -**Verification**: -- Agent logs show equipment details (IP, name, sensor count, interface count) -- No authentication errors -- Config matches what's in database - -#### Test 3: SNMP Polling ✅ - -**Expected Logs (Agent)**: -``` -INFO towerops_agent::poller::executor: Polling equipment: Test Router (127.0.0.1) -DEBUG towerops_agent::poller::executor: Polling 2 sensors and 1 interfaces -INFO towerops_agent::poller::executor: Successfully polled 2 sensor readings -INFO towerops_agent::poller::executor: Successfully polled 1 interface stats -``` - -**Verification (Database)**: -```sql --- Check sensor readings (should appear within 60 seconds) -SELECT sr.value, sr.status, sr.checked_at, s.sensor_type, s.sensor_oid -FROM snmp_sensor_readings sr -JOIN snmp_sensors s ON sr.sensor_id = s.id -JOIN snmp_devices d ON s.snmp_device_id = d.id -JOIN equipment e ON d.equipment_id = e.id -WHERE e.name = 'Test Router' -ORDER BY sr.checked_at DESC -LIMIT 10; - --- Check interface stats -SELECT - if_in_octets, if_out_octets, - if_in_errors, if_out_errors, - checked_at -FROM snmp_interface_stats ist -JOIN snmp_interfaces i ON ist.interface_id = i.id -JOIN snmp_devices d ON i.snmp_device_id = d.id -JOIN equipment e ON d.equipment_id = e.id -WHERE e.name = 'Test Router' -ORDER BY checked_at DESC -LIMIT 10; -``` - -**Expected Results**: -- New rows appear every 60 seconds (poll interval) -- Sensor values are numeric and reasonable (temperatures 20-80°C) -- Interface counters are increasing -- Timestamps are current - -#### Test 4: Metrics Submission ✅ - -**Expected Logs (Agent)**: -``` -INFO towerops_agent::buffer::storage: Storing 3 metrics in buffer -INFO towerops_agent::api_client: Flushing 3 pending metrics to API -INFO towerops_agent::api_client: Metrics submitted successfully: 3 accepted -``` - -**Expected Logs (Phoenix)**: -``` -[info] POST /api/v1/agent/metrics -[info] Sent 200 in 45ms -``` - -**Verification (UI)**: -- Equipment page shows recent sensor readings -- Charts update with new data points -- "Last Check" timestamp is current - -#### Test 5: Heartbeat ✅ - -**Expected Logs (Agent)**: -``` -INFO towerops_agent::api_client: Sending heartbeat... -INFO towerops_agent::api_client: Heartbeat successful -``` - -**Expected Logs (Phoenix)**: -``` -[info] POST /api/v1/agent/heartbeat -[info] Sent 200 in 12ms -``` - -**Verification**: -- Agent "Last Seen" updates every 60 seconds -- Agent status remains "Online" -- Agent metadata shows correct version, hostname, uptime - -**Database Check**: -```sql -SELECT - name, - last_seen_at, - metadata->>'version' as version, - metadata->>'hostname' as hostname, - metadata->>'uptime_seconds' as uptime -FROM agent_tokens -WHERE name = 'Test Agent'; -``` - -#### Test 6: API Outage Resilience ✅ - -**Test Procedure**: -1. Stop Phoenix server: `Ctrl+C` in Phoenix terminal -2. Wait 2 minutes (agent continues polling) -3. Restart Phoenix server: `mix phx.server` - -**Expected Behavior (Agent)**: -``` -WARN towerops_agent::api_client: Failed to submit metrics: Connection refused -INFO towerops_agent::buffer::storage: Metrics stored in buffer, will retry -INFO towerops_agent::poller::executor: Continuing to poll locally -``` - -**After Phoenix Restart**: -``` -INFO towerops_agent::api_client: API connection restored -INFO towerops_agent::api_client: Flushing buffered metrics (15 pending) -INFO towerops_agent::api_client: Metrics submitted successfully: 15 accepted -``` - -**Verification**: -- No data loss during outage -- All buffered metrics submitted after reconnection -- Timestamps reflect actual poll times (not submission time) -- SQLite database size grows during outage, shrinks after - -**Database Check**: -```bash -# During outage -ls -lh data/towerops-agent.db -# Size should increase - -# After reconnection -ls -lh data/towerops-agent.db -# Size should decrease as metrics are sent -``` - -#### Test 7: Token Revocation ✅ - -**Test Procedure**: -1. In UI, navigate to agent details -2. Click "Revoke Token" or disable agent -3. Observe agent logs - -**Expected Logs (Agent)**: -``` -ERROR towerops_agent::api_client: Authentication failed: 401 Unauthorized -ERROR towerops_agent::poller::scheduler: Failed to fetch config: authentication error -``` - -**Verification**: -- Agent stops polling immediately -- No new metrics appear in database -- Agent status shows "Offline" in UI -- Agent logs show authentication errors - -#### Test 8: Network Interruption ✅ - -**Test Procedure**: -1. While agent is running, simulate network issue: - ```bash - # Block localhost traffic temporarily (requires sudo) - sudo ifconfig lo0 down - sleep 10 - sudo ifconfig lo0 up - ``` - -**Expected Behavior**: -``` -WARN towerops_agent::api_client: Network error: Connection timeout -INFO towerops_agent::buffer::storage: Buffering metrics locally -INFO towerops_agent::api_client: Retrying connection... -INFO towerops_agent::api_client: Connection restored -``` - -**Verification**: -- Agent continues polling during network outage -- Metrics buffered locally -- Automatic reconnection after network restored -- All metrics eventually submitted - -### Phase 4: Load Testing - -#### Test 9: Multiple Equipment Assignment - -**Setup**: -1. Create 10 equipment entries with SNMP enabled -2. Assign all to same agent -3. Each equipment has 2-3 sensors and 1-2 interfaces - -**Expected Behavior**: -- Agent polls all equipment in parallel -- Memory usage stays under 50 MB -- CPU usage reasonable (<25% of one core) -- All metrics submitted successfully -- Poll interval maintained (60s ±5s) - -**Monitoring**: -```bash -# Watch agent resource usage -podman stats - -# Check database growth -watch -n 5 'du -h data/towerops-agent.db' - -# Monitor metrics rate -psql towerops_dev -c " -SELECT - COUNT(*) as total_readings, - MAX(checked_at) as latest, - MIN(checked_at) as earliest -FROM snmp_sensor_readings -WHERE checked_at > NOW() - INTERVAL '5 minutes';" -``` - -#### Test 10: 24-Hour Stability Test - -**Setup**: -1. Configure agent with 5-10 equipment -2. Run continuously for 24 hours -3. Monitor for crashes, memory leaks, connection issues - -**Metrics to Track**: -- Uptime (should be 24+ hours) -- Memory usage (should be stable, not growing) -- CPU usage (should be consistent) -- Database size (should cycle, not grow indefinitely) -- Error rate (should be near zero) -- Metrics success rate (should be >99%) - -**Check Script**: -```bash -#!/bin/bash -# stability-check.sh -while true; do - echo "=== $(date) ===" - - # Agent container status - podman ps | grep towerops-agent - - # Memory usage - podman stats --no-stream towerops-agent | tail -1 - - # Database size - du -h data/towerops-agent.db - - # Recent metrics count - psql towerops_dev -c "SELECT COUNT(*) FROM snmp_sensor_readings WHERE checked_at > NOW() - INTERVAL '5 minutes';" - - sleep 300 # Check every 5 minutes -done -``` - -## Success Criteria - -All tests must pass for agent to be production-ready: - -- [x] Agent authenticates with token successfully -- [x] Agent fetches configuration from API -- [x] Agent polls SNMP devices (sensors + interfaces) -- [x] Metrics appear in database within 60 seconds -- [ ] Threshold violations trigger events (requires threshold configuration) -- [x] Agent survives 24h API outage without data loss -- [x] UI shows agent status (online/offline) -- [x] Token revocation works immediately -- [x] Agent uses <256 MB memory with 50 devices -- [x] Docker image is <50 MB (actual: 11.8 MB) -- [ ] Load test: 100 devices, 500 sensors, 200 interfaces -- [ ] Stability test: 7 days continuous operation - -## Troubleshooting - -### Agent Won't Start - -**Symptoms**: Agent exits immediately or fails to start - -**Checks**: -1. Verify token is valid: `echo $TOWEROPS_AGENT_TOKEN` -2. Check API URL is correct: `curl http://localhost:4000/health` -3. Check logs: `podman logs ` -4. Verify database directory is writable: `ls -la data/` - -### Agent Shows Offline in UI - -**Symptoms**: Agent is running but shows offline - -**Checks**: -1. Check last_seen_at in database -2. Verify heartbeat endpoint works: `curl -H "Authorization: Bearer $TOKEN" http://localhost:4000/api/v1/agent/heartbeat -X POST` -3. Check for clock skew between agent and server -4. Verify agent can reach Phoenix server - -### No Metrics Appearing - -**Symptoms**: Agent running but no data in database - -**Checks**: -1. Verify SNMP device is reachable from agent -2. Check SNMP credentials are correct -3. Check equipment is assigned to agent -4. Check agent logs for SNMP errors -5. Verify equipment has discovered sensors/interfaces - -### High Memory Usage - -**Symptoms**: Agent memory usage growing over time - -**Checks**: -1. Check database size: `du -h data/towerops-agent.db` -2. Check how many metrics are buffered -3. Verify metrics are being submitted (not just buffered) -4. Check cleanup job is running (should run every hour) - -## Next Steps After Integration Testing - -Once integration testing passes: - -1. **Performance Testing**: Load test with 100+ devices -2. **Stability Testing**: 7-day continuous run -3. **Container Registry**: Publish image to registry -4. **Release Tagging**: Tag v0.1.0 release -5. **Beta Testing**: Deploy to select customers -6. **Monitoring Setup**: Grafana dashboards and alerts -7. **Documentation**: Update with real-world examples and screenshots diff --git a/README.md b/README.md index 324328c..8c4522a 100644 --- a/README.md +++ b/README.md @@ -4,14 +4,15 @@ A lightweight Rust-based remote polling agent for Towerops SNMP monitoring. ## Overview -The Towerops agent enables customers to deploy SNMP polling infrastructure on their internal networks. The agent polls SNMP devices locally and reports metrics to the Towerops API using token-based authentication. +The Towerops agent enables customers to deploy SNMP polling infrastructure on their internal networks. The agent connects to the Towerops server via WebSocket and executes SNMP queries as directed by the server. ## Features - **Local SNMP Polling**: Poll devices on your internal network without exposing them to the internet -- **Secure Communication**: All communication with Towerops API uses HTTPS with token authentication -- **Metric Buffering**: Stores up to 24 hours of metrics in SQLite when API is unavailable -- **Automatic Configuration**: Fetches polling configuration from the Towerops API +- **SNMP Trap Receiver**: Listen for SNMP v1 and v2c traps from network devices +- **Secure Communication**: All communication with Towerops uses WebSocket over TLS with token authentication +- **Real-time Updates**: Server pushes configuration changes instantly via persistent WebSocket connection +- **Automatic Reconnection**: Exponential backoff reconnection on network failures - **Automatic Updates**: Checks for new versions hourly and self-updates when available (requires Docker socket access) - **Low Resource Usage**: Built in Rust for minimal memory and CPU footprint (< 256 MB RAM typical) - **Docker Ready**: Pre-built Docker images for easy deployment @@ -20,10 +21,10 @@ The Towerops agent enables customers to deploy SNMP polling infrastructure on th ### Using Pre-built Image -Pull the latest image from GitLab Container Registry: +Pull the latest image from Docker Hub: ```bash -docker pull registry.gitlab.com/towerops/towerops-agent:latest +docker pull gmcintire/towerops-agent:latest ``` ### Using Docker Compose @@ -32,17 +33,21 @@ docker pull registry.gitlab.com/towerops/towerops-agent:latest ```yaml version: '3.8' + services: towerops-agent: - image: registry.gitlab.com/towerops/towerops-agent:latest + image: gmcintire/towerops-agent:latest restart: unless-stopped environment: - TOWEROPS_API_URL=https://app.towerops.com - TOWEROPS_AGENT_TOKEN=your-agent-token-here - volumes: - - ./data:/data - # Required for automatic self-updates - - /var/run/docker.sock:/var/run/docker.sock + - LOG_LEVEL=info + # Optional: Enable SNMP trap listener + - TRAP_ENABLED=true + - TRAP_PORT=162 + ports: + # SNMP trap listener (UDP) - only needed if TRAP_ENABLED=true + - "162:162/udp" ``` 2. Start the agent: @@ -51,8 +56,6 @@ services: docker-compose up -d ``` -**Note**: The Docker socket mount (`/var/run/docker.sock`) is required for automatic updates. The agent checks for new versions hourly and will automatically pull and restart with the latest version when available. - ### Configuration The agent is configured via environment variables: @@ -61,8 +64,9 @@ The agent is configured via environment variables: |----------|-------------|---------| | `TOWEROPS_API_URL` | Towerops API endpoint | Required | | `TOWEROPS_AGENT_TOKEN` | Agent authentication token | Required | -| `CONFIG_REFRESH_SECONDS` | How often to refresh configuration | 300 (5 minutes) | -| `DATABASE_PATH` | SQLite database path for buffering | `/data/towerops-agent.db` | +| `LOG_LEVEL` | Logging level (error, warn, info, debug) | info | +| `TRAP_ENABLED` | Enable SNMP trap listener | false | +| `TRAP_PORT` | UDP port for SNMP traps | 162 | ### Obtaining an Agent Token @@ -73,31 +77,34 @@ The agent is configured via environment variables: ## Architecture -The agent consists of several components: +The agent uses a WebSocket-based architecture for real-time communication: -- **API Client**: Communicates with Towerops API to fetch configuration and submit metrics -- **SNMP Poller**: Polls configured devices for sensor readings and interface statistics -- **Storage Buffer**: SQLite database that buffers metrics during API outages -- **Scheduler**: Coordinates polling intervals and metric submission +- **WebSocket Client**: Maintains a persistent connection to the Towerops server +- **SNMP Executor**: Executes SNMP queries (GET, WALK) as directed by the server +- **Trap Listener**: Optional UDP listener for receiving SNMP traps from devices -### Polling Flow +### Communication Flow -1. Agent fetches configuration from API every 5 minutes (configurable) -2. For each equipment item, polls sensors and interfaces at configured intervals -3. Metrics are stored locally in SQLite -4. Every 30 seconds, pending metrics are submitted to the API -5. Successfully submitted metrics are marked as sent and cleaned up after 24 hours +1. Agent establishes WebSocket connection to `{api_url}/socket/agent/websocket` +2. Agent authenticates by joining Phoenix channel with token +3. Server pushes SNMP jobs (queries to execute) to agent +4. Agent executes queries and sends results back via WebSocket +5. Periodic heartbeats maintain connection health +6. On disconnect, agent reconnects with exponential backoff (1s to 60s) -### Buffering +### SNMP Trap Listener -If the API is unreachable, metrics are stored locally for up to 24 hours. When connectivity is restored, the agent automatically submits all buffered metrics. +When enabled (`TRAP_ENABLED=true`), the agent listens for SNMP traps: + +- Supports SNMPv1 and SNMPv2c trap formats +- Logs received traps with source address, enterprise OID, and variable bindings +- Default port 162 (standard SNMP trap port) ## Building from Source ### Prerequisites -- Rust 1.83 or later -- SQLite development libraries +- Rust 1.91 or later ### Build @@ -117,39 +124,38 @@ docker build -t towerops-agent . ### Agent Not Connecting -- Verify the API URL is correct +- Verify the API URL is correct (accepts http://, https://, ws://, or wss://) - Check that the agent token is valid and hasn't been revoked - Ensure network connectivity to the Towerops API +- Check logs for connection errors: `docker logs towerops-agent` ### No Metrics Appearing - Check that equipment is assigned to this agent in Towerops - Verify SNMP credentials are correct in Towerops equipment settings - Review agent logs for SNMP polling errors +- Ensure the agent is connected (check Towerops UI for agent status) -### High Memory Usage +### Traps Not Received -- Check the size of the SQLite database (`/data/towerops-agent.db`) -- Verify metrics are being submitted successfully (check API connectivity) +- Ensure `TRAP_ENABLED=true` is set +- Verify UDP port 162 is exposed and not blocked by firewall +- Check that devices are configured to send traps to the agent's IP +- Look for trap messages in logs with `LOG_LEVEL=debug` ## Resource Requirements -- **Memory**: 128-256 MB typical, 512 MB maximum +- **Memory**: 64-128 MB typical, 256 MB maximum - **CPU**: 0.1-0.5 cores typical -- **Disk**: ~100 MB for 24 hours of buffered metrics -- **Network**: Minimal (metrics are small JSON payloads) +- **Network**: Minimal (small protobuf messages over WebSocket) ## Security - Agent token should be kept secret (treat like a password) -- All API communication uses HTTPS with certificate verification -- Agent requires no inbound network connections +- All API communication uses TLS with certificate verification +- Agent requires no inbound network connections (except optional trap listener on UDP 162) - SNMP community strings are only used locally and never logged -## Development Status - -**NOTE**: SNMP library integration is incomplete. The current implementation compiles but requires proper SNMP library integration for production use. This will be completed in the next development phase. - ## License -Copyright © 2026 Towerops +Copyright 2026 Towerops diff --git a/RELEASE.md b/RELEASE.md deleted file mode 100644 index 4411c07..0000000 --- a/RELEASE.md +++ /dev/null @@ -1,441 +0,0 @@ -# Release Process for Towerops Agent - -This document describes how to build, tag, and publish releases of the Towerops agent Docker image. - -## Prerequisites - -- Podman or Docker installed -- Access to container registry (Docker Hub, GitHub Container Registry, GitLab Registry, etc.) -- Agent code built and tested - -## Version Numbering - -Follow semantic versioning (SemVer): -- **MAJOR**: Incompatible API/protocol changes -- **MINOR**: New functionality, backwards compatible -- **PATCH**: Bug fixes, backwards compatible - -Current version: **0.1.0** - -## Build Process - -### 1. Update Version Numbers - -Before building a release, update version numbers in: - -1. **Cargo.toml**: -```toml -[package] -name = "towerops-agent" -version = "0.1.0" # Update this -``` - -2. **CLAUDE.md** - Update status section - -3. **README.md** - Update any version references - -### 2. Build Multi-Architecture Images - -Build for both AMD64 and ARM64: - -```bash -cd /Users/graham/dev/towerops/towerops-agent - -# Build for ARM64 (Apple Silicon) -podman build --platform linux/arm64 -t towerops-agent:0.1.0-arm64 . - -# Build for AMD64 (Intel/AMD) -podman build --platform linux/amd64 -t towerops-agent:0.1.0-amd64 . -``` - -### 3. Tag Images - -Tag with version and 'latest': - -```bash -# Tag ARM64 -podman tag towerops-agent:0.1.0-arm64 localhost/towerops-agent:0.1.0 -podman tag towerops-agent:0.1.0-arm64 localhost/towerops-agent:latest - -# Tag AMD64 -podman tag towerops-agent:0.1.0-amd64 localhost/towerops-agent:0.1.0-amd64 -``` - -### 4. Test Images Locally - -Before publishing, test both images: - -```bash -# Test ARM64 -podman run --rm \ - -e TOWEROPS_API_URL=http://localhost:4000 \ - -e TOWEROPS_AGENT_TOKEN=test-token \ - localhost/towerops-agent:0.1.0 --version - -# Test AMD64 (if on compatible platform) -podman run --rm --platform linux/amd64 \ - -e TOWEROPS_API_URL=http://localhost:4000 \ - -e TOWEROPS_AGENT_TOKEN=test-token \ - localhost/towerops-agent:0.1.0-amd64 --version -``` - -## Publishing to Container Registries - -### Option 1: Docker Hub - -**Registry**: `docker.io/username/towerops-agent` - -1. **Login**: -```bash -podman login docker.io -# Enter username and password/token -``` - -2. **Tag for Docker Hub**: -```bash -# Replace 'username' with your Docker Hub username -DOCKER_USER="username" - -podman tag localhost/towerops-agent:0.1.0 docker.io/${DOCKER_USER}/towerops-agent:0.1.0 -podman tag localhost/towerops-agent:latest docker.io/${DOCKER_USER}/towerops-agent:latest -podman tag localhost/towerops-agent:0.1.0-amd64 docker.io/${DOCKER_USER}/towerops-agent:0.1.0-amd64 -``` - -3. **Push**: -```bash -podman push docker.io/${DOCKER_USER}/towerops-agent:0.1.0 -podman push docker.io/${DOCKER_USER}/towerops-agent:latest -podman push docker.io/${DOCKER_USER}/towerops-agent:0.1.0-amd64 -``` - -4. **Create multi-arch manifest** (optional, for `docker pull` without specifying platform): -```bash -podman manifest create docker.io/${DOCKER_USER}/towerops-agent:0.1.0 -podman manifest add docker.io/${DOCKER_USER}/towerops-agent:0.1.0 docker.io/${DOCKER_USER}/towerops-agent:0.1.0-arm64 -podman manifest add docker.io/${DOCKER_USER}/towerops-agent:0.1.0 docker.io/${DOCKER_USER}/towerops-agent:0.1.0-amd64 -podman manifest push docker.io/${DOCKER_USER}/towerops-agent:0.1.0 -``` - -### Option 2: GitHub Container Registry (ghcr.io) - -**Registry**: `ghcr.io/username/towerops-agent` - -1. **Create Personal Access Token**: - - Go to GitHub Settings → Developer settings → Personal access tokens - - Generate new token with `write:packages` and `read:packages` scopes - - Save the token securely - -2. **Login**: -```bash -echo $GITHUB_TOKEN | podman login ghcr.io -u USERNAME --password-stdin -``` - -3. **Tag for GHCR**: -```bash -GITHUB_USER="username" - -podman tag localhost/towerops-agent:0.1.0 ghcr.io/${GITHUB_USER}/towerops-agent:0.1.0 -podman tag localhost/towerops-agent:latest ghcr.io/${GITHUB_USER}/towerops-agent:latest -``` - -4. **Push**: -```bash -podman push ghcr.io/${GITHUB_USER}/towerops-agent:0.1.0 -podman push ghcr.io/${GITHUB_USER}/towerops-agent:latest -``` - -5. **Make Package Public** (optional): - - Go to package settings on GitHub - - Change visibility to public - -### Option 3: GitLab Container Registry - -**Registry**: `registry.gitlab.com/username/towerops-agent` - -1. **Create Deploy Token or Personal Access Token**: - - GitLab Project → Settings → Repository → Deploy tokens - - Or use personal access token with `read_registry` and `write_registry` scopes - -2. **Login**: -```bash -podman login registry.gitlab.com -# Username: your GitLab username or deploy token name -# Password: personal access token or deploy token -``` - -3. **Tag for GitLab**: -```bash -GITLAB_USER="username" - -podman tag localhost/towerops-agent:0.1.0 registry.gitlab.com/${GITLAB_USER}/towerops-agent:0.1.0 -podman tag localhost/towerops-agent:latest registry.gitlab.com/${GITLAB_USER}/towerops-agent:latest -``` - -4. **Push**: -```bash -podman push registry.gitlab.com/${GITLAB_USER}/towerops-agent:0.1.0 -podman push registry.gitlab.com/${GITLAB_USER}/towerops-agent:latest -``` - -### Option 4: Self-Hosted Registry - -**Registry**: `registry.example.com/towerops-agent` - -1. **Login** (if authentication required): -```bash -podman login registry.example.com -``` - -2. **Tag**: -```bash -podman tag localhost/towerops-agent:0.1.0 registry.example.com/towerops-agent:0.1.0 -podman tag localhost/towerops-agent:latest registry.example.com/towerops-agent:latest -``` - -3. **Push**: -```bash -podman push registry.example.com/towerops-agent:0.1.0 -podman push registry.example.com/towerops-agent:latest -``` - -## Git Release Tagging - -After publishing the Docker images: - -1. **Commit all changes**: -```bash -git add -A -git commit -m "Release v0.1.0" -``` - -2. **Create and push git tag**: -```bash -git tag -a v0.1.0 -m "Release v0.1.0 - Initial production release" -git push origin v0.1.0 -git push origin main -``` - -3. **Create GitHub/GitLab Release**: - - Go to repository releases page - - Create new release from tag v0.1.0 - - Add release notes (see template below) - -## Release Notes Template - -```markdown -# Towerops Agent v0.1.0 - -## Features - -- Remote SNMP polling for Towerops equipment -- Protocol Buffers API communication -- SQLite-based metric buffering (24-hour retention) -- Automatic reconnection and retry logic -- Multi-architecture support (AMD64, ARM64) -- Minimal footprint: 11.8 MB Docker image - -## Configuration - -- API URL and authentication token via environment variables -- Configurable poll intervals per equipment -- Customizable database path - -## Installation - -```bash -docker pull ghcr.io/username/towerops-agent:0.1.0 -``` - -See [USER_GUIDE.md](USER_GUIDE.md) for deployment instructions. - -## System Requirements - -- Docker or Podman -- Network access to Towerops API -- Network access to SNMP devices (UDP port 161) -- 50-100 MB disk space for database - -## Breaking Changes - -None (initial release) - -## Known Issues - -None - -## Contributors - -- [List contributors] -``` - -## CI/CD Automation (Optional) - -### GitLab CI Example - -Create `.gitlab-ci.yml`: - -```yaml -variables: - REGISTRY_IMAGE: $CI_REGISTRY_IMAGE - -stages: - - test - - build - - release - -test: - stage: test - image: rust:1.83-alpine - before_script: - - apk add --no-cache musl-dev protobuf-dev - script: - - cargo test --release - only: - - branches - -build: - stage: build - image: docker:latest - services: - - docker:dind - script: - - docker build -t $REGISTRY_IMAGE:$CI_COMMIT_SHORT_SHA . - - docker push $REGISTRY_IMAGE:$CI_COMMIT_SHORT_SHA - only: - - main - -release: - stage: release - image: docker:latest - services: - - docker:dind - script: - - docker pull $REGISTRY_IMAGE:$CI_COMMIT_SHORT_SHA - - docker tag $REGISTRY_IMAGE:$CI_COMMIT_SHORT_SHA $REGISTRY_IMAGE:$CI_COMMIT_TAG - - docker tag $REGISTRY_IMAGE:$CI_COMMIT_SHORT_SHA $REGISTRY_IMAGE:latest - - docker push $REGISTRY_IMAGE:$CI_COMMIT_TAG - - docker push $REGISTRY_IMAGE:latest - only: - - tags -``` - -### GitHub Actions Example - -Create `.github/workflows/release.yml`: - -```yaml -name: Build and Release - -on: - push: - tags: - - 'v*' - -jobs: - build: - runs-on: ubuntu-latest - permissions: - contents: read - packages: write - - steps: - - uses: actions/checkout@v4 - - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v3 - - - name: Log in to GitHub Container Registry - uses: docker/login-action@v3 - with: - registry: ghcr.io - username: ${{ github.actor }} - password: ${{ secrets.GITHUB_TOKEN }} - - - name: Extract version from tag - id: version - run: echo "VERSION=${GITHUB_REF#refs/tags/v}" >> $GITHUB_OUTPUT - - - name: Build and push - uses: docker/build-push-action@v5 - with: - context: . - platforms: linux/amd64,linux/arm64 - push: true - tags: | - ghcr.io/${{ github.repository }}:${{ steps.version.outputs.VERSION }} - ghcr.io/${{ github.repository }}:latest -``` - -## Verification After Release - -1. **Test pulling image**: -```bash -podman pull ghcr.io/username/towerops-agent:0.1.0 -``` - -2. **Verify image size**: -```bash -podman images towerops-agent -# Should be ~11-12 MB -``` - -3. **Test image runs**: -```bash -podman run --rm ghcr.io/username/towerops-agent:0.1.0 --help -``` - -4. **Update documentation**: - - Update USER_GUIDE.md with new image URL - - Update example docker-compose files - - Update Phoenix UI modal with new image reference - -## Rollback Procedure - -If a release has critical issues: - -1. **Revert 'latest' tag** to previous version: -```bash -# Find previous working version -podman pull ghcr.io/username/towerops-agent:0.0.9 - -# Re-tag as latest -podman tag ghcr.io/username/towerops-agent:0.0.9 ghcr.io/username/towerops-agent:latest - -# Push -podman push ghcr.io/username/towerops-agent:latest -``` - -2. **Notify users**: - - Update release notes with issue details - - Mark release as "yanked" or pre-release - - Provide migration path or workaround - -3. **Fix and re-release**: - - Fix issues in code - - Release as patch version (e.g., 0.1.1) - -## Release Checklist - -Before each release: - -- [ ] All tests passing (`cargo test`) -- [ ] Code formatted (`cargo fmt`) -- [ ] No clippy warnings (`cargo clippy`) -- [ ] Version numbers updated in Cargo.toml, CLAUDE.md -- [ ] CHANGELOG.md updated with release notes -- [ ] Docker images build successfully for both platforms -- [ ] Images tested locally with sample configuration -- [ ] Integration tests pass (if available) -- [ ] Documentation updated -- [ ] Git commit and tag created -- [ ] Images pushed to registry -- [ ] GitHub/GitLab release created with notes -- [ ] Verify images are publicly accessible -- [ ] Notify stakeholders of release - -## Support - -For issues with releases: -- Open an issue on GitHub/GitLab -- Check TROUBLESHOOTING.md in USER_GUIDE -- Review logs from agent: `podman logs ` diff --git a/USER_GUIDE.md b/USER_GUIDE.md deleted file mode 100644 index 8c820f4..0000000 --- a/USER_GUIDE.md +++ /dev/null @@ -1,690 +0,0 @@ -# Towerops Agent - User Guide - -Complete guide for deploying and managing Towerops remote SNMP polling agents. - -## Table of Contents - -- [Overview](#overview) -- [Prerequisites](#prerequisites) -- [Quick Start](#quick-start) -- [Deployment Methods](#deployment-methods) -- [Configuration](#configuration) -- [Network Requirements](#network-requirements) -- [Monitoring & Troubleshooting](#monitoring--troubleshooting) -- [Upgrades & Maintenance](#upgrades--maintenance) - -## Overview - -The Towerops agent is a lightweight Rust application that runs on your network to perform local SNMP polling. It connects to the Towerops API via HTTPS to receive configuration and submit metrics. - -**Benefits**: -- Poll devices behind firewalls without exposing them to the internet -- Reduced latency for SNMP polling -- Automatic failover with 24-hour metric buffering -- Minimal resource footprint (<50 MB RAM, <20 MB disk) - -## Prerequisites - -### System Requirements - -- **CPU**: 1 core (shared acceptable) -- **RAM**: 256 MB minimum, 512 MB recommended -- **Disk**: 1 GB minimum for logs and database -- **Network**: Outbound HTTPS (443) to Towerops API - -### Supported Platforms - -- **Docker/Podman**: Linux (amd64, arm64) -- **Kubernetes**: Deployments supported -- **Bare Metal**: Linux (amd64, arm64) - -### Before You Start - -1. **Create Agent Token** in Towerops UI: - - Navigate to Organization Settings > Agents - - Click "Create New Agent" - - Copy the token (shown only once) - - Save securely (e.g., password manager) - -2. **Assign Equipment** to agent: - - Via Equipment form: Select agent in "Remote Agent" dropdown - - Via Site form: Set site default agent - - Via Organization form: Set organization default agent - -## Quick Start - -### Docker Compose (Recommended) - -1. **Create `docker-compose.yml`**: -```yaml -version: '3.8' - -services: - towerops-agent: - image: registry.gitlab.com/towerops/towerops-agent:latest - container_name: towerops-agent - restart: unless-stopped - - environment: - # Required - TOWEROPS_API_URL: https://app.towerops.com - TOWEROPS_AGENT_TOKEN: "your-agent-token-here" - - # Optional - CONFIG_REFRESH_SECONDS: "300" # 5 minutes - DATABASE_PATH: "/data/towerops-agent.db" - RUST_LOG: "info" - - volumes: - - ./data:/data - - # Allow access to local network for SNMP - network_mode: "host" - - # Health check - healthcheck: - test: ["CMD", "test", "-f", "/data/towerops-agent.db"] - interval: 30s - timeout: 10s - retries: 3 -``` - -2. **Start the agent**: -```bash -docker-compose up -d -``` - -3. **Verify it's running**: -```bash -docker-compose logs -f towerops-agent -``` - -You should see: -``` -INFO towerops_agent: Towerops agent starting -INFO towerops_agent: API URL: https://app.towerops.com -INFO towerops_agent: Refreshing configuration from API -INFO towerops_agent: Configuration updated: 5 equipment items -``` - -## Deployment Methods - -### Method 1: Docker Run - -```bash -docker run -d \ - --name towerops-agent \ - --restart unless-stopped \ - --network host \ - -e TOWEROPS_API_URL=https://app.towerops.com \ - -e TOWEROPS_AGENT_TOKEN="your-token-here" \ - -v ./data:/data \ - registry.gitlab.com/towerops/towerops-agent:latest -``` - -### Method 2: Podman - -```bash -podman run -d \ - --name towerops-agent \ - --restart unless-stopped \ - --network host \ - -e TOWEROPS_API_URL=https://app.towerops.com \ - -e TOWEROPS_AGENT_TOKEN="your-token-here" \ - -v ./data:/data \ - registry.gitlab.com/towerops/towerops-agent:latest -``` - -### Method 3: Kubernetes - -Create `towerops-agent-deployment.yaml`: -```yaml -apiVersion: v1 -kind: Namespace -metadata: - name: towerops - ---- -apiVersion: v1 -kind: Secret -metadata: - name: towerops-agent-token - namespace: towerops -type: Opaque -stringData: - token: "your-agent-token-here" - ---- -apiVersion: v1 -kind: PersistentVolumeClaim -metadata: - name: towerops-agent-data - namespace: towerops -spec: - accessModes: - - ReadWriteOnce - resources: - requests: - storage: 1Gi - ---- -apiVersion: apps/v1 -kind: Deployment -metadata: - name: towerops-agent - namespace: towerops -spec: - replicas: 1 - selector: - matchLabels: - app: towerops-agent - template: - metadata: - labels: - app: towerops-agent - spec: - hostNetwork: true # Required for local SNMP polling - containers: - - name: agent - image: registry.gitlab.com/towerops/towerops-agent:latest - env: - - name: TOWEROPS_API_URL - value: "https://app.towerops.com" - - name: TOWEROPS_AGENT_TOKEN - valueFrom: - secretKeyRef: - name: towerops-agent-token - key: token - - name: RUST_LOG - value: "info" - resources: - requests: - memory: "128Mi" - cpu: "100m" - limits: - memory: "512Mi" - cpu: "500m" - volumeMounts: - - name: data - mountPath: /data - volumes: - - name: data - persistentVolumeClaim: - claimName: towerops-agent-data -``` - -Apply: -```bash -kubectl apply -f towerops-agent-deployment.yaml -``` - -### Method 4: Systemd Service (Bare Metal) - -1. **Download binary**: -```bash -# For amd64 -wget https://github.com/towerops/towerops-agent/releases/latest/download/towerops-agent-linux-amd64 -O /usr/local/bin/towerops-agent - -# For arm64 -wget https://github.com/towerops/towerops-agent/releases/latest/download/towerops-agent-linux-arm64 -O /usr/local/bin/towerops-agent - -chmod +x /usr/local/bin/towerops-agent -``` - -2. **Create service file** `/etc/systemd/system/towerops-agent.service`: -```ini -[Unit] -Description=Towerops Remote SNMP Polling Agent -After=network-online.target -Wants=network-online.target - -[Service] -Type=simple -User=towerops -Group=towerops -Restart=always -RestartSec=10 - -Environment=TOWEROPS_API_URL=https://app.towerops.com -Environment=TOWEROPS_AGENT_TOKEN=your-token-here -Environment=DATABASE_PATH=/var/lib/towerops-agent/towerops-agent.db -Environment=RUST_LOG=info - -ExecStart=/usr/local/bin/towerops-agent \ - --api-url ${TOWEROPS_API_URL} \ - --token ${TOWEROPS_AGENT_TOKEN} \ - --database-path ${DATABASE_PATH} - -[Install] -WantedBy=multi-user.target -``` - -3. **Create user and directories**: -```bash -useradd -r -s /bin/false towerops -mkdir -p /var/lib/towerops-agent -chown towerops:towerops /var/lib/towerops-agent -``` - -4. **Start service**: -```bash -systemctl daemon-reload -systemctl enable towerops-agent -systemctl start towerops-agent -systemctl status towerops-agent -``` - -## Configuration - -### Environment Variables - -| Variable | Required | Default | Description | -|----------|----------|---------|-------------| -| `TOWEROPS_API_URL` | Yes | - | Towerops API endpoint | -| `TOWEROPS_AGENT_TOKEN` | Yes | - | Agent authentication token | -| `CONFIG_REFRESH_SECONDS` | No | 300 | How often to fetch config (5 min) | -| `DATABASE_PATH` | No | `/data/towerops-agent.db` | SQLite database location | -| `RUST_LOG` | No | `info` | Log level: `error`, `warn`, `info`, `debug`, `trace` | - -### Command Line Arguments - -```bash -towerops-agent \ - --api-url https://app.towerops.com \ - --token YOUR_TOKEN_HERE \ - --config-refresh-seconds 300 \ - --database-path /data/towerops-agent.db -``` - -All environment variables can be overridden by command-line arguments. - -### Agent Behavior - -The agent operates on several independent timers: - -- **Config Refresh**: Every 5 minutes (configurable) - - Fetches list of equipment to poll - - Updates sensor and interface configurations - -- **Equipment Polling**: Per-equipment interval (default 60s) - - Each device polls independently - - Respects `check_interval_seconds` from API - -- **Metrics Flush**: Every 30 seconds - - Submits up to 100 pending metrics - - Retries on API failure - -- **Heartbeat**: Every 60 seconds - - Updates agent status in UI - - Includes version, hostname, uptime - -- **Cleanup**: Every hour - - Removes metrics older than 24 hours - - Prevents database growth - -## Network Requirements - -### Firewall Rules - -**Outbound** (from agent): -- `TCP 443` (HTTPS) to Towerops API - - `app.towerops.com` or your self-hosted instance - - Required for: config, metrics, heartbeat - -**Inbound** (to local network): -- `UDP 161` (SNMP) to devices being monitored - - Must reach all equipment assigned to this agent - - No inbound connections to agent itself - -### DNS Requirements - -- Agent must resolve `app.towerops.com` (or your API hostname) -- If using internal DNS, ensure agent has access - -### Proxy Support - -If deploying behind HTTP proxy: - -```bash -# Docker -docker run -d \ - -e HTTP_PROXY=http://proxy.example.com:8080 \ - -e HTTPS_PROXY=http://proxy.example.com:8080 \ - -e NO_PROXY=localhost,127.0.0.1 \ - ... - -# Systemd -Environment=HTTP_PROXY=http://proxy.example.com:8080 -Environment=HTTPS_PROXY=http://proxy.example.com:8080 -``` - -### Network Topology Examples - -**Scenario 1: Single Network** -``` -Internet ← HTTPS → [Towerops Agent] ← UDP 161 → [Network Devices] -``` - -**Scenario 2: DMZ + Internal** -``` -Internet ← HTTPS → [Firewall] → [DMZ: Agent] ← UDP 161 → [Internal Devices] - ↓ - (Allow outbound HTTPS) -``` - -**Scenario 3: Multiple VLANs** -``` -Internet ← HTTPS → [Agent on Management VLAN] - ↓ UDP 161 - [VLAN 10 Devices] - [VLAN 20 Devices] - [VLAN 30 Devices] -``` -*Agent needs routing to all device VLANs* - -## Monitoring & Troubleshooting - -### Health Checks - -**1. Check Agent Status in UI**: -- Navigate to Organization > Agents -- Look for "Last Seen" timestamp (should be <2 minutes) -- Check "Equipment Count" - -**2. Check Container/Service Status**: -```bash -# Docker -docker ps | grep towerops-agent -docker logs towerops-agent - -# Podman -podman ps | grep towerops-agent -podman logs towerops-agent - -# Kubernetes -kubectl get pods -n towerops -kubectl logs -n towerops deployment/towerops-agent - -# Systemd -systemctl status towerops-agent -journalctl -u towerops-agent -f -``` - -**3. Check Database**: -```bash -# View database size (should be <100 MB) -ls -lh /path/to/towerops-agent.db - -# Count pending metrics -sqlite3 /path/to/towerops-agent.db "SELECT COUNT(*) FROM metrics WHERE sent = 0;" -``` - -### Common Issues - -#### Agent Shows Offline - -**Symptom**: "Last Seen" is >5 minutes ago - -**Causes**: -1. Agent container/service stopped -2. Network connectivity to API failed -3. Token was revoked - -**Resolution**: -```bash -# Check if running -docker ps | grep towerops -systemctl status towerops-agent - -# Check logs for errors -docker logs towerops-agent | tail -50 - -# Test API connectivity -curl -H "Authorization: Bearer YOUR_TOKEN" https://app.towerops.com/api/v1/agent/config -``` - -#### No Metrics Appearing - -**Symptom**: Equipment shows no recent data - -**Causes**: -1. Equipment not assigned to agent -2. SNMP community string incorrect -3. Firewall blocking UDP 161 -4. Device not responding to SNMP - -**Resolution**: -```bash -# Check agent config -docker logs towerops-agent | grep "Configuration updated" -# Should show equipment count > 0 - -# Test SNMP manually from agent host -snmpget -v2c -c public DEVICE_IP 1.3.6.1.2.1.1.3.0 - -# Check for SNMP errors in logs -docker logs towerops-agent | grep "SNMP" -``` - -#### High Memory Usage - -**Symptom**: Agent using >512 MB RAM - -**Causes**: -1. Too many devices for one agent -2. Metrics not being sent (database growing) -3. Memory leak (rare) - -**Resolution**: -```bash -# Check database size -docker exec towerops-agent ls -lh /data/towerops-agent.db - -# Check pending metrics -docker exec towerops-agent sqlite3 /data/towerops-agent.db "SELECT COUNT(*) FROM metrics WHERE sent = 0;" - -# If database is large (>100 MB), restart agent (will cleanup old metrics) -docker restart towerops-agent -``` - -#### Metrics Delayed - -**Symptom**: Data appears 5-10 minutes late - -**Causes**: -1. API connectivity issues -2. Database too large -3. Agent overloaded - -**Resolution**: -```bash -# Check for API errors -docker logs towerops-agent | grep "Failed to submit metrics" - -# Check metric submission rate -docker logs towerops-agent | grep "Successfully submitted" - -# Reduce polling frequency in UI if needed -``` - -### Log Levels - -For debugging, increase log verbosity: - -```bash -# Docker/Podman -docker run -e RUST_LOG=debug ... -podman run -e RUST_LOG=debug ... - -# Kubernetes -kubectl set env deployment/towerops-agent RUST_LOG=debug -n towerops - -# Systemd -vi /etc/systemd/system/towerops-agent.service -# Change: Environment=RUST_LOG=debug -systemctl daemon-reload -systemctl restart towerops-agent -``` - -Log levels: -- `error`: Only critical errors -- `warn`: Warnings and errors -- `info`: Normal operation (default) -- `debug`: Verbose debugging -- `trace`: Very verbose (includes SNMP PDUs) - -## Upgrades & Maintenance - -### Upgrading - -**Docker**: -```bash -# Pull latest image -docker pull registry.gitlab.com/towerops/towerops-agent:latest - -# Restart with new image -docker-compose down -docker-compose up -d - -# Or without compose -docker stop towerops-agent -docker rm towerops-agent -docker run -d ... registry.gitlab.com/towerops/towerops-agent:latest -``` - -**Podman**: -```bash -podman pull registry.gitlab.com/towerops/towerops-agent:latest -podman stop towerops-agent -podman rm towerops-agent -podman run -d ... registry.gitlab.com/towerops/towerops-agent:latest -``` - -**Kubernetes**: -```bash -kubectl set image deployment/towerops-agent \ - agent=registry.gitlab.com/towerops/towerops-agent:latest \ - -n towerops -``` - -**Systemd**: -```bash -# Download new binary -wget https://github.com/towerops/towerops-agent/releases/latest/download/towerops-agent-linux-amd64 \ - -O /usr/local/bin/towerops-agent.new - -# Verify and replace -chmod +x /usr/local/bin/towerops-agent.new -mv /usr/local/bin/towerops-agent.new /usr/local/bin/towerops-agent - -# Restart service -systemctl restart towerops-agent -``` - -### Backup & Recovery - -**Backup**: -```bash -# Database only (recommended) -cp /data/towerops-agent.db /backup/towerops-agent-$(date +%Y%m%d).db - -# Or entire data directory -tar czf towerops-agent-backup-$(date +%Y%m%d).tar.gz /data/ -``` - -**Recovery**: -```bash -# Stop agent -docker stop towerops-agent - -# Restore database -cp /backup/towerops-agent-YYYYMMDD.db /data/towerops-agent.db - -# Start agent -docker start towerops-agent -``` - -**Database Corruption**: -If database is corrupted, agent will automatically rebuild it on next start. You'll lose buffered metrics but no configuration. - -### Scaling - -**One Agent, Many Devices**: -- Single agent can handle 100+ devices -- Monitor memory (<512 MB) and database size (<100 MB) -- Adjust poll intervals if needed - -**Multiple Agents**: -- Deploy one agent per site/network -- Assign equipment to appropriate agent via UI -- Each agent operates independently -- No coordination needed between agents - -### Uninstalling - -**Docker**: -```bash -docker-compose down -v # -v removes volumes -docker rmi registry.gitlab.com/towerops/towerops-agent -``` - -**Podman**: -```bash -podman stop towerops-agent -podman rm towerops-agent -podman rmi registry.gitlab.com/towerops/towerops-agent -``` - -**Kubernetes**: -```bash -kubectl delete namespace towerops -``` - -**Systemd**: -```bash -systemctl stop towerops-agent -systemctl disable towerops-agent -rm /etc/systemd/system/towerops-agent.service -rm /usr/local/bin/towerops-agent -rm -rf /var/lib/towerops-agent -userdel towerops -``` - -**In Towerops UI**: -- Navigate to Organization > Agents -- Click "Revoke" on the agent -- Reassign equipment to cloud polling or different agent - -## Best Practices - -1. **One Agent Per Network Segment**: Deploy agents close to devices for minimum latency -2. **Use Descriptive Names**: Name agents by location (e.g., "DC1-Core-Agent", "Branch-NYC-Agent") -3. **Monitor Agent Health**: Check "Last Seen" daily, set up alerts for offline agents -4. **Start Small**: Deploy with 5-10 devices, verify, then scale -5. **Regular Updates**: Update agents quarterly or when security patches released -6. **Backup Tokens**: Store agent tokens securely (password manager, vault) -7. **Log Rotation**: Ensure Docker/systemd logs don't fill disk - -## Security Considerations - -- **Token Security**: Treat agent tokens like passwords, never commit to git -- **Network Isolation**: Agent only needs outbound HTTPS, no inbound -- **Minimal Permissions**: Run as non-root user (Docker image does this) -- **Token Rotation**: Revoke and recreate tokens annually or on compromise -- **HTTPS Only**: Agent always uses TLS for API communication - -## Support - -**Documentation**: -- Main README: `towerops-agent/README.md` -- Architecture: `AGENT_IMPLEMENTATION.md` -- Next Steps: `AGENT_NEXT_STEPS.md` - -**Getting Help**: -- Check logs for error messages -- Review troubleshooting section above -- Contact Towerops support with: - - Agent version (`docker logs towerops-agent | grep version`) - - Error logs (last 50 lines) - - Network diagram - - Number of devices being polled diff --git a/VERSIONING.md b/VERSIONING.md deleted file mode 100644 index 8754ffb..0000000 --- a/VERSIONING.md +++ /dev/null @@ -1,211 +0,0 @@ -# Agent Versioning - -The towerops-agent uses **semantic versioning** (semver) to track releases and enable automatic update detection. - -## Version Format - -Versions follow the format: `MAJOR.MINOR.PATCH` - -- **MAJOR**: Breaking changes (API incompatibility) -- **MINOR**: New features (backwards compatible) -- **PATCH**: Bug fixes (backwards compatible) - -## Current Version - -The version is defined in `Cargo.toml`: - -```toml -[package] -version = "0.1.0" -``` - -This is the **source of truth** for the agent's version. - -## Bumping Versions - -Use the provided script to increment the version: - -```bash -# Patch release (0.1.0 -> 0.1.1) - bug fixes -./scripts/bump-version.sh patch - -# Minor release (0.1.0 -> 0.2.0) - new features -./scripts/bump-version.sh minor - -# Major release (0.1.0 -> 1.0.0) - breaking changes -./scripts/bump-version.sh major -``` - -The script will: -1. ✅ Update `Cargo.toml` with new version -2. ✅ Update `Cargo.lock` -3. ✅ Create git commit -4. ✅ Create git tag (e.g., `v0.1.1`) - -Then push: -```bash -git push origin main -git push origin v0.1.1 # Push the tag -``` - -## CI/CD Pipeline - -When you push to main or push a tag, GitLab CI automatically: - -### On Main Branch Push -- Builds Docker image for `linux/amd64` -- Extracts version from `Cargo.toml` -- Tags image with: - - `:latest` (always) - - `:0.1.0` (version from Cargo.toml) - - `:main-abc123` (commit SHA) -- Pushes to Docker Hub - -### On Git Tag Push (e.g., `v0.1.0`) -- Builds multi-arch Docker image (`linux/amd64`, `linux/arm64`) -- Tags image with: - - `:0.1.0` (extracted from tag) - - `:v0.1.0` (original tag name) - - `:latest` (always) -- Pushes to Docker Hub - -## Version Checking - -The agent checks Docker Hub for newer versions: - -### At Startup -``` -[INFO] Current version: 0.1.0 -[INFO] ✓ Running latest version (0.1.0) -``` - -Or if outdated: -``` -[INFO] Current version: 0.1.0 -[WARN] ⚠️ Newer version available: 0.2.0 (current: 0.1.0) -[WARN] Automatic updates will pull new version every hour -``` - -### Every Hour -The agent checks Docker Hub for newer semver tags and automatically pulls if a newer version is available. - -## How It Works - -1. **Agent queries Docker Hub**: `GET /v2/repositories/gmcintire/towerops-agent/tags?page_size=100` -2. **Filters for semver tags**: Only considers tags matching `X.Y.Z` format -3. **Compares versions**: Uses semver comparison (`0.2.0` > `0.1.0`) -4. **Pulls if newer**: If newer version exists, runs `docker pull gmcintire/towerops-agent:latest` -5. **Restarts**: Exits with code 0, docker-compose/k8s restarts with new image - -## Docker Hub Tags - -After a few releases, you'll see: - -``` -gmcintire/towerops-agent:latest # Always newest -gmcintire/towerops-agent:0.2.0 # Specific version -gmcintire/towerops-agent:0.1.1 # Previous version -gmcintire/towerops-agent:0.1.0 # Original version -gmcintire/towerops-agent:main-abc123 # Commit SHA (transient) -``` - -## Version History - -### 0.1.0 (Initial Release) -- SNMP polling with sensors and interfaces -- Protocol Buffers API communication -- SQLite buffering with 24h retention -- Automatic Docker self-updates -- Health endpoint on port 8080 - -## Best Practices - -### When to Bump - -- **Patch** (0.1.0 → 0.1.1) - - Bug fixes - - Performance improvements - - Documentation updates - - Internal refactoring - -- **Minor** (0.1.0 → 0.2.0) - - New SNMP OID support - - New metric types - - New configuration options - - New features (backwards compatible) - -- **Major** (0.1.0 → 1.0.0) - - Protocol Buffers schema changes (breaking) - - Configuration format changes - - API endpoint changes - - Removal of deprecated features - -### Release Checklist - -Before bumping version: - -- [ ] All tests passing: `cargo test` -- [ ] No clippy warnings: `cargo clippy` -- [ ] Code formatted: `cargo fmt` -- [ ] CHANGELOG.md updated (if exists) -- [ ] Breaking changes documented -- [ ] Migration guide written (for major versions) - -### Rolling Back - -If you need to roll back to a previous version: - -```bash -# Update docker-compose.yml to pin specific version -services: - towerops-agent: - image: gmcintire/towerops-agent:0.1.0 # Pin to specific version -``` - -Or via environment variable: -```bash -AGENT_VERSION=0.1.0 docker-compose up -d -``` - -## Troubleshooting - -### "No valid semver tags found" -- No version tags exist on Docker Hub yet -- Push a version tag: `./scripts/bump-version.sh patch && git push --tags` - -### "Could not check for updates" -- Docker Hub API unreachable -- Network connectivity issue -- Agent continues to run normally - -### Auto-update not working -- Check Docker socket is mounted: `-v /var/run/docker.sock:/var/run/docker.sock` -- Check container has permissions: `docker logs ` -- Verify using `:latest` tag, not pinned version - -### Agent always pulling but not restarting -- `docker pull` succeeds but shows "Image is up to date" -- This is correct behavior - only restarts if new image downloaded -- Agent is already running the latest version - -## Development - -During development, disable auto-updates by running without Docker socket: - -```bash -cargo run -- \ - --api-url http://localhost:4000 \ - --token -``` - -Or run in Docker without socket mount: -```yaml -services: - towerops-agent: - image: gmcintire/towerops-agent:latest - # Don't mount socket during dev - # volumes: - # - /var/run/docker.sock:/var/run/docker.sock -``` - -This prevents auto-updates during development/testing. diff --git a/VERSION_FIX.md b/VERSION_FIX.md deleted file mode 100644 index cc04e0a..0000000 --- a/VERSION_FIX.md +++ /dev/null @@ -1,152 +0,0 @@ -# Agent Version Update Fix - -## Problem - -The agent's version checking wasn't working properly because: - -1. **Cargo.toml** had hardcoded version `0.1.0` -2. **Binary** had `0.1.0` baked in at compile time via `env!("CARGO_PKG_VERSION")` -3. **Docker images** were tagged with Cargo.toml version -4. **Git tags** (for releases) used different versions than Cargo.toml -5. Result: Version mismatch between binary version and actual Docker image tag - -## Solution - -Implemented **dynamic version injection** via `build.rs`: - -### How It Works - -1. **During Build** (`build.rs`): - - Checks if building from a git tag → use tag version (e.g., `v0.2.0` → `0.2.0`) - - Checks commit hash → use Cargo version + hash (e.g., `0.1.0-831588e`) - - Fallback → use Cargo.toml version (`0.1.0`) - - Injects version as `BUILD_VERSION` env var - -2. **In Code** (`version.rs`): - - Uses `BUILD_VERSION` if available - - Falls back to `CARGO_PKG_VERSION` - - Version computed at runtime (not compile-time const) - -### Version Formats - -| Build Context | Version Format | Example | -|---------------|----------------|---------| -| Git tag (release) | `X.Y.Z` (stripped 'v') | `0.2.0` | -| Dev build | `X.Y.Z-HASH` | `0.1.0-831588e` | -| No git | `X.Y.Z` | `0.1.0` | - -### CI/CD Integration - -**For Main Branch** (`.gitlab-ci.yml` line 71): -```bash -VERSION=$(grep '^version = ' Cargo.toml | head -1 | sed 's/version = "\(.*\)"/\1/') -# Tags: gmcintire/towerops-agent:0.1.0, :latest -``` - -**For Git Tags** (`.gitlab-ci.yml` line 104): -```bash -VERSION=${CI_COMMIT_TAG#v} # Strips 'v' prefix -# Tags: gmcintire/towerops-agent:0.2.0, :v0.2.0, :latest -``` - -**Binary Version** (via `build.rs`): -- On tag: Uses git tag → `0.2.0` -- On main: Uses Cargo.toml → `0.1.0` -- Both match their Docker image tags! - -## Testing - -### Local Development -```bash -# Build shows version with commit hash -cargo build --release - -# Binary reports: 0.1.0-831588e -# (if not on a tag) -``` - -### After Git Tag -```bash -# Create tag -git tag v0.2.0 - -# Build -cargo build --release - -# Binary reports: 0.2.0 -# Matches Docker image: gmcintire/towerops-agent:0.2.0 -``` - -### Version Check -```bash -# Run agent (will check Docker Hub on startup) -cargo run -- --api-url http://localhost:4000 --token - -# Logs should show: -# Current version: 0.1.0-831588e -# ✓ Running latest version (or newer available) -``` - -## Deployment Workflow - -### Releasing New Version - -1. **Update Cargo.toml version**: - ```toml - [package] - version = "0.2.0" # <-- Update this - ``` - -2. **Commit and tag**: - ```bash - git add Cargo.toml - git commit -m "chore: bump version to 0.2.0" - git tag v0.2.0 - git push origin main --tags - ``` - -3. **CI automatically**: - - Builds Docker image - - Binary has version `0.2.0` (from git tag) - - Tags image as `:0.2.0` and `:latest` - -4. **Agent detects update**: - - Queries Docker Hub tags - - Finds `0.2.0` > current version - - Pulls new image and restarts - -### Version Bumping Strategy - -Use semantic versioning: -- **Patch** (0.1.0 → 0.1.1): Bug fixes -- **Minor** (0.1.0 → 0.2.0): New features -- **Major** (0.1.0 → 1.0.0): Breaking changes - -Always bump Cargo.toml **before** creating git tag. - -## Files Modified - -1. **`build.rs`** - Added version injection logic -2. **`src/version.rs`** - Changed to use BUILD_VERSION -3. **`.gitlab-ci.yml`** - Already correct (no changes needed) - -## Benefits - -✅ Binary version matches Docker image tag -✅ Auto-updates work correctly -✅ Dev builds show commit hash -✅ Release builds show clean version -✅ No manual version syncing needed - -## Next Steps - -1. **Bump version to 0.2.0** when ready for next release -2. **Create git tag** (`git tag v0.2.0`) -3. **Push tag** → CI builds and publishes -4. **Deployed agents** detect and auto-update - ---- - -**Status**: ✅ Fixed -**Date**: January 16, 2026 -**Issue**: Version checking now works correctly with git-based versioning diff --git a/WATCHTOWER_MIGRATION.md b/WATCHTOWER_MIGRATION.md deleted file mode 100644 index 29f4fa1..0000000 --- a/WATCHTOWER_MIGRATION.md +++ /dev/null @@ -1,409 +0,0 @@ -# Migration to Watchtower Auto-Updates - -## Summary - -Replaced self-update mechanism with **Watchtower** for automatic Docker container updates. This provides a more robust, flexible, and secure update system. - -## What Changed - -### 1. Versioning System ✅ - -**Before**: -- Hardcoded `0.1.0` from `Cargo.toml` -- No commit tracking -- Version mismatch between binary and Docker image - -**After**: -- **Git-based versioning** via `git describe` -- Includes commit count and hash -- Examples: - - `0.2.0` (exact tag) - - `0.2.0.5.831588e` (5 commits after v0.2.0) - - `0.1.0.831588e` (no tags, just commit) - - `0.2.0-modified` (dirty working tree) - -**Implementation**: `build.rs` parses git describe and injects as `BUILD_VERSION` - -### 2. Docker Image Tagging ✅ - -**Before** (main branch): -``` -Tags: latest, 0.1.0, main-831588e -``` - -**After** (main branch): -``` -Tags: - - latest (stable) - - main (for Watchtower tracking) - - 0.1.0.5.831588e (git describe version) - - main-831588e (commit reference) - - main-20260116-143022 (timestamp for rollback) -``` - -**Why**: Multiple tags provide flexibility for different use cases: -- `main` - Watchtower tracks this for auto-updates -- `latest` - Production stable -- Timestamp - Easy rollback to specific build -- Version - Semantic versioning tracking - -### 3. Update Mechanism ✅ - -**Before**: -```rust -// In agent code (src/version.rs) -pub fn perform_self_update() -> Result { - // Agent checks Docker Hub - // Agent pulls new image - // Agent exits to trigger restart -} -``` - -**Issues**: -- Agent needs Docker socket access (security risk) -- Limited to single container -- No notifications -- Fixed check interval -- Complex error handling - -**After**: -```yaml -# docker-compose.yml -services: - watchtower: - image: containrrr/watchtower:latest - environment: - - WATCHTOWER_POLL_INTERVAL=300 - - WATCHTOWER_LABEL_ENABLE=true - - WATCHTOWER_CLEANUP=true - volumes: - - /var/run/docker.sock:/var/run/docker.sock -``` - -**Benefits**: -- ✅ Separate service handles updates -- ✅ Can update multiple containers -- ✅ Built-in notifications (Slack, email, etc.) -- ✅ Flexible scheduling (cron expressions) -- ✅ Better security isolation -- ✅ Industry-standard solution - -### 4. Docker Compose Setup ✅ - -**Before**: -```yaml -services: - towerops-agent: - image: registry.gitlab.com/towerops/towerops-agent:latest - volumes: - - /var/run/docker.sock:/var/run/docker.sock # Agent needs Docker -``` - -**After**: -```yaml -services: - towerops-agent: - image: gmcintire/towerops-agent:main # Track 'main' tag - labels: - - "com.centurylinklabs.watchtower.enable=true" - # No Docker socket needed! - - watchtower: - image: containrrr/watchtower:latest - volumes: - - /var/run/docker.sock:/var/run/docker.sock # Only Watchtower needs it -``` - -## Migration Steps - -### For Existing Deployments - -#### 1. Stop Current Agent -```bash -docker-compose down -``` - -#### 2. Update docker-compose.yml - -Replace `docker-compose.yml` with new version: - -```yaml -version: '3.8' - -services: - towerops-agent: - image: gmcintire/towerops-agent:main - container_name: towerops-agent - restart: unless-stopped - environment: - - TOWEROPS_API_URL=https://app.towerops.com - - TOWEROPS_AGENT_TOKEN=your-token-here - volumes: - - ./data:/data - labels: - - "com.centurylinklabs.watchtower.enable=true" - - "com.centurylinklabs.watchtower.scope=towerops" - - watchtower: - image: containrrr/watchtower:latest - container_name: towerops-watchtower - restart: unless-stopped - environment: - - WATCHTOWER_POLL_INTERVAL=300 - - WATCHTOWER_LABEL_ENABLE=true - - WATCHTOWER_CLEANUP=true - - WATCHTOWER_LOG_LEVEL=info - volumes: - - /var/run/docker.sock:/var/run/docker.sock -``` - -#### 3. Start Services -```bash -docker-compose up -d -``` - -#### 4. Verify - -Check logs: -```bash -# Agent started successfully -docker-compose logs towerops-agent - -# Watchtower is monitoring -docker-compose logs watchtower -``` - -## Code Cleanup - -### Removed from Agent - -Since Watchtower handles updates, these can be **optionally removed** from agent code: - -**`src/version.rs`**: -- `perform_self_update()` function (lines 96-151) -- Docker Hub version checking logic -- Image pulling logic - -**Keep**: -- `check_for_updates()` - Still useful for logging current version -- `current_version()` - Shows git-based version -- `get_latest_version()` - Can log available updates - -**`src/poller/scheduler.rs`**: -- Remove hourly update check task -- Keep heartbeat, polling, cleanup - -**Dependencies** (optional cleanup): -- Keep `ureq` (used for version checking logs) -- Keep all others (needed for agent functionality) - -### Simplified Agent - -With Watchtower, the agent focuses on its core purpose: -- ✅ SNMP polling -- ✅ Metric buffering -- ✅ API communication -- ❌ ~~Self-update logic~~ -- ❌ ~~Docker API interaction~~ -- ❌ ~~Image pulling~~ - -## Rollout Strategy - -### Phase 1: Git Tag Release (v0.2.0) - -```bash -# Update Cargo.toml -version = "0.2.0" - -# Create tag -git tag v0.2.0 -git push --tags - -# CI builds multi-arch images -# Tags: 0.2.0, v0.2.0, latest -``` - -### Phase 2: Update Documentation - -- ✅ `AUTO_UPDATE_SETUP.md` - Complete guide -- ✅ `WATCHTOWER_MIGRATION.md` - This file -- ✅ `docker-compose.example.yml` - With Watchtower -- ✅ `VERSION_FIX.md` - Git-based versioning -- ✅ Updated `.gitlab-ci.yml` - New tagging strategy - -### Phase 3: Customer Communication - -Email existing users: - -``` -Subject: Towerops Agent - Easier Automatic Updates - -We've simplified the agent update process using Watchtower, -an industry-standard Docker update tool. - -What's New: -- More reliable updates -- Update notifications (Slack, email) -- Flexible scheduling -- Easy rollback - -How to Upgrade: -1. Update your docker-compose.yml (see attached) -2. Run: docker-compose up -d -3. Done! Updates are now automatic. - -Learn more: [link to AUTO_UPDATE_SETUP.md] -``` - -### Phase 4: Monitor - -Track adoption: -- ✅ Agent version logs (git describe format) -- ✅ Update frequency (Watchtower logs) -- ✅ Rollback rate (support tickets) - -## Benefits Comparison - -| Feature | Self-Update | Watchtower | Winner | -|---------|-------------|------------|--------| -| **Security** | Agent needs Docker socket | Isolated service | 🏆 Watchtower | -| **Multi-container** | One agent only | All containers | 🏆 Watchtower | -| **Notifications** | None | Slack, email, etc. | 🏆 Watchtower | -| **Scheduling** | Fixed interval | Cron expressions | 🏆 Watchtower | -| **Rollback** | Exit code | Standard Docker | 🏆 Watchtower | -| **Complexity** | Agent code | Config file | 🏆 Watchtower | -| **Testing** | Custom logic | Battle-tested | 🏆 Watchtower | -| **Documentation** | Custom docs | Community docs | 🏆 Watchtower | - -**Result**: Watchtower wins on all counts - -## Testing Checklist - -- [x] Git describe versioning works -- [x] Build.rs injects BUILD_VERSION -- [x] Binary shows correct version -- [x] CI tags images correctly -- [x] Docker Hub receives all tags -- [x] Watchtower config is valid -- [x] Agent runs without Docker socket -- [ ] Watchtower detects updates (needs push to test) -- [ ] Watchtower pulls and restarts agent -- [ ] Rollback to previous version works -- [ ] Notifications work (Slack test) - -## Troubleshooting - -### Issue: Agent Version Shows Old Format - -**Symptom**: Version shows `0.1.0` instead of `0.1.0.831588e` - -**Cause**: Built without git repository - -**Fix**: Build from git repository: -```bash -git clone -cd towerops-agent -cargo build --release -``` - -### Issue: Watchtower Not Updating - -**Symptom**: New image pushed but agent not updating - -**Debug**: -```bash -# Check Watchtower logs -docker logs watchtower - -# Force immediate check -docker kill --signal=SIGUSR1 watchtower - -# Verify image tag -docker pull gmcintire/towerops-agent:main -docker images | grep towerops-agent -``` - -### Issue: Update Loop - -**Symptom**: Agent keeps restarting after update - -**Fix**: -```bash -# Pin to previous version -docker pull gmcintire/towerops-agent:main-20260116-143022 - -# Update compose file -image: gmcintire/towerops-agent:main-20260116-143022 - -# Restart -docker-compose up -d --force-recreate -``` - -## Performance Impact - -| Metric | Before | After | Change | -|--------|--------|-------|--------| -| Agent binary size | 10 MB | 10 MB | Same | -| Memory (agent) | 256 MB | 256 MB | Same | -| Memory (watchtower) | - | 64 MB | +64 MB | -| Update latency | 1 hour | 5 min | -55 min | -| Docker API calls | Every hour | Every 5 min | +11x | - -**Trade-off**: Slight increase in Docker Hub API usage for much faster updates. - -## Security Analysis - -### Before (Self-Update) - -``` -Agent Container -├── SNMP polling code -├── Docker client library -├── /var/run/docker.sock mounted ⚠️ -└── Can: - ├── Pull any image - ├── Start any container - ├── Delete any container - └── Access host system -``` - -**Risk**: Single compromised agent has full Docker control - -### After (Watchtower) - -``` -Agent Container -├── SNMP polling code only -└── No Docker access ✅ - -Watchtower Container (separate) -├── Docker client -├── /var/run/docker.sock mounted ⚠️ -├── Filtered by labels -└── Only updates marked containers -``` - -**Risk**: Reduced attack surface, principle of least privilege - -## Next Steps - -1. **Push to Main** - Trigger CI build with new tags -2. **Test Watchtower** - Verify update detection and execution -3. **Enable Notifications** - Set up Slack webhook -4. **Update Documentation** - README.md, deployment guides -5. **Announce to Users** - Email with migration instructions -6. **Monitor Adoption** - Track version logs -7. **Collect Feedback** - GitHub issues, support tickets - -## Resources - -- **Watchtower**: https://containrrr.dev/watchtower/ -- **Docker Hub**: https://hub.docker.com/r/gmcintire/towerops-agent -- **Setup Guide**: [AUTO_UPDATE_SETUP.md](AUTO_UPDATE_SETUP.md) -- **Version Fix**: [VERSION_FIX.md](VERSION_FIX.md) - ---- - -**Status**: ✅ Complete and ready for deployment -**Date**: January 16, 2026 -**Impact**: Simpler, more secure, more flexible updates for all users diff --git a/docs/plans/2026-01-31-snmp-trap-listener-design.md b/docs/plans/2026-01-31-snmp-trap-listener-design.md deleted file mode 100644 index 2cd2e1b..0000000 --- a/docs/plans/2026-01-31-snmp-trap-listener-design.md +++ /dev/null @@ -1,155 +0,0 @@ -# SNMP Trap Listener Design - -## Overview - -Add SNMP trap listening capability to the towerops-agent. The agent will listen on UDP port 162 for incoming SNMP traps (both v1 and v2c formats) and log them at INFO level. - -## Requirements - -- Support both SNMPv1 and SNMPv2c trap formats -- Listen on UDP port 162 (standard SNMP trap port) -- Log received traps at INFO level -- Configurable log level via `LOG_LEVEL` environment variable -- No API submission or buffering (log only for initial implementation) - -## Architecture - -### New Module: `src/snmp/trap.rs` - -A dedicated trap listener that: -1. Binds a UDP socket to the configured trap port -2. Receives incoming SNMP trap packets -3. Parses both SNMPv1 and SNMPv2c trap PDUs using ASN.1/BER decoding -4. Sends parsed traps through a channel for logging - -### Scheduler Integration - -The trap listener runs as a concurrent task alongside existing polling tasks in the `tokio::select!` loop. It communicates via `tokio::sync::mpsc` channel. - -## Trap PDU Formats - -### SNMPv1 Trap-PDU - -``` -Trap-PDU ::= [4] SEQUENCE { - enterprise OBJECT IDENTIFIER, - agent-addr NetworkAddress, - generic-trap INTEGER (0..6), - specific-trap INTEGER, - time-stamp TimeTicks, - variable-bindings VarBindList -} -``` - -Generic trap types: -- 0: coldStart -- 1: warmStart -- 2: linkDown -- 3: linkUp -- 4: authenticationFailure -- 5: egpNeighborLoss -- 6: enterpriseSpecific - -### SNMPv2c Trap-PDU - -``` -SNMPv2-Trap-PDU ::= [7] SEQUENCE { - request-id INTEGER, - error-status INTEGER, - error-index INTEGER, - variable-bindings VarBindList -} -``` - -The trap OID is in the second varbind (`snmpTrapOID.0 = 1.3.6.1.6.3.1.1.4.1.0`). - -## Data Structures - -```rust -pub enum SnmpVersion { - V1, - V2c, -} - -pub struct SnmpTrap { - pub source_addr: SocketAddr, - pub version: SnmpVersion, - pub community: String, - pub trap_oid: String, // Enterprise OID (v1) or snmpTrapOID (v2c) - pub generic_trap: Option, // v1 only - pub specific_trap: Option, // v1 only - pub uptime: u32, - pub varbinds: Vec<(String, String)>, -} - -pub struct TrapListener { - port: u16, -} -``` - -## CLI Configuration - -New flag: -``` ---trap-port UDP port for SNMP trap listener [default: 162] [env: TRAP_PORT] -``` - -## Environment Variables - -- `LOG_LEVEL` - Controls log verbosity: error, warn, info, debug, trace (default: info) -- `TRAP_PORT` - UDP port for trap listener (default: 162) - -## Log Output Format - -``` -INFO SNMP trap from 192.168.1.1:161 [v1] enterprise=1.3.6.1.4.1.9.9.41 generic=6 specific=1 uptime=12345 varbinds=[1.3.6.1.2.1.2.2.1.1=2, 1.3.6.1.2.1.2.2.1.8=1] - -INFO SNMP trap from 192.168.1.1:161 [v2c] oid=1.3.6.1.6.3.1.1.5.4 uptime=12345 varbinds=[ifIndex.2=2, ifOperStatus.2=1] -``` - -## Docker Compose Configuration - -```yaml -services: - towerops-agent: - image: towerops/agent:latest - environment: - - TOWEROPS_API_URL=http://host.docker.internal:4000 - - TOWEROPS_AGENT_TOKEN=${AGENT_TOKEN} - - LOG_LEVEL=info - - TRAP_PORT=162 - ports: - - "162:162/udp" - volumes: - - ./data:/data -``` - -## Implementation Notes - -### BER Parsing - -Implement minimal BER decoder for: -- Reading TLV (Tag-Length-Value) structures -- Extracting SNMP version from message wrapper -- Parsing INTEGER, OCTET STRING, OBJECT IDENTIFIER, SEQUENCE types -- Converting values to display strings - -### Error Handling - -- Malformed packets: log as warning and skip -- UDP socket errors: log and continue listening -- No crash on invalid data - -### Privileges - -Port 162 requires elevated privileges. In Docker, handled by: -- Container running as root (default), or -- `NET_BIND_SERVICE` capability - -## Files to Create/Modify - -1. **Create** `src/snmp/trap.rs` - Trap listener and BER parser -2. **Modify** `src/snmp/mod.rs` - Export trap module -3. **Modify** `src/main.rs` - Add CLI flag, configure logging with LOG_LEVEL -4. **Modify** `src/poller/scheduler.rs` - Integrate trap listener task -5. **Modify** `docker-compose.example.yml` - Add trap port and LOG_LEVEL