show correct agent on edit screen and fix airfiber/ltu

This commit is contained in:
Graham McIntire 2026-01-27 12:52:43 -06:00
parent b9d01248d4
commit 328d4659a7
No known key found for this signature in database
4 changed files with 149 additions and 11 deletions

View file

@ -2,17 +2,19 @@ defmodule Towerops.Snmp.Profiles.Vendors.Airfiber do
@moduledoc """
Ubiquiti AirFiber device-specific SNMP handling.
Supports AirFiber 5, 5X, 5XHD, 24, 24HD, and 60 series.
Supports AirFiber 5, 5X, 5XHD, 24, 24HD, 60 series, and LTU series.
Supported devices:
- AirFiber 5/5X/5XHD
- AirFiber 24/24HD
- AirFiber 60/60 LR
- AirFiber 60 XG
- AirFiber LTU (LTU Rocket, LTU-PRO, etc.)
"""
@behaviour Towerops.Snmp.Profiles.Vendors.Vendor
alias Towerops.Snmp.Client
alias Towerops.Snmp.Profiles.Vendors.Vendor
@impl true
@ -28,13 +30,27 @@ defmodule Towerops.Snmp.Profiles.Vendors.Airfiber do
@impl true
def discover_wireless_sensors(client_opts) do
Vendor.fetch_sensors(wireless_oid_defs(), client_opts)
# Detect if this is an LTU device by checking for LTU-specific OID
case Client.get(client_opts, "1.3.6.1.4.1.41112.1.10.1.2.2.0") do
{:ok, _frequency} ->
# LTU device detected - use AFLTU MIB OIDs
Vendor.fetch_sensors(ltu_wireless_oid_defs(), client_opts)
{:error, _} ->
# Regular AirFiber device - use AirFIBER MIB OIDs
Vendor.fetch_sensors(airfiber_wireless_oid_defs(), client_opts)
end
end
@impl true
def wireless_oid_defs do
# UBNT-AirFIBER-MIB OIDs
# Enterprise OID: 1.3.6.1.4.1.41112.1.3
# Default to regular AirFiber OIDs for backward compatibility
airfiber_wireless_oid_defs()
end
# UBNT-AirFIBER-MIB OIDs for regular AirFiber devices
# Enterprise OID: 1.3.6.1.4.1.41112.1.3
defp airfiber_wireless_oid_defs do
[
# TX Frequency (MHz)
%{
@ -94,4 +110,59 @@ defmodule Towerops.Snmp.Profiles.Vendors.Airfiber do
}
]
end
# UBNT-AFLTU-MIB OIDs for AirFiber LTU devices
# Enterprise OID: 1.3.6.1.4.1.41112.1.10
defp ltu_wireless_oid_defs do
[
# Frequency (MHz) - Configuration value
%{
oid: "1.3.6.1.4.1.41112.1.10.1.2.2.0",
sensor_type: "frequency",
sensor_descr: "Frequency",
sensor_unit: "MHz",
sensor_divisor: 1
},
# TX Power (dBm EIRP)
%{
oid: "1.3.6.1.4.1.41112.1.10.1.2.6.0",
sensor_type: "power",
sensor_descr: "Tx EIRP",
sensor_unit: "dBm",
sensor_divisor: 1
},
# Station RX Power Chain 0 (dBm) - uses station table index 1
%{
oid: "1.3.6.1.4.1.41112.1.10.1.4.1.5.1",
sensor_type: "rssi",
sensor_descr: "Rx Power Chain 0",
sensor_unit: "dBm",
sensor_divisor: 1
},
# Station RX Power Chain 1 (dBm) - uses station table index 1
%{
oid: "1.3.6.1.4.1.41112.1.10.1.4.1.6.1",
sensor_type: "rssi",
sensor_descr: "Rx Power Chain 1",
sensor_unit: "dBm",
sensor_divisor: 1
},
# Station TX Capacity (Kbps) - convert to Mbps by dividing by 1000
%{
oid: "1.3.6.1.4.1.41112.1.10.1.4.1.3.1",
sensor_type: "rate",
sensor_descr: "Tx Capacity",
sensor_unit: "Mbps",
sensor_divisor: 1000
},
# Station RX Capacity (Kbps) - convert to Mbps by dividing by 1000
%{
oid: "1.3.6.1.4.1.41112.1.10.1.4.1.4.1",
sensor_type: "rate",
sensor_descr: "Rx Capacity",
sensor_unit: "Mbps",
sensor_divisor: 1000
}
]
end
end

View file

@ -111,7 +111,7 @@ defmodule ToweropsWeb.DeviceLive.Form do
# Add agent_token_id to the changeset data
device_with_agent = Map.put(device, :agent_token_id, agent_token_id)
changeset = Devices.change_device(device, %{})
changeset = Devices.change_device(device_with_agent, %{})
# Get effective SNMP configuration and source
snmp_config = Devices.get_snmp_config(device)

View file

@ -1,5 +1,12 @@
Devices Working
* Mikrotik RouterOS
* Ubiquiti AC, LTU, AirFiber
2025-01-27
* Infrastructure improvements
* Bug fix: poller agent assignment on devices
2025-01-26
* Cloud poller improvements
* Accessability improved
* Added initial help documentation

View file

@ -61,9 +61,14 @@ defmodule Towerops.Snmp.Profiles.Vendors.AirfiberTest do
end
describe "discover_wireless_sensors/1" do
test "discovers sensors when SNMP responds" do
expect(SnmpMock, :get, 7, fn _, oid, _ ->
test "discovers sensors from regular AirFiber device" do
# First call checks for LTU device (returns error = not LTU)
# Then 7 calls for regular AirFiber sensors
expect(SnmpMock, :get, 8, fn _target, oid, _opts ->
cond do
# LTU detection OID (should fail for regular AirFiber)
String.contains?(oid, "41112.1.10.1.2.2.0") -> {:error, :no_such_object}
# Regular AirFiber OIDs (should succeed)
String.contains?(oid, "41112.1.3.2.1.6.1") -> {:ok, 5800}
String.contains?(oid, "41112.1.3.2.1.7.1") -> {:ok, 5800}
String.contains?(oid, "41112.1.3.2.1.8.1") -> {:ok, 25}
@ -79,11 +84,66 @@ defmodule Towerops.Snmp.Profiles.Vendors.AirfiberTest do
assert is_list(sensors)
assert length(sensors) == 7
# Verify regular AirFiber OIDs were used
freq_sensors = Enum.filter(sensors, &(&1.sensor_type == "frequency"))
assert length(freq_sensors) == 2
end
test "returns empty list when no sensors respond" do
expect(SnmpMock, :get, 7, fn _, _, _ ->
{:error, :no_such_object}
test "discovers sensors from LTU device with correct OIDs" do
# First call detects LTU device (returns frequency)
# Then 6 calls for LTU-specific sensors
expect(SnmpMock, :get, 7, fn _target, oid, _opts ->
cond do
# LTU detection OID (should succeed for LTU)
String.contains?(oid, "41112.1.10.1.2.2.0") -> {:ok, 5800}
# LTU-specific OIDs
String.contains?(oid, "41112.1.10.1.2.6.0") -> {:ok, 25}
String.contains?(oid, "41112.1.10.1.4.1.5.1") -> {:ok, -55}
String.contains?(oid, "41112.1.10.1.4.1.6.1") -> {:ok, -56}
String.contains?(oid, "41112.1.10.1.4.1.3.1") -> {:ok, 450_000}
String.contains?(oid, "41112.1.10.1.4.1.4.1") -> {:ok, 450_000}
true -> {:error, :no_such_object}
end
end)
sensors = Airfiber.discover_wireless_sensors(@client_opts)
assert is_list(sensors)
assert length(sensors) == 6
# Verify LTU OIDs were used
rate_sensors = Enum.filter(sensors, &(&1.sensor_type == "rate"))
assert length(rate_sensors) == 2
# Verify the divisor is set correctly (division happens at display time)
assert Enum.all?(rate_sensors, &(&1.sensor_divisor == 1000))
# Raw value should be 450000 Kbps (not divided during discovery)
assert Enum.all?(rate_sensors, &(&1.last_value == 450_000.0))
end
test "returns empty list when LTU device has no active stations" do
# LTU detected but no station data available
expect(SnmpMock, :get, 7, fn _target, oid, _opts ->
# LTU detection succeeds
if String.contains?(oid, "41112.1.10.1.2.2.0") do
{:ok, 5800}
else
# But station OIDs fail (no connected stations)
{:error, :no_such_object}
end
end)
sensors = Airfiber.discover_wireless_sensors(@client_opts)
# Frequency sensor should still be discovered
assert is_list(sensors)
assert length(sensors) == 1
assert List.first(sensors).sensor_type == "frequency"
end
test "returns empty list when device does not respond" do
expect(SnmpMock, :get, 8, fn _target, _oid, _opts ->
{:error, :timeout}
end)
sensors = Airfiber.discover_wireless_sensors(@client_opts)