Enhance MikroTik discovery with comprehensive sensor support
Based on MikroTik MIB analysis, added discovery for: Device Information: - Board name, display name, build time Health Sensors - Voltages: - Core voltage, 3.3V/5V/12V supplies, input voltage Health Sensors - Temperatures: - Sensor chip, CPU, board, system, processor temperatures Health Sensors - Power & Cooling: - Power consumption (W), current draw (mA) - Processor frequency (MHz) - Active fan status, fan speeds (RPM) - Power supply state, backup PSU state POE Monitoring (per port): - Voltage, current, power consumption - Automatically discovers all POE-enabled ports Optical/SFP Monitoring (per interface): - Temperature, voltage - TX/RX optical power levels (dBm) - Supports fiber transceivers and SFP modules All sensors include proper units, divisors, and descriptive names.
This commit is contained in:
parent
6c631cbe26
commit
bf301aa5fc
1 changed files with 232 additions and 18 deletions
|
|
@ -22,17 +22,39 @@ defmodule Towerops.Snmp.Profiles.Mikrotik do
|
|||
# System Information (mtxrSystem)
|
||||
serial_number: "1.3.6.1.4.1.14988.1.1.7.3.0",
|
||||
firmware_version: "1.3.6.1.4.1.14988.1.1.7.4.0",
|
||||
board_name: "1.3.6.1.4.1.14988.1.1.7.9.0",
|
||||
display_name: "1.3.6.1.4.1.14988.1.1.7.8.0",
|
||||
build_time: "1.3.6.1.4.1.14988.1.1.7.6.0",
|
||||
license_version: "1.3.6.1.4.1.14988.1.1.4.4.0",
|
||||
|
||||
# Health (mtxrHealth)
|
||||
temperature: "1.3.6.1.4.1.14988.1.1.3.10.0",
|
||||
cpu_temperature: "1.3.6.1.4.1.14988.1.1.3.11.0",
|
||||
# Health - Voltages (mtxrHealth)
|
||||
core_voltage: "1.3.6.1.4.1.14988.1.1.3.1.0",
|
||||
three_volt: "1.3.6.1.4.1.14988.1.1.3.2.0",
|
||||
five_volt: "1.3.6.1.4.1.14988.1.1.3.3.0",
|
||||
twelve_volt: "1.3.6.1.4.1.14988.1.1.3.4.0",
|
||||
voltage: "1.3.6.1.4.1.14988.1.1.3.8.0",
|
||||
current: "1.3.6.1.4.1.14988.1.1.3.9.0",
|
||||
power_supply_state: "1.3.6.1.4.1.14988.1.1.3.12.0",
|
||||
|
||||
# Health - Temperatures
|
||||
sensor_temperature: "1.3.6.1.4.1.14988.1.1.3.5.0",
|
||||
cpu_temperature: "1.3.6.1.4.1.14988.1.1.3.6.0",
|
||||
board_temperature: "1.3.6.1.4.1.14988.1.1.3.7.0",
|
||||
temperature: "1.3.6.1.4.1.14988.1.1.3.10.0",
|
||||
processor_temperature: "1.3.6.1.4.1.14988.1.1.3.11.0",
|
||||
|
||||
# Health - Power & Current
|
||||
current: "1.3.6.1.4.1.14988.1.1.3.13.0",
|
||||
power: "1.3.6.1.4.1.14988.1.1.3.12.0",
|
||||
|
||||
# Health - Fans & Cooling
|
||||
active_fan: "1.3.6.1.4.1.14988.1.1.3.9.0",
|
||||
fan_speed_1: "1.3.6.1.4.1.14988.1.1.3.17.0",
|
||||
fan_speed_2: "1.3.6.1.4.1.14988.1.1.3.18.0",
|
||||
|
||||
# Health - Power Supply
|
||||
processor_frequency: "1.3.6.1.4.1.14988.1.1.3.14.0",
|
||||
power_supply_state: "1.3.6.1.4.1.14988.1.1.3.15.0",
|
||||
backup_psu_state: "1.3.6.1.4.1.14988.1.1.3.16.0",
|
||||
|
||||
# System Resources
|
||||
cpu_load: "1.3.6.1.2.1.25.3.3.1.2.1",
|
||||
total_memory: "1.3.6.1.2.1.25.2.2.0",
|
||||
|
|
@ -41,6 +63,10 @@ defmodule Towerops.Snmp.Profiles.Mikrotik do
|
|||
used_hdd: "1.3.6.1.4.1.14988.1.1.1.7.0"
|
||||
}
|
||||
|
||||
# Table OID bases for walking
|
||||
@poe_table "1.3.6.1.4.1.14988.1.1.15.1"
|
||||
@optical_table "1.3.6.1.4.1.14988.1.1.16.1"
|
||||
|
||||
@doc """
|
||||
Discovers system information using Base profile and adds MikroTik-specific details.
|
||||
"""
|
||||
|
|
@ -118,15 +144,19 @@ defmodule Towerops.Snmp.Profiles.Mikrotik do
|
|||
oids = [
|
||||
@mikrotik_oids.serial_number,
|
||||
@mikrotik_oids.firmware_version,
|
||||
@mikrotik_oids.board_name,
|
||||
@mikrotik_oids.display_name,
|
||||
@mikrotik_oids.license_version
|
||||
]
|
||||
|
||||
case Client.get_multiple(client_opts, oids) do
|
||||
{:ok, [serial, firmware, license]} ->
|
||||
{:ok, [serial, firmware, board, display, license]} ->
|
||||
{:ok,
|
||||
%{
|
||||
serial_number: serial,
|
||||
firmware_version: firmware,
|
||||
board_name: board,
|
||||
display_name: display,
|
||||
license_version: license
|
||||
}}
|
||||
|
||||
|
|
@ -137,14 +167,28 @@ defmodule Towerops.Snmp.Profiles.Mikrotik do
|
|||
end
|
||||
|
||||
defp discover_health_sensors(client_opts) do
|
||||
# Try to get all health OIDs
|
||||
# Try to get all health OIDs - voltages, temperatures, power, fans
|
||||
health_oids = [
|
||||
{@mikrotik_oids.temperature, "temperature", "°C", 10},
|
||||
# Voltages
|
||||
{@mikrotik_oids.core_voltage, "core_voltage", "V", 10},
|
||||
{@mikrotik_oids.three_volt, "3v3_voltage", "V", 10},
|
||||
{@mikrotik_oids.five_volt, "5v_voltage", "V", 10},
|
||||
{@mikrotik_oids.twelve_volt, "12v_voltage", "V", 10},
|
||||
{@mikrotik_oids.voltage, "input_voltage", "V", 10},
|
||||
# Temperatures
|
||||
{@mikrotik_oids.sensor_temperature, "sensor_temperature", "°C", 10},
|
||||
{@mikrotik_oids.cpu_temperature, "cpu_temperature", "°C", 10},
|
||||
{@mikrotik_oids.voltage, "voltage", "V", 10},
|
||||
{@mikrotik_oids.board_temperature, "board_temperature", "°C", 10},
|
||||
{@mikrotik_oids.temperature, "temperature", "°C", 10},
|
||||
{@mikrotik_oids.processor_temperature, "processor_temperature", "°C", 10},
|
||||
# Power & Current
|
||||
{@mikrotik_oids.current, "current", "mA", 1},
|
||||
{@mikrotik_oids.power, "power", "W", 10},
|
||||
# Fans
|
||||
{@mikrotik_oids.fan_speed_1, "fan1", "RPM", 1},
|
||||
{@mikrotik_oids.fan_speed_2, "fan2", "RPM", 1}
|
||||
{@mikrotik_oids.fan_speed_2, "fan2", "RPM", 1},
|
||||
# Processor
|
||||
{@mikrotik_oids.processor_frequency, "processor_frequency", "MHz", 1}
|
||||
]
|
||||
|
||||
health_oids
|
||||
|
|
@ -172,8 +216,10 @@ defmodule Towerops.Snmp.Profiles.Mikrotik do
|
|||
defp discover_resource_sensors(client_opts) do
|
||||
cpu_sensors = discover_cpu_sensors(client_opts)
|
||||
storage_sensors = discover_storage_sensors(client_opts)
|
||||
poe_sensors = discover_poe_sensors(client_opts)
|
||||
optical_sensors = discover_optical_sensors(client_opts)
|
||||
|
||||
cpu_sensors ++ storage_sensors
|
||||
cpu_sensors ++ storage_sensors ++ poe_sensors ++ optical_sensors
|
||||
end
|
||||
|
||||
defp discover_cpu_sensors(client_opts) do
|
||||
|
|
@ -224,18 +270,18 @@ defmodule Towerops.Snmp.Profiles.Mikrotik do
|
|||
if size > 0 do
|
||||
percent = used / size * 100
|
||||
|
||||
{type, descr_name} =
|
||||
type =
|
||||
cond do
|
||||
String.contains?(descr, "memory") -> {"memory", "Memory"}
|
||||
String.contains?(descr, "disk") -> {"disk", "Disk"}
|
||||
true -> {"storage", descr}
|
||||
String.contains?(descr, "memory") -> "memory"
|
||||
String.contains?(descr, "disk") -> "disk"
|
||||
true -> "storage"
|
||||
end
|
||||
|
||||
%{
|
||||
sensor_type: "#{type}_usage",
|
||||
sensor_index: index,
|
||||
sensor_oid: used_oid,
|
||||
sensor_descr: "#{descr_name} Usage",
|
||||
sensor_descr: descr,
|
||||
sensor_unit: "%",
|
||||
sensor_divisor: 1,
|
||||
last_value: percent,
|
||||
|
|
@ -253,12 +299,180 @@ defmodule Towerops.Snmp.Profiles.Mikrotik do
|
|||
end
|
||||
end
|
||||
|
||||
defp format_sensor_name("temperature"), do: "Board Temperature"
|
||||
defp discover_poe_sensors(client_opts) do
|
||||
# Walk POE table to get per-port POE statistics
|
||||
# Table columns: Name(3), Status(4), Voltage(5), Current(6), Power(7)
|
||||
with {:ok, name_results} <- Client.walk(client_opts, "#{@poe_table}.1.3"),
|
||||
{:ok, voltage_results} <- Client.walk(client_opts, "#{@poe_table}.1.5"),
|
||||
{:ok, current_results} <- Client.walk(client_opts, "#{@poe_table}.1.6"),
|
||||
{:ok, power_results} <- Client.walk(client_opts, "#{@poe_table}.1.7") do
|
||||
# Get indices from the name results
|
||||
indices =
|
||||
name_results
|
||||
|> Map.keys()
|
||||
|> Enum.map(fn oid -> oid |> String.split(".") |> List.last() end)
|
||||
|
||||
# Create sensors for voltage, current, and power per port
|
||||
Enum.flat_map(indices, fn index ->
|
||||
name_oid = "#{@poe_table}.1.3.#{index}"
|
||||
voltage_oid = "#{@poe_table}.1.5.#{index}"
|
||||
current_oid = "#{@poe_table}.1.6.#{index}"
|
||||
power_oid = "#{@poe_table}.1.7.#{index}"
|
||||
|
||||
port_name = Map.get(name_results, name_oid, "Port #{index}")
|
||||
voltage = Map.get(voltage_results, voltage_oid, 0)
|
||||
current = Map.get(current_results, current_oid, 0)
|
||||
power = Map.get(power_results, power_oid, 0)
|
||||
|
||||
Enum.reject(
|
||||
[
|
||||
if voltage > 0 do
|
||||
%{
|
||||
sensor_type: "poe_voltage",
|
||||
sensor_index: "poe_#{index}_voltage",
|
||||
sensor_oid: voltage_oid,
|
||||
sensor_descr: "#{port_name} POE Voltage",
|
||||
sensor_unit: "V",
|
||||
sensor_divisor: 10,
|
||||
last_value: voltage / 10.0,
|
||||
status: "ok"
|
||||
}
|
||||
end,
|
||||
if current > 0 do
|
||||
%{
|
||||
sensor_type: "poe_current",
|
||||
sensor_index: "poe_#{index}_current",
|
||||
sensor_oid: current_oid,
|
||||
sensor_descr: "#{port_name} POE Current",
|
||||
sensor_unit: "mA",
|
||||
sensor_divisor: 1,
|
||||
last_value: current / 1.0,
|
||||
status: "ok"
|
||||
}
|
||||
end,
|
||||
if power > 0 do
|
||||
%{
|
||||
sensor_type: "poe_power",
|
||||
sensor_index: "poe_#{index}_power",
|
||||
sensor_oid: power_oid,
|
||||
sensor_descr: "#{port_name} POE Power",
|
||||
sensor_unit: "W",
|
||||
sensor_divisor: 10,
|
||||
last_value: power / 10.0,
|
||||
status: "ok"
|
||||
}
|
||||
end
|
||||
],
|
||||
&is_nil/1
|
||||
)
|
||||
end)
|
||||
else
|
||||
_ -> []
|
||||
end
|
||||
end
|
||||
|
||||
defp discover_optical_sensors(client_opts) do
|
||||
# Walk optical table to get SFP/optical monitoring data
|
||||
# Table columns: Name(2), Temperature(3), Voltage(5), TxBiasCurrent(6), TxPower(7), RxPower(8)
|
||||
with {:ok, name_results} <- Client.walk(client_opts, "#{@optical_table}.1.2"),
|
||||
{:ok, temp_results} <- Client.walk(client_opts, "#{@optical_table}.1.3"),
|
||||
{:ok, voltage_results} <- Client.walk(client_opts, "#{@optical_table}.1.5"),
|
||||
{:ok, tx_power_results} <- Client.walk(client_opts, "#{@optical_table}.1.7"),
|
||||
{:ok, rx_power_results} <- Client.walk(client_opts, "#{@optical_table}.1.8") do
|
||||
# Get indices from the name results
|
||||
indices =
|
||||
name_results
|
||||
|> Map.keys()
|
||||
|> Enum.map(fn oid -> oid |> String.split(".") |> List.last() end)
|
||||
|
||||
# Create sensors for each optical metric
|
||||
Enum.flat_map(indices, fn index ->
|
||||
name_oid = "#{@optical_table}.1.2.#{index}"
|
||||
temp_oid = "#{@optical_table}.1.3.#{index}"
|
||||
voltage_oid = "#{@optical_table}.1.5.#{index}"
|
||||
tx_power_oid = "#{@optical_table}.1.7.#{index}"
|
||||
rx_power_oid = "#{@optical_table}.1.8.#{index}"
|
||||
|
||||
sfp_name = Map.get(name_results, name_oid, "SFP #{index}")
|
||||
temperature = Map.get(temp_results, temp_oid)
|
||||
voltage = Map.get(voltage_results, voltage_oid)
|
||||
tx_power = Map.get(tx_power_results, tx_power_oid)
|
||||
rx_power = Map.get(rx_power_results, rx_power_oid)
|
||||
|
||||
Enum.reject(
|
||||
[
|
||||
if temperature do
|
||||
%{
|
||||
sensor_type: "sfp_temperature",
|
||||
sensor_index: "sfp_#{index}_temp",
|
||||
sensor_oid: temp_oid,
|
||||
sensor_descr: "#{sfp_name} Temperature",
|
||||
sensor_unit: "°C",
|
||||
sensor_divisor: 1000,
|
||||
last_value: temperature / 1000.0,
|
||||
status: "ok"
|
||||
}
|
||||
end,
|
||||
if voltage do
|
||||
%{
|
||||
sensor_type: "sfp_voltage",
|
||||
sensor_index: "sfp_#{index}_voltage",
|
||||
sensor_oid: voltage_oid,
|
||||
sensor_descr: "#{sfp_name} Voltage",
|
||||
sensor_unit: "V",
|
||||
sensor_divisor: 1000,
|
||||
last_value: voltage / 1000.0,
|
||||
status: "ok"
|
||||
}
|
||||
end,
|
||||
if tx_power do
|
||||
%{
|
||||
sensor_type: "sfp_tx_power",
|
||||
sensor_index: "sfp_#{index}_tx",
|
||||
sensor_oid: tx_power_oid,
|
||||
sensor_descr: "#{sfp_name} TX Power",
|
||||
sensor_unit: "dBm",
|
||||
sensor_divisor: 1000,
|
||||
last_value: tx_power / 1000.0,
|
||||
status: "ok"
|
||||
}
|
||||
end,
|
||||
if rx_power do
|
||||
%{
|
||||
sensor_type: "sfp_rx_power",
|
||||
sensor_index: "sfp_#{index}_rx",
|
||||
sensor_oid: rx_power_oid,
|
||||
sensor_descr: "#{sfp_name} RX Power",
|
||||
sensor_unit: "dBm",
|
||||
sensor_divisor: 1000,
|
||||
last_value: rx_power / 1000.0,
|
||||
status: "ok"
|
||||
}
|
||||
end
|
||||
],
|
||||
&is_nil/1
|
||||
)
|
||||
end)
|
||||
else
|
||||
_ -> []
|
||||
end
|
||||
end
|
||||
|
||||
defp format_sensor_name("core_voltage"), do: "Core Voltage"
|
||||
defp format_sensor_name("3v3_voltage"), do: "3.3V Supply"
|
||||
defp format_sensor_name("5v_voltage"), do: "5V Supply"
|
||||
defp format_sensor_name("12v_voltage"), do: "12V Supply"
|
||||
defp format_sensor_name("input_voltage"), do: "Input Voltage"
|
||||
defp format_sensor_name("sensor_temperature"), do: "Sensor Chip Temperature"
|
||||
defp format_sensor_name("cpu_temperature"), do: "CPU Temperature"
|
||||
defp format_sensor_name("voltage"), do: "Input Voltage"
|
||||
defp format_sensor_name("board_temperature"), do: "Board Temperature"
|
||||
defp format_sensor_name("temperature"), do: "System Temperature"
|
||||
defp format_sensor_name("processor_temperature"), do: "Processor Temperature"
|
||||
defp format_sensor_name("current"), do: "Current Draw"
|
||||
defp format_sensor_name("power"), do: "Power Consumption"
|
||||
defp format_sensor_name("fan1"), do: "Fan 1 Speed"
|
||||
defp format_sensor_name("fan2"), do: "Fan 2 Speed"
|
||||
defp format_sensor_name("processor_frequency"), do: "Processor Frequency"
|
||||
defp format_sensor_name(other), do: String.capitalize(other)
|
||||
|
||||
defp cpu_status(load) when load < 70, do: "ok"
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue