Summary
cisco.dcnm.dcnm_policy crashes with KeyError: 'description' when use_desc_as_key: true and NDFC 12.5 is in use, because NDFC 12.5 no longer includes the description field in policy objects returned by the GET API. The crash is on the self.have dict (the NDFC API response), not the self.want dict.
Affected Version
cisco.dcnm collection, develop branch (version 3.11.0-dev)
- Nexus Dashboard 4.2 / NDFC 12.5
Traceback
File "dcnm_policy.py", line 836, in dcnm_policy_get_diff_merge
File "dcnm_policy.py", line 777, in dcnm_policy_compare_policies
KeyError: 'description'
Root Cause (Verified)
The collection calls dcnm_policy with use_desc_as_key: true. In dcnm_policy_compare_policies():
# Line 769-774: key selection
if policy.get("policyId", None) is not None:
key = "policyId"
elif self.use_desc_as_key:
key = "description" # ← this branch is taken
else:
key = "templateName"
# Line 776-777: the crash
for have in self.have:
if (have[key] == policy[key]) and ( # ← have["description"] → KeyError
self.have is populated from the raw NDFC GET API response (dcnm_policy_get_all_policies()). On NDFC 12.5, the policy GET API omits the description field entirely from policy objects. So have["description"] raises KeyError at line 777.
self.want (the policy argument) is NOT the problem — it's built by dcnm_get_policy_payload_with_template_name() which always sets policy_payload["description"] = pelem["description"], and description has a default of "" in the module's argument spec (line 512). So policy["description"] is always present.
Line 790 (policy["description"]) is a secondary issue — it would also crash if policy ever lacked description, but in practice the current code always sets it. Still, have.get("description", None) == policy["description"] is inconsistent style; using .get() on both sides is safer.
Precise Fix
Line 777 — change have[key] to have.get(key, ""):
# Before
if (have[key] == policy[key]) and (
# After
if (have.get(key, "") == policy.get(key, "")) and (
Line 790 — change policy["description"] to policy.get("description", None):
# Before
if have.get("description", None) == policy["description"]:
# After
if have.get("description", None) == policy.get("description", None):
These changes preserve the existing comparison semantics while tolerating missing description keys in NDFC 12.5 API responses.
Reproduction
- Fabric type:
eBGP_VXLAN
- Task:
cisco.dcnm.dcnm_policy with use_desc_as_key: true, state: merged
- Trigger condition: Policies already exist on the fabric (non-empty
self.have from NDFC GET)
- NDFC 12.5 GET response omits
description key in policy objects → have["description"] → KeyError
Environment
- Nexus Dashboard: 4.2
- NDFC: 12.5
- Ansible: 2.16+
- Python: 3.10
cisco.dcnm: develop branch (3.11.0-dev)
Summary
cisco.dcnm.dcnm_policycrashes withKeyError: 'description'whenuse_desc_as_key: trueand NDFC 12.5 is in use, because NDFC 12.5 no longer includes thedescriptionfield in policy objects returned by the GET API. The crash is on theself.havedict (the NDFC API response), not theself.wantdict.Affected Version
cisco.dcnmcollection,developbranch (version3.11.0-dev)Traceback
Root Cause (Verified)
The collection calls
dcnm_policywithuse_desc_as_key: true. Indcnm_policy_compare_policies():self.haveis populated from the raw NDFC GET API response (dcnm_policy_get_all_policies()). On NDFC 12.5, the policy GET API omits thedescriptionfield entirely from policy objects. Sohave["description"]raisesKeyErrorat line 777.self.want(thepolicyargument) is NOT the problem — it's built bydcnm_get_policy_payload_with_template_name()which always setspolicy_payload["description"] = pelem["description"], anddescriptionhas a default of""in the module's argument spec (line 512). Sopolicy["description"]is always present.Line 790 (
policy["description"]) is a secondary issue — it would also crash ifpolicyever lackeddescription, but in practice the current code always sets it. Still,have.get("description", None) == policy["description"]is inconsistent style; using.get()on both sides is safer.Precise Fix
Line 777 — change
have[key]tohave.get(key, ""):Line 790 — change
policy["description"]topolicy.get("description", None):These changes preserve the existing comparison semantics while tolerating missing
descriptionkeys in NDFC 12.5 API responses.Reproduction
eBGP_VXLANcisco.dcnm.dcnm_policywithuse_desc_as_key: true,state: mergedself.havefrom NDFC GET)descriptionkey in policy objects →have["description"]→KeyErrorEnvironment
cisco.dcnm: develop branch (3.11.0-dev)