diff --git a/plugins/module_utils/netbox_utils.py b/plugins/module_utils/netbox_utils.py index 6a5484409..e40f82a17 100644 --- a/plugins/module_utils/netbox_utils.py +++ b/plugins/module_utils/netbox_utils.py @@ -204,6 +204,7 @@ "cluster_groups": "cluster_groups", "cluster_type": "cluster_types", "cluster_types": "cluster_types", + "component": "interfaces", "config_context": "config_contexts", "contact_groups": "contact_groups", "dcim.consoleport": "console_ports", @@ -386,6 +387,7 @@ "cluster": set(["name", "type"]), "cluster_group": set(["slug"]), "cluster_type": set(["slug"]), + "component": set(["name", "device"]), "config_context": set( [ "name", @@ -437,7 +439,7 @@ "interface_a": set(["name", "device"]), "interface_b": set(["name", "device"]), "interface_template": set(["name", "device_type"]), - "inventory_item": set(["name", "device"]), + "inventory_item": set(["name", "device", "component", "component_type"]), "inventory_item_role": set(["name"]), "ip_address": set(["address", "vrf", "device", "interface", "assigned_object"]), "ip_addresses": set(["address", "vrf", "device", "interface", "assigned_object"]), @@ -561,6 +563,7 @@ "circuit_type": "type", "cluster_type": "type", "cluster_group": "group", + "component": "component_id", "contact_group": "group", "device_role": "role", "fhrp_group": "group", @@ -831,7 +834,7 @@ def _convert_identical_keys(self, data): temp_dict[key] = data[key] elif key in CONVERT_KEYS: # This will keep the original key for keys in list, but also convert it. - if key in ("assigned_object", "scope"): + if key in ("assigned_object", "scope", "component"): temp_dict[key] = data[key] new_key = CONVERT_KEYS[key] temp_dict[new_key] = data[key] @@ -1134,6 +1137,8 @@ def _find_ids(self, data, user_query_params): endpoint = CONVERT_TO_ID[data.get("termination_b_type")] elif k == "assigned_object": endpoint = "interfaces" + elif k == "component": + endpoint = CONVERT_TO_ID[data.get("component_type")] elif k == "scope": # Determine endpoint name for scope ID resolution endpoint = SCOPE_TO_ENDPOINT[data["scope_type"]] diff --git a/plugins/modules/netbox_inventory_item.py b/plugins/modules/netbox_inventory_item.py index 348614f68..1c4908ae2 100644 --- a/plugins/modules/netbox_inventory_item.py +++ b/plugins/modules/netbox_inventory_item.py @@ -82,6 +82,35 @@ required: false default: false type: bool + component_type: + description: + - The type of the component. Required if component is defined. + choices: + - dcim.consoleport + - dcim.consoleserverport + - dcim.frontport + - dcim.interface + - dcim.poweroutlet + - dcim.powerport + - dcim.rearport + required: false + type: str + component: + description: + - The associated component + required: false + type: dict + suboptions: + name: + description: + - The name of the component + type: str + required: False + device: + description: + - The device the component is attached to. + type: str + required: False tags: description: - Any tags that the device may need to be associated with @@ -145,6 +174,19 @@ device: test100 state: present + - name: Create inventory item with component + netbox.netbox.netbox_inventory_item: + netbox_url: http://netbox.local + netbox_token: thisIsMyToken + data: + name: "10G-SFP+" + device: test100 + component_type: "dcim.interface" + component: + name: GigabitEthernet2 + device: "test100" + state: present + - name: Delete inventory item within netbox netbox.netbox.netbox_inventory_item: netbox_url: http://netbox.local @@ -198,6 +240,27 @@ def main(): asset_tag=dict(required=False, type="str"), description=dict(required=False, type="str"), discovered=dict(required=False, type="bool", default=False), + component_type=dict( + required=False, + choices=[ + "dcim.consoleport", + "dcim.consoleserverport", + "dcim.frontport", + "dcim.interface", + "dcim.poweroutlet", + "dcim.powerport", + "dcim.rearport", + ], + type="str", + ), + component=dict( + required=False, + type="dict", + options=dict( + name=dict(required=False, type="str"), + device=dict(required=False, type="str"), + ), + ), tags=dict(required=False, type="list", elements="raw"), custom_fields=dict(required=False, type="dict"), inventory_item_role=dict(required=False, type="raw"), @@ -210,9 +273,13 @@ def main(): ("state", "present", ["device", "name"]), ("state", "absent", ["device", "name"]), ] + required_together = [("component_type", "component")] module = NetboxAnsibleModule( - argument_spec=argument_spec, supports_check_mode=True, required_if=required_if + argument_spec=argument_spec, + supports_check_mode=True, + required_if=required_if, + required_together=required_together, ) netbox_inventory_item = NetboxDcimModule(module, NB_INVENTORY_ITEMS) diff --git a/tests/integration/targets/v3.3/tasks/netbox_inventory_item.yml b/tests/integration/targets/v3.3/tasks/netbox_inventory_item.yml index 48f9a1ffb..cc038ac94 100644 --- a/tests/integration/targets/v3.3/tasks/netbox_inventory_item.yml +++ b/tests/integration/targets/v3.3/tasks/netbox_inventory_item.yml @@ -155,3 +155,49 @@ that: - test_six.failed - test_six.msg == "Could not resolve id of inventory_item_role: Foo" + +- name: "INVENTORY_ITEM 7: Create inventory item with component" + netbox.netbox.netbox_inventory_item: + netbox_url: http://localhost:32768 + netbox_token: 0123456789abcdef0123456789abcdef01234567 + data: + device: test100 + name: test_component + component_type: "dcim.interface" + component: + name: GigabitEthernet2 + device: "test100" + state: present + register: test_seven + +- name: "INVENTORY_ITEM 7: ASSERT - Inventory item creation with component" + ansible.builtin.assert: + that: + - test_seven is changed + - test_seven.diff.before.state == "absent" + - test_seven.diff.after.state == "present" + - test_seven.inventory_item.name == "test_component" + - test_seven.inventory_item.component_type == "dcim.interface" + - test_seven.inventory_item.component_id == 4 + - test_seven.inventory_item.device == 1 + - test_seven.msg == "inventory_item test_component created" + +- name: "INVENTORY_ITEM 8: Create inventory item with missing component_type" + netbox.netbox.netbox_inventory_item: + netbox_url: http://localhost:32768 + netbox_token: 0123456789abcdef0123456789abcdef01234567 + data: + device: test100 + name: test_component + component: + name: GigabitEthernet2 + device: "test100" + state: present + ignore_errors: true + register: test_eight + +- name: "INVENTORY_ITEM 8: ASSERT - Inventory item creation with missing component_type" + ansible.builtin.assert: + that: + - test_eight.failed + - test_eight.msg == "parameters are required together: component_type, component" diff --git a/tests/integration/targets/v3.4/tasks/netbox_inventory_item.yml b/tests/integration/targets/v3.4/tasks/netbox_inventory_item.yml index 48f9a1ffb..cc038ac94 100644 --- a/tests/integration/targets/v3.4/tasks/netbox_inventory_item.yml +++ b/tests/integration/targets/v3.4/tasks/netbox_inventory_item.yml @@ -155,3 +155,49 @@ that: - test_six.failed - test_six.msg == "Could not resolve id of inventory_item_role: Foo" + +- name: "INVENTORY_ITEM 7: Create inventory item with component" + netbox.netbox.netbox_inventory_item: + netbox_url: http://localhost:32768 + netbox_token: 0123456789abcdef0123456789abcdef01234567 + data: + device: test100 + name: test_component + component_type: "dcim.interface" + component: + name: GigabitEthernet2 + device: "test100" + state: present + register: test_seven + +- name: "INVENTORY_ITEM 7: ASSERT - Inventory item creation with component" + ansible.builtin.assert: + that: + - test_seven is changed + - test_seven.diff.before.state == "absent" + - test_seven.diff.after.state == "present" + - test_seven.inventory_item.name == "test_component" + - test_seven.inventory_item.component_type == "dcim.interface" + - test_seven.inventory_item.component_id == 4 + - test_seven.inventory_item.device == 1 + - test_seven.msg == "inventory_item test_component created" + +- name: "INVENTORY_ITEM 8: Create inventory item with missing component_type" + netbox.netbox.netbox_inventory_item: + netbox_url: http://localhost:32768 + netbox_token: 0123456789abcdef0123456789abcdef01234567 + data: + device: test100 + name: test_component + component: + name: GigabitEthernet2 + device: "test100" + state: present + ignore_errors: true + register: test_eight + +- name: "INVENTORY_ITEM 8: ASSERT - Inventory item creation with missing component_type" + ansible.builtin.assert: + that: + - test_eight.failed + - test_eight.msg == "parameters are required together: component_type, component" diff --git a/tests/integration/targets/v3.5/tasks/netbox_inventory_item.yml b/tests/integration/targets/v3.5/tasks/netbox_inventory_item.yml index 48f9a1ffb..cc038ac94 100644 --- a/tests/integration/targets/v3.5/tasks/netbox_inventory_item.yml +++ b/tests/integration/targets/v3.5/tasks/netbox_inventory_item.yml @@ -155,3 +155,49 @@ that: - test_six.failed - test_six.msg == "Could not resolve id of inventory_item_role: Foo" + +- name: "INVENTORY_ITEM 7: Create inventory item with component" + netbox.netbox.netbox_inventory_item: + netbox_url: http://localhost:32768 + netbox_token: 0123456789abcdef0123456789abcdef01234567 + data: + device: test100 + name: test_component + component_type: "dcim.interface" + component: + name: GigabitEthernet2 + device: "test100" + state: present + register: test_seven + +- name: "INVENTORY_ITEM 7: ASSERT - Inventory item creation with component" + ansible.builtin.assert: + that: + - test_seven is changed + - test_seven.diff.before.state == "absent" + - test_seven.diff.after.state == "present" + - test_seven.inventory_item.name == "test_component" + - test_seven.inventory_item.component_type == "dcim.interface" + - test_seven.inventory_item.component_id == 4 + - test_seven.inventory_item.device == 1 + - test_seven.msg == "inventory_item test_component created" + +- name: "INVENTORY_ITEM 8: Create inventory item with missing component_type" + netbox.netbox.netbox_inventory_item: + netbox_url: http://localhost:32768 + netbox_token: 0123456789abcdef0123456789abcdef01234567 + data: + device: test100 + name: test_component + component: + name: GigabitEthernet2 + device: "test100" + state: present + ignore_errors: true + register: test_eight + +- name: "INVENTORY_ITEM 8: ASSERT - Inventory item creation with missing component_type" + ansible.builtin.assert: + that: + - test_eight.failed + - test_eight.msg == "parameters are required together: component_type, component" diff --git a/tests/integration/targets/v3.6/tasks/netbox_inventory_item.yml b/tests/integration/targets/v3.6/tasks/netbox_inventory_item.yml index 48f9a1ffb..cc038ac94 100644 --- a/tests/integration/targets/v3.6/tasks/netbox_inventory_item.yml +++ b/tests/integration/targets/v3.6/tasks/netbox_inventory_item.yml @@ -155,3 +155,49 @@ that: - test_six.failed - test_six.msg == "Could not resolve id of inventory_item_role: Foo" + +- name: "INVENTORY_ITEM 7: Create inventory item with component" + netbox.netbox.netbox_inventory_item: + netbox_url: http://localhost:32768 + netbox_token: 0123456789abcdef0123456789abcdef01234567 + data: + device: test100 + name: test_component + component_type: "dcim.interface" + component: + name: GigabitEthernet2 + device: "test100" + state: present + register: test_seven + +- name: "INVENTORY_ITEM 7: ASSERT - Inventory item creation with component" + ansible.builtin.assert: + that: + - test_seven is changed + - test_seven.diff.before.state == "absent" + - test_seven.diff.after.state == "present" + - test_seven.inventory_item.name == "test_component" + - test_seven.inventory_item.component_type == "dcim.interface" + - test_seven.inventory_item.component_id == 4 + - test_seven.inventory_item.device == 1 + - test_seven.msg == "inventory_item test_component created" + +- name: "INVENTORY_ITEM 8: Create inventory item with missing component_type" + netbox.netbox.netbox_inventory_item: + netbox_url: http://localhost:32768 + netbox_token: 0123456789abcdef0123456789abcdef01234567 + data: + device: test100 + name: test_component + component: + name: GigabitEthernet2 + device: "test100" + state: present + ignore_errors: true + register: test_eight + +- name: "INVENTORY_ITEM 8: ASSERT - Inventory item creation with missing component_type" + ansible.builtin.assert: + that: + - test_eight.failed + - test_eight.msg == "parameters are required together: component_type, component"