Skip to content

nd_interface_loopback: normalize ip to bare IPv4 (ND 4.2.1 rejects CIDR)#402

Open
allenrobel wants to merge 3 commits into
developfrom
nd_interface_loopback_ip_bare_ipv4
Open

nd_interface_loopback: normalize ip to bare IPv4 (ND 4.2.1 rejects CIDR)#402
allenrobel wants to merge 3 commits into
developfrom
nd_interface_loopback_ip_bare_ipv4

Conversation

@allenrobel

Copy link
Copy Markdown
Collaborator

Related Issue(s)

Fixes #401

Proposed Changes

  • Added an IPv4Host Annotated type to plugins/module_utils/models/types.py: a BeforeValidator that 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 clear ValueError on invalid input.
  • Switched LoopbackPolicyModel.ip (in plugins/module_utils/models/interfaces/loopback_interface.py) from IPv4CIDR to IPv4Host and updated its field description.
  • Updated the loopback model unit tests to expect the normalized bare form and the new "is not a valid IPv4 address" error message.
  • Added a merged-state integration task exercising a CIDR-format ip end-to-end: asserts the create succeeds with a bare ip in 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 ip on a loopback create (HTTP 400 - Validation failed for following fields: [ip]) and accepts only a bare IPv4 (HTTP 207). The intLoopbackTemplate declares ip as format: 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

  • Unit tests: ndpytest tests/unit/3173 passed. The loopback model suite was updated TDD-style (watched the 7 relevant assertions fail against the old IPv4CIDR typing, then pass after the IPv4Host switch).
  • Integration: nd_interface_loopback merged-state suite run against a live ND 4.2.1 fabric — green, including the new CIDR-normalization/idempotency task.
  • Lint/format: ndblack --check, ndisort --check-only, ndpylint, ndmypy clean on the changed files (no new findings; pre-existing argument-spec R1735 and environmental mypy import-not-found unaffected). ndlint passes at the production profile on the changed integration task file.

Cisco Nexus Dashboard Version

4.2.1

Related ND API Resource Category

  • analyze
  • infra
  • 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

Copilot AI review requested due to automatic review settings July 15, 2026 19:02
@allenrobel allenrobel self-assigned this Jul 15, 2026

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 IPv4Host annotated type with a BeforeValidator that normalizes IPv4 input to bare host form.
  • Switched LoopbackPolicyModel.ip from IPv4CIDR to IPv4Host and 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.

Comment thread tests/unit/module_utils/models/test_loopback_interface.py
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
@allenrobel
allenrobel requested a review from Copilot July 15, 2026 19:15

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 4 out of 4 changed files in this pull request and generated no new comments.

@allenrobel allenrobel added ready for review Submitter is requesting a PR review 2.0.0 Release 2.0.0 labels Jul 15, 2026

@gmicol gmicol left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

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
allenrobel force-pushed the nd_interface_loopback_ip_bare_ipv4 branch from 1694d51 to 6b85c72 Compare July 19, 2026 18:53
allenrobel and others added 3 commits July 22, 2026 06:11
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
allenrobel force-pushed the nd_interface_loopback_ip_bare_ipv4 branch from 6b85c72 to f8d650f Compare July 22, 2026 16:12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

2.0.0 Release 2.0.0 NaC-CapSet1 ready for review Submitter is requesting a PR review

Projects

None yet

Development

Successfully merging this pull request may close these issues.

nd_interface_loopback: ip typed as IPv4CIDR sends /32 that ND 4.2.1 rejects (wants bare IPv4)

5 participants