Purpose
This issue tracks problems found in individual cisco.nd interface modules while testing cisco.nd.nd_interfaces_workflow.
The aggregator is the discovery context only. Each finding documents behavior attributable to a standalone interface module or its shared implementation.
Finding conventions
- Every finding receives a permanent
IFACE-### identifier.
- Every finding is added to the index.
- Every finding uses visible headings and HTML start/end delimiters.
- Finding identifiers will not be renumbered.
- If a finding is moved into a separate GitHub issue, that issue will be linked from the index while the summary remains here.
Initial test environment
- Ansible Core:
2.16.3
- Python:
3.12.13
cisco.nd: 1.5.0 development checkout
- Tested branch:
interface_aggregator
- Tested revision:
cdcb8de1488e30a635a93c1cfd9444fed9b14da0
- Nexus Dashboard:
4.2.1 (build_version: 4.2.1.10)
- NDFC:
12.5.0.475
- NX-OS version: Not relevant to IFACE-001 because the failure occurs during module planning before any controller mutation or deployment request.
Future findings should document any differing environment details inside their respective finding block.
Finding index
| ID |
Module |
Summary |
Status |
| IFACE-001 |
cisco.nd.nd_interface_ethernet_access |
state: deleted silently ignores a named physical Ethernet interface whose current policy is dot1qTunnelHost |
Open |
===== BEGIN FINDING IFACE-001 =====
IFACE-001: nd_interface_ethernet_access silently ignores a delete when the current policy is not accessHost
Module
cisco.nd.nd_interface_ethernet_access
Summary
When cisco.nd.nd_interface_ethernet_access is called with state: deleted for an explicitly named physical Ethernet interface whose current policyType is dot1qTunnelHost, the interface is silently excluded from deletion planning.
The task succeeds with:
The requested interface is absent from both before and after, and no interface normalization is planned.
This behavior was discovered through interface-aggregator testing and then reproduced directly with cisco.nd.nd_interface_ethernet_access in check mode. The problem originates in the standalone module's shared Ethernet orchestration path.
Preconditions
- The target is a physical Ethernet interface.
- The target is explicitly identified by
switch_ip and interface_names.
- The target is not a port-channel member.
- The interface is not already at fabric-default configuration.
- Its current controller state includes:
interfaceType: ethernet
configData:
mode: dot1qTunnel
networkOS:
policy:
policyType: dot1qTunnelHost
Ansible playbook
The addresses and fabric name below are sanitized.
---
- name: Reproduce cross-policy Ethernet deletion
hosts: nd_controller
gather_facts: false
tasks:
- name: Reset an explicitly named physical Ethernet interface
cisco.nd.nd_interface_ethernet_access:
fabric_name: test_fabric
config:
- switch_ip: 192.0.2.10
interface_names:
- Ethernet1/40
config_actions:
deploy: false
state: deleted
check_mode: true
register: delete_result
- name: Display the result
ansible.builtin.debug:
var: delete_result
Steps to reproduce
- Configure a physical Ethernet interface with
policyType: dot1qTunnelHost through Nexus Dashboard.
- Confirm that the interface is not a port-channel member.
- Run the playbook above.
- Inspect
changed, before, and after.
- Observe that the explicitly requested interface is absent from both state collections and no normalization is planned.
Expected behavior
Because the user explicitly named an eligible physical Ethernet interface with state: deleted, the module should select it regardless of its current Ethernet policy family.
In check mode, the module should report a prospective change:
During normal execution, it should use the existing normalize/reset implementation to return the interface to the applicable fabric-default physical-interface configuration, currently represented by the trunkHost normalization template.
Existing safeguards must remain enforced, including the protection against normalizing port-channel members. A subsequent identical deletion against an interface already at fabric default must be idempotent.
If cross-policy normalization is intentionally outside the module contract, the module should instead return a clear policy-mismatch error. A successful silent no-op should not occur.
Actual behavior
The direct standalone check-mode invocation completes successfully with:
changed: false
before:
# Contains unrelated accessHost interfaces only.
# The explicitly requested Ethernet1/40 is absent.
after:
# Identical to before.
# Ethernet1/40 remains absent.
The requested interface is treated as though it does not exist even though it is present in the controller's physical Ethernet inventory.
Suspected cause
EthernetAccessInterfaceOrchestrator._managed_policy_types() returns only:
EthernetBaseOrchestrator.query_all() then filters the physical Ethernet inventory using that managed-policy set before deletion planning.
Relevant paths:
plugins/module_utils/orchestrators/ethernet_access_interface.py
EthernetAccessInterfaceOrchestrator._managed_policy_types()
plugins/module_utils/orchestrators/ethernet_base.py
EthernetBaseOrchestrator.query_all()
plugins/module_utils/nd_state_machine.py
NDStateMachine._manage_delete_state()
The standalone delete logic only selects proposed identifiers found in the filtered current-state collection. Because dot1qTunnelHost was removed by query_all(), the explicitly requested interface never reaches delete_bulk() or remove_pending().
The existing delete execution path already supports normalization once an interface reaches it:
plugins/module_utils/orchestrators/ethernet_base.py
EthernetBaseOrchestrator.delete_bulk()
EthernetBaseOrchestrator.remove_pending()
Suggested implementation scope
Deletion discovery should retain explicitly named, eligible, non-default physical Ethernet interfaces independently of their current policy family.
The existing policy-family filtering should remain unchanged for:
state: merged
state: replaced
state: overridden
A foreign-policy response cannot simply be deserialized unchanged as EthernetAccessInterfaceModel, because that model fixes mode to access and policyType to accessHost. Identity-only deletion candidates can be used while retaining access to the cached raw interface record for:
- Port-channel membership protection
- Detection of fields requiring the PUT reset path
- Normalization payload construction
Acceptance criteria
- An explicitly named, eligible physical Ethernet interface using
dot1qTunnelHost is not silently filtered from state: deleted.
- Check mode reports
changed: true when normalization is required.
- Normal execution resets the interface to fabric-default configuration.
- Existing port-channel-member protection remains enforced.
- A subsequent identical deletion is idempotent.
- Policy-family filtering remains unchanged for create and update states.
- Standalone-module regression coverage is added.
- Aggregate-workflow regression coverage verifies the inherited behavior.
Recommended regression cases:
- A named
dot1qTunnelHost interface becomes a deletion candidate.
- The candidate produces
changed: true in check mode.
- Normal execution resets the interface.
- A second deletion is idempotent.
- An interface already at fabric default remains unchanged.
- A port-channel member remains protected.
merged, replaced, and overridden remain scoped to accessHost.
===== END FINDING IFACE-001 =====
Purpose
This issue tracks problems found in individual
cisco.ndinterface modules while testingcisco.nd.nd_interfaces_workflow.The aggregator is the discovery context only. Each finding documents behavior attributable to a standalone interface module or its shared implementation.
Finding conventions
IFACE-###identifier.Initial test environment
2.16.33.12.13cisco.nd:1.5.0development checkoutinterface_aggregatorcdcb8de1488e30a635a93c1cfd9444fed9b14da04.2.1(build_version: 4.2.1.10)12.5.0.475Future findings should document any differing environment details inside their respective finding block.
Finding index
cisco.nd.nd_interface_ethernet_accessstate: deletedsilently ignores a named physical Ethernet interface whose current policy isdot1qTunnelHost===== BEGIN FINDING IFACE-001 =====
IFACE-001:
nd_interface_ethernet_accesssilently ignores a delete when the current policy is notaccessHostModule
cisco.nd.nd_interface_ethernet_accessSummary
When
cisco.nd.nd_interface_ethernet_accessis called withstate: deletedfor an explicitly named physical Ethernet interface whose currentpolicyTypeisdot1qTunnelHost, the interface is silently excluded from deletion planning.The task succeeds with:
The requested interface is absent from both
beforeandafter, and no interface normalization is planned.This behavior was discovered through interface-aggregator testing and then reproduced directly with
cisco.nd.nd_interface_ethernet_accessin check mode. The problem originates in the standalone module's shared Ethernet orchestration path.Preconditions
switch_ipandinterface_names.Ansible playbook
The addresses and fabric name below are sanitized.
Steps to reproduce
policyType: dot1qTunnelHostthrough Nexus Dashboard.changed,before, andafter.Expected behavior
Because the user explicitly named an eligible physical Ethernet interface with
state: deleted, the module should select it regardless of its current Ethernet policy family.In check mode, the module should report a prospective change:
During normal execution, it should use the existing normalize/reset implementation to return the interface to the applicable fabric-default physical-interface configuration, currently represented by the
trunkHostnormalization template.Existing safeguards must remain enforced, including the protection against normalizing port-channel members. A subsequent identical deletion against an interface already at fabric default must be idempotent.
If cross-policy normalization is intentionally outside the module contract, the module should instead return a clear policy-mismatch error. A successful silent no-op should not occur.
Actual behavior
The direct standalone check-mode invocation completes successfully with:
The requested interface is treated as though it does not exist even though it is present in the controller's physical Ethernet inventory.
Suspected cause
EthernetAccessInterfaceOrchestrator._managed_policy_types()returns only:EthernetBaseOrchestrator.query_all()then filters the physical Ethernet inventory using that managed-policy set before deletion planning.Relevant paths:
The standalone delete logic only selects proposed identifiers found in the filtered current-state collection. Because
dot1qTunnelHostwas removed byquery_all(), the explicitly requested interface never reachesdelete_bulk()orremove_pending().The existing delete execution path already supports normalization once an interface reaches it:
Suggested implementation scope
Deletion discovery should retain explicitly named, eligible, non-default physical Ethernet interfaces independently of their current policy family.
The existing policy-family filtering should remain unchanged for:
state: mergedstate: replacedstate: overriddenA foreign-policy response cannot simply be deserialized unchanged as
EthernetAccessInterfaceModel, because that model fixesmodetoaccessandpolicyTypetoaccessHost. Identity-only deletion candidates can be used while retaining access to the cached raw interface record for:Acceptance criteria
dot1qTunnelHostis not silently filtered fromstate: deleted.changed: truewhen normalization is required.Recommended regression cases:
dot1qTunnelHostinterface becomes a deletion candidate.changed: truein check mode.merged,replaced, andoverriddenremain scoped toaccessHost.===== END FINDING IFACE-001 =====