From 4a3afc469afb0cf926c84a8479abfdb791747754 Mon Sep 17 00:00:00 2001 From: akinross Date: Thu, 13 Jun 2024 20:05:17 +0200 Subject: [PATCH] [minor_change] Added module ndo_dhcp_relay_policy to support dhcp relay policy configuration in tenant templates --- plugins/modules/ndo_dhcp_relay_policy.py | 307 ++++++++++ .../targets/ndo_dhcp_relay_policy/aliases | 2 + .../ndo_dhcp_relay_policy/tasks/main.yml | 545 ++++++++++++++++++ 3 files changed, 854 insertions(+) create mode 100644 plugins/modules/ndo_dhcp_relay_policy.py create mode 100644 tests/integration/targets/ndo_dhcp_relay_policy/aliases create mode 100644 tests/integration/targets/ndo_dhcp_relay_policy/tasks/main.yml diff --git a/plugins/modules/ndo_dhcp_relay_policy.py b/plugins/modules/ndo_dhcp_relay_policy.py new file mode 100644 index 00000000..17311f6a --- /dev/null +++ b/plugins/modules/ndo_dhcp_relay_policy.py @@ -0,0 +1,307 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +# Copyright: (c) 2024, Akini Ross (@akinross) + +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) + +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + +ANSIBLE_METADATA = {"metadata_version": "1.1", "status": ["preview"], "supported_by": "community"} + +DOCUMENTATION = r""" +--- +module: ndo_dhcp_relay_policy +short_description: Manage DHCP Relay Policies on Cisco Nexus Dashboard Orchestrator (NDO). +description: +- Manage DHCP Relay Policies on Cisco Nexus Dashboard Orchestrator (NDO). +author: +- Akini Ross (@akinross) +options: + template: + description: + - The name of the template. + - The template must be a tenant template. + type: str + required: true + relay_policy: + description: + - The name of the DHCP Relay Policy. + type: str + aliases: [ name ] + relay_policy_uuid: + description: + - The uuid of the DHCP Relay Policy. + - This parameter is required when the O(relay_policy) needs to be updated. + type: str + aliases: [ uuid ] + description: + description: + - The description of the DHCP Relay Policy. + type: str + providers: + description: + - A list of providers attached to the DHCP Relay Policy. + - The list of configured providers must contain at least one provider. + - When the list of providers is null the update will not change existing providers configuration. + type: list + elements: dict + suboptions: + schema: + description: + - The name of the schema for the (External) EPG. + type: str + required: true + template: + description: + - The name of the template for the (External) EPG. + type: str + required: true + anp: + description: + - The name of the Application Profile (ANP). + - This parameter is required when O(providers.epg) is provided. + type: str + epg: + description: + - The name of the Endpoint Group (EPG). + - O(providers.epg) and O(providers.external_epg) are mutually exclusive. + - O(providers.epg) is required when O(providers.external_epg) is not provided. + type: str + external_epg: + description: + - The name of the External Endpoint Group (EPG). + - O(providers.external_epg) and O(providers.epg) are mutually exclusive. + - O(providers.external_epg) is required when O(providers.epg) is not provided. + type: str + ip: + description: + - The IP address of the DHCP server. + type: str + required: true + use_server_vrf: + description: + - Use the server VRF. + type: bool + default: false + state: + description: + - Use C(absent) for removing. + - Use C(query) for listing an object or multiple objects. + - Use C(present) for creating or updating. + type: str + choices: [ absent, query, present ] + default: query +extends_documentation_fragment: cisco.mso.modules +""" + +EXAMPLES = r""" +- name: Create a new dhcp relay policy + cisco.mso.ndo_dhcp_relay_policy: + host: mso_host + username: admin + password: SomeSecretPassword + template: ansible_tenant_template + relay_policy: ansible_test_relay_policy + providers: + - name: option_1 + id: 1 + data: data_1 + state: present + +- name: Query a dhcp relay policy with template_name + cisco.mso.ndo_dhcp_relay_policy: + host: mso_host + username: admin + password: SomeSecretPassword + template: ansible_tenant_template + relay_policy: ansible_test_relay_policy + state: query + register: query_one + +- name: Query all dhcp relay policy in the template + cisco.mso.ndo_dhcp_relay_policy: + host: mso_host + username: admin + password: SomeSecretPassword + template: ansible_tenant_template + state: query + register: query_all + +- name: Delete a dhcp relay policy + cisco.mso.ndo_dhcp_relay_policy: + host: mso_host + username: admin + password: SomeSecretPassword + template: ansible_tenant_template + relay_policy: ansible_test_relay_policy + state: absent +""" + +RETURN = r""" +""" + + +import copy +from ansible.module_utils.basic import AnsibleModule +from ansible_collections.cisco.mso.plugins.module_utils.mso import MSOModule, mso_argument_spec +from ansible_collections.cisco.mso.plugins.module_utils.schema import MSOSchema +from ansible_collections.cisco.mso.plugins.module_utils.template import MSOTemplate, KVPair + + +def main(): + argument_spec = mso_argument_spec() + argument_spec.update( + template=dict(type="str", required=True), + relay_policy=dict(type="str", aliases=["name"]), + relay_policy_uuid=dict(type="str", aliases=["uuid"]), + description=dict(type="str"), + providers=dict( + type="list", + elements="dict", + options=dict( + schema=dict(type="str", required=True), + template=dict(type="str", required=True), + anp=dict(type="str"), + epg=dict(type="str"), + external_epg=dict(type="str"), + ip=dict(type="str", required=True), + use_server_vrf=dict(type="bool", default=False), + ), + ), + state=dict(type="str", default="query", choices=["absent", "query", "present"]), + ) + + module = AnsibleModule( + argument_spec=argument_spec, + supports_check_mode=True, + required_if=[ + ["state", "absent", ["relay_policy"]], + ["state", "present", ["relay_policy"]], + ], + ) + + mso = MSOModule(module) + + template = module.params.get("template") + relay_policy = module.params.get("relay_policy") + relay_policy_uuid = module.params.get("relay_policy_uuid") + providers = get_providers_payload(mso, module.params.get("providers")) if module.params.get("providers") else [] + description = module.params.get("description") + state = module.params.get("state") + + ops = [] + match = None + err_message_min_providers = "At least one provider is required when state is present." + + mso_template = MSOTemplate(mso, "tenant", template) + mso_template.validate_template("tenantPolicy") + + path = "/tenantPolicyTemplate/template/dhcpRelayPolicies" + existing_dhcp_option_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_option_policies, relay_policy_uuid) + else: + kv_list = [KVPair("name", relay_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": + + if match: + + if module.params.get("providers") is not None and len(providers) == 0: + mso.fail_json(msg=err_message_min_providers) + + if relay_policy and match.details.get("name") != relay_policy: + ops.append(dict(op="replace", path="{0}/{1}/name".format(path, match.index), value=relay_policy)) + match.details["name"] = relay_policy + + if description is not None and match.details.get("description") != description: + ops.append(dict(op="replace", path="{0}/{1}/description".format(path, match.index), value=description)) + match.details["description"] = description + + if module.params.get("providers") is not None and match.details.get("providers") != providers: + ops.append(dict(op="replace", path="{0}/{1}/providers".format(path, match.index), value=providers)) + match.details["providers"] = providers + + mso.sanitize(match.details) + + else: + + if not providers: + mso.fail_json(msg=err_message_min_providers) + + payload = {"name": relay_policy, "providers": providers} + if description: + payload["description"] = description + + ops.append(dict(op="add", path="{0}/-".format(path), value=payload)) + + mso.sanitize(payload) + + mso.existing = mso.proposed + + elif state == "absent": + if match: + ops.append(dict(op="remove", path="{0}/{1}".format(path, match.index))) + mso.existing = {} + + if not module.check_mode and ops: + mso.request(mso_template.template_path, method="PATCH", data=ops) + + mso.exit_json() + + +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") + epg = provider.get("epg") + external_epg = provider.get("external_epg") + ip = provider.get("ip") + + provider_payload = {"ip": ip, "useServerVrf": provider.get("use_server_vrf")} + + # Check if schema is already in cache, if not create a new MSOSchema object and add it to the cache. + if not schema_cache.get(schema): + schema_cache[schema] = MSOSchema(mso, schema) + + schema_cache[schema].set_template(template) + + if epg and not anp: + mso.fail_json(msg="The anp argument is required for each provider when the epg argument is provided.") + elif not epg and not external_epg: + mso.fail_json(msg="The epg or external_epg argument is required for each provider.") + elif epg and external_epg: + mso.fail_json(msg="The epg and external_epg arguments are mutually exclusive for each provider.") + elif external_epg and anp: + mso.fail_json(msg="The anp and external_epg arguments are mutually exclusive for each provider.") + elif epg: + schema_cache[schema].set_template_anp(anp) + schema_cache[schema].set_template_anp_epg(epg) + provider_payload["epgRef"] = schema_cache[schema].schema_objects["template_anp_epg"].details.get("uuid") + else: + schema_cache[schema].set_template_external_epg(external_epg) + provider_payload["externalEpgRef"] = schema_cache[schema].schema_objects.get("template_external_epg").details.get("uuid") + + payload.append(provider_payload) + return payload + + +if __name__ == "__main__": + main() diff --git a/tests/integration/targets/ndo_dhcp_relay_policy/aliases b/tests/integration/targets/ndo_dhcp_relay_policy/aliases new file mode 100644 index 00000000..5042c9c0 --- /dev/null +++ b/tests/integration/targets/ndo_dhcp_relay_policy/aliases @@ -0,0 +1,2 @@ +# No ACI MultiSite infrastructure, so not enabled +# unsupported diff --git a/tests/integration/targets/ndo_dhcp_relay_policy/tasks/main.yml b/tests/integration/targets/ndo_dhcp_relay_policy/tasks/main.yml new file mode 100644 index 00000000..3e7088c5 --- /dev/null +++ b/tests/integration/targets/ndo_dhcp_relay_policy/tasks/main.yml @@ -0,0 +1,545 @@ +# Test code for the MSO modules +# Copyright: (c) 2024, Akini Ross (@akinross) + +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) + +- 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.' + 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) }}' + output_level: '{{ mso_output_level | default("info") }}' + +# QUERY VERSION +- name: Query MSO version + cisco.mso.mso_version: + <<: *mso_info + 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 }}' + urls: + - https://{{ apic_hostname }} + state: present + loop: + - {site: "ansible_test", apic_site_id: 101} + - {site: "ansible_test_2", apic_site_id: 102} + + - name: Ensure tenant exist + cisco.mso.mso_tenant: + <<: *mso_info + tenant: '{{ item }}' + users: + - '{{ mso_username }}' + sites: + - '{{ mso_site | default("ansible_test") }}' + - ansible_test_2 + state: present + loop: + - ansible_test + + - name: Ensure templates do not exist + cisco.mso.ndo_template: &template_absent + <<: *mso_info + name: ansible_tenant_template + template_type: tenant + tenant: ansible_test + state: absent + + - name: Ensure schemas do not exist + cisco.mso.mso_schema: &remove_schemas + <<: *mso_info + schema: '{{ mso_schema | default("ansible_test") }}' + state: absent + + - name: Ensure schema with template exists + cisco.mso.mso_schema_template: + <<: *mso_info + schema: '{{ mso_schema | default("ansible_test") }}' + tenant: ansible_test + template: ansible_test + state: present + + - name: Ensure ANP exist + cisco.mso.mso_schema_template_anp: &ansible_test_anp + <<: *mso_info + schema: '{{ mso_schema | default("ansible_test") }}' + template: ansible_test + anp: ansible_test_anp + state: present + + - name: Ensure EPGs exist + cisco.mso.mso_schema_template_anp_epg: + <<: *ansible_test_anp + epg: "{{ item }}" + state: present + loop: + - ansible_test_epg_1 + - ansible_test_epg_2 + + - name: Ensure VRF exist + cisco.mso.mso_schema_template_vrf: + <<: *mso_info + schema: '{{ mso_schema | default("ansible_test") }}' + template: ansible_test + vrf: ansible_test_vrf + state: present + + - name: Ensure External EPGs exist + cisco.mso.mso_schema_template_externalepg: + <<: *mso_info + schema: '{{ mso_schema | default("ansible_test") }}' + template: ansible_test + external_epg: "{{ item }}" + vrf: + name: ansible_test_vrf + template: ansible_test + schema: '{{ mso_schema | default("ansible_test") }}' + state: present + loop: + - ansible_test_external_epg_1 + - ansible_test_external_epg_2 + + - name: Ensure templates exist + cisco.mso.ndo_template: + <<: *template_absent + state: present + + # CREATE + + - name: Create a new dhcp relay policy (check_mode) + cisco.mso.ndo_dhcp_relay_policy: &create_dhcp_relay_policy + <<: *mso_info + template: ansible_tenant_template + relay_policy: ansible_test_relay_policy + providers: + - schema: '{{ mso_schema | default("ansible_test") }}' + template: ansible_test + anp: ansible_test_anp + epg: ansible_test_epg_1 + ip: 1.1.1.1 + state: present + check_mode: true + register: cm_create_new_dhcp_relay_policy + + - name: Create a new dhcp relay policy + cisco.mso.ndo_dhcp_relay_policy: + <<: *create_dhcp_relay_policy + register: nm_create_new_dhcp_relay_policy + + - name: Create a new dhcp relay policy again + cisco.mso.ndo_dhcp_relay_policy: + <<: *create_dhcp_relay_policy + register: nm_create_new_dhcp_relay_policy_again + + - name: Assert dhcp relay policy was created + assert: + that: + - cm_create_new_dhcp_relay_policy is changed + - cm_create_new_dhcp_relay_policy.previous == {} + - cm_create_new_dhcp_relay_policy.current.name == "ansible_test_relay_policy" + - cm_create_new_dhcp_relay_policy.current.providers.0.epgRef is defined + - cm_create_new_dhcp_relay_policy.current.providers.0.ip == "1.1.1.1" + - cm_create_new_dhcp_relay_policy.current.providers.0.useServerVrf == false + - nm_create_new_dhcp_relay_policy is changed + - nm_create_new_dhcp_relay_policy.previous == {} + - nm_create_new_dhcp_relay_policy.current.name == "ansible_test_relay_policy" + - nm_create_new_dhcp_relay_policy.current.providers.0.epgRef is defined + - nm_create_new_dhcp_relay_policy.current.providers.0.ip == "1.1.1.1" + - nm_create_new_dhcp_relay_policy.current.providers.0.useServerVrf == false + - nm_create_new_dhcp_relay_policy_again is not changed + - nm_create_new_dhcp_relay_policy_again.previous.name == "ansible_test_relay_policy" + - nm_create_new_dhcp_relay_policy_again.previous.description == "" + - nm_create_new_dhcp_relay_policy_again.previous.uuid is defined + - nm_create_new_dhcp_relay_policy_again.previous.providers.0.epgRef is defined + - nm_create_new_dhcp_relay_policy_again.previous.providers.0.ip == "1.1.1.1" + - nm_create_new_dhcp_relay_policy_again.previous.providers.0.useServerVrf == false + - nm_create_new_dhcp_relay_policy_again.current.name == "ansible_test_relay_policy" + - nm_create_new_dhcp_relay_policy_again.current.description == "" + - nm_create_new_dhcp_relay_policy_again.current.uuid is defined + - nm_create_new_dhcp_relay_policy_again.current.providers.0.epgRef is defined + - nm_create_new_dhcp_relay_policy_again.current.providers.0.ip == "1.1.1.1" + - nm_create_new_dhcp_relay_policy_again.current.providers.0.useServerVrf == false + + # UPDATE + + - name: Update a dhcp relay policy description (check_mode) + cisco.mso.ndo_dhcp_relay_policy: &update_dhcp_relay_policy + <<: *create_dhcp_relay_policy + description: changed_description + check_mode: true + register: cm_update_dhcp_relay_policy_description + + - name: Update a dhcp relay policy description + cisco.mso.ndo_dhcp_relay_policy: + <<: *update_dhcp_relay_policy + register: nm_update_dhcp_relay_policy_description + + - name: Update a dhcp relay policy description again + cisco.mso.ndo_dhcp_relay_policy: + <<: *update_dhcp_relay_policy + register: nm_update_dhcp_relay_policy_description_again + + - name: Assert dhcp relay policy was updated + assert: + that: + - cm_update_dhcp_relay_policy_description is changed + - cm_update_dhcp_relay_policy_description.previous.description == "" + - cm_update_dhcp_relay_policy_description.current.description == "changed_description" + - nm_update_dhcp_relay_policy_description is changed + - nm_update_dhcp_relay_policy_description.previous.description == "" + - nm_update_dhcp_relay_policy_description.current.description == "changed_description" + - nm_update_dhcp_relay_policy_description_again is not changed + - nm_update_dhcp_relay_policy_description_again.previous.description == "changed_description" + - nm_update_dhcp_relay_policy_description_again.current.description == "changed_description" + + - name: Update a dhcp relay policy name + cisco.mso.ndo_dhcp_relay_policy: &update_dhcp_relay_policy_name + <<: *update_dhcp_relay_policy + relay_policy_uuid: '{{ nm_update_dhcp_relay_policy_description.current.uuid }}' + relay_policy: ansible_test_relay_policy_changed + register: nm_update_dhcp_relay_policy_name + + - name: Update a dhcp relay policy providers change input + cisco.mso.ndo_dhcp_relay_policy: + <<: *update_dhcp_relay_policy_name + providers: + - schema: '{{ mso_schema | default("ansible_test") }}' + template: ansible_test + external_epg: ansible_test_external_epg_1 + ip: 2.2.2.2 + use_server_vrf: true + register: nm_update_dhcp_relay_policy_providers_change_input + + - name: Update a dhcp relay policy providers to 4 + cisco.mso.ndo_dhcp_relay_policy: &update_dhcp_relay_policy_providers_4 + <<: *update_dhcp_relay_policy_name + providers: + - schema: '{{ mso_schema | default("ansible_test") }}' + template: ansible_test + anp: ansible_test_anp + epg: ansible_test_epg_1 + ip: 1.1.1.1 + - schema: '{{ mso_schema | default("ansible_test") }}' + template: ansible_test + anp: ansible_test_anp + epg: ansible_test_epg_2 + ip: 2.2.2.2 + use_server_vrf: true + - schema: '{{ mso_schema | default("ansible_test") }}' + template: ansible_test + external_epg: ansible_test_external_epg_1 + ip: 3.3.3.3 + - schema: '{{ mso_schema | default("ansible_test") }}' + template: ansible_test + external_epg: ansible_test_external_epg_2 + ip: 4.4.4.4 + use_server_vrf: true + register: nm_update_dhcp_relay_policy_providers_4 + + - name: Update a dhcp relay policy providers to 4 again + cisco.mso.ndo_dhcp_relay_policy: + <<: *update_dhcp_relay_policy_providers_4 + register: nm_update_dhcp_relay_policy_providers_4_again + + - name: Update a dhcp relay policy providers order without change + cisco.mso.ndo_dhcp_relay_policy: + <<: *update_dhcp_relay_policy_name + providers: + - schema: '{{ mso_schema | default("ansible_test") }}' + template: ansible_test + anp: ansible_test_anp + epg: ansible_test_epg_1 + ip: 1.1.1.1 + - schema: '{{ mso_schema | default("ansible_test") }}' + template: ansible_test + anp: ansible_test_anp + epg: ansible_test_epg_2 + ip: 2.2.2.2 + use_server_vrf: true + - schema: '{{ mso_schema | default("ansible_test") }}' + template: ansible_test + external_epg: ansible_test_external_epg_2 + ip: 4.4.4.4 + use_server_vrf: true + - schema: '{{ mso_schema | default("ansible_test") }}' + template: ansible_test + external_epg: ansible_test_external_epg_1 + ip: 3.3.3.3 + register: nm_update_dhcp_relay_policy_providers_4_order + + - name: Delete a dhcp relay policy relay from the list + cisco.mso.ndo_dhcp_relay_policy: + <<: *update_dhcp_relay_policy_name + providers: + - schema: '{{ mso_schema | default("ansible_test") }}' + template: ansible_test + anp: ansible_test_anp + epg: ansible_test_epg_1 + ip: 1.1.1.1 + - schema: '{{ mso_schema | default("ansible_test") }}' + template: ansible_test + external_epg: ansible_test_external_epg_2 + ip: 4.4.4.4 + use_server_vrf: true + - schema: '{{ mso_schema | default("ansible_test") }}' + template: ansible_test + external_epg: ansible_test_external_epg_1 + ip: 3.3.3.3 + register: nm_delete_dhcp_relay_policy_providers_3 + + - name: Assert dhcp relay policy was updated + assert: + that: + - nm_update_dhcp_relay_policy_name is changed + - nm_update_dhcp_relay_policy_name.previous.name == "ansible_test_relay_policy" + - nm_update_dhcp_relay_policy_name.current.name == "ansible_test_relay_policy_changed" + - nm_update_dhcp_relay_policy_providers_change_input is changed + - nm_update_dhcp_relay_policy_providers_change_input.previous.providers | length == 1 + - nm_update_dhcp_relay_policy_providers_change_input.previous.providers.0.epgRef is defined + - nm_update_dhcp_relay_policy_providers_change_input.previous.providers.0.ip == "1.1.1.1" + - nm_update_dhcp_relay_policy_providers_change_input.previous.providers.0.useServerVrf == false + - nm_update_dhcp_relay_policy_providers_change_input.current.providers | length == 1 + - nm_update_dhcp_relay_policy_providers_change_input.current.providers.0.externalEpgRef is defined + - nm_update_dhcp_relay_policy_providers_change_input.current.providers.0.ip == "2.2.2.2" + - nm_update_dhcp_relay_policy_providers_change_input.current.providers.0.useServerVrf == true + - nm_update_dhcp_relay_policy_providers_4 is changed + - nm_update_dhcp_relay_policy_providers_4.previous.providers | length == 1 + - nm_update_dhcp_relay_policy_providers_4.current.providers | length == 4 + - nm_update_dhcp_relay_policy_providers_4_again is not changed + - nm_update_dhcp_relay_policy_providers_4_again.previous.providers | length == 4 + - nm_update_dhcp_relay_policy_providers_4_again.current.providers | length == 4 + - nm_update_dhcp_relay_policy_providers_4_order is changed + - nm_update_dhcp_relay_policy_providers_4_order.previous.providers | length == 4 + - nm_update_dhcp_relay_policy_providers_4_order.current.providers | length == 4 + - nm_delete_dhcp_relay_policy_providers_3 is changed + - nm_delete_dhcp_relay_policy_providers_3.previous.providers | length == 4 + - nm_delete_dhcp_relay_policy_providers_3.current.providers | length == 3 + + # QUERY + + - name: Create another dhcp relay policy + cisco.mso.ndo_dhcp_relay_policy: &create_dhcp_relay_policy_2 + <<: *create_dhcp_relay_policy + relay_policy: ansible_test_relay_policy_2 + description: "This is a test relay policy 2" + + - name: Query a dhcp relay policy with template_name + cisco.mso.ndo_dhcp_relay_policy: + <<: *create_dhcp_relay_policy_2 + state: query + register: query_one + + - name: Query all dhcp relay policy in the template + cisco.mso.ndo_dhcp_relay_policy: + <<: *mso_info + template: ansible_tenant_template + state: query + register: query_all + + - name: Assert dhcp relay policy was queried + assert: + that: + - query_one is not changed + - query_one.current.name == "ansible_test_relay_policy_2" + - query_all is not changed + - query_all.current | length == 2 + + # ERRORS + + - name: Error providers provided as null on create + cisco.mso.ndo_dhcp_relay_policy: &create_dhcp_relay_policy_null_providers + <<: *create_dhcp_relay_policy + relay_policy: ansible_test_relay_policy_3 + providers: '{{ fakevar | default(omit)}}' + register: err_providers_create_null + ignore_errors: true + + - name: Error providers provided as empty list on create + cisco.mso.ndo_dhcp_relay_policy: + <<: *create_dhcp_relay_policy_null_providers + providers: [] + register: err_providers_create_empty_list + ignore_errors: true + + - name: Error no providers provided on update + cisco.mso.ndo_dhcp_relay_policy: + <<: *update_dhcp_relay_policy_name + providers: [] + register: err_providers_update_empty_list + ignore_errors: true + + - name: Error providers provided no schema + cisco.mso.ndo_dhcp_relay_policy: + <<: *create_dhcp_relay_policy + relay_policy: ansible_test_relay_policy_error + providers: + - template: ansible_test + anp: ansible_test_anp + epg: ansible_test_epg_1 + ip: 1.1.1.1 + register: err_providers_create_no_schema + ignore_errors: true + + - name: Error providers provided no template + cisco.mso.ndo_dhcp_relay_policy: + <<: *create_dhcp_relay_policy + relay_policy: ansible_test_relay_policy_error + providers: + - schema: '{{ mso_schema | default("ansible_test") }}' + anp: ansible_test_anp + epg: ansible_test_epg_1 + ip: 1.1.1.1 + register: err_providers_create_no_template + ignore_errors: true + + - name: Error providers provided no ip + cisco.mso.ndo_dhcp_relay_policy: + <<: *create_dhcp_relay_policy + relay_policy: ansible_test_relay_policy_error + providers: + - schema: '{{ mso_schema | default("ansible_test") }}' + template: ansible_test + anp: ansible_test_anp + epg: ansible_test_epg_1 + register: err_providers_create_no_ip + ignore_errors: true + + - name: Error providers provided no epg or external_epg + cisco.mso.ndo_dhcp_relay_policy: + <<: *create_dhcp_relay_policy + relay_policy: ansible_test_relay_policy_error + providers: + - schema: '{{ mso_schema | default("ansible_test") }}' + template: ansible_test + ip: 1.1.1.1 + register: err_providers_create_no_epg_or_external_epg + ignore_errors: true + + - name: Error providers provided epg and external_epg + cisco.mso.ndo_dhcp_relay_policy: + <<: *create_dhcp_relay_policy + relay_policy: ansible_test_relay_policy_error + providers: + - schema: '{{ mso_schema | default("ansible_test") }}' + template: ansible_test + anp: ansible_test_anp + epg: ansible_test_epg_1 + external_epg: ansible_test_external_epg_1 + ip: 1.1.1.1 + register: err_providers_create_epg_and_external_epg + ignore_errors: true + + - name: Error providers provided anp and external_epg + cisco.mso.ndo_dhcp_relay_policy: + <<: *create_dhcp_relay_policy + relay_policy: ansible_test_relay_policy_error + providers: + - schema: '{{ mso_schema | default("ansible_test") }}' + template: ansible_test + anp: ansible_test_anp + external_epg: ansible_test_external_epg_1 + ip: 1.1.1.1 + register: err_providers_create_anp_and_external_epg + ignore_errors: true + + - name: Error providers provided no anp with epg + cisco.mso.ndo_dhcp_relay_policy: + <<: *create_dhcp_relay_policy + relay_policy: ansible_test_relay_policy_error + providers: + - schema: '{{ mso_schema | default("ansible_test") }}' + template: ansible_test + epg: ansible_test_epg_1 + ip: 1.1.1.1 + register: err_providers_create_no_anp + ignore_errors: true + + - name: Assert errors + assert: + that: + - err_providers_create_null is failed + - err_providers_create_null.msg == "At least one provider is required when state is present." + - err_providers_create_empty_list is failed + - err_providers_create_empty_list.msg == "At least one provider is required when state is present." + - err_providers_update_empty_list is failed + - err_providers_update_empty_list.msg == "At least one provider is required when state is present." + - err_providers_create_no_schema is failed + - err_providers_create_no_schema.msg == "missing required arguments{{":"}} schema found in providers" + - err_providers_create_no_template is failed + - err_providers_create_no_template.msg == "missing required arguments{{":"}} template found in providers" + - err_providers_create_no_ip is failed + - err_providers_create_no_ip.msg == "missing required arguments{{":"}} ip found in providers" + - err_providers_create_no_epg_or_external_epg is failed + - err_providers_create_no_epg_or_external_epg.msg == "The epg or external_epg argument is required for each provider." + - err_providers_create_epg_and_external_epg is failed + - err_providers_create_epg_and_external_epg.msg == "The epg and external_epg arguments are mutually exclusive for each provider." + - err_providers_create_anp_and_external_epg is failed + - err_providers_create_anp_and_external_epg.msg == "The anp and external_epg arguments are mutually exclusive for each provider." + - err_providers_create_no_anp is failed + - err_providers_create_no_anp.msg == "The anp argument is required for each provider when the epg argument is provided." + + # DELETE + + - name: Delete a dhcp relay policy (check_mode) + cisco.mso.ndo_dhcp_relay_policy: &delete_dhcp_relay_policy + <<: *update_dhcp_relay_policy_name + state: absent + check_mode: true + register: cm_delete_dhcp_relay_policy + + - name: Delete a dhcp relay policy + cisco.mso.ndo_dhcp_relay_policy: + <<: *delete_dhcp_relay_policy + register: nm_delete_dhcp_relay_policy + + - name: Delete a dhcp relay policy again + cisco.mso.ndo_dhcp_relay_policy: + <<: *delete_dhcp_relay_policy + register: nm_delete_dhcp_relay_policy_again + + - name: Assert dhcp relay policy was deleted + assert: + that: + - cm_delete_dhcp_relay_policy is changed + - cm_delete_dhcp_relay_policy.previous.name == 'ansible_test_relay_policy_changed' + - cm_delete_dhcp_relay_policy.previous.providers | length == 3 + - cm_delete_dhcp_relay_policy.current == {} + - nm_delete_dhcp_relay_policy is changed + - nm_delete_dhcp_relay_policy.previous.name == 'ansible_test_relay_policy_changed' + - nm_delete_dhcp_relay_policy.previous.providers | length == 3 + - nm_delete_dhcp_relay_policy.current == {} + - nm_delete_dhcp_relay_policy_again is not changed + - nm_delete_dhcp_relay_policy_again.previous == {} + - nm_delete_dhcp_relay_policy_again.current == {} + + # CLEANUP TEMPLATE + + - name: Ensure templates do not exist + cisco.mso.ndo_template: + <<: *template_absent + + - name: Ensure schemas do not exist + cisco.mso.mso_schema: + <<: *remove_schemas