Ansible Version
ansible [core 2.16.3]
python version = 3.11.15
jinja version = 3.1.6
Ansible Collection Versions
Collection Version
------------------- --------
cisco.nac_dc_vxlan 0.8.1-dev (develop @ 11588f44)
cisco.dcnm 3.12.1-dev
cisco.nxos 10.2.0
ansible.netcommon 7.1.0
ansible.posix 2.0.0
ansible.utils 5.1.2
community.general 10.1.0
Cisco Nexus Dashboard Version
4.1.1g (NDFC 12.4.1.321)
Cisco NX-OS Version
10.6(2), virtual N9K-C9300v
Which role is this issue related to?
cisco.nac_dc_vxlan.dtc.remove
Which section of the data model is this issue related to?
vxlan.multisite
Expected Behavior
When the final remaining vxlan.multisite.overlay VRF or network entries are removed and the corresponding list becomes empty for an MCFG fabric, the remove pipeline should detect the change and send the corresponding VRF/network delete requests to NDFC — the same way any other declared-then-removed resource is handled in diff-run mode.
Actual Behavior
The collection keeps a small file on disk for each MCFG fabric (the sentinel file, _msite_overlay_sentinel.yml) to remember what the VRFs/networks looked like last time, so it can tell if anything changed.
The function that writes it — _detect_msite_overlay_changes() (plugins/action/dtc/build_resource_data.py) — doesn't save the data as plain values. Instead of writing name: VRF01, the file ends up with something like this for that same value:
? !!python/object/apply:ansible.utils.unsafe_proxy.AnsibleUnsafeText
- VRF01
That's a Python-specific instruction embedded in the file, not just plain text. The function that reads the file back — _sentinel_had_key(), same file — deliberately refuses to load files containing that kind of instruction (a normal security precaution, so it never rebuilds arbitrary code from a file). Because of this mismatch, reading the file always fails.
That failure is silently ignored instead of being reported. So instead of saying "I couldn't read my saved data," the collection just assumes "there was nothing here before."
This becomes a problem specifically once every VRF/network is removed: the current data doesn't disappear, it just becomes an empty list. The only way to tell "these existed before and were removed" from "there was never anything here" is by checking that saved file — and that check is exactly what's silently failing.
End result: the collection always assumes nothing existed before, so it thinks nothing changed, and it never asks NDFC to delete the VRF/networks. Since nothing fails loudly, the playbook finishes normally as if the removal worked — but the VRF/networks are still attached in NDFC.
- API method: none
- API endpoint: none
- Controller requests: 0
Scope
Affected:
- MCFG fabrics where the final remaining
vxlan.multisite.overlay.vrfs or .networks entries are removed, so that list becomes empty (e.g. removing the corresponding host_vars files or clearing the lists) in diff-run mode (force_run_all: false). Present since 0.8.0 (confirmed in the 0.8.0 tag's plugins/action/dtc/build_resource_data.py; the file did not exist prior to 0.7.2).
- The failure occurs before any controller request and has no NDFC-version conditional — it is a client-side collection defect in how the collection serializes/deserializes its own local change-detection file. Confirmed on ND 4.1.1g / NDFC 12.4.1.321; expected on ND 4.2 as well, but ND 4.2 has not yet been tested directly.
Not affected:
- Removing some, but not all, entries from an otherwise still-populated vrfs/networks list (e.g. removing 2 of 3 networks while one remains) — that case is handled correctly via the normal per-resource diff mechanism, independent of this defect.
- Greenfield deployments (first-ever run for a given overlay) — there is no pre-existing sentinel to misread in that case.
- MSD fabrics share the same overlay change-detection code path but have not been separately reproduced/validated here — that remains open.
Ansible Playbook
---
- name: Manage VXLAN MCFG Fabric
hosts: all
gather_facts: false
roles:
- role: cisco.nac_dc_vxlan.dtc.create
- role: cisco.nac_dc_vxlan.dtc.deploy
- role: cisco.nac_dc_vxlan.dtc.remove
Data Model
# Previous desired state (already deployed and attached in NDFC)
vxlan:
multisite:
overlay:
vrfs:
- name: VRF01
vlan_id: 3001
vrf_attach_group: all
networks:
- name: Net01
vrf_name: VRF01
vlan_id: 3101
net_id: 130101
network_attach_group: all
vrf_attach_groups:
- name: all
switches: [...]
network_attach_groups:
- name: all
switches: [...]
# Current desired state: VRF01/Net01 removed. The extended/rendered data
# model keeps every overlay key present with an empty list rather than
# removing the "overlay" key itself -- this truthy-dict-of-empty-lists
# shape is what actually reaches the pipeline, and is the specific
# condition that triggers the defect:
vxlan:
multisite:
overlay:
vrfs: []
networks: []
vrf_attach_groups: []
network_attach_groups: []
Steps to Reproduce
- Deploy an MCFG parent fabric with
vxlan.multisite.overlay.vrfs/networks declared and successfully created/attached in NDFC.
- Remove every entry from
vxlan.multisite.overlay.vrfs and .networks (or delete the corresponding data model files/host_vars entries), so both lists become empty.
- Run the create → deploy → remove workflow in diff-run mode (
force_run_all: false).
- Observe the networks/vrfs remove steps report
skipped with reason change flag ... is False, and the overall play reports success with no errors.
- Query NDFC directly and confirm the VRFs/networks are still present and attached.
Relevant Debug Output
{
"module": "dcnm_network",
"reason": "change flag 'changes_detected_networks' is False",
"resource_name": "networks",
"status": "skipped"
},
{
"module": "dcnm_vrf",
"reason": "change flag 'changes_detected_vrfs' is False",
"resource_name": "vrfs",
"status": "skipped"
}
Ansible Version
Ansible Collection Versions
Cisco Nexus Dashboard Version
4.1.1g (NDFC 12.4.1.321)
Cisco NX-OS Version
10.6(2), virtual N9K-C9300v
Which role is this issue related to?
cisco.nac_dc_vxlan.dtc.removeWhich section of the data model is this issue related to?
vxlan.multisiteExpected Behavior
When the final remaining
vxlan.multisite.overlayVRF or network entries are removed and the corresponding list becomes empty for an MCFG fabric, the remove pipeline should detect the change and send the corresponding VRF/network delete requests to NDFC — the same way any other declared-then-removed resource is handled in diff-run mode.Actual Behavior
The collection keeps a small file on disk for each MCFG fabric (the sentinel file,
_msite_overlay_sentinel.yml) to remember what the VRFs/networks looked like last time, so it can tell if anything changed.The function that writes it —
_detect_msite_overlay_changes()(plugins/action/dtc/build_resource_data.py) — doesn't save the data as plain values. Instead of writingname: VRF01, the file ends up with something like this for that same value:That's a Python-specific instruction embedded in the file, not just plain text. The function that reads the file back —
_sentinel_had_key(), same file — deliberately refuses to load files containing that kind of instruction (a normal security precaution, so it never rebuilds arbitrary code from a file). Because of this mismatch, reading the file always fails.That failure is silently ignored instead of being reported. So instead of saying "I couldn't read my saved data," the collection just assumes "there was nothing here before."
This becomes a problem specifically once every VRF/network is removed: the current data doesn't disappear, it just becomes an empty list. The only way to tell "these existed before and were removed" from "there was never anything here" is by checking that saved file — and that check is exactly what's silently failing.
End result: the collection always assumes nothing existed before, so it thinks nothing changed, and it never asks NDFC to delete the VRF/networks. Since nothing fails loudly, the playbook finishes normally as if the removal worked — but the VRF/networks are still attached in NDFC.
Scope
Affected:
vxlan.multisite.overlay.vrfsor.networksentries are removed, so that list becomes empty (e.g. removing the corresponding host_vars files or clearing the lists) in diff-run mode (force_run_all: false). Present since 0.8.0 (confirmed in the0.8.0tag'splugins/action/dtc/build_resource_data.py; the file did not exist prior to0.7.2).Not affected:
Ansible Playbook
Data Model
Steps to Reproduce
vxlan.multisite.overlay.vrfs/networksdeclared and successfully created/attached in NDFC.vxlan.multisite.overlay.vrfsand.networks(or delete the corresponding data model files/host_vars entries), so both lists become empty.force_run_all: false).skippedwith reasonchange flag ... is False, and the overall play reports success with no errors.Relevant Debug Output
{ "module": "dcnm_network", "reason": "change flag 'changes_detected_networks' is False", "resource_name": "networks", "status": "skipped" }, { "module": "dcnm_vrf", "reason": "change flag 'changes_detected_vrfs' is False", "resource_name": "vrfs", "status": "skipped" }