feat: synthesize LAG/trunk interfaces and support trunk member editing
get_interfaces() now fills in ports missing from the /ports collection
(e.g. the 4th SFP uplink on a 2530-48G) using system/status/switch, and
synthesizes a logical interface for each configured LAG/trunk group with
lag_members/lag_mode. New set_lag_members() adds/removes trunk members via
the REST /cli passthrough (PUT ports/{id} silently ignores trunk_group).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 4.6
parent
ef544be540
commit
576752da23
@@ -796,6 +796,55 @@ class ProcurveDriver(SwitchDriver):
|
||||
self._exit_config_mode()
|
||||
self._save_config()
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# LAG / trunk membership
|
||||
# ------------------------------------------------------------------
|
||||
|
||||
def set_lag_members(self, lag_name: str, members: List[str]) -> None:
|
||||
"""Set the full member-port list of a LAG/trunk group.
|
||||
|
||||
Diffs ``members`` against the trunk's current members (as reported
|
||||
by ``get_interfaces()``) and issues ``trunk``/``no trunk`` commands
|
||||
for the difference. Available on both REST API and CLI transports —
|
||||
ArubaOS-Switch only exposes trunk membership via the CLI, including
|
||||
through the REST API's ``/cli`` passthrough endpoint (``PUT /ports``
|
||||
does not apply ``trunk_group``/``trunk_mode`` changes).
|
||||
"""
|
||||
current = self.get_interfaces().get(lag_name, {})
|
||||
current_members = set(current.get("lag_members") or [])
|
||||
desired = set(members)
|
||||
to_remove = sorted(current_members - desired, key=lambda s: int(s) if s.isdigit() else 0)
|
||||
to_add = sorted(desired - current_members, key=lambda s: int(s) if s.isdigit() else 0)
|
||||
|
||||
if not to_remove and not to_add:
|
||||
return
|
||||
|
||||
mode = current.get("lag_mode") or "trunk"
|
||||
trk_name = lag_name.lower()
|
||||
|
||||
commands: List[str] = []
|
||||
if to_remove:
|
||||
commands.append(f"no trunk {','.join(to_remove)}")
|
||||
if to_add:
|
||||
commands.append(f"trunk {','.join(to_add)} {trk_name} {mode}")
|
||||
|
||||
if self._transport == "api":
|
||||
for cmd in ["configure terminal", *commands]:
|
||||
resp = self._api.post("cli", json={"cmd": cmd})
|
||||
if not resp.ok or resp.json().get("status") == "CCS_FAILURE":
|
||||
raise CommandErrorException(
|
||||
f"set_lag_members({lag_name}): '{cmd}' -> {resp.text[:200]}"
|
||||
)
|
||||
else:
|
||||
self._enter_config_mode()
|
||||
try:
|
||||
errors = self._apply_config_lines("\n".join(commands))
|
||||
if errors:
|
||||
raise CommandErrorException(f"set_lag_members({lag_name}) errors: {errors}")
|
||||
finally:
|
||||
self._exit_config_mode()
|
||||
self._save_config()
|
||||
|
||||
def set_interface(self, interface: str, config: InterfaceConfigDict) -> None:
|
||||
"""Configure a switch interface (mode, VLAN membership)."""
|
||||
if self._transport == "api":
|
||||
|
||||
Reference in New Issue
Block a user