From 9d63e54b18c6b9d6b0cde0461be4db813d7dbf0a Mon Sep 17 00:00:00 2001 From: Shreyas Date: Tue, 10 Dec 2024 18:58:40 -0500 Subject: [PATCH] [minor_change] Addition of new module ndo_ptp_policy and its child ndo_ptp_policy_profiles --- plugins/modules/ndo_ptp_policy.py | 297 ++++++++++++++++++ plugins/modules/ndo_ptp_policy_profiles.py | 255 +++++++++++++++ tests/integration/inventory.networking | 6 +- .../targets/ndo_ptp_policy/aliases | 2 + .../targets/ndo_ptp_policy/tasks/main.yml | 234 ++++++++++++++ .../targets/ndo_ptp_policy_profiles/aliases | 2 + .../ndo_ptp_policy_profiles/tasks/main.yml | 247 +++++++++++++++ 7 files changed, 1040 insertions(+), 3 deletions(-) create mode 100644 plugins/modules/ndo_ptp_policy.py create mode 100644 plugins/modules/ndo_ptp_policy_profiles.py create mode 100644 tests/integration/targets/ndo_ptp_policy/aliases create mode 100644 tests/integration/targets/ndo_ptp_policy/tasks/main.yml create mode 100644 tests/integration/targets/ndo_ptp_policy_profiles/aliases create mode 100644 tests/integration/targets/ndo_ptp_policy_profiles/tasks/main.yml diff --git a/plugins/modules/ndo_ptp_policy.py b/plugins/modules/ndo_ptp_policy.py new file mode 100644 index 00000000..d6a4887b --- /dev/null +++ b/plugins/modules/ndo_ptp_policy.py @@ -0,0 +1,297 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +# Copyright: (c) 2024, Shreyas Srish (@shrsr) + +# 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_ptp_policy +short_description: Manage PTP Policies on Cisco Nexus Dashboard Orchestrator (NDO). +description: +- Manage PTP Policies on Cisco Nexus Dashboard Orchestrator (NDO). +- This module is only supported on ND v3.1 (NDO v4.3) and later. +author: +- Shreyas Srish (@shrsr) +options: + template: + description: + - The name of the template. + - The template must be a fabric policy template. + type: str + required: true + ptp_policy: + description: + - The name of the PTP policy. + type: str + aliases: [ name ] + ptp_policy_uuid: + description: + - The uuid of the PTP policy. + - This parameter is required when the O(ptp_policy) needs to be updated. + type: str + aliases: [ uuid ] + description: + description: + - The description of the PTP Policy. + type: str + admin_state: + description: + - The administrative state of the PTP Policy. + type: str + choices: [ enabled, disabled ] + fabric_sync_interval: + description: + - Fabric synchronization interval for the PTP Policy. + - The value should be between -4 to 1. + - This is required when O(state=present). + type: int + global_domain: + description: + - Global domain number for the PTP Policy. + - The value should be between 1 to 128. + - This is required when O(state=present). + type: int + fabric_delay_interval: + description: + - Fabric delay interval for the PTP policy. + - The value should be between -3 to 5. + - This is required when O(state=present). + type: int + global_priority1: + description: + - Priority 1 for the PTP Policy. + - The value should be between 1 to 255. + - This is required when O(state=present). + type: int + global_priority2: + description: + - Priority 2 for the PTP Policy. + - The value should be between 1 to 255. + - This is required when O(state=present). + type: int + fabric_announce_timeout: + description: + - Fabric announce timeout for the PTP policy. + - The value should be between 2 to 10. + - This is required when O(state=present). + type: int + fabric_announce_interval: + description: + - Fabric announce interval for the PTP policy. + - The value should be between 0 to 4. + - This is required when O(state=present). + type: int + fabric_profile_template: + description: + - Fabric profile template for the PTP policy. + type: str + choices: [ aes67, default, smpte ] + 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 PTP policy + cisco.mso.ndo_ptp_policy: + host: mso_host + username: admin + password: SomeSecretPassword + template: ansible_fabric_policy_template + ptp_policy: ansible_test_ptp_policy + admin_state: enabled + fabric_sync_interval: -3 + global_domain: 0 + fabric_delay_interval: -2 + global_priority1: 255 + global_priority2: 255 + fabric_announce_timeout: 3 + fabric_announce_interval: 1 + fabric_profile_template: aes67 + state: present + +- name: Query a PTP policy with ptp_policy name + cisco.mso.ndo_ptp_policy: + host: mso_host + username: admin + password: SomeSecretPassword + template: ansible_fabric_policy_template + ptp_policy: ansible_test_ptp_policy + state: query + register: query_one + +- name: Delete a PTP policy + cisco.mso.ndo_ptp_policy: + host: mso_host + username: admin + password: SomeSecretPassword + template: ansible_fabric_policy_template + ptp_policy: ansible_test_ptp_policy + state: absent + +- name: Delete a PTP policy using UUID + cisco.mso.ndo_ptp_policy_profiles: + host: mso_host + username: admin + password: SomeSecretPassword + template: ansible_fabric_policy_template + ptp_policy_uuid: "{{ query_one.current.uuid }}" + state: absent +""" + +RETURN = r""" +""" + +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.template import MSOTemplate, KVPair +from ansible_collections.cisco.mso.plugins.module_utils.utils import append_update_ops_data +import copy + + +def main(): + argument_spec = mso_argument_spec() + argument_spec.update( + dict( + template=dict(type="str", required=True), + ptp_policy=dict(type="str", aliases=["name"]), + ptp_policy_uuid=dict(type="str", aliases=["uuid"]), + description=dict(type="str"), + admin_state=dict(type="str", choices=["enabled", "disabled"]), + fabric_sync_interval=dict(type="int"), + global_domain=dict(type="int"), + fabric_delay_interval=dict(type="int"), + global_priority1=dict(type="int"), + global_priority2=dict(type="int"), + fabric_announce_timeout=dict(type="int"), + fabric_announce_interval=dict(type="int"), + fabric_profile_template=dict(type="str", choices=["aes67", "default", "smpte"]), + state=dict(type="str", choices=["absent", "query", "present"], default="query"), + ) + ) + + module = AnsibleModule( + argument_spec=argument_spec, + supports_check_mode=True, + required_if=[ + ["state", "present", ["ptp_policy", "ptp_policy_uuid"], True], + ["state", "absent", ["ptp_policy", "ptp_policy_uuid"], True], + [ + "state", + "present", + [ + "global_priority1", + "global_priority2", + "global_domain", + "fabric_announce_timeout", + "fabric_announce_interval", + "fabric_sync_interval", + "fabric_delay_interval", + ], + ], + ], + ) + + mso = MSOModule(module) + + template = module.params.get("template") + ptp_policy = module.params.get("ptp_policy") + ptp_policy_uuid = module.params.get("ptp_policy_uuid") + description = module.params.get("description") + admin_state = module.params.get("admin_state") + fabric_sync_interval = module.params.get("fabric_sync_interval") + global_domain = module.params.get("global_domain") + fabric_delay_interval = module.params.get("fabric_delay_interval") + global_priority1 = module.params.get("global_priority1") + global_priority2 = module.params.get("global_priority2") + fabric_announce_timeout = module.params.get("fabric_announce_timeout") + fabric_announce_interval = module.params.get("fabric_announce_interval") + fabric_profile_template = module.params.get("fabric_profile_template") + state = module.params.get("state") + + ops = [] + match = None + + mso_template = MSOTemplate(mso, "fabric_policy", template) + mso_template.validate_template("fabricPolicy") + object_description = "PTP Policy" + + path = "/fabricPolicyTemplate/template/ptpPolicy" + + existing_ptp_policies = mso_template.template.get("fabricPolicyTemplate", {}).get("template", {}).get("ptpPolicy", {}) + + if ptp_policy or ptp_policy_uuid: + match = mso_template.get_object_by_key_value_pairs( + object_description, + [existing_ptp_policies], + [KVPair("uuid", ptp_policy_uuid) if ptp_policy_uuid else KVPair("name", ptp_policy)], + ) + if match: + mso.existing = mso.previous = copy.deepcopy(match.details) + else: + mso.existing = mso.previous = existing_ptp_policies + + if state == "present": + mso_values = { + "name": ptp_policy, + "description": description, + "global": { + "adminState": admin_state, + "fabSyncIntvl": fabric_sync_interval, + "globalDomain": global_domain, + "fabDelayIntvl": fabric_delay_interval, + "prio1": global_priority1, + "prio2": global_priority2, + "fabAnnounceTimeout": fabric_announce_timeout, + "fabAnnounceIntvl": fabric_announce_interval, + "fabProfileTemplate": fabric_profile_template, + }, + } + + if match: + update_path = "{0}".format(path) + mso_values["global"]["uuid"] = match.details.get("global").get("uuid") + append_update_ops_data(ops, match.details, update_path, mso_values) + mso.sanitize(match.details, collate=True) + else: + mso.sanitize(mso_values) + ops.append(dict(op="add", path="{0}".format(path), value=mso.sent)) + + elif state == "absent": + if match: + ops.append(dict(op="remove", path="{0}".format(path))) + + if not module.check_mode and ops: + response = mso.request(mso_template.template_path, method="PATCH", data=ops) + ptp_policies = response.get("fabricPolicyTemplate", {}).get("template", {}).get("ptpPolicy", {}) + match = mso_template.get_object_by_key_value_pairs( + object_description, + [ptp_policies], + [KVPair("uuid", ptp_policy_uuid) if ptp_policy_uuid else KVPair("name", ptp_policy)], + ) + if match: + mso.existing = match.details + else: + mso.existing = {} + elif module.check_mode and state != "query": + mso.existing = mso.proposed if state == "present" else {} + + mso.exit_json() + + +if __name__ == "__main__": + main() diff --git a/plugins/modules/ndo_ptp_policy_profiles.py b/plugins/modules/ndo_ptp_policy_profiles.py new file mode 100644 index 00000000..c83047b7 --- /dev/null +++ b/plugins/modules/ndo_ptp_policy_profiles.py @@ -0,0 +1,255 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +# Copyright: (c) 2024, Shreyas Srish (@shrsr) + +# 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_ptp_policy_profiles +short_description: Manage PTP Policy Profiles on Cisco Nexus Dashboard Orchestrator (NDO). +description: +- Manage PTP Policy Profiles on Cisco Nexus Dashboard Orchestrator (NDO). +- This module is only supported on ND v3.1 (NDO v4.3) and later. +author: +- Your Name (@yourusername) +options: + template: + description: + - The name of the template. + - The template must be a fabric policy template. + type: str + required: true + ptp_policy_profile_name: + description: + - The name of the PTP Policy profile. + type: str + aliases: [ name ] + ptp_policy_profile_uuid: + description: + - The UUID of the PTP Policy profile. + type: str + aliases: [ uuid ] + delay_interval: + description: + - Delay interval of the PTP Policy profile. + - The value should be between -4 to 4. + - This is required when O(state=present). + type: int + profile_template: + description: + - Profile template of the PTP Policy profile. + - The default value is aes67. + type: str + choices: [ aes67, default, telecomFullPath, smpte ] + sync_interval: + description: + - Sync interval of the PTP Policy profile. + - The value should be between -4 to -1. + - This is required when O(state=present). + type: int + override_node_profile: + description: + - Node profile override of the PTP Policy profile. + type: bool + announce_timeout: + description: + - Announce timeout of the PTP Policy profile. + - The value should be between 2 to 10. + - This is required when O(state=present). + type: int + announce_interval: + description: + - Announce interval of the PTP Policy profile. + - The value should be between -3 to 1. + - This is required when O(state=present). + type: int + 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 +notes: +- The C(ptp_policy) must exist before using this module in your playbook. + The M(cisco.mso.ndo_ptp_policy) module can be used for this. +extends_documentation_fragment: cisco.mso.modules +""" + +EXAMPLES = r""" +- name: Create a new PTP profile + cisco.mso.ndo_ptp_policy_profiles: + host: mso_host + username: admin + password: SomeSecretPassword + template: ansible_fabric_policy_template + ptp_policy_profile_name: ansible_profile + delay_interval: 2 + sync_interval: 1 + announce_timeout: 3 + announce_interval: 4 + profile_template: aes67 + state: present + +- name: Query a PTP profile + cisco.mso.ndo_ptp_policy_profiles: + host: mso_host + username: admin + password: SomeSecretPassword + template: ansible_fabric_policy_template + ptp_policy_profile_name: ansible_profile + state: query + register: query_one + +- name: Query all PTP profiles + cisco.mso.ndo_ptp_policy_profiles: + host: mso_host + username: admin + password: SomeSecretPassword + template: ansible_fabric_policy_template + state: query + register: query_all + +- name: Delete a PTP profile using name + cisco.mso.ndo_ptp_policy_profiles: + host: mso_host + username: admin + password: SomeSecretPassword + template: ansible_fabric_policy_template + ptp_policy_profile_name: ansible_profile + state: absent + +- name: Delete a PTP profile using UUID + cisco.mso.ndo_ptp_policy_profiles: + host: mso_host + username: admin + password: SomeSecretPassword + template: ansible_fabric_policy_template + ptp_policy_profile_uuid: "{{ query_one.current.uuid }}" + state: absent +""" + +RETURN = r""" +""" + +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.template import MSOTemplate, KVPair +from ansible_collections.cisco.mso.plugins.module_utils.utils import append_update_ops_data +import copy + + +def main(): + argument_spec = mso_argument_spec() + argument_spec.update( + dict( + template=dict(type="str", required=True), + ptp_policy_profile_name=dict(type="str", aliases=["name"]), + ptp_policy_profile_uuid=dict(type="str", aliases=["uuid"]), + delay_interval=dict(type="int"), + profile_template=dict(type="str", choices=["aes67", "default", "telecomFullPath", "smpte"]), + sync_interval=dict(type="int"), + override_node_profile=dict(type="bool"), + announce_timeout=dict(type="int"), + announce_interval=dict(type="int"), + state=dict(type="str", choices=["absent", "query", "present"], default="query"), + ) + ) + + module = AnsibleModule( + argument_spec=argument_spec, + supports_check_mode=True, + required_if=[ + ["state", "present", ["ptp_policy_profile_name", "ptp_policy_profile_uuid"], True], + ["state", "absent", ["ptp_policy_profile_name", "ptp_policy_profile_uuid"], True], + ["state", "present", ["announce_interval", "announce_timeout", "sync_interval", "delay_interval"]], + ], + ) + + mso = MSOModule(module) + + template = module.params.get("template") + ptp_policy_profile_name = module.params.get("ptp_policy_profile_name") + ptp_policy_profile_uuid = module.params.get("ptp_policy_profile_uuid") + delay_interval = module.params.get("delay_interval") + profile_template = module.params.get("profile_template") + sync_interval = module.params.get("sync_interval") + override_node_profile = module.params.get("override_node_profile") + announce_timeout = module.params.get("announce_timeout") + announce_interval = module.params.get("announce_interval") + state = module.params.get("state") + + ops = [] + match = None + + mso_template = MSOTemplate(mso, "fabric_policy", template) + mso_template.validate_template("fabricPolicy") + object_description = "Profiles" + + path = "/fabricPolicyTemplate/template/ptpPolicy/profiles" + + existing_profiles = mso_template.template.get("fabricPolicyTemplate", {}).get("template", {}).get("ptpPolicy", {}).get("profiles") or [] + + if ptp_policy_profile_name or ptp_policy_profile_uuid: + match = mso_template.get_object_by_key_value_pairs( + object_description, + existing_profiles, + [KVPair("uuid", ptp_policy_profile_uuid) if ptp_policy_profile_uuid else KVPair("name", ptp_policy_profile_name)], + ) + if match: + mso.existing = mso.previous = copy.deepcopy(match.details) + else: + mso.existing = mso.previous = existing_profiles + + if state == "present": + mso_values = dict( + name=ptp_policy_profile_name, + delayIntvl=delay_interval, + profileTemplate=profile_template, + syncIntvl=sync_interval, + nodeProfileOverride=override_node_profile, + announceTimeout=announce_timeout, + announceIntvl=announce_interval, + ) + + if match: + update_path = "{0}/{1}".format(path, match.index) + append_update_ops_data(ops, match.details, update_path, mso_values) + mso.sanitize(match.details, collate=True) + else: + mso.sanitize(mso_values) + ops.append(dict(op="add", path="{0}/-".format(path), value=mso.sent)) + + elif state == "absent": + if match: + ops.append(dict(op="remove", path="{0}/{1}".format(path, match.index))) + + if not module.check_mode and ops: + response = mso.request(mso_template.template_path, method="PATCH", data=ops) + profiles = response.get("fabricPolicyTemplate", {}).get("template", {}).get("ptpPolicy", {}).get("profiles") or [] + match = mso_template.get_object_by_key_value_pairs( + object_description, + profiles, + [KVPair("uuid", ptp_policy_profile_uuid) if ptp_policy_profile_uuid else KVPair("name", ptp_policy_profile_name)], + ) + if match: + mso.existing = match.details + else: + mso.existing = {} + elif module.check_mode and state != "query": + mso.existing = mso.proposed if state == "present" else {} + + mso.exit_json() + + +if __name__ == "__main__": + main() diff --git a/tests/integration/inventory.networking b/tests/integration/inventory.networking index 680627d6..f73dc3f7 100644 --- a/tests/integration/inventory.networking +++ b/tests/integration/inventory.networking @@ -4,9 +4,9 @@ ndo [ndo] -lh-dmz1-pod1-ndo-v421 ansible_host=173.36.219.30 mso_hostname=173.36.219.30 -lh-dmz1-pod1-ndo-v372 ansible_host=173.36.219.31 mso_hostname=173.36.219.31 -lh-dmz1-pod1-ndo-v412 ansible_host=173.36.219.32 mso_hostname=173.36.219.32 +#lh-dmz1-pod1-ndo-v421 ansible_host=173.36.219.30 mso_hostname=173.36.219.30 +#lh-dmz1-pod1-ndo-v372 ansible_host=173.36.219.31 mso_hostname=173.36.219.31 +#lh-dmz1-pod1-ndo-v412 ansible_host=173.36.219.32 mso_hostname=173.36.219.32 lh-dmz1-pod1-ndo-v431 ansible_host=173.36.219.35 mso_hostname=173.36.219.35 [all:vars] diff --git a/tests/integration/targets/ndo_ptp_policy/aliases b/tests/integration/targets/ndo_ptp_policy/aliases new file mode 100644 index 00000000..5042c9c0 --- /dev/null +++ b/tests/integration/targets/ndo_ptp_policy/aliases @@ -0,0 +1,2 @@ +# No ACI MultiSite infrastructure, so not enabled +# unsupported diff --git a/tests/integration/targets/ndo_ptp_policy/tasks/main.yml b/tests/integration/targets/ndo_ptp_policy/tasks/main.yml new file mode 100644 index 00000000..48d7c5f6 --- /dev/null +++ b/tests/integration/targets/ndo_ptp_policy/tasks/main.yml @@ -0,0 +1,234 @@ +# Test code for the MSO modules +# Copyright: (c) 2024, Shreyas Srish (@shrsr) + +# 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 + +- 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("debug") }}' + +# 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: Remove fabric template + cisco.mso.ndo_template: &template_absent + <<: *mso_info + name: ansible_fabric_policy_template + type: fabric_policy + state: absent + + - name: Create a fabric template + cisco.mso.ndo_template: + <<: *mso_info + name: ansible_fabric_policy_template + type: fabric_policy + state: present + + # CREATE + - name: Create a new PTP policy (check mode) + cisco.mso.ndo_ptp_policy: &add_ptp_policy + <<: *mso_info + template: ansible_fabric_policy_template + ptp_policy: ansible_test_ptp_policy + admin_state: enabled + fabric_sync_interval: -3 + global_domain: 0 + fabric_delay_interval: -2 + global_priority1: 255 + global_priority2: 255 + fabric_announce_timeout: 3 + fabric_announce_interval: 1 + fabric_profile_template: aes67 + state: present + check_mode: true + register: cm_add_ptp_policy + + - name: Create a new PTP policy + cisco.mso.ndo_ptp_policy: + <<: *add_ptp_policy + register: nm_add_ptp_policy + + - name: Create a PTP policy again + cisco.mso.ndo_ptp_policy: + <<: *add_ptp_policy + register: nm_add_ptp_policy_again + + - name: Assert PTP policy was created + assert: + that: + - cm_add_ptp_policy is changed + - cm_add_ptp_policy.previous == {} + - cm_add_ptp_policy.current == nm_add_ptp_policy.proposed + - cm_add_ptp_policy.current.name == cm_add_ptp_policy.proposed.name == "ansible_test_ptp_policy" + - nm_add_ptp_policy is changed + - nm_add_ptp_policy.previous == {} + - nm_add_ptp_policy.current.name == "ansible_test_ptp_policy" + - nm_add_ptp_policy.current.name == "ansible_test_ptp_policy" + - nm_add_ptp_policy.current.global.adminState == "enabled" + - nm_add_ptp_policy.current.global.globalDomain == 0 + - nm_add_ptp_policy.current.global.fabSyncIntvl == -3 + - nm_add_ptp_policy.current.global.fabDelayIntvl == -2 + - nm_add_ptp_policy.current.global.prio1 == 255 + - nm_add_ptp_policy.current.global.prio2 == 255 + - nm_add_ptp_policy.current.global.fabAnnounceTimeout == 3 + - nm_add_ptp_policy.current.global.fabAnnounceIntvl == 1 + - nm_add_ptp_policy.current.global.fabProfileTemplate == "aes67" + - nm_add_ptp_policy_again is not changed + - nm_add_ptp_policy_again.previous.name == nm_add_ptp_policy_again.current.name == "ansible_test_ptp_policy" + - nm_add_ptp_policy_again.previous.global.adminState == nm_add_ptp_policy_again.current.global.adminState == "enabled" + - nm_add_ptp_policy_again.previous.global.globalDomain == nm_add_ptp_policy_again.current.global.globalDomain == 0 + - nm_add_ptp_policy_again.previous.global.fabSyncIntvl == nm_add_ptp_policy_again.current.global.fabSyncIntvl == -3 + - nm_add_ptp_policy_again.previous.global.fabDelayIntvl == nm_add_ptp_policy_again.current.global.fabDelayIntvl == -2 + - nm_add_ptp_policy_again.previous.global.prio1 == nm_add_ptp_policy_again.current.global.prio1 == 255 + - nm_add_ptp_policy_again.previous.global.prio2 == nm_add_ptp_policy_again.current.global.prio2 == 255 + - nm_add_ptp_policy_again.previous.global.fabAnnounceTimeout == nm_add_ptp_policy_again.current.global.fabAnnounceTimeout == 3 + - nm_add_ptp_policy_again.previous.global.fabAnnounceIntvl == nm_add_ptp_policy_again.current.global.fabAnnounceIntvl == 1 + - nm_add_ptp_policy_again.previous.global.fabProfileTemplate == nm_add_ptp_policy_again.current.global.fabProfileTemplate == "aes67" + - nm_add_ptp_policy_again.previous.uuid is defined + - nm_add_ptp_policy_again.current.uuid is defined + + # UPDATE + - name: Update a PTP policy (check mode) + cisco.mso.ndo_ptp_policy: &update_ptp_policy + <<: *add_ptp_policy + description: changed_description + admin_state: disabled + fabric_sync_interval: -2 + global_domain: 1 + global_priority1: 100 + global_priority2: 200 + ptp_policy_uuid: + state: present + check_mode: true + register: cm_update_ptp_policy + + - name: Update a PTP policy + cisco.mso.ndo_ptp_policy: + <<: *update_ptp_policy + register: nm_update_ptp_policy + + - name: Update a PTP policy again + cisco.mso.ndo_ptp_policy: + <<: *update_ptp_policy + register: nm_update_ptp_policy_again + + - name: Assert PTP policy was updated + assert: + that: + - cm_update_ptp_policy is changed + - cm_update_ptp_policy.previous.description == "" + - cm_update_ptp_policy.previous.global.adminState == "enabled" + - cm_update_ptp_policy.previous.global.fabSyncIntvl == -3 + - cm_update_ptp_policy.current == cm_update_ptp_policy.proposed + - cm_update_ptp_policy.current.description == cm_update_ptp_policy.proposed.description == "changed_description" + - cm_update_ptp_policy.current.global.adminState == cm_update_ptp_policy.proposed.global.adminState == "disabled" + - cm_update_ptp_policy.current.global.fabSyncIntvl == cm_update_ptp_policy.proposed.global.fabSyncIntvl == -2 + - cm_update_ptp_policy.current.global.prio1 == cm_update_ptp_policy.proposed.global.prio1 == 100 + - cm_update_ptp_policy.current.global.prio2 == cm_update_ptp_policy.proposed.global.prio2 == 200 + - cm_update_ptp_policy.current.global.globalDomain == cm_update_ptp_policy.proposed.global.globalDomain == 1 + - nm_update_ptp_policy is changed + - nm_update_ptp_policy.current.description == "changed_description" + - nm_update_ptp_policy.current.global.adminState == "disabled" + - nm_update_ptp_policy.current.global.fabSyncIntvl == -2 + - nm_update_ptp_policy.current.global.globalDomain == 1 + - nm_update_ptp_policy.current.global.prio1 == 100 + - nm_update_ptp_policy.current.global.prio2 == 200 + - nm_update_ptp_policy_again is not changed + + # QUERY + - name: Update PTP policy name with UUID + cisco.mso.ndo_ptp_policy: + <<: *update_ptp_policy + ptp_policy: ansible_test_ptp_policy_updated + ptp_policy_uuid: "{{ nm_add_ptp_policy.current.uuid }}" + state: present + + - name: Query a PTP policy with ptp_policy name + cisco.mso.ndo_ptp_policy: + <<: *mso_info + template: ansible_fabric_policy_template + ptp_policy: ansible_test_ptp_policy_updated + state: query + register: query_one + + - name: Query all PTP policies in the template + cisco.mso.ndo_ptp_policy: + <<: *mso_info + template: ansible_fabric_policy_template + state: query + register: query_all + + - name: Verify query_one and query_all + assert: + that: + - query_all is not changed + - query_one is not changed + - query_all.current == query_one.current + - query_one.current.name == "ansible_test_ptp_policy_updated" + - query_one.current.description == "changed_description" + - query_one.current.global.adminState == "disabled" + - query_one.current.global.fabSyncIntvl == -2 + - query_one.current.global.globalDomain == 1 + - query_one.current.global.prio1 == 100 + - query_one.current.global.prio2 == 200 + - query_one.current.global.fabAnnounceTimeout == 3 + - query_one.current.global.fabAnnounceIntvl == 1 + - query_one.current.global.fabProfileTemplate == "aes67" + + # DELETE + - name: Delete a PTP policy (check mode) + cisco.mso.ndo_ptp_policy: &rm_ptp_policy + <<: *mso_info + template: ansible_fabric_policy_template + ptp_policy: ansible_test_ptp_policy_updated + state: absent + check_mode: true + register: cm_rm_ptp_policy + + - name: Delete a PTP policy + cisco.mso.ndo_ptp_policy: + <<: *rm_ptp_policy + register: nm_rm_ptp_policy + + - name: Delete a PTP policy again + cisco.mso.ndo_ptp_policy: + <<: *rm_ptp_policy + register: nm_rm_ptp_policy_again + + - name: Assert PTP policy was deleted + assert: + that: + - cm_rm_ptp_policy is changed + - cm_rm_ptp_policy.previous.name == "ansible_test_ptp_policy_updated" + - cm_rm_ptp_policy.previous.description == "changed_description" + - cm_rm_ptp_policy.current == {} + - nm_rm_ptp_policy is changed + - nm_rm_ptp_policy.previous.name == "ansible_test_ptp_policy_updated" + - nm_rm_ptp_policy.previous.description == "changed_description" + - nm_rm_ptp_policy.current == {} + - nm_rm_ptp_policy_again is not changed + - nm_rm_ptp_policy_again.previous == nm_rm_ptp_policy_again.current == {} + + # CLEANUP TEMPLATE + - name: Ensure templates do not exist + cisco.mso.ndo_template: + <<: *template_absent \ No newline at end of file diff --git a/tests/integration/targets/ndo_ptp_policy_profiles/aliases b/tests/integration/targets/ndo_ptp_policy_profiles/aliases new file mode 100644 index 00000000..5042c9c0 --- /dev/null +++ b/tests/integration/targets/ndo_ptp_policy_profiles/aliases @@ -0,0 +1,2 @@ +# No ACI MultiSite infrastructure, so not enabled +# unsupported diff --git a/tests/integration/targets/ndo_ptp_policy_profiles/tasks/main.yml b/tests/integration/targets/ndo_ptp_policy_profiles/tasks/main.yml new file mode 100644 index 00000000..b274f6e7 --- /dev/null +++ b/tests/integration/targets/ndo_ptp_policy_profiles/tasks/main.yml @@ -0,0 +1,247 @@ +# Test code for the MSO modules +# Copyright: (c) 2024, Shreyas Srish (@shrsr) + +# 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 + +- 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("debug") }}' + +# 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: Remove fabric template + cisco.mso.ndo_template: &template_absent + <<: *mso_info + name: ansible_fabric_policy_template + type: fabric_policy + state: absent + + - name: Create a fabric template + cisco.mso.ndo_template: + <<: *mso_info + name: ansible_fabric_policy_template + type: fabric_policy + state: present + +- name: Create a new PTP policy + cisco.mso.ndo_ptp_policy: + <<: *mso_info + template: ansible_fabric_policy_template + ptp_policy: ansible_test_ptp_policy + admin_state: enabled + fabric_sync_interval: -3 + global_domain: 0 + fabric_delay_interval: -2 + global_priority1: 255 + global_priority2: 255 + fabric_announce_timeout: 3 + fabric_announce_interval: 1 + fabric_profile_template: aes67 + state: present + +# Create +- name: Create a PTP profile (check mode) + cisco.mso.ndo_ptp_policy_profiles: &add_ptp_policy_profile + <<: *mso_info + template: ansible_fabric_policy_template + ptp_policy_profile_name: ansible_profile + delay_interval: 2 + sync_interval: 1 + announce_timeout: 3 + announce_interval: 4 + profile_template: aes67 + state: present + check_mode: true + register: cm_create_ptp_profile + +- name: Create a PTP profile (normal mode) + cisco.mso.ndo_ptp_policy_profiles: + <<: *add_ptp_policy_profile + register: nm_add_ptp_profile + +- name: Create a PTP profile again (normal mode) + cisco.mso.ndo_ptp_policy_profiles: + <<: *add_ptp_policy_profile + register: nm_add_ptp_profile_again + +- name: Assert PTP profile creation + assert: + that: + - cm_create_ptp_profile is changed + - cm_create_ptp_profile.previous == {} + - cm_create_ptp_profile.current == nm_add_ptp_profile.proposed + - cm_create_ptp_profile.current.name == cm_create_ptp_profile.proposed.name == "ansible_profile" + - nm_add_ptp_profile is changed + - nm_add_ptp_profile.previous == {} + - nm_add_ptp_profile.current.name == "ansible_profile" + - nm_add_ptp_profile.current.delayIntvl == 2 + - nm_add_ptp_profile.current.syncIntvl == 1 + - nm_add_ptp_profile.current.announceTimeout == 3 + - nm_add_ptp_profile.current.announceIntvl == 4 + - nm_add_ptp_profile.current.profileTemplate == "aes67" + - nm_add_ptp_profile_again is not changed + - nm_add_ptp_profile_again.previous.name == nm_add_ptp_profile_again.current.name == "ansible_profile" + - nm_add_ptp_profile_again.previous.delayIntvl == nm_add_ptp_profile_again.current.delayIntvl == 2 + - nm_add_ptp_profile_again.previous.syncIntvl == nm_add_ptp_profile_again.current.syncIntvl == 1 + - nm_add_ptp_profile_again.previous.announceTimeout == nm_add_ptp_profile_again.current.announceTimeout == 3 + - nm_add_ptp_profile_again.previous.announceIntvl == nm_add_ptp_profile_again.current.announceIntvl == 4 + - nm_add_ptp_profile_again.previous.profileTemplate == nm_add_ptp_profile_again.current.profileTemplate == "aes67" + - nm_add_ptp_profile_again.previous.uuid is defined + - nm_add_ptp_profile_again.current.uuid is defined + +# Update +- name: Update a PTP profile (check mode) + cisco.mso.ndo_ptp_policy_profiles: &update_ptp_policy_profile + <<: *mso_info + template: ansible_fabric_policy_template + ptp_policy_profile_name: ansible_profile + delay_interval: 5 + sync_interval: -1 + announce_timeout: 6 + announce_interval: 3 + profile_template: default + state: present + check_mode: true + register: cm_update_ptp_profile + +- name: Update a PTP profile (normal mode) + cisco.mso.ndo_ptp_policy_profiles: + <<: *update_ptp_policy_profile + register: nm_update_ptp_profile + +- name: Update a PTP profile again (normal mode) + cisco.mso.ndo_ptp_policy_profiles: + <<: *update_ptp_policy_profile + register: nm_update_ptp_profile_again + +- name: Assert PTP profile update + assert: + that: + - cm_update_ptp_profile is changed + - cm_update_ptp_profile.current == nm_update_ptp_profile.proposed + - cm_update_ptp_profile.current.name == cm_update_ptp_profile.proposed.name == "ansible_profile" + - nm_update_ptp_profile is changed + - nm_update_ptp_profile.current.name == "ansible_profile" + - nm_update_ptp_profile.current.delayIntvl == 5 + - nm_update_ptp_profile.current.syncIntvl == -1 + - nm_update_ptp_profile.current.announceTimeout == 6 + - nm_update_ptp_profile.current.announceIntvl == 3 + - nm_update_ptp_profile.current.profileTemplate == "default" + - nm_update_ptp_profile_again is not changed + - nm_update_ptp_profile_again.previous.name == nm_update_ptp_profile_again.current.name == "ansible_profile" + - nm_update_ptp_profile_again.previous.delayIntvl == nm_update_ptp_profile_again.current.delayIntvl == 5 + - nm_update_ptp_profile_again.previous.syncIntvl == nm_update_ptp_profile_again.current.syncIntvl == -1 + - nm_update_ptp_profile_again.previous.announceTimeout == nm_update_ptp_profile_again.current.announceTimeout == 6 + - nm_update_ptp_profile_again.previous.announceIntvl == nm_update_ptp_profile_again.current.announceIntvl == 3 + - nm_update_ptp_profile_again.previous.profileTemplate == nm_update_ptp_profile_again.current.profileTemplate == "default" + +# Update name and Query +- name: Update a PTP profile name with UUID (normal mode) + cisco.mso.ndo_ptp_policy_profiles: + <<: *update_ptp_policy_profile + ptp_policy_profile_name: profile_update + ptp_policy_profile_uuid: "{{ nm_update_ptp_profile.current.uuid }}" + register: nm_update_name_ptp_profile + +- name: Create another PTP profile + cisco.mso.ndo_ptp_policy_profiles: + <<: *mso_info + template: ansible_fabric_policy_template + ptp_policy_profile_name: ansible_profile2 + delay_interval: 2 + sync_interval: 1 + announce_timeout: 3 + announce_interval: 4 + profile_template: aes67 + state: present + register: nm_create_another_ptp_profile + +- name: Query a PTP profile + cisco.mso.ndo_ptp_policy_profiles: + <<: *mso_info + template: ansible_fabric_policy_template + ptp_policy_profile_name: profile_update + state: query + register: query_one + +- name: Query all PTP profiles in the template + cisco.mso.ndo_ptp_policy_profiles: + <<: *mso_info + template: ansible_fabric_policy_template + state: query + register: query_all + +- name: Verify query_one and query_all + assert: + that: + - query_all is not changed + - query_one is not changed + - nm_update_name_ptp_profile.current.name == "profile_update" + - query_one.current.name == "profile_update" + - query_one.current.delayIntvl == 5 + - query_one.current.syncIntvl == -1 + - query_one.current.announceTimeout == 6 + - query_one.current.announceIntvl == 3 + - query_one.current.profileTemplate == "default" + - query_all.current | length == 2 + +# DELETE +- name: Delete a PTP profile (check mode) + cisco.mso.ndo_ptp_policy_profiles: &rm_ptp_policy_profile + <<: *mso_info + template: ansible_fabric_policy_template + ptp_policy_profile_name: profile_update + state: absent + check_mode: true + register: cm_rm_ptp_profile + +- name: Delete a PTP profile + cisco.mso.ndo_ptp_policy_profiles: + <<: *rm_ptp_policy_profile + register: nm_rm_ptp_profile + +- name: Delete a PTP profile again + cisco.mso.ndo_ptp_policy_profiles: + <<: *rm_ptp_policy_profile + register: nm_rm_ptp_profile_again + +- name: Delete the other PTP profile using UUID + cisco.mso.ndo_ptp_policy_profiles: + <<: *mso_info + template: ansible_fabric_policy_template + ptp_policy_profile_uuid: "{{ nm_create_another_ptp_profile.current.uuid }}" + state: absent + register: nm_rm_other_ptp_profile + +- name: Assert PTP profiles were deleted + assert: + that: + - cm_rm_ptp_profile is changed + - cm_rm_ptp_profile.previous.name == "profile_update" + - cm_rm_ptp_profile.current == {} + - nm_rm_ptp_profile is changed + - nm_rm_ptp_profile.previous.name == "profile_update" + - nm_rm_ptp_profile.current == {} + - nm_rm_ptp_profile_again is not changed + - nm_rm_ptp_profile_again.previous == nm_rm_ptp_profile_again.current == {} + - nm_rm_other_ptp_profile.current == {}