towerops/PROFILES.md
Graham McIntire 56093bb493
refactor: use API token auth for profile imports instead of session cookies
Changes profile import endpoint to use standard API token authentication:

API Token Changes:
- Add user_id to api_tokens table (tracks who created the token)
- Update ApiTokens.verify_token/1 to return user along with org_id
- Update ApiAuth plug to assign current_user from token

Profile Import Changes:
- Move endpoint from /api/v1/admin/profiles/import to /api/v1/profiles/import
- Check user.is_superuser in controller instead of using RequireSuperuser plug
- Use api_v1 pipeline (Bearer token auth) instead of browser session
- Update documentation to show API token usage

Security:
- Only API tokens created by superusers can import profiles
- Returns 403 Forbidden if token user is not a superuser
- Logs import attempts with user email for audit trail

This provides a consistent API experience using Bearer tokens
instead of requiring browser session cookies.
2026-01-18 09:30:21 -06:00

7.9 KiB

Device Profile Management

This document describes how to manage SNMP device profiles in Towerops. Device profiles define how to discover and monitor different types of network equipment via SNMP.

Overview

Towerops uses a database-driven profile system that supports 671+ device types dynamically without code changes. Profiles are imported from external YAML definitions and stored in the database.

Architecture

Profile Discovery Flow:

  1. Device performs SNMP discovery
  2. System reads sysDescr and sysObjectID from device
  3. Matches against detection rules in database
  4. Uses matched profile to discover sensors, CPU, memory, etc.
  5. Saves discovered data for monitoring and graphing

Profile Components:

  • Detection Rules: sysObjectID prefix matching, sysDescr regex patterns
  • Sensor Definitions: Temperature, voltage, current, power, fan speed, state sensors
  • Processor Definitions: CPU usage monitoring (converted to percent sensors)
  • Memory Pool Definitions: Memory usage monitoring
  • OS Definitions: Firmware version, serial number, location data

Exporting Profiles Locally

Use the mix export_profiles task to export profiles from an external source to JSON format:

# Export all profiles
mix export_profiles --librenms-path ~/dev/librenms --output profiles.json

# Export specific profiles only
mix export_profiles --librenms-path ~/dev/librenms --profiles epmp,unifi,airos-af --output profiles.json

Options:

  • --librenms-path PATH - Path to external source installation (required)
  • --output PATH - Output JSON file path (default: profiles.json)
  • --profiles LIST - Comma-separated list of specific profiles to export (optional)

Output: The task generates a JSON file containing all profile data (detection rules, sensor definitions, etc.) suitable for uploading to production.

Importing Profiles to Production

Requirements:

  • Superuser account (user with is_superuser = true)
  • API token created by superuser account

Step 1: Create Superuser API Token

  1. Log in to Towerops as a superuser
  2. Navigate to your organization settings
  3. Create a new API token
  4. Copy the token (shown only once) - it will start with towerops_

Note: Only API tokens created by superuser accounts can import device profiles.

Step 2: Upload Profiles

curl -X POST https://towerops.net/api/v1/profiles/import \
  -H "Authorization: Bearer YOUR_SUPERUSER_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d @profiles.json

Response:

{
  "status": "queued",
  "job_id": "uuid",
  "profile_count": 15,
  "message": "Import job queued successfully. 15 profiles will be imported in the background."
}

Step 3: Monitor Import Progress

The import runs as a background job in the maintenance queue. Monitor progress via:

  1. Server logs:

    kubectl logs -n towerops deployment/towerops | grep "profile import"
    
  2. Exq dashboard: Navigate to /dashboard and check the Maintenance queue

Log messages:

  • Starting profile import job <job_id> with N profiles - Job started
  • [<job_id>] Successfully imported profile: <os> - Profile imported
  • [<job_id>] Failed to import profile <os>: <reason> - Import error
  • [<job_id>] Import complete: N succeeded, M failed - Job finished

Profile Structure

Detection YAML (os_detection/*)

os: epmp
text: Cambium epmp
type: wireless
group: cambium
icon: cambium
discovery:
  - sysObjectID:
      - ".1.3.6.1.4.1.17713.21"

Discovery YAML (os_discovery/*)

mib: CAMBIUM-PMP80211-MIB
modules:
  os:
    version: CAMBIUM-PMP80211-MIB::cambiumCurrentuImageVersion.0
    serial: CAMBIUM-PMP80211-MIB::cambiumEPMPMSN.0

  processors:
    data:
      - oid: sysCPUUsage
        num_oid: ".1.3.6.1.4.1.17713.21.2.1.64.{{ $index }}"
        type: cambium-cpu
        precision: 10

  sensors:
    temperature:
      data:
        - oid: boardTemp
          num_oid: ".1.3.6.1.4.1.17713.21.1.2.1.0"
          descr: Board Temperature
          precision: 10

Database Schema

device_profiles - Main profile table

  • os - Operating system identifier (e.g., "epmp", "unifi")
  • text - Display name (e.g., "Cambium epmp")
  • type - Device type (wireless, switch, router, etc.)
  • group - Manufacturer group (cambium, ubiquiti, cisco, etc.)
  • priority - Matching priority (lower = higher priority)
  • enabled - Whether profile is active

profile_detection_rules - Device detection patterns

  • rule_type - "sysObjectID", "sysDescr", "sysDescr_regex"
  • pattern - OID prefix or regex pattern
  • value - Exact match value

profile_sensor_definitions - Sensor discovery definitions

  • sensor_class - temperature, voltage, current, power, fanspeed, humidity, dbm, snr, percent, count, frequency, state
  • oid - Symbolic OID name
  • num_oid - Numeric OID (e.g., ".1.3.6.1.4.1.17713.21.2.1.36.{{ $index }}")
  • descr - Sensor description
  • divisor - Value divisor for unit conversion
  • precision - Number of decimal places (stored in divisor field)

profile_processor_definitions - CPU discovery definitions

  • oid - Symbolic OID name
  • num_oid - Numeric OID
  • precision - Divisor for CPU percentage (e.g., 10 means divide by 10)
  • type - Processor type identifier

Force Replacement

All profile imports use force replacement - existing profiles with the same os name are deleted before importing. This ensures clean updates without conflicts.

Troubleshooting

Import fails immediately:

  • Check you're logged in as a superuser (is_superuser = true)
  • Verify session cookie is correct and not expired
  • Check JSON format is valid: jq . profiles.json

Profiles import but discovery doesn't work:

  • Check profile detection rules match device sysObjectID/sysDescr
  • Verify sensor OIDs are numeric (not symbolic MIB names)
  • Check logs for SNMP walk errors
  • Test SNMP manually: snmpwalk -v2c -c public <ip> <oid>

Sensor indices conflict:

  • Sensor indices must be unique per device
  • Scalar sensors (index .0) use descriptive names (e.g., "dfs_detected_count")
  • Table sensors use class prefix (e.g., "temperature_1", "voltage_2")

CPU not showing:

  • Processor definitions are converted to "percent" type sensors
  • Check divisor/precision is correct (usually 10 or 100)
  • Verify num_oid is accessible via SNMP

Examples

Export ePMP and UniFi profiles

mix export_profiles \
  --librenms-path ~/dev/librenms \
  --profiles epmp,unifi \
  --output production_profiles.json

Import to production

# Use your superuser API token
SUPERUSER_TOKEN="towerops_abc123..."

curl -X POST https://towerops.net/api/v1/profiles/import \
  -H "Authorization: Bearer ${SUPERUSER_TOKEN}" \
  -H "Content-Type: application/json" \
  -d @production_profiles.json

Check import status

kubectl logs -n towerops deployment/towerops --tail=100 | grep "Import complete"
  • lib/mix/tasks/export_profiles.ex - Export task
  • lib/mix/tasks/import_profiles.ex - Local import task (for development)
  • lib/towerops/device_profiles/importer.ex - Profile import logic
  • lib/towerops/snmp/profiles/dynamic.ex - Dynamic profile discovery engine
  • lib/towerops/workers/profile_import_worker.ex - Background import worker
  • lib/towerops_web/controllers/api/v1/profiles_controller.ex - API endpoint
  • lib/towerops_web/plugs/require_superuser.ex - Superuser authorization

Security

  • Profile import requires superuser API token
  • Only tokens created by superusers can import profiles
  • User who created the token must still be a superuser
  • Runs in background to prevent timeouts
  • Validates profile data before importing
  • Logs all import operations with user email

Supported Profile Count

As of January 2026, the system supports 671+ device profiles including:

  • Cambium ePMP, PMP, cnPilot
  • Ubiquiti AirFiber, airMAX, UniFi
  • Cisco IOS, IOS-XE, NX-OS
  • MikroTik RouterOS
  • Juniper JunOS
  • And many more...

New profiles can be added without code changes by exporting and importing.