diff --git a/plugins/module_utils/dcim.py b/plugins/module_utils/dcim.py index 0e3bbf73..37b765b6 100644 --- a/plugins/module_utils/dcim.py +++ b/plugins/module_utils/dcim.py @@ -31,6 +31,7 @@ NB_LOCATIONS = "locations" NB_LOCATION_TYPES = "location_types" NB_MANUFACTURERS = "manufacturers" +NB_NAMESPACES = "namespaces" NB_PLATFORMS = "platforms" NB_POWER_FEEDS = "power_feeds" NB_POWER_OUTLETS = "power_outlets" diff --git a/plugins/modules/namespace.py b/plugins/modules/namespace.py new file mode 100644 index 00000000..96a5ba38 --- /dev/null +++ b/plugins/modules/namespace.py @@ -0,0 +1,114 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# Copyright: (c) 2023, 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: namespace +short_description: Creates or removes namespaces from Nautobot +description: + - Creates or removes namespaces from Nautobot +notes: + - Tags should be defined as a YAML list + - This should be ran with connection C(local) and hosts C(localhost) +author: + - Joe Wesch (@joewesch) +requirements: + - pynautobot +version_added: "5.1.0" +extends_documentation_fragment: + - networktocode.nautobot.fragments.base + - networktocode.nautobot.fragments.tags + - networktocode.nautobot.fragments.custom_fields +options: + name: + description: + - The name of the namespace + required: true + type: str + version_added: "5.1.0" + description: + description: + - The description of the namespace + required: false + type: str + version_added: "5.1.0" + location: + description: + - The location of the namespace + required: false + type: raw + version_added: "5.1.0" +""" + +EXAMPLES = r""" +--- +- name: Create a namespace + networktocode.nautobot.namespace: + url: http://nautobot.local + token: thisIsMyToken + name: My Namespace + location: My Location + description: My Description + tags: + - tag1 + - tag2 + custom_fields: + my_custom_field: my_value + state: present + +- name: Delete a namespace + networktocode.nautobot.namespace: + url: http://nautobot.local + token: thisIsMyToken + name: My Namespace + state: absent +""" + +RETURN = r""" +namespace: + 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 +from ansible_collections.networktocode.nautobot.plugins.module_utils.dcim import ( + NautobotDcimModule, + NB_NAMESPACES, +) +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( + name=dict(required=True, type="str"), + description=dict(required=False, type="str"), + location=dict(required=False, type="raw"), + tags=dict(required=False, type="list", elements="raw"), + custom_fields=dict(required=False, type="dict"), + ) + ) + + module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True) + namespace = NautobotDcimModule(module, NB_NAMESPACES) + namespace.run() + + +if __name__ == "__main__": # pragma: no cover + main() diff --git a/tests/integration/targets/latest/tasks/main.yml b/tests/integration/targets/latest/tasks/main.yml index fe669412..80784d29 100644 --- a/tests/integration/targets/latest/tasks/main.yml +++ b/tests/integration/targets/latest/tasks/main.yml @@ -511,3 +511,12 @@ - custom_field_choice tags: - custom_field_choice + +- name: "PYNAUTOBOT_NAMESPACE TESTS" + include_tasks: + file: "namespace.yml" + apply: + tags: + - namespace + tags: + - namespace diff --git a/tests/integration/targets/latest/tasks/namespace.yml b/tests/integration/targets/latest/tasks/namespace.yml new file mode 100644 index 00000000..f9fd8380 --- /dev/null +++ b/tests/integration/targets/latest/tasks/namespace.yml @@ -0,0 +1,124 @@ +--- +## +## +### PYNAUTOBOT_DNAMESPACE +## +## +- set_fact: + test_location: "{{ lookup('networktocode.nautobot.lookup', 'locations', api_endpoint=nautobot_url, token=nautobot_token, api_filter='name=\"Child Test Location\" parent=\"Parent Test Location\"') }}" + +- name: "1 - Create namespace within Nautobot with only required information" + networktocode.nautobot.namespace: + url: "{{ nautobot_url }}" + token: "{{ nautobot_token }}" + name: Test Namespace + 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['namespace']['name'] == "Test Namespace" + - test_create_min['msg'] == "namespace Test Namespace created" + +- name: "2 - Duplicate" + networktocode.nautobot.namespace: + url: "{{ nautobot_url }}" + token: "{{ nautobot_token }}" + name: Test Namespace + register: test_create_idem + +- name: "2 - ASSERT" + assert: + that: + - not test_create_idem['changed'] + - test_create_idem['msg'] == "namespace Test Namespace already exists" + - test_create_idem['namespace']['name'] == "Test Namespace" + +- name: "3 - Update namespace" + networktocode.nautobot.namespace: + url: "{{ nautobot_url }}" + token: "{{ nautobot_token }}" + name: Test Namespace + description: Test Namespace Description + register: test_update + +- name: "3 - ASSERT" + assert: + that: + - test_update is changed + - test_update['diff']['before']['description'] == "" + - test_update['diff']['after']['description'] == "Test Namespace Description" + +- name: "4 - Create namespace with all parameters" + networktocode.nautobot.namespace: + url: "{{ nautobot_url }}" + token: "{{ nautobot_token }}" + name: Test Namespace 2 + description: Test Namespace Description 2 + location: + name: Child Test Location + parent: Parent Test Location + register: test_create_max + +- name: "4 - 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['namespace']['name'] == "Test Namespace 2" + - test_create_max['namespace']['description'] == "Test Namespace Description 2" + - test_create_max['namespace']['location'] == test_location['key'] + - test_create_max['msg'] == "namespace Test Namespace 2 created" + +- name: "5 - Duplicate create with all parameters" + networktocode.nautobot.namespace: + url: "{{ nautobot_url }}" + token: "{{ nautobot_token }}" + name: Test Namespace 2 + description: Test Namespace Description 2 + location: + name: Child Test Location + parent: Parent Test Location + register: test_create_max_idem + +- name: "5 - ASSERT" + assert: + that: + - not test_create_max_idem['changed'] + - test_create_max_idem['msg'] == "namespace Test Namespace 2 already exists" + - test_create_max_idem['namespace']['name'] == "Test Namespace 2" + +- name: "6 - Delete namespace" + networktocode.nautobot.namespace: + url: "{{ nautobot_url }}" + token: "{{ nautobot_token }}" + name: Test Namespace 2 + state: absent + register: test_delete + +- name: "6 - ASSERT" + assert: + that: + - test_delete is changed + - test_delete['diff']['before']['state'] == "present" + - test_delete['diff']['after']['state'] == "absent" + - test_delete['namespace']['name'] == "Test Namespace 2" + - "'deleted' in test_delete['msg']" + +- name: "7 - Delete idempotent" + networktocode.nautobot.namespace: + url: "{{ nautobot_url }}" + token: "{{ nautobot_token }}" + name: Test Namespace 2 + state: absent + register: test_delete_idem + +- name: "7 - ASSERT" + assert: + that: + - not test_delete_idem['changed'] + - "'already absent' in test_delete_idem['msg']"