diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 000000000..d969f962b --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,5 @@ +{ + "python.testing.pytestArgs": ["tests"], + "python.testing.unittestEnabled": false, + "python.testing.pytestEnabled": true +} diff --git a/docs/cisco.dcnm.dcnm_interface_module.rst b/docs/cisco.dcnm.dcnm_interface_module.rst index 02282465f..e110d59ff 100644 --- a/docs/cisco.dcnm.dcnm_interface_module.rst +++ b/docs/cisco.dcnm.dcnm_interface_module.rst @@ -681,15 +681,7 @@ Parameters - + Default:
"Auto"
Speed of the interface.
diff --git a/docs/cisco.dcnm.dcnm_policy_module.rst b/docs/cisco.dcnm.dcnm_policy_module.rst index 8324e8522..3871646ac 100644 --- a/docs/cisco.dcnm.dcnm_policy_module.rst +++ b/docs/cisco.dcnm.dcnm_policy_module.rst @@ -347,6 +347,26 @@ Parameters
The required state of the configuration after module completion.
+ + +
+ use_desc_as_key + +
+ boolean +
+ + + + + +
Flag to enforce using the description parameter as the unique key for policy management.
+
When set to True, the description parameter must be unique and non-empty for each policy in the playbook. The module will also use the description to find the policy to modify or delete. If exsiting policies have the same description, the module will raise an error. If the existing policy with the matching description is using differnet template name, the module will delete the existing policy and create a new one.
+ +
@@ -535,6 +555,46 @@ Examples - switch: - ip: "{{ ansible_switch1 }}" + # Use the description as key + + # NOTE: As the description of the policy in NDFC/DCNM is not unique, + # the user must make sure no policies with the same description are created on NDFC out of the playbook. + # If the description is not unique, the module will raise an error. + + ## Below task will create policies with description "policy_radius" on swtich1, switch2 and switch3, + ## and only create policy "feature bfd" and "feature bash-shell" on the switch1 only + + - name: Create policies + cisco.dcnm.dcnm_policy: + fabric: fabric_prod + use_desc_as_key: true + config: + - name: switch_freeform + create_additional_policy: false + description: policy_radius + policy_vars: + CONF: | + radius-server host 10.1.1.2 key 7 "ljw3976!" authentication accounting + - switch: + - ip: "{{ switch1 }}" + policies: + - name: switch_freeform + create_additional_policy: false + priority: 101 + description: feature bfd + policy_vars: + CONF: | + feature bfd + - name: switch_freeform + create_additional_policy: false + priority: 102 + description: feature bash-shell + policy_vars: + CONF: | + feature bash-shell + - ip: "{{ switch2 }}" + - ip: "{{ switch3 }}" + diff --git a/plugins/modules/dcnm_policy.py b/plugins/modules/dcnm_policy.py index 9bdd101a6..42d2ae29d 100644 --- a/plugins/modules/dcnm_policy.py +++ b/plugins/modules/dcnm_policy.py @@ -44,6 +44,17 @@ - query default: merged + use_desc_as_key: + description: + - Flag to enforce using the description parameter as the unique key for policy management. + - When set to True, the description parameter must be unique and non-empty for each policy in the playbook. + The module will also use the description to find the policy to modify or delete. + If exsiting policies have the same description, the module will raise an error. + If the existing policy with the matching description is using differnet template name, the module will delete the existing policy and create a new one. + type: bool + required: false + default: false + deploy: description: - A flag specifying if a policy is to be deployed on the switches @@ -338,6 +349,46 @@ - name: POLICY-103103 - switch: - ip: "{{ ansible_switch1 }}" + +# Use the description as key + +# NOTE: As the description of the policy in NDFC/DCNM is not unique, +# the user must make sure no policies with the same description are created on NDFC out of the playbook. +# If the description is not unique, the module will raise an error. + +## Below task will create policies with description "policy_radius" on swtich1, switch2 and switch3, +## and only create policy "feature bfd" and "feature bash-shell" on the switch1 only + +- name: Create policies + cisco.dcnm.dcnm_policy: + fabric: fabric_prod + use_desc_as_key: true + config: + - name: switch_freeform + create_additional_policy: false + description: policy_radius + policy_vars: + CONF: | + radius-server host 10.1.1.2 key 7 "ljw3976!" authentication accounting + - switch: + - ip: "{{ switch1 }}" + policies: + - name: switch_freeform + create_additional_policy: false + priority: 101 + description: feature bfd + policy_vars: + CONF: | + feature bfd + - name: switch_freeform + create_additional_policy: false + priority: 102 + description: feature bash-shell + policy_vars: + CONF: | + feature bash-shell + - ip: "{{ switch2 }}" + - ip: "{{ switch3 }}" """ import json @@ -363,6 +414,7 @@ class DcnmPolicy: "POLICY_WITH_ID": "/rest/control/policies/{}", "POLICY_GET_SWITCHES": "/rest/control/policies/switches?serialNumber={}", "POLICY_BULK_CREATE": "/rest/control/policies/bulk-create", + "POLICY_BULK_UPDATE": "/rest/control/policies/{}/bulk", "POLICY_MARK_DELETE": "/rest/control/policies/{}/mark-delete", "POLICY_DEPLOY": "/rest/control/policies/deploy", "POLICY_CFG_DEPLOY": "/rest/control/fabrics/{}/config-deploy/", @@ -373,6 +425,7 @@ class DcnmPolicy: "POLICY_WITH_ID": "/appcenter/cisco/ndfc/api/v1/lan-fabric/rest/control/policies/{}", "POLICY_GET_SWITCHES": "/appcenter/cisco/ndfc/api/v1/lan-fabric/rest/control/policies/switches?serialNumber={}", "POLICY_BULK_CREATE": "/appcenter/cisco/ndfc/api/v1/lan-fabric/rest/control/policies/bulk-create", + "POLICY_BULK_UPDATE": "/appcenter/cisco/ndfc/api/v1/lan-fabric/rest/control/policies/{}/bulk", "POLICY_MARK_DELETE": "/appcenter/cisco/ndfc/api/v1/lan-fabric/rest/control/policies/{}/mark-delete", "POLICY_DEPLOY": "/appcenter/cisco/ndfc/api/v1/lan-fabric/rest/control/policies/deploy", "POLICY_CFG_DEPLOY": "/appcenter/cisco/ndfc/api/v1/lan-fabric/rest/control/fabrics/{}/config-deploy/", @@ -385,6 +438,7 @@ def __init__(self, module): self.module = module self.params = module.params self.fabric = module.params["fabric"] + self.use_desc_as_key = module.params["use_desc_as_key"] self.config = copy.deepcopy(module.params.get("config")) self.deploy = True # Global 'deploy' flag self.pb_input = [] @@ -458,6 +512,8 @@ def dcnm_policy_validate_input(self): switch=dict(required=True, type="list"), ) + desc_hash = {} # hash table to store the count of policy descriptions + for cfg in self.config: clist = [] @@ -470,7 +526,30 @@ def dcnm_policy_validate_input(self): cfg["name"], invalid_params ) self.module.fail_json(msg=mesg) + if self.use_desc_as_key: + # Fail the module when use_desc_as_key is True but description is not given or empty + if cfg.get("description", "") == "": + mesg = f"description can't be empty when use_desc_as_key is True: {cfg}" + self.module.fail_json(msg=mesg) + # Count the occurance of the "description|switch" + for sw in cfg["switch"]: + if desc_hash.get(f"{cfg['description']}|{sw}", -1) == -1: + desc_hash[f"{cfg['description']}|{sw}"] = 1 + else: + desc_hash[f"{cfg['description']}|{sw}"] += 1 + self.policy_info.extend(policy_info) + # Find the duplicated description per swtich + dup_desc = [] + for desc in desc_hash.keys(): + if desc_hash[desc] == 1: + continue + dup_desc.append( + f"description: {desc.split('|')[0]}, switch: {desc.split('|')[1]}" + ) + if dup_desc != []: + mesg = f"duplicated description found: description: {dup_desc}" + self.module.fail_json(msg=mesg) def dcnm_get_policy_payload_with_template_name(self, pelem, sw): @@ -637,12 +716,26 @@ def dcnm_policy_get_have(self): pl for pl in plist for wp in self.want - if (pl["templateName"] == wp["templateName"]) + # exclude the policies that have the source + # when the user modifies a policy but has not deployed the policy, + # a sub-policy might be created with the same description, but marked as deleted + # The signature of this kind of policy is that it as a original policyId as the source + # it should be excluded from the match list + # as the policy will be deleted once the user deploys the configuration + if pl.get("source", "") == "" + and ( + (pl["templateName"] == wp["templateName"]) + or ( + not self.use_desc_as_key + or (pl.get("description") == wp.get("description", "")) + ) + ) ] # match_pol can be a list of dicts, containing duplicates. Remove the duplicate entries + # also exclude the policies that are marked for deletion for pol in match_pol: - if pol not in self.have: + if pol not in self.have and not pol.get("deleted", True): self.have.append(pol) def dcnm_policy_compare_nvpairs(self, pnv, hnv): @@ -658,8 +751,12 @@ def dcnm_policy_compare_nvpairs(self, pnv, hnv): return "DCNM_POLICY_MATCH" def dcnm_policy_compare_policies(self, policy): - - found = False + # use list to instead of boolean + # need to handle two templates associated with switch have the same description + # when use_desc_as_key is true, raise error + found = [] + match = False + template_changed = False if self.have == []: return ("DCNM_POLICY_ADD_NEW", None) @@ -669,6 +766,8 @@ def dcnm_policy_compare_policies(self, policy): if policy.get("policyId", None) is not None: key = "policyId" + elif self.use_desc_as_key: + key = "description" else: key = "templateName" @@ -676,8 +775,16 @@ def dcnm_policy_compare_policies(self, policy): if (have[key] == policy[key]) and ( have.get("serialNumber", None) == policy["serialNumber"] ): - found = True - # Have a policy with matching template name. Check for other objects + found.append(have) + # if use description as key, use policyId got from the target + # if templateName is changed, remove the original policy and create a new one + if self.use_desc_as_key: + policy["policyId"] = have.get("policyId") + if have["templateName"] != policy["templateName"]: + template_changed = True + continue + + # Have a policy with matching key. Check for other objects if have.get("description", None) == policy["description"]: if have.get("priority", None) == policy["priority"]: if ( @@ -687,11 +794,22 @@ def dcnm_policy_compare_policies(self, policy): ) == "DCNM_POLICY_MATCH" ): - return ("DCNM_POLICY_DONT_ADD", have["policyId"]) - if found is True: + match = True + + if len(found) == 1 and not match and not template_changed: # Found a matching policy with the given template name, but other objects don't match. # Go ahead and merge the objects into the existing policy - return ("DCNM_POLICY_MERGE", have["policyId"]) + return ("DCNM_POLICY_MERGE", found[0]["policyId"]) + elif len(found) == 1 and not match and template_changed: + return ("DCNM_POLICY_TEMPLATE_CHANGED", found[0]["policyId"]) + elif len(found) == 1 and match: + return ("DCNM_POLICY_DONT_ADD", found[0]["policyId"]) + elif len(found) > 1 and self.use_desc_as_key: + # module will raise error when duplicated description is found + return ("DCNM_POLICY_DUPLICATED", None) + elif len(found) > 1 and not self.use_desc_as_key: + # if not using description as the key, new + return ("DCNM_POLICY_DONT_ADD", found[0]["policyId"]) else: return ("DCNM_POLICY_ADD_NEW", None) @@ -715,7 +833,11 @@ def dcnm_policy_get_diff_merge(self): rc, policy_id = self.dcnm_policy_compare_policies(policy) - if rc == "DCNM_POLICY_ADD_NEW": + if rc == "DCNM_POLICY_DUPLICATED": + self.module.fail_json( + f"Multiple policies found with the same description in DCNM/NDFC: {self.use_desc_as_key}, {policy['description']}" + ) + elif rc == "DCNM_POLICY_ADD_NEW": # A policy does not exists, create a new one. Even if one exists, if create_additional_policy # is specified, then create the policy if (policy not in self.diff_create) or ( @@ -730,6 +852,11 @@ def dcnm_policy_get_diff_merge(self): # will not know which policy the user is referring to. In the case where a user is providing # a templateName and we are here, ignore the policy. if policy.get("policyId", None) is not None: + # id is needed for policy update + id = policy["policyId"].split("-")[1] + policy["id"] = id + policy["policy_id_given"] = True + if policy not in self.diff_modify: self.changed_dict[0]["merged"].append(policy) self.diff_modify.append(policy) @@ -760,6 +887,27 @@ def dcnm_policy_get_diff_merge(self): self.changed_dict[0]["merged"].append(policy) self.diff_create.append(policy) policy_id = None + elif rc == "DCNM_POLICY_TEMPLATE_CHANGED": + # A policy exists and the template name is changed + # Remove the existing policy and create a new one + + pinfo = self.dcnm_policy_get_policy_info_from_dcnm(policy["policyId"]) + prev_template_name = policy["templateName"] + if pinfo != []: + prev_template_name = pinfo["templateName"] + + del_payload = self.dcnm_policy_get_delete_payload(policy) + if del_payload not in self.diff_delete: + self.diff_delete.append(del_payload) + self.changed_dict[0]["deleted"].append( + { + "policy": policy["policyId"], + "templateName": prev_template_name, + } + ) + policy.pop("policyId") + self.changed_dict[0]["merged"].append(policy) + self.diff_create.append(policy) # Check the 'deploy' flag and decide if this policy is to be deployed if self.deploy is True: @@ -814,13 +962,22 @@ def dcnm_policy_get_diff_deleted(self): for pl in plist for wp in self.want if ( - (wp["policy_id_given"] is False) - and (pl["templateName"] == wp["templateName"]) - or (wp["policy_id_given"] is True) - and (pl["policyId"] == wp["policyId"]) + not pl["deleted"] + and ( + (wp["policy_id_given"] is False) + and (pl["templateName"] == wp["templateName"]) + and ( + # When use_desc_as_key is True, only add the policy match the description + not self.use_desc_as_key + or (pl.get("description", "") == wp.get("description", "")) + ) + ) + or ( + (wp["policy_id_given"] is True) + and (pl["policyId"] == wp["policyId"]) + ) ) ] - # match_pol contains all the policies which exist and are to be deleted # Build the delete payloads @@ -875,7 +1032,7 @@ def dcnm_policy_get_diff_query(self): self.result["response"].append(pinfo) else: # templateName is given. Note this down - match_templates.append(cfg["name"]) + match_templates.append(cfg) if (get_specific_policies is False) or (match_templates != []): @@ -890,12 +1047,16 @@ def dcnm_policy_get_diff_query(self): match_pol = [ pl for pl in plist - for mt_name in match_templates - if (pl["templateName"] == mt_name) + for mt in match_templates + if (pl["templateName"] == mt["name"]) + # When use_desc_as_key is True, only add the policy match the description + and ( + not self.use_desc_as_key + or pl.get("description", "") == mt["description"] + ) ] else: match_pol = plist - if match_pol: # match_pol contains all the policies which exist and match the given templates self.changed_dict[0]["query"].extend( @@ -943,6 +1104,35 @@ def dcnm_policy_create_policy(self, policy, command): return resp + def dcnm_policy_update_policy(self, policy, command): + + path = self.paths["POLICY_BULK_UPDATE"].format(policy["policyId"]) + + json_payload = json.dumps([policy]) + + retries = 0 + while retries < 3: + resp = dcnm_send(self.module, command, path, json_payload) + + if ( + (resp.get("DATA", None) is not None) + and (isinstance(resp["DATA"], dict)) + and (resp["DATA"].get("failureList", None) is not None) + ): + if isinstance(resp["DATA"]["failureList"], list): + fl = resp["DATA"]["failureList"][0] + else: + fl = resp["DATA"]["failureList"] + + if "is not unique" in fl.get("message", ""): + retries = retries + 1 + continue + break + + self.result["response"].append(resp) + + return resp + def dcnm_policy_delete_policy(self, policy, mark_del): if mark_del is True: @@ -1137,7 +1327,8 @@ def dcnm_policy_send_message_to_dcnm(self): for policy in self.diff_modify: # POP the 'create_additional_policy' object before sending create policy.pop("create_additional_policy") - resp = self.dcnm_policy_create_policy(policy, "PUT") + policy.pop("policy_id_given", "") + resp = self.dcnm_policy_update_policy(policy, "PUT") if isinstance(resp, list): resp = resp[0] if ( @@ -1231,8 +1422,9 @@ def dcnm_translate_config(self, config): cfg["switch"] = [] if sw["ip"] not in cfg["switch"]: cfg["switch"].append(sw["ip"]) - - if config: + # if use_desc_as_key is true, don't override the policy with the same templateName + # the per-switch polices will be simpliy merged with global policies config + if config and not self.use_desc_as_key: updated_config = [] for ovr_cfg in override_config: for cfg in config: @@ -1251,7 +1443,7 @@ def dcnm_translate_config(self, config): updated_config.append(cfg) config = updated_config else: - config = override_config + config += override_config return config @@ -1262,6 +1454,7 @@ def main(): element_spec = dict( fabric=dict(required=True, type="str"), config=dict(required=False, type="list", elements="dict"), + use_desc_as_key=dict(required=False, type="bool", default=False), state=dict( type="str", default="merged", @@ -1310,11 +1503,7 @@ def main(): if module.params["state"] != "query": # Translate the given playbook config to some convenient format. Each policy should # have the switches to be deployed. - - dcnm_policy.config = dcnm_policy.dcnm_translate_config( - dcnm_policy.config - ) - + dcnm_policy.config = dcnm_policy.dcnm_translate_config(dcnm_policy.config) # See if this is required dcnm_policy.dcnm_policy_copy_config() dcnm_policy.dcnm_policy_validate_input() diff --git a/tests/unit/modules/dcnm/fixtures/dcnm_policy_configs.json b/tests/unit/modules/dcnm/fixtures/dcnm_policy_configs.json index e52937e55..be4909828 100644 --- a/tests/unit/modules/dcnm/fixtures/dcnm_policy_configs.json +++ b/tests/unit/modules/dcnm/fixtures/dcnm_policy_configs.json @@ -1,7 +1,7 @@ { "create_policy_125_127_with_vars": [ - { - "create_additional_policy": false, + { + "create_additional_policy": false, "name": "template_125", "description": "125 - policy with vars", "priority": 125, @@ -9,472 +9,543 @@ "OSPF_TAG": 2000, "LOOPBACK_IP": "10.10.10.108" } - }, - { - "create_additional_policy": false, - "name": "template_126", - "description": "126 - policy with vars", - "priority": 126, - "policy_vars": { - "OSPF_TAG": 3000, - "LOOPBACK_IP": "10.10.10.109" - } - }, - { - "create_additional_policy": false, - "name": "template_127", - "description": "127 - policy with vars", - "priority": 127, - "policy_vars": { - "OSPF_TAG": 4000, - "LOOPBACK_IP": "10.10.10.110" - } - }, - { - "switch": [ + }, + { + "create_additional_policy": false, + "name": "template_126", + "description": "126 - policy with vars", + "priority": 126, + "policy_vars": { + "OSPF_TAG": 3000, + "LOOPBACK_IP": "10.10.10.109" + } + }, + { + "create_additional_policy": false, + "name": "template_127", + "description": "127 - policy with vars", + "priority": 127, + "policy_vars": { + "OSPF_TAG": 4000, + "LOOPBACK_IP": "10.10.10.110" + } + }, { - "ip": "10.10.10.224" + "switch": [ + { + "ip": "10.10.10.224" + } + ] } - ] - }], + ], "create_policy_multi_switch_101_105": [ - { - "create_additional_policy": false, - "name": "template_101", - "priority": 101 - }, - { - "create_additional_policy": false, - "description": "102 - No piority given", - "name": "template_102" - }, - { - "create_additional_policy": false, - "description": "Both description and priority given", - "name": "template_103", - "priority": 500 - }, - { - "switch": [ - { - "ip": "10.10.10.224", - "policies": [ - { - "create_additional_policy": false, - "name": "template_104" - }, - { - "create_additional_policy": false, - "name": "template_105" - } - ] + { + "create_additional_policy": false, + "name": "template_101", + "priority": 101 + }, + { + "create_additional_policy": false, + "description": "102 - No piority given", + "name": "template_102" }, { - "ip": "10.10.10.225" + "create_additional_policy": false, + "description": "Both description and priority given", + "name": "template_103", + "priority": 500 }, { - "ip": "10.10.10.226" + "switch": [ + { + "ip": "10.10.10.224", + "policies": [ + { + "create_additional_policy": false, + "name": "template_104" + }, + { + "create_additional_policy": false, + "name": "template_105" + } + ] + }, + { + "ip": "10.10.10.225" + }, + { + "ip": "10.10.10.226" + } + ] } - ] - }], + ], "create_policy_101_101_5": [ - { - "create_additional_policy": false, - "name": "template_101", - "priority": 101, - "description": "Create again even if it exists" - }, - { - "create_additional_policy": false, - "description": "101 - No piority given", - "name": "template_101" - }, - { - "create_additional_policy": false, - "description": "Both description and priority given", - "name": "template_101", - "priority": 500 - }, - { - "switch": [ - { - "ip": "10.10.10.224", - "policies": [ - { - "create_additional_policy": false, - "name": "template_101", - "description": "description changed" - }, - { - "create_additional_policy": false, - "name": "template_101", - "description": "description changed to verify merge" - } - ] + { + "create_additional_policy": false, + "name": "template_101", + "priority": 101, + "description": "Create again even if it exists" + }, + { + "create_additional_policy": false, + "description": "101 - No piority given", + "name": "template_101" + }, + { + "create_additional_policy": false, + "description": "Both description and priority given", + "name": "template_101", + "priority": 500 }, { - "ip": "10.10.10.224" + "switch": [ + { + "ip": "10.10.10.224", + "policies": [ + { + "create_additional_policy": false, + "name": "template_101", + "description": "description changed" + }, + { + "create_additional_policy": false, + "name": "template_101", + "description": "description changed to verify merge" + } + ] + }, + { + "ip": "10.10.10.224" + } + ] } - ] - }], + ], - "modify_policy_125_with_vars" : [ - { - "create_additional_policy": false, - "name": "POLICY-125125", - "priority": 125, - "policy_vars": { - "OSPF_TAG": 2000, - "LOOPBACK_IP": "11.11.11.108" - } - }, - { - "switch": [ + "modify_policy_125_with_vars": [ { - "ip": "10.10.10.224" + "create_additional_policy": false, + "name": "POLICY-125125", + "priority": 125, + "policy_vars": { + "OSPF_TAG": 2000, + "LOOPBACK_IP": "11.11.11.108" + } + }, + { + "switch": [ + { + "ip": "10.10.10.224" + } + ] } - ] - }], + ], "create_policy_101_105": [ - { - "create_additional_policy": false, - "name": "template_101", - "priority": 101 - }, - { - "create_additional_policy": false, - "description": "102 - No piority given", - "name": "template_102" - }, - { - "create_additional_policy": false, - "description": "Both description and priority given", - "name": "template_103", - "priority": 500 - }, - { - "switch": [ - { - "ip": "10.10.10.224", - "policies": [ - { - "create_additional_policy": false, - "name": "template_104" - }, - { - "create_additional_policy": false, - "name": "template_105" - } + { + "create_additional_policy": false, + "name": "template_101", + "description": "policy101", + "priority": 101 + }, + { + "create_additional_policy": false, + "description": "policy102", + "name": "template_102" + }, + { + "create_additional_policy": false, + "name": "template_103", + "description": "policy103", + "priority": 500 + }, + { + "switch": [ + { + "ip": "10.10.10.224", + "policies": [ + { + "create_additional_policy": false, + "name": "template_104", + "description": "policy104" + }, + { + "create_additional_policy": false, + "name": "template_105", + "description": "policy105" + } + ] + }, + { + "ip": "10.10.10.224" + } ] + } + ], + + "modify_policy_101_102": [ + { + "create_additional_policy": false, + "name": "template_101_1", + "description": "policy101", + "priority": 101 }, { - "ip": "10.10.10.224" + "create_additional_policy": false, + "description": "policy102", + "name": "template_102_1" + }, + { + "switch": [ + { + "ip": "10.10.10.224" + } + ] } - ] - }], + ], "create_policy_101_105_5": [ - { - "create_additional_policy": false, - "name": "template_101", - "priority": 101 - }, - { - "create_additional_policy": false, - "description": "102 - No piority given", - "name": "template_102" - }, - { - "create_additional_policy": false, - "description": "Both description and priority given", - "name": "template_103", - "priority": 500 - }, - { - "switch": [ - { - "ip": "10.10.10.224", - "policies": [ - { - "create_additional_policy": false, - "name": "template_101", - "description": "Description override - 10.10.10.225" - }, - { - "create_additional_policy": false, - "name": "template_102", - "description": "Description override - 10.10.10.225" - } - ] + { + "create_additional_policy": false, + "name": "template_101", + "priority": 101 }, { - "ip": "10.10.10.225", - "policies": [ - { - "create_additional_policy": false, - "name": "template_101", - "description": "Description override - 10.10.10.225" - }, - { - "create_additional_policy": false, - "name": "template_102", - "description": "Description override - 10.10.10.225" - } - ] + "create_additional_policy": false, + "description": "102 - No piority given", + "name": "template_102" }, { - "ip": "10.10.10.226", - "policies": [ - { - "create_additional_policy": false, - "name": "template_104", - "description": "Description override - 10.10.10.225" - }, - { - "create_additional_policy": false, - "name": "template_105", - "description": "Description override - 10.10.10.225" - } - ] + "create_additional_policy": false, + "description": "Both description and priority given", + "name": "template_103", + "priority": 500 }, { - "ip": "10.10.10.226" + "switch": [ + { + "ip": "10.10.10.224", + "policies": [ + { + "create_additional_policy": false, + "name": "template_101", + "description": "Description override - 10.10.10.225" + }, + { + "create_additional_policy": false, + "name": "template_102", + "description": "Description override - 10.10.10.225" + } + ] + }, + { + "ip": "10.10.10.225", + "policies": [ + { + "create_additional_policy": false, + "name": "template_101", + "description": "Description override - 10.10.10.225" + }, + { + "create_additional_policy": false, + "name": "template_102", + "description": "Description override - 10.10.10.225" + } + ] + }, + { + "ip": "10.10.10.226", + "policies": [ + { + "create_additional_policy": false, + "name": "template_104", + "description": "Description override - 10.10.10.225" + }, + { + "create_additional_policy": false, + "name": "template_105", + "description": "Description override - 10.10.10.225" + } + ] + }, + { + "ip": "10.10.10.226" + } + ] } - ] - }], + ], "create_policy_without_state_104_105": [ - { - "switch": [ - { - "ip": "10.10.10.224", - "policies": [ - { - "create_additional_policy": false, - "name": "template_104" - }, - { - "create_additional_policy": false, - "name": "template_105" - } + { + "switch": [ + { + "ip": "10.10.10.224", + "policies": [ + { + "create_additional_policy": false, + "name": "template_104" + }, + { + "create_additional_policy": false, + "name": "template_105" + } + ] + }, + { + "ip": "10.10.10.225" + } ] + } + ], + + "create_policy_additional_flags_104": [ + { + "create_additional_policy": true, + "description": "create template_104", + "name": "template_104", + "priority": 104 + }, + { + "create_additional_policy": true, + "description": "create template_104", + "name": "template_104", + "priority": 104 }, { - "ip": "10.10.10.225" + "switch": [ + { + "ip": "10.10.10.224" + } + ] } - ] - }], + ], - "create_policy_additional_flags_104" : [ - { - "create_additional_policy": true, - "description": "create template_104", - "name": "template_104", - "priority": 104 - }, - { - "create_additional_policy": true, - "description": "create template_104", - "name": "template_104", - "priority": 104 - }, - { - "switch": [ - { - "ip": "10.10.10.224" + "modify_policy_104_with_policy_id": [ + { + "create_additional_policy": false, + "description": "modifying policy with policy ID", + "name": "POLICY-123840", + "priority": 904 + }, + { + "switch": [ + { + "ip": "10.10.10.224" + } + ] } - ] - }], + ], - "modify_policy_104_with_policy_id" : [ - { - "create_additional_policy": false, - "description": "modifying policy with policy ID", - "name": "POLICY-123840", - "priority": 904 - }, - { - "switch": [ - { - "ip": "10.10.10.224" + "modify_policy_104_with_template_name": [ + { + "create_additional_policy": false, + "description": "modifying policy with template name", + "name": "template_104", + "priority": 904 + }, + { + "switch": [ + { + "ip": "10.10.10.224" + } + ] } - ] - }], + ], - "modify_policy_104_with_template_name" : [ - { - "create_additional_policy": false, - "description": "modifying policy with template name", - "name": "template_104", - "priority": 904 - }, - { - "switch": [ - { - "ip": "10.10.10.224" + "create_policy_no_deploy_104": [ + { + "create_additional_policy": false, + "description": "create template_104", + "name": "template_104", + "priority": 104 + }, + { + "switch": [ + { + "ip": "10.10.10.224" + } + ] } - ] - }], + ], - "create_policy_no_deploy_104" : [ - { - "create_additional_policy": false, - "description": "create template_104", - "name": "template_104", - "priority": 104 - }, - { - "switch": [ - { - "ip": "10.10.10.224" + "create_policy_wrong_state_104": [ + { + "create_additional_policy": false, + "description": "create template_104", + "name": "template_104", + "priority": 104 + }, + { + "switch": [ + { + "ip": "10.10.10.224" + } + ] } - ] - }], + ], - "create_policy_wrong_state_104" : [ - { - "create_additional_policy": false, - "description": "create template_104", - "name": "template_104", - "priority": 104 - }, - { - "switch": [ - { - "ip": "10.10.10.224" + "delete_policy_template_name_101_105": [ + { + "name": "template_101" + }, + { + "name": "template_102" + }, + { + "name": "template_103" + }, + { + "name": "template_104" + }, + { + "name": "template_105" + }, + { + "switch": [ + { + "ip": "10.10.10.224" + } + ] } - ] - }], - - "delete_policy_template_name_101_105" : [ - { - "name": "template_101" - }, - { - "name": "template_102" - }, - { - "name": "template_103" - }, - { - "name": "template_104" - }, - { - "name": "template_105" - }, - { - "switch": [ - { - "ip": "10.10.10.224" + ], + "delete_policy_template_desc_101_105": [ + { + "name": "template_101", + "description": "policy101" + }, + { + "name": "template_102", + "description": "policy102" + }, + { + "name": "template_103", + "description": "policy103" + }, + { + "name": "template_104", + "description": "policy104" + }, + { + "name": "template_105", + "description": "policy105" + }, + { + "switch": [ + { + "ip": "10.10.10.224" + } + ] } - ] - }], + ], - "delete_policy_policy_id_101_105" : [ - { - "name": "POLICY-101101" - }, - { - "name": "POLICY-102102" - }, - { - "name": "POLICY-103103" - }, - { - "name": "POLICY-104104" - }, - { - "name": "POLICY-105105" - }, - { - "switch": [ - { - "ip": "10.10.10.224" + "delete_policy_policy_id_101_105": [ + { + "name": "POLICY-101101" + }, + { + "name": "POLICY-102102" + }, + { + "name": "POLICY-103103" + }, + { + "name": "POLICY-104104" + }, + { + "name": "POLICY-105105" + }, + { + "switch": [ + { + "ip": "10.10.10.224" + } + ] } - ] - }], + ], - "delete_policy_template_name_multi" : [ - { - "name": "template_101" - }, - { - "name": "template_102" - }, - { - "name": "template_103" - }, - { - "name": "template_104" - }, - { - "name": "template_105" - }, - { - "switch": [ - { - "ip": "10.10.10.224" + "delete_policy_template_name_multi": [ + { + "name": "template_101" + }, + { + "name": "template_102" + }, + { + "name": "template_103" + }, + { + "name": "template_104" + }, + { + "name": "template_105" + }, + { + "switch": [ + { + "ip": "10.10.10.224" + } + ] } - ] - }], + ], - "query_policy_with_switch_info" : [ - { - "switch": [ + "query_policy_with_switch_info": [ { - "ip": "10.10.10.224" + "switch": [ + { + "ip": "10.10.10.224" + } + ] } - ] - }], + ], - "query_policy_with_policy_id" : [ - { - "name": "POLICY-101101" - }, - { - "name": "POLICY-102102" - }, - { - "name": "POLICY-103103" - }, - { - "name": "POLICY-104104" - }, - { - "name": "POLICY-105105" - }, - { - "switch": [ - { - "ip": "10.10.10.224" + "query_policy_with_policy_id": [ + { + "name": "POLICY-101101" + }, + { + "name": "POLICY-102102" + }, + { + "name": "POLICY-103103" + }, + { + "name": "POLICY-104104" + }, + { + "name": "POLICY-105105" + }, + { + "switch": [ + { + "ip": "10.10.10.224" + } + ] } - ] - }], + ], - "query_policy_with_template_name" : [ - { - "name": "template_101" - }, - { - "name": "template_102" - }, - { - "name": "template_103" - }, - { - "name": "template_104" - }, - { - "name": "template_105" - }, - { - "switch": [ - { - "ip": "10.10.10.224" + "query_policy_with_template_name": [ + { + "name": "template_101" + }, + { + "name": "template_102" + }, + { + "name": "template_103" + }, + { + "name": "template_104" + }, + { + "name": "template_105" + }, + { + "switch": [ + { + "ip": "10.10.10.224" + } + ] } - ] - }] + ] } diff --git a/tests/unit/modules/dcnm/fixtures/dcnm_policy_payloads.json b/tests/unit/modules/dcnm/fixtures/dcnm_policy_payloads.json index 81c4a51ff..d954ded59 100644 --- a/tests/unit/modules/dcnm/fixtures/dcnm_policy_payloads.json +++ b/tests/unit/modules/dcnm/fixtures/dcnm_policy_payloads.json @@ -639,182 +639,183 @@ "REQUEST_PATH": "https://10.64.78.151:443/rest/control/policies/switches?serialNumber=XYZKSJHSMK1", "MESSAGE": "OK", "DATA": [ - { - "id": 101101, - "policyId": "POLICY-101101", - "description": "", - "serialNumber": "XYZKSJHSMK1", - "entityType": "SWITCH", - "entityName": "SWITCH", - "templateName": "template_101", - "templateContentType": "TEMPLATE_CLI", - "nvPairs": { - "FABRIC_NAME": "mmudigon" - }, - "autoGenerated": false, - "deleted": false, - "source": "", - "priority": 101, - "status": "NA", - "statusOn": 1605693124239, - "createdOn": 1605693124239, - "modifiedOn": 1605693124239, - "fabricName": "mmudigon" - }, - { - "id": 101201, - "policyId": "POLICY-101201", - "description": "", - "serialNumber": "XYZKSJHSMK1", - "entityType": "SWITCH", - "entityName": "SWITCH", - "templateName": "template_101", - "templateContentType": "TEMPLATE_CLI", - "nvPairs": { - "FABRIC_NAME": "mmudigon" - }, - "autoGenerated": false, - "deleted": false, - "source": "", - "priority": 101, - "status": "NA", - "statusOn": 1605693124239, - "createdOn": 1605693124239, - "modifiedOn": 1605693124239, - "fabricName": "mmudigon" - }, - { - "id": 101301, - "policyId": "POLICY-101301", - "description": "", - "serialNumber": "XYZKSJHSMK1", - "entityType": "SWITCH", - "entityName": "SWITCH", - "templateName": "template_101", - "templateContentType": "TEMPLATE_CLI", - "nvPairs": { - "FABRIC_NAME": "mmudigon" - }, - "autoGenerated": false, - "deleted": false, - "source": "", - "priority": 101, - "status": "NA", - "statusOn": 1605693124239, - "createdOn": 1605693124239, - "modifiedOn": 1605693124239, - "fabricName": "mmudigon" - }, - { - "id": 102102, - "policyId": "POLICY-102102", - "description": "102 - No piority given", - "serialNumber": "XYZKSJHSMK1", - "entityType": "SWITCH", - "entityName": "SWITCH", - "templateName": "template_102", - "templateContentType": "TEMPLATE_CLI", - "nvPairs": { - "FABRIC_NAME": "mmudigon" - }, - "autoGenerated": false, - "deleted": false, - "source": "", - "priority": 500, - "status": "NA", - "statusOn": 1605693124377, - "createdOn": 1605693124377, - "modifiedOn": 1605693124377, - "fabricName": "mmudigon" - }, - { - "id": 102202, - "policyId": "POLICY-102202", - "description": "102 - No piority given", - "serialNumber": "XYZKSJHSMK1", - "entityType": "SWITCH", - "entityName": "SWITCH", - "templateName": "template_102", - "templateContentType": "TEMPLATE_CLI", - "nvPairs": { - "FABRIC_NAME": "mmudigon" - }, - "autoGenerated": false, - "deleted": false, - "source": "", - "priority": 500, - "status": "NA", - "statusOn": 1605693124377, - "createdOn": 1605693124377, - "modifiedOn": 1605693124377, - "fabricName": "mmudigon" - }, - { - "id": 103103, - "policyId": "POLICY-103103", - "description": "Both description and priority given", - "serialNumber": "XYZKSJHSMK1", - "entityType": "SWITCH", - "entityName": "SWITCH", - "templateName": "template_103", - "templateContentType": "TEMPLATE_CLI", - "nvPairs": { - "FABRIC_NAME": "mmudigon" - }, - "autoGenerated": false, - "deleted": false, - "source": "", - "priority": 500, - "status": "NA", - "statusOn": 1605693124502, - "createdOn": 1605693124502, - "modifiedOn": 1605693124502, - "fabricName": "mmudigon" - }, - { - "id": 104104, - "policyId": "POLICY-104104", - "description": "", - "serialNumber": "XYZKSJHSMK1", - "entityType": "SWITCH", - "entityName": "SWITCH", - "templateName": "template_104", - "templateContentType": "TEMPLATE_CLI", - "nvPairs": { - "FABRIC_NAME": "mmudigon" - }, - "autoGenerated": false, - "deleted": false, - "source": "", - "priority": 500, - "status": "NA", - "statusOn": 1605693124617, - "createdOn": 1605693124617, - "modifiedOn": 1605693124617, - "fabricName": "mmudigon" - }, - { - "id": 105105, - "policyId": "POLICY-105105", - "description": "", - "serialNumber": "XYZKSJHSMK1", - "entityType": "SWITCH", - "entityName": "SWITCH", - "templateName": "template_105", - "templateContentType": "TEMPLATE_CLI", - "nvPairs": { - "FABRIC_NAME": "mmudigon" - }, - "autoGenerated": false, - "deleted": false, - "source": "", - "priority": 500, - "status": "NA", - "statusOn": 1605693124733, - "createdOn": 1605693124733, - "modifiedOn": 1605693124733, - "fabricName": "mmudigon" - }] + { + "id": 101101, + "policyId": "POLICY-101101", + "description": "policy101", + "serialNumber": "XYZKSJHSMK1", + "entityType": "SWITCH", + "entityName": "SWITCH", + "templateName": "template_101", + "templateContentType": "TEMPLATE_CLI", + "nvPairs": { + "FABRIC_NAME": "mmudigon" + }, + "autoGenerated": false, + "deleted": false, + "source": "", + "priority": 101, + "status": "NA", + "statusOn": 1605693124239, + "createdOn": 1605693124239, + "modifiedOn": 1605693124239, + "fabricName": "mmudigon" + }, + { + "id": 101201, + "policyId": "POLICY-101201", + "description": "", + "serialNumber": "XYZKSJHSMK1", + "entityType": "SWITCH", + "entityName": "SWITCH", + "templateName": "template_101", + "templateContentType": "TEMPLATE_CLI", + "nvPairs": { + "FABRIC_NAME": "mmudigon" + }, + "autoGenerated": false, + "deleted": false, + "source": "", + "priority": 101, + "status": "NA", + "statusOn": 1605693124239, + "createdOn": 1605693124239, + "modifiedOn": 1605693124239, + "fabricName": "mmudigon" + }, + { + "id": 101301, + "policyId": "POLICY-101301", + "description": "", + "serialNumber": "XYZKSJHSMK1", + "entityType": "SWITCH", + "entityName": "SWITCH", + "templateName": "template_101", + "templateContentType": "TEMPLATE_CLI", + "nvPairs": { + "FABRIC_NAME": "mmudigon" + }, + "autoGenerated": false, + "deleted": false, + "source": "", + "priority": 101, + "status": "NA", + "statusOn": 1605693124239, + "createdOn": 1605693124239, + "modifiedOn": 1605693124239, + "fabricName": "mmudigon" + }, + { + "id": 102102, + "policyId": "POLICY-102102", + "description": "102 - No piority given", + "serialNumber": "XYZKSJHSMK1", + "entityType": "SWITCH", + "entityName": "SWITCH", + "templateName": "template_102", + "templateContentType": "TEMPLATE_CLI", + "nvPairs": { + "FABRIC_NAME": "mmudigon" + }, + "autoGenerated": false, + "deleted": false, + "source": "", + "priority": 500, + "status": "NA", + "statusOn": 1605693124377, + "createdOn": 1605693124377, + "modifiedOn": 1605693124377, + "fabricName": "mmudigon" + }, + { + "id": 102202, + "policyId": "POLICY-102202", + "description": "102 - No piority given", + "serialNumber": "XYZKSJHSMK1", + "entityType": "SWITCH", + "entityName": "SWITCH", + "templateName": "template_102", + "templateContentType": "TEMPLATE_CLI", + "nvPairs": { + "FABRIC_NAME": "mmudigon" + }, + "autoGenerated": false, + "deleted": false, + "source": "", + "priority": 500, + "status": "NA", + "statusOn": 1605693124377, + "createdOn": 1605693124377, + "modifiedOn": 1605693124377, + "fabricName": "mmudigon" + }, + { + "id": 103103, + "policyId": "POLICY-103103", + "description": "Both description and priority given", + "serialNumber": "XYZKSJHSMK1", + "entityType": "SWITCH", + "entityName": "SWITCH", + "templateName": "template_103", + "templateContentType": "TEMPLATE_CLI", + "nvPairs": { + "FABRIC_NAME": "mmudigon" + }, + "autoGenerated": false, + "deleted": false, + "source": "", + "priority": 500, + "status": "NA", + "statusOn": 1605693124502, + "createdOn": 1605693124502, + "modifiedOn": 1605693124502, + "fabricName": "mmudigon" + }, + { + "id": 104104, + "policyId": "POLICY-104104", + "description": "policy104", + "serialNumber": "XYZKSJHSMK1", + "entityType": "SWITCH", + "entityName": "SWITCH", + "templateName": "template_104", + "templateContentType": "TEMPLATE_CLI", + "nvPairs": { + "FABRIC_NAME": "mmudigon" + }, + "autoGenerated": false, + "deleted": false, + "source": "", + "priority": 500, + "status": "NA", + "statusOn": 1605693124617, + "createdOn": 1605693124617, + "modifiedOn": 1605693124617, + "fabricName": "mmudigon" + }, + { + "id": 105105, + "policyId": "POLICY-105105", + "description": "policy105", + "serialNumber": "XYZKSJHSMK1", + "entityType": "SWITCH", + "entityName": "SWITCH", + "templateName": "template_105", + "templateContentType": "TEMPLATE_CLI", + "nvPairs": { + "FABRIC_NAME": "mmudigon" + }, + "autoGenerated": false, + "deleted": false, + "source": "", + "priority": 500, + "status": "NA", + "statusOn": 1605693124733, + "createdOn": 1605693124733, + "modifiedOn": 1605693124733, + "fabricName": "mmudigon" + } + ] }, "have_response_101_101_5" : { "RETURN_CODE": 200, @@ -942,7 +943,7 @@ { "id": 101101, "policyId": "POLICY-101101", - "description": "", + "description": "policy101", "serialNumber": "XYZKSJHSMK1", "entityType": "SWITCH", "entityName": "SWITCH", @@ -964,7 +965,7 @@ { "id": 102102, "policyId": "POLICY-102102", - "description": "102 - No piority given", + "description": "policy102", "serialNumber": "XYZKSJHSMK1", "entityType": "SWITCH", "entityName": "SWITCH", @@ -986,7 +987,7 @@ { "id": 103103, "policyId": "POLICY-103103", - "description": "Both description and priority given", + "description": "policy103", "serialNumber": "XYZKSJHSMK1", "entityType": "SWITCH", "entityName": "SWITCH", @@ -1008,7 +1009,7 @@ { "id": 104104, "policyId": "POLICY-104104", - "description": "", + "description": "policy104", "serialNumber": "XYZKSJHSMK1", "entityType": "SWITCH", "entityName": "SWITCH", @@ -1030,7 +1031,7 @@ { "id": 105105, "policyId": "POLICY-105105", - "description": "", + "description": "policy105", "serialNumber": "XYZKSJHSMK1", "entityType": "SWITCH", "entityName": "SWITCH", @@ -1204,7 +1205,7 @@ { "id": 123810, "policyId": "POLICY-123810", - "description": "", + "description": "policy101", "serialNumber": "XYZKSJHSMK1", "entityType": "SWITCH", "entityName": "SWITCH", @@ -1226,7 +1227,7 @@ { "id": 123820, "policyId": "POLICY-123820", - "description": "102 - No piority given", + "description": "policy102", "serialNumber": "XYZKSJHSMK1", "entityType": "SWITCH", "entityName": "SWITCH", @@ -1248,7 +1249,7 @@ { "id": 123830, "policyId": "POLICY-123830", - "description": "Both description and priority given", + "description": "policy103", "serialNumber": "XYZKSJHSMK1", "entityType": "SWITCH", "entityName": "SWITCH", diff --git a/tests/unit/modules/dcnm/test_dcnm_policy.py b/tests/unit/modules/dcnm/test_dcnm_policy.py index 18c7d7ac1..044099c7f 100644 --- a/tests/unit/modules/dcnm/test_dcnm_policy.py +++ b/tests/unit/modules/dcnm/test_dcnm_policy.py @@ -166,6 +166,23 @@ def load_policy_fixtures(self): deploy_succ_resp, ] + if ( + "test_dcnm_policy_merged_existing_and_non_exist_desc_as_key" + == self._testMethodName + ): + + have_101_103_resp = self.payloads_data.get("have_response_101_103") + create_succ_resp4 = self.payloads_data.get("success_create_response_104") + create_succ_resp5 = self.payloads_data.get("success_create_response_105") + deploy_succ_resp = self.payloads_data.get("success_deploy_response_101_105") + + self.run_dcnm_send.side_effect = [ + have_101_103_resp, + create_succ_resp4, + create_succ_resp5, + deploy_succ_resp, + ] + if "test_dcnm_policy_without_state" == self._testMethodName: create_succ_resp4 = self.payloads_data.get("success_create_response_104") @@ -319,6 +336,26 @@ def load_policy_fixtures(self): deploy_succ_resp, ] + if ( + "test_dcnm_policy_merged_existing_different_template_desc_as_key" + == self._testMethodName + ): + have_all_resp = self.payloads_data.get("have_response_101_105") + create_succ_resp_101 = self.payloads_data.get("success_create_response_101") + create_succ_resp_102 = self.payloads_data.get("success_create_response_102") + get_resp_101 = self.payloads_data.get("get_response_101") + get_resp_102 = self.payloads_data.get("get_response_102") + mark_delete_resp_101 = self.payloads_data.get("mark_delete_response_101") + mark_delete_resp_102 = self.payloads_data.get("mark_delete_response_102") + self.run_dcnm_send.side_effect = [ + have_all_resp, + get_resp_101, + get_resp_102, + mark_delete_resp_101, + mark_delete_resp_102, + create_succ_resp_101, + create_succ_resp_102, + ] if "test_dcnm_policy_modify_with_policy_id" == self._testMethodName: create_succ_resp4 = self.payloads_data.get("success_create_response_104") @@ -453,6 +490,30 @@ def load_policy_fixtures(self): [], [], ] + if "test_dcnm_policy_delete_with_desc_as_key" == self._testMethodName: + + have_resp_101_105_multi = self.payloads_data.get( + "have_response_101_105_multi" + ) + mark_delete_resp_101 = self.payloads_data.get("mark_delete_response_101") + mark_delete_resp_104 = self.payloads_data.get("mark_delete_response_104") + mark_delete_resp_105 = self.payloads_data.get("mark_delete_response_105") + get_response_101 = self.payloads_data.get("get_response_101") + get_response_104 = self.payloads_data.get("get_response_104") + get_response_105 = self.payloads_data.get("get_response_105") + delete_config_save_resp = self.payloads_data.get( + "delete_config_deploy_response_101_105" + ) + + self.run_dcnm_send.side_effect = [ + have_resp_101_105_multi, + mark_delete_resp_101, + mark_delete_resp_104, + mark_delete_resp_105, + [], + [], + [], + ] if ( "test_dcnm_policy_delete_with_template_name_with_second_delete" @@ -824,6 +885,60 @@ def test_dcnm_policy_merged_existing_and_non_exist(self): ) count = count + 1 + def test_dcnm_policy_merged_existing_and_non_exist_desc_as_key(self): + + self.config_data = loadPlaybookData("dcnm_policy_configs") + self.payloads_data = loadPlaybookData("dcnm_policy_payloads") + + # get mock ip_sn and fabric_inventory_details + self.mock_fab_inv = self.payloads_data.get("mock_fab_inv") + self.mock_ip_sn = self.payloads_data.get("mock_ip_sn") + + # load required config data + self.playbook_config = self.config_data.get("create_policy_101_105") + + set_module_args( + dict( + state="merged", + deploy=True, + fabric="mmudigon", + use_desc_as_key=True, + config=self.playbook_config, + ) + ) + result = self.execute_module(changed=True, failed=False) + self.assertEqual(len(result["diff"][0]["merged"]), 2) + self.assertEqual(len(result["diff"][0]["deleted"]), 0) + self.assertEqual(len(result["diff"][0]["query"]), 0) + self.assertEqual(len(result["diff"][0]["deploy"]), 5) + + def test_dcnm_policy_merged_existing_different_template_desc_as_key(self): + + self.config_data = loadPlaybookData("dcnm_policy_configs") + self.payloads_data = loadPlaybookData("dcnm_policy_payloads") + + # get mock ip_sn and fabric_inventory_details + self.mock_fab_inv = self.payloads_data.get("mock_fab_inv") + self.mock_ip_sn = self.payloads_data.get("mock_ip_sn") + + # load required config data + self.playbook_config = self.config_data.get("modify_policy_101_102") + + set_module_args( + dict( + state="merged", + deploy=False, + fabric="mmudigon", + use_desc_as_key=True, + config=self.playbook_config, + ) + ) + result = self.execute_module(changed=True, failed=False) + self.assertEqual(len(result["diff"][0]["merged"]), 2) + self.assertEqual(len(result["diff"][0]["deleted"]), 2) + self.assertEqual(len(result["diff"][0]["query"]), 0) + self.assertEqual(len(result["diff"][0]["deploy"]), 0) + def test_dcnm_policy_without_state(self): # load the json from playbooks @@ -1363,6 +1478,38 @@ def test_dcnm_policy_delete_with_template_name(self): ) count = count + 1 + def test_dcnm_policy_delete_with_desc_as_key(self): + + # load the json from playbooks + self.config_data = loadPlaybookData("dcnm_policy_configs") + self.payloads_data = loadPlaybookData("dcnm_policy_payloads") + + # get mock ip_sn and fabric_inventory_details + self.mock_fab_inv = self.payloads_data.get("mock_fab_inv") + self.mock_ip_sn = self.payloads_data.get("mock_ip_sn") + + # load required config data + self.playbook_config = self.config_data.get( + "delete_policy_template_desc_101_105" + ) + + set_module_args( + dict( + state="deleted", + deploy=False, + fabric="mmudigon", + use_desc_as_key=True, + config=self.playbook_config, + ) + ) + result = self.execute_module(changed=True, failed=False) + + self.assertEqual(len(result["diff"][0]["merged"]), 0) + self.assertEqual(len(result["diff"][0]["deleted"]), 3) + self.assertEqual(len(result["diff"][0]["query"]), 0) + self.assertEqual(len(result["diff"][0]["deploy"]), 0) + self.assertEqual(len(result["diff"][0]["skipped"]), 0) + def test_dcnm_policy_delete_with_policy_id(self): # load the json from playbooks