Community Note
- Please vote on this issue by adding a 👍 reaction to the original issue to help the community and maintainers prioritize this request
- Please do not leave "+1" or other comments that do not add relevant new information or questions, they generate extra noise for issue followers and do not help prioritize the request
- If you are interested in working on this issue or have submitted a pull request, please leave a comment
Ansible Version and collection version
DCNM version
- Applies to ND 4.1/4.2 (any controller where
is_controller_version_4x is true)
- Symptom observed on ND 4.3 EFT (out of support scope for this collection — see "scope" note below)
Affected module(s)
Problem
Since the fix for #609, when the controller is ND 4.x, FabricUpdateCommon._fabric_needs_update_for_merged_state() (plugins/module_utils/fabric/update.py) builds the update payload by deep-copying the fabric's current nvPairs from the controller GET and overlaying the user's changes, because ND 4.x requires the full parameter set on PUT.
If the fabric was created with a minimal config, the controller stores "" for optional feature-dependent nvPairs (e.g. PTP_DOMAIN_ID, PTP_LB_ID, L3VNI_MCAST_GROUP, AUTO_SYMMETRIC_VRF_LITE, AUTO_SYMMETRIC_DEFAULT_VRF, DEFAULT_VRF_REDIS_BGP_RMAP). A later merged-state task that enables the parent features (FEATURE_PTP, ENABLE_TRM, VRF_LITE_AUTOCONFIG, AUTO_VRFLITE_IFC_DEFAULT_VRF) echoes those dependent parameters back to the controller as "".
This is internally inconsistent: VerifyPlaybookParams passes validation on the assumption that template defaults satisfy the dependency rules, but the payload the module then sends explicitly contradicts those defaults with empty strings. It works on ND 4.1/4.2 only because the legacy API silently populates template defaults for empty dependent fields server-side.
Example failure (ND 4.3 EFT, where the server validates strictly instead of populating defaults):
"DATA": "Invalid JSON response: Failed to update the fabric, due to invalid fields
[{PTP_DOMAIN_ID=, AUTO_SYMMETRIC_VRF_LITE=, PTP_LB_ID=, DEFAULT_VRF_REDIS_BGP_RMAP=,
enableMvpnVriId=, AUTO_SYMMETRIC_DEFAULT_VRF=, L3VNI_MCAST_GROUP=}], please provide valid fields
[{PTP_DOMAIN_ID=0, AUTO_SYMMETRIC_VRF_LITE=false, PTP_LB_ID=0,
DEFAULT_VRF_REDIS_BGP_RMAP=extcon-rmap-filter, enableMvpnVriId=true,
AUTO_SYMMETRIC_DEFAULT_VRF=false, L3VNI_MCAST_GROUP=239.1.1.0}] for fabric-settings",
"MESSAGE": "Bad Request", "METHOD": "PUT",
"REQUEST_PATH": ".../rest/control/fabrics/<fabric>/Easy_Fabric", "RETURN_CODE": 400
Every rejected field is a dependent of a feature the playbook enables, and every suggested value is the fabric template's defaultValue.
Expected Behavior
When building the ND 4.x full payload, the module should substitute the fabric template's default value for nvPairs whose controller-stored value is "", rather than echoing the empty string. The values sent would then match both what VerifyPlaybookParams assumed during validation and what the ND 4.1/4.2 server computes anyway (behavior-neutral on those releases).
Actual Behavior
Empty-string nvPairs are echoed verbatim in the PUT payload.
Steps to Reproduce
state: merged — create a VXLAN_EVPN fabric with only FABRIC_NAME, FABRIC_TYPE, BGP_AS.
state: merged — update the same fabric enabling FEATURE_PTP: true, ENABLE_TRM: true, VRF_LITE_AUTOCONFIG: Back2Back&ToExternal, AUTO_VRFLITE_IFC_DEFAULT_VRF: true without supplying their dependent parameters.
- Inspect the PUT payload (debug log): dependent parameters are sent as
"" while their parent features are enabled.
Proposed fix
The merged-state path already fetches the fabric template from the controller (plugins/modules/dcnm_fabric.py, TemplateGet + VerifyPlaybookParams), and ParamInfo already extracts per-parameter defaults (plugins/module_utils/fabric/param_info.py, _get_default()). Wire the template/ParamInfo into FabricUpdateBulk and, in the ND 4.x full-payload branch, replace "" values with the template default.
Because the defaults come from the controller's own template, version-specific parameters (e.g. enableMvpnVriId) resolve correctly per-controller — no hardcoded key lists to maintain, unlike _remove_nd4x_problematic_keys.
Caution: substitution must not clobber the #622 workaround — STP_BRIDGE_PRIORITY must remain "" when STP_ROOT_OPTION is "unmanaged". This argues for gating substitution on the template's IsShow/dependency rules (the Ruleset machinery already exists) rather than blanket replacement of every empty value that has a default.
Scope note: this collection has no plans to support ND 4.3; the justification for this change is ND 4.1/4.2 correctness/consistency (payload should match what the module's own validation assumed). That it also avoids the strict-validation 400 on newer servers is a side effect.
References
Community Note
Ansible Version and collection version
DCNM version
is_controller_version_4xis true)Affected module(s)
Problem
Since the fix for #609, when the controller is ND 4.x,
FabricUpdateCommon._fabric_needs_update_for_merged_state()(plugins/module_utils/fabric/update.py) builds the update payload by deep-copying the fabric's currentnvPairsfrom the controller GET and overlaying the user's changes, because ND 4.x requires the full parameter set on PUT.If the fabric was created with a minimal config, the controller stores
""for optional feature-dependent nvPairs (e.g.PTP_DOMAIN_ID,PTP_LB_ID,L3VNI_MCAST_GROUP,AUTO_SYMMETRIC_VRF_LITE,AUTO_SYMMETRIC_DEFAULT_VRF,DEFAULT_VRF_REDIS_BGP_RMAP). A later merged-state task that enables the parent features (FEATURE_PTP,ENABLE_TRM,VRF_LITE_AUTOCONFIG,AUTO_VRFLITE_IFC_DEFAULT_VRF) echoes those dependent parameters back to the controller as"".This is internally inconsistent:
VerifyPlaybookParamspasses validation on the assumption that template defaults satisfy the dependency rules, but the payload the module then sends explicitly contradicts those defaults with empty strings. It works on ND 4.1/4.2 only because the legacy API silently populates template defaults for empty dependent fields server-side.Example failure (ND 4.3 EFT, where the server validates strictly instead of populating defaults):
Every rejected field is a dependent of a feature the playbook enables, and every suggested value is the fabric template's
defaultValue.Expected Behavior
When building the ND 4.x full payload, the module should substitute the fabric template's default value for nvPairs whose controller-stored value is
"", rather than echoing the empty string. The values sent would then match both whatVerifyPlaybookParamsassumed during validation and what the ND 4.1/4.2 server computes anyway (behavior-neutral on those releases).Actual Behavior
Empty-string nvPairs are echoed verbatim in the PUT payload.
Steps to Reproduce
state: merged— create a VXLAN_EVPN fabric with onlyFABRIC_NAME,FABRIC_TYPE,BGP_AS.state: merged— update the same fabric enablingFEATURE_PTP: true,ENABLE_TRM: true,VRF_LITE_AUTOCONFIG: Back2Back&ToExternal,AUTO_VRFLITE_IFC_DEFAULT_VRF: truewithout supplying their dependent parameters.""while their parent features are enabled.Proposed fix
The merged-state path already fetches the fabric template from the controller (
plugins/modules/dcnm_fabric.py,TemplateGet+VerifyPlaybookParams), andParamInfoalready extracts per-parameter defaults (plugins/module_utils/fabric/param_info.py,_get_default()). Wire the template/ParamInfointoFabricUpdateBulkand, in the ND 4.x full-payload branch, replace""values with the template default.Because the defaults come from the controller's own template, version-specific parameters (e.g.
enableMvpnVriId) resolve correctly per-controller — no hardcoded key lists to maintain, unlike_remove_nd4x_problematic_keys.Caution: substitution must not clobber the #622 workaround —
STP_BRIDGE_PRIORITYmust remain""whenSTP_ROOT_OPTIONis"unmanaged". This argues for gating substitution on the template's IsShow/dependency rules (theRulesetmachinery already exists) rather than blanket replacement of every empty value that has a default.Scope note: this collection has no plans to support ND 4.3; the justification for this change is ND 4.1/4.2 correctness/consistency (payload should match what the module's own validation assumed). That it also avoids the strict-validation 400 on newer servers is a side effect.
References