Skip to content

Commit 2ad8bd6

Browse files
authored
Add custom link module (#722)
1 parent 9d096c8 commit 2ad8bd6

File tree

5 files changed

+285
-2
lines changed

5 files changed

+285
-2
lines changed

plugins/module_utils/netbox_extras.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
NB_CONFIG_CONTEXTS = "config_contexts"
1515
NB_TAGS = "tags"
1616
NB_CUSTOM_FIELDS = "custom_fields"
17+
NB_CUSTOM_LINKS = "custom_links"
1718

1819

1920
class NetboxExtrasModule(NetboxModule):

plugins/module_utils/netbox_utils.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@
7474
"site_groups",
7575
"virtual_chassis",
7676
],
77-
extras=["config_contexts", "tags", "custom_fields"],
77+
extras=["config_contexts", "tags", "custom_fields", "custom_links"],
7878
ipam=[
7979
"aggregates",
8080
"ip_addresses",
@@ -110,6 +110,7 @@
110110
contact_group="name",
111111
contact_role="name",
112112
custom_field="name",
113+
custom_link="name",
113114
device="name",
114115
device_role="slug",
115116
device_type="slug",
@@ -281,6 +282,7 @@
281282
"contact_groups": "contact_group",
282283
"contact_roles": "contact_role",
283284
"custom_fields": "custom_field",
285+
"custom_links": "custom_link",
284286
"device_bays": "device_bay",
285287
"device_bay_templates": "device_bay_template",
286288
"devices": "device",
@@ -363,6 +365,7 @@
363365
"contact_group": set(["name"]),
364366
"contact_role": set(["name"]),
365367
"custom_field": set(["name"]),
368+
"custom_link": set(["name"]),
366369
"dcim.consoleport": set(["name", "device"]),
367370
"dcim.consoleserverport": set(["name", "device"]),
368371
"dcim.frontport": set(["name", "device", "rear_port"]),

plugins/modules/netbox_custom_link.py

Lines changed: 162 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,162 @@
1+
#!/usr/bin/python
2+
# -*- coding: utf-8 -*-
3+
# Copyright: (c) 2022, Martin Rødvand (@rodvand) <p@tristero.se>
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_custom_link
13+
short_description: Creates, updates or deletes custom links within NetBox
14+
description:
15+
- Creates, updates or removes custom links from NetBox
16+
notes:
17+
- This should be ran with connection C(local) and hosts C(localhost)
18+
- Use the C(!unsafe) data type if you want jinja2 code in link_text or link_url
19+
author:
20+
- Martin Rødvand (@rodvand)
21+
requirements:
22+
- pynetbox
23+
version_added: "3.6.0"
24+
extends_documentation_fragment:
25+
- netbox.netbox.common
26+
options:
27+
data:
28+
type: dict
29+
description:
30+
- Defines the custom field
31+
suboptions:
32+
content_type:
33+
description:
34+
- The content type to apply this custom link to
35+
required: false
36+
type: raw
37+
name:
38+
description:
39+
- The name of the custom link
40+
required: true
41+
type: str
42+
link_text:
43+
description:
44+
- Link text of the custom link
45+
required: true
46+
type: raw
47+
link_url:
48+
description:
49+
- Link URL of the custom link
50+
required: true
51+
type: raw
52+
weight:
53+
description:
54+
- Fields with higher weights appear lower in a form
55+
required: false
56+
type: int
57+
group_name:
58+
description:
59+
- The group to associate the custom link with
60+
required: false
61+
type: str
62+
button_class:
63+
description:
64+
- Button class for the custom link
65+
required: false
66+
type: raw
67+
new_window:
68+
description:
69+
- Open link in new window
70+
required: false
71+
type: bool
72+
required: true
73+
"""
74+
75+
EXAMPLES = r"""
76+
- name: "Test NetBox custom_link module"
77+
connection: local
78+
hosts: localhost
79+
tasks:
80+
- name: Create a custom link on device
81+
netbox_custom_link:
82+
netbox_url: http://netbox.local
83+
netbox_token: thisIsMyToken
84+
data:
85+
content_type: "dcim.device"
86+
name: Custom Link
87+
link_text: "Open Web Management"
88+
link_url: !unsafe https://{{ obj.name }}.domain.local
89+
90+
- name: Delete the custom link
91+
netbox_custom_field:
92+
netbox_url: http://netbox.local
93+
netbox_token: thisIsMyToken
94+
data:
95+
content_type: "dcim.device"
96+
name: Custom Link
97+
link_text: "Open Web Management"
98+
link_url: !unsafe https://{{ obj.name }}.domain.local
99+
state: absent
100+
"""
101+
102+
RETURN = r"""
103+
custom_link:
104+
description: Serialized object as created/existent/updated/deleted within NetBox
105+
returned: always
106+
type: dict
107+
msg:
108+
description: Message indicating failure or info about what has been achieved
109+
returned: always
110+
type: str
111+
"""
112+
113+
from ansible_collections.netbox.netbox.plugins.module_utils.netbox_utils import (
114+
NetboxAnsibleModule,
115+
NETBOX_ARG_SPEC,
116+
)
117+
from ansible_collections.netbox.netbox.plugins.module_utils.netbox_extras import (
118+
NetboxExtrasModule,
119+
NB_CUSTOM_LINKS,
120+
)
121+
from copy import deepcopy
122+
123+
124+
def main():
125+
"""
126+
Main entry point for module execution
127+
"""
128+
argument_spec = deepcopy(NETBOX_ARG_SPEC)
129+
argument_spec.update(
130+
dict(
131+
data=dict(
132+
type="dict",
133+
required=True,
134+
options=dict(
135+
content_type=dict(required=False, type="raw"),
136+
name=dict(required=True, type="str"),
137+
link_text=dict(required=True, type="raw"),
138+
link_url=dict(required=True, type="raw"),
139+
weight=dict(required=False, type="int"),
140+
group_name=dict(required=False, type="str"),
141+
button_class=dict(required=False, type="raw"),
142+
new_window=dict(required=False, type="bool"),
143+
),
144+
)
145+
)
146+
)
147+
148+
required_if = [
149+
("state", "present", ["content_type", "name", "link_text", "link_url"]),
150+
("state", "absent", ["name"]),
151+
]
152+
153+
module = NetboxAnsibleModule(
154+
argument_spec=argument_spec, supports_check_mode=True, required_if=required_if
155+
)
156+
157+
netbox_custom_link = NetboxExtrasModule(module, NB_CUSTOM_LINKS)
158+
netbox_custom_link.run()
159+
160+
161+
if __name__ == "__main__":
162+
main()

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

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -207,4 +207,13 @@
207207
tags:
208208
- netbox_custom_field
209209
tags:
210-
- netbox_custom_field
210+
- netbox_custom_field
211+
212+
- name: "NETBOX_CUSTOM_LINK TESTS"
213+
include_tasks:
214+
file: "netbox_custom_link.yml"
215+
apply:
216+
tags:
217+
- netbox_custom_link
218+
tags:
219+
- netbox_custom_link
Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
---
2+
##
3+
##
4+
### NETBOX_CUSTOM_LINK
5+
##
6+
##
7+
- name: "CUSTOM_LINK 1: Necessary info creation"
8+
netbox.netbox.netbox_custom_link:
9+
netbox_url: http://localhost:32768
10+
netbox_token: 0123456789abcdef0123456789abcdef01234567
11+
data:
12+
content_type: "dcim.device"
13+
name: Custom Link
14+
link_text: Open Web management
15+
link_url: !unsafe https://{{ obj.name }}.domain.local/
16+
state: present
17+
register: test_one
18+
19+
- name: "CUSTOM_LINK 1: ASSERT - Necessary info creation"
20+
assert:
21+
that:
22+
- test_one is changed
23+
- test_one['diff']['before']['state'] == "absent"
24+
- test_one['diff']['after']['state'] == "present"
25+
- test_one['custom_link']['name'] == "Custom Link"
26+
- test_one['custom_link']['content_type'] == "dcim.device"
27+
- test_one['custom_link']['link_text'] == "Open Web management"
28+
- test_one['msg'] == "custom_link Custom Link created"
29+
30+
- name: "CUSTOM_LINK 2: Create duplicate"
31+
netbox.netbox.netbox_custom_link:
32+
netbox_url: http://localhost:32768
33+
netbox_token: 0123456789abcdef0123456789abcdef01234567
34+
data:
35+
content_type: "dcim.device"
36+
name: Custom Link
37+
link_text: Open Web management
38+
link_url: !unsafe https://{{ obj.name }}.domain.local/
39+
state: present
40+
register: test_two
41+
42+
- name: "CUSTOM_LINK 2: ASSERT - Create duplicate"
43+
assert:
44+
that:
45+
- not test_two['changed']
46+
- test_two['custom_link']['name'] == "Custom Link"
47+
- test_two['msg'] == "custom_link Custom Link already exists"
48+
49+
- name: "CUSTOM_FIELD 3: Update data and add weight"
50+
netbox.netbox.netbox_custom_link:
51+
netbox_url: http://localhost:32768
52+
netbox_token: 0123456789abcdef0123456789abcdef01234567
53+
data:
54+
content_type: "dcim.device"
55+
name: Custom Link
56+
link_text: Open Web management
57+
link_url: !unsafe https://{{ obj.name }}.domain.local/
58+
weight: 50
59+
state: present
60+
register: test_three
61+
62+
- name: "CUSTOM_FIELD 3: ASSERT - Updated"
63+
assert:
64+
that:
65+
- test_three is changed
66+
- test_three['diff']['after']['weight'] == 50
67+
- test_three['custom_link']['name'] == "Custom Link"
68+
- test_three['msg'] == "custom_link Custom Link updated"
69+
70+
- name: "CUSTOM_LINK 4: Change content type"
71+
netbox.netbox.netbox_custom_link:
72+
netbox_url: http://localhost:32768
73+
netbox_token: 0123456789abcdef0123456789abcdef01234567
74+
data:
75+
content_type: "virtualization.virtualmachine"
76+
name: Custom Link
77+
link_text: Open Web management
78+
link_url: !unsafe https://{{ obj.name }}.domain.local/
79+
state: present
80+
register: test_four
81+
82+
- name: "CUSTOM_LINK 4: ASSERT - Change content type"
83+
assert:
84+
that:
85+
- test_four is changed
86+
- test_four['diff']['after']['content_type'] == "virtualization.virtualmachine"
87+
- test_four['custom_link']['name'] == "Custom Link"
88+
- test_four['msg'] == "custom_link Custom Link updated"
89+
90+
- name: "CUSTOM_LINK 5: Delete"
91+
netbox.netbox.netbox_custom_link:
92+
netbox_url: http://localhost:32768
93+
netbox_token: 0123456789abcdef0123456789abcdef01234567
94+
data:
95+
content_type: "virtualization.virtualmachine"
96+
name: Custom Link
97+
link_text: Open Web management
98+
link_url: !unsafe https://{{ obj.name }}.domain.local/
99+
state: absent
100+
register: test_five
101+
102+
- name: "CUSTOM_LINK 5: ASSERT - Deleted"
103+
assert:
104+
that:
105+
- test_five is changed
106+
- test_five['diff']['after']['state'] == "absent"
107+
- test_five['custom_link']['name'] == "Custom Link"
108+
- test_five['msg'] == "custom_link Custom Link deleted"

0 commit comments

Comments
 (0)