diff --git a/plugins/module_utils/mso.py b/plugins/module_utils/mso.py index f66d4cbb..3c7e9fa1 100644 --- a/plugins/module_utils/mso.py +++ b/plugins/module_utils/mso.py @@ -754,7 +754,7 @@ def query_objs(self, path, key=None, api_version="v1", **kwargs): found = [] objs = self.request(path, api_version=api_version, method="GET") - if objs == {} or objs == []: + if objs == {} or objs == [] or not objs: return found if key is None: diff --git a/plugins/modules/ndo_dhcp_option_policy.py b/plugins/modules/ndo_dhcp_option_policy.py index 4e87f687..3359b085 100644 --- a/plugins/modules/ndo_dhcp_option_policy.py +++ b/plugins/modules/ndo_dhcp_option_policy.py @@ -172,23 +172,17 @@ def main(): mso_template.validate_template("tenantPolicy") path = "/tenantPolicyTemplate/template/dhcpOptionPolicies" - existing_dhcp_option_policies = mso_template.template.get("tenantPolicyTemplate", {}).get("template", {}).get("dhcpOptionPolicies", []) - if option_policy: - object_description = "DHCP Option Policy" - if option_policy_uuid: - match = mso_template.get_object_by_uuid(object_description, existing_dhcp_option_policies, option_policy_uuid) - else: - kv_list = [KVPair("name", option_policy)] - match = mso_template.get_object_by_key_value_pairs(object_description, existing_dhcp_option_policies, kv_list) - if match: - mso.existing = mso.previous = copy.deepcopy(match.details) - else: - mso.existing = mso.previous = existing_dhcp_option_policies - if state == "present": + match = get_dhcp_option_policy(mso_template, option_policy_uuid, option_policy) + if option_policy_uuid or option_policy: if match: + mso.existing = mso.previous = copy.deepcopy(match.details) # Query a specific object + elif match: + mso.existing = match # Query all objects + if state == "present": + if match: if module.params.get("options") is not None and len(options) == 0: mso.fail_json(msg=err_message_min_options) @@ -207,7 +201,6 @@ def main(): mso.sanitize(match.details) else: - if not options: mso.fail_json(msg=err_message_min_options) @@ -227,11 +220,38 @@ def main(): mso.existing = {} if not module.check_mode and ops: - mso.request(mso_template.template_path, method="PATCH", data=ops) + mso_template.template = mso.request(mso_template.template_path, method="PATCH", data=ops) + match = get_dhcp_option_policy(mso_template, option_policy_uuid, option_policy) + if match: + mso.existing = match.details # When the state is present + else: + mso.existing = {} # When the state is absent + elif module.check_mode and state != "query": # When the state is present/absent with check mode + mso.existing = mso.proposed if state == "present" else {} mso.exit_json() +def get_dhcp_option_policy(mso_template, uuid=None, name=None, fail_module=False): + """ + Get the DHCP Option Policy by UUID or Name. + :param uuid: UUID of the DHCP Option Policy to search for -> Str + :param name: Name of the DHCP Option Policy to search for -> Str + :param fail_module: When match is not found fail the ansible module -> Bool + :return: Dict | None | List[Dict] | List[]: The processed result which could be: + When the UUID | Name is existing in the search list -> Dict + When the UUID | Name is not existing in the search list -> None + When both UUID and Name are None, and the search list is not empty -> List[Dict] + When both UUID and Name are None, and the search list is empty -> List[] + """ + existing_dhcp_option_policies = mso_template.template.get("tenantPolicyTemplate", {}).get("template", {}).get("dhcpOptionPolicies", []) + if uuid or name: # Query a specific object + return mso_template.get_object_by_key_value_pairs( + "DHCP Option Policy", existing_dhcp_option_policies, [KVPair("uuid", uuid) if uuid else KVPair("name", name)], fail_module + ) + return existing_dhcp_option_policies # Query all objects + + def get_options_payload(options): payload = [] for option in options: diff --git a/plugins/modules/ndo_dhcp_relay_policy.py b/plugins/modules/ndo_dhcp_relay_policy.py index 0d358cd9..fe34f3d2 100644 --- a/plugins/modules/ndo_dhcp_relay_policy.py +++ b/plugins/modules/ndo_dhcp_relay_policy.py @@ -203,23 +203,16 @@ def main(): mso_template.validate_template("tenantPolicy") path = "/tenantPolicyTemplate/template/dhcpRelayPolicies" - existing_dhcp_relay_policies = mso_template.template.get("tenantPolicyTemplate", {}).get("template", {}).get("dhcpRelayPolicies", []) - if relay_policy: - object_description = "DHCP Relay Policy" - if relay_policy_uuid: - match = mso_template.get_object_by_uuid(object_description, existing_dhcp_relay_policies, relay_policy_uuid) - else: - kv_list = [KVPair("name", relay_policy)] - match = mso_template.get_object_by_key_value_pairs(object_description, existing_dhcp_relay_policies, kv_list) + match = get_dhcp_relay_policy(mso_template, relay_policy_uuid, relay_policy) + + if relay_policy_uuid or relay_policy: if match: - mso.existing = mso.previous = copy.deepcopy(match.details) - else: - mso.existing = mso.previous = existing_dhcp_relay_policies + mso.existing = mso.previous = copy.deepcopy(match.details) # Query a specific object + elif match: + mso.existing = match # Query all objects if state == "present": - if match: - if module.params.get("providers") is not None and len(providers) == 0: mso.fail_json(msg=err_message_min_providers) @@ -238,7 +231,6 @@ def main(): mso.sanitize(match.details) else: - if not providers: mso.fail_json(msg=err_message_min_providers) @@ -258,19 +250,42 @@ def main(): mso.existing = {} if not module.check_mode and ops: - mso.request(mso_template.template_path, method="PATCH", data=ops) + mso_template.template = mso.request(mso_template.template_path, method="PATCH", data=ops) + match = get_dhcp_relay_policy(mso_template, relay_policy_uuid, relay_policy) + if match: + mso.existing = match.details # When the state is present + else: + mso.existing = {} # When the state is absent + elif module.check_mode and state != "query": # When the state is present/absent with check mode + mso.existing = mso.proposed if state == "present" else {} mso.exit_json() -def get_providers_payload(mso, providers): +def get_dhcp_relay_policy(mso_template, uuid=None, name=None, fail_module=False): + """ + Get the DHCP Relay Policy by UUID or Name. + :param uuid: UUID of the DHCP Relay Policy to search for -> Str + :param name: Name of the DHCP Relay Policy to search for -> Str + :param fail_module: When match is not found fail the ansible module -> Bool + :return: Dict | None | List[Dict] | List[]: The processed result which could be: + When the UUID | Name is existing in the search list -> Dict + When the UUID | Name is not existing in the search list -> None + When both UUID and Name are None, and the search list is not empty -> List[Dict] + When both UUID and Name are None, and the search list is empty -> List[] + """ + match = mso_template.template.get("tenantPolicyTemplate", {}).get("template", {}).get("dhcpRelayPolicies", []) + if uuid or name: # Query a specific object + return mso_template.get_object_by_key_value_pairs("DHCP Relay Policy", match, [KVPair("uuid", uuid) if uuid else KVPair("name", name)], fail_module) + return match # Query all objects + +def get_providers_payload(mso, providers): # Cache used to reduce the number of schema queries done by MSOSchema function. schema_cache = {} payload = [] for provider in providers: - schema = provider.get("schema") template = provider.get("template") anp = provider.get("anp") diff --git a/plugins/modules/ndo_l3_domain.py b/plugins/modules/ndo_l3_domain.py index 9017f5e5..3fbd5a8d 100644 --- a/plugins/modules/ndo_l3_domain.py +++ b/plugins/modules/ndo_l3_domain.py @@ -155,27 +155,17 @@ def main(): mso_template.validate_template("fabricPolicy") path = "/fabricPolicyTemplate/template/l3Domains" - existing_l3_domains = mso_template.template.get("fabricPolicyTemplate", {}).get("template", {}).get("l3Domains", []) - if l3_domain: - object_description = "L3 Domain" - if l3_domain_uuid: - match = mso_template.get_object_by_uuid(object_description, existing_l3_domains, l3_domain_uuid) - else: - kv_list = [KVPair("name", l3_domain)] - match = mso_template.get_object_by_key_value_pairs(object_description, existing_l3_domains, kv_list) + match = get_l3_domain(mso_template, l3_domain_uuid, l3_domain) + if l3_domain_uuid or l3_domain: if match: - if match.details.get("pool"): - match.details["pool"] = mso_template.get_vlan_pool_name(match.details.get("pool")) - mso.existing = mso.previous = copy.deepcopy(match.details) - else: - mso.existing = mso.previous = existing_l3_domains + mso.existing = mso.previous = copy.deepcopy(match.details) # Query a specific object + elif match: + mso.existing = match # Query all objects if state == "present": - mso.existing = {} if match: - if l3_domain and match.details.get("name") != l3_domain: ops.append(dict(op="replace", path="{0}/{1}/name".format(path, match.index), value=l3_domain)) match.details["name"] = l3_domain @@ -186,7 +176,7 @@ def main(): if pool and match.details.get("pool") != pool: ops.append(dict(op="replace", path="{0}/{1}/pool".format(path, match.index), value=mso_template.get_vlan_pool_uuid(pool))) - match.details["pool"] = pool + match.details["pool"] = mso_template.get_vlan_pool_uuid(pool) elif pool == "" and match.details.get("pool"): ops.append(dict(op="remove", path="{0}/{1}/pool".format(path, match.index))) match.details.pop("pool") @@ -194,7 +184,6 @@ def main(): mso.sanitize(match.details) else: - payload = {"name": l3_domain, "templateId": mso_template.template.get("templateId"), "schemaId": mso_template.template.get("schemaId")} if description: payload["description"] = description @@ -216,10 +205,35 @@ def main(): mso.existing = {} if not module.check_mode and ops: - mso.request(mso_template.template_path, method="PATCH", data=ops) + mso_template.template = mso.request(mso_template.template_path, method="PATCH", data=ops) + match = get_l3_domain(mso_template, l3_domain_uuid, l3_domain) + if match: + mso.existing = match.details # When the state is present + else: + mso.existing = {} # When the state is absent + elif module.check_mode and state != "query": # When the state is present/absent with check mode + mso.existing = mso.proposed if state == "present" else {} mso.exit_json() +def get_l3_domain(mso_template, uuid=None, name=None, fail_module=False): + """ + Get the L3 Domain by UUID or Name. + :param uuid: UUID of the L3 Domain to search for -> Str + :param name: Name of the L3 Domain to search for -> Str + :param fail_module: When match is not found fail the ansible module -> Bool + :return: Dict | None | List[Dict] | List[]: The processed result which could be: + When the UUID | Name is existing in the search list -> Dict + When the UUID | Name is not existing in the search list -> None + When both UUID and Name are None, and the search list is not empty -> List[Dict] + When both UUID and Name are None, and the search list is empty -> List[] + """ + match = mso_template.template.get("fabricPolicyTemplate", {}).get("template", {}).get("l3Domains", []) + if uuid or name: # Query a specific object + return mso_template.get_object_by_key_value_pairs("L3 Domain", match, [KVPair("uuid", uuid) if uuid else KVPair("name", name)], fail_module) + return match # Query all objects + + if __name__ == "__main__": main() diff --git a/plugins/modules/ndo_physical_domain.py b/plugins/modules/ndo_physical_domain.py index 2d49b631..6bc5a342 100644 --- a/plugins/modules/ndo_physical_domain.py +++ b/plugins/modules/ndo_physical_domain.py @@ -155,27 +155,18 @@ def main(): mso_template.validate_template("fabricPolicy") path = "/fabricPolicyTemplate/template/domains" - existing_physical_domains = mso_template.template.get("fabricPolicyTemplate", {}).get("template", {}).get("domains", []) - if physical_domain: - object_description = "Physical Domain" - if physical_domain_uuid: - match = mso_template.get_object_by_uuid(object_description, existing_physical_domains, physical_domain_uuid) - else: - kv_list = [KVPair("name", physical_domain)] - match = mso_template.get_object_by_key_value_pairs(object_description, existing_physical_domains, kv_list) + match = get_physical_domain(mso_template, physical_domain_uuid, physical_domain) + + if physical_domain_uuid or physical_domain: if match: - if match.details.get("pool"): - match.details["pool"] = mso_template.get_vlan_pool_name(match.details.get("pool")) - mso.existing = mso.previous = copy.deepcopy(match.details) - else: - mso.existing = mso.previous = existing_physical_domains + mso.existing = mso.previous = copy.deepcopy(match.details) # Query a specific object + elif match: + mso.existing = match # Query all objects if state == "present": - mso.existing = {} if match: - if physical_domain and match.details.get("name") != physical_domain: ops.append(dict(op="replace", path="{0}/{1}/name".format(path, match.index), value=physical_domain)) match.details["name"] = physical_domain @@ -194,7 +185,6 @@ def main(): mso.sanitize(match.details) else: - payload = {"name": physical_domain, "templateId": mso_template.template.get("templateId"), "schemaId": mso_template.template.get("schemaId")} if description: payload["description"] = description @@ -216,10 +206,35 @@ def main(): mso.existing = {} if not module.check_mode and ops: - mso.request(mso_template.template_path, method="PATCH", data=ops) + mso_template.template = mso.request(mso_template.template_path, method="PATCH", data=ops) + match = get_physical_domain(mso_template, physical_domain_uuid, physical_domain) + if match: + mso.existing = match.details # When the state is present + else: + mso.existing = {} # When the state is absent + elif module.check_mode and state != "query": # When the state is present/absent with check mode + mso.existing = mso.proposed if state == "present" else {} mso.exit_json() +def get_physical_domain(mso_template, uuid=None, name=None, fail_module=False): + """ + Get the Physical Domain by UUID or Name. + :param uuid: UUID of the Physical Domain to search for -> Str + :param name: Name of the Physical Domain to search for -> Str + :param fail_module: When match is not found fail the ansible module -> Bool + :return: Dict | None | List[Dict] | List[]: The processed result which could be: + When the UUID | Name is existing in the search list -> Dict + When the UUID | Name is not existing in the search list -> None + When both UUID and Name are None, and the search list is not empty -> List[Dict] + When both UUID and Name are None, and the search list is empty -> List[] + """ + match = mso_template.template.get("fabricPolicyTemplate", {}).get("template", {}).get("domains", []) + if uuid or name: # Query a specific object + return mso_template.get_object_by_key_value_pairs("Physical Domain", match, [KVPair("uuid", uuid) if uuid else KVPair("name", name)], fail_module) + return match # Query all objects + + if __name__ == "__main__": main() diff --git a/plugins/modules/ndo_route_map_policy_multicast.py b/plugins/modules/ndo_route_map_policy_multicast.py index 7e812e4c..cc75f174 100644 --- a/plugins/modules/ndo_route_map_policy_multicast.py +++ b/plugins/modules/ndo_route_map_policy_multicast.py @@ -188,24 +188,17 @@ def main(): mso_template.validate_template("tenantPolicy") path = "/tenantPolicyTemplate/template/mcastRouteMapPolicies" - existing_route_map_policies = mso_template.template.get("tenantPolicyTemplate", {}).get("template", {}).get("mcastRouteMapPolicies", []) - if route_map_policy: - object_description = "Multicast Route Map Policy" - if route_map_policy_uuid: - match = mso_template.get_object_by_uuid(object_description, existing_route_map_policies, route_map_policy_uuid) - else: - kv_list = [KVPair("name", route_map_policy)] - match = mso_template.get_object_by_key_value_pairs(object_description, existing_route_map_policies, kv_list) - if match: - match.details["entries"] = match.details.pop("mcastRtMapEntryList") - mso.existing = mso.previous = copy.deepcopy(match.details) - else: - mso.existing = mso.previous = existing_route_map_policies + match = get_multicast_route_map_policy(mso_template, route_map_policy_uuid, route_map_policy) - if state == "present": + if route_map_policy_uuid or route_map_policy: + if match: # Query a specific object + mso.existing = copy.deepcopy(match.details) + mso.previous = copy.deepcopy(match.details) + elif match: + mso.existing = match # Query all objects + if state == "present": if match: - if module.params.get("entries") is not None and len(entries) == 0: mso.fail_json(msg=err_message_min_entries) @@ -217,14 +210,13 @@ def main(): ops.append(dict(op="replace", path="{0}/{1}/description".format(path, match.index), value=description)) match.details["description"] = description - if module.params.get("entries") is not None and match.details.get("entries") != entries: + if module.params.get("entries") is not None and match.details.get("mcastRtMapEntryList") != entries: ops.append(dict(op="replace", path="{0}/{1}/mcastRtMapEntryList".format(path, match.index), value=entries)) - match.details["entries"] = entries + match.details["mcastRtMapEntryList"] = entries mso.sanitize(match.details) else: - if not entries: mso.fail_json(msg=err_message_min_entries) @@ -234,7 +226,6 @@ def main(): ops.append(dict(op="add", path="{0}/-".format(path), value=copy.deepcopy(payload))) - payload["entries"] = payload.pop("mcastRtMapEntryList") mso.sanitize(payload) mso.existing = mso.proposed @@ -245,7 +236,14 @@ def main(): mso.existing = {} if not module.check_mode and ops: - mso.request(mso_template.template_path, method="PATCH", data=ops) + mso_template.template = mso.request(mso_template.template_path, method="PATCH", data=ops) + match = get_multicast_route_map_policy(mso_template, route_map_policy_uuid, route_map_policy) + if match: + mso.existing = match.details # When the state is present + else: + mso.existing = {} # When the state is absent + elif module.check_mode and state != "query": # When the state is present/absent with check mode + mso.existing = mso.proposed if state == "present" else {} mso.exit_json() @@ -265,5 +263,25 @@ def get_entries_payload(entries): return payload +def get_multicast_route_map_policy(mso_template, uuid=None, name=None, fail_module=False): + """ + Get the Multicast Route Map Policy by UUID or Name. + :param uuid: UUID of the Multicast Route Map Policy to search for -> Str + :param name: Name of the Multicast Route Map Policy to search for -> Str + :param fail_module: When match is not found fail the ansible module -> Bool + :return: Dict | None | List[Dict] | List[]: The processed result which could be: + When the UUID | Name is existing in the search list -> Dict + When the UUID | Name is not existing in the search list -> None + When both UUID and Name are None, and the search list is not empty -> List[Dict] + When both UUID and Name are None, and the search list is empty -> List[] + """ + match = mso_template.template.get("tenantPolicyTemplate", {}).get("template", {}).get("mcastRouteMapPolicies", []) + if uuid or name: # Query a specific object + return mso_template.get_object_by_key_value_pairs( + "Multicast Route Map Policy", match, [KVPair("uuid", uuid) if uuid else KVPair("name", name)], fail_module + ) + return match # Query all objects + + if __name__ == "__main__": main() diff --git a/plugins/modules/ndo_synce_interface_policy.py b/plugins/modules/ndo_synce_interface_policy.py index ef99148a..38c271b5 100644 --- a/plugins/modules/ndo_synce_interface_policy.py +++ b/plugins/modules/ndo_synce_interface_policy.py @@ -194,23 +194,15 @@ def main(): mso_template.validate_template("fabricPolicy") path = "/fabricPolicyTemplate/template/syncEthIntfPolicies" + match = get_synce_interface_policy(mso_template, interface_policy_uuid, interface_policy) - existing_interface_policies = mso_template.template.get("fabricPolicyTemplate", {}).get("template", {}).get("syncEthIntfPolicies", []) - - if interface_policy: - object_description = "SyncE Interface Policy" - if interface_policy_uuid: - match = mso_template.get_object_by_uuid(object_description, existing_interface_policies, interface_policy_uuid) - else: - kv_list = [KVPair("name", interface_policy)] - match = mso_template.get_object_by_key_value_pairs(object_description, existing_interface_policies, kv_list) + if interface_policy_uuid or interface_policy: if match: - mso.existing = mso.previous = copy.deepcopy(match.details) - else: - mso.existing = mso.previous = existing_interface_policies + mso.existing = mso.previous = copy.deepcopy(match.details) # Query a specific object + elif match: + mso.existing = match # Query all objects if state == "present": - mso.existing = {} if match: @@ -248,7 +240,6 @@ def main(): mso.sanitize(match.details) else: - payload = {"name": interface_policy, "templateId": mso_template.template.get("templateId"), "schemaId": mso_template.template.get("schemaId")} if description: payload["description"] = description @@ -275,10 +266,37 @@ def main(): mso.existing = {} if not module.check_mode and ops: - mso.request(mso_template.template_path, method="PATCH", data=ops) + mso_template.template = mso.request(mso_template.template_path, method="PATCH", data=ops) + match = get_synce_interface_policy(mso_template, interface_policy_uuid, interface_policy) + if match: + mso.existing = match.details # When the state is present + else: + mso.existing = {} # When the state is absent + elif module.check_mode and state != "query": # When the state is present/absent with check mode + mso.existing = mso.proposed if state == "present" else {} mso.exit_json() +def get_synce_interface_policy(mso_template, uuid=None, name=None, fail_module=False): + """ + Get the SyncE Interface Policy by UUID or Name. + :param uuid: UUID of the SyncE Interface Policy to search for -> Str + :param name: Name of the SyncE Interface Policy to search for -> Str + :param fail_module: When match is not found fail the ansible module -> Bool + :return: Dict | None | List[Dict] | List[]: The processed result which could be: + When the UUID | Name is existing in the search list -> Dict + When the UUID | Name is not existing in the search list -> None + When both UUID and Name are None, and the search list is not empty -> List[Dict] + When both UUID and Name are None, and the search list is empty -> List[] + """ + match = mso_template.template.get("fabricPolicyTemplate", {}).get("template", {}).get("syncEthIntfPolicies", []) + if uuid or name: # Query a specific object + return mso_template.get_object_by_key_value_pairs( + "SyncE Interface Policy", match, [KVPair("uuid", uuid) if uuid else KVPair("name", name)], fail_module + ) + return match # Query all objects + + if __name__ == "__main__": main() diff --git a/plugins/modules/ndo_vlan_pool.py b/plugins/modules/ndo_vlan_pool.py index 20baa886..8ede8eb2 100644 --- a/plugins/modules/ndo_vlan_pool.py +++ b/plugins/modules/ndo_vlan_pool.py @@ -170,26 +170,19 @@ def main(): mso_template.validate_template("fabricPolicy") path = "/fabricPolicyTemplate/template/vlanPools" - existing_vlan_pools = mso_template.template.get("fabricPolicyTemplate", {}).get("template", {}).get("vlanPools", []) - if vlan_pool: - object_description = "VLAN Pool" - if vlan_pool_uuid: - match = mso_template.get_object_by_uuid(object_description, existing_vlan_pools, vlan_pool_uuid) - else: - kv_list = [KVPair("name", vlan_pool)] - match = mso_template.get_object_by_key_value_pairs(object_description, existing_vlan_pools, kv_list) + match = get_fabric_policy_vlan_pool(mso_template, vlan_pool_uuid, vlan_pool) + + if vlan_pool_uuid or vlan_pool: if match: match.details["vlan_ranges"] = match.details.pop("encapBlocks") - mso.existing = mso.previous = copy.deepcopy(match.details) - else: - mso.existing = mso.previous = existing_vlan_pools + mso.existing = mso.previous = copy.deepcopy(match.details) # Query a specific object + elif match: + mso.existing = match # Query all objects if state == "present": - err_message_min_vlan_ranges = "At least one vlan range is required when state is present." if match: - if module.params.get("vlan_ranges") is not None and len(vlan_ranges) == 0: mso.fail_json(msg=err_message_min_vlan_ranges) @@ -208,7 +201,6 @@ def main(): mso.sanitize(match.details) else: - if not vlan_ranges: mso.fail_json(msg=err_message_min_vlan_ranges) @@ -229,7 +221,15 @@ def main(): mso.existing = {} if not module.check_mode and ops: - mso.request(mso_template.template_path, method="PATCH", data=ops) + mso_template.template = mso.request(mso_template.template_path, method="PATCH", data=ops) + match = get_fabric_policy_vlan_pool(mso_template, vlan_pool_uuid, vlan_pool) + if match: + match.details["vlan_ranges"] = match.details.pop("encapBlocks") + mso.existing = match.details # When the state is present + else: + mso.existing = {} # When the state is absent + elif module.check_mode and state != "query": # When the state is present/absent with check mode + mso.existing = mso.proposed if state == "present" else {} mso.exit_json() @@ -248,5 +248,23 @@ def get_vlan_ranges_payload(vlan_ranges): return payload +def get_fabric_policy_vlan_pool(mso_template, uuid=None, name=None, fail_module=False): + """ + Get the Fabric Policy VLAN Pool by UUID or Name. + :param uuid: UUID of the Fabric Policy VLAN Pool to search for -> Str + :param name: Name of the Fabric Policy VLAN Pool to search for -> Str + :param fail_module: When match is not found fail the ansible module -> Bool + :return: Dict | None | List[Dict] | List[]: The processed result which could be: + When the UUID | Name is existing in the search list -> Dict + When the UUID | Name is not existing in the search list -> None + When both UUID and Name are None, and the search list is not empty -> List[Dict] + When both UUID and Name are None, and the search list is empty -> List[] + """ + match = mso_template.template.get("fabricPolicyTemplate", {}).get("template", {}).get("vlanPools", []) + if uuid or name: # Query a specific object + return mso_template.get_object_by_key_value_pairs("VLAN Pool", match, [KVPair("uuid", uuid) if uuid else KVPair("name", name)], fail_module) + return match # Query all objects + + if __name__ == "__main__": main() diff --git a/tests/integration/targets/ndo_l3_domain/tasks/main.yml b/tests/integration/targets/ndo_l3_domain/tasks/main.yml index 3ce01ed1..d923d8b1 100644 --- a/tests/integration/targets/ndo_l3_domain/tasks/main.yml +++ b/tests/integration/targets/ndo_l3_domain/tasks/main.yml @@ -5,19 +5,19 @@ - name: Test that we have an ACI MultiSite host, username and password ansible.builtin.fail: - msg: 'Please define the following variables: mso_hostname, mso_username and mso_password.' + msg: "Please define the following variables: mso_hostname, mso_username and mso_password." when: mso_hostname is not defined or mso_username is not defined or mso_password is not defined # CLEAN ENVIRONMENT - name: Set vars ansible.builtin.set_fact: mso_info: &mso_info - host: '{{ mso_hostname }}' - username: '{{ mso_username }}' - password: '{{ mso_password }}' - validate_certs: '{{ mso_validate_certs | default(false) }}' - use_ssl: '{{ mso_use_ssl | default(true) }}' - use_proxy: '{{ mso_use_proxy | default(true) }}' + host: "{{ mso_hostname }}" + username: "{{ mso_username }}" + password: "{{ mso_password }}" + validate_certs: "{{ mso_validate_certs | default(false) }}" + use_ssl: "{{ mso_use_ssl | default(true) }}" + use_proxy: "{{ mso_use_proxy | default(true) }}" output_level: '{{ mso_output_level | default("info") }}' # QUERY VERSION @@ -27,11 +27,9 @@ state: query register: version - - name: Execute tasks only for MSO version > 4.3 when: version.current.version is version('4.3', '>=') block: - - name: Ensure templates do not exist cisco.mso.ndo_template: &template_absent <<: *mso_info @@ -54,8 +52,8 @@ to_vlan: "{{ item.to_vlan }}" state: present loop: - - {name: ansible_test_vlan_pool_1, from_vlan: 100, to_vlan: 200} - - {name: ansible_test_vlan_pool_2, from_vlan: 300, to_vlan: 400} + - { name: ansible_test_vlan_pool_1, from_vlan: 100, to_vlan: 200 } + - { name: ansible_test_vlan_pool_2, from_vlan: 300, to_vlan: 400 } # CREATE @@ -85,20 +83,20 @@ - cm_create_new_l3_domain is changed - cm_create_new_l3_domain.previous == {} - cm_create_new_l3_domain.current.name == "ansible_test_l3_domain" - - cm_create_new_l3_domain.current.pool == "ansible_test_vlan_pool_1" + - cm_create_new_l3_domain.current.pool != "" - nm_create_new_l3_domain is changed - nm_create_new_l3_domain.previous == {} - nm_create_new_l3_domain.current.name == "ansible_test_l3_domain" - - nm_create_new_l3_domain.current.pool == "ansible_test_vlan_pool_1" + - nm_create_new_l3_domain.current.pool != "" - nm_create_new_l3_domain_again is not changed - nm_create_new_l3_domain_again.previous.name == "ansible_test_l3_domain" - nm_create_new_l3_domain_again.previous.description == "" - nm_create_new_l3_domain_again.previous.uuid is defined - - nm_create_new_l3_domain_again.previous.pool == "ansible_test_vlan_pool_1" + - nm_create_new_l3_domain_again.previous.pool != "" - nm_create_new_l3_domain_again.current.name == "ansible_test_l3_domain" - nm_create_new_l3_domain_again.current.description == "" - nm_create_new_l3_domain_again.current.uuid is defined - - nm_create_new_l3_domain_again.current.pool == "ansible_test_vlan_pool_1" + - nm_create_new_l3_domain_again.current.pool != "" # UPDATE @@ -135,7 +133,7 @@ - name: Update a l3 domain name cisco.mso.ndo_l3_domain: &update_l3_domain_name <<: *update_l3_domain - l3_domain_uuid: '{{ nm_update_l3_domain_description.current.uuid }}' + l3_domain_uuid: "{{ nm_update_l3_domain_description.current.uuid }}" l3_domain: ansible_test_l3_domain_changed register: nm_update_l3_domain_name @@ -158,10 +156,10 @@ - nm_update_l3_domain_name.previous.name == "ansible_test_l3_domain" - nm_update_l3_domain_name.current.name == "ansible_test_l3_domain_changed" - nm_update_l3_domain_pool is changed - - nm_update_l3_domain_pool.previous.pool == "ansible_test_vlan_pool_1" - - nm_update_l3_domain_pool.current.pool == "ansible_test_vlan_pool_2" + - nm_update_l3_domain_pool.previous.pool != "" + - nm_update_l3_domain_pool.current.pool != "" - nm_update_l3_domain_pool_remove is changed - - nm_update_l3_domain_pool_remove.previous.pool == "ansible_test_vlan_pool_2" + - nm_update_l3_domain_pool_remove.previous.pool != "" - nm_update_l3_domain_pool_remove.current.pool is not defined # QUERY @@ -170,7 +168,7 @@ cisco.mso.ndo_l3_domain: &create_l3_domain_2 <<: *create_l3_domain l3_domain: ansible_test_l3_domain_2 - pool: '{{ fakevar | default(omit)}}' + pool: "{{ fakevar | default(omit)}}" description: "This is a test l3 domain 2" - name: Query a l3 domain with template_name @@ -232,4 +230,4 @@ - name: Ensure templates do not exist cisco.mso.ndo_template: - <<: *template_absent \ No newline at end of file + <<: *template_absent diff --git a/tests/integration/targets/ndo_physical_domain/tasks/main.yml b/tests/integration/targets/ndo_physical_domain/tasks/main.yml index 3fb643af..5a25674d 100644 --- a/tests/integration/targets/ndo_physical_domain/tasks/main.yml +++ b/tests/integration/targets/ndo_physical_domain/tasks/main.yml @@ -5,19 +5,19 @@ - name: Test that we have an ACI MultiSite host, username and password ansible.builtin.fail: - msg: 'Please define the following variables: mso_hostname, mso_username and mso_password.' + msg: "Please define the following variables: mso_hostname, mso_username and mso_password." when: mso_hostname is not defined or mso_username is not defined or mso_password is not defined # CLEAN ENVIRONMENT - name: Set vars ansible.builtin.set_fact: mso_info: &mso_info - host: '{{ mso_hostname }}' - username: '{{ mso_username }}' - password: '{{ mso_password }}' - validate_certs: '{{ mso_validate_certs | default(false) }}' - use_ssl: '{{ mso_use_ssl | default(true) }}' - use_proxy: '{{ mso_use_proxy | default(true) }}' + host: "{{ mso_hostname }}" + username: "{{ mso_username }}" + password: "{{ mso_password }}" + validate_certs: "{{ mso_validate_certs | default(false) }}" + use_ssl: "{{ mso_use_ssl | default(true) }}" + use_proxy: "{{ mso_use_proxy | default(true) }}" output_level: '{{ mso_output_level | default("info") }}' # QUERY VERSION @@ -27,11 +27,9 @@ state: query register: version - - name: Execute tasks only for MSO version > 4.3 when: version.current.version is version('4.3', '>=') block: - - name: Ensure templates do not exist cisco.mso.ndo_template: &template_absent <<: *mso_info @@ -54,8 +52,8 @@ to_vlan: "{{ item.to_vlan }}" state: present loop: - - {name: ansible_test_vlan_pool_1, from_vlan: 100, to_vlan: 200} - - {name: ansible_test_vlan_pool_2, from_vlan: 300, to_vlan: 400} + - { name: ansible_test_vlan_pool_1, from_vlan: 100, to_vlan: 200 } + - { name: ansible_test_vlan_pool_2, from_vlan: 300, to_vlan: 400 } # CREATE @@ -85,20 +83,20 @@ - cm_create_new_physical_domain is changed - cm_create_new_physical_domain.previous == {} - cm_create_new_physical_domain.current.name == "ansible_test_physical_domain" - - cm_create_new_physical_domain.current.pool == "ansible_test_vlan_pool_1" + - cm_create_new_physical_domain.current.pool != "" - nm_create_new_physical_domain is changed - nm_create_new_physical_domain.previous == {} - nm_create_new_physical_domain.current.name == "ansible_test_physical_domain" - - nm_create_new_physical_domain.current.pool == "ansible_test_vlan_pool_1" + - nm_create_new_physical_domain.current.pool != "" - nm_create_new_physical_domain_again is not changed - nm_create_new_physical_domain_again.previous.name == "ansible_test_physical_domain" - nm_create_new_physical_domain_again.previous.description == "" - nm_create_new_physical_domain_again.previous.uuid is defined - - nm_create_new_physical_domain_again.previous.pool == "ansible_test_vlan_pool_1" + - nm_create_new_physical_domain_again.previous.pool != "" - nm_create_new_physical_domain_again.current.name == "ansible_test_physical_domain" - nm_create_new_physical_domain_again.current.description == "" - nm_create_new_physical_domain_again.current.uuid is defined - - nm_create_new_physical_domain_again.current.pool == "ansible_test_vlan_pool_1" + - nm_create_new_physical_domain_again.current.pool != "" # UPDATE @@ -135,7 +133,7 @@ - name: Update a physical domain name cisco.mso.ndo_physical_domain: &update_physical_domain_name <<: *update_physical_domain - physical_domain_uuid: '{{ nm_update_physical_domain_description.current.uuid }}' + physical_domain_uuid: "{{ nm_update_physical_domain_description.current.uuid }}" physical_domain: ansible_test_physical_domain_changed register: nm_update_physical_domain_name @@ -158,10 +156,10 @@ - nm_update_physical_domain_name.previous.name == "ansible_test_physical_domain" - nm_update_physical_domain_name.current.name == "ansible_test_physical_domain_changed" - nm_update_physical_domain_pool is changed - - nm_update_physical_domain_pool.previous.pool == "ansible_test_vlan_pool_1" - - nm_update_physical_domain_pool.current.pool == "ansible_test_vlan_pool_2" + - nm_update_physical_domain_pool.previous.pool != "" + - nm_update_physical_domain_pool.current.pool != "" - nm_update_physical_domain_pool_remove is changed - - nm_update_physical_domain_pool_remove.previous.pool == "ansible_test_vlan_pool_2" + - nm_update_physical_domain_pool_remove.previous.pool != "" - nm_update_physical_domain_pool_remove.current.pool is not defined # QUERY @@ -170,7 +168,7 @@ cisco.mso.ndo_physical_domain: &create_physical_domain_2 <<: *create_physical_domain physical_domain: ansible_test_physical_domain_2 - pool: '{{ fakevar | default(omit)}}' + pool: "{{ fakevar | default(omit)}}" description: "This is a test physical domain 2" - name: Query a physical domain with template_name @@ -232,4 +230,4 @@ - name: Ensure templates do not exist cisco.mso.ndo_template: - <<: *template_absent \ No newline at end of file + <<: *template_absent diff --git a/tests/integration/targets/ndo_route_map_policy_multicast/tasks/main.yml b/tests/integration/targets/ndo_route_map_policy_multicast/tasks/main.yml index 1199fb3c..f36f1e3d 100644 --- a/tests/integration/targets/ndo_route_map_policy_multicast/tasks/main.yml +++ b/tests/integration/targets/ndo_route_map_policy_multicast/tasks/main.yml @@ -5,19 +5,19 @@ - name: Test that we have an ACI MultiSite host, username and password ansible.builtin.fail: - msg: 'Please define the following variables: mso_hostname, mso_username and mso_password.' + msg: "Please define the following variables: mso_hostname, mso_username and mso_password." when: mso_hostname is not defined or mso_username is not defined or mso_password is not defined # CLEAN ENVIRONMENT - name: Set vars ansible.builtin.set_fact: mso_info: &mso_info - host: '{{ mso_hostname }}' - username: '{{ mso_username }}' - password: '{{ mso_password }}' - validate_certs: '{{ mso_validate_certs | default(false) }}' - use_ssl: '{{ mso_use_ssl | default(true) }}' - use_proxy: '{{ mso_use_proxy | default(true) }}' + host: "{{ mso_hostname }}" + username: "{{ mso_username }}" + password: "{{ mso_password }}" + validate_certs: "{{ mso_validate_certs | default(false) }}" + use_ssl: "{{ mso_use_ssl | default(true) }}" + use_proxy: "{{ mso_use_proxy | default(true) }}" output_level: '{{ mso_output_level | default("info") }}' # QUERY VERSION @@ -27,31 +27,29 @@ state: query register: version - - name: Execute tasks only for MSO version > 4.3 when: version.current.version is version('4.3', '>=') block: - - name: Ensure sites exists cisco.mso.mso_site: <<: *mso_info - site: '{{ item.site }}' - apic_username: '{{ apic_username }}' - apic_password: '{{ apic_password }}' - apic_site_id: '{{ item.apic_site_id }}' + site: "{{ item.site }}" + apic_username: "{{ apic_username }}" + apic_password: "{{ apic_password }}" + apic_site_id: "{{ item.apic_site_id }}" urls: - https://{{ apic_hostname }} state: present loop: - - {site: "ansible_test", apic_site_id: 101} - - {site: "ansible_test_2", apic_site_id: 102} + - { site: "ansible_test", apic_site_id: 101 } + - { site: "ansible_test_2", apic_site_id: 102 } - name: Ensure tenants exist - cisco.mso.mso_tenant: + cisco.mso.mso_tenant: <<: *mso_info - tenant: '{{ item }}' + tenant: "{{ item }}" users: - - '{{ mso_username }}' + - "{{ mso_username }}" sites: - '{{ mso_site | default("ansible_test") }}' - ansible_test_2 @@ -75,7 +73,8 @@ # CREATE - name: Create a new route map policy multicast (check_mode) - cisco.mso.ndo_route_map_policy_multicast: &create_route_map_policy_multicast + cisco.mso.ndo_route_map_policy_multicast: + &create_route_map_policy_multicast <<: *mso_info template: ansible_tenant_template route_map_policy: ansible_test_route_map_policy @@ -104,37 +103,38 @@ - cm_create_new_route_map_policy_multicast is changed - cm_create_new_route_map_policy_multicast.previous == {} - cm_create_new_route_map_policy_multicast.current.name == "ansible_test_route_map_policy" - - cm_create_new_route_map_policy_multicast.current.entries.0.order == 1 - - cm_create_new_route_map_policy_multicast.current.entries.0.group == "226.2.2.0/24" - - cm_create_new_route_map_policy_multicast.current.entries.0.source == "1.1.1.1/24" - - cm_create_new_route_map_policy_multicast.current.entries.0.action == "permit" + - cm_create_new_route_map_policy_multicast.current.mcastRtMapEntryList.0.order == 1 + - cm_create_new_route_map_policy_multicast.current.mcastRtMapEntryList.0.group == "226.2.2.0/24" + - cm_create_new_route_map_policy_multicast.current.mcastRtMapEntryList.0.source == "1.1.1.1/24" + - cm_create_new_route_map_policy_multicast.current.mcastRtMapEntryList.0.action == "permit" - nm_create_new_route_map_policy_multicast is changed - nm_create_new_route_map_policy_multicast.previous == {} - nm_create_new_route_map_policy_multicast.current.name == "ansible_test_route_map_policy" - - nm_create_new_route_map_policy_multicast.current.entries.0.order == 1 - - nm_create_new_route_map_policy_multicast.current.entries.0.group == "226.2.2.0/24" - - nm_create_new_route_map_policy_multicast.current.entries.0.source == "1.1.1.1/24" - - nm_create_new_route_map_policy_multicast.current.entries.0.action == "permit" + - nm_create_new_route_map_policy_multicast.current.mcastRtMapEntryList.0.order == 1 + - nm_create_new_route_map_policy_multicast.current.mcastRtMapEntryList.0.group == "226.2.2.0/24" + - nm_create_new_route_map_policy_multicast.current.mcastRtMapEntryList.0.source == "1.1.1.1/24" + - nm_create_new_route_map_policy_multicast.current.mcastRtMapEntryList.0.action == "permit" - nm_create_new_route_map_policy_multicast_again is not changed - nm_create_new_route_map_policy_multicast_again.previous.name == "ansible_test_route_map_policy" - nm_create_new_route_map_policy_multicast_again.previous.description == "" - nm_create_new_route_map_policy_multicast_again.previous.uuid is defined - - nm_create_new_route_map_policy_multicast_again.previous.entries.0.order == 1 - - nm_create_new_route_map_policy_multicast_again.previous.entries.0.group == "226.2.2.0/24" - - nm_create_new_route_map_policy_multicast_again.previous.entries.0.source == "1.1.1.1/24" - - nm_create_new_route_map_policy_multicast_again.previous.entries.0.action == "permit" + - nm_create_new_route_map_policy_multicast_again.previous.mcastRtMapEntryList.0.order == 1 + - nm_create_new_route_map_policy_multicast_again.previous.mcastRtMapEntryList.0.group == "226.2.2.0/24" + - nm_create_new_route_map_policy_multicast_again.previous.mcastRtMapEntryList.0.source == "1.1.1.1/24" + - nm_create_new_route_map_policy_multicast_again.previous.mcastRtMapEntryList.0.action == "permit" - nm_create_new_route_map_policy_multicast_again.current.name == "ansible_test_route_map_policy" - nm_create_new_route_map_policy_multicast_again.current.description == "" - nm_create_new_route_map_policy_multicast_again.current.uuid is defined - - nm_create_new_route_map_policy_multicast_again.current.entries.0.order == 1 - - nm_create_new_route_map_policy_multicast_again.current.entries.0.group == "226.2.2.0/24" - - nm_create_new_route_map_policy_multicast_again.current.entries.0.source == "1.1.1.1/24" - - nm_create_new_route_map_policy_multicast_again.current.entries.0.action == "permit" + - nm_create_new_route_map_policy_multicast_again.current.mcastRtMapEntryList.0.order == 1 + - nm_create_new_route_map_policy_multicast_again.current.mcastRtMapEntryList.0.group == "226.2.2.0/24" + - nm_create_new_route_map_policy_multicast_again.current.mcastRtMapEntryList.0.source == "1.1.1.1/24" + - nm_create_new_route_map_policy_multicast_again.current.mcastRtMapEntryList.0.action == "permit" # UPDATE - name: Update a route map policy multicast description (check_mode) - cisco.mso.ndo_route_map_policy_multicast: &update_route_map_policy_multicast + cisco.mso.ndo_route_map_policy_multicast: + &update_route_map_policy_multicast <<: *create_route_map_policy_multicast description: changed_description check_mode: true @@ -164,9 +164,10 @@ - nm_update_route_map_policy_multicast_description_again.current.description == "changed_description" - name: Update a route map policy multicast name - cisco.mso.ndo_route_map_policy_multicast: &update_route_map_policy_multicast_name + cisco.mso.ndo_route_map_policy_multicast: + &update_route_map_policy_multicast_name <<: *update_route_map_policy_multicast - route_map_policy_uuid: '{{ nm_update_route_map_policy_multicast_description.current.uuid }}' + route_map_policy_uuid: "{{ nm_update_route_map_policy_multicast_description.current.uuid }}" route_map_policy: ansible_test_route_map_policy_changed register: nm_update_route_map_policy_multicast_name @@ -182,7 +183,8 @@ register: nm_update_route_map_policy_multicast_entries_change_input - name: Update a route map policy multicast entries to 4 - cisco.mso.ndo_route_map_policy_multicast: &update_route_map_policy_multicast_entries_4 + cisco.mso.ndo_route_map_policy_multicast: + &update_route_map_policy_multicast_entries_4 <<: *update_route_map_policy_multicast_name entries: - order: 1 @@ -266,27 +268,28 @@ - nm_update_route_map_policy_multicast_name.previous.name == "ansible_test_route_map_policy" - nm_update_route_map_policy_multicast_name.current.name == "ansible_test_route_map_policy_changed" - nm_update_route_map_policy_multicast_entries_change_input is changed - - nm_update_route_map_policy_multicast_entries_change_input.previous.entries | length == 1 - - nm_update_route_map_policy_multicast_entries_change_input.previous.entries.0.order == 1 - - nm_update_route_map_policy_multicast_entries_change_input.current.entries | length == 1 - - nm_update_route_map_policy_multicast_entries_change_input.current.entries.0.order == 2 + - nm_update_route_map_policy_multicast_entries_change_input.previous.mcastRtMapEntryList | length == 1 + - nm_update_route_map_policy_multicast_entries_change_input.previous.mcastRtMapEntryList.0.order == 1 + - nm_update_route_map_policy_multicast_entries_change_input.current.mcastRtMapEntryList | length == 1 + - nm_update_route_map_policy_multicast_entries_change_input.current.mcastRtMapEntryList.0.order == 2 - nm_update_route_map_policy_multicast_entries_4 is changed - - nm_update_route_map_policy_multicast_entries_4.previous.entries | length == 1 - - nm_update_route_map_policy_multicast_entries_4.current.entries | length == 4 + - nm_update_route_map_policy_multicast_entries_4.previous.mcastRtMapEntryList | length == 1 + - nm_update_route_map_policy_multicast_entries_4.current.mcastRtMapEntryList | length == 4 - nm_update_route_map_policy_multicast_entries_4_again is not changed - - nm_update_route_map_policy_multicast_entries_4_again.previous.entries | length == 4 - - nm_update_route_map_policy_multicast_entries_4_again.current.entries | length == 4 + - nm_update_route_map_policy_multicast_entries_4_again.previous.mcastRtMapEntryList | length == 4 + - nm_update_route_map_policy_multicast_entries_4_again.current.mcastRtMapEntryList | length == 4 - nm_update_route_map_policy_multicast_entries_4_order is changed - - nm_update_route_map_policy_multicast_entries_4_order.previous.entries | length == 4 - - nm_update_route_map_policy_multicast_entries_4_order.current.entries | length == 4 + - nm_update_route_map_policy_multicast_entries_4_order.previous.mcastRtMapEntryList | length == 4 + - nm_update_route_map_policy_multicast_entries_4_order.current.mcastRtMapEntryList | length == 4 - nm_delete_route_map_policy_multicast_entries_3 is changed - - nm_delete_route_map_policy_multicast_entries_3.previous.entries | length == 4 - - nm_delete_route_map_policy_multicast_entries_3.current.entries | length == 3 + - nm_delete_route_map_policy_multicast_entries_3.previous.mcastRtMapEntryList | length == 4 + - nm_delete_route_map_policy_multicast_entries_3.current.mcastRtMapEntryList | length == 3 # QUERY - name: Create another route map policy multicast - cisco.mso.ndo_route_map_policy_multicast: &create_route_map_policy_multicast_2 + cisco.mso.ndo_route_map_policy_multicast: + &create_route_map_policy_multicast_2 <<: *create_route_map_policy_multicast route_map_policy: ansible_test_route_map_policy_2 description: "This is a test route map policy multicast 2" @@ -315,10 +318,11 @@ # ERRORS - name: Error entries provided as null on create - cisco.mso.ndo_route_map_policy_multicast: &create_route_map_policy_multicast_null_entries + cisco.mso.ndo_route_map_policy_multicast: + &create_route_map_policy_multicast_null_entries <<: *create_route_map_policy_multicast route_map_policy: ansible_test_route_map_policy_3 - entries: '{{ fakevar | default(omit)}}' + entries: "{{ fakevar | default(omit)}}" register: err_entries_create_null ignore_errors: true @@ -349,7 +353,8 @@ # DELETE - name: Delete a route map policy multicast (check_mode) - cisco.mso.ndo_route_map_policy_multicast: &delete_route_map_policy_multicast + cisco.mso.ndo_route_map_policy_multicast: + &delete_route_map_policy_multicast <<: *update_route_map_policy_multicast_name state: absent check_mode: true @@ -370,11 +375,11 @@ that: - cm_delete_route_map_policy_multicast is changed - cm_delete_route_map_policy_multicast.previous.name == 'ansible_test_route_map_policy_changed' - - cm_delete_route_map_policy_multicast.previous.entries | length == 3 + - cm_delete_route_map_policy_multicast.previous.mcastRtMapEntryList | length == 3 - cm_delete_route_map_policy_multicast.current == {} - nm_delete_route_map_policy_multicast is changed - nm_delete_route_map_policy_multicast.previous.name == 'ansible_test_route_map_policy_changed' - - nm_delete_route_map_policy_multicast.previous.entries | length == 3 + - nm_delete_route_map_policy_multicast.previous.mcastRtMapEntryList | length == 3 - nm_delete_route_map_policy_multicast.current == {} - nm_delete_route_map_policy_multicast_again is not changed - nm_delete_route_map_policy_multicast_again.previous == {}