Skip to content

Commit 86f6b3d

Browse files
authored
New Module: netbox_location (#543)
1 parent 9e9de39 commit 86f6b3d

File tree

7 files changed

+369
-2
lines changed

7 files changed

+369
-2
lines changed

plugins/module_utils/netbox_dcim.py

+2
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
NB_INTERFACES = "interfaces"
2929
NB_INTERFACE_TEMPLATES = "interface_templates"
3030
NB_INVENTORY_ITEMS = "inventory_items"
31+
NB_LOCATIONS = "locations"
3132
NB_MANUFACTURERS = "manufacturers"
3233
NB_PLATFORMS = "platforms"
3334
NB_POWER_FEEDS = "power_feeds"
@@ -78,6 +79,7 @@ def run(self):
7879
- interfaces
7980
- interface_templates
8081
- inventory_items
82+
- locations
8183
- manufacturers
8284
- platforms
8385
- power_feeds

plugins/module_utils/netbox_utils.py

+4
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,7 @@
107107
manufacturer="slug",
108108
nat_inside="address",
109109
nat_outside="address",
110+
parent_location="slug",
110111
parent_region="slug",
111112
parent_site_group="slug",
112113
parent_tenant_group="slug",
@@ -181,6 +182,7 @@
181182
"nat_inside": "ip_addresses",
182183
"nat_outside": "ip_addresses",
183184
"platform": "platforms",
185+
"parent_location": "locations",
184186
"parent_interface": "interfaces",
185187
"parent_vm_interface": "interfaces",
186188
"parent_region": "regions",
@@ -343,6 +345,7 @@
343345
"manufacturer": set(["slug"]),
344346
"master": set(["name"]),
345347
"nat_inside": set(["vrf", "address"]),
348+
"parent_location": set(["slug"]),
346349
"parent_interface": set(["name"]),
347350
"parent_vm_interface": set(["name"]),
348351
"parent_region": set(["slug"]),
@@ -439,6 +442,7 @@
439442
"circuit_type": "type",
440443
"cluster_type": "type",
441444
"cluster_group": "group",
445+
"parent_location": "parent",
442446
"parent_interface": "parent",
443447
"parent_vm_interface": "parent",
444448
"parent_region": "parent",

plugins/modules/netbox_location.py

+188
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,188 @@
1+
#!/usr/bin/python
2+
# -*- coding: utf-8 -*-
3+
# Copyright: (c) 2021, Andrew Simmons (@andybro19) <[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+
ANSIBLE_METADATA = {
11+
"metadata_version": "1.1",
12+
"status": ["preview"],
13+
"supported_by": "community",
14+
}
15+
16+
DOCUMENTATION = r"""
17+
---
18+
module: netbox_location
19+
short_description: Create, update or delete locations within NetBox
20+
description:
21+
- Creates, updates or removes locations from NetBox
22+
notes:
23+
- Tags should be defined as a YAML list
24+
- This should be ran with connection C(local) and hosts C(localhost)
25+
author:
26+
- Andrew Simmons (@andybro19)
27+
requirements:
28+
- pynetbox
29+
version_added: '4.0.0'
30+
options:
31+
netbox_url:
32+
description:
33+
- URL of the NetBox instance resolvable by Ansible control host
34+
required: true
35+
type: str
36+
netbox_token:
37+
description:
38+
- The token created within NetBox to authorize API access
39+
required: true
40+
type: str
41+
cert:
42+
description:
43+
- Certificate path
44+
required: false
45+
type: raw
46+
data:
47+
type: dict
48+
description:
49+
- Defines the location configuration
50+
suboptions:
51+
name:
52+
description:
53+
- The name of the location
54+
required: true
55+
type: str
56+
slug:
57+
description:
58+
- The slugified version of the name or custom slug.
59+
- This is auto-generated following NetBox rules if not provided
60+
required: false
61+
type: str
62+
site:
63+
description:
64+
- Required if I(state=present) and the location does not exist yet
65+
required: false
66+
type: raw
67+
parent_location:
68+
description:
69+
- The parent location the location will be associated with
70+
required: false
71+
type: raw
72+
description:
73+
description:
74+
- The description of the location
75+
required: false
76+
type: str
77+
required: true
78+
state:
79+
description:
80+
- Use C(present) or C(absent) for adding or removing.
81+
choices: [ absent, present ]
82+
default: present
83+
type: str
84+
query_params:
85+
description:
86+
- This can be used to override the specified values in ALLOWED_QUERY_PARAMS that is defined
87+
- in plugins/module_utils/netbox_utils.py and provides control to users on what may make
88+
- an object unique in their environment.
89+
required: false
90+
type: list
91+
elements: str
92+
validate_certs:
93+
description:
94+
- If C(no), SSL certificates will not be validated. This should only be used on personally controlled sites using self-signed certificates.
95+
default: true
96+
type: raw
97+
"""
98+
99+
EXAMPLES = r"""
100+
- name: "Test NetBox modules"
101+
connection: local
102+
hosts: localhost
103+
gather_facts: False
104+
105+
tasks:
106+
- name: Create location within NetBox with only required information
107+
netbox.netbox.netbox_location:
108+
netbox_url: http://netbox.local
109+
netbox_token: thisIsMyToken
110+
data:
111+
name: Test location
112+
site: Test Site
113+
state: present
114+
115+
- name: Create location within NetBox with a parent location
116+
netbox.netbox.netbox_location:
117+
netbox_url: http://netbox.local
118+
netbox_token: thisIsMyToken
119+
data:
120+
name: Child location
121+
site: Test Site
122+
parent_location: Test location
123+
state: present
124+
125+
- name: Delete location within NetBox
126+
netbox.netbox.netbox_location:
127+
netbox_url: http://netbox.local
128+
netbox_token: thisIsMyToken
129+
data:
130+
name: Test location
131+
state: absent
132+
"""
133+
134+
RETURN = r"""
135+
location:
136+
description: Serialized object as created or already existent within NetBox
137+
returned: success (when I(state=present))
138+
type: dict
139+
msg:
140+
description: Message indicating failure or info about what has been achieved
141+
returned: always
142+
type: str
143+
"""
144+
145+
from ansible_collections.netbox.netbox.plugins.module_utils.netbox_utils import (
146+
NetboxAnsibleModule,
147+
NETBOX_ARG_SPEC,
148+
)
149+
from ansible_collections.netbox.netbox.plugins.module_utils.netbox_dcim import (
150+
NetboxDcimModule,
151+
NB_LOCATIONS,
152+
)
153+
from copy import deepcopy
154+
155+
156+
def main():
157+
"""
158+
Main entry point for module execution
159+
"""
160+
argument_spec = deepcopy(NETBOX_ARG_SPEC)
161+
argument_spec.update(
162+
dict(
163+
data=dict(
164+
type="dict",
165+
required=True,
166+
options=dict(
167+
name=dict(required=True, type="str"),
168+
slug=dict(required=False, type="str"),
169+
site=dict(required=False, type="raw"),
170+
parent_location=dict(required=False, type="raw"),
171+
description=dict(required=False, type="str"),
172+
),
173+
),
174+
)
175+
)
176+
177+
required_if = [("state", "present", ["name"]), ("state", "absent", ["name"])]
178+
179+
module = NetboxAnsibleModule(
180+
argument_spec=argument_spec, supports_check_mode=True, required_if=required_if
181+
)
182+
183+
netbox_location = NetboxDcimModule(module, NB_LOCATIONS)
184+
netbox_location.run()
185+
186+
187+
if __name__ == "__main__": # pragma: no cover
188+
main()

tests/integration/targets/v2.11/tasks/main.yml

+3
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,9 @@
3232
- name: "NETBOX_RACK_ROLE TESTS"
3333
include_tasks: "netbox_rack_role.yml"
3434

35+
- name: "NETBOX_LOCATION TESTS"
36+
include_tasks: "netbox_location.yml"
37+
3538
- name: "NETBOX_MANUFACTURER TESTS"
3639
include_tasks: "netbox_manufacturer.yml"
3740

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
---
2+
##
3+
##
4+
### NETBOX_LOCATION
5+
##
6+
##
7+
- name: "LOCATION 1: Necessary info creation"
8+
netbox.netbox.netbox_location:
9+
netbox_url: http://localhost:32768
10+
netbox_token: 0123456789abcdef0123456789abcdef01234567
11+
data:
12+
name: Location
13+
site: Test Site
14+
state: present
15+
register: test_one
16+
17+
- name: "LOCATION 1: ASSERT - Necessary info creation"
18+
assert:
19+
that:
20+
- test_one is changed
21+
- test_one['diff']['before']['state'] == "absent"
22+
- test_one['diff']['after']['state'] == "present"
23+
- test_one['location']['name'] == "Location"
24+
- test_one['location']['slug'] == "location"
25+
- test_one['location']['site'] == 1
26+
- test_one['msg'] == "location Location created"
27+
28+
- name: "LOCATION 2: Create duplicate"
29+
netbox.netbox.netbox_location:
30+
netbox_url: http://localhost:32768
31+
netbox_token: 0123456789abcdef0123456789abcdef01234567
32+
data:
33+
name: Location
34+
site: Test Site
35+
state: present
36+
register: test_two
37+
38+
- name: "LOCATION 2: ASSERT - Create duplicate"
39+
assert:
40+
that:
41+
- not test_two['changed']
42+
- test_two['location']['name'] == "Location"
43+
- test_two['location']['slug'] == "location"
44+
- test_two['location']['site'] == 1
45+
- test_two['msg'] == "location Location already exists"
46+
47+
- name: "LOCATION 3: Update"
48+
netbox.netbox.netbox_location:
49+
netbox_url: http://localhost:32768
50+
netbox_token: 0123456789abcdef0123456789abcdef01234567
51+
data:
52+
name: Location
53+
parent_location: Parent Rack Group
54+
description: This is a location
55+
state: present
56+
register: test_three
57+
58+
- name: "LOCATION 3: ASSERT - Update"
59+
assert:
60+
that:
61+
- test_three is changed
62+
- test_three['diff']['after']['parent'] == 2
63+
- test_three['diff']['after']['description'] == "This is a location"
64+
- test_three['location']['name'] == "Location"
65+
- test_three['location']['slug'] == "location"
66+
- test_three['location']['parent'] == 2
67+
- test_three['location']['description'] == "This is a location"
68+
- test_three['msg'] == "location Location updated"
69+
70+
- name: "LOCATION 4: Delete"
71+
netbox.netbox.netbox_location:
72+
netbox_url: http://localhost:32768
73+
netbox_token: 0123456789abcdef0123456789abcdef01234567
74+
data:
75+
name: Location
76+
state: absent
77+
register: test_four
78+
79+
- name: "LOCATION 4: ASSERT - Delete"
80+
assert:
81+
that:
82+
- test_four is changed
83+
- test_four['diff']['before']['state'] == "present"
84+
- test_four['diff']['after']['state'] == "absent"
85+
- test_four['msg'] == "location Location deleted"

tests/integration/targets/v3.0/tasks/main.yml

+2-2
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,8 @@
3232
- name: "NETBOX_RACK_ROLE TESTS"
3333
include_tasks: "netbox_rack_role.yml"
3434

35-
# - name: "NETBOX_RACK_GROUP TESTS"
36-
# include_tasks: "netbox_rack_group.yml"
35+
- name: "NETBOX_LOCATION TESTS"
36+
include_tasks: "netbox_location.yml"
3737

3838
- name: "NETBOX_MANUFACTURER TESTS"
3939
include_tasks: "netbox_manufacturer.yml"

0 commit comments

Comments
 (0)