Skip to content

nd_vpc_pair#278

Open
allenrobel wants to merge 4 commits into
nd_interface_port_channel_trunk_hostfrom
nd_vpc_pair
Open

nd_vpc_pair#278
allenrobel wants to merge 4 commits into
nd_interface_port_channel_trunk_hostfrom
nd_vpc_pair

Conversation

@allenrobel
Copy link
Copy Markdown
Collaborator

@allenrobel allenrobel commented May 13, 2026

Related Issue(s)

Sivakami has an open PR 197 - VPC Pair 4.x Implementation for VPC pairing. I needed this to implement VPC interface modules, but this has not been merged into develop, and it does not currently leverage Gaspard's framework. Due to this, I asked Claude to write a VPC pair module that I could stack my VPC interface PRs (both will be created today) onto. I want to acknowledge Sivakami's work and did ask Claude to ensure nd_vpc_pair is functionally equivalent to it (so the PR did serve as a baseline reference from a functionality perspective). I'll reach out to Sivakami to explain this situation and ask if this is OK with her.

Proposed Changes

  • Adds the nd_vpc_pair module, which manages vPC pair lifecycle (pair / unpair) between two switches in a fabric via the ND PUT /api/v1/manage/fabrics/{fabric}/switches/{sn}/vpcPair endpoint.
  • Adds the shared VpcBaseOrchestrator (plugins/module_utils/orchestrators/vpc_base.py) that every nd_interface_vpc_* module will reuse for CRUD, peer-serial resolution, per-interface DELETE, and query_all dedupe.
  • Adds endpoint models: EpManageFabricSwitchVpcPairGet, EpManageFabricVpcPairsListGet, EpManageFabricSwitchActionsDeploy, and EpManageInterfacesDelete.
  • Adds the VpcPairModel Pydantic model with vpcPairDetails subtree and identifier_strategy = "single" on switch_ip.

Three ND 4.2.1 wire quirks are accommodated and tagged TODO(4.2.1):

  • interfaceActions/remove returns "Invalid Interface" for vPC entries; vPC delete uses the per-interface DELETE endpoint instead.
  • ND echoes each vPC interface from BOTH peer switches in their per-switch /interfaces GET; the orchestrator dedupes by interfaceName, keeping the alphabetically-lower switchId as canonical.
  • These are documented inline at each workaround site and audited by /nd-workaround-audit.

Test Notes

  • 69 new unit tests across model, orchestrator, and 3 endpoint files: `python -m pytest tests/unit/module_utils/{models,orchestrators,endpoints}/ -q` (926 total pass, no regressions).
  • Integration target `tests/integration/targets/nd_vpc_pair/` with `merged` / `replaced` / `deleted` state coverage, exercised against ND 4.2.1 on the SITE1 lab (S1_LE1 / S1_LE2): `ansible-test integration --docker nd_vpc_pair -vv`.
  • `ansible-test sanity --docker default --python 3.11` passes on the changed files.
  • Wire shape verified live against ND 4.2.1: pair create returns 204, GET `/vpcPair` returns the per-peer record, `vpcAction: unPair` cleanly tears the pair down.

Cisco Nexus Dashboard Version

4.2.1

Related ND API Resource Category

  • analyze
  • infa
  • manage
  • onemanage
  • other

Checklist

  • Latest commit is rebased from develop with merge conflicts resolved
  • New or updates to documentation has been made accordingly
  • Assigned the proper reviewers

@allenrobel allenrobel self-assigned this May 13, 2026
@allenrobel allenrobel changed the title nd_vpc_pair module nd_vpc_pair May 13, 2026
@allenrobel allenrobel force-pushed the nd_interface_port_channel_trunk_host branch from 9e5fac2 to c8dc38b Compare May 14, 2026 18:40
@allenrobel allenrobel force-pushed the nd_interface_port_channel_trunk_host branch from c8dc38b to 6feffd8 Compare May 14, 2026 20:44
@allenrobel allenrobel force-pushed the nd_interface_port_channel_trunk_host branch from 6feffd8 to 1e1d26d Compare May 20, 2026 21:23
@allenrobel allenrobel force-pushed the nd_interface_port_channel_trunk_host branch from 1e1d26d to 69c77c5 Compare May 21, 2026 19:41
@allenrobel allenrobel force-pushed the nd_interface_port_channel_trunk_host branch from 69c77c5 to b993187 Compare May 22, 2026 00:50
@allenrobel allenrobel force-pushed the nd_interface_port_channel_trunk_host branch from 01d4292 to 3061435 Compare May 22, 2026 03:13
@allenrobel allenrobel force-pushed the nd_interface_port_channel_trunk_host branch 4 times, most recently from a042e60 to 297e66c Compare May 22, 2026 17:14
@allenrobel allenrobel force-pushed the nd_interface_port_channel_trunk_host branch from 297e66c to 539ac4e Compare May 28, 2026 17:34
allenrobel and others added 4 commits May 28, 2026 08:14
Adds EpManageInterfacesDelete to manage_interfaces.py. The per-interface
DELETE endpoint at /fabrics/{fabric}/switches/{sn}/interfaces/{name} returns
204 on success and a subsequent GET returns 404.

This is the workaround path used by VpcBaseOrchestrator.delete() because the
interfaceActions/remove bulk endpoint returns "Invalid Interface" (HTTP 207
with per-item status "Failed") for vPC entries on ND 4.2.1 (lab-verified).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Introduces vPC pair management plus the shared orchestrator base reused by
every vpc_* interface module (vpc_access, vpc_trunk_host, etc.).

Module:

- nd_vpc_pair: create / replace / delete a vPC pair between two switches in
  a fabric. Wraps the ND vpcPair PUT endpoint with the merged / replaced /
  deleted state machine.

Shared infrastructure (intended to land on this branch so downstream
interface modules can rebase on top of it):

- VpcBaseOrchestrator (orchestrators/vpc_base.py): generic CRUD for any
  vPC-typed interface model. Resolves the peer-switch serial from the
  vpcPair record (cached per orchestrator instance), uses per-interface
  DELETE (workaround for ND 4.2.1 interfaceActions/remove returning
  "Invalid Interface" on vPC entries), and dedupes the query_all results
  ND echoes once per peer switch.
- EpManageFabricSwitchVpcPairGet, EpManageFabricVpcPairsListGet: endpoint
  models for the vpcPair / vpcPairs GETs.
- EpManageFabricSwitchActionsDeploy: bulk deploy endpoint used after vPC
  pair mutations.

Models:

- VpcPairModel with vpcPairDetails subtree, identifier strategy single on
  switch_ip, frozen scaffolding for action/type discriminators.

Tests:

- 69 unit tests (model + orchestrator + 3 endpoint test files + fixture
  JSON).
- Integration target with merged / replaced / deleted state coverage,
  vPC pair create + un-pair lifecycle on the live ND 4.2 lab.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Five unit test files introduced by c5ac406 had stale agent-style boilerplate:

- Generic "Cisco Systems, Inc." copyright instead of the per-author form
- Bloated `from __future__ import absolute_import, annotations, division, print_function`
- `__metaclass__ = type` block (no longer needed; documented in CLAUDE.md)

Update copyright to Allen Robel (@allenrobel), trim the future import to just
`annotations`, and drop the __metaclass__ stanza. Pre-existing pylint disables
unrelated to invalid-name are preserved (line-too-long, too-many-lines in
test_vpc_pair.py models). All 69 vpc_pair-side unit tests still pass.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@allenrobel allenrobel force-pushed the nd_interface_port_channel_trunk_host branch from 539ac4e to 9825378 Compare May 28, 2026 18:16
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant