feat(lldp): report neighbours from the LLDP Remote Device Summary page

get_lldp_neighbors() was never implemented, so the switch reported no
neighbours and NetOrk's network map had nothing to draw for the site it
serves — on the reference installation two APs, a firewall and a Proxmox host
behind a 1820 8G PoE+ (J9982A) all stood unconnected.

The web UI does carry the data. /htdocs/pages/switching/lldp_remote.lsp is
served with the rows embedded in the page's aDataSet, so the existing _rows()
helper reads it with no new plumbing:

    ['7', '3', '00:...:44', '00:...:46', 'enp3s0', 'host.example.com',
     'bridge, WLAN access point, router, station only', 'bridge', '192.0.2.10']

Column 3 is the neighbour's port ID, which on many peers is a MAC, while
column 4 is its port description — a name a person can read. The description
wins, with the ID used only when it is missing. The chassis ID is passed
through as `mac` when it looks like one, since netOrk resolves a neighbour by
MAC before falling back to its name.

Fixture captured from the live switch and anonymised in the style of the
existing ones.

Closes #1
This commit is contained in:
Christian Manivong
2026-08-18 15:19:13 +07:00
parent c76a177ff2
commit cc5f615dbc
3 changed files with 256 additions and 0 deletions
+29
View File
@@ -14,6 +14,7 @@ PAGE_FOR_PATH = {
OfficeConnectDriver.PORT_SUMMARY: "base_port_summary",
OfficeConnectDriver.MAC_TABLE: "base_mac_address_table",
OfficeConnectDriver.VLAN_STATUS: "switching_vlan_status",
OfficeConnectDriver.LLDP_REMOTE: "switching_lldp_remote",
}
@@ -194,3 +195,31 @@ def test_get_interfaces_counters_is_not_implemented(driver):
zeros would look like real counters. See README."""
with pytest.raises(NotImplementedError):
driver.get_interfaces_counters()
# ===========================================================================
# LLDP — the map has nothing to draw for this site without it
# ===========================================================================
def test_get_lldp_neighbors_keys_on_local_port(driver):
neighbors = driver.get_lldp_neighbors()
assert set(neighbors) == {"7", "8"}
def test_get_lldp_neighbors_reports_hostname_and_remote_port(driver):
"""The remote port description beats its MAC — `enp3s0` names something."""
entry = driver.get_lldp_neighbors()["7"][0]
assert entry["hostname"] == "host-1.example.com"
assert entry["port"] == "enp3s0"
def test_get_lldp_neighbors_carries_the_chassis_mac(driver):
"""netOrk resolves a neighbour by MAC before falling back to its name."""
entry = driver.get_lldp_neighbors()["7"][0]
assert entry["mac"] == "00:11:22:33:44:01"
def test_get_lldp_neighbors_without_neighbours_is_empty(driver):
driver._client.fetch.side_effect = lambda path: "<html><body>no table</body></html>"
assert driver.get_lldp_neighbors() == {}