towerops/PROFILES_README.md

6.5 KiB

Device Profiles Implementation Status

Completed

Database Schema

  • Created device_profiles table for storing profile metadata
  • Created profile_device_oids table for device identification OIDs (serial, firmware, etc.)
  • Created profile_sensor_oids table for sensor discovery OIDs (temp, voltage, current, power)
  • Seeded MikroTik profile with all MIB symbolic names

Ecto Schemas

  • Towerops.Profiles.DeviceProfile - Profile schema with associations
  • Towerops.Profiles.DeviceOid - Device identification OID schema
  • Towerops.Profiles.SensorOid - Sensor OID schema with divisor support

Context

  • Towerops.Profiles context for CRUD operations
    • list_profiles/0 - Get all enabled profiles ordered by priority
    • get_profile/1 - Get profile by name with associations
    • match_profile/1 - Match device to profile based on sysDescr/sysObjectID
    • create_profile/1, update_profile/2, delete_profile/1
    • add_device_oid/3, add_sensor_oid/2

Dynamic Profile

  • Towerops.Snmp.Profiles.Dynamic - Runtime profile using database definitions
    • identify_device/3 - Polls device OIDs using MIB translation
    • discover_sensors/2 - Discovers sensors using MIB translation
    • discover_interfaces/2 - Delegates to Base profile

Discovery Integration

  • Updated Towerops.Snmp.Discovery to support database profiles
    • Tries database profiles first via Profiles.match_profile/1
    • Falls back to hardcoded profiles (MikroTik, Cisco, etc.)
    • Handles {:dynamic, profile} tuples for database profiles

Mix Task (Basic Structure)

  • Created Mix.Tasks.ImportProfiles with basic structure
  • Argument parsing (--source-path, --profiles filter)
  • YAML file discovery and reading

Current Status

The core database-driven profile system is fully functional:

  • MikroTik devices will be detected using the database profile
  • Device info (serial, firmware, license) will be polled via MIB translation
  • Sensors (temp, voltage, current, power) will be discovered via MIB translation
  • Profiles can be updated without redeployment

Completed: LibreNMS Import Task

The mix import_profiles task has been implemented and tested successfully with LibreNMS YAML files.

LibreNMS File Structure

LibreNMS splits profile definitions across two files:

  1. resources/definitions/os_detection/{os}.yaml - Detection and metadata

    os: routeros
    text: 'Mikrotik RouterOS'
    discovery:
      - sysObjectID:
        - .1.3.6.1.4.1.14988.1
    
  2. resources/definitions/os_discovery/{os}.yaml - Device info and sensors

    modules:
      os:
        serial: MIKROTIK-MIB::mtxrSerialNumber.0
        version: MIKROTIK-MIB::mtxrLicVersion.0
      sensors:
        temperature:
          data:
            - oid: MIKROTIK-MIB::mtxrGaugeTable
              value: MIKROTIK-MIB::mtxrGaugeValue
              num_oid: '.1.3.6.1.4.1.14988.1.1.3.100.1.3.{{ $index }}'
              descr: MIKROTIK-MIB::mtxrGaugeName
              divisor: 10
    

Implementation Details

  1. import_profile/2 function

    • Reads both os_detection/{name}.yaml and os_discovery/{name}.yaml
    • Extracts detection patterns from os_detection file (sysObjectID)
    • Extracts device OIDs from modules.os section (serial, version, hardware)
    • Extracts sensor OIDs from modules.sensors.{type}.data[] arrays
  2. Sensor handling

    • Only imports scalar sensors (with .0 suffix)
    • Skips table-based sensors with {{ $index }} templates
    • Cleans up template syntax in descriptions
    • Handles divisor values correctly
  3. Supported sensor types

    • temperature, voltage, current, power, fanspeed
    • Other types (dbm, state, count) can be added as needed
  4. Tested with real LibreNMS

    • Successfully imported routeros profile from ~/dev/librenms/resources/definitions/
    • Profile created with correct detection OID and device OIDs
    • Scalar sensors imported (though routeros only has table-based sensors)

Usage

Import profiles from LibreNMS YAML definitions:

# Import all profiles
mix import_profiles --source-path ~/dev/librenms/resources/definitions

# Import specific profiles
mix import_profiles --source-path ~/dev/librenms/resources/definitions --profiles routeros,ios

# Import single profile
mix import_profiles --source-path ~/dev/librenms/resources/definitions --profiles routeros

Note: The task looks for files in:

  • {source-path}/os_detection/{profile}.yaml - Detection patterns
  • {source-path}/os_discovery/{profile}.yaml - Device info and sensors

Current Limitations

  1. Table-based sensors - Only scalar sensors (ending with .0) are imported

    • Table sensors with {{ $index }} templates are skipped
    • This excludes most interface-level sensors (POE ports, optical transceivers, etc.)
  2. Complex templates - Template syntax in descriptions is removed

    • {{ MIKROTIK-MIB::mtxrPOEName }} POE becomes just "POE"
  3. Sensor types - Only common types are imported

    • Supported: temperature, voltage, current, power, fanspeed
    • Not supported: dbm, state, count (can be added as needed)

Next Steps

  1. Add more sensor types - Add dbm, state, count if needed
  2. Web UI for profiles - Build LiveView CRUD for managing profiles
  3. Table sensor support - Implement support for table-based sensors
  4. Import more profiles - Test with Cisco, Ubiquiti, etc.

Testing

To test the current implementation:

# Get the seeded MikroTik profile
profile = Towerops.Profiles.get_profile("mikrotik")

# Check device OIDs
profile.device_oids
# => [
#   %{field: "serial_number", mib_name: "MIKROTIK-MIB::mtxrSerialNumber.0"},
#   %{field: "firmware_version", mib_name: "MIKROTIK-MIB::mtxrFirmwareVersion.0"},
#   ...
# ]

# Check sensor OIDs
profile.sensor_oids
# => [
#   %{sensor_type: "temperature", mib_name: "MIKROTIK-MIB::mtxrHlTemperature.0", divisor: 10},
#   %{sensor_type: "voltage", mib_name: "MIKROTIK-MIB::mtxrHlVoltage.0", divisor: 10},
#   ...
# ]

# Match a device to a profile
system_info = %{
  sys_descr: "RouterOS 7.16.1",
  sys_object_id: ".1.3.6.1.4.1.14988.1"
}
matched = Towerops.Profiles.match_profile(system_info)
# => %DeviceProfile{name: "mikrotik", ...}

Next Steps

  1. Test with real MikroTik device - Verify dynamic profile works end-to-end
  2. Add Web UI - Build LiveView pages for managing profiles
  3. Improve import task - Parse LibreNMS YAML structure correctly
  4. Add more profiles - Cisco, Ubiquiti, etc.