diff --git a/plugins/lookup/lookup.py b/plugins/lookup/lookup.py index 5928b39c..5fa24f63 100644 --- a/plugins/lookup/lookup.py +++ b/plugins/lookup/lookup.py @@ -209,6 +209,9 @@ def get_endpoint(nautobot, term): "locations": {"endpoint": nautobot.dcim.locations}, "location-types": {"endpoint": nautobot.dcim.location_types}, "manufacturers": {"endpoint": nautobot.dcim.manufacturers}, + "module-bay-templates": {"endpoint": nautobot.dcim.module_bay_templates}, + "module-bays": {"endpoint": nautobot.dcim.module_bays}, + "module-types": {"endpoint": nautobot.dcim.module_types}, "modules": {"endpoint": nautobot.dcim.modules}, "namespaces": {"endpoint": nautobot.ipam.namespaces}, "object-changes": {"endpoint": nautobot.extras.object_changes}, diff --git a/plugins/module_utils/dcim.py b/plugins/module_utils/dcim.py index 9dce4313..4a253e92 100644 --- a/plugins/module_utils/dcim.py +++ b/plugins/module_utils/dcim.py @@ -32,6 +32,10 @@ NB_LOCATIONS = "locations" NB_LOCATION_TYPES = "location_types" NB_MANUFACTURERS = "manufacturers" +NB_MODULE_BAY_TEMPLATES = "module_bay_templates" +NB_MODULE_BAYS = "module_bays" +NB_MODULE_TYPES = "module_types" +NB_MODULES = "modules" NB_NAMESPACES = "namespaces" NB_PLATFORMS = "platforms" NB_POWER_FEEDS = "power_feeds" @@ -69,6 +73,10 @@ def run(self): - interface_templates - inventory_items - manufacturers + - module_bay_templates + - module_bays + - module_types + - modules - platforms - power_feeds - power_outlets @@ -133,6 +141,19 @@ def run(self): termination_b_name, ) + elif endpoint_name == "module": + name = self.module.params["module_type"] + if isinstance(self.module.params["parent_module_bay"], str): + name = f"{self.module.params['parent_module_bay']} > {name}" + elif isinstance(self.module.params["parent_module_bay"], dict): + name = f"{self.module.params['parent_module_bay'].get('name')} > {name}" + if self.module.params["parent_module_bay"].get("parent_device"): + name = f"{self.module.params['parent_module_bay'].get('parent_device')} > {name}" + elif self.module.params["parent_module_bay"].get("parent_module"): + name = f"{self.module.params['parent_module_bay'].get('parent_module')} > {name}" + elif isinstance(self.module.params["location"], dict): + name = f"{self.module.params['location'].get('parent', '—')} > {self.module.params['location'].get('name')} > {name}" + # Make color params lowercase if data.get("color"): data["color"] = data["color"].lower() diff --git a/plugins/module_utils/utils.py b/plugins/module_utils/utils.py index bde7582c..816047c8 100644 --- a/plugins/module_utils/utils.py +++ b/plugins/module_utils/utils.py @@ -61,6 +61,9 @@ "locations", "location_types", "manufacturers", + "module_bay_templates", + "module_bays", + "module_types", "modules", "platforms", "power_feeds", @@ -131,6 +134,9 @@ location_type="name", manufacturer="name", master="name", + module_bay_template="name", + module_bay="name", + module_type="model", nat_inside="address", nat_outside="address", parent_cloud_network="name", @@ -205,12 +211,18 @@ "location": "locations", "location_type": "location_types", "manufacturer": "manufacturers", + "module_bay_template": "module_bay_templates", + "module_bay": "module_bays", + "module_type": "module_types", "module": "modules", "master": "devices", "nat_inside": "ip_addresses", "nat_outside": "ip_addresses", "namespace": "namespaces", "platform": "platforms", + "parent_device": "devices", + "parent_module_bay": "module_bays", + "parent_module": "modules", "parent_rack_group": "rack_groups", "parent_cloud_network": "cloud_networks", "parent_location": "locations", @@ -286,6 +298,9 @@ "locations": "location", "location_types": "location_type", "manufacturers": "manufacturer", + "module_bay_templates": "module_bay_template", + "module_bays": "module_bay", + "module_types": "module_type", "modules": "module", "namespaces": "namespace", "permissions": "permission", @@ -375,8 +390,14 @@ "location_type": set(["name"]), "manufacturer": set(["name"]), "master": set(["name"]), + "module_bay_template": set(["name"]), + "module_bay": set(["name", "parent_device", "parent_module"]), + "module_type": set(["model"]), + "module": set(["module_type", "parent_module_bay", "location"]), "namespace": set(["name"]), "nat_inside": set(["namespace", "address"]), + "parent_module_bay": set(["name", "parent_device", "parent_module"]), + "parent_module": set(["module_type", "parent_module_bay"]), "parent_rack_group": set(["name"]), "parent_tenant_group": set(["name"]), "permission": set(["name"]), diff --git a/plugins/modules/module.py b/plugins/modules/module.py new file mode 100644 index 00000000..97854f38 --- /dev/null +++ b/plugins/modules/module.py @@ -0,0 +1,170 @@ +#!/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: module +short_description: Create, update or delete modules within Nautobot +description: + - Creates, updates or removes modules 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) +version_added: "5.4.0" +extends_documentation_fragment: + - networktocode.nautobot.fragments.base + - networktocode.nautobot.fragments.tags + - networktocode.nautobot.fragments.custom_fields +options: + module_type: + description: + - The module type of the module + required: true + type: raw + serial: + description: + - The serial number of the module + required: false + type: str + asset_tag: + description: + - The asset tag of the module + required: false + type: str + role: + description: + - The role of the module + required: false + type: raw + status: + description: + - The status of the module + - Required if I(state=present) and the device does not exist yet + required: false + type: raw + tenant: + description: + - The tenant of the module + required: false + type: raw + location: + description: + - The location of the module + required: false + type: raw + parent_module_bay: + description: + - The parent module bay of the module + required: false + type: raw +""" + +EXAMPLES = r""" +- name: Create a module in module bay + networktocode.nautobot.module: + url: http://nautobot.local + token: thisIsMyToken + module_type: HooverMaxProModel60 + parent_module_bay: + name: PowerStripTwo + parent_device: test100 + status: Active + state: present + +- name: Create a module at location + networktocode.nautobot.module: + url: http://nautobot.local + token: thisIsMyToken + module_type: HooverMaxProModel60 + location: + name: "Child Test Location" + parent: "Parent Test Location" + serial: "654321" + asset_tag: "123456" + role: Test Module Role + status: Active + tenant: Test Tenant + state: present + +- name: Delete a module + networktocode.nautobot.module: + url: http://nautobot.local + token: thisIsMyToken + module_type: HooverMaxProModel60 + parent_module_bay: + name: PowerStripTwo + parent_device: test100 + state: absent +""" + +RETURN = r""" +module: + 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.dcim import ( + NautobotDcimModule, + NB_MODULES, +) +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( + module_type=dict(required=True, type="raw"), + serial=dict(required=False, type="str"), + asset_tag=dict(required=False, type="str"), + role=dict(required=False, type="raw"), + status=dict(required=False, type="raw"), + tenant=dict(required=False, type="raw"), + location=dict(required=False, type="raw"), + parent_module_bay=dict(required=False, type="raw"), + ) + ) + + required_one_of = [ + ("location", "parent_module_bay"), + ] + mutually_exclusive = [ + ("location", "parent_module_bay"), + ] + module = AnsibleModule( + argument_spec=argument_spec, + supports_check_mode=True, + required_one_of=required_one_of, + mutually_exclusive=mutually_exclusive, + ) + + nb_module = NautobotDcimModule(module, NB_MODULES) + nb_module.run() + + +if __name__ == "__main__": # pragma: no cover + main() diff --git a/plugins/modules/module_bay.py b/plugins/modules/module_bay.py new file mode 100644 index 00000000..0da93f68 --- /dev/null +++ b/plugins/modules/module_bay.py @@ -0,0 +1,152 @@ +#!/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: module_bay +short_description: Create, update or delete module bays within Nautobot +description: + - Creates, updates or removes module bays 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) +version_added: "5.4.0" +extends_documentation_fragment: + - networktocode.nautobot.fragments.base + - networktocode.nautobot.fragments.tags + - networktocode.nautobot.fragments.custom_fields +options: + parent_device: + description: + - The parent device of the module bay + required: false + type: raw + parent_module: + description: + - The parent module of the module bay + required: false + type: raw + name: + description: + - The name of the module bay + required: true + type: str + label: + description: + - The label of the module bay + required: false + type: str + position: + description: + - The position of the module bay within the device or module + required: false + type: str + description: + description: + - The description of the module bay + required: false + type: str +""" + +EXAMPLES = r""" +- name: Create a module bay inside a device + networktocode.nautobot.module_bay: + url: http://nautobot.local + token: thisIsMyToken + parent_device: test100 + name: Watch Bay + label: watchbay + position: "42" + description: The bay of watches + state: present + +- name: Create a module bay inside a module + networktocode.nautobot.module_bay: + url: http://nautobot.local + token: thisIsMyToken + parent_module: + module_type: HooverMaxProModel60 + parent_module_bay: "{{ some_module_bay['key'] }}" + name: Fixing Good + label: FiXiNgGoOd + position: "321" + description: Good Fixing is better than Bad Breaking + state: present + +- name: Delete a module bay + networktocode.nautobot.module_bay: + url: http://nautobot.local + token: thisIsMyToken + parent_device: test100 + name: Watch Bay + state: absent +""" + +RETURN = r""" +module_bay: + 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.dcim import ( + NautobotDcimModule, + NB_MODULE_BAYS, +) +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( + parent_device=dict(required=False, type="raw"), + parent_module=dict(required=False, type="raw"), + name=dict(required=True, type="str"), + label=dict(required=False, type="str"), + position=dict(required=False, type="str"), + description=dict(required=False, type="str"), + ) + ) + + required_one_of = [ + ("parent_device", "parent_module"), + ] + mutually_exclusive = [ + ("parent_device", "parent_module"), + ] + module = AnsibleModule( + argument_spec=argument_spec, + supports_check_mode=True, + required_one_of=required_one_of, + mutually_exclusive=mutually_exclusive, + ) + module_bay = NautobotDcimModule(module, NB_MODULE_BAYS) + module_bay.run() + + +if __name__ == "__main__": # pragma: no cover + main() diff --git a/plugins/modules/module_bay_template.py b/plugins/modules/module_bay_template.py new file mode 100644 index 00000000..b4c86064 --- /dev/null +++ b/plugins/modules/module_bay_template.py @@ -0,0 +1,139 @@ +#!/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: module_bay_template +short_description: Create, update or delete module bay templates within Nautobot +description: + - Creates, updates or removes module bay templates 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) +version_added: "5.4.0" +extends_documentation_fragment: + - networktocode.nautobot.fragments.base + - networktocode.nautobot.fragments.tags + - networktocode.nautobot.fragments.custom_fields +options: + device_type: + description: + - The device type of the module bay template + required: false + type: raw + module_type: + description: + - The module type of the module bay template + required: false + type: raw + name: + description: + - The name of the module bay template + required: true + type: str + label: + description: + - The label of the module bay template + required: false + type: str + position: + description: + - The position of the module bay within the device or module + required: false + type: str + description: + description: + - The description of the module bay template + required: false + type: str +""" + +EXAMPLES = r""" +- name: Create a module bay template + networktocode.nautobot.module_bay_template: + url: http://nautobot.local + token: thisIsMyToken + module_type: HooverMaxProModel60 + name: Edward Galbraith + label: Br Ba + position: "1" + description: Granite State + state: present + +- name: Delete a module bay template + networktocode.nautobot.module_bay_template: + url: http://nautobot.local + token: thisIsMyToken + module_type: HooverMaxProModel60 + name: Edward Galbraith + state: absent +""" + +RETURN = r""" +module_bay_template: + 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.dcim import ( + NautobotDcimModule, + NB_MODULE_BAY_TEMPLATES, +) +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( + device_type=dict(required=False, type="raw"), + module_type=dict(required=False, type="raw"), + name=dict(required=True, type="str"), + label=dict(required=False, type="str"), + position=dict(required=False, type="str"), + description=dict(required=False, type="str"), + ) + ) + + required_one_of = [ + ("device_type", "module_type"), + ] + mutually_exclusive = [ + ("device_type", "module_type"), + ] + module = AnsibleModule( + argument_spec=argument_spec, + supports_check_mode=True, + required_one_of=required_one_of, + mutually_exclusive=mutually_exclusive, + ) + module_bay_template = NautobotDcimModule(module, NB_MODULE_BAY_TEMPLATES) + module_bay_template.run() + + +if __name__ == "__main__": # pragma: no cover + main() diff --git a/plugins/modules/module_type.py b/plugins/modules/module_type.py new file mode 100644 index 00000000..d1bf8e68 --- /dev/null +++ b/plugins/modules/module_type.py @@ -0,0 +1,114 @@ +#!/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: module_type +short_description: Create, update or delete module types within Nautobot +description: + - Creates, updates or removes module types 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) +version_added: "5.4.0" +extends_documentation_fragment: + - networktocode.nautobot.fragments.base + - networktocode.nautobot.fragments.tags + - networktocode.nautobot.fragments.custom_fields +options: + manufacturer: + description: + - The manufacturer of the module type + - Required if I(state=present) and the module type does not exist yet + required: false + type: raw + model: + description: + - The model of the module type + required: true + type: raw + part_number: + description: + - The part number of the module type + required: false + type: str + comments: + description: + - Comments that may include additional information in regards to the module type + required: false + type: str +""" + +EXAMPLES = r""" +- name: Create a module type + networktocode.nautobot.module_type: + url: http://nautobot.local + token: thisIsMyToken + model: HooverMaxProModel60 + manufacturer: Best Quality Vacuum + state: present + +- name: Delete a module type + networktocode.nautobot.module_type: + url: http://nautobot.local + token: thisIsMyToken + model: HooverMaxProModel60 + state: absent +""" + +RETURN = r""" +module_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.dcim import ( + NautobotDcimModule, + NB_MODULE_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( + manufacturer=dict(required=False, type="raw"), + model=dict(required=True, type="raw"), + part_number=dict(required=False, type="str"), + comments=dict(required=False, type="str"), + ) + ) + + module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True) + + module_type = NautobotDcimModule(module, NB_MODULE_TYPES) + module_type.run() + + +if __name__ == "__main__": # pragma: no cover + main() diff --git a/tests/integration/nautobot-populate.py b/tests/integration/nautobot-populate.py index bc3e27c4..c7bcea11 100755 --- a/tests/integration/nautobot-populate.py +++ b/tests/integration/nautobot-populate.py @@ -119,6 +119,8 @@ def make_nautobot_calls(endpoint, payload): if nautobot_version >= version.parse("2.2"): location_content_types.append("dcim.controller") +if nautobot_version >= version.parse("2.3"): + location_content_types.append("dcim.module") location_types = [{"name": "My Parent Location Type", "content_types": location_content_types, "nestable": True}] created_location_types = make_nautobot_calls(nb.dcim.location_types, location_types) @@ -267,6 +269,8 @@ def make_nautobot_calls(endpoint, payload): if nautobot_version >= version.parse("2.2"): device_roles.append({"name": "Test Controller Role", "color": "e91e65", "vm_role": False, "content_types": ["dcim.controller"]}) +if nautobot_version >= version.parse("2.3"): + device_roles.append({"name": "Test Module Role", "color": "795548", "vm_role": False, "content_types": ["dcim.module"]}) created_device_roles = make_nautobot_calls(nb.extras.roles, device_roles) @@ -662,7 +666,7 @@ def make_nautobot_calls(endpoint, payload): created_power_outlet_module_types = make_nautobot_calls(nb.dcim.module_types, power_outlet_module_types) # Create a module bay - power_outlet_module_bays = [{"parent_device": test100.id, "name": "PowerStrip"}] + power_outlet_module_bays = [{"parent_device": test100.id, "name": "PowerStrip"}, {"parent_device": test100.id, "name": "PowerStripTwo"}] created_power_outlet_module_bays = make_nautobot_calls(nb.dcim.module_bays, power_outlet_module_bays) # Assign module type to module bay diff --git a/tests/integration/targets/latest/tasks/main.yml b/tests/integration/targets/latest/tasks/main.yml index 986699a7..3905ca6c 100644 --- a/tests/integration/targets/latest/tasks/main.yml +++ b/tests/integration/targets/latest/tasks/main.yml @@ -591,6 +591,42 @@ tags: - controller +- name: "PYNAUTOBOT_MODULE_TYPE TESTS" + include_tasks: + file: "module_type.yml" + apply: + tags: + - module_type + tags: + - module_type + +- name: "PYNAUTOBOT_MODULE_BAY_TEMPLATE TESTS" + include_tasks: + file: "module_bay_template.yml" + apply: + tags: + - module_bay_template + tags: + - module_bay_template + +- name: "PYNAUTOBOT_MODULE_BAY TESTS" + include_tasks: + file: "module_bay.yml" + apply: + tags: + - module_bay + tags: + - module_bay + +- name: "PYNAUTOBOT_MODULE TESTS" + include_tasks: + file: "module.yml" + apply: + tags: + - module + tags: + - module + - name: "PYNAUTOBOT_CLOUD_ACCOUNT TESTS" include_tasks: file: "cloud_account.yml" @@ -643,4 +679,4 @@ tags: - cloud_network_prefix_assignment tags: - - cloud_network_prefix_assignment \ No newline at end of file + - cloud_network_prefix_assignment diff --git a/tests/integration/targets/latest/tasks/module.yml b/tests/integration/targets/latest/tasks/module.yml new file mode 100644 index 00000000..6e0760e7 --- /dev/null +++ b/tests/integration/targets/latest/tasks/module.yml @@ -0,0 +1,203 @@ +--- +## +## +### PYNAUTOBOT_MODULE +## +## +- name: "NAUTOBOT 2.3+ MODULE TESTS" + when: + - "nautobot_version is version('2.3', '>=')" + block: + - set_fact: + test_module_type: '{{ lookup(''networktocode.nautobot.lookup'', ''module-types'', api_endpoint=nautobot_url, token=nautobot_token, api_filter=''model="HooverMaxProModel60"'') }}' + test_module_role: "{{ lookup('networktocode.nautobot.lookup', 'roles', api_endpoint=nautobot_url, token=nautobot_token, api_filter='name=\"Test Module Role\"') }}" + test_module_bay: '{{ lookup(''networktocode.nautobot.lookup'', ''module-bays'', api_endpoint=nautobot_url, token=nautobot_token, api_filter=''name="PowerStripTwo"'') }}' + test_module_status: "{{ lookup('networktocode.nautobot.lookup', 'statuses', api_endpoint=nautobot_url, token=nautobot_token, api_filter='name=Active') }}" + test_module_tenant: "{{ lookup('networktocode.nautobot.lookup', 'tenants', api_endpoint=nautobot_url, token=nautobot_token, api_filter='name=\"Test Tenant\"') }}" + test_module_child_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 module with minimum information" + networktocode.nautobot.module: + url: "{{ nautobot_url }}" + token: "{{ nautobot_token }}" + module_type: HooverMaxProModel60 + parent_module_bay: + name: PowerStripTwo + parent_device: test100 + status: Active + state: present + register: test_one + + - name: "1 - ASSERT" + assert: + that: + - test_one is changed + - test_one['diff']['before']['state'] == "absent" + - test_one['diff']['after']['state'] == "present" + - test_one['module']['module_type'] == test_module_type['key'] + - test_one['module']['parent_module_bay'] == test_module_bay['key'] + - test_one['module']['status'] == test_module_status['key'] + - test_one['msg'] == "module test100 > PowerStripTwo > HooverMaxProModel60 created" + + - name: "2 - Create module with minimum information idempotent" + networktocode.nautobot.module: + url: "{{ nautobot_url }}" + token: "{{ nautobot_token }}" + module_type: HooverMaxProModel60 + parent_module_bay: + name: PowerStripTwo + parent_device: test100 + status: Active + state: present + register: test_two + + - name: "2 - ASSERT" + assert: + that: + - not test_two['changed'] + - test_two['module']['module_type'] == test_module_type['key'] + - test_two['module']['parent_module_bay'] == test_module_bay['key'] + - test_two['module']['status'] == test_module_status['key'] + - test_two['msg'] == "module test100 > PowerStripTwo > HooverMaxProModel60 already exists" + + - name: "3 - Update module" + networktocode.nautobot.module: + url: "{{ nautobot_url }}" + token: "{{ nautobot_token }}" + module_type: HooverMaxProModel60 + parent_module_bay: + name: PowerStripTwo + parent_device: test100 + serial: "123456" + asset_tag: "654321" + state: present + register: test_three + + - name: "3 - ASSERT" + assert: + that: + - test_three is changed + - test_three['diff']['after']['serial'] == "123456" + - test_three['diff']['after']['asset_tag'] == "654321" + - test_three['module']['module_type'] == test_module_type['key'] + - test_three['module']['parent_module_bay'] == test_module_bay['key'] + - test_three['module']['status'] == test_module_status['key'] + - test_three['module']['serial'] == "123456" + - test_three['module']['asset_tag'] == "654321" + - test_three['msg'] == "module test100 > PowerStripTwo > HooverMaxProModel60 updated" + + - name: "4 - Update idempotent" + networktocode.nautobot.module: + url: "{{ nautobot_url }}" + token: "{{ nautobot_token }}" + module_type: HooverMaxProModel60 + parent_module_bay: + name: PowerStripTwo + parent_device: test100 + serial: "123456" + asset_tag: "654321" + state: present + register: test_four + + - name: "4 - ASSERT" + assert: + that: + - not test_four['changed'] + - test_four['module']['module_type'] == test_module_type['key'] + - test_four['module']['parent_module_bay'] == test_module_bay['key'] + - test_four['msg'] == "module test100 > PowerStripTwo > HooverMaxProModel60 already exists" + + - name: "5 - Create module with all params" + networktocode.nautobot.module: + url: "{{ nautobot_url }}" + token: "{{ nautobot_token }}" + module_type: HooverMaxProModel60 + location: + name: "Child Test Location" + parent: "Parent Test Location" + serial: "654321" + asset_tag: "123456" + role: Test Module Role + status: Active + tenant: Test Tenant + state: present + register: test_five + + - name: "5 - ASSERT" + assert: + that: + - test_five is changed + - test_five['module']['module_type'] == test_module_type['key'] + - test_five['module']['location'] == test_module_child_location['key'] + - test_five['module']['serial'] == "654321" + - test_five['module']['asset_tag'] == "123456" + - test_five['module']['role'] == test_module_role['key'] + - test_five['module']['status'] == test_module_status['key'] + - test_five['module']['tenant'] == test_module_tenant['key'] + - test_five['msg'] == "module Parent Test Location > Child Test Location > HooverMaxProModel60 created" + + - name: "6 - Create module with all params idempotent" + networktocode.nautobot.module: + url: "{{ nautobot_url }}" + token: "{{ nautobot_token }}" + module_type: HooverMaxProModel60 + location: + name: "Child Test Location" + parent: "Parent Test Location" + serial: "654321" + asset_tag: "123456" + role: Test Module Role + status: Active + tenant: Test Tenant + state: present + register: test_six + + - name: "6 - ASSERT" + assert: + that: + - not test_six['changed'] + - test_six['module']['module_type'] == test_module_type['key'] + - test_six['module']['location'] == test_module_child_location['key'] + - test_six['module']['serial'] == "654321" + - test_six['module']['asset_tag'] == "123456" + - test_six['module']['role'] == test_module_role['key'] + - test_six['module']['status'] == test_module_status['key'] + - test_six['module']['tenant'] == test_module_tenant['key'] + - test_six['msg'] == "module Parent Test Location > Child Test Location > HooverMaxProModel60 already exists" + + - name: "7 - Delete" + networktocode.nautobot.module: + url: "{{ nautobot_url }}" + token: "{{ nautobot_token }}" + module_type: HooverMaxProModel60 + location: + name: "Child Test Location" + parent: "Parent Test Location" + state: absent + register: test_seven + + - name: "7 - ASSERT" + assert: + that: + - test_seven is changed + - test_seven['diff']['before']['state'] == "present" + - test_seven['diff']['after']['state'] == "absent" + - test_seven['msg'] == "module Parent Test Location > Child Test Location > HooverMaxProModel60 deleted" + + - name: "8 - Delete idempotent" + networktocode.nautobot.module: + url: "{{ nautobot_url }}" + token: "{{ nautobot_token }}" + module_type: HooverMaxProModel60 + location: + name: "Child Test Location" + parent: "Parent Test Location" + state: absent + register: test_eight + + - name: "8 - ASSERT`" + assert: + that: + - not test_eight['changed'] + - test_eight['module'] == None + - test_eight['msg'] == "module Parent Test Location > Child Test Location > HooverMaxProModel60 already absent" diff --git a/tests/integration/targets/latest/tasks/module_bay.yml b/tests/integration/targets/latest/tasks/module_bay.yml new file mode 100644 index 00000000..9446b299 --- /dev/null +++ b/tests/integration/targets/latest/tasks/module_bay.yml @@ -0,0 +1,182 @@ +--- +## +## +### PYNAUTOBOT_MODULE_BAY +## +## +- name: "NAUTOBOT 2.3+ MODULE BAY TESTS" + when: + - "nautobot_version is version('2.3', '>=')" + block: + - set_fact: + test_module: '{{ lookup(''networktocode.nautobot.lookup'', ''modules'', api_endpoint=nautobot_url, token=nautobot_token, api_filter=''q="HooverMaxProModel60"'') }}' + test_device: "{{ lookup('networktocode.nautobot.lookup', 'devices', api_endpoint=nautobot_url, token=nautobot_token, api_filter='name=\"test100\"') }}" + test_module_bay: '{{ lookup(''networktocode.nautobot.lookup'', ''module-bays'', api_endpoint=nautobot_url, token=nautobot_token, api_filter=''name="PowerStrip"'') }}' + + - name: "1 - Create module bay with minimum information" + networktocode.nautobot.module_bay: + url: "{{ nautobot_url }}" + token: "{{ nautobot_token }}" + parent_device: test100 + name: Watch Bay + state: present + register: test_one + + - name: "1 - ASSERT" + assert: + that: + - test_one is changed + - test_one['diff']['before']['state'] == "absent" + - test_one['diff']['after']['state'] == "present" + - test_one['module_bay']['name'] == "Watch Bay" + - test_one['module_bay']['parent_device'] == test_device['key'] + - test_one['msg'] == "module_bay Watch Bay created" + + - name: "2 - Create module bay with minimum information idempotent" + networktocode.nautobot.module_bay: + url: "{{ nautobot_url }}" + token: "{{ nautobot_token }}" + parent_device: test100 + name: Watch Bay + state: present + register: test_two + + - name: "2 - ASSERT" + assert: + that: + - not test_two['changed'] + - test_two['module_bay']['name'] == "Watch Bay" + - test_two['module_bay']['parent_device'] == test_device['key'] + - test_two['msg'] == "module_bay Watch Bay already exists" + + - name: "3 - Update module bay" + networktocode.nautobot.module_bay: + url: "{{ nautobot_url }}" + token: "{{ nautobot_token }}" + parent_device: test100 + name: Watch Bay + label: watchbay + position: "42" + description: The bay of watches + state: present + register: test_three + + - name: "3 - ASSERT" + assert: + that: + - test_three is changed + - test_three['diff']['after']['label'] == "watchbay" + - test_three['diff']['after']['position'] == "42" + - test_three['diff']['after']['description'] == "The bay of watches" + - test_three['module_bay']['name'] == "Watch Bay" + - test_three['module_bay']['parent_device'] == test_device['key'] + - test_three['module_bay']['label'] == "watchbay" + - test_three['module_bay']['position'] == "42" + - test_three['module_bay']['description'] == "The bay of watches" + - test_three['msg'] == "module_bay Watch Bay updated" + + - name: "4 - Update idempotent" + networktocode.nautobot.module_bay: + url: "{{ nautobot_url }}" + token: "{{ nautobot_token }}" + parent_device: test100 + name: Watch Bay + label: watchbay + position: "42" + description: The bay of watches + state: present + register: test_four + + - name: "4 - ASSERT" + assert: + that: + - not test_four['changed'] + - test_four['module_bay']['name'] == "Watch Bay" + - test_four['msg'] == "module_bay Watch Bay already exists" + + - name: "5 - Create module bay with all params" + networktocode.nautobot.module_bay: + url: "{{ nautobot_url }}" + token: "{{ nautobot_token }}" + parent_module: + module_type: HooverMaxProModel60 + parent_module_bay: "{{ test_module_bay['key'] }}" + name: Fixing Good + label: FiXiNgGoOd + position: "321" + description: Good Fixing is better than Bad Breaking + state: present + register: test_five + + - name: "5 - ASSERT" + assert: + that: + - test_five is changed + - test_five['module_bay']['name'] == "Fixing Good" + - test_five['module_bay']['label'] == "FiXiNgGoOd" + - test_five['module_bay']['position'] == "321" + - test_five['module_bay']['description'] == "Good Fixing is better than Bad Breaking" + - test_five['module_bay']['parent_module'] == test_module['key'] + - test_five['msg'] == "module_bay Fixing Good created" + + - name: "6 - Create module bay with all params idempotent" + networktocode.nautobot.module_bay: + url: "{{ nautobot_url }}" + token: "{{ nautobot_token }}" + parent_module: + module_type: HooverMaxProModel60 + parent_module_bay: "{{ test_module_bay['key'] }}" + name: Fixing Good + label: FiXiNgGoOd + position: "321" + description: Good Fixing is better than Bad Breaking + state: present + register: test_six + + - name: "6 - ASSERT" + assert: + that: + - not test_six['changed'] + - test_six['module_bay']['name'] == "Fixing Good" + - test_six['module_bay']['label'] == "FiXiNgGoOd" + - test_six['module_bay']['position'] == "321" + - test_six['module_bay']['description'] == "Good Fixing is better than Bad Breaking" + - test_six['module_bay']['parent_module'] == test_module['key'] + - test_six['msg'] == "module_bay Fixing Good already exists" + + - name: "7 - Delete" + networktocode.nautobot.module_bay: + url: "{{ nautobot_url }}" + token: "{{ nautobot_token }}" + parent_module: + module_type: HooverMaxProModel60 + parent_module_bay: "{{ test_module_bay['key'] }}" + name: Fixing Good + state: absent + register: test_seven + + - name: "7 - ASSERT" + assert: + that: + - test_seven is changed + - test_seven['diff']['before']['state'] == "present" + - test_seven['diff']['after']['state'] == "absent" + - test_seven['msg'] == "module_bay Fixing Good deleted" + + - name: "8 - Delete idempotent" + networktocode.nautobot.module_bay: + url: "{{ nautobot_url }}" + token: "{{ nautobot_token }}" + parent_module: + module_type: HooverMaxProModel60 + parent_module_bay: "{{ test_module_bay['key'] }}" + name: Fixing Good + state: absent + register: test_eight + + - name: "8 - ASSERT`" + assert: + that: + - not test_eight['changed'] + - test_eight['module_bay'] == None + - test_eight['msg'] == "module_bay Fixing Good already absent" diff --git a/tests/integration/targets/latest/tasks/module_bay_template.yml b/tests/integration/targets/latest/tasks/module_bay_template.yml new file mode 100644 index 00000000..40a6cb7d --- /dev/null +++ b/tests/integration/targets/latest/tasks/module_bay_template.yml @@ -0,0 +1,173 @@ +--- +## +## +### PYNAUTOBOT_MODULE_BAY_TEMPLATE +## +## +- name: "NAUTOBOT 2.3+ MODULE BAY TEMPLATE TESTS" + when: + - "nautobot_version is version('2.3', '>=')" + block: + - set_fact: + test_module_type: "{{ lookup('networktocode.nautobot.lookup', 'module-types', api_endpoint=nautobot_url, token=nautobot_token, api_filter='model=\"HooverMaxProModel60\"') }}" + test_device_type: "{{ lookup('networktocode.nautobot.lookup', 'device-types', api_endpoint=nautobot_url, token=nautobot_token, api_filter='model=\"Cisco Test\"') }}" + + - name: "1 - Create module bay template with minimum information" + networktocode.nautobot.module_bay_template: + url: "{{ nautobot_url }}" + token: "{{ nautobot_token }}" + module_type: HooverMaxProModel60 + name: Edward Galbraith + state: present + register: test_one + + - name: "1 - ASSERT" + assert: + that: + - test_one is changed + - test_one['diff']['before']['state'] == "absent" + - test_one['diff']['after']['state'] == "present" + - test_one['module_bay_template']['name'] == "Edward Galbraith" + - test_one['module_bay_template']['module_type'] == test_module_type['key'] + - test_one['msg'] == "module_bay_template Edward Galbraith created" + + - name: "2 - Create module bay template with minimum information idempotent" + networktocode.nautobot.module_bay_template: + url: "{{ nautobot_url }}" + token: "{{ nautobot_token }}" + module_type: HooverMaxProModel60 + name: Edward Galbraith + state: present + register: test_two + + - name: "2 - ASSERT" + assert: + that: + - not test_two['changed'] + - test_two['module_bay_template']['name'] == "Edward Galbraith" + - test_two['module_bay_template']['module_type'] == test_module_type['key'] + - test_two['msg'] == "module_bay_template Edward Galbraith already exists" + + - name: "3 - Update module bay template" + networktocode.nautobot.module_bay_template: + url: "{{ nautobot_url }}" + token: "{{ nautobot_token }}" + module_type: HooverMaxProModel60 + name: Edward Galbraith + label: Br Ba + position: "1" + description: Granite State + state: present + register: test_three + + - name: "3 - ASSERT" + assert: + that: + - test_three is changed + - test_three['diff']['after']['label'] == "Br Ba" + - test_three['diff']['after']['position'] == "1" + - test_three['diff']['after']['description'] == "Granite State" + - test_three['module_bay_template']['name'] == "Edward Galbraith" + - test_three['module_bay_template']['module_type'] == test_module_type['key'] + - test_three['module_bay_template']['label'] == "Br Ba" + - test_three['module_bay_template']['position'] == "1" + - test_three['module_bay_template']['description'] == "Granite State" + - test_three['msg'] == "module_bay_template Edward Galbraith updated" + + - name: "4 - Update idempotent" + networktocode.nautobot.module_bay_template: + url: "{{ nautobot_url }}" + token: "{{ nautobot_token }}" + module_type: HooverMaxProModel60 + name: Edward Galbraith + label: Br Ba + position: "1" + description: Granite State + state: present + register: test_four + + - name: "4 - ASSERT" + assert: + that: + - not test_four['changed'] + - test_four['module_bay_template']['name'] == "Edward Galbraith" + - test_four['msg'] == "module_bay_template Edward Galbraith already exists" + + - name: "5 - Create module bay template with all params" + networktocode.nautobot.module_bay_template: + url: "{{ nautobot_url }}" + token: "{{ nautobot_token }}" + device_type: Cisco Test + name: Test1234 + label: test1234 + position: "42" + description: Cisco Test Module Bay + state: present + register: test_five + + - name: "5 - ASSERT" + assert: + that: + - test_five is changed + - test_five['module_bay_template']['name'] == "Test1234" + - test_five['module_bay_template']['label'] == "test1234" + - test_five['module_bay_template']['position'] == "42" + - test_five['module_bay_template']['description'] == "Cisco Test Module Bay" + - test_five['module_bay_template']['device_type'] == test_device_type['key'] + - test_five['msg'] == "module_bay_template Test1234 created" + + - name: "6 - Create module bay template with all params idempotent" + networktocode.nautobot.module_bay_template: + url: "{{ nautobot_url }}" + token: "{{ nautobot_token }}" + device_type: Cisco Test + name: Test1234 + label: test1234 + position: "42" + description: Cisco Test Module Bay + state: present + register: test_six + + - name: "6 - ASSERT" + assert: + that: + - not test_six['changed'] + - test_six['module_bay_template']['name'] == "Test1234" + - test_six['module_bay_template']['label'] == "test1234" + - test_six['module_bay_template']['position'] == "42" + - test_six['module_bay_template']['description'] == "Cisco Test Module Bay" + - test_six['module_bay_template']['device_type'] == test_device_type['key'] + - test_six['msg'] == "module_bay_template Test1234 already exists" + + - name: "7 - Delete" + networktocode.nautobot.module_bay_template: + url: "{{ nautobot_url }}" + token: "{{ nautobot_token }}" + device_type: Cisco Test + name: Test1234 + state: absent + register: test_seven + + - name: "7 - ASSERT" + assert: + that: + - test_seven is changed + - test_seven['diff']['before']['state'] == "present" + - test_seven['diff']['after']['state'] == "absent" + - test_seven['msg'] == "module_bay_template Test1234 deleted" + + - name: "8 - Delete idempotent" + networktocode.nautobot.module_bay_template: + url: "{{ nautobot_url }}" + token: "{{ nautobot_token }}" + device_type: Cisco Test + name: Test1234 + state: absent + register: test_eight + + - name: "8 - ASSERT`" + assert: + that: + - not test_eight['changed'] + - test_eight['module_bay_template'] == None + - test_eight['msg'] == "module_bay_template Test1234 already absent" diff --git a/tests/integration/targets/latest/tasks/module_type.yml b/tests/integration/targets/latest/tasks/module_type.yml new file mode 100644 index 00000000..e3650ed3 --- /dev/null +++ b/tests/integration/targets/latest/tasks/module_type.yml @@ -0,0 +1,161 @@ +--- +## +## +### PYNAUTOBOT_MODULE_TYPE +## +## +- name: "NAUTOBOT 2.3+ MODULE TYPE TESTS" + when: + - "nautobot_version is version('2.3', '>=')" + block: + - set_fact: + manufacturer: "{{ lookup('networktocode.nautobot.lookup', 'manufacturers', api_endpoint=nautobot_url, token=nautobot_token, api_filter='name=\"Test Manufacturer\"') }}" + + - name: "1 - Create module type with minimum information" + networktocode.nautobot.module_type: + url: "{{ nautobot_url }}" + token: "{{ nautobot_token }}" + model: ws-test-3750 + manufacturer: Test Manufacturer + state: present + register: test_one + + - name: "1 - ASSERT" + assert: + that: + - test_one is changed + - test_one['diff']['before']['state'] == "absent" + - test_one['diff']['after']['state'] == "present" + - test_one['module_type']['model'] == "ws-test-3750" + - test_one['module_type']['manufacturer'] == manufacturer['key'] + - test_one['msg'] == "module_type ws-test-3750 created" + + - name: "2 - Create module type with minimum information idempotent" + networktocode.nautobot.module_type: + url: "{{ nautobot_url }}" + token: "{{ nautobot_token }}" + model: "ws-test-3750" + manufacturer: Test Manufacturer + state: present + register: test_two + + - name: "2 - ASSERT" + assert: + that: + - not test_two['changed'] + - test_two['module_type']['model'] == "ws-test-3750" + - test_two['module_type']['manufacturer'] == manufacturer['key'] + - test_two['msg'] == "module_type ws-test-3750 already exists" + + - name: "3 - Update module type" + networktocode.nautobot.module_type: + url: "{{ nautobot_url }}" + token: "{{ nautobot_token }}" + model: ws-test-3750 + manufacturer: Test Manufacturer + part_number: ws-3750g-v2 + comments: With great power comes great responsibility! + state: present + register: test_three + + - name: "3 - ASSERT" + assert: + that: + - test_three is changed + - test_three['diff']['after']['part_number'] == "ws-3750g-v2" + - test_three['module_type']['model'] == "ws-test-3750" + - test_three['module_type']['manufacturer'] == manufacturer['key'] + - test_three['module_type']['comments'] == "With great power comes great responsibility!" + - test_three['module_type']['part_number'] == "ws-3750g-v2" + - test_three['msg'] == "module_type ws-test-3750 updated" + + - name: "4 - Update idempotent" + networktocode.nautobot.module_type: + url: "{{ nautobot_url }}" + token: "{{ nautobot_token }}" + model: ws-test-3750 + manufacturer: Test Manufacturer + part_number: ws-3750g-v2 + comments: With great power comes great responsibility! + state: present + register: test_four + + - name: "4 - ASSERT" + assert: + that: + - not test_four['changed'] + - test_four['module_type']['model'] == "ws-test-3750" + - test_four['msg'] == "module_type ws-test-3750 already exists" + + - name: "5 - Create module type with all params" + networktocode.nautobot.module_type: + url: "{{ nautobot_url }}" + token: "{{ nautobot_token }}" + model: ws-test-3750-2 + manufacturer: Test Manufacturer + part_number: ws-3750g-v3 + comments: With great power comes great responsibility! + state: present + register: test_five + + - name: "5 - ASSERT" + assert: + that: + - test_five is changed + - test_five['module_type']['model'] == "ws-test-3750-2" + - test_five['module_type']['manufacturer'] == manufacturer['key'] + - test_five['module_type']['comments'] == "With great power comes great responsibility!" + - test_five['module_type']['part_number'] == "ws-3750g-v3" + - test_five['msg'] == "module_type ws-test-3750-2 created" + + - name: "6 - Create module type with all params idempotent" + networktocode.nautobot.module_type: + url: "{{ nautobot_url }}" + token: "{{ nautobot_token }}" + model: ws-test-3750-2 + manufacturer: Test Manufacturer + part_number: ws-3750g-v3 + comments: With great power comes great responsibility! + state: present + register: test_six + + - name: "6 - ASSERT" + assert: + that: + - not test_six['changed'] + - test_six['module_type']['model'] == "ws-test-3750-2" + - test_six['module_type']['manufacturer'] == manufacturer['key'] + - test_six['module_type']['comments'] == "With great power comes great responsibility!" + - test_six['module_type']['part_number'] == "ws-3750g-v3" + - test_six['msg'] == "module_type ws-test-3750-2 already exists" + + - name: "7 - Delete" + networktocode.nautobot.module_type: + url: "{{ nautobot_url }}" + token: "{{ nautobot_token }}" + model: ws-test-3750-2 + state: absent + register: test_seven + + - name: "7 - ASSERT" + assert: + that: + - test_seven is changed + - test_seven['diff']['before']['state'] == "present" + - test_seven['diff']['after']['state'] == "absent" + - test_seven['msg'] == "module_type ws-test-3750-2 deleted" + + - name: "8 - Delete idempotent" + networktocode.nautobot.module_type: + url: "{{ nautobot_url }}" + token: "{{ nautobot_token }}" + model: "ws-test-3750-2" + state: absent + register: test_eight + + - name: "8 - ASSERT`" + assert: + that: + - not test_eight['changed'] + - test_eight['module_type'] == None + - test_eight['msg'] == "module_type ws-test-3750-2 already absent"