diff --git a/plugins/modules/nd_rest.py b/plugins/modules/nd_rest.py new file mode 100644 index 0000000..978fb5a --- /dev/null +++ b/plugins/modules/nd_rest.py @@ -0,0 +1,179 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +# Copyright: (c) 2024, Gaspard Micol (@gmicol) +# 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: nd_rest +short_description: Direct access to the Cisco Nexus Dashboard REST API +description: +- Enables the management of Cisco Nexus Dashboard (ND) through direct access to the Cisco ND REST API. +author: +- Gaspard Micol (@gmicol) +options: + method: + description: + - The HTTP method of the request. + - Using C(delete) is typically used for deleting objects. + - Using C(get) is typically used for querying objects. + - Using C(post) is typically used for modifying objects. + - Using C(put) is typically used for modifying existing objects. + - Using C(patch) is typically also used for modifying existing objects. + type: str + choices: [ delete, get, post, put, patch ] + default: get + aliases: [ action ] + path: + description: + - URI being used to execute API calls. + type: str + required: true + aliases: [ uri ] + content: + description: + - Sets the payload of the API request directly. + - This may be convenient to template simple requests. + - For anything complex use the C(template) lookup plugin (see examples). + type: raw + aliases: [ payload ] +extends_documentation_fragment: +- cisco.nd.modules + +notes: +- Some payloads are known not to be idempotent, so be careful when constructing payloads. +""" + +EXAMPLES = r""" +- name: Create Security Domain using POST method + cisco.nd.nd_rest: + host: nd + username: admin + password: SomeSecretPassword + path: /nexus/infra/api/aaa/v4/securitydomains + method: post + content: + { + "spec": { + "description": "Security Domain Test for nd_rest module.", + "name": "ansible_security_domain_test" + } + } + +- name: Update Security Domain using PUT method + cisco.nd.nd_rest: + host: nd + username: admin + password: SomeSecretPassword + path: /nexus/infra/api/aaa/v4/securitydomains/ansible_security_domain_test + method: put + content: + { + "spec": { + "description": "Updated Security Domain Test for nd_rest module." + } + } + +- name: Query Security Domain using GET method + cisco.nd.nd_rest: + host: nd + username: admin + password: SomeSecretPassword + path: /nexus/infra/api/aaa/v4/securitydomains/ansible_security_domain_test + method: get + register: quey_one + +- name: Query all Security Domains using GET method + cisco.nd.nd_rest: + host: nd + username: admin + password: SomeSecretPassword + path: /nexus/infra/api/aaa/v4/securitydomains + method: get + register: quey_all + +- name: Remove Security Domain using DELETE method + cisco.nd.nd_rest: + host: nd + username: admin + password: SomeSecretPassword + path: /nexus/infra/api/aaa/v4/securitydomains/ansible_security_domain_test + method: delete +""" + +RETURN = r""" +""" + +# Optional, only used for YAML validation +try: + import yaml + + HAS_YAML = True +except Exception: + HAS_YAML = False + +from ansible.module_utils.basic import AnsibleModule +from ansible_collections.cisco.nd.plugins.module_utils.nd import NDModule, nd_argument_spec +from ansible.module_utils._text import to_text + + +def main(): + argument_spec = nd_argument_spec() + argument_spec.update( + path=dict(type="str", required=True, aliases=["uri"]), + method=dict(type="str", default="get", choices=["delete", "get", "post", "put", "patch"], aliases=["action"]), + content=dict(type="raw", aliases=["payload"]), + ) + + module = AnsibleModule( + argument_spec=argument_spec, + supports_check_mode=True, + ) + + content = module.params.get("content") + path = module.params.get("path") + + nd = NDModule(module) + + # Validate content/payload + if content and isinstance(content, str) and HAS_YAML: + try: + # Validate YAML/JSON string + content = yaml.safe_load(content) + except Exception as e: + module.fail_json(msg="Failed to parse provided JSON/YAML payload: %s" % to_text(e), exception=to_text(e), payload=content) + + method = nd.params.get("method").upper() + + # Append previous state of the object + if method in ("PUT", "DELETE"): + nd.existing = nd.query_obj(path, ignore_not_found_error=True) + nd.previous = nd.existing + if method != "GET": + nd.result["previous"] = nd.previous + + # Perform request + if module.check_mode: + nd.result["jsondata"] = content + else: + nd.result["jsondata"] = nd.request(path, method=method, data=content) + nd.existing = nd.result["jsondata"] + + # Report changes for idempotency depending on methods + nd.result["status"] = nd.status + if nd.result["jsondata"] != nd.previous and method != "GET": + nd.result["changed"] = True + + # Report success + nd.exit_json(**nd.result) + + +if __name__ == "__main__": + main() diff --git a/tests/integration/inventory.networking b/tests/integration/inventory.networking index 6b37d8f..4984d66 100644 --- a/tests/integration/inventory.networking +++ b/tests/integration/inventory.networking @@ -1,5 +1,5 @@ [nd] -nd ansible_host= +nd ansible_host=173.36.219.36 [nd:vars] ansible_connection=ansible.netcommon.httpapi @@ -8,13 +8,13 @@ ansible_network_os=cisco.nd.nd ansible_httpapi_validate_certs=False ansible_httpapi_use_ssl=True ansible_httpapi_use_proxy=True -ansible_user=ansible_github_ci -ansible_password= +ansible_user=admin +ansible_password=ins3965! insights_group= -site_name= -site_host= -site_username= -site_password= +site_name= GaspardTest +site_host=173.36.219.86 +site_username=admin +site_password=ins3965! dns_server= app_network= service_network= diff --git a/tests/integration/targets/nd_rest/tasks/error_handling.yml b/tests/integration/targets/nd_rest/tasks/error_handling.yml new file mode 100644 index 0000000..982bfa0 --- /dev/null +++ b/tests/integration/targets/nd_rest/tasks/error_handling.yml @@ -0,0 +1,112 @@ +# Test code for the ND modules +# Copyright: (c) 2024, Gaspard Micol (@gmciol) + +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) + +- name: Test that we have a Nexus Dashboard host, username and password + ansible.builtin.fail: + msg: 'Please define the following variables: ansible_host, ansible_user and ansible_password.' + when: ansible_host is not defined or ansible_user is not defined or ansible_password is not defined + +- name: Set vars + ansible.builtin.set_fact: + nd_info: &nd_info + host: '{{ ansible_host }}' + username: '{{ ansible_user }}' + password: '{{ ansible_password }}' + validate_certs: '{{ ansible_httpapi_validate_certs | default(false) }}' + use_ssl: '{{ ansible_httpapi_use_ssl | default(true) }}' + use_proxy: '{{ ansible_httpapi_use_proxy | default(true) }}' + output_level: '{{ mso_output_level | default("info") }}' + timeout: 90 + +- name: Error when required parameter is missing + cisco.nd.nd_rest: + <<: *nd_info + method: post + content: + { + "spec": { + "name": "ansible_security_domain_test" + } + } + ignore_errors: true + register: error_missing_path + +- name: Assert missing required parameter error + ansible.builtin.assert: + that: + - error_missing_path is failed + - error_missing_path.msg == "missing required arguments: path" + +- name: Error when required attribute is missing + cisco.nd.nd_rest: + <<: *nd_info + path: /api/config/v2/addsite/ + method: post + content: + { + "name": "ansible_error_site", + "siteType": "ACI", + "verifySecure": false, + "useProxy": false, + "aci": { + "userName": '{{ site_username }}', + "password": '{{ site_password }}', + }, + } + ignore_errors: true + register: error_missing_site_address + +- name: Assert missing required attribute error + ansible.builtin.assert: + that: + - error_missing_site_address is failed + - error_missing_site_address.info.body.error == "controller URL/IP required" + - error_missing_site_address.payload.error == "controller URL/IP required" + - error_missing_site_address.status == 400 + +- name: Error when input does not validate + cisco.nd.nd_rest: + <<: *nd_info + path: /nexus/infra/api/aaa/v4/securitydomains + method: post + content: + { + "spec": { + "name": "[invalid] name" + } + } + ignore_errors: true + register: error_invalid_name + +- name: Assert invalid input error + ansible.builtin.assert: + that: + - error_invalid_name is failed + - error_invalid_name.info.body.errors == ["Invalid domain name"] + - error_invalid_name.payload.errors == ["Invalid domain name"] + - error_invalid_name.status == 500 + +- name: Error on name resolution + cisco.nd.nd_rest: + <<: *nd_info + host: foo.bar.cisco.com + path: /nexus/infra/api/aaa/v4/securitydomains + method: post + content: + { + "spec": { + "description": "Security Domain Test for nd_rest module.", + "name": "ansible_security_domain_test" + } + } + ignore_errors: true + register: error_name_resolution + +- name: Assert name resolution error + ansible.builtin.assert: + that: + - error_name_resolution is failed + - '"Could not connect to https://foo.bar.cisco.com:443/nexus/infra/api/aaa/v4/securitydomains" in error_name_resolution.msg' + - '"Name or service not known" in error_name_resolution.msg' diff --git a/tests/integration/targets/nd_rest/tasks/json_inline.yml b/tests/integration/targets/nd_rest/tasks/json_inline.yml new file mode 100644 index 0000000..7ed5129 --- /dev/null +++ b/tests/integration/targets/nd_rest/tasks/json_inline.yml @@ -0,0 +1,151 @@ +# Test code for the ND modules +# Copyright: (c) 2024, Gaspard Micol (@gmciol) + +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) + +- name: Test that we have a Nexus Dashboard host, username and password + ansible.builtin.fail: + msg: 'Please define the following variables: ansible_host, ansible_user and ansible_password.' + when: ansible_host is not defined or ansible_user is not defined or ansible_password is not defined + +- name: Set vars + ansible.builtin.set_fact: + nd_info: &nd_info + host: '{{ ansible_host }}' + username: '{{ ansible_user }}' + password: '{{ ansible_password }}' + validate_certs: '{{ ansible_httpapi_validate_certs | default(false) }}' + use_ssl: '{{ ansible_httpapi_use_ssl | default(true) }}' + use_proxy: '{{ ansible_httpapi_use_proxy | default(true) }}' + output_level: '{{ mso_output_level | default("info") }}' + timeout: 90 + +- name: Ensure Security Domain does not exist using DELETE method + cisco.nd.nd_rest: &delete_security_domain + <<: *nd_info + path: /nexus/infra/api/aaa/v4/securitydomains/ansible_security_domain_test + method: delete + +- name: Create Security Domain with POST method (check_mode) + cisco.nd.nd_rest: &create_security_domain + <<: *nd_info + path: /nexus/infra/api/aaa/v4/securitydomains + method: post + content: + { + "spec": { + "description": "Security Domain Test for nd_rest module.", + "name": "ansible_security_domain_test" + } + } + check_mode: true + register: cm_create_security_domain + +- name: Create Security Domain with POST method + cisco.nd.nd_rest: + <<: *create_security_domain + register: nm_create_security_domain + +- name: Assert creation tasks with POST method for nd_rest module + ansible.builtin.assert: + that: + - cm_create_security_domain is changed + - cm_create_security_domain.previous == {} + - cm_create_security_domain.current == {} + - cm_create_security_domain.jsondata.spec.name == "ansible_security_domain_test" + - cm_create_security_domain.jsondata.spec.description == "Security Domain Test for nd_rest module." + - nm_create_security_domain is changed + - nm_create_security_domain.previous == {} + - nm_create_security_domain.current.spec.name == "ansible_security_domain_test" + - nm_create_security_domain.current.spec.description == "Security Domain Test for nd_rest module." + - nm_create_security_domain.data.spec.name == "ansible_security_domain_test" + - nm_create_security_domain.data.spec.description == "Security Domain Test for nd_rest module." + - nm_create_security_domain.jsondata.spec.name == "ansible_security_domain_test" + - nm_create_security_domain.jsondata.spec.description == "Security Domain Test for nd_rest module." + +- name: Update Security Domain with PUT method + cisco.nd.nd_rest: &update_security_domain + <<: *nd_info + path: /nexus/infra/api/aaa/v4/securitydomains/ansible_security_domain_test + method: put + content: + { + "spec": { + "description": "Updated Security Domain Test for nd_rest module." + } + } + register: nm_update_security_domain + +- name: Update Security Domain with PUT method again + cisco.nd.nd_rest: + <<: *update_security_domain + register: nm_update_security_domain_again + +- name: Assert udpate tasks with PUT method for nd_rest module + ansible.builtin.assert: + that: + - nm_update_security_domain is changed + - nm_update_security_domain.previous.spec.name == "ansible_security_domain_test" + - nm_update_security_domain.previous.spec.description == "Security Domain Test for nd_rest module." + - nm_update_security_domain.current.spec.name == "ansible_security_domain_test" + - nm_update_security_domain.current.spec.description == "Updated Security Domain Test for nd_rest module." + - nm_update_security_domain.data.spec.description == "Updated Security Domain Test for nd_rest module." + - nm_update_security_domain.current.spec.name == "ansible_security_domain_test" + - nm_update_security_domain.jsondata.spec.description == "Updated Security Domain Test for nd_rest module." + - nm_update_security_domain_again is not changed + - nm_update_security_domain_again.previous.spec.name == "ansible_security_domain_test" + - nm_update_security_domain_again.previous.spec.description == "Updated Security Domain Test for nd_rest module." + - nm_update_security_domain_again.current.spec.name == "ansible_security_domain_test" + - nm_update_security_domain_again.current.spec.description == "Updated Security Domain Test for nd_rest module." + - nm_update_security_domain_again.data.spec.description == "Updated Security Domain Test for nd_rest module." + - nm_update_security_domain_again.current.spec.name == "ansible_security_domain_test" + - nm_update_security_domain_again.jsondata.spec.description == "Updated Security Domain Test for nd_rest module." + +- name: Query Security Domain with GET method + cisco.nd.nd_rest: + <<: *nd_info + path: /nexus/infra/api/aaa/v4/securitydomains/ansible_security_domain_test + method: get + register: quey_one_security_domain + +- name: Query all Security Domains with GET method + cisco.nd.nd_rest: + <<: *nd_info + path: /nexus/infra/api/aaa/v4/securitydomains + method: get + register: quey_all_security_domains + +- name: Assert udpate tasks with PUT method for nd_rest module + ansible.builtin.assert: + that: + - quey_one_security_domain is not changed + - quey_one_security_domain.current.spec.name == "ansible_security_domain_test" + - quey_one_security_domain.jsondata.spec.name == "ansible_security_domain_test" + - quey_all_security_domains is not changed + - quey_all_security_domains.current.items.0.spec.name == "all" + - quey_all_security_domains.current.items.1.spec.name == "ansible_security_domain_test" + - quey_all_security_domains.jsondata.items.0.spec.name == "all" + - quey_all_security_domains.jsondata.items.1.spec.name == "ansible_security_domain_test" + +- name: Delete Security Domain with DELETE method + cisco.nd.nd_rest: + <<: *delete_security_domain + register: nm_delete_security_domain + +- name: Delete Security Domain with DELETE method again + cisco.nd.nd_rest: + <<: *delete_security_domain + register: nm_delete_security_domain_again + +- name: Assert udpate tasks with PUT method for nd_rest module + ansible.builtin.assert: + that: + - nm_delete_security_domain is changed + - nm_delete_security_domain.previous.spec.name == "ansible_security_domain_test" + - nm_delete_security_domain.previous.spec.description == "Updated Security Domain Test for nd_rest module." + - nm_delete_security_domain.current == {} + - nm_delete_security_domain.jsondata == {} + - nm_delete_security_domain_again is not changed + - nm_delete_security_domain_again.previous == {} + - nm_delete_security_domain_again.current == {} + - nm_delete_security_domain_again.jsondata == {} diff --git a/tests/integration/targets/nd_rest/tasks/json_string.yml b/tests/integration/targets/nd_rest/tasks/json_string.yml new file mode 100644 index 0000000..ace93ad --- /dev/null +++ b/tests/integration/targets/nd_rest/tasks/json_string.yml @@ -0,0 +1,151 @@ +# Test code for the ND modules +# Copyright: (c) 2024, Gaspard Micol (@gmciol) + +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) + +- name: Test that we have a Nexus Dashboard host, username and password + ansible.builtin.fail: + msg: 'Please define the following variables: ansible_host, ansible_user and ansible_password.' + when: ansible_host is not defined or ansible_user is not defined or ansible_password is not defined + +- name: Set vars + ansible.builtin.set_fact: + nd_info: &nd_info + host: '{{ ansible_host }}' + username: '{{ ansible_user }}' + password: '{{ ansible_password }}' + validate_certs: '{{ ansible_httpapi_validate_certs | default(false) }}' + use_ssl: '{{ ansible_httpapi_use_ssl | default(true) }}' + use_proxy: '{{ ansible_httpapi_use_proxy | default(true) }}' + output_level: '{{ mso_output_level | default("info") }}' + timeout: 90 + +- name: Ensure Security Domain does not exist using DELETE method + cisco.nd.nd_rest: &delete_security_domain + <<: *nd_info + path: /nexus/infra/api/aaa/v4/securitydomains/ansible_security_domain_test + method: delete + +- name: Create Security Domain with POST method (check_mode) + cisco.nd.nd_rest: &create_security_domain + <<: *nd_info + path: /nexus/infra/api/aaa/v4/securitydomains + method: post + content: | + { + "spec": { + "description": "Security Domain Test for nd_rest module.", + "name": "ansible_security_domain_test" + } + } + check_mode: true + register: cm_create_security_domain + +- name: Create Security Domain with POST method + cisco.nd.nd_rest: + <<: *create_security_domain + register: nm_create_security_domain + +- name: Assert creation tasks with POST method for nd_rest module + ansible.builtin.assert: + that: + - cm_create_security_domain is changed + - cm_create_security_domain.previous == {} + - cm_create_security_domain.current == {} + - cm_create_security_domain.jsondata.spec.name == "ansible_security_domain_test" + - cm_create_security_domain.jsondata.spec.description == "Security Domain Test for nd_rest module." + - nm_create_security_domain is changed + - nm_create_security_domain.previous == {} + - nm_create_security_domain.current.spec.name == "ansible_security_domain_test" + - nm_create_security_domain.current.spec.description == "Security Domain Test for nd_rest module." + - nm_create_security_domain.data.spec.name == "ansible_security_domain_test" + - nm_create_security_domain.data.spec.description == "Security Domain Test for nd_rest module." + - nm_create_security_domain.jsondata.spec.name == "ansible_security_domain_test" + - nm_create_security_domain.jsondata.spec.description == "Security Domain Test for nd_rest module." + +- name: Update Security Domain with PUT method + cisco.nd.nd_rest: &update_security_domain + <<: *nd_info + path: /nexus/infra/api/aaa/v4/securitydomains/ansible_security_domain_test + method: put + content: | + { + "spec": { + "description": "Updated Security Domain Test for nd_rest module." + } + } + register: nm_update_security_domain + +- name: Update Security Domain with PUT method again + cisco.nd.nd_rest: + <<: *update_security_domain + register: nm_update_security_domain_again + +- name: Assert udpate tasks with PUT method for nd_rest module + ansible.builtin.assert: + that: + - nm_update_security_domain is changed + - nm_update_security_domain.previous.spec.name == "ansible_security_domain_test" + - nm_update_security_domain.previous.spec.description == "Security Domain Test for nd_rest module." + - nm_update_security_domain.current.spec.name == "ansible_security_domain_test" + - nm_update_security_domain.current.spec.description == "Updated Security Domain Test for nd_rest module." + - nm_update_security_domain.data.spec.description == "Updated Security Domain Test for nd_rest module." + - nm_update_security_domain.current.spec.name == "ansible_security_domain_test" + - nm_update_security_domain.jsondata.spec.description == "Updated Security Domain Test for nd_rest module." + - nm_update_security_domain_again is not changed + - nm_update_security_domain_again.previous.spec.name == "ansible_security_domain_test" + - nm_update_security_domain_again.previous.spec.description == "Updated Security Domain Test for nd_rest module." + - nm_update_security_domain_again.current.spec.name == "ansible_security_domain_test" + - nm_update_security_domain_again.current.spec.description == "Updated Security Domain Test for nd_rest module." + - nm_update_security_domain_again.data.spec.description == "Updated Security Domain Test for nd_rest module." + - nm_update_security_domain_again.current.spec.name == "ansible_security_domain_test" + - nm_update_security_domain_again.jsondata.spec.description == "Updated Security Domain Test for nd_rest module." + +- name: Query Security Domain with GET method + cisco.nd.nd_rest: + <<: *nd_info + path: /nexus/infra/api/aaa/v4/securitydomains/ansible_security_domain_test + method: get + register: quey_one_security_domain + +- name: Query all Security Domains with GET method + cisco.nd.nd_rest: + <<: *nd_info + path: /nexus/infra/api/aaa/v4/securitydomains + method: get + register: quey_all_security_domains + +- name: Assert udpate tasks with PUT method for nd_rest module + ansible.builtin.assert: + that: + - quey_one_security_domain is not changed + - quey_one_security_domain.current.spec.name == "ansible_security_domain_test" + - quey_one_security_domain.jsondata.spec.name == "ansible_security_domain_test" + - quey_all_security_domains is not changed + - quey_all_security_domains.current.items.0.spec.name == "all" + - quey_all_security_domains.current.items.1.spec.name == "ansible_security_domain_test" + - quey_all_security_domains.jsondata.items.0.spec.name == "all" + - quey_all_security_domains.jsondata.items.1.spec.name == "ansible_security_domain_test" + +- name: Delete Security Domain with DELETE method + cisco.nd.nd_rest: + <<: *delete_security_domain + register: nm_delete_security_domain + +- name: Delete Security Domain with DELETE method again + cisco.nd.nd_rest: + <<: *delete_security_domain + register: nm_delete_security_domain_again + +- name: Assert udpate tasks with PUT method for nd_rest module + ansible.builtin.assert: + that: + - nm_delete_security_domain is changed + - nm_delete_security_domain.previous.spec.name == "ansible_security_domain_test" + - nm_delete_security_domain.previous.spec.description == "Updated Security Domain Test for nd_rest module." + - nm_delete_security_domain.current == {} + - nm_delete_security_domain.jsondata == {} + - nm_delete_security_domain_again is not changed + - nm_delete_security_domain_again.previous == {} + - nm_delete_security_domain_again.current == {} + - nm_delete_security_domain_again.jsondata == {} diff --git a/tests/integration/targets/nd_rest/tasks/main.yml b/tests/integration/targets/nd_rest/tasks/main.yml new file mode 100644 index 0000000..c68960a --- /dev/null +++ b/tests/integration/targets/nd_rest/tasks/main.yml @@ -0,0 +1,24 @@ +# Test code for the ND modules +# Copyright: (c) 2024, Gaspard Micol (@gmciol) + +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) + +- name: Test that we have a Nexus Dashboard host, username and password + ansible.builtin.fail: + msg: 'Please define the following variables: ansible_host, ansible_user and ansible_password.' + when: ansible_host is not defined or ansible_user is not defined or ansible_password is not defined + +- ansible.builtin.include_tasks: json_inline.yml + tags: json_inline + +- ansible.builtin.include_tasks: json_string.yml + tags: json_string + +- ansible.builtin.include_tasks: yaml_inline.yml + tags: yaml_inline + +- ansible.builtin.include_tasks: yaml_string.yml + tags: yaml_string + +- ansible.builtin.include_tasks: error_handling.yml + tags: error_handling \ No newline at end of file diff --git a/tests/integration/targets/nd_rest/tasks/yaml_inline.yml b/tests/integration/targets/nd_rest/tasks/yaml_inline.yml new file mode 100644 index 0000000..7323328 --- /dev/null +++ b/tests/integration/targets/nd_rest/tasks/yaml_inline.yml @@ -0,0 +1,145 @@ +# Test code for the ND modules +# Copyright: (c) 2024, Gaspard Micol (@gmciol) + +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) + +- name: Test that we have a Nexus Dashboard host, username and password + ansible.builtin.fail: + msg: 'Please define the following variables: ansible_host, ansible_user and ansible_password.' + when: ansible_host is not defined or ansible_user is not defined or ansible_password is not defined + +- name: Set vars + ansible.builtin.set_fact: + nd_info: &nd_info + host: '{{ ansible_host }}' + username: '{{ ansible_user }}' + password: '{{ ansible_password }}' + validate_certs: '{{ ansible_httpapi_validate_certs | default(false) }}' + use_ssl: '{{ ansible_httpapi_use_ssl | default(true) }}' + use_proxy: '{{ ansible_httpapi_use_proxy | default(true) }}' + output_level: '{{ mso_output_level | default("info") }}' + timeout: 90 + +- name: Ensure Security Domain does not exist using DELETE method + cisco.nd.nd_rest: &delete_security_domain + <<: *nd_info + path: /nexus/infra/api/aaa/v4/securitydomains/ansible_security_domain_test + method: delete + +- name: Create Security Domain with POST method (check_mode) + cisco.nd.nd_rest: &create_security_domain + <<: *nd_info + path: /nexus/infra/api/aaa/v4/securitydomains + method: post + content: + spec: + description: "Security Domain Test for nd_rest module." + name: "ansible_security_domain_test" + check_mode: true + register: cm_create_security_domain + +- name: Create Security Domain with POST method + cisco.nd.nd_rest: + <<: *create_security_domain + register: nm_create_security_domain + +- name: Assert creation tasks with POST method for nd_rest module + ansible.builtin.assert: + that: + - cm_create_security_domain is changed + - cm_create_security_domain.previous == {} + - cm_create_security_domain.current == {} + - cm_create_security_domain.jsondata.spec.name == "ansible_security_domain_test" + - cm_create_security_domain.jsondata.spec.description == "Security Domain Test for nd_rest module." + - nm_create_security_domain is changed + - nm_create_security_domain.previous == {} + - nm_create_security_domain.current.spec.name == "ansible_security_domain_test" + - nm_create_security_domain.current.spec.description == "Security Domain Test for nd_rest module." + - nm_create_security_domain.data.spec.name == "ansible_security_domain_test" + - nm_create_security_domain.data.spec.description == "Security Domain Test for nd_rest module." + - nm_create_security_domain.jsondata.spec.name == "ansible_security_domain_test" + - nm_create_security_domain.jsondata.spec.description == "Security Domain Test for nd_rest module." + +- name: Update Security Domain with PUT method + cisco.nd.nd_rest: &update_security_domain + <<: *nd_info + path: /nexus/infra/api/aaa/v4/securitydomains/ansible_security_domain_test + method: put + content: + spec: + description: "Updated Security Domain Test for nd_rest module." + register: nm_update_security_domain + +- name: Update Security Domain with PUT method again + cisco.nd.nd_rest: + <<: *update_security_domain + register: nm_update_security_domain_again + +- name: Assert udpate tasks with PUT method for nd_rest module + ansible.builtin.assert: + that: + - nm_update_security_domain is changed + - nm_update_security_domain.previous.spec.name == "ansible_security_domain_test" + - nm_update_security_domain.previous.spec.description == "Security Domain Test for nd_rest module." + - nm_update_security_domain.current.spec.name == "ansible_security_domain_test" + - nm_update_security_domain.current.spec.description == "Updated Security Domain Test for nd_rest module." + - nm_update_security_domain.data.spec.description == "Updated Security Domain Test for nd_rest module." + - nm_update_security_domain.current.spec.name == "ansible_security_domain_test" + - nm_update_security_domain.jsondata.spec.description == "Updated Security Domain Test for nd_rest module." + - nm_update_security_domain_again is not changed + - nm_update_security_domain_again.previous.spec.name == "ansible_security_domain_test" + - nm_update_security_domain_again.previous.spec.description == "Updated Security Domain Test for nd_rest module." + - nm_update_security_domain_again.current.spec.name == "ansible_security_domain_test" + - nm_update_security_domain_again.current.spec.description == "Updated Security Domain Test for nd_rest module." + - nm_update_security_domain_again.data.spec.description == "Updated Security Domain Test for nd_rest module." + - nm_update_security_domain_again.current.spec.name == "ansible_security_domain_test" + - nm_update_security_domain_again.jsondata.spec.description == "Updated Security Domain Test for nd_rest module." + +- name: Query Security Domain with GET method + cisco.nd.nd_rest: + <<: *nd_info + path: /nexus/infra/api/aaa/v4/securitydomains/ansible_security_domain_test + method: get + register: quey_one_security_domain + +- name: Query all Security Domains with GET method + cisco.nd.nd_rest: + <<: *nd_info + path: /nexus/infra/api/aaa/v4/securitydomains + method: get + register: quey_all_security_domains + +- name: Assert udpate tasks with PUT method for nd_rest module + ansible.builtin.assert: + that: + - quey_one_security_domain is not changed + - quey_one_security_domain.current.spec.name == "ansible_security_domain_test" + - quey_one_security_domain.jsondata.spec.name == "ansible_security_domain_test" + - quey_all_security_domains is not changed + - quey_all_security_domains.current.items.0.spec.name == "all" + - quey_all_security_domains.current.items.1.spec.name == "ansible_security_domain_test" + - quey_all_security_domains.jsondata.items.0.spec.name == "all" + - quey_all_security_domains.jsondata.items.1.spec.name == "ansible_security_domain_test" + +- name: Delete Security Domain with DELETE method + cisco.nd.nd_rest: + <<: *delete_security_domain + register: nm_delete_security_domain + +- name: Delete Security Domain with DELETE method again + cisco.nd.nd_rest: + <<: *delete_security_domain + register: nm_delete_security_domain_again + +- name: Assert udpate tasks with PUT method for nd_rest module + ansible.builtin.assert: + that: + - nm_delete_security_domain is changed + - nm_delete_security_domain.previous.spec.name == "ansible_security_domain_test" + - nm_delete_security_domain.previous.spec.description == "Updated Security Domain Test for nd_rest module." + - nm_delete_security_domain.current == {} + - nm_delete_security_domain.jsondata == {} + - nm_delete_security_domain_again is not changed + - nm_delete_security_domain_again.previous == {} + - nm_delete_security_domain_again.current == {} + - nm_delete_security_domain_again.jsondata == {} diff --git a/tests/integration/targets/nd_rest/tasks/yaml_string.yml b/tests/integration/targets/nd_rest/tasks/yaml_string.yml new file mode 100644 index 0000000..bd72858 --- /dev/null +++ b/tests/integration/targets/nd_rest/tasks/yaml_string.yml @@ -0,0 +1,145 @@ +# Test code for the ND modules +# Copyright: (c) 2024, Gaspard Micol (@gmciol) + +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) + +- name: Test that we have a Nexus Dashboard host, username and password + ansible.builtin.fail: + msg: 'Please define the following variables: ansible_host, ansible_user and ansible_password.' + when: ansible_host is not defined or ansible_user is not defined or ansible_password is not defined + +- name: Set vars + ansible.builtin.set_fact: + nd_info: &nd_info + host: '{{ ansible_host }}' + username: '{{ ansible_user }}' + password: '{{ ansible_password }}' + validate_certs: '{{ ansible_httpapi_validate_certs | default(false) }}' + use_ssl: '{{ ansible_httpapi_use_ssl | default(true) }}' + use_proxy: '{{ ansible_httpapi_use_proxy | default(true) }}' + output_level: '{{ mso_output_level | default("info") }}' + timeout: 90 + +- name: Ensure Security Domain does not exist using DELETE method + cisco.nd.nd_rest: &delete_security_domain + <<: *nd_info + path: /nexus/infra/api/aaa/v4/securitydomains/ansible_security_domain_test + method: delete + +- name: Create Security Domain with POST method (check_mode) + cisco.nd.nd_rest: &create_security_domain + <<: *nd_info + path: /nexus/infra/api/aaa/v4/securitydomains + method: post + content: | + spec: + description: "Security Domain Test for nd_rest module." + name: "ansible_security_domain_test" + check_mode: true + register: cm_create_security_domain + +- name: Create Security Domain with POST method + cisco.nd.nd_rest: + <<: *create_security_domain + register: nm_create_security_domain + +- name: Assert creation tasks with POST method for nd_rest module + ansible.builtin.assert: + that: + - cm_create_security_domain is changed + - cm_create_security_domain.previous == {} + - cm_create_security_domain.current == {} + - cm_create_security_domain.jsondata.spec.name == "ansible_security_domain_test" + - cm_create_security_domain.jsondata.spec.description == "Security Domain Test for nd_rest module." + - nm_create_security_domain is changed + - nm_create_security_domain.previous == {} + - nm_create_security_domain.current.spec.name == "ansible_security_domain_test" + - nm_create_security_domain.current.spec.description == "Security Domain Test for nd_rest module." + - nm_create_security_domain.data.spec.name == "ansible_security_domain_test" + - nm_create_security_domain.data.spec.description == "Security Domain Test for nd_rest module." + - nm_create_security_domain.jsondata.spec.name == "ansible_security_domain_test" + - nm_create_security_domain.jsondata.spec.description == "Security Domain Test for nd_rest module." + +- name: Update Security Domain with PUT method + cisco.nd.nd_rest: &update_security_domain + <<: *nd_info + path: /nexus/infra/api/aaa/v4/securitydomains/ansible_security_domain_test + method: put + content: | + spec: + description: "Updated Security Domain Test for nd_rest module." + register: nm_update_security_domain + +- name: Update Security Domain with PUT method again + cisco.nd.nd_rest: + <<: *update_security_domain + register: nm_update_security_domain_again + +- name: Assert udpate tasks with PUT method for nd_rest module + ansible.builtin.assert: + that: + - nm_update_security_domain is changed + - nm_update_security_domain.previous.spec.name == "ansible_security_domain_test" + - nm_update_security_domain.previous.spec.description == "Security Domain Test for nd_rest module." + - nm_update_security_domain.current.spec.name == "ansible_security_domain_test" + - nm_update_security_domain.current.spec.description == "Updated Security Domain Test for nd_rest module." + - nm_update_security_domain.data.spec.description == "Updated Security Domain Test for nd_rest module." + - nm_update_security_domain.current.spec.name == "ansible_security_domain_test" + - nm_update_security_domain.jsondata.spec.description == "Updated Security Domain Test for nd_rest module." + - nm_update_security_domain_again is not changed + - nm_update_security_domain_again.previous.spec.name == "ansible_security_domain_test" + - nm_update_security_domain_again.previous.spec.description == "Updated Security Domain Test for nd_rest module." + - nm_update_security_domain_again.current.spec.name == "ansible_security_domain_test" + - nm_update_security_domain_again.current.spec.description == "Updated Security Domain Test for nd_rest module." + - nm_update_security_domain_again.data.spec.description == "Updated Security Domain Test for nd_rest module." + - nm_update_security_domain_again.current.spec.name == "ansible_security_domain_test" + - nm_update_security_domain_again.jsondata.spec.description == "Updated Security Domain Test for nd_rest module." + +- name: Query Security Domain with GET method + cisco.nd.nd_rest: + <<: *nd_info + path: /nexus/infra/api/aaa/v4/securitydomains/ansible_security_domain_test + method: get + register: quey_one_security_domain + +- name: Query all Security Domains with GET method + cisco.nd.nd_rest: + <<: *nd_info + path: /nexus/infra/api/aaa/v4/securitydomains + method: get + register: quey_all_security_domains + +- name: Assert udpate tasks with PUT method for nd_rest module + ansible.builtin.assert: + that: + - quey_one_security_domain is not changed + - quey_one_security_domain.current.spec.name == "ansible_security_domain_test" + - quey_one_security_domain.jsondata.spec.name == "ansible_security_domain_test" + - quey_all_security_domains is not changed + - quey_all_security_domains.current.items.0.spec.name == "all" + - quey_all_security_domains.current.items.1.spec.name == "ansible_security_domain_test" + - quey_all_security_domains.jsondata.items.0.spec.name == "all" + - quey_all_security_domains.jsondata.items.1.spec.name == "ansible_security_domain_test" + +- name: Delete Security Domain with DELETE method + cisco.nd.nd_rest: + <<: *delete_security_domain + register: nm_delete_security_domain + +- name: Delete Security Domain with DELETE method again + cisco.nd.nd_rest: + <<: *delete_security_domain + register: nm_delete_security_domain_again + +- name: Assert udpate tasks with PUT method for nd_rest module + ansible.builtin.assert: + that: + - nm_delete_security_domain is changed + - nm_delete_security_domain.previous.spec.name == "ansible_security_domain_test" + - nm_delete_security_domain.previous.spec.description == "Updated Security Domain Test for nd_rest module." + - nm_delete_security_domain.current == {} + - nm_delete_security_domain.jsondata == {} + - nm_delete_security_domain_again is not changed + - nm_delete_security_domain_again.previous == {} + - nm_delete_security_domain_again.current == {} + - nm_delete_security_domain_again.jsondata == {}