fix(cli): the trunk gets its own row, as over REST
Since f35b59e a CLI poll reports trunk members as `3` with
trunk_group `Trk3`, but `show interfaces brief` has no line for Trk3
itself, so the trunk was missing from the interface list. The REST path
built that row on its own.
Both paths now use napalm_device_types.add_lag_interfaces, and the REST
path's copy is gone. One visible change there: `lag_members` is now in
port order (7, 10) instead of API order; the description already was.
The CLI path does not know the mode yet, so its trunks carry no
lag_mode. That needs `show trunks`, whose output is not at hand.
Needs napalm-device-types f3fa75b.
Closes #5
This commit is contained in:
@@ -15,6 +15,7 @@ import urllib3
|
|||||||
|
|
||||||
from napalm.base import helpers as napalm_helpers
|
from napalm.base import helpers as napalm_helpers
|
||||||
from napalm.base.exceptions import ConnectionException, ConnectAuthError
|
from napalm.base.exceptions import ConnectionException, ConnectAuthError
|
||||||
|
from napalm_device_types import add_lag_interfaces
|
||||||
|
|
||||||
logger = logging.getLogger("napalm_procurve.api")
|
logger = logging.getLogger("napalm_procurve.api")
|
||||||
|
|
||||||
@@ -307,22 +308,11 @@ class ProcurveApiClient:
|
|||||||
if pid in output:
|
if pid in output:
|
||||||
output[pid]["speed"] = float(stat.get("port_speed_mbps", 0))
|
output[pid]["speed"] = float(stat.get("port_speed_mbps", 0))
|
||||||
|
|
||||||
# Synthesize a logical interface entry for each configured LAG/trunk
|
# One row per LAG/trunk group alongside its member ports.
|
||||||
# group so it shows up as its own row alongside its member ports.
|
return add_lag_interfaces(output, {
|
||||||
for group, members in trunk_groups.items():
|
group: "lacp" if trunk_modes.get(group) == "PTT_LACP" else "trunk"
|
||||||
output[group] = {
|
for group in trunk_groups
|
||||||
"is_up": any(output[m]["is_up"] for m in members),
|
})
|
||||||
"is_enabled": any(output[m]["is_enabled"] for m in members),
|
|
||||||
"description": f"LAG ({', '.join(sorted(members, key=lambda s: int(s) if s.isdigit() else 0))})",
|
|
||||||
"last_flapped": -1.0,
|
|
||||||
"speed": sum(output[m]["speed"] for m in members),
|
|
||||||
"mtu": -1,
|
|
||||||
"mac_address": "",
|
|
||||||
"lag_members": members,
|
|
||||||
"lag_mode": "lacp" if trunk_modes.get(group) == "PTT_LACP" else "trunk",
|
|
||||||
}
|
|
||||||
|
|
||||||
return output
|
|
||||||
|
|
||||||
def get_interfaces_ip(self) -> Dict[str, Dict]:
|
def get_interfaces_ip(self) -> Dict[str, Dict]:
|
||||||
"""Return NAPALM interfaces IP from the REST API."""
|
"""Return NAPALM interfaces IP from the REST API."""
|
||||||
|
|||||||
@@ -27,7 +27,12 @@ from netmiko.exceptions import (
|
|||||||
NetmikoAuthenticationException,
|
NetmikoAuthenticationException,
|
||||||
NetmikoTimeoutException,
|
NetmikoTimeoutException,
|
||||||
)
|
)
|
||||||
from napalm_device_types import ConfigLifecycleMixin, FingerprintRule, SwitchDriver
|
from napalm_device_types import (
|
||||||
|
ConfigLifecycleMixin,
|
||||||
|
FingerprintRule,
|
||||||
|
SwitchDriver,
|
||||||
|
add_lag_interfaces,
|
||||||
|
)
|
||||||
from napalm_device_types.models import InterfaceConfigDict, VlanConfigDict
|
from napalm_device_types.models import InterfaceConfigDict, VlanConfigDict
|
||||||
from napalm.base import helpers as napalm_helpers
|
from napalm.base import helpers as napalm_helpers
|
||||||
from napalm.base.exceptions import (
|
from napalm.base.exceptions import (
|
||||||
@@ -502,7 +507,8 @@ class ProcurveDriver(ConfigLifecycleMixin, SwitchDriver):
|
|||||||
except Exception:
|
except Exception:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
return ifaces
|
# The CLI lists member ports only ("3-Trk3"); the trunk gets its own row.
|
||||||
|
return add_lag_interfaces(ifaces)
|
||||||
|
|
||||||
# ------------------------------------------------------------------
|
# ------------------------------------------------------------------
|
||||||
# NAPALM: get_interfaces_ip
|
# NAPALM: get_interfaces_ip
|
||||||
|
|||||||
@@ -884,3 +884,58 @@ class TestApiSetInterfaceExistingMembership:
|
|||||||
drv.set_interface("10", {"mode": "trunk", "trunk_vlans": [10]})
|
drv.set_interface("10", {"mode": "trunk", "trunk_vlans": [10]})
|
||||||
assert "boom" in str(exc.value)
|
assert "boom" in str(exc.value)
|
||||||
api.put.assert_not_called()
|
api.put.assert_not_called()
|
||||||
|
|
||||||
|
|
||||||
|
# ===========================================================================
|
||||||
|
# LAG rows (#5)
|
||||||
|
# ===========================================================================
|
||||||
|
|
||||||
|
|
||||||
|
class TestApiGetInterfacesLag:
|
||||||
|
"""The REST path's trunk rows, kept as they were when it moved to add_lag_interfaces."""
|
||||||
|
|
||||||
|
def _client(self, ports):
|
||||||
|
from napalm_procurve.api_client import ProcurveApiClient
|
||||||
|
|
||||||
|
client = ProcurveApiClient(hostname="192.168.0.1", username="manager", password="secret")
|
||||||
|
responses = {
|
||||||
|
"ports": {"port_element": ports},
|
||||||
|
"port-statistics": {"port_statistics_element": [
|
||||||
|
{"id": p["id"], "port_speed_mbps": 1000} for p in ports
|
||||||
|
]},
|
||||||
|
"system/status/switch": {},
|
||||||
|
}
|
||||||
|
client.get = MagicMock(side_effect=lambda endpoint, **kw: responses[endpoint])
|
||||||
|
return client
|
||||||
|
|
||||||
|
def test_trunk_rows_with_mode(self):
|
||||||
|
client = self._client([
|
||||||
|
{"id": "1", "is_port_up": True, "is_port_enabled": True, "trunk_group": ""},
|
||||||
|
{"id": "3", "is_port_up": False, "is_port_enabled": True, "trunk_group": "trk3", "trunk_mode": "PTT_LACP"},
|
||||||
|
{"id": "4", "is_port_up": True, "is_port_enabled": True, "trunk_group": "trk3", "trunk_mode": "PTT_LACP"},
|
||||||
|
{"id": "10", "is_port_up": False, "is_port_enabled": True, "trunk_group": "trk6"},
|
||||||
|
{"id": "7", "is_port_up": False, "is_port_enabled": True, "trunk_group": "trk6"},
|
||||||
|
])
|
||||||
|
ifaces = client.get_interfaces()
|
||||||
|
|
||||||
|
assert ifaces["trk3"]["lag_members"] == ["3", "4"]
|
||||||
|
assert ifaces["trk3"]["lag_mode"] == "lacp"
|
||||||
|
assert ifaces["trk3"]["is_up"] is True
|
||||||
|
assert ifaces["trk3"]["speed"] == 2000.0
|
||||||
|
assert ifaces["trk6"]["lag_members"] == ["7", "10"]
|
||||||
|
assert ifaces["trk6"]["lag_mode"] == "trunk"
|
||||||
|
assert ifaces["trk6"]["description"] == "LAG (7, 10)"
|
||||||
|
assert ifaces["3"]["trunk_group"] == "trk3"
|
||||||
|
|
||||||
|
|
||||||
|
class TestCliGetInterfacesLag:
|
||||||
|
def test_trunk_rows_from_member_ports(self, driver):
|
||||||
|
driver._send_command = MagicMock(
|
||||||
|
side_effect=lambda cmd: SHOW_INTERFACES_BRIEF_INTRUSION if cmd == "show interfaces brief" else ""
|
||||||
|
)
|
||||||
|
ifaces = driver.get_interfaces()
|
||||||
|
|
||||||
|
assert ifaces["Trk3"]["lag_members"] == ["3", "4"]
|
||||||
|
assert ifaces["Trk6"]["lag_members"] == ["6", "7"]
|
||||||
|
assert ifaces["Trk6"]["is_up"] is True
|
||||||
|
assert ifaces["Trk6"]["is_enabled"] is True
|
||||||
|
|||||||
Reference in New Issue
Block a user