Skip to content

Commit 32fdc29

Browse files
authored
New modules: netbox_cable, netbox_device_bay_template and netbox_virtual_chassis management (#251)
1 parent 2608600 commit 32fdc29

File tree

12 files changed

+1241
-53
lines changed

12 files changed

+1241
-53
lines changed

README.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ To keep the code simple, we only officially support the two latest releases of N
1919
## Existing Modules
2020

2121
- netbox_aggregate
22+
- netbox_cable
2223
- netbox_circuit
2324
- netbox_circuit_termination
2425
- netbox_circuit_type
@@ -30,6 +31,7 @@ To keep the code simple, we only officially support the two latest releases of N
3031
- netbox_console_server_port
3132
- netbox_console_server_port_template
3233
- netbox_device_bay
34+
- netbox_device_bay_template
3335
- netbox_device_interface
3436
- netbox_device_role
3537
- netbox_device_type
@@ -60,6 +62,7 @@ To keep the code simple, we only officially support the two latest releases of N
6062
- netbox_service
6163
- netbox_tenant_group
6264
- netbox_tenant
65+
- netbox_virtual_chassis
6366
- netbox_virtual_machine
6467
- netbox_vm_interface
6568
- netbox_vlan_group

plugins/module_utils/netbox_dcim.py

Lines changed: 52 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
# -*- coding: utf-8 -*-
22
# Copyright: (c) 2018, Mikhail Yohman (@fragmentedpacket) <mikhail.yohman@gmail.com>
3+
# Copyright: (c) 2020, Nokia, Tobias Groß (@toerb) <tobias.gross@nokia.com>
34
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
45
from __future__ import absolute_import, division, print_function
56

@@ -16,11 +17,13 @@
1617
)
1718

1819

20+
NB_CABLES = "cables"
1921
NB_CONSOLE_PORTS = "console_ports"
2022
NB_CONSOLE_PORT_TEMPLATES = "console_port_templates"
2123
NB_CONSOLE_SERVER_PORTS = "console_server_ports"
2224
NB_CONSOLE_SERVER_PORT_TEMPLATES = "console_server_port_templates"
2325
NB_DEVICE_BAYS = "device_bays"
26+
NB_DEVICE_BAY_TEMPLATES = "device_bay_templates"
2427
NB_DEVICES = "devices"
2528
NB_DEVICE_ROLES = "device_roles"
2629
NB_DEVICE_TYPES = "device_types"
@@ -43,6 +46,7 @@
4346
NB_REAR_PORT_TEMPLATES = "rear_port_templates"
4447
NB_REGIONS = "regions"
4548
NB_SITES = "sites"
49+
NB_VIRTUAL_CHASSIS = "virtual_chassis"
4650

4751

4852
class NetboxDcimModule(NetboxModule):
@@ -54,11 +58,13 @@ def run(self):
5458
This function should have all necessary code for endpoints within the application
5559
to create/update/delete the endpoint objects
5660
Supported endpoints:
61+
- cables
5762
- console_ports
5863
- console_port_templates
5964
- console_server_ports
6065
- console_server_port_templates
6166
- device_bays
67+
- device_bay_templates
6268
- devices
6369
- device_roles
6470
- device_types
@@ -81,6 +87,7 @@ def run(self):
8187
- rear_ports
8288
- rear_port_templates
8389
- regions
90+
- virtual_chassis
8491
"""
8592
# Used to dynamically set key when returning results
8693
endpoint_name = ENDPOINT_NAME_MAPPING[self.endpoint]
@@ -99,8 +106,31 @@ def run(self):
99106
name = data["name"]
100107
elif data.get("model") and not data.get("slug"):
101108
name = data["model"]
109+
elif data.get("master"):
110+
name = self.module.params["data"]["master"]
102111
elif data.get("slug"):
103112
name = data["slug"]
113+
elif endpoint_name == "cable":
114+
if self.module.params["data"]["termination_a"].get("name"):
115+
termination_a_name = self.module.params["data"]["termination_a"]["name"]
116+
elif self.module.params["data"]["termination_a"].get("slug"):
117+
termination_a_name = self.module.params["data"]["termination_a"]["slug"]
118+
else:
119+
termination_a_name = data.get("termination_a_id")
120+
121+
if self.module.params["data"]["termination_b"].get("name"):
122+
termination_b_name = self.module.params["data"]["termination_b"]["name"]
123+
elif self.module.params["data"]["termination_b"].get("slug"):
124+
termination_b_name = self.module.params["data"]["termination_b"]["slug"]
125+
else:
126+
termination_b_name = data.get("termination_b_id")
127+
128+
name = "%s %s <> %s %s" % (
129+
data.get("termination_a_type"),
130+
termination_a_name,
131+
data.get("termination_b_type"),
132+
termination_b_name,
133+
)
104134

105135
if self.endpoint in SLUG_REQUIRED:
106136
if not data.get("slug"):
@@ -110,10 +140,28 @@ def run(self):
110140
if data.get("color"):
111141
data["color"] = data["color"].lower()
112142

113-
object_query_params = self._build_query_params(
114-
endpoint_name, data, user_query_params
115-
)
116-
self.nb_object = self._nb_endpoint_get(nb_endpoint, object_query_params, name)
143+
if self.endpoint == "cables":
144+
cables = [
145+
cable
146+
for cable in nb_endpoint.all()
147+
if cable.termination_a_type == data["termination_a_type"]
148+
and cable.termination_a_id == data["termination_a_id"]
149+
and cable.termination_b_type == data["termination_b_type"]
150+
and cable.termination_b_id == data["termination_b_id"]
151+
]
152+
if len(cables) == 0:
153+
self.nb_object = None
154+
elif len(cables) == 1:
155+
self.nb_object = cables[0]
156+
else:
157+
self._handle_errors(msg="More than one result returned for %s" % (name))
158+
else:
159+
object_query_params = self._build_query_params(
160+
endpoint_name, data, user_query_params
161+
)
162+
self.nb_object = self._nb_endpoint_get(
163+
nb_endpoint, object_query_params, name
164+
)
117165

118166
# This is logic to handle interfaces on a VC
119167
if self.endpoint == "interfaces":

plugins/module_utils/netbox_utils.py

Lines changed: 93 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
# -*- coding: utf-8 -*-
22
# Copyright: (c) 2018, Mikhail Yohman (@fragmentedpacket) <mikhail.yohman@gmail.com>
33
# Copyright: (c) 2018, David Gomez (@amb1s1) <david.gomez@networktocode.com>
4+
# Copyright: (c) 2020, Nokia, Tobias Groß (@toerb) <tobias.gross@nokia.com>
45
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
56

67
from __future__ import absolute_import, division, print_function
@@ -35,11 +36,13 @@
3536
API_APPS_ENDPOINTS = dict(
3637
circuits=["circuits", "circuit_types", "circuit_terminations", "providers"],
3738
dcim=[
39+
"cables",
3840
"console_ports",
3941
"console_port_templates",
4042
"console_server_ports",
4143
"console_server_port_templates",
4244
"device_bays",
45+
"device_bay_templates",
4346
"devices",
4447
"device_roles",
4548
"device_types",
@@ -62,6 +65,7 @@
6265
"rear_port_templates",
6366
"regions",
6467
"sites",
68+
"virtual_chassis",
6569
],
6670
extras=[],
6771
ipam=[
@@ -124,56 +128,70 @@
124128
)
125129

126130
# Specifies keys within data that need to be converted to ID and the endpoint to be used when queried
127-
CONVERT_TO_ID = dict(
128-
circuit="circuits",
129-
circuit_type="circuit_types",
130-
circuit_termination="circuit_terminations",
131-
cluster="clusters",
132-
cluster_group="cluster_groups",
133-
cluster_type="cluster_types",
134-
device="devices",
135-
device_role="device_roles",
136-
device_type="device_types",
137-
group="tenant_groups",
138-
installed_device="devices",
139-
interface="interfaces",
140-
ip_addresses="ip_addresses",
141-
ipaddresses="ip_addresses",
142-
lag="interfaces",
143-
manufacturer="manufacturers",
144-
nat_inside="ip_addresses",
145-
nat_outside="ip_addresses",
146-
platform="platforms",
147-
parent_region="regions",
148-
power_panel="power_panels",
149-
power_port="power_ports",
150-
prefix_role="roles",
151-
primary_ip="ip_addresses",
152-
primary_ip4="ip_addresses",
153-
primary_ip6="ip_addresses",
154-
provider="providers",
155-
rack="racks",
156-
rack_group="rack_groups",
157-
rack_role="rack_roles",
158-
region="regions",
159-
rear_port="rear_ports",
160-
rir="rirs",
161-
services="services",
162-
site="sites",
163-
tagged_vlans="vlans",
164-
tenant="tenants",
165-
tenant_group="tenant_groups",
166-
untagged_vlan="vlans",
167-
virtual_machine="virtual_machines",
168-
virtual_machine_role="device_roles",
169-
vlan="vlans",
170-
vlan_group="vlan_groups",
171-
vlan_role="roles",
172-
vrf="vrfs",
173-
)
131+
CONVERT_TO_ID = {
132+
"circuit": "circuits",
133+
"circuit_type": "circuit_types",
134+
"circuit_termination": "circuit_terminations",
135+
"circuit.circuittermination": "circuit_terminations",
136+
"cluster": "clusters",
137+
"cluster_group": "cluster_groups",
138+
"cluster_type": "cluster_types",
139+
"dcim.consoleport": "console_ports",
140+
"dcim.consoleserverport": "console_server_ports",
141+
"dcim.frontport": "front_ports",
142+
"dcim.interface": "interfaces",
143+
"dcim.powerfeed": "power_feeds",
144+
"dcim.poweroutlet": "power_outlet",
145+
"dcim.powerport": "power_port",
146+
"dcim.rearport": "rear_port",
147+
"device": "devices",
148+
"device_role": "device_roles",
149+
"device_type": "device_types",
150+
"group": "tenant_groups",
151+
"installed_device": "devices",
152+
"interface": "interfaces",
153+
"ip_addresses": "ip_addresses",
154+
"ipaddresses": "ip_addresses",
155+
"lag": "interfaces",
156+
"manufacturer": "manufacturers",
157+
"master": "devices",
158+
"nat_inside": "ip_addresses",
159+
"nat_outside": "ip_addresses",
160+
"platform": "platforms",
161+
"parent_region": "regions",
162+
"power_panel": "power_panels",
163+
"power_port": "power_ports",
164+
"prefix_role": "roles",
165+
"primary_ip": "ip_addresses",
166+
"primary_ip4": "ip_addresses",
167+
"primary_ip6": "ip_addresses",
168+
"provider": "providers",
169+
"rack": "racks",
170+
"rack_group": "rack_groups",
171+
"rack_role": "rack_roles",
172+
"region": "regions",
173+
"rear_port": "rear_ports",
174+
"rir": "rirs",
175+
"services": "services",
176+
"site": "sites",
177+
"tagged_vlans": "vlans",
178+
"tenant": "tenants",
179+
"tenant_group": "tenant_groups",
180+
"termination_a": "interfaces",
181+
"termination_b": "interfaces",
182+
"untagged_vlan": "vlans",
183+
"virtual_chassis": "virtual_chassis",
184+
"virtual_machine": "virtual_machines",
185+
"virtual_machine_role": "device_roles",
186+
"vlan": "vlans",
187+
"vlan_group": "vlan_groups",
188+
"vlan_role": "roles",
189+
"vrf": "vrfs",
190+
}
174191

175192
ENDPOINT_NAME_MAPPING = {
176193
"aggregates": "aggregate",
194+
"cables": "cable",
177195
"circuit_terminations": "circuit_termination",
178196
"circuit_types": "circuit_type",
179197
"circuits": "circuit",
@@ -185,6 +203,7 @@
185203
"console_server_ports": "console_server_port",
186204
"console_server_port_templates": "console_server_port_template",
187205
"device_bays": "device_bay",
206+
"device_bay_templates": "device_bay_template",
188207
"devices": "device",
189208
"device_roles": "device_role",
190209
"device_types": "device_type",
@@ -215,6 +234,7 @@
215234
"sites": "site",
216235
"tenants": "tenant",
217236
"tenant_groups": "tenant_group",
237+
"virtual_chassis": "virtual_chassis",
218238
"virtual_machines": "virtual_machine",
219239
"vlans": "vlan",
220240
"vlan_groups": "vlan_group",
@@ -226,14 +246,24 @@
226246
"circuit": set(["cid"]),
227247
"circuit_type": set(["slug"]),
228248
"circuit_termination": set(["circuit", "term_side"]),
249+
"circuit.circuittermination": set(["circuit", "term_side"]),
229250
"cluster": set(["name", "type"]),
230251
"cluster_group": set(["slug"]),
231252
"cluster_type": set(["slug"]),
232253
"console_port": set(["name", "device"]),
233254
"console_port_template": set(["name", "device_type"]),
234255
"console_server_port": set(["name", "device"]),
235256
"console_server_port_template": set(["name", "device_type"]),
257+
"dcim.consoleport": set(["name", "device"]),
258+
"dcim.consoleserverport": set(["name", "device"]),
259+
"dcim.frontport": set(["name", "device", "rear_port"]),
260+
"dcim.interface": set(["name", "device", "virtual_machine"]),
261+
"dcim.powerfeed": set(["name", "power_panel"]),
262+
"dcim.poweroutlet": set(["name", "device"]),
263+
"dcim.powerport": set(["name", "device"]),
264+
"dcim.rearport": set(["name", "device"]),
236265
"device_bay": set(["name", "device"]),
266+
"device_bay_template": set(["name", "device_type"]),
237267
"device": set(["name"]),
238268
"device_role": set(["slug"]),
239269
"device_type": set(["slug"]),
@@ -247,6 +277,7 @@
247277
"ipaddresses": set(["address", "vrf", "device", "interface"]),
248278
"lag": set(["name"]),
249279
"manufacturer": set(["slug"]),
280+
"master": set(["name"]),
250281
"nat_inside": set(["vrf", "address"]),
251282
"parent_region": set(["slug"]),
252283
"platform": set(["slug"]),
@@ -273,7 +304,10 @@
273304
"tagged_vlans": set(["name", "site", "vlan_group", "tenant"]),
274305
"tenant": set(["slug"]),
275306
"tenant_group": set(["slug"]),
307+
"termination_a": set(["name", "device", "virtual_machine"]),
308+
"termination_b": set(["name", "device", "virtual_machine"]),
276309
"untagged_vlan": set(["name", "site", "vlan_group", "tenant"]),
310+
"virtual_chassis": set(["master"]),
277311
"virtual_machine": set(["name", "cluster"]),
278312
"vlan": set(["name", "site", "tenant", "vlan_group"]),
279313
"vlan_group": set(["slug", "site"]),
@@ -297,6 +331,7 @@
297331
)
298332

299333
REQUIRED_ID_FIND = {
334+
"cables": set(["status", "type", "length_unit"]),
300335
"circuits": set(["status"]),
301336
"console_ports": set(["type"]),
302337
"console_port_templates": set(["type"]),
@@ -333,6 +368,8 @@
333368
"rack_group": "group",
334369
"rack_role": "role",
335370
"tenant_group": "group",
371+
"termination_a": "termination_a_id",
372+
"termination_b": "termination_b_id",
336373
"virtual_machine_role": "role",
337374
"vlan_role": "role",
338375
"vlan_group": "group",
@@ -360,7 +397,6 @@
360397
"vlan_groups",
361398
}
362399

363-
364400
NETBOX_ARG_SPEC = dict(
365401
netbox_url=dict(type="str", required=True),
366402
netbox_token=dict(type="str", required=True, no_log=True),
@@ -605,6 +641,9 @@ def _build_query_params(
605641
else:
606642
query_dict.update({"device": module_data["device"]})
607643

644+
elif parent == "virtual_chassis":
645+
query_dict = {"q": self.module.params["data"].get("master")}
646+
608647
query_dict = self._convert_identical_keys(query_dict)
609648
return query_dict
610649

@@ -666,7 +705,12 @@ def _find_ids(self, data, user_query_params):
666705
"""
667706
for k, v in data.items():
668707
if k in CONVERT_TO_ID:
669-
endpoint = CONVERT_TO_ID[k]
708+
if k == "termination_a":
709+
endpoint = CONVERT_TO_ID[data.get("termination_a_type")]
710+
elif k == "termination_b":
711+
endpoint = CONVERT_TO_ID[data.get("termination_b_type")]
712+
else:
713+
endpoint = CONVERT_TO_ID[k]
670714
search = v
671715
app = self._find_app(endpoint)
672716
nb_app = getattr(self.nb, app)

0 commit comments

Comments
 (0)