From 226d2b253e4836a52124f767ca97832e8488305c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20R=C3=B8dvand?= Date: Sun, 12 Jan 2025 22:21:15 +0100 Subject: [PATCH 01/19] Update netbox_prefix for NetBox 4.2 --- plugins/modules/netbox_prefix.py | 52 ++++++++++++++++++- tests/integration/targets/v4.2/tasks/main.yml | 8 ++- .../targets/v4.2/tasks/netbox_prefix.yml | 27 ++++++---- 3 files changed, 75 insertions(+), 12 deletions(-) diff --git a/plugins/modules/netbox_prefix.py b/plugins/modules/netbox_prefix.py index bfb9bba48..36fa6c48d 100644 --- a/plugins/modules/netbox_prefix.py +++ b/plugins/modules/netbox_prefix.py @@ -55,7 +55,24 @@ type: int site: description: - - Site that prefix is associated with + - Site that prefix is associated with (Deprecated in NetBox 4.2+) + required: false + type: raw + removed_in_version: "5.0.0" + scope_type: + description: + - Type of scope to be applied (NetBox 4.2+) + required: false + type: str + choices: + - "dcim.location" + - "dcim.rack" + - "dcim.region" + - "dcim.site" + - "dcim.sitegroup" + scope: + description: + - Object related to scope type (NetBox 4.2+) required: false type: raw vrf: @@ -212,6 +229,20 @@ site: Test Site state: present first_available: true + + - name: Create prefix with scope (NetBox 4.2+) + netbox.netbox.netbox_prefix: + netbox_url: http://netbox.local + netbox_token: thisIsMyToken + data: + prefix: 10.156.32.0/19 + scope_type: "dcim.site" + scope: Test Site + vrf: Test VRF + tenant: Test Tenant + status: Reserved + description: Test description + state: present """ RETURN = r""" @@ -252,7 +283,24 @@ def main(): prefix=dict(required=False, type="raw"), parent=dict(required=False, type="raw"), prefix_length=dict(required=False, type="int"), - site=dict(required=False, type="raw"), + site=dict( + required=False, + type="raw", + removed_in_version="5.0.0", + removed_from_collection="netbox.netbox", + ), + scope_type=dict( + required=False, + type="str", + choices=[ + "dcim.location", + "dcim.rack", + "dcim.region", + "dcim.site", + "dcim.sitegroup", + ], + ), + scope=dict(required=False, type="raw"), vrf=dict(required=False, type="raw"), tenant=dict(required=False, type="raw"), vlan=dict(required=False, type="raw"), diff --git a/tests/integration/targets/v4.2/tasks/main.yml b/tests/integration/targets/v4.2/tasks/main.yml index 1d56afb98..c6310b7bf 100644 --- a/tests/integration/targets/v4.2/tasks/main.yml +++ b/tests/integration/targets/v4.2/tasks/main.yml @@ -12,7 +12,13 @@ ansible.builtin.include_tasks: netbox_ip_address.yml - name: NETBOX_PREFIX TESTS - ansible.builtin.include_tasks: netbox_prefix.yml + ansible.builtin.include_tasks: + file: netbox_prefix.yml + apply: + tags: + - netbox_prefix + tags: + - netbox_prefix - name: NETBOX_SITE TESTS ansible.builtin.include_tasks: netbox_site.yml diff --git a/tests/integration/targets/v4.2/tasks/netbox_prefix.yml b/tests/integration/targets/v4.2/tasks/netbox_prefix.yml index 64adae855..4b42d748e 100644 --- a/tests/integration/targets/v4.2/tasks/netbox_prefix.yml +++ b/tests/integration/targets/v4.2/tasks/netbox_prefix.yml @@ -44,7 +44,8 @@ netbox_token: "0123456789abcdef0123456789abcdef01234567" data: prefix: 10.156.0.0/19 - site: Test Site + scope_type: "dcim.site" + scope: Test Site status: Reserved description: This prefix has been updated state: present @@ -54,12 +55,14 @@ ansible.builtin.assert: that: - test_three is changed - - test_three['diff']['after']['site'] == 1 + - test_three['diff']['after']['scope'] == 1 + - test_three['diff']['after']['scope_type'] == "dcim.site" - test_three['diff']['after']['status'] == "reserved" - test_three['diff']['after']['description'] == "This prefix has been updated" - test_three['msg'] == "prefix 10.156.0.0/19 updated" - test_three['prefix']['prefix'] == "10.156.0.0/19" - - test_three['prefix']['site'] == 1 + - test_three['prefix']['scope'] == 1 + - test_three['prefix']['scope_type'] == "dcim.site" - test_three['prefix']['status'] == "reserved" - test_three['prefix']['description'] == "This prefix has been updated" @@ -87,7 +90,8 @@ data: family: 4 prefix: 10.156.32.0/19 - site: Test Site + scope_type: "dcim.site" + scope: Test Site vrf: Test VRF tenant: Test Tenant vlan: @@ -113,7 +117,8 @@ - test_five['msg'] == "prefix 10.156.32.0/19 created" - test_five['prefix']['prefix'] == "10.156.32.0/19" - test_five['prefix']['family'] == 4 - - test_five['prefix']['site'] == 1 + - test_five['prefix']['scope'] == 1 + - test_five['prefix']['scope_type'] == "dcim.site" - test_five['prefix']['vrf'] == 1 - test_five['prefix']['tenant'] == 1 - test_five['prefix']['vlan'] == 4 @@ -185,7 +190,8 @@ data: prefix: 10.157.0.0/19 vrf: Test VRF - site: Test Site + scope_type: "dcim.site" + scope: Test Site state: present register: test_nine @@ -197,7 +203,8 @@ - test_nine['diff']['after']['state'] == "present" - test_nine['msg'] == "prefix 10.157.0.0/19 created" - test_nine['prefix']['prefix'] == "10.157.0.0/19" - - test_nine['prefix']['site'] == 1 + - test_nine['prefix']['scope'] == 1 + - test_nine['prefix']['scope_type'] == "dcim.site" - test_nine['prefix']['vrf'] == 1 - name: 10 - Get a new /24 inside 10.157.0.0/19 within NetBox with additional values @@ -208,7 +215,8 @@ parent: 10.157.0.0/19 prefix_length: 24 vrf: Test VRF - site: Test Site + scope_type: "dcim.site" + scope: Test Site state: present first_available: true register: test_ten @@ -221,7 +229,8 @@ - test_ten['diff']['after']['state'] == "present" - test_ten['msg'] == "prefix 10.157.0.0/24 created" - test_ten['prefix']['prefix'] == "10.157.0.0/24" - - test_ten['prefix']['site'] == 1 + - test_ten['prefix']['scope'] == 1 + - test_ten['prefix']['scope_type'] == "dcim.site" - test_ten['prefix']['vrf'] == 1 - name: 11 - Get a new /24 inside 10.156.0.0/19 within NetBox From cb498bbbed8fccdec91e07e39d8445dfbb98382b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20R=C3=B8dvand?= Date: Sun, 12 Jan 2025 22:35:49 +0100 Subject: [PATCH 02/19] Adjust test file to include tags for each test --- plugins/modules/netbox_cluster.py | 59 ++- plugins/modules/netbox_prefix.py | 2 + tests/integration/targets/v4.2/tasks/main.yml | 446 +++++++++++++++--- .../targets/v4.2/tasks/netbox_cluster.yml | 16 +- 4 files changed, 458 insertions(+), 65 deletions(-) diff --git a/plugins/modules/netbox_cluster.py b/plugins/modules/netbox_cluster.py index d91e770c6..4a2394be0 100644 --- a/plugins/modules/netbox_cluster.py +++ b/plugins/modules/netbox_cluster.py @@ -53,9 +53,28 @@ type: raw site: description: - - Required if I(state=present) and the cluster does not exist yet + - Required if I(state=present) and the cluster does not exist yet (Deprecated in NetBox 4.2+) required: false type: raw + removed_in_version: "5.0.0" + scope_type: + description: + - Type of scope to be applied (NetBox 4.2+) + required: false + type: str + choices: + - "dcim.location" + - "dcim.rack" + - "dcim.region" + - "dcim.site" + - "dcim.sitegroup" + version_added: "3.21.0" + scope: + description: + - Object related to scope type (NetBox 4.2+) + required: false + type: raw + version_added: "3.21.0" description: description: - The description of the cluster @@ -131,6 +150,19 @@ site: SITE status: planned state: present + + - name: Update the group and scope of an existing cluster (NetBox 4.2+) + netbox.netbox.netbox_cluster: + netbox_url: http://netbox.local + netbox_token: thisIsMyToken + data: + name: Test Cluster + cluster_type: qemu + cluster_group: GROUP + scope_type: "dcim.site" + scope: SITE + status: planned + state: present """ RETURN = r""" @@ -170,7 +202,24 @@ def main(): status=dict(required=False, type="raw"), cluster_type=dict(required=False, type="raw"), cluster_group=dict(required=False, type="raw"), - site=dict(required=False, type="raw"), + site=dict( + required=False, + type="raw", + removed_in_version="5.0.0", + removed_from_collection="netbox.netbox", + ), + scope_type=dict( + required=False, + type="str", + choices=[ + "dcim.location", + "dcim.rack", + "dcim.region", + "dcim.site", + "dcim.sitegroup", + ], + ), + scope=dict(required=False, type="raw"), tenant=dict(required=False, type="raw"), description=dict(required=False, type="str"), comments=dict(required=False, type="str"), @@ -182,9 +231,13 @@ def main(): ) required_if = [("state", "present", ["name"]), ("state", "absent", ["name"])] + required_together = [("scope_type", "scope")] 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_cluster = NetboxVirtualizationModule(module, NB_CLUSTERS) diff --git a/plugins/modules/netbox_prefix.py b/plugins/modules/netbox_prefix.py index 36fa6c48d..ab1913bd3 100644 --- a/plugins/modules/netbox_prefix.py +++ b/plugins/modules/netbox_prefix.py @@ -70,11 +70,13 @@ - "dcim.region" - "dcim.site" - "dcim.sitegroup" + version_added: "3.21.0" scope: description: - Object related to scope type (NetBox 4.2+) required: false type: raw + version_added: "3.21.0" vrf: description: - VRF that prefix is associated with diff --git a/tests/integration/targets/v4.2/tasks/main.yml b/tests/integration/targets/v4.2/tasks/main.yml index c6310b7bf..9b5b5c21a 100644 --- a/tests/integration/targets/v4.2/tasks/main.yml +++ b/tests/integration/targets/v4.2/tasks/main.yml @@ -1,15 +1,39 @@ --- - name: NETBOX_DEVICE TESTS - ansible.builtin.include_tasks: netbox_device.yml + ansible.builtin.include_tasks: + file: netbox_device.yml + apply: + tags: + - netbox_device + tags: + - netbox_device - name: NETBOX_DEVICE_INTERFACE TESTS - ansible.builtin.include_tasks: netbox_device_interface.yml + ansible.builtin.include_tasks: + file: netbox_device_interface.yml + apply: + tags: + - netbox_device_interface + tags: + - netbox_device_interface - name: NETBOX_DEVICE_INTERFACE_TEMPLATE TESTS - ansible.builtin.include_tasks: netbox_device_interface_template.yml + ansible.builtin.include_tasks: + file: netbox_device_interface_template.yml + apply: + tags: + - netbox_device_interface_template + tags: + - netbox_device_interface_template - name: NETBOX_IP_ADDRESS TESTS - ansible.builtin.include_tasks: netbox_ip_address.yml + ansible.builtin.include_tasks: + file: netbox_ip_address.yml + apply: + tags: + - netbox_ip_address + tags: + - netbox_ip_address - name: NETBOX_PREFIX TESTS ansible.builtin.include_tasks: @@ -21,22 +45,58 @@ - netbox_prefix - name: NETBOX_SITE TESTS - ansible.builtin.include_tasks: netbox_site.yml + ansible.builtin.include_tasks: + file: netbox_site.yml + apply: + tags: + - netbox_site + tags: + - netbox_site - name: NETBOX_SITE_GROUP TESTS - ansible.builtin.include_tasks: netbox_site_group.yml + ansible.builtin.include_tasks: + file: netbox_site_group.yml + apply: + tags: + - netbox_site_group + tags: + - netbox_site_group - name: NETBOX_CONTACT TESTS - ansible.builtin.include_tasks: netbox_contact.yml + ansible.builtin.include_tasks: + file: netbox_contact.yml + apply: + tags: + - netbox_contact + tags: + - netbox_contact - name: NETBOX_CONTACT_ROLE TESTS - ansible.builtin.include_tasks: netbox_contact_role.yml + ansible.builtin.include_tasks: + file: netbox_contact_role.yml + apply: + tags: + - netbox_contact_role + tags: + - netbox_contact_role - name: NETBOX_TENTANT TESTS - ansible.builtin.include_tasks: netbox_tenant.yml + ansible.builtin.include_tasks: + file: netbox_tenant.yml + apply: + tags: + - netbox_tenant + tags: + - netbox_tenant - name: NETBOX_TENTANT_GROUP TESTS - ansible.builtin.include_tasks: netbox_tenant_group.yml + ansible.builtin.include_tasks: + file: netbox_tenant_group.yml + apply: + tags: + - netbox_tenant_group + tags: + - netbox_tenant_group - name: NETBOX_RACK TESTS ansible.builtin.include_tasks: @@ -48,52 +108,148 @@ - netbox_rack - name: NETBOX_RACK_ROLE TESTS - ansible.builtin.include_tasks: netbox_rack_role.yml + ansible.builtin.include_tasks: + file: netbox_rack_role.yml + apply: + tags: + - netbox_rack_role + tags: + - netbox_rack_role - name: NETBOX_LOCATION TESTS - ansible.builtin.include_tasks: netbox_location.yml + ansible.builtin.include_tasks: + file: netbox_location.yml + apply: + tags: + - netbox_location + tags: + - netbox_location - name: NETBOX_MANUFACTURER TESTS - ansible.builtin.include_tasks: netbox_manufacturer.yml + ansible.builtin.include_tasks: + file: netbox_manufacturer.yml + apply: + tags: + - netbox_manufacturer + tags: + - netbox_manufacturer - name: NETBOX_PLATFORM TESTS - ansible.builtin.include_tasks: netbox_platform.yml + ansible.builtin.include_tasks: + file: netbox_platform.yml + apply: + tags: + - netbox_platform + tags: + - netbox_platform - name: NETBOX_DEVICE_TYPE TESTS - ansible.builtin.include_tasks: netbox_device_type.yml + ansible.builtin.include_tasks: + file: netbox_device_type.yml + apply: + tags: + - netbox_device_type + tags: + - netbox_device_type - name: NETBOX_DEVICE_ROLE TESTS - ansible.builtin.include_tasks: netbox_device_role.yml + ansible.builtin.include_tasks: + file: netbox_device_role.yml + apply: + tags: + - netbox_device_role + tags: + - netbox_device_role - name: NETBOX_IPAM_ROLE TESTS - ansible.builtin.include_tasks: netbox_ipam_role.yml + ansible.builtin.include_tasks: + file: netbox_ipam_role.yml + apply: + tags: + - netbox_ipam_role + tags: + - netbox_ipam_role - name: NETBOX_VLAN_GROUP TESTS - ansible.builtin.include_tasks: netbox_vlan_group.yml + ansible.builtin.include_tasks: + file: netbox_vlan_group.yml + apply: + tags: + - netbox_vlan_group + tags: + - netbox_vlan_group - name: NETBOX_VLAN TESTS - ansible.builtin.include_tasks: netbox_vlan.yml + ansible.builtin.include_tasks: + file: netbox_vlan.yml + apply: + tags: + - netbox_vlan + tags: + - netbox_vlan - name: NETBOX_VRF TESTS - ansible.builtin.include_tasks: netbox_vrf.yml + ansible.builtin.include_tasks: + file: netbox_vrf.yml + apply: + tags: + - netbox_vrf + tags: + - netbox_vrf - name: NETBOX_RIR TESTS - ansible.builtin.include_tasks: netbox_rir.yml + ansible.builtin.include_tasks: + file: netbox_rir.yml + apply: + tags: + - netbox_rir + tags: + - netbox_rir - name: NETBOX_AGGREGATE TESTS - ansible.builtin.include_tasks: netbox_aggregate.yml + ansible.builtin.include_tasks: + file: netbox_aggregate.yml + apply: + tags: + - netbox_aggregate + tags: + - netbox_aggregate - name: NETBOX_REGION TESTS - ansible.builtin.include_tasks: netbox_region.yml + ansible.builtin.include_tasks: + file: netbox_region.yml + apply: + tags: + - netbox_region + tags: + - netbox_region - name: NETBOX_DEVICE_BAY TESTS - ansible.builtin.include_tasks: netbox_device_bay.yml + ansible.builtin.include_tasks: + file: netbox_device_bay.yml + apply: + tags: + - netbox_device_bay + tags: + - netbox_device_bay - name: NETBOX_DEVICE_BAY_TEMPLATE TESTS - ansible.builtin.include_tasks: netbox_device_bay_template.yml + ansible.builtin.include_tasks: + file: netbox_device_bay_template.yml + apply: + tags: + - netbox_device_bay_template + tags: + - netbox_device_bay_template - name: NETBOX_INVENTORY_ITEM TESTS - ansible.builtin.include_tasks: netbox_inventory_item.yml + ansible.builtin.include_tasks: + file: netbox_inventory_item.yml + apply: + tags: + - netbox_inventory_item + tags: + - netbox_inventory_item - name: NETBOX_VIRTUAL_MACHINE TESTS ansible.builtin.include_tasks: @@ -105,76 +261,220 @@ - netbox_virtual_machine - name: NETBOX_CLUSTER TESTS - ansible.builtin.include_tasks: netbox_cluster.yml + ansible.builtin.include_tasks: + file: netbox_cluster.yml + apply: + tags: + - netbox_cluster + tags: + - netbox_cluster - name: NETBOX_CLUSTER_GROUP TESTS - ansible.builtin.include_tasks: netbox_cluster_group.yml + ansible.builtin.include_tasks: + file: netbox_cluster_group.yml + apply: + tags: + - netbox_cluster_group + tags: + - netbox_cluster_group - name: NETBOX_CLUSTER_TYPE TESTS - ansible.builtin.include_tasks: netbox_cluster_type.yml + ansible.builtin.include_tasks: + file: netbox_cluster_type.yml + apply: + tags: + - netbox_cluster_type + tags: + - netbox_cluster_type - name: NETBOX_VM_INTERFACE TESTS - ansible.builtin.include_tasks: netbox_vm_interface.yml + ansible.builtin.include_tasks: + file: netbox_vm_interface.yml + apply: + tags: + - netbox_vm_interface + tags: + - netbox_vm_interface - name: NETBOX_PROVIDER TESTS - ansible.builtin.include_tasks: netbox_provider.yml + ansible.builtin.include_tasks: + file: netbox_provider.yml + apply: + tags: + - netbox_provider + tags: + - netbox_provider - name: NETBOX_PROVIDER_NETWORK TESTS - ansible.builtin.include_tasks: netbox_provider_network.yml + ansible.builtin.include_tasks: + file: netbox_provider_network.yml + apply: + tags: + - netbox_provider_network + tags: + - netbox_provider_network - name: NETBOX_CIRCUIT_TYPE TESTS - ansible.builtin.include_tasks: netbox_circuit_type.yml + ansible.builtin.include_tasks: + file: netbox_circuit_type.yml + apply: + tags: + - netbox_circuit_type + tags: + - netbox_circuit_type - name: NETBOX_CIRCUIT TESTS - ansible.builtin.include_tasks: netbox_circuit.yml + ansible.builtin.include_tasks: + file: netbox_circuit.yml + apply: + tags: + - netbox_circuit + tags: + - netbox_circuit - name: NETBOX_CIRCUIT_TERMINATION TESTS - ansible.builtin.include_tasks: netbox_circuit_termination.yml + ansible.builtin.include_tasks: + file: netbox_circuit_termination.yml + apply: + tags: + - netbox_circuit_termination + tags: + - netbox_circuit_termination - name: NETBOX_REAR_PORT TESTS - ansible.builtin.include_tasks: netbox_rear_port.yml + ansible.builtin.include_tasks: + file: netbox_rear_port.yml + apply: + tags: + - netbox_rear_port + tags: + - netbox_rear_port - name: NETBOX_REAR_PORT_TEMPLATE TESTS - ansible.builtin.include_tasks: netbox_rear_port_template.yml + ansible.builtin.include_tasks: + file: netbox_rear_port_template.yml + apply: + tags: + - netbox_rear_port_template + tags: + - netbox_rear_port_template - name: NETBOX_FRONT_PORT TESTS - ansible.builtin.include_tasks: netbox_front_port.yml + ansible.builtin.include_tasks: + file: netbox_front_port.yml + apply: + tags: + - netbox_front_port + tags: + - netbox_front_port - name: NETBOX_FRONT_PORT_TEMPLATE TESTS - ansible.builtin.include_tasks: netbox_front_port_template.yml + ansible.builtin.include_tasks: + file: netbox_front_port_template.yml + apply: + tags: + - netbox_front_port_template + tags: + - netbox_front_port_template - name: NETBOX_CONSOLE_PORT TESTS - ansible.builtin.include_tasks: netbox_console_port.yml + ansible.builtin.include_tasks: + file: netbox_console_port.yml + apply: + tags: + - netbox_console_port + tags: + - netbox_console_port - name: NETBOX_CONSOLE_PORT_TEMPLATE TESTS - ansible.builtin.include_tasks: netbox_console_port_template.yml + ansible.builtin.include_tasks: + file: netbox_console_port_template.yml + apply: + tags: + - netbox_console_port_template + tags: + - netbox_console_port_template - name: NETBOX_CONSOLE_SERVER_PORT TESTS - ansible.builtin.include_tasks: netbox_console_server_port.yml + ansible.builtin.include_tasks: + file: netbox_console_server_port.yml + apply: + tags: + - netbox_console_server_port + tags: + - netbox_console_server_port - name: NETBOX_CONSOLE_SERVER_PORT_TEMPLATE TESTS - ansible.builtin.include_tasks: netbox_console_server_port_template.yml + ansible.builtin.include_tasks: + file: netbox_console_server_port_template.yml + apply: + tags: + - netbox_console_server_port_template + tags: + - netbox_console_server_port_template - name: NETBOX_POWER_PANEL TESTS - ansible.builtin.include_tasks: netbox_power_panel.yml + ansible.builtin.include_tasks: + file: netbox_power_panel.yml + apply: + tags: + - netbox_power_panel + tags: + - netbox_power_panel - name: NETBOX_POWER_FEED TESTS - ansible.builtin.include_tasks: netbox_power_feed.yml + ansible.builtin.include_tasks: + file: netbox_power_feed.yml + apply: + tags: + - netbox_power_feed + tags: + - netbox_power_feed - name: NETBOX_POWER_PORT TESTS - ansible.builtin.include_tasks: netbox_power_port.yml + ansible.builtin.include_tasks: + file: netbox_power_port.yml + apply: + tags: + - netbox_power_port + tags: + - netbox_power_port - name: NETBOX_POWER_PORT_TEMPLATE TESTS - ansible.builtin.include_tasks: netbox_power_port_template.yml + ansible.builtin.include_tasks: + file: netbox_power_port_template.yml + apply: + tags: + - netbox_power_port_template + tags: + - netbox_power_port_template - name: NETBOX_POWER_OUTLET TESTS - ansible.builtin.include_tasks: netbox_power_outlet.yml + ansible.builtin.include_tasks: + file: netbox_power_outlet.yml + apply: + tags: + - netbox_power_outlet + tags: + - netbox_power_outlet - name: NETBOX_POWER_OUTLET_TEMPLATE TESTS - ansible.builtin.include_tasks: netbox_power_outlet_template.yml + ansible.builtin.include_tasks: + file: netbox_power_outlet_template.yml + apply: + tags: + - netbox_power_outlet_template + tags: + - netbox_power_outlet_template - name: NETBOX_VIRTUAL_CHASSIS TESTS - ansible.builtin.include_tasks: netbox_virtual_chassis.yml + ansible.builtin.include_tasks: + file: netbox_virtual_chassis.yml + apply: + tags: + - netbox_virtual_chassis + tags: + - netbox_virtual_chassis - name: NETBOX_USER_TESTS ansible.builtin.include_tasks: @@ -195,7 +495,13 @@ - netbox_user_group - name: NETBOX_PERMISSION TESTS - ansible.builtin.include_tasks: netbox_permission.yml + ansible.builtin.include_tasks: + file: netbox_permission.yml + apply: + tags: + - netbox_permission + tags: + - netbox_permission - name: NETBOX_TOKEN_TESTS ansible.builtin.include_tasks: @@ -211,10 +517,22 @@ # include_tasks: "netbox_cable.yml" - name: NETBOX_SERVICE TESTS - ansible.builtin.include_tasks: netbox_service.yml + ansible.builtin.include_tasks: + file: netbox_service.yml + apply: + tags: + - netbox_service + tags: + - netbox_service - name: NETBOX_LOOKUP TESTS - ansible.builtin.include_tasks: netbox_lookup.yml + ansible.builtin.include_tasks: + file: netbox_lookup.yml + apply: + tags: + - netbox_lookup + tags: + - netbox_lookup - name: NETBOX_TAG_TESTS ansible.builtin.include_tasks: @@ -344,10 +662,22 @@ - netbox_service_template - name: NETBOX_ASN TESTS - ansible.builtin.include_tasks: netbox_asn.yml + ansible.builtin.include_tasks: + file: netbox_asn.yml + apply: + tags: + - netbox_asn + tags: + - netbox_asn - name: NETBOX_FHRP_GROUP TESTS - ansible.builtin.include_tasks: netbox_fhrp_group.yml + ansible.builtin.include_tasks: + file: netbox_fhrp_group.yml + apply: + tags: + - netbox_fhrp_group + tags: + - netbox_fhrp_group - name: NETBOX_JOURNAL_ENTRY TESTS ansible.builtin.include_tasks: @@ -368,7 +698,11 @@ - netbox_fhrp_group_assignmen - name: NETBOX_CONFIG_TEMPLATE - ansible.builtin.include_tasks: netbox_config_template.yml + ansible.builtin.include_tasks: + file: netbox_config_template.yml + apply: + tags: + - netbox_config_template tags: - netbox_config_template diff --git a/tests/integration/targets/v4.2/tasks/netbox_cluster.yml b/tests/integration/targets/v4.2/tasks/netbox_cluster.yml index b2810a1be..608715228 100644 --- a/tests/integration/targets/v4.2/tasks/netbox_cluster.yml +++ b/tests/integration/targets/v4.2/tasks/netbox_cluster.yml @@ -50,7 +50,8 @@ name: Test Cluster One cluster_type: Test Cluster Type cluster_group: Test Cluster Group - site: Test Site + scope_type: "dcim.site" + scope: Test Site comments: Updated cluster tenant: Test Tenant tags: @@ -63,20 +64,22 @@ that: - test_three is changed - test_three['diff']['after']['group'] == 1 - - test_three['diff']['after']['site'] == 1 + - test_three['diff']['after']['scope'] == 1 + - test_three['diff']['after']['scope_type'] == "dcim.site" - test_three['diff']['after']['comments'] == "Updated cluster" - test_three['diff']['after']['tags'][0] == 4 - test_three['diff']['after']['tenant'] == 1 - test_three['cluster']['name'] == "Test Cluster One" - test_three['cluster']['type'] == 1 - test_three['cluster']['group'] == 1 - - test_three['cluster']['site'] == 1 + - test_three['cluster']['scope'] == 1 + - test_three['cluster']['scope_type'] == "dcim.site" - test_three['cluster']['comments'] == "Updated cluster" - test_three['cluster']['tags'][0] == 4 - test_three['cluster']['tenant'] == 1 - test_three['msg'] == "cluster Test Cluster One updated" -- name: "CLUSTER 4: ASSERT - Delete" +- name: "CLUSTER 4: Delete" netbox.netbox.netbox_cluster: netbox_url: http://localhost:32768 netbox_token: "0123456789abcdef0123456789abcdef01234567" @@ -92,7 +95,8 @@ - test_four['cluster']['name'] == "Test Cluster One" - test_four['cluster']['type'] == 1 - test_four['cluster']['group'] == 1 - - test_four['cluster']['site'] == 1 + - test_four['cluster']['scope'] == 1 + - test_four['cluster']['scope_type'] == "dcim.site" - test_four['cluster']['comments'] == "Updated cluster" - test_four['cluster']['tags'][0] == 4 - - test_four['msg'] == "cluster Test Cluster One deleted" + - test_four['msg'] == "cluster Test Cluster One deleted" \ No newline at end of file From a0b45660333fcbfff58180ca5f0d8f1360017c7a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20R=C3=B8dvand?= Date: Sun, 12 Jan 2025 22:36:09 +0100 Subject: [PATCH 03/19] Reformat netbox_prefix --- plugins/modules/netbox_prefix.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/modules/netbox_prefix.py b/plugins/modules/netbox_prefix.py index ab1913bd3..203b14da5 100644 --- a/plugins/modules/netbox_prefix.py +++ b/plugins/modules/netbox_prefix.py @@ -286,7 +286,7 @@ def main(): parent=dict(required=False, type="raw"), prefix_length=dict(required=False, type="int"), site=dict( - required=False, + required=False, type="raw", removed_in_version="5.0.0", removed_from_collection="netbox.netbox", From fab45532381bca11f39fa3f95f1c43726145f85c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20R=C3=B8dvand?= Date: Sun, 12 Jan 2025 22:41:35 +0100 Subject: [PATCH 04/19] Fix removed_in_version --- plugins/modules/netbox_cluster.py | 4 ++-- plugins/modules/netbox_prefix.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/plugins/modules/netbox_cluster.py b/plugins/modules/netbox_cluster.py index 4a2394be0..c678f3bc1 100644 --- a/plugins/modules/netbox_cluster.py +++ b/plugins/modules/netbox_cluster.py @@ -54,9 +54,9 @@ site: description: - Required if I(state=present) and the cluster does not exist yet (Deprecated in NetBox 4.2+) + - Will be removed in version 5.0.0 required: false - type: raw - removed_in_version: "5.0.0" + type: raw scope_type: description: - Type of scope to be applied (NetBox 4.2+) diff --git a/plugins/modules/netbox_prefix.py b/plugins/modules/netbox_prefix.py index 203b14da5..f6135381c 100644 --- a/plugins/modules/netbox_prefix.py +++ b/plugins/modules/netbox_prefix.py @@ -56,9 +56,9 @@ site: description: - Site that prefix is associated with (Deprecated in NetBox 4.2+) + - Will be removed in version 5.0.0 required: false type: raw - removed_in_version: "5.0.0" scope_type: description: - Type of scope to be applied (NetBox 4.2+) From 29d4288d62e1c338b2492cb9623ef6c7b8b8496c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20R=C3=B8dvand?= Date: Mon, 13 Jan 2025 00:33:18 +0100 Subject: [PATCH 05/19] Linting --- plugins/modules/netbox_cluster.py | 2 +- tests/integration/targets/v4.2/tasks/netbox_cluster.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/modules/netbox_cluster.py b/plugins/modules/netbox_cluster.py index c678f3bc1..a89a05588 100644 --- a/plugins/modules/netbox_cluster.py +++ b/plugins/modules/netbox_cluster.py @@ -56,7 +56,7 @@ - Required if I(state=present) and the cluster does not exist yet (Deprecated in NetBox 4.2+) - Will be removed in version 5.0.0 required: false - type: raw + type: raw scope_type: description: - Type of scope to be applied (NetBox 4.2+) diff --git a/tests/integration/targets/v4.2/tasks/netbox_cluster.yml b/tests/integration/targets/v4.2/tasks/netbox_cluster.yml index 608715228..54047f6dd 100644 --- a/tests/integration/targets/v4.2/tasks/netbox_cluster.yml +++ b/tests/integration/targets/v4.2/tasks/netbox_cluster.yml @@ -99,4 +99,4 @@ - test_four['cluster']['scope_type'] == "dcim.site" - test_four['cluster']['comments'] == "Updated cluster" - test_four['cluster']['tags'][0] == 4 - - test_four['msg'] == "cluster Test Cluster One deleted" \ No newline at end of file + - test_four['msg'] == "cluster Test Cluster One deleted" From 5cfe06f861e6f59b1dd6d0aaea1d05f5d3c1d6f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20R=C3=B8dvand?= Date: Mon, 13 Jan 2025 00:44:48 +0100 Subject: [PATCH 06/19] Add changelog fragment --- changelogs/fragments/scope_prefix_cluster.yml | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 changelogs/fragments/scope_prefix_cluster.yml diff --git a/changelogs/fragments/scope_prefix_cluster.yml b/changelogs/fragments/scope_prefix_cluster.yml new file mode 100644 index 000000000..0fcc22b1e --- /dev/null +++ b/changelogs/fragments/scope_prefix_cluster.yml @@ -0,0 +1,3 @@ +changes: + - netbox_prefix - Add options scope and scope_type for NetBox 4.2+ + - netbox_cluster - Add options scope and scope_type for NetBox 4.2+ From 9f4cc5a8991b122fb77bf77b2306ab06bd7a2d4c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20R=C3=B8dvand?= Date: Mon, 13 Jan 2025 00:51:02 +0100 Subject: [PATCH 07/19] Fix fragment section --- changelogs/fragments/scope_prefix_cluster.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/changelogs/fragments/scope_prefix_cluster.yml b/changelogs/fragments/scope_prefix_cluster.yml index 0fcc22b1e..dfdfecd2b 100644 --- a/changelogs/fragments/scope_prefix_cluster.yml +++ b/changelogs/fragments/scope_prefix_cluster.yml @@ -1,3 +1,3 @@ -changes: +minor_changes: - netbox_prefix - Add options scope and scope_type for NetBox 4.2+ - netbox_cluster - Add options scope and scope_type for NetBox 4.2+ From cc399c39d3221decd63e2d124861a3097c6bef16 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20R=C3=B8dvand?= Date: Sun, 19 Jan 2025 20:36:56 +0100 Subject: [PATCH 08/19] Add netbox_mac_address --- plugins/module_utils/netbox_dcim.py | 3 + plugins/module_utils/netbox_utils.py | 4 + plugins/modules/netbox_mac_address.py | 168 ++++++++++++++++++ tests/integration/targets/v4.2/tasks/main.yml | 9 + .../targets/v4.2/tasks/netbox_mac_address.yml | 69 +++++++ 5 files changed, 253 insertions(+) create mode 100644 plugins/modules/netbox_mac_address.py create mode 100644 tests/integration/targets/v4.2/tasks/netbox_mac_address.yml diff --git a/plugins/module_utils/netbox_dcim.py b/plugins/module_utils/netbox_dcim.py index d3ede9c73..ccf1b0fc1 100644 --- a/plugins/module_utils/netbox_dcim.py +++ b/plugins/module_utils/netbox_dcim.py @@ -51,6 +51,7 @@ NB_SITES = "sites" NB_SITE_GROUPS = "site_groups" NB_VIRTUAL_CHASSIS = "virtual_chassis" +NB_MAC_ADDRESSES = "mac_addresses" try: from packaging.version import Version @@ -141,6 +142,8 @@ def run(self): name = self.module.params["data"]["master"] elif data.get("slug"): name = data["slug"] + elif data.get("mac_address"): + name = data["mac_address"] elif endpoint_name == "cable": if self.module.params["data"]["termination_a"].get("name"): termination_a_name = self.module.params["data"]["termination_a"]["name"] diff --git a/plugins/module_utils/netbox_utils.py b/plugins/module_utils/netbox_utils.py index ea76f43c0..644563d11 100644 --- a/plugins/module_utils/netbox_utils.py +++ b/plugins/module_utils/netbox_utils.py @@ -78,6 +78,7 @@ "sites": {}, "site_groups": {}, "virtual_chassis": {}, + "mac_addresses": {}, }, extras={ "config_contexts": {}, @@ -226,6 +227,7 @@ webhook="name", wireless_lan="ssid", wireless_lan_group="slug", + mac_address="mac_address", ) # Specifies keys within data that need to be converted to ID and the endpoint to be used when queried @@ -434,6 +436,7 @@ "wireless_lans": "wireless_lan", "wireless_lan_groups": "wireless_lan_group", "wireless_links": "wireless_link", + "mac_addresses": "mac_address", } ALLOWED_QUERY_PARAMS = { @@ -516,6 +519,7 @@ ), "lag": set(["name"]), "location": set(["name", "slug", "site"]), + "mac_address": set(["mac_address"]), "module": set(["device", "module_bay", "module_type"]), "module_bay": set(["device", "name"]), "module_type": set(["model"]), diff --git a/plugins/modules/netbox_mac_address.py b/plugins/modules/netbox_mac_address.py new file mode 100644 index 000000000..1051086ad --- /dev/null +++ b/plugins/modules/netbox_mac_address.py @@ -0,0 +1,168 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# Copyright: (c) 2025, Martin Rødvand (@rodvand) +# 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: netbox_mac_address +short_description: Create, update or delete MAC addresses within NetBox +description: + - Creates, updates or removes MAC addresses from NetBox +notes: + - Tags should be defined as a YAML list + - This should be ran with connection C(local) and hosts C(localhost) +author: + - Martin Rødvand (@rodvand) +requirements: + - pynetbox +version_added: "3.21.0" +extends_documentation_fragment: + - netbox.netbox.common +options: + data: + type: dict + description: + - Defines the MAC address configuration + suboptions: + mac_address: + description: + - The MAC address + required: true + type: str + assigned_object_type: + description: + - Type of the assigned object + required: false + type: str + assigned_object: + description: + - The object to assign this MAC address to + required: false + type: raw + description: + description: + - Description of the MAC address + required: false + type: str + comments: + description: + - Comments for the MAC address + required: false + type: str + tags: + description: + - Any tags that the MAC address may need to be associated with + required: false + type: list + elements: raw + custom_fields: + description: + - Must exist in NetBox and in key/value format + required: false + type: dict + required: true +""" + +EXAMPLES = r""" +- name: "Test NetBox MAC address module" + connection: local + hosts: localhost + gather_facts: false + + tasks: + - name: Create MAC address within NetBox with only required information + netbox.netbox.netbox_mac_address: + netbox_url: http://netbox.local + netbox_token: thisIsMyToken + data: + mac_address: "00:11:22:33:44:55" + state: present + + - name: Create MAC address with interface assignment + netbox.netbox.netbox_mac_address: + netbox_url: http://netbox.local + netbox_token: thisIsMyToken + data: + mac_address: "AA:BB:CC:DD:EE:FF" + assigned_object_type: "dcim.interface" + assigned_object: "eth0" + description: "MAC address for eth0" + tags: + - Network + state: present + + - name: Delete MAC address within netbox + netbox.netbox.netbox_mac_address: + netbox_url: http://netbox.local + netbox_token: thisIsMyToken + data: + mac_address: "00:11:22:33:44:55" + state: absent +""" + +RETURN = r""" +mac_address: + description: Serialized object as created or already existent within NetBox + 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.netbox.netbox.plugins.module_utils.netbox_utils import ( + NetboxAnsibleModule, + NETBOX_ARG_SPEC, +) +from ansible_collections.netbox.netbox.plugins.module_utils.netbox_dcim import ( + NetboxDcimModule, + NB_MAC_ADDRESSES, +) +from copy import deepcopy + + +def main(): + """ + Main entry point for module execution + """ + argument_spec = deepcopy(NETBOX_ARG_SPEC) + argument_spec.update( + dict( + data=dict( + type="dict", + required=True, + options=dict( + mac_address=dict(required=True, type="str"), + assigned_object_type=dict(required=False, type="str"), + assigned_object=dict(required=False, type="raw"), + description=dict(required=False, type="str"), + comments=dict(required=False, type="str"), + tags=dict(required=False, type="list", elements="raw"), + custom_fields=dict(required=False, type="dict"), + ), + ), + ) + ) + + required_if = [("state", "present", ["mac_address"]), ("state", "absent", ["mac_address"])] + required_together = [("assigned_object_type", "assigned_object")] + + module = NetboxAnsibleModule( + argument_spec=argument_spec, + supports_check_mode=True, + required_if=required_if, + required_together=required_together, + ) + + netbox_mac_address = NetboxDcimModule(module, NB_MAC_ADDRESSES) + netbox_mac_address.run() + + +if __name__ == "__main__": # pragma: no cover + main() \ No newline at end of file diff --git a/tests/integration/targets/v4.2/tasks/main.yml b/tests/integration/targets/v4.2/tasks/main.yml index 9b5b5c21a..bdfbd6c64 100644 --- a/tests/integration/targets/v4.2/tasks/main.yml +++ b/tests/integration/targets/v4.2/tasks/main.yml @@ -732,3 +732,12 @@ - netbox_tunnel_group tags: - netbox_tunnel_group + +- name: NETBOX_MAC_ADDRESS TESTS + ansible.builtin.include_tasks: + file: netbox_mac_address.yml + apply: + tags: + - netbox_mac_address + tags: + - netbox_mac_address diff --git a/tests/integration/targets/v4.2/tasks/netbox_mac_address.yml b/tests/integration/targets/v4.2/tasks/netbox_mac_address.yml new file mode 100644 index 000000000..51fe8b48f --- /dev/null +++ b/tests/integration/targets/v4.2/tasks/netbox_mac_address.yml @@ -0,0 +1,69 @@ +--- +## +## +### NETBOX_MAC_ADDRESS +## +## +- name: "MAC 1: Create MAC address with required parameters" + netbox.netbox.netbox_mac_address: + netbox_url: http://localhost:32768 + netbox_token: "0123456789abcdef0123456789abcdef01234567" + data: + mac_address: "00:11:22:33:44:55" + state: present + register: test_one + +- name: "MAC 1: ASSERT - Create MAC address" + ansible.builtin.assert: + that: + - test_one is changed + - test_one['diff']['before']['state'] == "absent" + - test_one['diff']['after']['state'] == "present" + - test_one['mac_address']['mac_address'] == "00:11:22:33:44:55" + - test_one['msg'] == "mac_address 00:11:22:33:44:55 created" + +- name: "MAC 2: Create MAC address with all parameters" + netbox.netbox.netbox_mac_address: + netbox_url: http://localhost:32768 + netbox_token: "0123456789abcdef0123456789abcdef01234567" + data: + mac_address: "AA:BB:CC:DD:EE:FF" + assigned_object_type: "dcim.interface" + assigned_object: Test Interface + description: "Test MAC address" + comments: "Test MAC address comment" + tags: + - Schnozzberry + state: present + register: test_two + +- name: "MAC 2: ASSERT - Create MAC address with all parameters" + ansible.builtin.assert: + that: + - test_two is changed + - test_two['diff']['before']['state'] == "absent" + - test_two['diff']['after']['state'] == "present" + - test_two['mac_address']['mac_address'] == "AA:BB:CC:DD:EE:FF" + - test_two['mac_address']['assigned_object_type'] == "dcim.interface" + - test_two['mac_address']['assigned_object']['id'] == 1 + - test_two['mac_address']['description'] == "Test MAC address" + - test_two['mac_address']['comments'] == "Test MAC address comment" + - test_two['mac_address']['tags'][0] == 4 + - test_two['msg'] == "mac_address AA:BB:CC:DD:EE:FF created" + +- name: "MAC 3: Delete MAC address" + netbox.netbox.netbox_mac_address: + netbox_url: http://localhost:32768 + netbox_token: "0123456789abcdef0123456789abcdef01234567" + data: + mac_address: "00:11:22:33:44:55" + state: absent + register: test_three + +- name: "MAC 3: ASSERT - Delete MAC address" + ansible.builtin.assert: + that: + - test_three is changed + - test_three['diff']['before']['state'] == "present" + - test_three['diff']['after']['state'] == "absent" + - test_three['msg'] == "mac_address 00:11:22:33:44:55 deleted" \ No newline at end of file From e770ad82ae3e152b3a2029dfdf8ffc4719bf4035 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20R=C3=B8dvand?= Date: Sun, 19 Jan 2025 20:53:33 +0100 Subject: [PATCH 09/19] Adjust tests and mac address module --- plugins/module_utils/netbox_utils.py | 2 +- plugins/modules/netbox_mac_address.py | 28 +++++++++---------- .../targets/v4.2/tasks/netbox_mac_address.yml | 4 ++- 3 files changed, 17 insertions(+), 17 deletions(-) diff --git a/plugins/module_utils/netbox_utils.py b/plugins/module_utils/netbox_utils.py index 644563d11..be954d84b 100644 --- a/plugins/module_utils/netbox_utils.py +++ b/plugins/module_utils/netbox_utils.py @@ -1418,7 +1418,7 @@ def _normalize_data(self, data): # We need to assign the correct type for the assigned object so the user doesn't have to worry about this. # We determine it by whether or not they pass in a device or virtual_machine - if data.get("assigned_object"): + if data.get("assigned_object") and isinstance(data["assigned_object"], dict): if data["assigned_object"].get("device"): data["assigned_object_type"] = "dcim.interface" if data["assigned_object"].get("virtual_machine"): diff --git a/plugins/modules/netbox_mac_address.py b/plugins/modules/netbox_mac_address.py index 1051086ad..6295315dd 100644 --- a/plugins/modules/netbox_mac_address.py +++ b/plugins/modules/netbox_mac_address.py @@ -33,17 +33,12 @@ description: - The MAC address required: true - type: str - assigned_object_type: - description: - - Type of the assigned object - required: false - type: str + type: str assigned_object: description: - The object to assign this MAC address to required: false - type: raw + type: dict description: description: - Description of the MAC address @@ -88,10 +83,11 @@ netbox_url: http://netbox.local netbox_token: thisIsMyToken data: - mac_address: "AA:BB:CC:DD:EE:FF" - assigned_object_type: "dcim.interface" - assigned_object: "eth0" - description: "MAC address for eth0" + mac_address: "AA:BB:CC:DD:EE:FF" + assigned_object: + device: Test Nexus One + name: Ethernet1/1 + description: "MAC address for eth1/1" tags: - Network state: present @@ -139,8 +135,7 @@ def main(): required=True, options=dict( mac_address=dict(required=True, type="str"), - assigned_object_type=dict(required=False, type="str"), - assigned_object=dict(required=False, type="raw"), + assigned_object=dict(required=False, type="dict"), description=dict(required=False, type="str"), comments=dict(required=False, type="str"), tags=dict(required=False, type="list", elements="raw"), @@ -150,7 +145,10 @@ def main(): ) ) - required_if = [("state", "present", ["mac_address"]), ("state", "absent", ["mac_address"])] + required_if = [ + ("state", "present", ["mac_address"]), + ("state", "absent", ["mac_address"]), + ] required_together = [("assigned_object_type", "assigned_object")] module = NetboxAnsibleModule( @@ -165,4 +163,4 @@ def main(): if __name__ == "__main__": # pragma: no cover - main() \ No newline at end of file + main() diff --git a/tests/integration/targets/v4.2/tasks/netbox_mac_address.yml b/tests/integration/targets/v4.2/tasks/netbox_mac_address.yml index 51fe8b48f..81d039033 100644 --- a/tests/integration/targets/v4.2/tasks/netbox_mac_address.yml +++ b/tests/integration/targets/v4.2/tasks/netbox_mac_address.yml @@ -29,7 +29,9 @@ data: mac_address: "AA:BB:CC:DD:EE:FF" assigned_object_type: "dcim.interface" - assigned_object: Test Interface + assigned_object: + device: Test Nexus One + name: Ethernet1/1 description: "Test MAC address" comments: "Test MAC address comment" tags: From 3564b7d1a0520afba7e3c353417ee9de9ecf7614 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20R=C3=B8dvand?= Date: Sun, 19 Jan 2025 20:58:19 +0100 Subject: [PATCH 10/19] Adjust test order --- tests/integration/targets/v4.2/tasks/main.yml | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/tests/integration/targets/v4.2/tasks/main.yml b/tests/integration/targets/v4.2/tasks/main.yml index bdfbd6c64..f66aabc67 100644 --- a/tests/integration/targets/v4.2/tasks/main.yml +++ b/tests/integration/targets/v4.2/tasks/main.yml @@ -332,15 +332,6 @@ tags: - netbox_circuit -- name: NETBOX_CIRCUIT_TERMINATION TESTS - ansible.builtin.include_tasks: - file: netbox_circuit_termination.yml - apply: - tags: - - netbox_circuit_termination - tags: - - netbox_circuit_termination - - name: NETBOX_REAR_PORT TESTS ansible.builtin.include_tasks: file: netbox_rear_port.yml @@ -741,3 +732,12 @@ - netbox_mac_address tags: - netbox_mac_address + +- name: NETBOX_CIRCUIT_TERMINATION TESTS + ansible.builtin.include_tasks: + file: netbox_circuit_termination.yml + apply: + tags: + - netbox_circuit_termination + tags: + - netbox_circuit_termination \ No newline at end of file From 9ca68905f02dcb7398213b67bec1736066495012 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20R=C3=B8dvand?= Date: Sun, 19 Jan 2025 21:55:50 +0100 Subject: [PATCH 11/19] Adjust for new mac address assignment method --- meta/runtime.yml | 1 + plugins/module_utils/netbox_utils.py | 1 + plugins/modules/netbox_device_interface.py | 6 ++++++ plugins/modules/netbox_vm_interface.py | 6 ++++++ tests/integration/netbox-deploy.py | 10 ++++++++++ .../v4.2/tasks/netbox_device_interface.yml | 20 +++++++++++++++++++ .../targets/v4.2/tasks/netbox_mac_address.yml | 3 +-- 7 files changed, 45 insertions(+), 2 deletions(-) diff --git a/meta/runtime.yml b/meta/runtime.yml index a20a9c404..863ab2802 100644 --- a/meta/runtime.yml +++ b/meta/runtime.yml @@ -51,6 +51,7 @@ action_groups: - netbox_l2vpn - netbox_l2vpn_termination - netbox_location + - netbox_mac_address - netbox_manufacturer - netbox_module - netbox_module_bay diff --git a/plugins/module_utils/netbox_utils.py b/plugins/module_utils/netbox_utils.py index be954d84b..08a756234 100644 --- a/plugins/module_utils/netbox_utils.py +++ b/plugins/module_utils/netbox_utils.py @@ -277,6 +277,7 @@ "ipsec_profile": "ipsec_profiles", "location": "locations", "lag": "interfaces", + "primary_mac_address": "mac_addresses", "manufacturer": "manufacturers", "master": "devices", "module": "modules", diff --git a/plugins/modules/netbox_device_interface.py b/plugins/modules/netbox_device_interface.py index 63980f922..42d6e73b8 100644 --- a/plugins/modules/netbox_device_interface.py +++ b/plugins/modules/netbox_device_interface.py @@ -86,6 +86,11 @@ - The MAC address of the interface required: false type: str + primary_mac_address: + description: + - The primary MAC address of the interface (NetBox 4.2 and later) + required: false + type: str wwn: description: - The WWN of the interface @@ -335,6 +340,7 @@ def main(): bridge=dict(required=False, type="raw"), mtu=dict(required=False, type="int"), mac_address=dict(required=False, type="str"), + primary_mac_address=dict(required=False, type="str"), wwn=dict(required=False, type="str"), mgmt_only=dict(required=False, type="bool"), poe_type=dict(required=False, type="raw"), diff --git a/plugins/modules/netbox_vm_interface.py b/plugins/modules/netbox_vm_interface.py index d4bf739f2..133bfee21 100644 --- a/plugins/modules/netbox_vm_interface.py +++ b/plugins/modules/netbox_vm_interface.py @@ -53,6 +53,11 @@ - The MAC address of the interface required: false type: str + primary_mac_address: + description: + - The primary MAC address of the interface (NetBox 4.2 and later) + required: false + type: str description: description: - The description of the interface @@ -209,6 +214,7 @@ def main(): enabled=dict(required=False, type="bool"), mtu=dict(required=False, type="int"), mac_address=dict(required=False, type="str"), + primary_mac_address=dict(required=False, type="str"), description=dict(required=False, type="str"), mode=dict(required=False, type="raw"), vm_bridge=dict(required=False, type="raw"), diff --git a/tests/integration/netbox-deploy.py b/tests/integration/netbox-deploy.py index 68f28cb2e..36c6faa6a 100755 --- a/tests/integration/netbox-deploy.py +++ b/tests/integration/netbox-deploy.py @@ -372,6 +372,16 @@ def make_netbox_calls(endpoint, payload): ] created_interfaces = make_netbox_calls(nb.dcim.interfaces, dev_interfaces) +# Create MAC addresses +if nb_version >= version.parse("4.2"): + test100_gi1 = nb.dcim.interfaces.get(name="GigabitEthernet1", device_id=1) + test100_gi2 = nb.dcim.interfaces.get(name="GigabitEthernet2", device_id=1) + mac_addresses = [ + {"mac_address": "AA:BB:CC:DD:EE:FF", "assigned_object_id": test100_gi1.id, "assigned_object_type": "dcim.interface"}, + {"mac_address": "AA:AB:CC:DD:EE:FF", "assigned_object_id": test100_gi2.id, "assigned_object_type": "dcim.interface"}, + ] + created_mac_addresses = make_netbox_calls(nb.dcim.mac_addresses, mac_addresses) + # Wireless Interfaces if nb_version >= version.parse("3.1"): wlink_interfaces = [ diff --git a/tests/integration/targets/v4.2/tasks/netbox_device_interface.yml b/tests/integration/targets/v4.2/tasks/netbox_device_interface.yml index dd3c2383b..6cd6cab78 100644 --- a/tests/integration/targets/v4.2/tasks/netbox_device_interface.yml +++ b/tests/integration/targets/v4.2/tasks/netbox_device_interface.yml @@ -310,3 +310,23 @@ - test_twelve['interface']['name'] == "GigabitEthernet5" - test_twelve['interface']['device'] == 1 - test_twelve['interface']['mark_connected'] == true + +- name: "13 - Update interface primary MAC address" + netbox.netbox.netbox_device_interface: + netbox_url: http://localhost:32768 + netbox_token: "0123456789abcdef0123456789abcdef01234567" + data: + device: test100 + name: GigabitEthernet2 + primary_mac_address: "AA:AB:CC:DD:EE:FF" + state: present + register: test_fourteen + +- name: "14 - ASSERT" + ansible.builtin.assert: + that: + - not test_fourteen['changed'] + - test_fourteen['msg'] == "interface GigabitEthernet2 updated" + - test_fourteen['interface']['name'] == "GigabitEthernet2" + - test_fourteen['interface']['device'] == 1 + - test_fourteen['interface']['primary_mac_address'] == "AA:AB:CC:DD:EE:FF" diff --git a/tests/integration/targets/v4.2/tasks/netbox_mac_address.yml b/tests/integration/targets/v4.2/tasks/netbox_mac_address.yml index 81d039033..682e66c28 100644 --- a/tests/integration/targets/v4.2/tasks/netbox_mac_address.yml +++ b/tests/integration/targets/v4.2/tasks/netbox_mac_address.yml @@ -27,8 +27,7 @@ netbox_url: http://localhost:32768 netbox_token: "0123456789abcdef0123456789abcdef01234567" data: - mac_address: "AA:BB:CC:DD:EE:FF" - assigned_object_type: "dcim.interface" + mac_address: "AA:BB:CC:DD:EE:FF" assigned_object: device: Test Nexus One name: Ethernet1/1 From c73454d4927b6be78e783b1c275bb9237a228ae8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20R=C3=B8dvand?= Date: Sun, 19 Jan 2025 21:56:14 +0100 Subject: [PATCH 12/19] Reformat netbox-deploy --- tests/integration/netbox-deploy.py | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/tests/integration/netbox-deploy.py b/tests/integration/netbox-deploy.py index 36c6faa6a..af5a7b5af 100755 --- a/tests/integration/netbox-deploy.py +++ b/tests/integration/netbox-deploy.py @@ -377,8 +377,16 @@ def make_netbox_calls(endpoint, payload): test100_gi1 = nb.dcim.interfaces.get(name="GigabitEthernet1", device_id=1) test100_gi2 = nb.dcim.interfaces.get(name="GigabitEthernet2", device_id=1) mac_addresses = [ - {"mac_address": "AA:BB:CC:DD:EE:FF", "assigned_object_id": test100_gi1.id, "assigned_object_type": "dcim.interface"}, - {"mac_address": "AA:AB:CC:DD:EE:FF", "assigned_object_id": test100_gi2.id, "assigned_object_type": "dcim.interface"}, + { + "mac_address": "AA:BB:CC:DD:EE:FF", + "assigned_object_id": test100_gi1.id, + "assigned_object_type": "dcim.interface", + }, + { + "mac_address": "AA:AB:CC:DD:EE:FF", + "assigned_object_id": test100_gi2.id, + "assigned_object_type": "dcim.interface", + }, ] created_mac_addresses = make_netbox_calls(nb.dcim.mac_addresses, mac_addresses) From 67f1f0ee7081c1ec601249679dd975c553545346 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20R=C3=B8dvand?= Date: Sun, 19 Jan 2025 22:16:43 +0100 Subject: [PATCH 13/19] Fix integration test --- .../targets/v4.2/tasks/netbox_device_interface.yml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/tests/integration/targets/v4.2/tasks/netbox_device_interface.yml b/tests/integration/targets/v4.2/tasks/netbox_device_interface.yml index 6cd6cab78..4b0460bde 100644 --- a/tests/integration/targets/v4.2/tasks/netbox_device_interface.yml +++ b/tests/integration/targets/v4.2/tasks/netbox_device_interface.yml @@ -320,13 +320,13 @@ name: GigabitEthernet2 primary_mac_address: "AA:AB:CC:DD:EE:FF" state: present - register: test_fourteen + register: test_thirteen -- name: "14 - ASSERT" +- name: "13 - ASSERT" ansible.builtin.assert: that: - - not test_fourteen['changed'] - - test_fourteen['msg'] == "interface GigabitEthernet2 updated" - - test_fourteen['interface']['name'] == "GigabitEthernet2" - - test_fourteen['interface']['device'] == 1 + - test_thirteen is changed + - test_thirteen['msg'] == "interface GigabitEthernet2 updated" + - test_thirteen['interface']['name'] == "GigabitEthernet2" + - test_thirteen['interface']['device'] == 1 - test_fourteen['interface']['primary_mac_address'] == "AA:AB:CC:DD:EE:FF" From a545bdeced0129ce959b40c9208a44b0cda21450 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20R=C3=B8dvand?= Date: Sun, 19 Jan 2025 22:31:45 +0100 Subject: [PATCH 14/19] Variable error --- .../integration/targets/v4.2/tasks/netbox_device_interface.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/integration/targets/v4.2/tasks/netbox_device_interface.yml b/tests/integration/targets/v4.2/tasks/netbox_device_interface.yml index 4b0460bde..272876852 100644 --- a/tests/integration/targets/v4.2/tasks/netbox_device_interface.yml +++ b/tests/integration/targets/v4.2/tasks/netbox_device_interface.yml @@ -329,4 +329,4 @@ - test_thirteen['msg'] == "interface GigabitEthernet2 updated" - test_thirteen['interface']['name'] == "GigabitEthernet2" - test_thirteen['interface']['device'] == 1 - - test_fourteen['interface']['primary_mac_address'] == "AA:AB:CC:DD:EE:FF" + - test_thirteen['interface']['primary_mac_address'] == "AA:AB:CC:DD:EE:FF" From ccdbe501ce58a99c7d50cce5566f7c6acb293357 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20R=C3=B8dvand?= Date: Sun, 19 Jan 2025 22:43:15 +0100 Subject: [PATCH 15/19] Refer to ID --- .../integration/targets/v4.2/tasks/netbox_device_interface.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/integration/targets/v4.2/tasks/netbox_device_interface.yml b/tests/integration/targets/v4.2/tasks/netbox_device_interface.yml index 272876852..5013b6edc 100644 --- a/tests/integration/targets/v4.2/tasks/netbox_device_interface.yml +++ b/tests/integration/targets/v4.2/tasks/netbox_device_interface.yml @@ -329,4 +329,4 @@ - test_thirteen['msg'] == "interface GigabitEthernet2 updated" - test_thirteen['interface']['name'] == "GigabitEthernet2" - test_thirteen['interface']['device'] == 1 - - test_thirteen['interface']['primary_mac_address'] == "AA:AB:CC:DD:EE:FF" + - test_thirteen['interface']['primary_mac_address'] == 2 From 570f9791ee94a68cd3b600a8179d3c10b50fa826 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20R=C3=B8dvand?= Date: Sun, 19 Jan 2025 22:59:39 +0100 Subject: [PATCH 16/19] Fix required_together --- plugins/modules/netbox_mac_address.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/plugins/modules/netbox_mac_address.py b/plugins/modules/netbox_mac_address.py index 6295315dd..9af880fd6 100644 --- a/plugins/modules/netbox_mac_address.py +++ b/plugins/modules/netbox_mac_address.py @@ -149,13 +149,11 @@ def main(): ("state", "present", ["mac_address"]), ("state", "absent", ["mac_address"]), ] - required_together = [("assigned_object_type", "assigned_object")] module = NetboxAnsibleModule( argument_spec=argument_spec, supports_check_mode=True, required_if=required_if, - required_together=required_together, ) netbox_mac_address = NetboxDcimModule(module, NB_MAC_ADDRESSES) From 6a334c2aa926b4c5875fb354fbaadfd41fc50ef7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20R=C3=B8dvand?= Date: Sun, 19 Jan 2025 23:20:06 +0100 Subject: [PATCH 17/19] Test adjustment --- .../integration/targets/v4.2/tasks/netbox_mac_address.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/integration/targets/v4.2/tasks/netbox_mac_address.yml b/tests/integration/targets/v4.2/tasks/netbox_mac_address.yml index 682e66c28..cafb99e4a 100644 --- a/tests/integration/targets/v4.2/tasks/netbox_mac_address.yml +++ b/tests/integration/targets/v4.2/tasks/netbox_mac_address.yml @@ -27,7 +27,7 @@ netbox_url: http://localhost:32768 netbox_token: "0123456789abcdef0123456789abcdef01234567" data: - mac_address: "AA:BB:CC:DD:EE:FF" + mac_address: "AA:BB:CC:DD:EE:F0" assigned_object: device: Test Nexus One name: Ethernet1/1 @@ -44,13 +44,13 @@ - test_two is changed - test_two['diff']['before']['state'] == "absent" - test_two['diff']['after']['state'] == "present" - - test_two['mac_address']['mac_address'] == "AA:BB:CC:DD:EE:FF" + - test_two['mac_address']['mac_address'] == "AA:BB:CC:DD:EE:F0" - test_two['mac_address']['assigned_object_type'] == "dcim.interface" - - test_two['mac_address']['assigned_object']['id'] == 1 + - test_two['mac_address']['assigned_object_id'] == 1 - test_two['mac_address']['description'] == "Test MAC address" - test_two['mac_address']['comments'] == "Test MAC address comment" - test_two['mac_address']['tags'][0] == 4 - - test_two['msg'] == "mac_address AA:BB:CC:DD:EE:FF created" + - test_two['msg'] == "mac_address AA:BB:CC:DD:EE:F0 created" - name: "MAC 3: Delete MAC address" netbox.netbox.netbox_mac_address: From 7ffe7ea105b49aa2366141d8416714dd227b0e49 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20R=C3=B8dvand?= Date: Sun, 19 Jan 2025 23:48:54 +0100 Subject: [PATCH 18/19] Linting and changelog fragment --- changelogs/fragments/netbox_mac_address.yml | 3 +++ plugins/modules/netbox_mac_address.py | 2 +- tests/integration/targets/v4.2/tasks/main.yml | 2 +- tests/integration/targets/v4.2/tasks/netbox_mac_address.yml | 4 ++-- 4 files changed, 7 insertions(+), 4 deletions(-) create mode 100644 changelogs/fragments/netbox_mac_address.yml diff --git a/changelogs/fragments/netbox_mac_address.yml b/changelogs/fragments/netbox_mac_address.yml new file mode 100644 index 000000000..86740c3d0 --- /dev/null +++ b/changelogs/fragments/netbox_mac_address.yml @@ -0,0 +1,3 @@ +minor_changes: + - netbox_device_interface - Add primary_mac_address option for NetBox 4.2+ + - netbox_vm_interface - Add primary_mac_address option for NetBox 4.2+ diff --git a/plugins/modules/netbox_mac_address.py b/plugins/modules/netbox_mac_address.py index 9af880fd6..c202e083d 100644 --- a/plugins/modules/netbox_mac_address.py +++ b/plugins/modules/netbox_mac_address.py @@ -83,7 +83,7 @@ netbox_url: http://netbox.local netbox_token: thisIsMyToken data: - mac_address: "AA:BB:CC:DD:EE:FF" + mac_address: "AA:BB:CC:DD:EE:FF" assigned_object: device: Test Nexus One name: Ethernet1/1 diff --git a/tests/integration/targets/v4.2/tasks/main.yml b/tests/integration/targets/v4.2/tasks/main.yml index f66aabc67..33ce77bcf 100644 --- a/tests/integration/targets/v4.2/tasks/main.yml +++ b/tests/integration/targets/v4.2/tasks/main.yml @@ -740,4 +740,4 @@ tags: - netbox_circuit_termination tags: - - netbox_circuit_termination \ No newline at end of file + - netbox_circuit_termination diff --git a/tests/integration/targets/v4.2/tasks/netbox_mac_address.yml b/tests/integration/targets/v4.2/tasks/netbox_mac_address.yml index cafb99e4a..88192d197 100644 --- a/tests/integration/targets/v4.2/tasks/netbox_mac_address.yml +++ b/tests/integration/targets/v4.2/tasks/netbox_mac_address.yml @@ -27,7 +27,7 @@ netbox_url: http://localhost:32768 netbox_token: "0123456789abcdef0123456789abcdef01234567" data: - mac_address: "AA:BB:CC:DD:EE:F0" + mac_address: "AA:BB:CC:DD:EE:F0" assigned_object: device: Test Nexus One name: Ethernet1/1 @@ -67,4 +67,4 @@ - test_three is changed - test_three['diff']['before']['state'] == "present" - test_three['diff']['after']['state'] == "absent" - - test_three['msg'] == "mac_address 00:11:22:33:44:55 deleted" \ No newline at end of file + - test_three['msg'] == "mac_address 00:11:22:33:44:55 deleted" From 57c5f41241e6710b9dd6c761356ec3e34f3af1da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20R=C3=B8dvand?= Date: Sun, 19 Jan 2025 23:55:13 +0100 Subject: [PATCH 19/19] Linting --- plugins/modules/netbox_mac_address.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/modules/netbox_mac_address.py b/plugins/modules/netbox_mac_address.py index c202e083d..7d70b8269 100644 --- a/plugins/modules/netbox_mac_address.py +++ b/plugins/modules/netbox_mac_address.py @@ -33,7 +33,7 @@ description: - The MAC address required: true - type: str + type: str assigned_object: description: - The object to assign this MAC address to