Skip to content

Commit c039789

Browse files
etonnerreerwan.tonnerre
and
erwan.tonnerre
authored
#769 : Add support for Module/Module Bay (#1206)
Co-authored-by: erwan.tonnerre <[email protected]>
1 parent 4ceb283 commit c039789

File tree

11 files changed

+1061
-0
lines changed

11 files changed

+1061
-0
lines changed

meta/runtime.yml

+2
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,8 @@ action_groups:
5050
- netbox_l2vpn_termination
5151
- netbox_location
5252
- netbox_manufacturer
53+
- netbox_module
54+
- netbox_module_bay
5355
- netbox_module_type
5456
- netbox_platform
5557
- netbox_power_feed

plugins/module_utils/netbox_dcim.py

+37
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@
3232
NB_INVENTORY_ITEM_ROLES = "inventory_item_roles"
3333
NB_LOCATIONS = "locations"
3434
NB_MANUFACTURERS = "manufacturers"
35+
NB_MODULES = "modules"
36+
NB_MODULE_BAYS = "module_bays"
3537
NB_MODULE_TYPES = "module_types"
3638
NB_PLATFORMS = "platforms"
3739
NB_POWER_FEEDS = "power_feeds"
@@ -91,6 +93,9 @@ def run(self):
9193
- inventory_item_roles
9294
- locations
9395
- manufacturers
96+
- modules
97+
- module_bays
98+
- module_types
9499
- platforms
95100
- power_feeds
96101
- power_outlets
@@ -150,6 +155,38 @@ def run(self):
150155
data.get("termination_b_type"),
151156
termination_b_name,
152157
)
158+
elif endpoint_name == "module":
159+
if isinstance(
160+
self.module.params["data"]["device"], dict
161+
) and self.module.params["data"]["device"].get("name"):
162+
device_name = self.module.params["data"]["device"]["name"]
163+
elif isinstance(
164+
self.module.params["data"]["device"], dict
165+
) and self.module.params["data"]["device"].get("slug"):
166+
device_name = self.module.params["data"]["device"]["slug"]
167+
else:
168+
device_name = self.module.params["data"]["device"]
169+
if isinstance(
170+
self.module.params["data"]["module_bay"], dict
171+
) and self.module.params["data"]["module_bay"].get("name"):
172+
module_bay = self.module.params["data"]["module_bay"]["name"]
173+
elif isinstance(
174+
self.module.params["data"]["module_bay"], dict
175+
) and self.module.params["data"]["module_bay"].get("slug"):
176+
module_bay = self.module.params["data"]["module_bay"]["slug"]
177+
else:
178+
module_bay = self.module.params["data"]["module_bay"]
179+
if isinstance(
180+
self.module.params["data"]["module_type"], dict
181+
) and self.module.params["data"]["module_bay"].get("model"):
182+
module_type = self.module.params["data"]["module_type"]["model"]
183+
elif isinstance(
184+
self.module.params["data"]["module_type"], dict
185+
) and self.module.params["data"]["module_bay"].get("part_number"):
186+
module_type = self.module.params["data"]["module_type"]["part_number"]
187+
else:
188+
module_type = self.module.params["data"]["module_type"]
189+
name = "%s: %s (%s)" % (device_name, module_bay, module_type)
153190

154191
if self.endpoint in SLUG_REQUIRED:
155192
if not data.get("slug"):

plugins/module_utils/netbox_utils.py

+17
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,8 @@
5858
"inventory_item_roles": {},
5959
"locations": {},
6060
"manufacturers": {},
61+
"modules": {},
62+
"module_bays": {},
6163
"module_types": {},
6264
"platforms": {},
6365
"power_feeds": {},
@@ -163,6 +165,8 @@
163165
l2vpn_termination="id",
164166
location="slug",
165167
manufacturer="slug",
168+
modules="id",
169+
module_bays="name",
166170
module_type="model",
167171
nat_inside="address",
168172
nat_outside="address",
@@ -257,6 +261,8 @@
257261
"lag": "interfaces",
258262
"manufacturer": "manufacturers",
259263
"master": "devices",
264+
"module": "modules",
265+
"module_bay": "module_bays",
260266
"module_type": "module_types",
261267
"nat_inside": "ip_addresses",
262268
"nat_outside": "ip_addresses",
@@ -363,6 +369,8 @@
363369
"l2vpn_terminations": "l2vpn_termination",
364370
"locations": "location",
365371
"manufacturers": "manufacturer",
372+
"modules": "module",
373+
"module_bays": "module_bay",
366374
"module_types": "module_type",
367375
"platforms": "platform",
368376
"power_feeds": "power_feed",
@@ -483,6 +491,8 @@
483491
),
484492
"lag": set(["name"]),
485493
"location": set(["name", "slug", "site"]),
494+
"module": set(["device", "module_bay", "module_type"]),
495+
"module_bay": set(["name"]),
486496
"module_type": set(["model"]),
487497
"manufacturer": set(["slug"]),
488498
"master": set(["name"]),
@@ -1078,6 +1088,13 @@ def _build_query_params(
10781088
query_key: module_data.get("assigned_object_id"),
10791089
}
10801090
)
1091+
elif parent == "module":
1092+
query_dict.update(
1093+
{
1094+
"module_bay_id": query_dict.pop("module_bay"),
1095+
"module_type_id": query_dict.pop("module_type"),
1096+
}
1097+
)
10811098
elif "_template" in parent:
10821099
if query_dict.get("device_type"):
10831100
query_dict["devicetype_id"] = query_dict.pop("device_type")

plugins/modules/netbox_module.py

+213
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,213 @@
1+
#!/usr/bin/python
2+
# -*- coding: utf-8 -*-
3+
# Copyright: (c) 2022, Erwan TONNERRE (@etonnerre) <[email protected]>
4+
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
5+
6+
from __future__ import absolute_import, division, print_function
7+
8+
__metaclass__ = type
9+
10+
DOCUMENTATION = r"""
11+
---
12+
module: netbox_module
13+
short_description: Create, update or delete module within NetBox
14+
description:
15+
- Creates, updates or removes module from NetBox
16+
notes:
17+
- Tags should be defined as a YAML list
18+
- This should be ran with connection C(local) and hosts C(localhost)
19+
author:
20+
- Erwan TONNERRE (@etonnerre)
21+
requirements:
22+
- pynetbox
23+
version_added: '3.17.0'
24+
extends_documentation_fragment:
25+
- netbox.netbox.common
26+
options:
27+
data:
28+
description:
29+
- Defines the device type configuration
30+
suboptions:
31+
device:
32+
description:
33+
- The device of the module
34+
required: True
35+
type: raw
36+
module_bay:
37+
description:
38+
- The module bay of the module
39+
required: true
40+
type: raw
41+
module_type:
42+
description:
43+
- The module type of the module
44+
required: true
45+
type: raw
46+
status:
47+
description:
48+
- The status of the module
49+
choices:
50+
- offline
51+
- active
52+
- planned
53+
- staged
54+
- side-to-rear
55+
- failed
56+
- decommissioning
57+
required: false
58+
type: str
59+
serial:
60+
description:
61+
- The weight of the device type
62+
required: false
63+
type: str
64+
description:
65+
description:
66+
- The description of the module
67+
required: false
68+
type: str
69+
asset_tag:
70+
description:
71+
- The asset tag of the modyle
72+
required: false
73+
type: str
74+
comments:
75+
description:
76+
- Comments that may include additional information in regards to the module
77+
required: false
78+
type: str
79+
tags:
80+
description:
81+
- Any tags that the module may need to be associated with
82+
required: false
83+
type: list
84+
elements: raw
85+
custom_fields:
86+
description:
87+
- must exist in NetBox
88+
required: false
89+
type: dict
90+
required: true
91+
type: dict
92+
"""
93+
94+
EXAMPLES = r"""
95+
- name: "Test NetBox modules"
96+
connection: local
97+
hosts: localhost
98+
gather_facts: False
99+
100+
tasks:
101+
- name: Create module type within NetBox with only required information
102+
netbox.netbox.netbox_module:
103+
netbox_url: http://netbox.local
104+
netbox_token: thisIsMyToken
105+
data:
106+
device: C9300-DEMO
107+
module_bay: Network Module
108+
module_type: C9300-NM-8X
109+
state: present
110+
111+
- name: Create module type within NetBox
112+
netbox.netbox.netbox_module:
113+
netbox_url: http://netbox.local
114+
netbox_token: thisIsMyToken
115+
data:
116+
device:
117+
name: C9300-DEMO
118+
site: EUPARIS
119+
module_bay:
120+
name: Network Module
121+
position: 1
122+
module_type:
123+
manufacturer: Cisco
124+
model: C9300-NM-8X
125+
state: present
126+
127+
- name: Delete module type within netbox
128+
netbox.netbox.netbox_module:
129+
netbox_url: http://netbox.local
130+
netbox_token: thisIsMyToken
131+
data:
132+
device: C9300-DEMO
133+
module_bay: Network Module
134+
module_type: C9300-NM-8X
135+
asset_tag: 00001
136+
serial: XXXNNNNXXXX
137+
state: absent
138+
"""
139+
140+
RETURN = r"""
141+
module:
142+
description: Serialized object as created or already existent within NetBox
143+
returned: success (when I(state=present))
144+
type: dict
145+
msg:
146+
description: Message indicating failure or info about what has been achieved
147+
returned: always
148+
type: str
149+
"""
150+
151+
from ansible_collections.netbox.netbox.plugins.module_utils.netbox_utils import (
152+
NetboxAnsibleModule,
153+
NETBOX_ARG_SPEC,
154+
)
155+
from ansible_collections.netbox.netbox.plugins.module_utils.netbox_dcim import (
156+
NetboxDcimModule,
157+
NB_MODULES,
158+
)
159+
from copy import deepcopy
160+
161+
162+
def main():
163+
"""
164+
Main entry point for module execution
165+
"""
166+
argument_spec = deepcopy(NETBOX_ARG_SPEC)
167+
argument_spec.update(
168+
dict(
169+
data=dict(
170+
type="dict",
171+
required=True,
172+
options=dict(
173+
device=dict(required=True, type="raw"),
174+
module_bay=dict(required=True, type="raw"),
175+
module_type=dict(required=True, type="raw"),
176+
status=dict(
177+
required=False,
178+
type="str",
179+
choices=[
180+
"offline",
181+
"active",
182+
"planned",
183+
"staged",
184+
"side-to-rear",
185+
"failed",
186+
"decommissioning",
187+
],
188+
),
189+
serial=dict(required=False, type="str"),
190+
description=dict(required=False, type="str"),
191+
asset_tag=dict(required=False, type="str"),
192+
comments=dict(required=False, type="str"),
193+
tags=dict(required=False, type="list", elements="raw"),
194+
custom_fields=dict(required=False, type="dict"),
195+
),
196+
),
197+
)
198+
)
199+
required_if = [
200+
("state", "present", ["device", "module_bay", "module_type", "status"]),
201+
("state", "absent", ["device", "module_bay", "module_type"]),
202+
]
203+
204+
module = NetboxAnsibleModule(
205+
argument_spec=argument_spec, supports_check_mode=True, required_if=required_if
206+
)
207+
208+
netbox_device_type = NetboxDcimModule(module, NB_MODULES)
209+
netbox_device_type.run()
210+
211+
212+
if __name__ == "__main__": # pragma: no cover
213+
main()

0 commit comments

Comments
 (0)