Skip to content

Commit 7bb393d

Browse files
New Module: netbox_tag (#368)
1 parent ce121d5 commit 7bb393d

File tree

8 files changed

+417
-3
lines changed

8 files changed

+417
-3
lines changed

plugins/module_utils/netbox_extras.py

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,11 @@
88
from ansible_collections.netbox.netbox.plugins.module_utils.netbox_utils import (
99
NetboxModule,
1010
ENDPOINT_NAME_MAPPING,
11+
SLUG_REQUIRED,
1112
)
1213

14+
NB_TAGS = "tags"
15+
1316

1417
class NetboxExtrasModule(NetboxModule):
1518
def __init__(self, module, endpoint):
@@ -20,6 +23,7 @@ def run(self):
2023
This function should have all necessary code for endpoints within the application
2124
to create/update/delete the endpoint objects
2225
Supported endpoints:
26+
- tags
2327
"""
2428
# Used to dynamically set key when returning results
2529
endpoint_name = ENDPOINT_NAME_MAPPING[self.endpoint]
@@ -34,9 +38,18 @@ def run(self):
3438
data = self.data
3539

3640
# Used for msg output
37-
name = data.get("name")
41+
if data.get("name"):
42+
name = data["name"]
43+
elif data.get("slug"):
44+
name = data["slug"]
45+
46+
if self.endpoint in SLUG_REQUIRED:
47+
if not data.get("slug"):
48+
data["slug"] = self._to_slug(name)
3849

39-
data["slug"] = self._to_slug(name)
50+
# Make color params lowercase
51+
if data.get("color"):
52+
data["color"] = data["color"].lower()
4053

4154
object_query_params = self._build_query_params(
4255
endpoint_name, data, user_query_params

plugins/module_utils/netbox_utils.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -241,6 +241,7 @@
241241
"roles": "role",
242242
"services": "services",
243243
"sites": "site",
244+
"tags": "tags",
244245
"tenants": "tenant",
245246
"tenant_groups": "tenant_group",
246247
"virtual_chassis": "virtual_chassis",

plugins/modules/netbox_tag.py

Lines changed: 173 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,173 @@
1+
#!/usr/bin/python
2+
# -*- coding: utf-8 -*-
3+
# Copyright: (c) 2020, Pavel Korovin (@pkorovin) <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+
ANSIBLE_METADATA = {
11+
"metadata_version": "1.1",
12+
"status": ["preview"],
13+
"supported_by": "community",
14+
}
15+
16+
DOCUMENTATION = r"""
17+
---
18+
module: netbox_tag
19+
short_description: Creates or removes tags from Netbox
20+
description:
21+
- Creates or removes tags 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+
- Pavel Korovin (@pkorovin)
27+
requirements:
28+
- pynetbox
29+
version_added: "1.1.1"
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+
data:
42+
type: dict
43+
description:
44+
- Defines the tag configuration
45+
suboptions:
46+
name:
47+
description:
48+
- Tag name
49+
required: true
50+
type: str
51+
slug:
52+
description:
53+
- The slugified version of the name or custom slug.
54+
- This is auto-generated following NetBox rules if not provided
55+
required: false
56+
type: str
57+
color:
58+
description:
59+
- Tag color
60+
required: false
61+
type: str
62+
description:
63+
description:
64+
- Tag description
65+
required: false
66+
type: str
67+
required: true
68+
state:
69+
description:
70+
- Use C(present) or C(absent) for adding or removing.
71+
choices: [ absent, present ]
72+
default: present
73+
type: str
74+
query_params:
75+
description:
76+
- This can be used to override the specified values in ALLOWED_QUERY_PARAMS that is defined
77+
- in plugins/module_utils/netbox_utils.py and provides control to users on what may make
78+
- an object unique in their environment.
79+
required: false
80+
type: list
81+
elements: str
82+
validate_certs:
83+
description:
84+
- |
85+
If C(no), SSL certificates will not be validated.
86+
This should only be used on personally controlled sites using self-signed certificates.
87+
default: true
88+
type: raw
89+
"""
90+
91+
EXAMPLES = r"""
92+
- name: "Test tags creation/deletion"
93+
connection: local
94+
hosts: localhost
95+
gather_facts: False
96+
tasks:
97+
- name: Create tags
98+
netbox_tag:
99+
netbox_url: http://netbox.local
100+
netbox_token: thisIsMyToken
101+
data:
102+
name: "{{ item.name }}"
103+
description: "{{ item.description }}"
104+
loop:
105+
- { name: mgmt, description: "management" }
106+
- { name: tun, description: "tunnel" }
107+
108+
- name: Delete tags
109+
netbox_tag:
110+
netbox_url: http://netbox.local
111+
netbox_token: thisIsMyToken
112+
data:
113+
name: "{{ item }}"
114+
state: absent
115+
loop:
116+
- mgmt
117+
- tun
118+
"""
119+
120+
RETURN = r"""
121+
tags:
122+
description: Serialized object as created/existent/updated/deleted within Netbox
123+
returned: always
124+
type: dict
125+
msg:
126+
description: Message indicating failure or info about what has been achieved
127+
returned: always
128+
type: str
129+
"""
130+
131+
from ansible_collections.netbox.netbox.plugins.module_utils.netbox_utils import (
132+
NetboxAnsibleModule,
133+
NETBOX_ARG_SPEC,
134+
)
135+
from ansible_collections.netbox.netbox.plugins.module_utils.netbox_extras import (
136+
NetboxExtrasModule,
137+
NB_TAGS,
138+
)
139+
from copy import deepcopy
140+
141+
142+
def main():
143+
"""
144+
Main entry point for module execution
145+
"""
146+
argument_spec = deepcopy(NETBOX_ARG_SPEC)
147+
argument_spec.update(
148+
dict(
149+
data=dict(
150+
type="dict",
151+
required=True,
152+
options=dict(
153+
name=dict(required=True, type="str"),
154+
color=dict(required=False, type="str"),
155+
description=dict(required=False, type="str"),
156+
slug=dict(required=False, type="str"),
157+
),
158+
),
159+
)
160+
)
161+
162+
required_if = [("state", "present", ["name"]), ("state", "absent", ["name"])]
163+
164+
module = NetboxAnsibleModule(
165+
argument_spec=argument_spec, supports_check_mode=True, required_if=required_if
166+
)
167+
168+
netbox_tag = NetboxExtrasModule(module, NB_TAGS)
169+
netbox_tag.run()
170+
171+
172+
if __name__ == "__main__": # pragma: no cover
173+
main()

tests/integration/targets/latest/tasks/main.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,3 +154,6 @@
154154

155155
- name: "NETBOX_LOOKUP TESTS"
156156
include_tasks: "netbox_lookup.yml"
157+
158+
- name: "NETBOX_TAG_TESTS"
159+
include_tasks: "netbox_tag.yml"
Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
---
2+
##
3+
##
4+
### NETBOX_TAGS
5+
##
6+
##
7+
- name: "TAG 1: ASSERT - Necessary info creation"
8+
netbox.netbox.netbox_tag:
9+
netbox_url: http://localhost:32768
10+
netbox_token: 0123456789abcdef0123456789abcdef01234567
11+
data:
12+
name: "Test Tag 1"
13+
description: "Tag 1 test"
14+
color: "0000ff"
15+
state: present
16+
register: test_one
17+
18+
- name: "TAG 1: ASSERT - Necessary info creation"
19+
assert:
20+
that:
21+
- test_one is changed
22+
- test_one['diff']['before']['state'] == "absent"
23+
- test_one['diff']['after']['state'] == "present"
24+
- test_one['tags']['color'] == "0000ff"
25+
- test_one['tags']['description'] == "Tag 1 test"
26+
- test_one['tags']['name'] == "Test Tag 1"
27+
- test_one['tags']['slug'] == "test-tag-1"
28+
- test_one['msg'] == "tags Test Tag 1 created"
29+
30+
- name: "TAG 2: Create duplicate"
31+
netbox.netbox.netbox_tag:
32+
netbox_url: http://localhost:32768
33+
netbox_token: 0123456789abcdef0123456789abcdef01234567
34+
data:
35+
name: "Test Tag 1"
36+
description: "Tag 1 test"
37+
color: "0000ff"
38+
state: present
39+
register: test_two
40+
41+
- name: "TAG 2: ASSERT - Create duplicate"
42+
assert:
43+
that:
44+
- not test_two['changed']
45+
- test_two['tags']['name'] == "Test Tag 1"
46+
- test_two['msg'] == "tags Test Tag 1 already exists"
47+
48+
- name: "TAG 3: ASSERT - Update"
49+
netbox.netbox.netbox_tag:
50+
netbox_url: http://localhost:32768
51+
netbox_token: 0123456789abcdef0123456789abcdef01234567
52+
data:
53+
name: "Test Tag 1"
54+
description: "Tag 1 update test"
55+
color: "00ff00"
56+
state: present
57+
register: test_three
58+
59+
- name: "TAG 3: ASSERT - Updated"
60+
assert:
61+
that:
62+
- test_three is changed
63+
- test_three['diff']['after']['color'] == "00ff00"
64+
- test_three['diff']['after']['description'] == "Tag 1 update test"
65+
- test_three['tags']['name'] == "Test Tag 1"
66+
- test_three['tags']['description'] == "Tag 1 update test"
67+
- test_three['tags']['color'] == "00ff00"
68+
- test_three['msg'] == "tags Test Tag 1 updated"
69+
70+
- name: "TAG 4: ASSERT - Delete"
71+
netbox.netbox.netbox_tag:
72+
netbox_url: http://localhost:32768
73+
netbox_token: 0123456789abcdef0123456789abcdef01234567
74+
data:
75+
name: "Test Tag 1"
76+
state: absent
77+
register: test_four
78+
79+
- name: "TAG 4: ASSERT - Delete"
80+
assert:
81+
that:
82+
- test_four is changed
83+
- test_four['diff']['after']['state'] == "absent"
84+
- test_four['tags']['name'] == "Test Tag 1"
85+
- test_four['tags']['slug'] == "test-tag-1"
86+
- test_four['msg'] == "tags Test Tag 1 deleted"
87+
88+
- name: "TAG 5: ASSERT - Necessary info creation"
89+
netbox.netbox.netbox_tag:
90+
netbox_url: http://localhost:32768
91+
netbox_token: 0123456789abcdef0123456789abcdef01234567
92+
data:
93+
name: "Test Tag 5"
94+
slug: "test-tag-five"
95+
description: "Tag 5 test"
96+
color: "0000ff"
97+
state: present
98+
register: test_five
99+
100+
- name: "TAG 5: ASSERT - Necessary info creation"
101+
assert:
102+
that:
103+
- test_five is changed
104+
- test_five['diff']['before']['state'] == "absent"
105+
- test_five['diff']['after']['state'] == "present"
106+
- test_five['tags']['color'] == "0000ff"
107+
- test_five['tags']['description'] == "Tag 5 test"
108+
- test_five['tags']['name'] == "Test Tag 5"
109+
- test_five['tags']['slug'] == "test-tag-five"
110+
- test_five['msg'] == "tags Test Tag 5 created"

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,3 +154,6 @@
154154

155155
- name: "NETBOX_LOOKUP TESTS"
156156
include_tasks: "netbox_lookup.yml"
157+
158+
- name: "NETBOX_TAG_TESTS"
159+
include_tasks: "netbox_tag.yml"

0 commit comments

Comments
 (0)