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.
246 lines
7.9 KiB
Markdown
246 lines
7.9 KiB
Markdown
# 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:
|
|
|
|
```bash
|
|
# 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
|
|
|
|
```bash
|
|
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:**
|
|
```json
|
|
{
|
|
"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:**
|
|
```bash
|
|
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/*)
|
|
```yaml
|
|
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/*)
|
|
```yaml
|
|
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
|
|
```bash
|
|
mix export_profiles \
|
|
--librenms-path ~/dev/librenms \
|
|
--profiles epmp,unifi \
|
|
--output production_profiles.json
|
|
```
|
|
|
|
### Import to production
|
|
```bash
|
|
# 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
|
|
```bash
|
|
kubectl logs -n towerops deployment/towerops --tail=100 | grep "Import complete"
|
|
```
|
|
|
|
## Related Files
|
|
|
|
- `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.
|