nd_interface_loopback: normalize ip to bare IPv4 (ND 4.2.1 rejects CIDR)#402
Open
allenrobel wants to merge 3 commits into
Open
nd_interface_loopback: normalize ip to bare IPv4 (ND 4.2.1 rejects CIDR)#402allenrobel wants to merge 3 commits into
allenrobel wants to merge 3 commits into
Conversation
allenrobel
requested review from
akinross,
anvitha-jain,
gmicol,
lhercot,
mikewiebe,
mtarking,
sajagana,
samiib and
shrsr
as code owners
July 15, 2026 19:02
There was a problem hiding this comment.
Pull request overview
This PR updates the loopback interface model to accept either bare IPv4 or CIDR input while normalizing to a bare IPv4 host address, matching Nexus Dashboard 4.2.1 wire behavior (which rejects CIDR for loopback ip) and preserving idempotency for existing /32-style playbooks.
Changes:
- Added a shared
IPv4Hostannotated type with aBeforeValidatorthat normalizes IPv4 input to bare host form. - Switched
LoopbackPolicyModel.ipfromIPv4CIDRtoIPv4Hostand updated the field description accordingly. - Updated unit and integration tests to validate normalization behavior and merged-state idempotency when CIDR is provided.
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 1 comment.
| File | Description |
|---|---|
plugins/module_utils/models/types.py |
Introduces IPv4Host validator/type to normalize CIDR/bare IPv4 input to bare host form. |
plugins/module_utils/models/interfaces/loopback_interface.py |
Updates loopback policy ip field to use IPv4Host so wire payload matches ND 4.2.1 expectations. |
tests/unit/module_utils/models/test_loopback_interface.py |
Adjusts unit tests to expect bare IPv4 output and updated validation error messaging. |
tests/integration/targets/nd_interface_loopback/tasks/merged.yaml |
Adds merged-state regression coverage for CIDR input normalization + idempotency end-to-end. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
allenrobel
added a commit
that referenced
this pull request
Jul 15, 2026
Addresses Copilot review on #402: the test_loopback_interface_00083 Summary said `ip` "rejects a bare IPv4 address without prefix length" while the test asserts the bare address is accepted and returned in bare host form. Update the Summary and Test bullet to describe the actual IPv4Host behavior (bare input accepted, returned unchanged as the bare host form). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DYUaS5GPgMkSwN3Rzpt4DT
11 tasks
akinross
approved these changes
Jul 16, 2026
allenrobel
added a commit
that referenced
this pull request
Jul 19, 2026
Addresses Copilot review on #402: the test_loopback_interface_00083 Summary said `ip` "rejects a bare IPv4 address without prefix length" while the test asserts the bare address is accepted and returned in bare host form. Update the Summary and Test bullet to describe the actual IPv4Host behavior (bare input accepted, returned unchanged as the bare host form). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DYUaS5GPgMkSwN3Rzpt4DT
allenrobel
force-pushed
the
nd_interface_loopback_ip_bare_ipv4
branch
from
July 19, 2026 18:53
1694d51 to
6b85c72
Compare
Fixes #401. On develop, LoopbackPolicyModel.ip is typed IPv4CIDR and the field description/tests use /32 CIDR values, but live ND 4.2.1 400s a loopback create when ip is CIDR (e.g. 10.99.99.250/32) and accepts only the bare host form (HTTP 207). The intLoopbackTemplate declares ip as format: ipv4 (bare), consistent with the wire behavior. Add IPv4Host to models/types.py (BeforeValidator normalizing IPv4Interface to its bare .ip form) and switch LoopbackPolicyModel.ip from IPv4CIDR to IPv4Host, so bare or CIDR input is accepted but always normalized to bare before it reaches the wire. This keeps existing /32-style playbooks working and preserves idempotency, since ND always returns the bare address on read. ipv6 (IPv6CIDR) is unchanged - not verified against ND in this probe. develop's integration tasks already use bare ip values, so they need no changes. Updated the loopback model unit tests that expected the CIDR ip form to expect the normalized bare form and the new "is not a valid IPv4 address" error message. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DYUaS5GPgMkSwN3Rzpt4DT
…401) Add a merged-state task to nd_interface_loopback integration that supplies the loopback ip in CIDR form (10.100.104.1/32) and asserts (a) the create succeeds with the ip normalized to bare (10.100.104.1) in the after-state and (b) a re-apply of the same CIDR ip is idempotent against ND's bare wire form. This covers the end-to-end wire behavior and idempotency loop that the model unit tests cannot: live ND 4.2.1 400s a CIDR ip and stores/returns bare, so without normalization the create fails and merged-state would perpetually report changed. Note: this suite is not run against a live fabric in CI, so the task is a manual/lab regression guard - it must be verified on a live integration run. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DYUaS5GPgMkSwN3Rzpt4DT
Addresses Copilot review on #402: the test_loopback_interface_00083 Summary said `ip` "rejects a bare IPv4 address without prefix length" while the test asserts the bare address is accepted and returned in bare host form. Update the Summary and Test bullet to describe the actual IPv4Host behavior (bare input accepted, returned unchanged as the bare host form). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DYUaS5GPgMkSwN3Rzpt4DT
allenrobel
force-pushed
the
nd_interface_loopback_ip_bare_ipv4
branch
from
July 22, 2026 16:12
6b85c72 to
f8d650f
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Related Issue(s)
Fixes #401
Proposed Changes
IPv4HostAnnotated type toplugins/module_utils/models/types.py: aBeforeValidatorthat accepts either a bare (10.1.1.1) or CIDR (10.1.1.1/32) IPv4 address and normalizes it to the bare host form (str(ipaddress.IPv4Interface(value).ip)), raising a clearValueErroron invalid input.LoopbackPolicyModel.ip(inplugins/module_utils/models/interfaces/loopback_interface.py) fromIPv4CIDRtoIPv4Hostand updated its field description."is not a valid IPv4 address"error message.ipend-to-end: asserts the create succeeds with a bareipin the after-state and that a re-apply of the same CIDR input is idempotent against ND's bare wire form.Why
On live ND 4.2.1, the Manage interfaces endpoint rejects a CIDR
ipon a loopback create (HTTP 400 - Validation failed for following fields: [ip]) and accepts only a bare IPv4 (HTTP 207). TheintLoopbackTemplatedeclaresipasformat: ipv4, consistent with the wire behavior. Normalizing to bare keeps existing/32-style playbooks working and preserves idempotency, since ND always returns the bare address on read.ipv6(IPv6CIDR) is unchanged — not verified against ND in this probe.Test Notes
ndpytest tests/unit/— 3173 passed. The loopback model suite was updated TDD-style (watched the 7 relevant assertions fail against the oldIPv4CIDRtyping, then pass after theIPv4Hostswitch).nd_interface_loopbackmerged-state suite run against a live ND 4.2.1 fabric — green, including the new CIDR-normalization/idempotency task.ndblack --check,ndisort --check-only,ndpylint,ndmypyclean on the changed files (no new findings; pre-existing argument-specR1735and environmental mypyimport-not-foundunaffected).ndlintpasses at theproductionprofile on the changed integration task file.Cisco Nexus Dashboard Version
4.2.1
Related ND API Resource Category
Checklist