From 50e345f136376b67f45ce87235ea8cc60d116a80 Mon Sep 17 00:00:00 2001 From: Travis Smith <141754521+tsm1th@users.noreply.github.com> Date: Thu, 31 Oct 2024 11:08:09 +0000 Subject: [PATCH 01/25] Added cloud_resource_type and tests --- plugins/module_utils/cloud.py | 67 ++++++++ plugins/module_utils/utils.py | 3 + plugins/modules/cloud_resource_type.py | 118 ++++++++++++++ .../latest/tasks/cloud_resource_type.yml | 148 ++++++++++++++++++ .../integration/targets/latest/tasks/main.yml | 9 ++ 5 files changed, 345 insertions(+) create mode 100644 plugins/module_utils/cloud.py create mode 100644 plugins/modules/cloud_resource_type.py create mode 100644 tests/integration/targets/latest/tasks/cloud_resource_type.yml diff --git a/plugins/module_utils/cloud.py b/plugins/module_utils/cloud.py new file mode 100644 index 00000000..42737ae1 --- /dev/null +++ b/plugins/module_utils/cloud.py @@ -0,0 +1,67 @@ +# -*- coding: utf-8 -*- +# Copyright: (c) 2018, Mikhail Yohman (@fragmentedpacket) +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + +from ansible_collections.networktocode.nautobot.plugins.module_utils.utils import ( + NautobotModule, + ENDPOINT_NAME_MAPPING, +) + +NB_CLOUD_RESOURCE_TYPES = "cloud_resource_types" + + +class NautobotCloudModule(NautobotModule): + def run(self): + """ + This function should have all necessary code for endpoints within the application + to create/update/delete the endpoint objects + Supported endpoints: + - cloud_resource_types + """ + # Used to dynamically set key when returning results + endpoint_name = ENDPOINT_NAME_MAPPING[self.endpoint] + + self.result = {"changed": False} + + application = self._find_app(self.endpoint) + nb_app = getattr(self.nb, application) + nb_endpoint = getattr(nb_app, self.endpoint) + user_query_params = self.module.params.get("query_params") + + data = self.data + + # Used for msg output + if data.get("name"): + name = data["name"] + + # This is to overcome a really bad naming clash with the new cloud models. provider=manufacturer + if data.get("manufacturer"): + data["provider"] = data["manufacturer"] + data.pop("manufacturer") + + + object_query_params = self._build_query_params(endpoint_name, data, user_query_params) + self.nb_object = self._nb_endpoint_get(nb_endpoint, object_query_params, name) + + if self.state == "present": + self._ensure_object_exists(nb_endpoint, endpoint_name, name, data) + elif self.state == "absent": + self._ensure_object_absent(endpoint_name, name) + + try: + serialized_object = self.nb_object.serialize() + except AttributeError: + serialized_object = self.nb_object + + # This is to overcome a really bad naming clash with the new cloud models. manufacturer=provider + if isinstance(serialized_object, dict): + if serialized_object.get("provider"): + serialized_object["manufacturer"] = serialized_object["provider"] + serialized_object.pop("provider") + + self.result.update({endpoint_name: serialized_object}) + + self.module.exit_json(**self.result) diff --git a/plugins/module_utils/utils.py b/plugins/module_utils/utils.py index 08b9191b..0abf920e 100644 --- a/plugins/module_utils/utils.py +++ b/plugins/module_utils/utils.py @@ -33,6 +33,7 @@ # Used to map endpoints to applications dynamically API_APPS_ENDPOINTS = dict( circuits=["circuits", "circuit_types", "circuit_terminations", "providers"], + cloud=["cloud_resource_types"], dcim=[ "cables", "console_ports", @@ -229,6 +230,7 @@ "circuit_terminations": "circuit_termination", "circuit_types": "circuit_type", "circuits": "circuit", + "cloud_resource_types": "cloud_resource_type", "clusters": "cluster", "cluster_groups": "cluster_group", "cluster_types": "cluster_type", @@ -296,6 +298,7 @@ "circuit_type": set(["name"]), "circuit_termination": set(["circuit", "term_side"]), "circuits.circuittermination": set(["circuit", "term_side"]), + "cloud_resource_type": set(["name"]), "cluster": set(["name", "type"]), "cluster_group": set(["name"]), "cluster_type": set(["name"]), diff --git a/plugins/modules/cloud_resource_type.py b/plugins/modules/cloud_resource_type.py new file mode 100644 index 00000000..cbe6dcc3 --- /dev/null +++ b/plugins/modules/cloud_resource_type.py @@ -0,0 +1,118 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# Copyright: (c) 2024, Network to Code (@networktocode) +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + +DOCUMENTATION = r""" +--- +module: cloud_resource_type +short_description: Creates or removes cloud_resource_type from Nautobot +description: + - Creates or removes cloud_resource_type from Nautobot +notes: + - Tags should be defined as a YAML list + - This should be ran with connection C(local) and hosts C(localhost) +author: + - Travis Smith (@tsm1th) +requirements: + - pynautobot +version_added: "5.4.0" +extends_documentation_fragment: + - networktocode.nautobot.fragments.base + - networktocode.nautobot.fragments.tags + - networktocode.nautobot.fragments.custom_fields +options: + name: + description: + - The name of the cloud_resource_type + required: true + type: str + description: + description: + - The description of the cloud_resource_type + required: false + type: str + manufacturer: + description: + - Required if I(state=present) and the cloud_resource_type does not exist yet + required: false + type: raw + content_types: + description: + - Cloud Resource Type content type(s). These match app.endpoint and the endpoint is singular. + - e.g. cloud.cloudnetwork, cloud.cloudservice (more can be found in the examples) + type: list + elements: str +""" + +EXAMPLES = r""" +--- +- name: Create a cloud_resource_type + networktocode.nautobot.cloud_resource_type: + url: http://nautobot.local + token: thisIsMyToken + name: Cisco Quantum Network + manufacturer: Cisco + content_types: + - "cloud.cloud_network" + state: present + +- name: Delete a cloud_resource_type + networktocode.nautobot.contact: + url: http://nautobot.local + token: thisIsMyToken + name: Cisco Quantum Network + state: absent +""" + +RETURN = r""" +cloud_resource_type: + description: Serialized object as created or already existent within Nautobot + returned: success (when I(state=present)) + type: dict +msg: + description: Message indicating failure or info about what has been achieved + returned: always + type: str +""" + +from ansible_collections.networktocode.nautobot.plugins.module_utils.utils import ( + NAUTOBOT_ARG_SPEC, + TAGS_ARG_SPEC, + CUSTOM_FIELDS_ARG_SPEC, +) +from ansible_collections.networktocode.nautobot.plugins.module_utils.cloud import ( + NautobotCloudModule, + NB_CLOUD_RESOURCE_TYPES, +) +from ansible.module_utils.basic import AnsibleModule +from copy import deepcopy + + +def main(): + """ + Main entry point for module execution + """ + argument_spec = deepcopy(NAUTOBOT_ARG_SPEC) + argument_spec.update(deepcopy(TAGS_ARG_SPEC)) + argument_spec.update(deepcopy(CUSTOM_FIELDS_ARG_SPEC)) + argument_spec.update( + dict( + name=dict(required=True, type="str"), + description=dict(required=False, type="str"), + manufacturer=dict(required=False, type="raw"), + content_types=dict(required=False, type="list", elements="str"), + ) + ) + + module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True) + cloud_resource_type = NautobotCloudModule(module, NB_CLOUD_RESOURCE_TYPES) + cloud_resource_type.run() + + +if __name__ == "__main__": # pragma: no cover + main() diff --git a/tests/integration/targets/latest/tasks/cloud_resource_type.yml b/tests/integration/targets/latest/tasks/cloud_resource_type.yml new file mode 100644 index 00000000..84238229 --- /dev/null +++ b/tests/integration/targets/latest/tasks/cloud_resource_type.yml @@ -0,0 +1,148 @@ +--- +## +## +### PYNAUTOBOT_CLOUD_RESOURCE_TYPE +## +## + +- block: + - set_fact: + provider: "{{ lookup('networktocode.nautobot.lookup', 'manufacturers', api_endpoint=nautobot_url, token=nautobot_token, api_filter='name=Cisco') }}" + + - name: "1 - Create cloud resource type within Nautobot with only required information" + networktocode.nautobot.cloud_resource_type: + url: "{{ nautobot_url }}" + token: "{{ nautobot_token }}" + name: Cisco Quantum Network + manufacturer: Cisco + content_types: + - "cloud.cloudnetwork" + register: test_create_min + + - name: "1 - ASSERT" + assert: + that:git + - test_create_min is changed + - test_create_min['diff']['before']['state'] == "absent" + - test_create_min['diff']['after']['state'] == "present" + - test_create_min['cloud_resource_type']['name'] == "Cisco Quantum Network" + - test_create_min['msg'] == "cloud_resource_type Cisco Quantum Network created" + + - name: "2 - Duplicate" + networktocode.nautobot.cloud_resource_type: + url: "{{ nautobot_url }}" + token: "{{ nautobot_token }}" + name: Cisco Quantum Network + + register: test_create_idem + - name: "2 - ASSERT" + assert: + that: + - not test_create_idem['changed'] + - test_create_idem['msg'] == "cloud_resource_type Cisco Quantum Network already exists" + - test_create_idem['cloud_resource_type']['name'] == "Cisco Quantum Network" + + - name: "3 - Update cloud_resource_type" + networktocode.nautobot.cloud_resource_type: + url: "{{ nautobot_url }}" + token: "{{ nautobot_token }}" + name: Cisco Quantum Network + description: Very fast network! + register: test_update + + - name: "3 - ASSERT" + assert: + that: + - test_update is changed + - test_update['diff']['before']['description'] == "" + - test_update['diff']['after']['description'] == "Very fast network!" + + - name: "4 - Update idempotent" + networktocode.nautobot.cloud_resource_type: + url: "{{ nautobot_url }}" + token: "{{ nautobot_token }}" + name: Cisco Quantum Network + description: Very fast network! + register: test_update_idem + + - name: "4 - ASSERT" + assert: + that: + - not test_update_idem['changed'] + - test_update_idem['msg'] == "cloud_resource_type Cisco Quantum Network already exists" + - test_update_idem['cloud_resource_type']['name'] == "Cisco Quantum Network" + + - name: "5 - Create cloud_resource_type with all parameters" + networktocode.nautobot.cloud_resource_type: + url: "{{ nautobot_url }}" + token: "{{ nautobot_token }}" + name: Cisco Quantum Network Remix + manufacturer: Cisco + description: Very fast network reimagined! + content_types: + - "cloud.cloudnetwork" + register: test_create_max + + - name: DEBUG + debug: + msg: "{{ test_create_max }}" + + - name: "5 - ASSERT" + assert: + that: + - test_create_max is changed + - test_create_max['diff']['before']['state'] == "absent" + - test_create_max['diff']['after']['state'] == "present" + - test_create_max['cloud_resource_type']['name'] == "Cisco Quantum Network Remix" + - test_create_max['cloud_resource_type']['manufacturer'] == provider['key'] + - test_create_max['cloud_resource_type']['description'] == "Very fast network reimagined!" + - test_create_max['cloud_resource_type']['content_types'] == ["cloud.cloudnetwork"] + + - name: "6 - Duplicate create with all parameters" + networktocode.nautobot.cloud_resource_type: + url: "{{ nautobot_url }}" + token: "{{ nautobot_token }}" + name: Cisco Quantum Network Remix + manufacturer: Cisco + description: Very fast network reimagined! + content_types: + - "cloud.cloudnetwork" + register: test_create_max_idem + + - name: "6 - ASSERT" + assert: + that: + - not test_create_max_idem['changed'] + - test_create_max_idem['msg'] == "cloud_resource_type Cisco Quantum Network Remix already exists" + - test_create_max_idem['cloud_resource_type']['name'] == "Cisco Quantum Network Remix" + + - name: "7 - Delete cloud_resource_type" + networktocode.nautobot.cloud_resource_type: + url: "{{ nautobot_url }}" + token: "{{ nautobot_token }}" + name: Cisco Quantum Network Remix + state: absent + register: test_delete + + - name: "7 - ASSERT" + assert: + that: + - test_delete is changed + - test_delete['diff']['before']['state'] == "present" + - test_delete['diff']['after']['state'] == "absent" + - test_delete['cloud_resource_type']['name'] == "Cisco Quantum Network Remix" + - "'deleted' in test_delete['msg']" + + - name: "8 - Delete idempotent" + networktocode.nautobot.cloud_resource_type: + url: "{{ nautobot_url }}" + token: "{{ nautobot_token }}" + name: Cisco Quantum Network Remix + state: absent + register: test_delete_idem + + - name: "8 - ASSERT" + assert: + that: + - not test_delete_idem['changed'] + - "'already absent' in test_delete_idem['msg']" \ No newline at end of file diff --git a/tests/integration/targets/latest/tasks/main.yml b/tests/integration/targets/latest/tasks/main.yml index 30291773..58831acb 100644 --- a/tests/integration/targets/latest/tasks/main.yml +++ b/tests/integration/targets/latest/tasks/main.yml @@ -590,3 +590,12 @@ - controller tags: - controller + +- name: "PYNAUTOBOT_CLOUD_RESOURCE_TYPE TESTS" + include_tasks: + file: "cloud_resource_type.yml" + apply: + tags: + - cloud_resource_type + tags: + - cloud_resource_type \ No newline at end of file From 519fb8c8461986976980b8efff400c4315a76f92 Mon Sep 17 00:00:00 2001 From: Travis Smith <141754521+tsm1th@users.noreply.github.com> Date: Thu, 31 Oct 2024 11:27:27 +0000 Subject: [PATCH 02/25] Fixed linting issue --- plugins/module_utils/cloud.py | 1 - plugins/modules/cloud_resource_type.py | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/plugins/module_utils/cloud.py b/plugins/module_utils/cloud.py index 42737ae1..5eb336d1 100644 --- a/plugins/module_utils/cloud.py +++ b/plugins/module_utils/cloud.py @@ -42,7 +42,6 @@ def run(self): data["provider"] = data["manufacturer"] data.pop("manufacturer") - object_query_params = self._build_query_params(endpoint_name, data, user_query_params) self.nb_object = self._nb_endpoint_get(nb_endpoint, object_query_params, name) diff --git a/plugins/modules/cloud_resource_type.py b/plugins/modules/cloud_resource_type.py index cbe6dcc3..9a89fbc7 100644 --- a/plugins/modules/cloud_resource_type.py +++ b/plugins/modules/cloud_resource_type.py @@ -104,7 +104,7 @@ def main(): dict( name=dict(required=True, type="str"), description=dict(required=False, type="str"), - manufacturer=dict(required=False, type="raw"), + manufacturer=dict(required=False, type="raw"), content_types=dict(required=False, type="list", elements="str"), ) ) From 9e803b7d57f06fb691de563f560ff48207e303be Mon Sep 17 00:00:00 2001 From: Travis Smith <141754521+tsm1th@users.noreply.github.com> Date: Thu, 31 Oct 2024 11:32:22 +0000 Subject: [PATCH 03/25] Updated cloud test to only run on nautobot2.3 --- .../integration/targets/latest/tasks/cloud_resource_type.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/integration/targets/latest/tasks/cloud_resource_type.yml b/tests/integration/targets/latest/tasks/cloud_resource_type.yml index 84238229..f689b82b 100644 --- a/tests/integration/targets/latest/tasks/cloud_resource_type.yml +++ b/tests/integration/targets/latest/tasks/cloud_resource_type.yml @@ -6,6 +6,8 @@ ## - block: + when: + - "nautobot_version is version('2.3', '>=')" - set_fact: provider: "{{ lookup('networktocode.nautobot.lookup', 'manufacturers', api_endpoint=nautobot_url, token=nautobot_token, api_filter='name=Cisco') }}" @@ -21,7 +23,7 @@ - name: "1 - ASSERT" assert: - that:git + that: - test_create_min is changed - test_create_min['diff']['before']['state'] == "absent" - test_create_min['diff']['after']['state'] == "present" From 419d0e9e0dd5228b4c4b4ee8e3a9d938cdfedf1c Mon Sep 17 00:00:00 2001 From: Travis Smith <141754521+tsm1th@users.noreply.github.com> Date: Thu, 31 Oct 2024 12:05:42 +0000 Subject: [PATCH 04/25] Fixed indentation issue in test --- .../latest/tasks/cloud_resource_type.yml | 257 +++++++++--------- 1 file changed, 129 insertions(+), 128 deletions(-) diff --git a/tests/integration/targets/latest/tasks/cloud_resource_type.yml b/tests/integration/targets/latest/tasks/cloud_resource_type.yml index f689b82b..1b19a241 100644 --- a/tests/integration/targets/latest/tasks/cloud_resource_type.yml +++ b/tests/integration/targets/latest/tasks/cloud_resource_type.yml @@ -5,146 +5,147 @@ ## ## -- block: +- name: "NAUTOBOT 2.3+ CLOUD RESOURCE TYPE TESTS" when: - "nautobot_version is version('2.3', '>=')" - - set_fact: - provider: "{{ lookup('networktocode.nautobot.lookup', 'manufacturers', api_endpoint=nautobot_url, token=nautobot_token, api_filter='name=Cisco') }}" + block: + - set_fact: + provider: "{{ lookup('networktocode.nautobot.lookup', 'manufacturers', api_endpoint=nautobot_url, token=nautobot_token, api_filter='name=Cisco') }}" - - name: "1 - Create cloud resource type within Nautobot with only required information" - networktocode.nautobot.cloud_resource_type: - url: "{{ nautobot_url }}" - token: "{{ nautobot_token }}" - name: Cisco Quantum Network - manufacturer: Cisco - content_types: - - "cloud.cloudnetwork" - register: test_create_min + - name: "1 - Create cloud resource type within Nautobot with only required information" + networktocode.nautobot.cloud_resource_type: + url: "{{ nautobot_url }}" + token: "{{ nautobot_token }}" + name: Cisco Quantum Network + manufacturer: Cisco + content_types: + - "cloud.cloudnetwork" + register: test_create_min - - name: "1 - ASSERT" - assert: - that: - - test_create_min is changed - - test_create_min['diff']['before']['state'] == "absent" - - test_create_min['diff']['after']['state'] == "present" - - test_create_min['cloud_resource_type']['name'] == "Cisco Quantum Network" - - test_create_min['msg'] == "cloud_resource_type Cisco Quantum Network created" + - name: "1 - ASSERT" + assert: + that: + - test_create_min is changed + - test_create_min['diff']['before']['state'] == "absent" + - test_create_min['diff']['after']['state'] == "present" + - test_create_min['cloud_resource_type']['name'] == "Cisco Quantum Network" + - test_create_min['msg'] == "cloud_resource_type Cisco Quantum Network created" - - name: "2 - Duplicate" - networktocode.nautobot.cloud_resource_type: - url: "{{ nautobot_url }}" - token: "{{ nautobot_token }}" - name: Cisco Quantum Network + - name: "2 - Duplicate" + networktocode.nautobot.cloud_resource_type: + url: "{{ nautobot_url }}" + token: "{{ nautobot_token }}" + name: Cisco Quantum Network - register: test_create_idem - - name: "2 - ASSERT" - assert: - that: - - not test_create_idem['changed'] - - test_create_idem['msg'] == "cloud_resource_type Cisco Quantum Network already exists" - - test_create_idem['cloud_resource_type']['name'] == "Cisco Quantum Network" - - - name: "3 - Update cloud_resource_type" - networktocode.nautobot.cloud_resource_type: - url: "{{ nautobot_url }}" - token: "{{ nautobot_token }}" - name: Cisco Quantum Network - description: Very fast network! - register: test_update - - - name: "3 - ASSERT" - assert: - that: - - test_update is changed - - test_update['diff']['before']['description'] == "" - - test_update['diff']['after']['description'] == "Very fast network!" + register: test_create_idem + - name: "2 - ASSERT" + assert: + that: + - not test_create_idem['changed'] + - test_create_idem['msg'] == "cloud_resource_type Cisco Quantum Network already exists" + - test_create_idem['cloud_resource_type']['name'] == "Cisco Quantum Network" + + - name: "3 - Update cloud_resource_type" + networktocode.nautobot.cloud_resource_type: + url: "{{ nautobot_url }}" + token: "{{ nautobot_token }}" + name: Cisco Quantum Network + description: Very fast network! + register: test_update + + - name: "3 - ASSERT" + assert: + that: + - test_update is changed + - test_update['diff']['before']['description'] == "" + - test_update['diff']['after']['description'] == "Very fast network!" - - name: "4 - Update idempotent" - networktocode.nautobot.cloud_resource_type: - url: "{{ nautobot_url }}" - token: "{{ nautobot_token }}" - name: Cisco Quantum Network - description: Very fast network! - register: test_update_idem + - name: "4 - Update idempotent" + networktocode.nautobot.cloud_resource_type: + url: "{{ nautobot_url }}" + token: "{{ nautobot_token }}" + name: Cisco Quantum Network + description: Very fast network! + register: test_update_idem - - name: "4 - ASSERT" - assert: - that: - - not test_update_idem['changed'] - - test_update_idem['msg'] == "cloud_resource_type Cisco Quantum Network already exists" - - test_update_idem['cloud_resource_type']['name'] == "Cisco Quantum Network" + - name: "4 - ASSERT" + assert: + that: + - not test_update_idem['changed'] + - test_update_idem['msg'] == "cloud_resource_type Cisco Quantum Network already exists" + - test_update_idem['cloud_resource_type']['name'] == "Cisco Quantum Network" - - name: "5 - Create cloud_resource_type with all parameters" - networktocode.nautobot.cloud_resource_type: - url: "{{ nautobot_url }}" - token: "{{ nautobot_token }}" - name: Cisco Quantum Network Remix - manufacturer: Cisco - description: Very fast network reimagined! - content_types: - - "cloud.cloudnetwork" - register: test_create_max + - name: "5 - Create cloud_resource_type with all parameters" + networktocode.nautobot.cloud_resource_type: + url: "{{ nautobot_url }}" + token: "{{ nautobot_token }}" + name: Cisco Quantum Network Remix + manufacturer: Cisco + description: Very fast network reimagined! + content_types: + - "cloud.cloudnetwork" + register: test_create_max - - name: DEBUG - debug: - msg: "{{ test_create_max }}" + - name: DEBUG + debug: + msg: "{{ test_create_max }}" - - name: "5 - ASSERT" - assert: - that: - - test_create_max is changed - - test_create_max['diff']['before']['state'] == "absent" - - test_create_max['diff']['after']['state'] == "present" - - test_create_max['cloud_resource_type']['name'] == "Cisco Quantum Network Remix" - - test_create_max['cloud_resource_type']['manufacturer'] == provider['key'] - - test_create_max['cloud_resource_type']['description'] == "Very fast network reimagined!" - - test_create_max['cloud_resource_type']['content_types'] == ["cloud.cloudnetwork"] + - name: "5 - ASSERT" + assert: + that: + - test_create_max is changed + - test_create_max['diff']['before']['state'] == "absent" + - test_create_max['diff']['after']['state'] == "present" + - test_create_max['cloud_resource_type']['name'] == "Cisco Quantum Network Remix" + - test_create_max['cloud_resource_type']['manufacturer'] == provider['key'] + - test_create_max['cloud_resource_type']['description'] == "Very fast network reimagined!" + - test_create_max['cloud_resource_type']['content_types'] == ["cloud.cloudnetwork"] - - name: "6 - Duplicate create with all parameters" - networktocode.nautobot.cloud_resource_type: - url: "{{ nautobot_url }}" - token: "{{ nautobot_token }}" - name: Cisco Quantum Network Remix - manufacturer: Cisco - description: Very fast network reimagined! - content_types: - - "cloud.cloudnetwork" - register: test_create_max_idem + - name: "6 - Duplicate create with all parameters" + networktocode.nautobot.cloud_resource_type: + url: "{{ nautobot_url }}" + token: "{{ nautobot_token }}" + name: Cisco Quantum Network Remix + manufacturer: Cisco + description: Very fast network reimagined! + content_types: + - "cloud.cloudnetwork" + register: test_create_max_idem - - name: "6 - ASSERT" - assert: - that: - - not test_create_max_idem['changed'] - - test_create_max_idem['msg'] == "cloud_resource_type Cisco Quantum Network Remix already exists" - - test_create_max_idem['cloud_resource_type']['name'] == "Cisco Quantum Network Remix" + - name: "6 - ASSERT" + assert: + that: + - not test_create_max_idem['changed'] + - test_create_max_idem['msg'] == "cloud_resource_type Cisco Quantum Network Remix already exists" + - test_create_max_idem['cloud_resource_type']['name'] == "Cisco Quantum Network Remix" - - name: "7 - Delete cloud_resource_type" - networktocode.nautobot.cloud_resource_type: - url: "{{ nautobot_url }}" - token: "{{ nautobot_token }}" - name: Cisco Quantum Network Remix - state: absent - register: test_delete - - - name: "7 - ASSERT" - assert: - that: - - test_delete is changed - - test_delete['diff']['before']['state'] == "present" - - test_delete['diff']['after']['state'] == "absent" - - test_delete['cloud_resource_type']['name'] == "Cisco Quantum Network Remix" - - "'deleted' in test_delete['msg']" - - - name: "8 - Delete idempotent" - networktocode.nautobot.cloud_resource_type: - url: "{{ nautobot_url }}" - token: "{{ nautobot_token }}" - name: Cisco Quantum Network Remix - state: absent - register: test_delete_idem + - name: "7 - Delete cloud_resource_type" + networktocode.nautobot.cloud_resource_type: + url: "{{ nautobot_url }}" + token: "{{ nautobot_token }}" + name: Cisco Quantum Network Remix + state: absent + register: test_delete + + - name: "7 - ASSERT" + assert: + that: + - test_delete is changed + - test_delete['diff']['before']['state'] == "present" + - test_delete['diff']['after']['state'] == "absent" + - test_delete['cloud_resource_type']['name'] == "Cisco Quantum Network Remix" + - "'deleted' in test_delete['msg']" + + - name: "8 - Delete idempotent" + networktocode.nautobot.cloud_resource_type: + url: "{{ nautobot_url }}" + token: "{{ nautobot_token }}" + name: Cisco Quantum Network Remix + state: absent + register: test_delete_idem - - name: "8 - ASSERT" - assert: - that: - - not test_delete_idem['changed'] - - "'already absent' in test_delete_idem['msg']" \ No newline at end of file + - name: "8 - ASSERT" + assert: + that: + - not test_delete_idem['changed'] + - "'already absent' in test_delete_idem['msg']" \ No newline at end of file From 575e4f897d1c2ed2e41beca146813ace59d702e4 Mon Sep 17 00:00:00 2001 From: Travis Smith <141754521+tsm1th@users.noreply.github.com> Date: Fri, 1 Nov 2024 12:00:53 +0000 Subject: [PATCH 05/25] Added alias to handle name clashing and added lookup for new model --- development/dev.env | 5 +++- plugins/lookup/lookup.py | 1 + plugins/module_utils/cloud.py | 15 +++-------- plugins/module_utils/utils.py | 3 +++ plugins/modules/cloud_resource_type.py | 16 +++++++++--- .../latest/tasks/cloud_resource_type.yml | 26 ++++++++++++------- 6 files changed, 39 insertions(+), 27 deletions(-) diff --git a/development/dev.env b/development/dev.env index 79d49669..cde00465 100644 --- a/development/dev.env +++ b/development/dev.env @@ -28,4 +28,7 @@ POSTGRES_PASSWORD=decinablesprewad POSTGRES_USER=nautobot # Needed for Redis should match the values for Nautobot above -REDIS_PASSWORD=decinablesprewad \ No newline at end of file +REDIS_PASSWORD=decinablesprewad + +INVOKE_NAUTOBOT_ANSIBLE_PYTHON_VER: 3.11 +INVOKE_NAUTOBOT_ANSIBLE_NAUTOBOT_VER: 2.3 \ No newline at end of file diff --git a/plugins/lookup/lookup.py b/plugins/lookup/lookup.py index 3989d462..e034fa0b 100644 --- a/plugins/lookup/lookup.py +++ b/plugins/lookup/lookup.py @@ -173,6 +173,7 @@ def get_endpoint(nautobot, term): "circuits": {"endpoint": nautobot.circuits.circuits}, "circuit-providers": {"endpoint": nautobot.circuits.providers}, "cables": {"endpoint": nautobot.dcim.cables}, + "cloud-resource-types": {"endpoint": nautobot.cloud.cloud_resource_types}, "cluster-groups": {"endpoint": nautobot.virtualization.cluster_groups}, "cluster-types": {"endpoint": nautobot.virtualization.cluster_types}, "clusters": {"endpoint": nautobot.virtualization.clusters}, diff --git a/plugins/module_utils/cloud.py b/plugins/module_utils/cloud.py index 5eb336d1..002c2750 100644 --- a/plugins/module_utils/cloud.py +++ b/plugins/module_utils/cloud.py @@ -1,6 +1,8 @@ +#!/usr/bin/python # -*- coding: utf-8 -*- -# Copyright: (c) 2018, Mikhail Yohman (@fragmentedpacket) +# Copyright: (c) 2024, Network to Code (@networktocode) # GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + from __future__ import absolute_import, division, print_function __metaclass__ = type @@ -37,11 +39,6 @@ def run(self): if data.get("name"): name = data["name"] - # This is to overcome a really bad naming clash with the new cloud models. provider=manufacturer - if data.get("manufacturer"): - data["provider"] = data["manufacturer"] - data.pop("manufacturer") - object_query_params = self._build_query_params(endpoint_name, data, user_query_params) self.nb_object = self._nb_endpoint_get(nb_endpoint, object_query_params, name) @@ -55,12 +52,6 @@ def run(self): except AttributeError: serialized_object = self.nb_object - # This is to overcome a really bad naming clash with the new cloud models. manufacturer=provider - if isinstance(serialized_object, dict): - if serialized_object.get("provider"): - serialized_object["manufacturer"] = serialized_object["provider"] - serialized_object.pop("provider") - self.result.update({endpoint_name: serialized_object}) self.module.exit_json(**self.result) diff --git a/plugins/module_utils/utils.py b/plugins/module_utils/utils.py index 0abf920e..e496f3b1 100644 --- a/plugins/module_utils/utils.py +++ b/plugins/module_utils/utils.py @@ -102,6 +102,7 @@ circuit="cid", circuit_termination="circuit", circuit_type="name", + cloud_provider="name", cluster="name", cluster_group="name", cluster_type="name", @@ -156,6 +157,7 @@ "circuit_type": "circuit_types", "circuit_termination": "circuit_terminations", "circuits.circuittermination": "circuit_terminations", + "cloud_provider": "manufacturers", "cluster": "clusters", "cluster_group": "cluster_groups", "cluster_type": "cluster_types", @@ -434,6 +436,7 @@ # This is used to map non-clashing keys to Nautobot API compliant keys to prevent bad logic in code for similar keys but different modules CONVERT_KEYS = { + "cloud_provider": "provider", "parent_rack_group": "parent", "parent_location": "parent", "parent_location_type": "parent", diff --git a/plugins/modules/cloud_resource_type.py b/plugins/modules/cloud_resource_type.py index 9a89fbc7..ed6c9ef6 100644 --- a/plugins/modules/cloud_resource_type.py +++ b/plugins/modules/cloud_resource_type.py @@ -36,7 +36,9 @@ - The description of the cloud_resource_type required: false type: str - manufacturer: + cloud_provider: + aliases: + - provider description: - Required if I(state=present) and the cloud_resource_type does not exist yet required: false @@ -47,6 +49,11 @@ - e.g. cloud.cloudnetwork, cloud.cloudservice (more can be found in the examples) type: list elements: str + config_schema: + description: + - Arbitrary JSON data to define the config schema. + required: false + type: dict """ EXAMPLES = r""" @@ -56,9 +63,9 @@ url: http://nautobot.local token: thisIsMyToken name: Cisco Quantum Network - manufacturer: Cisco + cloud_provider: Cisco content_types: - - "cloud.cloud_network" + - "cloud.cloudnetwork" state: present - name: Delete a cloud_resource_type @@ -104,8 +111,9 @@ def main(): dict( name=dict(required=True, type="str"), description=dict(required=False, type="str"), - manufacturer=dict(required=False, type="raw"), + cloud_provider=dict(required=False, type="raw", aliases=["provider"]), content_types=dict(required=False, type="list", elements="str"), + config_schema=dict(required=False, type="dict"), ) ) diff --git a/tests/integration/targets/latest/tasks/cloud_resource_type.yml b/tests/integration/targets/latest/tasks/cloud_resource_type.yml index 1b19a241..6fe32b7f 100644 --- a/tests/integration/targets/latest/tasks/cloud_resource_type.yml +++ b/tests/integration/targets/latest/tasks/cloud_resource_type.yml @@ -10,14 +10,14 @@ - "nautobot_version is version('2.3', '>=')" block: - set_fact: - provider: "{{ lookup('networktocode.nautobot.lookup', 'manufacturers', api_endpoint=nautobot_url, token=nautobot_token, api_filter='name=Cisco') }}" + cisco_provider: "{{ lookup('networktocode.nautobot.lookup', 'manufacturers', api_endpoint=nautobot_url, token=nautobot_token, api_filter='name=Cisco') }}" - name: "1 - Create cloud resource type within Nautobot with only required information" networktocode.nautobot.cloud_resource_type: url: "{{ nautobot_url }}" token: "{{ nautobot_token }}" name: Cisco Quantum Network - manufacturer: Cisco + cloud_provider: Cisco content_types: - "cloud.cloudnetwork" register: test_create_min @@ -80,16 +80,15 @@ url: "{{ nautobot_url }}" token: "{{ nautobot_token }}" name: Cisco Quantum Network Remix - manufacturer: Cisco + cloud_provider: Cisco description: Very fast network reimagined! content_types: - "cloud.cloudnetwork" + config_schema: + my_config: + foo: bar register: test_create_max - - name: DEBUG - debug: - msg: "{{ test_create_max }}" - - name: "5 - ASSERT" assert: that: @@ -97,16 +96,23 @@ - test_create_max['diff']['before']['state'] == "absent" - test_create_max['diff']['after']['state'] == "present" - test_create_max['cloud_resource_type']['name'] == "Cisco Quantum Network Remix" - - test_create_max['cloud_resource_type']['manufacturer'] == provider['key'] + - test_create_max['cloud_resource_type']['provider'] == cisco_provider['key'] - test_create_max['cloud_resource_type']['description'] == "Very fast network reimagined!" - - test_create_max['cloud_resource_type']['content_types'] == ["cloud.cloudnetwork"] + - test_create_max['cloud_resource_type']['content_types'] == ["cloud.cloudnetwork"] + + - name: "5.1 - ASSERT" + assert: + that: + - cloud_resource_type['value']['config_schema']['my_config']['foo'] == "bar" + vars: + cloud_resource_type: "{{ lookup('networktocode.nautobot.lookup', 'cloud-resource-types', api_endpoint=nautobot_url, token=nautobot_token, api_filter='name=\"Cisco Quantum Network Remix\"') }}" - name: "6 - Duplicate create with all parameters" networktocode.nautobot.cloud_resource_type: url: "{{ nautobot_url }}" token: "{{ nautobot_token }}" name: Cisco Quantum Network Remix - manufacturer: Cisco + cloud_provider: Cisco description: Very fast network reimagined! content_types: - "cloud.cloudnetwork" From 9b7b41818ee0c97d8737b5a2faf24ca29fde0cf2 Mon Sep 17 00:00:00 2001 From: Travis Smith <141754521+tsm1th@users.noreply.github.com> Date: Fri, 1 Nov 2024 12:04:38 +0000 Subject: [PATCH 06/25] Undoing change to dev.env --- development/dev.env | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/development/dev.env b/development/dev.env index cde00465..79d49669 100644 --- a/development/dev.env +++ b/development/dev.env @@ -28,7 +28,4 @@ POSTGRES_PASSWORD=decinablesprewad POSTGRES_USER=nautobot # Needed for Redis should match the values for Nautobot above -REDIS_PASSWORD=decinablesprewad - -INVOKE_NAUTOBOT_ANSIBLE_PYTHON_VER: 3.11 -INVOKE_NAUTOBOT_ANSIBLE_NAUTOBOT_VER: 2.3 \ No newline at end of file +REDIS_PASSWORD=decinablesprewad \ No newline at end of file From 3c08ec2ddb560e13468ef7470bfcf72433cdb2fc Mon Sep 17 00:00:00 2001 From: Travis Smith <141754521+tsm1th@users.noreply.github.com> Date: Fri, 1 Nov 2024 12:09:46 +0000 Subject: [PATCH 07/25] Removing erroneous shebang --- plugins/module_utils/cloud.py | 1 - 1 file changed, 1 deletion(-) diff --git a/plugins/module_utils/cloud.py b/plugins/module_utils/cloud.py index 002c2750..bdb0e994 100644 --- a/plugins/module_utils/cloud.py +++ b/plugins/module_utils/cloud.py @@ -1,4 +1,3 @@ -#!/usr/bin/python # -*- coding: utf-8 -*- # Copyright: (c) 2024, Network to Code (@networktocode) # GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) From 14966ed304b4f0c12cbe11eec6c05bd7e7a3ad0d Mon Sep 17 00:00:00 2001 From: Travis Smith <141754521+tsm1th@users.noreply.github.com> Date: Sat, 2 Nov 2024 01:50:36 +0000 Subject: [PATCH 08/25] Added cloud account module and tests --- plugins/lookup/lookup.py | 1 + plugins/module_utils/cloud.py | 2 + plugins/module_utils/utils.py | 4 +- plugins/modules/cloud_account.py | 128 ++++++++++++++ .../targets/latest/tasks/cloud_account.yml | 156 ++++++++++++++++++ .../integration/targets/latest/tasks/main.yml | 11 +- 6 files changed, 300 insertions(+), 2 deletions(-) create mode 100644 plugins/modules/cloud_account.py create mode 100644 tests/integration/targets/latest/tasks/cloud_account.yml diff --git a/plugins/lookup/lookup.py b/plugins/lookup/lookup.py index e034fa0b..b26b39cf 100644 --- a/plugins/lookup/lookup.py +++ b/plugins/lookup/lookup.py @@ -173,6 +173,7 @@ def get_endpoint(nautobot, term): "circuits": {"endpoint": nautobot.circuits.circuits}, "circuit-providers": {"endpoint": nautobot.circuits.providers}, "cables": {"endpoint": nautobot.dcim.cables}, + "cloud-accounts": {"endpoint": nautobot.cloud.cloud_accounts}, "cloud-resource-types": {"endpoint": nautobot.cloud.cloud_resource_types}, "cluster-groups": {"endpoint": nautobot.virtualization.cluster_groups}, "cluster-types": {"endpoint": nautobot.virtualization.cluster_types}, diff --git a/plugins/module_utils/cloud.py b/plugins/module_utils/cloud.py index bdb0e994..a92768a3 100644 --- a/plugins/module_utils/cloud.py +++ b/plugins/module_utils/cloud.py @@ -12,6 +12,7 @@ ) NB_CLOUD_RESOURCE_TYPES = "cloud_resource_types" +NB_CLOUD_ACCOUNTS = "cloud_accounts" class NautobotCloudModule(NautobotModule): @@ -20,6 +21,7 @@ def run(self): This function should have all necessary code for endpoints within the application to create/update/delete the endpoint objects Supported endpoints: + - cloud_accounts - cloud_resource_types """ # Used to dynamically set key when returning results diff --git a/plugins/module_utils/utils.py b/plugins/module_utils/utils.py index e496f3b1..45dc155b 100644 --- a/plugins/module_utils/utils.py +++ b/plugins/module_utils/utils.py @@ -33,7 +33,7 @@ # Used to map endpoints to applications dynamically API_APPS_ENDPOINTS = dict( circuits=["circuits", "circuit_types", "circuit_terminations", "providers"], - cloud=["cloud_resource_types"], + cloud=["cloud_accounts", "cloud_resource_types"], dcim=[ "cables", "console_ports", @@ -232,6 +232,7 @@ "circuit_terminations": "circuit_termination", "circuit_types": "circuit_type", "circuits": "circuit", + "cloud_accounts": "cloud_account", "cloud_resource_types": "cloud_resource_type", "clusters": "cluster", "cluster_groups": "cluster_group", @@ -300,6 +301,7 @@ "circuit_type": set(["name"]), "circuit_termination": set(["circuit", "term_side"]), "circuits.circuittermination": set(["circuit", "term_side"]), + "cloud_account": set(["name"]), "cloud_resource_type": set(["name"]), "cluster": set(["name", "type"]), "cluster_group": set(["name"]), diff --git a/plugins/modules/cloud_account.py b/plugins/modules/cloud_account.py new file mode 100644 index 00000000..bac472de --- /dev/null +++ b/plugins/modules/cloud_account.py @@ -0,0 +1,128 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# Copyright: (c) 2024, Network to Code (@networktocode) +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + +DOCUMENTATION = r""" +--- +module: cloud_account +short_description: Creates or removes cloud_account from Nautobot +description: + - Creates or removes cloud_account from Nautobot +notes: + - Tags should be defined as a YAML list + - This should be ran with connection C(local) and hosts C(localhost) +author: + - Travis Smith (@tsm1th) +requirements: + - pynautobot +version_added: "5.4.0" +extends_documentation_fragment: + - networktocode.nautobot.fragments.base + - networktocode.nautobot.fragments.tags + - networktocode.nautobot.fragments.custom_fields +options: + name: + description: + - The name of the cloud_account + required: true + type: str + account_number: + description: + - Required if I(state=present) and the cloud_account does not exist yet + required: false + type: str + description: + description: + - The description of the cloud_account + required: false + type: str + cloud_provider: + aliases: + - provider + description: + - Required if I(state=present) and the cloud_account does not exist yet + required: false + type: raw + secrets_group: + description: + - The secrets group of the cloud_account + required: false + type: raw +""" + +EXAMPLES = r""" +--- +- name: Create a cloud_account + networktocode.nautobot.cloud_account: + url: http://nautobot.local + token: thisIsMyToken + name: Cisco Quantum Account + cloud_provider: Cisco + secrets_group: "{{ my_secrets_group['key'] }}" + state: present + vars: + my_secrets_group: "{{ lookup('networktocode.nautobot.lookup', 'secrets-groups', api_endpoint=nautobot_url, token=nautobot_token, api_filter='name=\"My Secrets Group\"') }}" + + state: present + +- name: Delete a cloud_account + networktocode.nautobot.cloud_account: + url: http://nautobot.local + token: thisIsMyToken + name: Cisco Quantum Account + state: absent +""" + +RETURN = r""" +cloud_account: + description: Serialized object as created or already existent within Nautobot + returned: success (when I(state=present)) + type: dict +msg: + description: Message indicating failure or info about what has been achieved + returned: always + type: str +""" + +from ansible_collections.networktocode.nautobot.plugins.module_utils.utils import ( + NAUTOBOT_ARG_SPEC, + TAGS_ARG_SPEC, + CUSTOM_FIELDS_ARG_SPEC, +) +from ansible_collections.networktocode.nautobot.plugins.module_utils.cloud import ( + NautobotCloudModule, + NB_CLOUD_ACCOUNTS, +) +from ansible.module_utils.basic import AnsibleModule +from copy import deepcopy + + +def main(): + """ + Main entry point for module execution + """ + argument_spec = deepcopy(NAUTOBOT_ARG_SPEC) + argument_spec.update(deepcopy(TAGS_ARG_SPEC)) + argument_spec.update(deepcopy(CUSTOM_FIELDS_ARG_SPEC)) + argument_spec.update( + dict( + name=dict(required=True, type="str"), + description=dict(required=False, type="str"), + account_number=dict(required=False, type="str"), + cloud_provider=dict(required=False, type="raw", aliases=["provider"]), + secrets_group=dict(required=False, type="raw"), + ) + ) + + module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True) + cloud_account = NautobotCloudModule(module, NB_CLOUD_ACCOUNTS) + cloud_account.run() + + +if __name__ == "__main__": # pragma: no cover + main() diff --git a/tests/integration/targets/latest/tasks/cloud_account.yml b/tests/integration/targets/latest/tasks/cloud_account.yml new file mode 100644 index 00000000..0fedbc65 --- /dev/null +++ b/tests/integration/targets/latest/tasks/cloud_account.yml @@ -0,0 +1,156 @@ +--- +## +## +### PYNAUTOBOT_CLOUD_ACCOUNT +## +## + +- name: "NAUTOBOT 2.3+ CLOUD ACCOUNTS TESTS" + when: + - "nautobot_version is version('2.3', '>=')" + block: + - set_fact: + cisco_provider: "{{ lookup('networktocode.nautobot.lookup', 'manufacturers', api_endpoint=nautobot_url, token=nautobot_token, api_filter='name=Cisco') }}" + secrets_group: "{{ lookup('networktocode.nautobot.lookup', 'secrets-groups', api_endpoint=nautobot_url, token=nautobot_token, api_filter='name=\"Test Secrets Group\"') }}" + + - name: "1 - Create cloud account within Nautobot with only required information" + networktocode.nautobot.cloud_account: + url: "{{ nautobot_url }}" + token: "{{ nautobot_token }}" + name: Cisco Quantum Account + cloud_provider: Cisco + account_number: "123456" + register: test_create_min + + - name: "1 - ASSERT" + assert: + that: + - test_create_min is changed + - test_create_min['diff']['before']['state'] == "absent" + - test_create_min['diff']['after']['state'] == "present" + - test_create_min['cloud_account']['name'] == "Cisco Quantum Account" + - test_create_min['msg'] == "cloud_account Cisco Quantum Account created" + + - name: "2 - Duplicate" + networktocode.nautobot.cloud_account: + url: "{{ nautobot_url }}" + token: "{{ nautobot_token }}" + name: Cisco Quantum Account + + register: test_create_idem + - name: "2 - ASSERT" + assert: + that: + - not test_create_idem['changed'] + - test_create_idem['msg'] == "cloud_account Cisco Quantum Account already exists" + - test_create_idem['cloud_account']['name'] == "Cisco Quantum Account" + + - name: "3 - Update cloud_account" + networktocode.nautobot.cloud_account: + url: "{{ nautobot_url }}" + token: "{{ nautobot_token }}" + name: Cisco Quantum Account + description: The rootest of all root accounts! + register: test_update + + - name: "3 - ASSERT" + assert: + that: + - test_update is changed + - test_update['diff']['before']['description'] == "" + - test_update['diff']['after']['description'] == "The rootest of all root accounts!" + + - name: "4 - Update idempotent" + networktocode.nautobot.cloud_account: + url: "{{ nautobot_url }}" + token: "{{ nautobot_token }}" + name: Cisco Quantum Account + description: The rootest of all root accounts! + register: test_update_idem + + - name: "4 - ASSERT" + assert: + that: + - not test_update_idem['changed'] + - test_update_idem['msg'] == "cloud_account Cisco Quantum Account already exists" + - test_update_idem['cloud_account']['name'] == "Cisco Quantum Account" + + - name: "5 - Create cloud_account with all parameters" + networktocode.nautobot.cloud_account: + url: "{{ nautobot_url }}" + token: "{{ nautobot_token }}" + name: Cisco Quantum Not So Root Account + cloud_provider: Cisco + description: Rooty but not the rootest! + account_number: "654321" + secrets_group: "{{ secrets_group['key'] }}" + register: test_create_max + + - name: "5 - ASSERT" + assert: + that: + - test_create_max is changed + - test_create_max['diff']['before']['state'] == "absent" + - test_create_max['diff']['after']['state'] == "present" + - test_create_max['cloud_account']['name'] == "Cisco Quantum Not So Root Account" + - test_create_max['cloud_account']['provider'] == cisco_provider['key'] + - test_create_max['cloud_account']['description'] == "Rooty but not the rootest!" + - test_create_max['cloud_account']['account_number'] == "654321" + - test_create_max['cloud_account']['secrets_group'] == secrets_group['key'] + + - name: "5.1 - ASSERT" + assert: + that: + - cloud_account['value']['name'] == "Cisco Quantum Not So Root Account" + vars: + cloud_account: "{{ lookup('networktocode.nautobot.lookup', 'cloud-accounts', api_endpoint=nautobot_url, token=nautobot_token, api_filter='name=\"Cisco Quantum Not So Root Account\"') }}" + + + - name: "6 - Duplicate create with all parameters" + networktocode.nautobot.cloud_account: + url: "{{ nautobot_url }}" + token: "{{ nautobot_token }}" + name: Cisco Quantum Not So Root Account + cloud_provider: Cisco + description: Rooty but not the rootest! + account_number: "654321" + secrets_group: "{{ secrets_group['key'] }}" + register: test_create_max_idem + + - name: "6 - ASSERT" + assert: + that: + - not test_create_max_idem['changed'] + - test_create_max_idem['msg'] == "cloud_account Cisco Quantum Not So Root Account already exists" + - test_create_max_idem['cloud_account']['name'] == "Cisco Quantum Not So Root Account" + + - name: "7 - Delete cloud_account" + networktocode.nautobot.cloud_account: + url: "{{ nautobot_url }}" + token: "{{ nautobot_token }}" + name: Cisco Quantum Account + state: absent + register: test_delete + + - name: "7 - ASSERT" + assert: + that: + - test_delete is changed + - test_delete['diff']['before']['state'] == "present" + - test_delete['diff']['after']['state'] == "absent" + - test_delete['cloud_account']['name'] == "Cisco Quantum Account" + - "'deleted' in test_delete['msg']" + + - name: "8 - Delete idempotent" + networktocode.nautobot.cloud_account: + url: "{{ nautobot_url }}" + token: "{{ nautobot_token }}" + name: Cisco Quantum Account + state: absent + register: test_delete_idem + + - name: "8 - ASSERT" + assert: + that: + - not test_delete_idem['changed'] + - "'already absent' in test_delete_idem['msg']" \ No newline at end of file diff --git a/tests/integration/targets/latest/tasks/main.yml b/tests/integration/targets/latest/tasks/main.yml index 58831acb..b7e36b30 100644 --- a/tests/integration/targets/latest/tasks/main.yml +++ b/tests/integration/targets/latest/tasks/main.yml @@ -598,4 +598,13 @@ tags: - cloud_resource_type tags: - - cloud_resource_type \ No newline at end of file + - cloud_resource_type + +- name: "PYNAUTOBOT_CLOUD_ACCOUNT TESTS" + include_tasks: + file: "cloud_account.yml" + apply: + tags: + - cloud_account + tags: + - cloud_account \ No newline at end of file From 16bb47a82de62a6359adc8ac7dab18640322b306 Mon Sep 17 00:00:00 2001 From: Travis Smith <141754521+tsm1th@users.noreply.github.com> Date: Sat, 2 Nov 2024 02:00:22 +0000 Subject: [PATCH 09/25] Fixed examples --- plugins/modules/cloud_account.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/modules/cloud_account.py b/plugins/modules/cloud_account.py index bac472de..6dbeead7 100644 --- a/plugins/modules/cloud_account.py +++ b/plugins/modules/cloud_account.py @@ -63,13 +63,13 @@ token: thisIsMyToken name: Cisco Quantum Account cloud_provider: Cisco + description: A quantum account for Cisco + account_number: "654321" secrets_group: "{{ my_secrets_group['key'] }}" state: present vars: my_secrets_group: "{{ lookup('networktocode.nautobot.lookup', 'secrets-groups', api_endpoint=nautobot_url, token=nautobot_token, api_filter='name=\"My Secrets Group\"') }}" - state: present - - name: Delete a cloud_account networktocode.nautobot.cloud_account: url: http://nautobot.local From 12040fb461633a2d34faca2ec9f95f00ba1e2534 Mon Sep 17 00:00:00 2001 From: Travis Smith <141754521+tsm1th@users.noreply.github.com> Date: Sat, 2 Nov 2024 02:26:37 +0000 Subject: [PATCH 10/25] Added no_log to secret_group --- plugins/module_utils/cloud.py | 3 ++- plugins/modules/cloud_account.py | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/plugins/module_utils/cloud.py b/plugins/module_utils/cloud.py index a92768a3..2ddd0a1e 100644 --- a/plugins/module_utils/cloud.py +++ b/plugins/module_utils/cloud.py @@ -11,8 +11,9 @@ ENDPOINT_NAME_MAPPING, ) -NB_CLOUD_RESOURCE_TYPES = "cloud_resource_types" + NB_CLOUD_ACCOUNTS = "cloud_accounts" +NB_CLOUD_RESOURCE_TYPES = "cloud_resource_types" class NautobotCloudModule(NautobotModule): diff --git a/plugins/modules/cloud_account.py b/plugins/modules/cloud_account.py index 6dbeead7..8d3deafa 100644 --- a/plugins/modules/cloud_account.py +++ b/plugins/modules/cloud_account.py @@ -115,7 +115,7 @@ def main(): description=dict(required=False, type="str"), account_number=dict(required=False, type="str"), cloud_provider=dict(required=False, type="raw", aliases=["provider"]), - secrets_group=dict(required=False, type="raw"), + secrets_group=dict(required=False, type="raw", no_log=True), ) ) From 9e2e774dab09bec6db04cf5f44477aa53f4a5f2a Mon Sep 17 00:00:00 2001 From: Travis Smith <141754521+tsm1th@users.noreply.github.com> Date: Sat, 2 Nov 2024 03:40:10 +0000 Subject: [PATCH 11/25] Added cloud service module and tests --- plugins/lookup/lookup.py | 1 + plugins/module_utils/cloud.py | 3 +- plugins/module_utils/utils.py | 6 +- plugins/modules/cloud_service.py | 124 ++++++++++++++ tests/integration/nautobot-populate.py | 23 +++ .../targets/latest/tasks/cloud_service.yml | 160 ++++++++++++++++++ .../integration/targets/latest/tasks/main.yml | 11 +- 7 files changed, 325 insertions(+), 3 deletions(-) create mode 100644 plugins/modules/cloud_service.py create mode 100644 tests/integration/targets/latest/tasks/cloud_service.yml diff --git a/plugins/lookup/lookup.py b/plugins/lookup/lookup.py index b26b39cf..c834d289 100644 --- a/plugins/lookup/lookup.py +++ b/plugins/lookup/lookup.py @@ -175,6 +175,7 @@ def get_endpoint(nautobot, term): "cables": {"endpoint": nautobot.dcim.cables}, "cloud-accounts": {"endpoint": nautobot.cloud.cloud_accounts}, "cloud-resource-types": {"endpoint": nautobot.cloud.cloud_resource_types}, + "cloud-services": {"endpoint": nautobot.cloud.cloud_services}, "cluster-groups": {"endpoint": nautobot.virtualization.cluster_groups}, "cluster-types": {"endpoint": nautobot.virtualization.cluster_types}, "clusters": {"endpoint": nautobot.virtualization.clusters}, diff --git a/plugins/module_utils/cloud.py b/plugins/module_utils/cloud.py index 2ddd0a1e..a3751562 100644 --- a/plugins/module_utils/cloud.py +++ b/plugins/module_utils/cloud.py @@ -11,7 +11,7 @@ ENDPOINT_NAME_MAPPING, ) - +NB_CLOUD_SERVICES = "cloud_services" NB_CLOUD_ACCOUNTS = "cloud_accounts" NB_CLOUD_RESOURCE_TYPES = "cloud_resource_types" @@ -22,6 +22,7 @@ def run(self): This function should have all necessary code for endpoints within the application to create/update/delete the endpoint objects Supported endpoints: + - cloud_services - cloud_accounts - cloud_resource_types """ diff --git a/plugins/module_utils/utils.py b/plugins/module_utils/utils.py index 45dc155b..94893a09 100644 --- a/plugins/module_utils/utils.py +++ b/plugins/module_utils/utils.py @@ -33,7 +33,7 @@ # Used to map endpoints to applications dynamically API_APPS_ENDPOINTS = dict( circuits=["circuits", "circuit_types", "circuit_terminations", "providers"], - cloud=["cloud_accounts", "cloud_resource_types"], + cloud=["cloud_accounts", "cloud_resource_types", "cloud_services"], dcim=[ "cables", "console_ports", @@ -157,7 +157,9 @@ "circuit_type": "circuit_types", "circuit_termination": "circuit_terminations", "circuits.circuittermination": "circuit_terminations", + "cloud_account": "cloud_accounts", "cloud_provider": "manufacturers", + "cloud_resource_type": "cloud_resource_types", "cluster": "clusters", "cluster_group": "cluster_groups", "cluster_type": "cluster_types", @@ -234,6 +236,7 @@ "circuits": "circuit", "cloud_accounts": "cloud_account", "cloud_resource_types": "cloud_resource_type", + "cloud_services": "cloud_service", "clusters": "cluster", "cluster_groups": "cluster_group", "cluster_types": "cluster_type", @@ -303,6 +306,7 @@ "circuits.circuittermination": set(["circuit", "term_side"]), "cloud_account": set(["name"]), "cloud_resource_type": set(["name"]), + "cloud_service": set(["name"]), "cluster": set(["name", "type"]), "cluster_group": set(["name"]), "cluster_type": set(["name"]), diff --git a/plugins/modules/cloud_service.py b/plugins/modules/cloud_service.py new file mode 100644 index 00000000..5e01bdee --- /dev/null +++ b/plugins/modules/cloud_service.py @@ -0,0 +1,124 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# Copyright: (c) 2024, Network to Code (@networktocode) +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + +DOCUMENTATION = r""" +--- +module: cloud_service +short_description: Creates or removes cloud_service from Nautobot +description: + - Creates or removes cloud_service from Nautobot +notes: + - Tags should be defined as a YAML list + - This should be ran with connection C(local) and hosts C(localhost) +author: + - Travis Smith (@tsm1th) +requirements: + - pynautobot +version_added: "5.4.0" +extends_documentation_fragment: + - networktocode.nautobot.fragments.base + - networktocode.nautobot.fragments.tags + - networktocode.nautobot.fragments.custom_fields +options: + name: + description: + - The name of the cloud_service + required: true + type: str + description: + description: + - The description of the cloud_service + required: false + type: str + cloud_resource_type: + description: + - Required if I(state=present) and the cloud_service does not exist yet + required: false + type: raw + cloud_account: + description: + - A cloud account for this service. + required: false + type: raw + cloud_networks: + description: + - A list of cloud networks for this service. + required: false + type: list + elements: raw +""" + +EXAMPLES = r""" +--- +- name: Create a cloud_service + networktocode.nautobot.cloud_service: + url: http://nautobot.local + token: thisIsMyToken + name: Cisco Quantum Service + cloud_resource_type: Cisco Quantum Type + cloud_account: Cisco Quantum Type + description: A quantum service for Cisco + state: present + +- name: Delete a cloud_service + networktocode.nautobot.cloud_service: + url: http://nautobot.local + token: thisIsMyToken + name: Cisco Quantum Service + state: absent +""" + +RETURN = r""" +cloud_service: + description: Serialized object as created or already existent within Nautobot + returned: success (when I(state=present)) + type: dict +msg: + description: Message indicating failure or info about what has been achieved + returned: always + type: str +""" + +from ansible_collections.networktocode.nautobot.plugins.module_utils.utils import ( + NAUTOBOT_ARG_SPEC, + TAGS_ARG_SPEC, + CUSTOM_FIELDS_ARG_SPEC, +) +from ansible_collections.networktocode.nautobot.plugins.module_utils.cloud import ( + NautobotCloudModule, + NB_CLOUD_SERVICES, +) +from ansible.module_utils.basic import AnsibleModule +from copy import deepcopy + + +def main(): + """ + Main entry point for module execution + """ + argument_spec = deepcopy(NAUTOBOT_ARG_SPEC) + argument_spec.update(deepcopy(TAGS_ARG_SPEC)) + argument_spec.update(deepcopy(CUSTOM_FIELDS_ARG_SPEC)) + argument_spec.update( + dict( + name=dict(required=True, type="str"), + description=dict(required=False, type="str"), + cloud_resource_type=dict(required=False, type="raw"), + cloud_account=dict(required=False, type="raw"), + cloud_networks=dict(required=False, type="list", elements="raw"), + ) + ) + + module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True) + cloud_service = NautobotCloudModule(module, NB_CLOUD_SERVICES) + cloud_service.run() + + +if __name__ == "__main__": # pragma: no cover + main() diff --git a/tests/integration/nautobot-populate.py b/tests/integration/nautobot-populate.py index 51efed61..d5ed6d5c 100755 --- a/tests/integration/nautobot-populate.py +++ b/tests/integration/nautobot-populate.py @@ -642,5 +642,28 @@ def make_nautobot_calls(endpoint, payload): ] created_vm_interface_roles = make_nautobot_calls(nb.extras.roles, vm_interface_roles) + cloud_resource_types = [ + {"name": "CiscoCloudServiceType", "provider": "Cisco", "content_types": ["cloud.cloudservice"]}, + {"name": "CiscoCloudNetworkType", "provider": "Cisco", "content_types": ["cloud.cloudnetwork"]}, + ] + created_cloud_resource_types = make_nautobot_calls(nb.cloud.cloud_resource_types, cloud_resource_types) + + cloud_accounts = [ + {"name": "CiscoCloudAccount", "provider": "Cisco", "account_number": "424242"} + ] + created_cloud_accounts = make_nautobot_calls(nb.cloud.cloud_accounts, cloud_accounts) + + cloud_services = [ + {"name": "CiscoCloudService", "cloud_resource_type": "CiscoCloudServiceType", "cloud_account": "CiscoCloudAccount"} + ] + created_cloud_services = make_nautobot_calls(nb.cloud.cloud_services, cloud_services) + + cloud_networks = [ + {"name": "CiscoCloudNetwork", "cloud_resource_type": "CiscoCloudNetworkType", "cloud_account": "CiscoCloudAccount"}, + {"name": "CiscoCloudNetworkTwo", "cloud_resource_type": "CiscoCloudNetworkType", "cloud_account": "CiscoCloudAccount"} + ] + created_cloud_networks = make_nautobot_calls(nb.cloud.cloud_networks, cloud_networks) + + if ERRORS: sys.exit("Errors have occurred when creating objects, and should have been printed out. Check previous output.") diff --git a/tests/integration/targets/latest/tasks/cloud_service.yml b/tests/integration/targets/latest/tasks/cloud_service.yml new file mode 100644 index 00000000..47d66c0b --- /dev/null +++ b/tests/integration/targets/latest/tasks/cloud_service.yml @@ -0,0 +1,160 @@ +--- +## +## +### PYNAUTOBOT_CLOUD_SERVICE +## +## + +- name: "NAUTOBOT 2.3+ CLOUD SERVICES TESTS" + when: + - "nautobot_version is version('2.3', '>=')" + block: + - set_fact: + cloud_resource_type: "{{ lookup('networktocode.nautobot.lookup', 'cloud-resource-types', api_endpoint=nautobot_url, token=nautobot_token, api_filter='name=CiscoCloudServiceType') }}" + cloud_account: "{{ lookup('networktocode.nautobot.lookup', 'cloud-accounts', api_endpoint=nautobot_url, token=nautobot_token, api_filter='name=CiscoCloudAccount') }}" + #cloud_network: "{{ lookup('networktocode.nautobot.lookup', 'cloud-networks', api_endpoint=nautobot_url, token=nautobot_token, api_filter='name=CiscoCloudNetwork') }}" + + - name: "1 - Create cloud service within Nautobot with only required information" + networktocode.nautobot.cloud_service: + url: "{{ nautobot_url }}" + token: "{{ nautobot_token }}" + name: Cisco Quantum Service + cloud_resource_type: CiscoCloudServiceType + register: test_create_min + + - name: "1 - ASSERT" + assert: + that: + - test_create_min is changed + - test_create_min['diff']['before']['state'] == "absent" + - test_create_min['diff']['after']['state'] == "present" + - test_create_min['cloud_service']['name'] == "Cisco Quantum Service" + - test_create_min['msg'] == "cloud_service Cisco Quantum Service created" + + - name: "2 - Duplicate" + networktocode.nautobot.cloud_service: + url: "{{ nautobot_url }}" + token: "{{ nautobot_token }}" + name: Cisco Quantum Service + + register: test_create_idem + - name: "2 - ASSERT" + assert: + that: + - not test_create_idem['changed'] + - test_create_idem['msg'] == "cloud_service Cisco Quantum Service already exists" + - test_create_idem['cloud_service']['name'] == "Cisco Quantum Service" + + - name: "3 - Update cloud_service" + networktocode.nautobot.cloud_service: + url: "{{ nautobot_url }}" + token: "{{ nautobot_token }}" + name: Cisco Quantum Service + description: Super secret quantum service! + register: test_update + + - name: "3 - ASSERT" + assert: + that: + - test_update is changed + - test_update['diff']['before']['description'] == "" + - test_update['diff']['after']['description'] == "Super secret quantum service!" + + - name: "4 - Update idempotent" + networktocode.nautobot.cloud_service: + url: "{{ nautobot_url }}" + token: "{{ nautobot_token }}" + name: Cisco Quantum Service + description: Super secret quantum service! + register: test_update_idem + + - name: "4 - ASSERT" + assert: + that: + - not test_update_idem['changed'] + - test_update_idem['msg'] == "cloud_service Cisco Quantum Service already exists" + - test_update_idem['cloud_service']['name'] == "Cisco Quantum Service" + + - name: "5 - Create cloud_service with all parameters" + networktocode.nautobot.cloud_service: + url: "{{ nautobot_url }}" + token: "{{ nautobot_token }}" + name: Cisco Quantum Secreter Service + cloud_resource_type: CiscoCloudServiceType + cloud_account: CiscoCloudAccount + #cloud_network: + # - CiscoCloudNetwork + # - CiscoCloudNetworkTwo + description: Super secreter quantum service! + register: test_create_max + + - name: "5 - ASSERT" + assert: + that: + - test_create_max is changed + - test_create_max['diff']['before']['state'] == "absent" + - test_create_max['diff']['after']['state'] == "present" + - test_create_max['cloud_service']['name'] == "Cisco Quantum Secreter Service" + - test_create_max['cloud_service']['cloud_resource_type'] == cloud_resource_type['key'] + - test_create_max['cloud_service']['cloud_account'] == cloud_account['key'] + - test_create_max['cloud_service']['description'] == "Super secreter quantum service!" + #- test_create_max['cloud_service']['cloud_network'] == "654321" + + - name: "5.1 - ASSERT" + assert: + that: + - cloud_service['value']['name'] == "Cisco Quantum Secreter Service" + vars: + cloud_service: "{{ lookup('networktocode.nautobot.lookup', 'cloud-services', api_endpoint=nautobot_url, token=nautobot_token, api_filter='name=\"Cisco Quantum Secreter Service\"') }}" + + + - name: "6 - Duplicate create with all parameters" + networktocode.nautobot.cloud_service: + url: "{{ nautobot_url }}" + token: "{{ nautobot_token }}" + name: Cisco Quantum Secreter Service + cloud_resource_type: CiscoCloudServiceType + cloud_account: CiscoCloudAccount + #cloud_network: + # - CiscoCloudNetwork + # - CiscoCloudNetworkTwo + description: Super secreter quantum service! + register: test_create_max_idem + + - name: "6 - ASSERT" + assert: + that: + - not test_create_max_idem['changed'] + - test_create_max_idem['msg'] == "cloud_service Cisco Quantum Secreter Service already exists" + - test_create_max_idem['cloud_service']['name'] == "Cisco Quantum Secreter Service" + + - name: "7 - Delete cloud_service" + networktocode.nautobot.cloud_service: + url: "{{ nautobot_url }}" + token: "{{ nautobot_token }}" + name: Cisco Quantum Secreter Service + state: absent + register: test_delete + + - name: "7 - ASSERT" + assert: + that: + - test_delete is changed + - test_delete['diff']['before']['state'] == "present" + - test_delete['diff']['after']['state'] == "absent" + - test_delete['cloud_service']['name'] == "Cisco Quantum Secreter Service" + - "'deleted' in test_delete['msg']" + + - name: "8 - Delete idempotent" + networktocode.nautobot.cloud_service: + url: "{{ nautobot_url }}" + token: "{{ nautobot_token }}" + name: Cisco Quantum Secreter Service + state: absent + register: test_delete_idem + + - name: "8 - ASSERT" + assert: + that: + - not test_delete_idem['changed'] + - "'already absent' in test_delete_idem['msg']" \ No newline at end of file diff --git a/tests/integration/targets/latest/tasks/main.yml b/tests/integration/targets/latest/tasks/main.yml index b7e36b30..2daaa556 100644 --- a/tests/integration/targets/latest/tasks/main.yml +++ b/tests/integration/targets/latest/tasks/main.yml @@ -607,4 +607,13 @@ tags: - cloud_account tags: - - cloud_account \ No newline at end of file + - cloud_account + +- name: "PYNAUTOBOT_CLOUD_SERVICE TESTS" + include_tasks: + file: "cloud_service.yml" + apply: + tags: + - cloud_service + tags: + - cloud_service \ No newline at end of file From 02d2f011618987e31d449dc50405998fcbee70e0 Mon Sep 17 00:00:00 2001 From: Travis Smith <141754521+tsm1th@users.noreply.github.com> Date: Sat, 2 Nov 2024 04:54:12 +0000 Subject: [PATCH 12/25] Added cloud network and tests, fixed invalid fields in cloud service --- plugins/lookup/lookup.py | 1 + plugins/module_utils/cloud.py | 2 + plugins/module_utils/utils.py | 9 +- plugins/modules/cloud_network.py | 125 ++++++++++++++ plugins/modules/cloud_service.py | 9 +- tests/integration/nautobot-populate.py | 3 +- .../targets/latest/tasks/cloud_network.yml | 157 ++++++++++++++++++ .../targets/latest/tasks/cloud_service.yml | 8 - .../integration/targets/latest/tasks/main.yml | 25 ++- 9 files changed, 312 insertions(+), 27 deletions(-) create mode 100644 plugins/modules/cloud_network.py create mode 100644 tests/integration/targets/latest/tasks/cloud_network.yml diff --git a/plugins/lookup/lookup.py b/plugins/lookup/lookup.py index c834d289..4e1347cb 100644 --- a/plugins/lookup/lookup.py +++ b/plugins/lookup/lookup.py @@ -174,6 +174,7 @@ def get_endpoint(nautobot, term): "circuit-providers": {"endpoint": nautobot.circuits.providers}, "cables": {"endpoint": nautobot.dcim.cables}, "cloud-accounts": {"endpoint": nautobot.cloud.cloud_accounts}, + "cloud-networks": {"endpoint": nautobot.cloud.cloud_networks}, "cloud-resource-types": {"endpoint": nautobot.cloud.cloud_resource_types}, "cloud-services": {"endpoint": nautobot.cloud.cloud_services}, "cluster-groups": {"endpoint": nautobot.virtualization.cluster_groups}, diff --git a/plugins/module_utils/cloud.py b/plugins/module_utils/cloud.py index a3751562..440b230f 100644 --- a/plugins/module_utils/cloud.py +++ b/plugins/module_utils/cloud.py @@ -12,6 +12,7 @@ ) NB_CLOUD_SERVICES = "cloud_services" +NB_CLOUD_NETWORKS = "cloud_networks" NB_CLOUD_ACCOUNTS = "cloud_accounts" NB_CLOUD_RESOURCE_TYPES = "cloud_resource_types" @@ -23,6 +24,7 @@ def run(self): to create/update/delete the endpoint objects Supported endpoints: - cloud_services + - cloud_networks - cloud_accounts - cloud_resource_types """ diff --git a/plugins/module_utils/utils.py b/plugins/module_utils/utils.py index 94893a09..ce8e7585 100644 --- a/plugins/module_utils/utils.py +++ b/plugins/module_utils/utils.py @@ -33,7 +33,7 @@ # Used to map endpoints to applications dynamically API_APPS_ENDPOINTS = dict( circuits=["circuits", "circuit_types", "circuit_terminations", "providers"], - cloud=["cloud_accounts", "cloud_resource_types", "cloud_services"], + cloud=["cloud_accounts", "cloud_networks", "cloud_resource_types", "cloud_services"], dcim=[ "cables", "console_ports", @@ -121,6 +121,7 @@ master="name", nat_inside="address", nat_outside="address", + parent_cloud_network="name", parent_location="name", parent_location_type="name", parent_rack_group="name", @@ -160,6 +161,8 @@ "cloud_account": "cloud_accounts", "cloud_provider": "manufacturers", "cloud_resource_type": "cloud_resource_types", + "cloud_network": "cloud_networks", + "cloud_service": "cloud_services", "cluster": "clusters", "cluster_group": "cluster_groups", "cluster_type": "cluster_types", @@ -193,6 +196,7 @@ "namespace": "namespaces", "platform": "platforms", "parent_rack_group": "rack_groups", + "parent_cloud_network": "cloud_networks", "parent_location": "locations", "parent_location_type": "location_types", "parent_tenant_group": "tenant_groups", @@ -235,6 +239,7 @@ "circuit_types": "circuit_type", "circuits": "circuit", "cloud_accounts": "cloud_account", + "cloud_networks": "cloud_network", "cloud_resource_types": "cloud_resource_type", "cloud_services": "cloud_service", "clusters": "cluster", @@ -305,6 +310,7 @@ "circuit_termination": set(["circuit", "term_side"]), "circuits.circuittermination": set(["circuit", "term_side"]), "cloud_account": set(["name"]), + "cloud_network": set(["name"]), "cloud_resource_type": set(["name"]), "cloud_service": set(["name"]), "cluster": set(["name", "type"]), @@ -443,6 +449,7 @@ # This is used to map non-clashing keys to Nautobot API compliant keys to prevent bad logic in code for similar keys but different modules CONVERT_KEYS = { "cloud_provider": "provider", + "parent_cloud_network": "parent", "parent_rack_group": "parent", "parent_location": "parent", "parent_location_type": "parent", diff --git a/plugins/modules/cloud_network.py b/plugins/modules/cloud_network.py new file mode 100644 index 00000000..01c7e08a --- /dev/null +++ b/plugins/modules/cloud_network.py @@ -0,0 +1,125 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# Copyright: (c) 2024, Network to Code (@networktocode) +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + +DOCUMENTATION = r""" +--- +module: cloud_network +short_description: Creates or removes cloud_network from Nautobot +description: + - Creates or removes cloud_network from Nautobot +notes: + - Tags should be defined as a YAML list + - This should be ran with connection C(local) and hosts C(localhost) +author: + - Travis Smith (@tsm1th) +requirements: + - pynautobot +version_added: "5.4.0" +extends_documentation_fragment: + - networktocode.nautobot.fragments.base + - networktocode.nautobot.fragments.tags + - networktocode.nautobot.fragments.custom_fields +options: + name: + description: + - The name of the cloud_network + required: true + type: str + description: + description: + - The description of the cloud_network + required: false + type: str + cloud_resource_type: + description: + - Required if I(state=present) and the cloud_network does not exist yet + required: false + type: raw + cloud_account: + description: + - Required if I(state=present) and the cloud_network does not exist yet + required: false + type: raw + parent_cloud_network: + aliases: + - parent + description: + - The parent cloud network this network should be child to + required: false + type: raw +""" + +EXAMPLES = r""" +--- +- name: Create a cloud_network + networktocode.nautobot.cloud_network: + url: http://nautobot.local + token: thisIsMyToken + name: Cisco Quantum Network + cloud_resource_type: Cisco Quantum Type + cloud_account: Cisco Quantum Account + description: A quantum network for Cisco + state: present + +- name: Delete a cloud_network + networktocode.nautobot.cloud_network: + url: http://nautobot.local + token: thisIsMyToken + name: Cisco Quantum Network + state: absent +""" + +RETURN = r""" +cloud_network: + description: Serialized object as created or already existent within Nautobot + returned: success (when I(state=present)) + type: dict +msg: + description: Message indicating failure or info about what has been achieved + returned: always + type: str +""" + +from ansible_collections.networktocode.nautobot.plugins.module_utils.utils import ( + NAUTOBOT_ARG_SPEC, + TAGS_ARG_SPEC, + CUSTOM_FIELDS_ARG_SPEC, +) +from ansible_collections.networktocode.nautobot.plugins.module_utils.cloud import ( + NautobotCloudModule, + NB_CLOUD_NETWORKS, +) +from ansible.module_utils.basic import AnsibleModule +from copy import deepcopy + + +def main(): + """ + Main entry point for module execution + """ + argument_spec = deepcopy(NAUTOBOT_ARG_SPEC) + argument_spec.update(deepcopy(TAGS_ARG_SPEC)) + argument_spec.update(deepcopy(CUSTOM_FIELDS_ARG_SPEC)) + argument_spec.update( + dict( + name=dict(required=True, type="str"), + description=dict(required=False, type="str"), + cloud_resource_type=dict(required=False, type="raw"), + cloud_account=dict(required=False, type="raw"), + parent_cloud_network=dict(required=False, type="raw", aliases=["parent"]), + ) + ) + + module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True) + cloud_network = NautobotCloudModule(module, NB_CLOUD_NETWORKS) + cloud_network.run() + + +if __name__ == "__main__": # pragma: no cover + main() diff --git a/plugins/modules/cloud_service.py b/plugins/modules/cloud_service.py index 5e01bdee..b24d4ed1 100644 --- a/plugins/modules/cloud_service.py +++ b/plugins/modules/cloud_service.py @@ -46,12 +46,6 @@ - A cloud account for this service. required: false type: raw - cloud_networks: - description: - - A list of cloud networks for this service. - required: false - type: list - elements: raw """ EXAMPLES = r""" @@ -62,7 +56,7 @@ token: thisIsMyToken name: Cisco Quantum Service cloud_resource_type: Cisco Quantum Type - cloud_account: Cisco Quantum Type + cloud_account: Cisco Quantum Account description: A quantum service for Cisco state: present @@ -111,7 +105,6 @@ def main(): description=dict(required=False, type="str"), cloud_resource_type=dict(required=False, type="raw"), cloud_account=dict(required=False, type="raw"), - cloud_networks=dict(required=False, type="list", elements="raw"), ) ) diff --git a/tests/integration/nautobot-populate.py b/tests/integration/nautobot-populate.py index d5ed6d5c..1cd0cdc3 100755 --- a/tests/integration/nautobot-populate.py +++ b/tests/integration/nautobot-populate.py @@ -659,8 +659,7 @@ def make_nautobot_calls(endpoint, payload): created_cloud_services = make_nautobot_calls(nb.cloud.cloud_services, cloud_services) cloud_networks = [ - {"name": "CiscoCloudNetwork", "cloud_resource_type": "CiscoCloudNetworkType", "cloud_account": "CiscoCloudAccount"}, - {"name": "CiscoCloudNetworkTwo", "cloud_resource_type": "CiscoCloudNetworkType", "cloud_account": "CiscoCloudAccount"} + {"name": "CiscoCloudNetwork", "cloud_resource_type": "CiscoCloudNetworkType", "cloud_account": "CiscoCloudAccount"} ] created_cloud_networks = make_nautobot_calls(nb.cloud.cloud_networks, cloud_networks) diff --git a/tests/integration/targets/latest/tasks/cloud_network.yml b/tests/integration/targets/latest/tasks/cloud_network.yml new file mode 100644 index 00000000..6b898720 --- /dev/null +++ b/tests/integration/targets/latest/tasks/cloud_network.yml @@ -0,0 +1,157 @@ +--- +## +## +### PYNAUTOBOT_CLOUD_NETWORK +## +## + +- name: "NAUTOBOT 2.3+ CLOUD NETWORKS TESTS" + when: + - "nautobot_version is version('2.3', '>=')" + block: + - set_fact: + cloud_resource_type: "{{ lookup('networktocode.nautobot.lookup', 'cloud-resource-types', api_endpoint=nautobot_url, token=nautobot_token, api_filter='name=CiscoCloudNetworkType') }}" + cloud_account: "{{ lookup('networktocode.nautobot.lookup', 'cloud-accounts', api_endpoint=nautobot_url, token=nautobot_token, api_filter='name=CiscoCloudAccount') }}" + cloud_network: "{{ lookup('networktocode.nautobot.lookup', 'cloud-networks', api_endpoint=nautobot_url, token=nautobot_token, api_filter='name=CiscoCloudNetwork') }}" + + - name: "1 - Create cloud network within Nautobot with only required information" + networktocode.nautobot.cloud_network: + url: "{{ nautobot_url }}" + token: "{{ nautobot_token }}" + name: Cisco Quantum Network + cloud_resource_type: CiscoCloudNetworkType + cloud_account: CiscoCloudAccount + register: test_create_min + + - name: "1 - ASSERT" + assert: + that: + - test_create_min is changed + - test_create_min['diff']['before']['state'] == "absent" + - test_create_min['diff']['after']['state'] == "present" + - test_create_min['cloud_network']['name'] == "Cisco Quantum Network" + - test_create_min['msg'] == "cloud_network Cisco Quantum Network created" + + - name: "2 - Duplicate" + networktocode.nautobot.cloud_network: + url: "{{ nautobot_url }}" + token: "{{ nautobot_token }}" + name: Cisco Quantum Network + + register: test_create_idem + - name: "2 - ASSERT" + assert: + that: + - not test_create_idem['changed'] + - test_create_idem['msg'] == "cloud_network Cisco Quantum Network already exists" + - test_create_idem['cloud_network']['name'] == "Cisco Quantum Network" + + - name: "3 - Update cloud_network" + networktocode.nautobot.cloud_network: + url: "{{ nautobot_url }}" + token: "{{ nautobot_token }}" + name: Cisco Quantum Network + description: Super fast quantum network! + register: test_update + + - name: "3 - ASSERT" + assert: + that: + - test_update is changed + - test_update['diff']['before']['description'] == "" + - test_update['diff']['after']['description'] == "Super fast quantum network!" + + - name: "4 - Update idempotent" + networktocode.nautobot.cloud_network: + url: "{{ nautobot_url }}" + token: "{{ nautobot_token }}" + name: Cisco Quantum Network + description: Super fast quantum network! + register: test_update_idem + + - name: "4 - ASSERT" + assert: + that: + - not test_update_idem['changed'] + - test_update_idem['msg'] == "cloud_network Cisco Quantum Network already exists" + - test_update_idem['cloud_network']['name'] == "Cisco Quantum Network" + + - name: "5 - Create cloud_network with all parameters" + networktocode.nautobot.cloud_network: + url: "{{ nautobot_url }}" + token: "{{ nautobot_token }}" + name: Cisco Quantum Faster Network + cloud_resource_type: CiscoCloudNetworkType + cloud_account: CiscoCloudAccount + parent_cloud_network: CiscoCloudNetwork + description: Super faster quantum network! + register: test_create_max + + - name: "5 - ASSERT" + assert: + that: + - test_create_max is changed + - test_create_max['diff']['before']['state'] == "absent" + - test_create_max['diff']['after']['state'] == "present" + - test_create_max['cloud_network']['name'] == "Cisco Quantum Faster Network" + - test_create_max['cloud_network']['cloud_resource_type'] == cloud_resource_type['key'] + - test_create_max['cloud_network']['cloud_account'] == cloud_account['key'] + - test_create_max['cloud_network']['description'] == "Super faster quantum network!" + - test_create_max['cloud_network']['parent'] == cloud_network['key'] + + - name: "5.1 - ASSERT" + assert: + that: + - new_cloud_network['value']['name'] == "Cisco Quantum Faster Network" + vars: + new_cloud_network: "{{ lookup('networktocode.nautobot.lookup', 'cloud-networks', api_endpoint=nautobot_url, token=nautobot_token, api_filter='name=\"Cisco Quantum Faster Network\"') }}" + + + - name: "6 - Duplicate create with all parameters" + networktocode.nautobot.cloud_network: + url: "{{ nautobot_url }}" + token: "{{ nautobot_token }}" + name: Cisco Quantum Faster Network + cloud_resource_type: CiscoCloudNetworkType + cloud_account: CiscoCloudAccount + parent_cloud_network: CiscoCloudNetwork + description: Super faster quantum network! + register: test_create_max_idem + + - name: "6 - ASSERT" + assert: + that: + - not test_create_max_idem['changed'] + - test_create_max_idem['msg'] == "cloud_network Cisco Quantum Faster Network already exists" + - test_create_max_idem['cloud_network']['name'] == "Cisco Quantum Faster Network" + + - name: "7 - Delete cloud_network" + networktocode.nautobot.cloud_network: + url: "{{ nautobot_url }}" + token: "{{ nautobot_token }}" + name: Cisco Quantum Faster Network + state: absent + register: test_delete + + - name: "7 - ASSERT" + assert: + that: + - test_delete is changed + - test_delete['diff']['before']['state'] == "present" + - test_delete['diff']['after']['state'] == "absent" + - test_delete['cloud_network']['name'] == "Cisco Quantum Faster Network" + - "'deleted' in test_delete['msg']" + + - name: "8 - Delete idempotent" + networktocode.nautobot.cloud_network: + url: "{{ nautobot_url }}" + token: "{{ nautobot_token }}" + name: Cisco Quantum Faster Network + state: absent + register: test_delete_idem + + - name: "8 - ASSERT" + assert: + that: + - not test_delete_idem['changed'] + - "'already absent' in test_delete_idem['msg']" \ No newline at end of file diff --git a/tests/integration/targets/latest/tasks/cloud_service.yml b/tests/integration/targets/latest/tasks/cloud_service.yml index 47d66c0b..43391ece 100644 --- a/tests/integration/targets/latest/tasks/cloud_service.yml +++ b/tests/integration/targets/latest/tasks/cloud_service.yml @@ -12,7 +12,6 @@ - set_fact: cloud_resource_type: "{{ lookup('networktocode.nautobot.lookup', 'cloud-resource-types', api_endpoint=nautobot_url, token=nautobot_token, api_filter='name=CiscoCloudServiceType') }}" cloud_account: "{{ lookup('networktocode.nautobot.lookup', 'cloud-accounts', api_endpoint=nautobot_url, token=nautobot_token, api_filter='name=CiscoCloudAccount') }}" - #cloud_network: "{{ lookup('networktocode.nautobot.lookup', 'cloud-networks', api_endpoint=nautobot_url, token=nautobot_token, api_filter='name=CiscoCloudNetwork') }}" - name: "1 - Create cloud service within Nautobot with only required information" networktocode.nautobot.cloud_service: @@ -82,9 +81,6 @@ name: Cisco Quantum Secreter Service cloud_resource_type: CiscoCloudServiceType cloud_account: CiscoCloudAccount - #cloud_network: - # - CiscoCloudNetwork - # - CiscoCloudNetworkTwo description: Super secreter quantum service! register: test_create_max @@ -98,7 +94,6 @@ - test_create_max['cloud_service']['cloud_resource_type'] == cloud_resource_type['key'] - test_create_max['cloud_service']['cloud_account'] == cloud_account['key'] - test_create_max['cloud_service']['description'] == "Super secreter quantum service!" - #- test_create_max['cloud_service']['cloud_network'] == "654321" - name: "5.1 - ASSERT" assert: @@ -115,9 +110,6 @@ name: Cisco Quantum Secreter Service cloud_resource_type: CiscoCloudServiceType cloud_account: CiscoCloudAccount - #cloud_network: - # - CiscoCloudNetwork - # - CiscoCloudNetworkTwo description: Super secreter quantum service! register: test_create_max_idem diff --git a/tests/integration/targets/latest/tasks/main.yml b/tests/integration/targets/latest/tasks/main.yml index 2daaa556..3072c657 100644 --- a/tests/integration/targets/latest/tasks/main.yml +++ b/tests/integration/targets/latest/tasks/main.yml @@ -591,23 +591,32 @@ tags: - controller -- name: "PYNAUTOBOT_CLOUD_RESOURCE_TYPE TESTS" +- name: "PYNAUTOBOT_CLOUD_ACCOUNT TESTS" include_tasks: - file: "cloud_resource_type.yml" + file: "cloud_account.yml" apply: tags: - - cloud_resource_type + - cloud_account tags: - - cloud_resource_type + - cloud_account -- name: "PYNAUTOBOT_CLOUD_ACCOUNT TESTS" +- name: "PYNAUTOBOT_CLOUD_NETWORK TESTS" include_tasks: - file: "cloud_account.yml" + file: "cloud_network.yml" apply: tags: - - cloud_account + - cloud_network tags: - - cloud_account + - cloud_network + +- name: "PYNAUTOBOT_CLOUD_RESOURCE_TYPE TESTS" + include_tasks: + file: "cloud_resource_type.yml" + apply: + tags: + - cloud_resource_type + tags: + - cloud_resource_type - name: "PYNAUTOBOT_CLOUD_SERVICE TESTS" include_tasks: From c5734d70dd5949598be95d724ebb43a2a03bf923 Mon Sep 17 00:00:00 2001 From: Travis Smith <141754521+tsm1th@users.noreply.github.com> Date: Sat, 2 Nov 2024 04:56:08 +0000 Subject: [PATCH 13/25] Fixed linting error --- tests/integration/nautobot-populate.py | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/tests/integration/nautobot-populate.py b/tests/integration/nautobot-populate.py index 1cd0cdc3..7d4d76d3 100755 --- a/tests/integration/nautobot-populate.py +++ b/tests/integration/nautobot-populate.py @@ -648,19 +648,13 @@ def make_nautobot_calls(endpoint, payload): ] created_cloud_resource_types = make_nautobot_calls(nb.cloud.cloud_resource_types, cloud_resource_types) - cloud_accounts = [ - {"name": "CiscoCloudAccount", "provider": "Cisco", "account_number": "424242"} - ] + cloud_accounts = [{"name": "CiscoCloudAccount", "provider": "Cisco", "account_number": "424242"}] created_cloud_accounts = make_nautobot_calls(nb.cloud.cloud_accounts, cloud_accounts) - cloud_services = [ - {"name": "CiscoCloudService", "cloud_resource_type": "CiscoCloudServiceType", "cloud_account": "CiscoCloudAccount"} - ] + cloud_services = [{"name": "CiscoCloudService", "cloud_resource_type": "CiscoCloudServiceType", "cloud_account": "CiscoCloudAccount"}] created_cloud_services = make_nautobot_calls(nb.cloud.cloud_services, cloud_services) - cloud_networks = [ - {"name": "CiscoCloudNetwork", "cloud_resource_type": "CiscoCloudNetworkType", "cloud_account": "CiscoCloudAccount"} - ] + cloud_networks = [{"name": "CiscoCloudNetwork", "cloud_resource_type": "CiscoCloudNetworkType", "cloud_account": "CiscoCloudAccount"}] created_cloud_networks = make_nautobot_calls(nb.cloud.cloud_networks, cloud_networks) From 60fea30b4b6bef63135d4ba54c385ec6145d54fc Mon Sep 17 00:00:00 2001 From: Travis Smith <141754521+tsm1th@users.noreply.github.com> Date: Sun, 3 Nov 2024 00:51:48 +0000 Subject: [PATCH 14/25] Added cloud service network assignment module and tests --- plugins/lookup/lookup.py | 1 + plugins/module_utils/cloud.py | 10 ++ plugins/module_utils/utils.py | 5 +- .../cloud_service_network_assignment.py | 95 +++++++++++++++++++ .../cloud_service_network_assignment.yml | 82 ++++++++++++++++ .../integration/targets/latest/tasks/main.yml | 11 ++- 6 files changed, 202 insertions(+), 2 deletions(-) create mode 100644 plugins/modules/cloud_service_network_assignment.py create mode 100644 tests/integration/targets/latest/tasks/cloud_service_network_assignment.yml diff --git a/plugins/lookup/lookup.py b/plugins/lookup/lookup.py index 4e1347cb..7dccb4db 100644 --- a/plugins/lookup/lookup.py +++ b/plugins/lookup/lookup.py @@ -177,6 +177,7 @@ def get_endpoint(nautobot, term): "cloud-networks": {"endpoint": nautobot.cloud.cloud_networks}, "cloud-resource-types": {"endpoint": nautobot.cloud.cloud_resource_types}, "cloud-services": {"endpoint": nautobot.cloud.cloud_services}, + "cloud-service-network-assignments": {"endpoint": nautobot.cloud.cloud_service_network_assignments}, "cluster-groups": {"endpoint": nautobot.virtualization.cluster_groups}, "cluster-types": {"endpoint": nautobot.virtualization.cluster_types}, "clusters": {"endpoint": nautobot.virtualization.clusters}, diff --git a/plugins/module_utils/cloud.py b/plugins/module_utils/cloud.py index 440b230f..f9c42f29 100644 --- a/plugins/module_utils/cloud.py +++ b/plugins/module_utils/cloud.py @@ -13,6 +13,7 @@ NB_CLOUD_SERVICES = "cloud_services" NB_CLOUD_NETWORKS = "cloud_networks" +NB_CLOUD_SERVICE_NETWORK_ASSIGNMENTS = "cloud_service_network_assignments" NB_CLOUD_ACCOUNTS = "cloud_accounts" NB_CLOUD_RESOURCE_TYPES = "cloud_resource_types" @@ -25,6 +26,7 @@ def run(self): Supported endpoints: - cloud_services - cloud_networks + - cloud_service_network_assignments - cloud_accounts - cloud_resource_types """ @@ -43,6 +45,14 @@ def run(self): # Used for msg output if data.get("name"): name = data["name"] + elif endpoint_name == "cloud_service_network_assignment": + cloud_service = self.module.params["cloud_service"] + cloud_network = self.module.params["cloud_network"] + + name = "%s <> %s" % ( + cloud_service, + cloud_network, + ) object_query_params = self._build_query_params(endpoint_name, data, user_query_params) self.nb_object = self._nb_endpoint_get(nb_endpoint, object_query_params, name) diff --git a/plugins/module_utils/utils.py b/plugins/module_utils/utils.py index ce8e7585..163c3030 100644 --- a/plugins/module_utils/utils.py +++ b/plugins/module_utils/utils.py @@ -33,7 +33,7 @@ # Used to map endpoints to applications dynamically API_APPS_ENDPOINTS = dict( circuits=["circuits", "circuit_types", "circuit_terminations", "providers"], - cloud=["cloud_accounts", "cloud_networks", "cloud_resource_types", "cloud_services"], + cloud=["cloud_accounts", "cloud_networks", "cloud_resource_types", "cloud_services", "cloud_service_network_assignments"], dcim=[ "cables", "console_ports", @@ -163,6 +163,7 @@ "cloud_resource_type": "cloud_resource_types", "cloud_network": "cloud_networks", "cloud_service": "cloud_services", + "cloud_service_network_assignment": "cloud_service_network_assignments", "cluster": "clusters", "cluster_group": "cluster_groups", "cluster_type": "cluster_types", @@ -242,6 +243,7 @@ "cloud_networks": "cloud_network", "cloud_resource_types": "cloud_resource_type", "cloud_services": "cloud_service", + "cloud_service_network_assignments": "cloud_service_network_assignment", "clusters": "cluster", "cluster_groups": "cluster_group", "cluster_types": "cluster_type", @@ -313,6 +315,7 @@ "cloud_network": set(["name"]), "cloud_resource_type": set(["name"]), "cloud_service": set(["name"]), + "cloud_service_network_assignment": set(["cloud_service", "cloud_network"]), "cluster": set(["name", "type"]), "cluster_group": set(["name"]), "cluster_type": set(["name"]), diff --git a/plugins/modules/cloud_service_network_assignment.py b/plugins/modules/cloud_service_network_assignment.py new file mode 100644 index 00000000..bf030ebd --- /dev/null +++ b/plugins/modules/cloud_service_network_assignment.py @@ -0,0 +1,95 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# Copyright: (c) 2024, Network to Code (@networktocode) +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + +DOCUMENTATION = r""" +--- +module: cloud_service_network_assignment +short_description: Creates or removes cloud service to cloud network association from Nautobot +description: + - Creates or removes cloud service to cloud network association from Nautobot +notes: + - This should be ran with connection C(local) and hosts C(localhost) +author: + - Travis Smith (@tsm1th) +requirements: + - pynautobot +version_added: "5.4.0" +extends_documentation_fragment: + - networktocode.nautobot.fragments.base +options: + cloud_service: + description: + - Cloud service to associate with a cloud network. + required: true + type: raw + cloud_network: + description: + - Cloud network to associate with a cloud service. + required: true + type: raw +""" + +EXAMPLES = r""" +--- +- name: Create a cloud_service to cloud_network assignment + networktocode.nautobot.cloud_network: + url: http://nautobot.local + token: thisIsMyToken + cloud_service: Cisco Quantum Service + cloud_network: Cisco Quantum Network + state: present + +- name: Delete a cloud_service to cloud_network assignment + networktocode.nautobot.cloud_network: + url: http://nautobot.local + token: thisIsMyToken + cloud_service: Cisco Quantum Service + cloud_network: Cisco Quantum Network + state: absent +""" + +RETURN = r""" +cloud_service_network_assignment: + description: Serialized object as created or already existent within Nautobot + returned: on creation + type: dict +msg: + description: Message indicating failure or info about what has been achieved + returned: always + type: str +""" + +from ansible_collections.networktocode.nautobot.plugins.module_utils.utils import NAUTOBOT_ARG_SPEC +from ansible_collections.networktocode.nautobot.plugins.module_utils.cloud import ( + NautobotCloudModule, + NB_CLOUD_SERVICE_NETWORK_ASSIGNMENTS, +) +from ansible.module_utils.basic import AnsibleModule +from copy import deepcopy + + +def main(): + """ + Main entry point for module execution + """ + argument_spec = deepcopy(NAUTOBOT_ARG_SPEC) + argument_spec.update( + dict( + cloud_service=dict(required=True, type="raw"), + cloud_network=dict(required=True, type="raw"), + ) + ) + + module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True) + cloud_service_network_assignment = NautobotCloudModule(module, NB_CLOUD_SERVICE_NETWORK_ASSIGNMENTS) + cloud_service_network_assignment.run() + + +if __name__ == "__main__": # pragma: no cover + main() diff --git a/tests/integration/targets/latest/tasks/cloud_service_network_assignment.yml b/tests/integration/targets/latest/tasks/cloud_service_network_assignment.yml new file mode 100644 index 00000000..6fb07eeb --- /dev/null +++ b/tests/integration/targets/latest/tasks/cloud_service_network_assignment.yml @@ -0,0 +1,82 @@ +--- +## +## +### PYNAUTOBOT_CLOUD_SERVICE_NETWORK_ASSIGNMENT +## +## + +- name: "NAUTOBOT 2.3+ CLOUD SERVICE NETWORK ASSIGNMENT TESTS" + when: + - "nautobot_version is version('2.3', '>=')" + block: + - set_fact: + cloud_service: "{{ lookup('networktocode.nautobot.lookup', 'cloud-services', api_endpoint=nautobot_url, token=nautobot_token, api_filter='name=CiscoCloudService') }}" + cloud_network: "{{ lookup('networktocode.nautobot.lookup', 'cloud-networks', api_endpoint=nautobot_url, token=nautobot_token, api_filter='name=CiscoCloudNetwork') }}" + + - name: "1 - Create cloud service to cloud network assignment" + networktocode.nautobot.cloud_service_network_assignment: + url: "{{ nautobot_url }}" + token: "{{ nautobot_token }}" + cloud_service: CiscoCloudService + cloud_network: CiscoCloudNetwork + register: test_create_one + + - name: "1 - ASSERT" + assert: + that: + - test_create_one is changed + - test_create_one['diff']['before']['state'] == "absent" + - test_create_one['diff']['after']['state'] == "present" + - test_create_one['cloud_service_network_assignment']['cloud_service'] == cloud_service['key'] + - test_create_one['cloud_service_network_assignment']['cloud_network'] == cloud_network['key'] + - "'created' in test_create_one['msg']" + + - name: "2 - Duplicate" + networktocode.nautobot.cloud_service_network_assignment: + url: "{{ nautobot_url }}" + token: "{{ nautobot_token }}" + cloud_service: CiscoCloudService + cloud_network: CiscoCloudNetwork + register: test_create_idem + + - name: "2 - ASSERT" + assert: + that: + - not test_create_idem['changed'] + - "'already exists' in test_create_idem['msg']" + - test_create_idem['cloud_service_network_assignment']['cloud_service'] == cloud_service['key'] + - test_create_idem['cloud_service_network_assignment']['cloud_network'] == cloud_network['key'] + + - name: "3 - Delete cloud_service_network_assignment" + networktocode.nautobot.cloud_service_network_assignment: + url: "{{ nautobot_url }}" + token: "{{ nautobot_token }}" + cloud_service: CiscoCloudService + cloud_network: CiscoCloudNetwork + state: absent + register: test_delete + + - name: "3 - ASSERT" + assert: + that: + - test_delete is changed + - test_delete['diff']['before']['state'] == "present" + - test_delete['diff']['after']['state'] == "absent" + - test_delete['cloud_service_network_assignment']['cloud_service'] == cloud_service['key'] + - test_delete['cloud_service_network_assignment']['cloud_network'] == cloud_network['key'] + - "'deleted' in test_delete['msg']" + + - name: "4 - Delete idempotent" + networktocode.nautobot.cloud_service_network_assignment: + url: "{{ nautobot_url }}" + token: "{{ nautobot_token }}" + cloud_service: CiscoCloudService + cloud_network: CiscoCloudNetwork + state: absent + register: test_delete_idem + + - name: "4 - ASSERT" + assert: + that: + - not test_delete_idem['changed'] + - "'already absent' in test_delete_idem['msg']" \ No newline at end of file diff --git a/tests/integration/targets/latest/tasks/main.yml b/tests/integration/targets/latest/tasks/main.yml index 3072c657..bf10ccce 100644 --- a/tests/integration/targets/latest/tasks/main.yml +++ b/tests/integration/targets/latest/tasks/main.yml @@ -625,4 +625,13 @@ tags: - cloud_service tags: - - cloud_service \ No newline at end of file + - cloud_service + +- name: "PYNAUTOBOT_CLOUD_SERVICE_NETWORK_ASSIGNMENT TESTS" + include_tasks: + file: "cloud_service_network_assignment.yml" + apply: + tags: + - cloud_service_network_assignment + tags: + - cloud_service_network_assignment From fcba5114297ccc4bbc84f14061c53629081f3eec Mon Sep 17 00:00:00 2001 From: Travis Smith <141754521+tsm1th@users.noreply.github.com> Date: Sun, 3 Nov 2024 01:46:47 +0000 Subject: [PATCH 15/25] Added cloud network to prefix assignment module and tests --- plugins/lookup/lookup.py | 1 + plugins/module_utils/cloud.py | 7 ++ plugins/module_utils/utils.py | 14 ++- .../cloud_network_prefix_assignment.py | 95 +++++++++++++++++++ .../tasks/cloud_network_prefix_assignment.yml | 82 ++++++++++++++++ .../integration/targets/latest/tasks/main.yml | 9 ++ 6 files changed, 207 insertions(+), 1 deletion(-) create mode 100644 plugins/modules/cloud_network_prefix_assignment.py create mode 100644 tests/integration/targets/latest/tasks/cloud_network_prefix_assignment.yml diff --git a/plugins/lookup/lookup.py b/plugins/lookup/lookup.py index 7dccb4db..6bbd9f9d 100644 --- a/plugins/lookup/lookup.py +++ b/plugins/lookup/lookup.py @@ -175,6 +175,7 @@ def get_endpoint(nautobot, term): "cables": {"endpoint": nautobot.dcim.cables}, "cloud-accounts": {"endpoint": nautobot.cloud.cloud_accounts}, "cloud-networks": {"endpoint": nautobot.cloud.cloud_networks}, + "cloud-network-prefix-assignments": {"endpoint": nautobot.cloud.cloud_network_prefix_assignments}, "cloud-resource-types": {"endpoint": nautobot.cloud.cloud_resource_types}, "cloud-services": {"endpoint": nautobot.cloud.cloud_services}, "cloud-service-network-assignments": {"endpoint": nautobot.cloud.cloud_service_network_assignments}, diff --git a/plugins/module_utils/cloud.py b/plugins/module_utils/cloud.py index f9c42f29..9da063de 100644 --- a/plugins/module_utils/cloud.py +++ b/plugins/module_utils/cloud.py @@ -13,6 +13,7 @@ NB_CLOUD_SERVICES = "cloud_services" NB_CLOUD_NETWORKS = "cloud_networks" +NB_CLOUD_NETWORK_PREFIX_ASSIGNMENTS = "cloud_network_prefix_assignments" NB_CLOUD_SERVICE_NETWORK_ASSIGNMENTS = "cloud_service_network_assignments" NB_CLOUD_ACCOUNTS = "cloud_accounts" NB_CLOUD_RESOURCE_TYPES = "cloud_resource_types" @@ -26,6 +27,7 @@ def run(self): Supported endpoints: - cloud_services - cloud_networks + - cloud_network_prefix_assignments - cloud_service_network_assignments - cloud_accounts - cloud_resource_types @@ -53,6 +55,11 @@ def run(self): cloud_service, cloud_network, ) + elif endpoint_name == "cloud_network_prefix_assignment": + cloud_network = self.module.params["cloud_network"] + prefix = self.module.params["prefix"] + + name = "%s <> %s" % (cloud_network, prefix) object_query_params = self._build_query_params(endpoint_name, data, user_query_params) self.nb_object = self._nb_endpoint_get(nb_endpoint, object_query_params, name) diff --git a/plugins/module_utils/utils.py b/plugins/module_utils/utils.py index 163c3030..a6484562 100644 --- a/plugins/module_utils/utils.py +++ b/plugins/module_utils/utils.py @@ -33,7 +33,14 @@ # Used to map endpoints to applications dynamically API_APPS_ENDPOINTS = dict( circuits=["circuits", "circuit_types", "circuit_terminations", "providers"], - cloud=["cloud_accounts", "cloud_networks", "cloud_resource_types", "cloud_services", "cloud_service_network_assignments"], + cloud=[ + "cloud_accounts", + "cloud_networks", + "cloud_network_prefix_assignments", + "cloud_resource_types", + "cloud_services", + "cloud_service_network_assignments", + ], dcim=[ "cables", "console_ports", @@ -130,6 +137,7 @@ power_port="name", power_port_template="name", platform="name", + prefix="prefix", primary_ip="address", primary_ip4="address", primary_ip6="address", @@ -162,6 +170,7 @@ "cloud_provider": "manufacturers", "cloud_resource_type": "cloud_resource_types", "cloud_network": "cloud_networks", + "cloud_network_prefix_assignment": "cloud_network_prefix_assignments", "cloud_service": "cloud_services", "cloud_service_network_assignment": "cloud_service_network_assignments", "cluster": "clusters", @@ -204,6 +213,7 @@ "power_panel": "power_panels", "power_port": "power_ports", "power_port_template": "power_port_templates", + "prefix": "prefixes", "primary_ip": "ip_addresses", "primary_ip4": "ip_addresses", "primary_ip6": "ip_addresses", @@ -241,6 +251,7 @@ "circuits": "circuit", "cloud_accounts": "cloud_account", "cloud_networks": "cloud_network", + "cloud_network_prefix_assignments": "cloud_network_prefix_assignment", "cloud_resource_types": "cloud_resource_type", "cloud_services": "cloud_service", "cloud_service_network_assignments": "cloud_service_network_assignment", @@ -313,6 +324,7 @@ "circuits.circuittermination": set(["circuit", "term_side"]), "cloud_account": set(["name"]), "cloud_network": set(["name"]), + "cloud_network_prefix_assignment": set(["cloud_network", "prefix"]), "cloud_resource_type": set(["name"]), "cloud_service": set(["name"]), "cloud_service_network_assignment": set(["cloud_service", "cloud_network"]), diff --git a/plugins/modules/cloud_network_prefix_assignment.py b/plugins/modules/cloud_network_prefix_assignment.py new file mode 100644 index 00000000..9a709177 --- /dev/null +++ b/plugins/modules/cloud_network_prefix_assignment.py @@ -0,0 +1,95 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# Copyright: (c) 2024, Network to Code (@networktocode) +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + +DOCUMENTATION = r""" +--- +module: cloud_network_prefix_assignment +short_description: Creates or removes cloud network to prefix association from Nautobot +description: + - Creates or removes cloud network to prefix association from Nautobot +notes: + - This should be ran with connection C(local) and hosts C(localhost) +author: + - Travis Smith (@tsm1th) +requirements: + - pynautobot +version_added: "5.4.0" +extends_documentation_fragment: + - networktocode.nautobot.fragments.base +options: + cloud_network: + description: + - Cloud network to associate with a prefix. + required: true + type: raw + prefix: + description: + - Prefix to associate with a cloud network. + required: true + type: raw +""" + +EXAMPLES = r""" +--- +- name: Create a cloud_network to prefix assignment + networktocode.nautobot.cloud_network: + url: http://nautobot.local + token: thisIsMyToken + cloud_network: Cisco Quantum Network + prefix: 10.1.198.0/23 + state: present + +- name: Delete a cloud_network to prefix assignment + networktocode.nautobot.cloud_network: + url: http://nautobot.local + token: thisIsMyToken + cloud_network: Cisco Quantum Network + prefix: 10.1.198.0/23 + state: absent +""" + +RETURN = r""" +cloud_network_prefix_assignment: + description: Serialized object as created or already existent within Nautobot + returned: on creation + type: dict +msg: + description: Message indicating failure or info about what has been achieved + returned: always + type: str +""" + +from ansible_collections.networktocode.nautobot.plugins.module_utils.utils import NAUTOBOT_ARG_SPEC +from ansible_collections.networktocode.nautobot.plugins.module_utils.cloud import ( + NautobotCloudModule, + NB_CLOUD_NETWORK_PREFIX_ASSIGNMENTS, +) +from ansible.module_utils.basic import AnsibleModule +from copy import deepcopy + + +def main(): + """ + Main entry point for module execution + """ + argument_spec = deepcopy(NAUTOBOT_ARG_SPEC) + argument_spec.update( + dict( + cloud_network=dict(required=True, type="raw"), + prefix=dict(required=True, type="raw"), + ) + ) + + module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True) + cloud_network_prefix_assignment = NautobotCloudModule(module, NB_CLOUD_NETWORK_PREFIX_ASSIGNMENTS) + cloud_network_prefix_assignment.run() + + +if __name__ == "__main__": # pragma: no cover + main() diff --git a/tests/integration/targets/latest/tasks/cloud_network_prefix_assignment.yml b/tests/integration/targets/latest/tasks/cloud_network_prefix_assignment.yml new file mode 100644 index 00000000..239c7cd0 --- /dev/null +++ b/tests/integration/targets/latest/tasks/cloud_network_prefix_assignment.yml @@ -0,0 +1,82 @@ +--- +## +## +### PYNAUTOBOT_CLOUD_NETWORK_PREFIX_ASSIGNMENT +## +## + +- name: "NAUTOBOT 2.3+ CLOUD NETWORK PREFIX ASSIGNMENT TESTS" + when: + - "nautobot_version is version('2.3', '>=')" + block: + - set_fact: + cloud_network: "{{ lookup('networktocode.nautobot.lookup', 'cloud-networks', api_endpoint=nautobot_url, token=nautobot_token, api_filter='name=CiscoCloudNetwork') }}" + prefix: "{{ lookup('networktocode.nautobot.lookup', 'prefixes', api_endpoint=nautobot_url, token=nautobot_token, api_filter='prefix=10.10.0.0/16') }}" + + - name: "1 - Create cloud network to prefix assignment" + networktocode.nautobot.cloud_network_prefix_assignment: + url: "{{ nautobot_url }}" + token: "{{ nautobot_token }}" + cloud_network: CiscoCloudNetwork + prefix: 10.10.0.0/16 + register: test_create_one + + - name: "1 - ASSERT" + assert: + that: + - test_create_one is changed + - test_create_one['diff']['before']['state'] == "absent" + - test_create_one['diff']['after']['state'] == "present" + - test_create_one['cloud_network_prefix_assignment']['cloud_network'] == cloud_network['key'] + - test_create_one['cloud_network_prefix_assignment']['prefix'] == prefix['key'] + - "'created' in test_create_one['msg']" + + - name: "2 - Duplicate" + networktocode.nautobot.cloud_network_prefix_assignment: + url: "{{ nautobot_url }}" + token: "{{ nautobot_token }}" + cloud_network: CiscoCloudNetwork + prefix: 10.10.0.0/16 + register: test_create_idem + + - name: "2 - ASSERT" + assert: + that: + - not test_create_idem['changed'] + - "'already exists' in test_create_idem['msg']" + - test_create_idem['cloud_network_prefix_assignment']['cloud_network'] == cloud_network['key'] + - test_create_idem['cloud_network_prefix_assignment']['prefix'] == prefix['key'] + + - name: "3 - Delete cloud_network_prefix_assignment" + networktocode.nautobot.cloud_network_prefix_assignment: + url: "{{ nautobot_url }}" + token: "{{ nautobot_token }}" + cloud_network: CiscoCloudNetwork + prefix: 10.10.0.0/16 + state: absent + register: test_delete + + - name: "3 - ASSERT" + assert: + that: + - test_delete is changed + - test_delete['diff']['before']['state'] == "present" + - test_delete['diff']['after']['state'] == "absent" + - test_delete['cloud_network_prefix_assignment']['cloud_network'] == cloud_network['key'] + - test_delete['cloud_network_prefix_assignment']['prefix'] == prefix['key'] + - "'deleted' in test_delete['msg']" + + - name: "4 - Delete idempotent" + networktocode.nautobot.cloud_network_prefix_assignment: + url: "{{ nautobot_url }}" + token: "{{ nautobot_token }}" + cloud_network: CiscoCloudNetwork + prefix: 10.10.0.0/16 + state: absent + register: test_delete_idem + + - name: "4 - ASSERT" + assert: + that: + - not test_delete_idem['changed'] + - "'already absent' in test_delete_idem['msg']" \ No newline at end of file diff --git a/tests/integration/targets/latest/tasks/main.yml b/tests/integration/targets/latest/tasks/main.yml index bf10ccce..986699a7 100644 --- a/tests/integration/targets/latest/tasks/main.yml +++ b/tests/integration/targets/latest/tasks/main.yml @@ -635,3 +635,12 @@ - cloud_service_network_assignment tags: - cloud_service_network_assignment + +- name: "PYNAUTOBOT_CLOUD_NETWORK_PREFIX_ASSIGNMENT TESTS" + include_tasks: + file: "cloud_network_prefix_assignment.yml" + apply: + tags: + - cloud_network_prefix_assignment + tags: + - cloud_network_prefix_assignment \ No newline at end of file From 44cd2ec4bbdc9f1425f79d0df0735c659fcd3962 Mon Sep 17 00:00:00 2001 From: Travis Smith <141754521+tsm1th@users.noreply.github.com> Date: Sun, 3 Nov 2024 03:17:11 +0000 Subject: [PATCH 16/25] Added cloud network prefix assignment module and tests --- plugins/module_utils/cloud.py | 4 ++-- plugins/module_utils/utils.py | 5 +++-- plugins/modules/cloud_account.py | 2 +- plugins/modules/cloud_network_prefix_assignment.py | 10 ++++++---- .../latest/tasks/cloud_network_prefix_assignment.yml | 8 ++++---- 5 files changed, 16 insertions(+), 13 deletions(-) diff --git a/plugins/module_utils/cloud.py b/plugins/module_utils/cloud.py index 9da063de..36944e89 100644 --- a/plugins/module_utils/cloud.py +++ b/plugins/module_utils/cloud.py @@ -57,9 +57,9 @@ def run(self): ) elif endpoint_name == "cloud_network_prefix_assignment": cloud_network = self.module.params["cloud_network"] - prefix = self.module.params["prefix"] + cloud_prefix = self.module.params["cloud_prefix"] - name = "%s <> %s" % (cloud_network, prefix) + name = "%s <> %s" % (cloud_network, cloud_prefix) object_query_params = self._build_query_params(endpoint_name, data, user_query_params) self.nb_object = self._nb_endpoint_get(nb_endpoint, object_query_params, name) diff --git a/plugins/module_utils/utils.py b/plugins/module_utils/utils.py index a6484562..a89828b1 100644 --- a/plugins/module_utils/utils.py +++ b/plugins/module_utils/utils.py @@ -109,6 +109,7 @@ circuit="cid", circuit_termination="circuit", circuit_type="name", + cloud_prefix="prefix", cloud_provider="name", cluster="name", cluster_group="name", @@ -137,7 +138,6 @@ power_port="name", power_port_template="name", platform="name", - prefix="prefix", primary_ip="address", primary_ip4="address", primary_ip6="address", @@ -167,6 +167,7 @@ "circuit_termination": "circuit_terminations", "circuits.circuittermination": "circuit_terminations", "cloud_account": "cloud_accounts", + "cloud_prefix": "prefixes", "cloud_provider": "manufacturers", "cloud_resource_type": "cloud_resource_types", "cloud_network": "cloud_networks", @@ -213,7 +214,6 @@ "power_panel": "power_panels", "power_port": "power_ports", "power_port_template": "power_port_templates", - "prefix": "prefixes", "primary_ip": "ip_addresses", "primary_ip4": "ip_addresses", "primary_ip6": "ip_addresses", @@ -463,6 +463,7 @@ # This is used to map non-clashing keys to Nautobot API compliant keys to prevent bad logic in code for similar keys but different modules CONVERT_KEYS = { + "cloud_prefix": "prefix", "cloud_provider": "provider", "parent_cloud_network": "parent", "parent_rack_group": "parent", diff --git a/plugins/modules/cloud_account.py b/plugins/modules/cloud_account.py index 8d3deafa..8d294602 100644 --- a/plugins/modules/cloud_account.py +++ b/plugins/modules/cloud_account.py @@ -115,7 +115,7 @@ def main(): description=dict(required=False, type="str"), account_number=dict(required=False, type="str"), cloud_provider=dict(required=False, type="raw", aliases=["provider"]), - secrets_group=dict(required=False, type="raw", no_log=True), + secrets_group=dict(required=False, type="raw", no_log=False), ) ) diff --git a/plugins/modules/cloud_network_prefix_assignment.py b/plugins/modules/cloud_network_prefix_assignment.py index 9a709177..584acb90 100644 --- a/plugins/modules/cloud_network_prefix_assignment.py +++ b/plugins/modules/cloud_network_prefix_assignment.py @@ -28,7 +28,9 @@ - Cloud network to associate with a prefix. required: true type: raw - prefix: + cloud_prefix: + aliases: + - prefix description: - Prefix to associate with a cloud network. required: true @@ -42,7 +44,7 @@ url: http://nautobot.local token: thisIsMyToken cloud_network: Cisco Quantum Network - prefix: 10.1.198.0/23 + cloud_prefix: 10.1.198.0/23 state: present - name: Delete a cloud_network to prefix assignment @@ -50,7 +52,7 @@ url: http://nautobot.local token: thisIsMyToken cloud_network: Cisco Quantum Network - prefix: 10.1.198.0/23 + cloud_prefix: 10.1.198.0/23 state: absent """ @@ -82,7 +84,7 @@ def main(): argument_spec.update( dict( cloud_network=dict(required=True, type="raw"), - prefix=dict(required=True, type="raw"), + cloud_prefix=dict(required=True, type="raw", aliases=["prefix"]), ) ) diff --git a/tests/integration/targets/latest/tasks/cloud_network_prefix_assignment.yml b/tests/integration/targets/latest/tasks/cloud_network_prefix_assignment.yml index 239c7cd0..4d588d4b 100644 --- a/tests/integration/targets/latest/tasks/cloud_network_prefix_assignment.yml +++ b/tests/integration/targets/latest/tasks/cloud_network_prefix_assignment.yml @@ -18,7 +18,7 @@ url: "{{ nautobot_url }}" token: "{{ nautobot_token }}" cloud_network: CiscoCloudNetwork - prefix: 10.10.0.0/16 + cloud_prefix: 10.10.0.0/16 register: test_create_one - name: "1 - ASSERT" @@ -36,7 +36,7 @@ url: "{{ nautobot_url }}" token: "{{ nautobot_token }}" cloud_network: CiscoCloudNetwork - prefix: 10.10.0.0/16 + cloud_prefix: 10.10.0.0/16 register: test_create_idem - name: "2 - ASSERT" @@ -52,7 +52,7 @@ url: "{{ nautobot_url }}" token: "{{ nautobot_token }}" cloud_network: CiscoCloudNetwork - prefix: 10.10.0.0/16 + cloud_prefix: 10.10.0.0/16 state: absent register: test_delete @@ -71,7 +71,7 @@ url: "{{ nautobot_url }}" token: "{{ nautobot_token }}" cloud_network: CiscoCloudNetwork - prefix: 10.10.0.0/16 + cloud_prefix: 10.10.0.0/16 state: absent register: test_delete_idem From 1c3dcdcc157ee165b353e8e0f81794f2c75838c5 Mon Sep 17 00:00:00 2001 From: Travis Smith <141754521+tsm1th@users.noreply.github.com> Date: Sun, 3 Nov 2024 04:31:06 +0000 Subject: [PATCH 17/25] Added query params to cloud objects to prevent q query and fixed var clash in test --- plugins/module_utils/utils.py | 2 ++ .../integration/targets/latest/tasks/cloud_resource_type.yml | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/plugins/module_utils/utils.py b/plugins/module_utils/utils.py index a89828b1..bf1ab0a9 100644 --- a/plugins/module_utils/utils.py +++ b/plugins/module_utils/utils.py @@ -109,8 +109,10 @@ circuit="cid", circuit_termination="circuit", circuit_type="name", + cloud_network="name", cloud_prefix="prefix", cloud_provider="name", + cloud_service="name", cluster="name", cluster_group="name", cluster_type="name", diff --git a/tests/integration/targets/latest/tasks/cloud_resource_type.yml b/tests/integration/targets/latest/tasks/cloud_resource_type.yml index 6fe32b7f..692ee95f 100644 --- a/tests/integration/targets/latest/tasks/cloud_resource_type.yml +++ b/tests/integration/targets/latest/tasks/cloud_resource_type.yml @@ -103,9 +103,9 @@ - name: "5.1 - ASSERT" assert: that: - - cloud_resource_type['value']['config_schema']['my_config']['foo'] == "bar" + - test_cloud_resource_type['value']['config_schema']['my_config']['foo'] == "bar" vars: - cloud_resource_type: "{{ lookup('networktocode.nautobot.lookup', 'cloud-resource-types', api_endpoint=nautobot_url, token=nautobot_token, api_filter='name=\"Cisco Quantum Network Remix\"') }}" + test_cloud_resource_type: "{{ lookup('networktocode.nautobot.lookup', 'cloud-resource-types', api_endpoint=nautobot_url, token=nautobot_token, api_filter='name=\"Cisco Quantum Network Remix\"') }}" - name: "6 - Duplicate create with all parameters" networktocode.nautobot.cloud_resource_type: From d5123e7e25372b97c73943826a44dce708de54ad Mon Sep 17 00:00:00 2001 From: Travis Smith <141754521+tsm1th@users.noreply.github.com> Date: Wed, 6 Nov 2024 19:28:16 +0000 Subject: [PATCH 18/25] Fixed cosmetic issues in docs, tests, vars, etc. --- plugins/modules/cloud_account.py | 18 +++++++++--------- plugins/modules/cloud_network.py | 16 ++++++++-------- .../cloud_network_prefix_assignment.py | 8 ++++---- plugins/modules/cloud_resource_type.py | 19 ++++++++++--------- plugins/modules/cloud_service.py | 14 +++++++------- .../cloud_service_network_assignment.py | 8 ++++---- .../tasks/cloud_network_prefix_assignment.yml | 8 ++++---- 7 files changed, 46 insertions(+), 45 deletions(-) diff --git a/plugins/modules/cloud_account.py b/plugins/modules/cloud_account.py index 8d294602..881746d7 100644 --- a/plugins/modules/cloud_account.py +++ b/plugins/modules/cloud_account.py @@ -10,9 +10,9 @@ DOCUMENTATION = r""" --- module: cloud_account -short_description: Creates or removes cloud_account from Nautobot +short_description: Creates or removes cloud account from Nautobot description: - - Creates or removes cloud_account from Nautobot + - Creates or removes cloud account from Nautobot notes: - Tags should be defined as a YAML list - This should be ran with connection C(local) and hosts C(localhost) @@ -28,36 +28,36 @@ options: name: description: - - The name of the cloud_account + - The name of the cloud account required: true type: str account_number: description: - - Required if I(state=present) and the cloud_account does not exist yet + - Required if I(state=present) and the cloud account does not exist yet required: false type: str description: description: - - The description of the cloud_account + - The description of the cloud account required: false type: str cloud_provider: aliases: - provider description: - - Required if I(state=present) and the cloud_account does not exist yet + - Required if I(state=present) and the cloud account does not exist yet required: false type: raw secrets_group: description: - - The secrets group of the cloud_account + - The secrets group of the cloud account required: false type: raw """ EXAMPLES = r""" --- -- name: Create a cloud_account +- name: Create a cloud account networktocode.nautobot.cloud_account: url: http://nautobot.local token: thisIsMyToken @@ -70,7 +70,7 @@ vars: my_secrets_group: "{{ lookup('networktocode.nautobot.lookup', 'secrets-groups', api_endpoint=nautobot_url, token=nautobot_token, api_filter='name=\"My Secrets Group\"') }}" -- name: Delete a cloud_account +- name: Delete a cloud account networktocode.nautobot.cloud_account: url: http://nautobot.local token: thisIsMyToken diff --git a/plugins/modules/cloud_network.py b/plugins/modules/cloud_network.py index 01c7e08a..b2bdbcea 100644 --- a/plugins/modules/cloud_network.py +++ b/plugins/modules/cloud_network.py @@ -10,9 +10,9 @@ DOCUMENTATION = r""" --- module: cloud_network -short_description: Creates or removes cloud_network from Nautobot +short_description: Creates or removes cloud network from Nautobot description: - - Creates or removes cloud_network from Nautobot + - Creates or removes cloud network from Nautobot notes: - Tags should be defined as a YAML list - This should be ran with connection C(local) and hosts C(localhost) @@ -28,22 +28,22 @@ options: name: description: - - The name of the cloud_network + - The name of the cloud network required: true type: str description: description: - - The description of the cloud_network + - The description of the cloud network required: false type: str cloud_resource_type: description: - - Required if I(state=present) and the cloud_network does not exist yet + - Required if I(state=present) and the cloud network does not exist yet required: false type: raw cloud_account: description: - - Required if I(state=present) and the cloud_network does not exist yet + - Required if I(state=present) and the cloud network does not exist yet required: false type: raw parent_cloud_network: @@ -57,7 +57,7 @@ EXAMPLES = r""" --- -- name: Create a cloud_network +- name: Create a cloud network networktocode.nautobot.cloud_network: url: http://nautobot.local token: thisIsMyToken @@ -67,7 +67,7 @@ description: A quantum network for Cisco state: present -- name: Delete a cloud_network +- name: Delete a cloud network networktocode.nautobot.cloud_network: url: http://nautobot.local token: thisIsMyToken diff --git a/plugins/modules/cloud_network_prefix_assignment.py b/plugins/modules/cloud_network_prefix_assignment.py index 584acb90..4b465532 100644 --- a/plugins/modules/cloud_network_prefix_assignment.py +++ b/plugins/modules/cloud_network_prefix_assignment.py @@ -39,16 +39,16 @@ EXAMPLES = r""" --- -- name: Create a cloud_network to prefix assignment - networktocode.nautobot.cloud_network: +- name: Create a cloud network to prefix assignment + networktocode.nautobot.cloud_network_prefix_assignment: url: http://nautobot.local token: thisIsMyToken cloud_network: Cisco Quantum Network cloud_prefix: 10.1.198.0/23 state: present -- name: Delete a cloud_network to prefix assignment - networktocode.nautobot.cloud_network: +- name: Delete a cloud network to prefix assignment + networktocode.nautobot.cloud_network_prefix_assignment: url: http://nautobot.local token: thisIsMyToken cloud_network: Cisco Quantum Network diff --git a/plugins/modules/cloud_resource_type.py b/plugins/modules/cloud_resource_type.py index ed6c9ef6..1a145eb6 100644 --- a/plugins/modules/cloud_resource_type.py +++ b/plugins/modules/cloud_resource_type.py @@ -10,9 +10,9 @@ DOCUMENTATION = r""" --- module: cloud_resource_type -short_description: Creates or removes cloud_resource_type from Nautobot +short_description: Creates or removes cloud resource type from Nautobot description: - - Creates or removes cloud_resource_type from Nautobot + - Creates or removes cloud resource type from Nautobot notes: - Tags should be defined as a YAML list - This should be ran with connection C(local) and hosts C(localhost) @@ -28,25 +28,26 @@ options: name: description: - - The name of the cloud_resource_type + - The name of the cloud resource type required: true type: str description: description: - - The description of the cloud_resource_type + - The description of the cloud resource type required: false type: str cloud_provider: aliases: - provider description: - - Required if I(state=present) and the cloud_resource_type does not exist yet + - Required if I(state=present) and the cloud resource type does not exist yet required: false type: raw content_types: description: + - Required if I(state=present) and the cloud resource type does not exist yet - Cloud Resource Type content type(s). These match app.endpoint and the endpoint is singular. - - e.g. cloud.cloudnetwork, cloud.cloudservice (more can be found in the examples) + - cloud.cloudnetwork, cloud.cloudservice type: list elements: str config_schema: @@ -58,7 +59,7 @@ EXAMPLES = r""" --- -- name: Create a cloud_resource_type +- name: Create a cloud resource type networktocode.nautobot.cloud_resource_type: url: http://nautobot.local token: thisIsMyToken @@ -68,8 +69,8 @@ - "cloud.cloudnetwork" state: present -- name: Delete a cloud_resource_type - networktocode.nautobot.contact: +- name: Delete a cloud resource type + networktocode.nautobot.cloud_resource_type: url: http://nautobot.local token: thisIsMyToken name: Cisco Quantum Network diff --git a/plugins/modules/cloud_service.py b/plugins/modules/cloud_service.py index b24d4ed1..54937b44 100644 --- a/plugins/modules/cloud_service.py +++ b/plugins/modules/cloud_service.py @@ -10,9 +10,9 @@ DOCUMENTATION = r""" --- module: cloud_service -short_description: Creates or removes cloud_service from Nautobot +short_description: Creates or removes cloud service from Nautobot description: - - Creates or removes cloud_service from Nautobot + - Creates or removes cloud service from Nautobot notes: - Tags should be defined as a YAML list - This should be ran with connection C(local) and hosts C(localhost) @@ -28,17 +28,17 @@ options: name: description: - - The name of the cloud_service + - The name of the cloud service required: true type: str description: description: - - The description of the cloud_service + - The description of the cloud service required: false type: str cloud_resource_type: description: - - Required if I(state=present) and the cloud_service does not exist yet + - Required if I(state=present) and the cloud service does not exist yet required: false type: raw cloud_account: @@ -50,7 +50,7 @@ EXAMPLES = r""" --- -- name: Create a cloud_service +- name: Create a cloud service networktocode.nautobot.cloud_service: url: http://nautobot.local token: thisIsMyToken @@ -60,7 +60,7 @@ description: A quantum service for Cisco state: present -- name: Delete a cloud_service +- name: Delete a cloud service networktocode.nautobot.cloud_service: url: http://nautobot.local token: thisIsMyToken diff --git a/plugins/modules/cloud_service_network_assignment.py b/plugins/modules/cloud_service_network_assignment.py index bf030ebd..5c8856c4 100644 --- a/plugins/modules/cloud_service_network_assignment.py +++ b/plugins/modules/cloud_service_network_assignment.py @@ -37,16 +37,16 @@ EXAMPLES = r""" --- -- name: Create a cloud_service to cloud_network assignment - networktocode.nautobot.cloud_network: +- name: Create a cloud service to cloud network assignment + networktocode.nautobot.cloud_service_network_assignment: url: http://nautobot.local token: thisIsMyToken cloud_service: Cisco Quantum Service cloud_network: Cisco Quantum Network state: present -- name: Delete a cloud_service to cloud_network assignment - networktocode.nautobot.cloud_network: +- name: Delete a cloud service to cloud network assignment + networktocode.nautobot.cloud_service_network_assignment: url: http://nautobot.local token: thisIsMyToken cloud_service: Cisco Quantum Service diff --git a/tests/integration/targets/latest/tasks/cloud_network_prefix_assignment.yml b/tests/integration/targets/latest/tasks/cloud_network_prefix_assignment.yml index 4d588d4b..86038151 100644 --- a/tests/integration/targets/latest/tasks/cloud_network_prefix_assignment.yml +++ b/tests/integration/targets/latest/tasks/cloud_network_prefix_assignment.yml @@ -11,7 +11,7 @@ block: - set_fact: cloud_network: "{{ lookup('networktocode.nautobot.lookup', 'cloud-networks', api_endpoint=nautobot_url, token=nautobot_token, api_filter='name=CiscoCloudNetwork') }}" - prefix: "{{ lookup('networktocode.nautobot.lookup', 'prefixes', api_endpoint=nautobot_url, token=nautobot_token, api_filter='prefix=10.10.0.0/16') }}" + cloud_prefix: "{{ lookup('networktocode.nautobot.lookup', 'prefixes', api_endpoint=nautobot_url, token=nautobot_token, api_filter='prefix=10.10.0.0/16') }}" - name: "1 - Create cloud network to prefix assignment" networktocode.nautobot.cloud_network_prefix_assignment: @@ -28,7 +28,7 @@ - test_create_one['diff']['before']['state'] == "absent" - test_create_one['diff']['after']['state'] == "present" - test_create_one['cloud_network_prefix_assignment']['cloud_network'] == cloud_network['key'] - - test_create_one['cloud_network_prefix_assignment']['prefix'] == prefix['key'] + - test_create_one['cloud_network_prefix_assignment']['prefix'] == cloud_prefix['key'] - "'created' in test_create_one['msg']" - name: "2 - Duplicate" @@ -45,7 +45,7 @@ - not test_create_idem['changed'] - "'already exists' in test_create_idem['msg']" - test_create_idem['cloud_network_prefix_assignment']['cloud_network'] == cloud_network['key'] - - test_create_idem['cloud_network_prefix_assignment']['prefix'] == prefix['key'] + - test_create_idem['cloud_network_prefix_assignment']['prefix'] == cloud_prefix['key'] - name: "3 - Delete cloud_network_prefix_assignment" networktocode.nautobot.cloud_network_prefix_assignment: @@ -63,7 +63,7 @@ - test_delete['diff']['before']['state'] == "present" - test_delete['diff']['after']['state'] == "absent" - test_delete['cloud_network_prefix_assignment']['cloud_network'] == cloud_network['key'] - - test_delete['cloud_network_prefix_assignment']['prefix'] == prefix['key'] + - test_delete['cloud_network_prefix_assignment']['prefix'] == cloud_prefix['key'] - "'deleted' in test_delete['msg']" - name: "4 - Delete idempotent" From ed06a2d57499ed5e6e253771ea24364bb5df9dcf Mon Sep 17 00:00:00 2001 From: Travis Smith <141754521+tsm1th@users.noreply.github.com> Date: Wed, 6 Nov 2024 20:41:44 +0000 Subject: [PATCH 19/25] Refactored circuit module to fix issue with alias 'provider' and updated cloud resource type tests --- plugins/module_utils/utils.py | 5 +++-- plugins/modules/circuit.py | 6 ++++-- plugins/modules/cloud_resource_type.py | 2 +- .../targets/latest/tasks/cloud_resource_type.yml | 4 ++-- 4 files changed, 10 insertions(+), 7 deletions(-) diff --git a/plugins/module_utils/utils.py b/plugins/module_utils/utils.py index bf1ab0a9..8729e77e 100644 --- a/plugins/module_utils/utils.py +++ b/plugins/module_utils/utils.py @@ -107,6 +107,7 @@ # Used to normalize data for the respective query types used to find endpoints QUERY_TYPES = dict( circuit="cid", + circuit_provider="name", circuit_termination="circuit", circuit_type="name", cloud_network="name", @@ -143,7 +144,6 @@ primary_ip="address", primary_ip4="address", primary_ip6="address", - provider="name", rack="name", rack_group="name", rear_port="name", @@ -165,6 +165,7 @@ # Specifies keys within data that need to be converted to ID and the endpoint to be used when queried CONVERT_TO_ID = { "circuit": "circuits", + "circuit_provider": "providers", "circuit_type": "circuit_types", "circuit_termination": "circuit_terminations", "circuits.circuittermination": "circuit_terminations", @@ -219,7 +220,6 @@ "primary_ip": "ip_addresses", "primary_ip4": "ip_addresses", "primary_ip6": "ip_addresses", - "provider": "providers", "rack": "racks", "rack_group": "rack_groups", "rear_port": "rear_ports", @@ -465,6 +465,7 @@ # This is used to map non-clashing keys to Nautobot API compliant keys to prevent bad logic in code for similar keys but different modules CONVERT_KEYS = { + "circuit_provider": "provider", "cloud_prefix": "prefix", "cloud_provider": "provider", "parent_cloud_network": "parent", diff --git a/plugins/modules/circuit.py b/plugins/modules/circuit.py index e1401ff5..f473d24b 100644 --- a/plugins/modules/circuit.py +++ b/plugins/modules/circuit.py @@ -31,7 +31,9 @@ required: true type: str version_added: "3.0.0" - provider: + circuit_provider: + aliases: + - provider description: - The provider of the circuit required: false @@ -157,7 +159,7 @@ def main(): argument_spec.update( dict( cid=dict(required=True, type="str"), - provider=dict(required=False, type="raw"), + circuit_provider=dict(required=False, type="raw", aliases=["provider"]), circuit_type=dict(required=False, type="raw"), status=dict(required=False, type="raw"), tenant=dict(required=False, type="raw"), diff --git a/plugins/modules/cloud_resource_type.py b/plugins/modules/cloud_resource_type.py index 1a145eb6..fe9d5cb6 100644 --- a/plugins/modules/cloud_resource_type.py +++ b/plugins/modules/cloud_resource_type.py @@ -64,7 +64,7 @@ url: http://nautobot.local token: thisIsMyToken name: Cisco Quantum Network - cloud_provider: Cisco + provider: Cisco content_types: - "cloud.cloudnetwork" state: present diff --git a/tests/integration/targets/latest/tasks/cloud_resource_type.yml b/tests/integration/targets/latest/tasks/cloud_resource_type.yml index 692ee95f..032b9a25 100644 --- a/tests/integration/targets/latest/tasks/cloud_resource_type.yml +++ b/tests/integration/targets/latest/tasks/cloud_resource_type.yml @@ -17,7 +17,7 @@ url: "{{ nautobot_url }}" token: "{{ nautobot_token }}" name: Cisco Quantum Network - cloud_provider: Cisco + provider: Cisco content_types: - "cloud.cloudnetwork" register: test_create_min @@ -80,7 +80,7 @@ url: "{{ nautobot_url }}" token: "{{ nautobot_token }}" name: Cisco Quantum Network Remix - cloud_provider: Cisco + provider: Cisco description: Very fast network reimagined! content_types: - "cloud.cloudnetwork" From d22458999c9caa3731371c83e7cca100ed17bb9a Mon Sep 17 00:00:00 2001 From: Travis Smith <141754521+tsm1th@users.noreply.github.com> Date: Wed, 6 Nov 2024 21:03:07 +0000 Subject: [PATCH 20/25] Added extra_config to cloud_service module and updated test case --- plugins/modules/cloud_service.py | 6 ++++++ tests/integration/targets/latest/tasks/cloud_service.yml | 5 ++++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/plugins/modules/cloud_service.py b/plugins/modules/cloud_service.py index 54937b44..00a5ad69 100644 --- a/plugins/modules/cloud_service.py +++ b/plugins/modules/cloud_service.py @@ -46,6 +46,11 @@ - A cloud account for this service. required: false type: raw + extra_config: + description: + - Arbitrary JSON data to define the extra config. + required: false + type: dict """ EXAMPLES = r""" @@ -105,6 +110,7 @@ def main(): description=dict(required=False, type="str"), cloud_resource_type=dict(required=False, type="raw"), cloud_account=dict(required=False, type="raw"), + extra_config=dict(required=False, type="dict"), ) ) diff --git a/tests/integration/targets/latest/tasks/cloud_service.yml b/tests/integration/targets/latest/tasks/cloud_service.yml index 43391ece..8bd64fc6 100644 --- a/tests/integration/targets/latest/tasks/cloud_service.yml +++ b/tests/integration/targets/latest/tasks/cloud_service.yml @@ -82,6 +82,9 @@ cloud_resource_type: CiscoCloudServiceType cloud_account: CiscoCloudAccount description: Super secreter quantum service! + extra_config: + my_config: + foo: bar register: test_create_max - name: "5 - ASSERT" @@ -99,10 +102,10 @@ assert: that: - cloud_service['value']['name'] == "Cisco Quantum Secreter Service" + - cloud_service['value']['extra_config']['my_config']['foo'] == "bar" vars: cloud_service: "{{ lookup('networktocode.nautobot.lookup', 'cloud-services', api_endpoint=nautobot_url, token=nautobot_token, api_filter='name=\"Cisco Quantum Secreter Service\"') }}" - - name: "6 - Duplicate create with all parameters" networktocode.nautobot.cloud_service: url: "{{ nautobot_url }}" From f0a3cdcefc16ae4ef4eb1bef78219b2dd99d1d7c Mon Sep 17 00:00:00 2001 From: Travis Smith <141754521+tsm1th@users.noreply.github.com> Date: Wed, 6 Nov 2024 21:49:58 +0000 Subject: [PATCH 21/25] Added back module creation after bad merge --- tests/integration/nautobot-populate.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/integration/nautobot-populate.py b/tests/integration/nautobot-populate.py index bfa64ad9..ac5fb474 100755 --- a/tests/integration/nautobot-populate.py +++ b/tests/integration/nautobot-populate.py @@ -669,7 +669,8 @@ def make_nautobot_calls(endpoint, payload): test_module_type = nb.dcim.module_types.get(model="HooverMaxProModel60") test_module_bay = nb.dcim.module_bays.get(name="PowerStrip") power_outlet_modules = [{"module_type": test_module_type.id, "status": "Active", "parent_module_bay": test_module_bay.id}] - + created_power_outlet_modules = make_nautobot_calls(nb.dcim.modules, power_outlet_modules) + # Create role for device interfaces device_interface_roles = [ {"name": "Loop the Network", "color": "111111", "vm_role": False, "content_types": ["dcim.interface"]}, From ff12575c3506f06b9e3280ae90b265e8a6b883d6 Mon Sep 17 00:00:00 2001 From: Travis Smith <141754521+tsm1th@users.noreply.github.com> Date: Wed, 6 Nov 2024 21:52:44 +0000 Subject: [PATCH 22/25] Removed whitespace for linting --- tests/integration/nautobot-populate.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/integration/nautobot-populate.py b/tests/integration/nautobot-populate.py index ac5fb474..bc3e27c4 100755 --- a/tests/integration/nautobot-populate.py +++ b/tests/integration/nautobot-populate.py @@ -670,7 +670,7 @@ def make_nautobot_calls(endpoint, payload): test_module_bay = nb.dcim.module_bays.get(name="PowerStrip") power_outlet_modules = [{"module_type": test_module_type.id, "status": "Active", "parent_module_bay": test_module_bay.id}] created_power_outlet_modules = make_nautobot_calls(nb.dcim.modules, power_outlet_modules) - + # Create role for device interfaces device_interface_roles = [ {"name": "Loop the Network", "color": "111111", "vm_role": False, "content_types": ["dcim.interface"]}, From f5108bfd2588e2e8375ff725d687b5a2b88d9c37 Mon Sep 17 00:00:00 2001 From: Travis Smith <141754521+tsm1th@users.noreply.github.com> Date: Thu, 7 Nov 2024 01:43:23 +0000 Subject: [PATCH 23/25] Added extra_config to cloud service and updated idempotency tests --- plugins/modules/cloud_network.py | 6 ++++++ tests/integration/targets/latest/tasks/cloud_network.yml | 9 ++++++++- .../targets/latest/tasks/cloud_resource_type.yml | 5 +++++ tests/integration/targets/latest/tasks/cloud_service.yml | 5 +++++ 4 files changed, 24 insertions(+), 1 deletion(-) diff --git a/plugins/modules/cloud_network.py b/plugins/modules/cloud_network.py index b2bdbcea..8bd7953a 100644 --- a/plugins/modules/cloud_network.py +++ b/plugins/modules/cloud_network.py @@ -53,6 +53,11 @@ - The parent cloud network this network should be child to required: false type: raw + extra_config: + description: + - Arbitrary JSON data to define the extra config. + required: false + type: dict """ EXAMPLES = r""" @@ -113,6 +118,7 @@ def main(): cloud_resource_type=dict(required=False, type="raw"), cloud_account=dict(required=False, type="raw"), parent_cloud_network=dict(required=False, type="raw", aliases=["parent"]), + extra_config=dict(required=False, type="dict"), ) ) diff --git a/tests/integration/targets/latest/tasks/cloud_network.yml b/tests/integration/targets/latest/tasks/cloud_network.yml index 6b898720..17efddc9 100644 --- a/tests/integration/targets/latest/tasks/cloud_network.yml +++ b/tests/integration/targets/latest/tasks/cloud_network.yml @@ -85,6 +85,9 @@ cloud_account: CiscoCloudAccount parent_cloud_network: CiscoCloudNetwork description: Super faster quantum network! + extra_config: + my_config: + foo: bar register: test_create_max - name: "5 - ASSERT" @@ -98,6 +101,7 @@ - test_create_max['cloud_network']['cloud_account'] == cloud_account['key'] - test_create_max['cloud_network']['description'] == "Super faster quantum network!" - test_create_max['cloud_network']['parent'] == cloud_network['key'] + - test_create_max['cloud_network']['extra_config']['my_config']['foo'] == "bar" - name: "5.1 - ASSERT" assert: @@ -106,7 +110,6 @@ vars: new_cloud_network: "{{ lookup('networktocode.nautobot.lookup', 'cloud-networks', api_endpoint=nautobot_url, token=nautobot_token, api_filter='name=\"Cisco Quantum Faster Network\"') }}" - - name: "6 - Duplicate create with all parameters" networktocode.nautobot.cloud_network: url: "{{ nautobot_url }}" @@ -116,6 +119,9 @@ cloud_account: CiscoCloudAccount parent_cloud_network: CiscoCloudNetwork description: Super faster quantum network! + extra_config: + my_config: + foo: bar register: test_create_max_idem - name: "6 - ASSERT" @@ -124,6 +130,7 @@ - not test_create_max_idem['changed'] - test_create_max_idem['msg'] == "cloud_network Cisco Quantum Faster Network already exists" - test_create_max_idem['cloud_network']['name'] == "Cisco Quantum Faster Network" + - test_create_max_idem['cloud_network']['extra_config']['my_config']['foo'] == "bar" - name: "7 - Delete cloud_network" networktocode.nautobot.cloud_network: diff --git a/tests/integration/targets/latest/tasks/cloud_resource_type.yml b/tests/integration/targets/latest/tasks/cloud_resource_type.yml index 032b9a25..24ac4626 100644 --- a/tests/integration/targets/latest/tasks/cloud_resource_type.yml +++ b/tests/integration/targets/latest/tasks/cloud_resource_type.yml @@ -99,6 +99,7 @@ - test_create_max['cloud_resource_type']['provider'] == cisco_provider['key'] - test_create_max['cloud_resource_type']['description'] == "Very fast network reimagined!" - test_create_max['cloud_resource_type']['content_types'] == ["cloud.cloudnetwork"] + - test_create_max['cloud_resource_type']['config_schema']['my_config']['foo'] == "bar" - name: "5.1 - ASSERT" assert: @@ -116,6 +117,9 @@ description: Very fast network reimagined! content_types: - "cloud.cloudnetwork" + config_schema: + my_config: + foo: bar register: test_create_max_idem - name: "6 - ASSERT" @@ -124,6 +128,7 @@ - not test_create_max_idem['changed'] - test_create_max_idem['msg'] == "cloud_resource_type Cisco Quantum Network Remix already exists" - test_create_max_idem['cloud_resource_type']['name'] == "Cisco Quantum Network Remix" + - test_create_max_idem['cloud_resource_type']['config_schema']['my_config']['foo'] == "bar" - name: "7 - Delete cloud_resource_type" networktocode.nautobot.cloud_resource_type: diff --git a/tests/integration/targets/latest/tasks/cloud_service.yml b/tests/integration/targets/latest/tasks/cloud_service.yml index 8bd64fc6..9f8cb700 100644 --- a/tests/integration/targets/latest/tasks/cloud_service.yml +++ b/tests/integration/targets/latest/tasks/cloud_service.yml @@ -97,6 +97,7 @@ - test_create_max['cloud_service']['cloud_resource_type'] == cloud_resource_type['key'] - test_create_max['cloud_service']['cloud_account'] == cloud_account['key'] - test_create_max['cloud_service']['description'] == "Super secreter quantum service!" + - test_create_max['cloud_service']['extra_config']['my_config']['foo'] == "bar" - name: "5.1 - ASSERT" assert: @@ -114,6 +115,9 @@ cloud_resource_type: CiscoCloudServiceType cloud_account: CiscoCloudAccount description: Super secreter quantum service! + extra_config: + my_config: + foo: bar register: test_create_max_idem - name: "6 - ASSERT" @@ -122,6 +126,7 @@ - not test_create_max_idem['changed'] - test_create_max_idem['msg'] == "cloud_service Cisco Quantum Secreter Service already exists" - test_create_max_idem['cloud_service']['name'] == "Cisco Quantum Secreter Service" + - test_create_max_idem['cloud_service']['extra_config']['my_config']['foo'] == "bar" - name: "7 - Delete cloud_service" networktocode.nautobot.cloud_service: From d949ef59a4a71357a7fd89d408c215117e70a3a8 Mon Sep 17 00:00:00 2001 From: Travis Smith <141754521+tsm1th@users.noreply.github.com> Date: Fri, 8 Nov 2024 01:08:39 +0000 Subject: [PATCH 24/25] Swapped to alias names in all cloud tests --- .../targets/latest/tasks/cloud_account.yml | 14 +++++++------- .../targets/latest/tasks/cloud_network.yml | 4 ++-- .../tasks/cloud_network_prefix_assignment.yml | 8 ++++---- .../targets/latest/tasks/cloud_resource_type.yml | 2 +- 4 files changed, 14 insertions(+), 14 deletions(-) diff --git a/tests/integration/targets/latest/tasks/cloud_account.yml b/tests/integration/targets/latest/tasks/cloud_account.yml index 0fedbc65..2b0fedba 100644 --- a/tests/integration/targets/latest/tasks/cloud_account.yml +++ b/tests/integration/targets/latest/tasks/cloud_account.yml @@ -11,14 +11,14 @@ block: - set_fact: cisco_provider: "{{ lookup('networktocode.nautobot.lookup', 'manufacturers', api_endpoint=nautobot_url, token=nautobot_token, api_filter='name=Cisco') }}" - secrets_group: "{{ lookup('networktocode.nautobot.lookup', 'secrets-groups', api_endpoint=nautobot_url, token=nautobot_token, api_filter='name=\"Test Secrets Group\"') }}" + cloud_secrets_group: "{{ lookup('networktocode.nautobot.lookup', 'secrets-groups', api_endpoint=nautobot_url, token=nautobot_token, api_filter='name=\"Test Secrets Group\"') }}" - name: "1 - Create cloud account within Nautobot with only required information" networktocode.nautobot.cloud_account: url: "{{ nautobot_url }}" token: "{{ nautobot_token }}" name: Cisco Quantum Account - cloud_provider: Cisco + provider: Cisco account_number: "123456" register: test_create_min @@ -80,10 +80,10 @@ url: "{{ nautobot_url }}" token: "{{ nautobot_token }}" name: Cisco Quantum Not So Root Account - cloud_provider: Cisco + provider: Cisco description: Rooty but not the rootest! account_number: "654321" - secrets_group: "{{ secrets_group['key'] }}" + secrets_group: "{{ cloud_secrets_group['key'] }}" register: test_create_max - name: "5 - ASSERT" @@ -96,7 +96,7 @@ - test_create_max['cloud_account']['provider'] == cisco_provider['key'] - test_create_max['cloud_account']['description'] == "Rooty but not the rootest!" - test_create_max['cloud_account']['account_number'] == "654321" - - test_create_max['cloud_account']['secrets_group'] == secrets_group['key'] + - test_create_max['cloud_account']['secrets_group'] == cloud_secrets_group['key'] - name: "5.1 - ASSERT" assert: @@ -111,10 +111,10 @@ url: "{{ nautobot_url }}" token: "{{ nautobot_token }}" name: Cisco Quantum Not So Root Account - cloud_provider: Cisco + provider: Cisco description: Rooty but not the rootest! account_number: "654321" - secrets_group: "{{ secrets_group['key'] }}" + secrets_group: "{{ cloud_secrets_group['key'] }}" register: test_create_max_idem - name: "6 - ASSERT" diff --git a/tests/integration/targets/latest/tasks/cloud_network.yml b/tests/integration/targets/latest/tasks/cloud_network.yml index 17efddc9..9a246b1a 100644 --- a/tests/integration/targets/latest/tasks/cloud_network.yml +++ b/tests/integration/targets/latest/tasks/cloud_network.yml @@ -83,7 +83,7 @@ name: Cisco Quantum Faster Network cloud_resource_type: CiscoCloudNetworkType cloud_account: CiscoCloudAccount - parent_cloud_network: CiscoCloudNetwork + parent: CiscoCloudNetwork description: Super faster quantum network! extra_config: my_config: @@ -117,7 +117,7 @@ name: Cisco Quantum Faster Network cloud_resource_type: CiscoCloudNetworkType cloud_account: CiscoCloudAccount - parent_cloud_network: CiscoCloudNetwork + parent: CiscoCloudNetwork description: Super faster quantum network! extra_config: my_config: diff --git a/tests/integration/targets/latest/tasks/cloud_network_prefix_assignment.yml b/tests/integration/targets/latest/tasks/cloud_network_prefix_assignment.yml index 86038151..15c2ec00 100644 --- a/tests/integration/targets/latest/tasks/cloud_network_prefix_assignment.yml +++ b/tests/integration/targets/latest/tasks/cloud_network_prefix_assignment.yml @@ -18,7 +18,7 @@ url: "{{ nautobot_url }}" token: "{{ nautobot_token }}" cloud_network: CiscoCloudNetwork - cloud_prefix: 10.10.0.0/16 + prefix: 10.10.0.0/16 register: test_create_one - name: "1 - ASSERT" @@ -36,7 +36,7 @@ url: "{{ nautobot_url }}" token: "{{ nautobot_token }}" cloud_network: CiscoCloudNetwork - cloud_prefix: 10.10.0.0/16 + prefix: 10.10.0.0/16 register: test_create_idem - name: "2 - ASSERT" @@ -52,7 +52,7 @@ url: "{{ nautobot_url }}" token: "{{ nautobot_token }}" cloud_network: CiscoCloudNetwork - cloud_prefix: 10.10.0.0/16 + prefix: 10.10.0.0/16 state: absent register: test_delete @@ -71,7 +71,7 @@ url: "{{ nautobot_url }}" token: "{{ nautobot_token }}" cloud_network: CiscoCloudNetwork - cloud_prefix: 10.10.0.0/16 + prefix: 10.10.0.0/16 state: absent register: test_delete_idem diff --git a/tests/integration/targets/latest/tasks/cloud_resource_type.yml b/tests/integration/targets/latest/tasks/cloud_resource_type.yml index 24ac4626..c87f3b27 100644 --- a/tests/integration/targets/latest/tasks/cloud_resource_type.yml +++ b/tests/integration/targets/latest/tasks/cloud_resource_type.yml @@ -113,7 +113,7 @@ url: "{{ nautobot_url }}" token: "{{ nautobot_token }}" name: Cisco Quantum Network Remix - cloud_provider: Cisco + provider: Cisco description: Very fast network reimagined! content_types: - "cloud.cloudnetwork" From 269643f4980bbc9f77853b90c93645537ba42edb Mon Sep 17 00:00:00 2001 From: Travis Smith <141754521+tsm1th@users.noreply.github.com> Date: Mon, 11 Nov 2024 18:14:51 +0000 Subject: [PATCH 25/25] Updated example in cloud account module --- plugins/modules/cloud_account.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/modules/cloud_account.py b/plugins/modules/cloud_account.py index 881746d7..4afae12f 100644 --- a/plugins/modules/cloud_account.py +++ b/plugins/modules/cloud_account.py @@ -62,7 +62,7 @@ url: http://nautobot.local token: thisIsMyToken name: Cisco Quantum Account - cloud_provider: Cisco + provider: Cisco description: A quantum account for Cisco account_number: "654321" secrets_group: "{{ my_secrets_group['key'] }}"