Skip to content

Commit b99915c

Browse files
new_module: netbox_aggregate
1 parent 67b9415 commit b99915c

File tree

7 files changed

+321
-3
lines changed

7 files changed

+321
-3
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525

2626
## Existing Modules
2727

28+
- netbox_aggregate
2829
- netbox_device
2930
- netbox_device_interface
3031
- netbox_device_role

plugins/module_utils/netbox_ipam.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
from netbox_utils import NetboxModule, ENDPOINT_NAME_MAPPING, SLUG_REQUIRED
2525

2626

27+
NB_AGGREGATES = "aggregates"
2728
NB_IP_ADDRESSES = "ip_addresses"
2829
NB_PREFIXES = "prefixes"
2930
NB_IPAM_ROLES = "roles"
@@ -124,6 +125,7 @@ def run(self):
124125
This function should have all necessary code for endpoints within the application
125126
to create/update/delete the endpoint objects
126127
Supported endpoints:
128+
- aggregates
127129
- ipam_roles
128130
- ip_addresses
129131
- prefixes
@@ -145,7 +147,7 @@ def run(self):
145147

146148
if self.endpoint == "ip_addresses":
147149
name = data.get("address")
148-
elif self.endpoint == "prefixes":
150+
elif self.endpoint in ["aggregates", "prefixes"]:
149151
name = data.get("prefix")
150152
else:
151153
name = data.get("name")

plugins/module_utils/netbox_utils.py

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,17 @@
3737
"sites",
3838
],
3939
extras=[],
40-
ipam=["ip_addresses", "prefixes", "rirs", "roles", "vlans", "vlan_groups", "vrfs"],
40+
ipam=[
41+
"aggregates",
42+
"ip_addresses",
43+
"prefixes",
44+
"services",
45+
"rirs",
46+
"roles",
47+
"vlans",
48+
"vlan_groups",
49+
"vrfs",
50+
],
4151
secrets=[],
4252
tenancy=["tenants", "tenant_groups"],
4353
virtualization=["clusters"],
@@ -68,6 +78,7 @@
6878
tenant="name",
6979
tenant_group="slug",
7080
time_zone="timezone",
81+
virtual_machine="name",
7182
vlan="name",
7283
vlan_group="slug",
7384
vlan_role="name",
@@ -82,6 +93,7 @@
8293
device_type="device_types",
8394
group="tenant_groups",
8495
interface="interfaces",
96+
ip_addresses="ip_addresses",
8597
lag="interfaces",
8698
manufacturer="manufacturers",
8799
nat_inside="ip_addresses",
@@ -96,18 +108,21 @@
96108
rack_role="rack_roles",
97109
region="regions",
98110
rir="rirs",
111+
services="services",
99112
site="sites",
100113
tagged_vlans="vlans",
101114
tenant="tenants",
102115
tenant_group="tenant_groups",
103116
untagged_vlan="vlans",
117+
virtual_machine="virtual_machines",
104118
vlan="vlans",
105119
vlan_group="vlan_groups",
106120
vlan_role="roles",
107121
vrf="vrfs",
108122
)
109123

110124
ENDPOINT_NAME_MAPPING = {
125+
"aggregates": "aggregate",
111126
"devices": "device",
112127
"device_roles": "device_role",
113128
"device_types": "device_type",
@@ -121,6 +136,7 @@
121136
"rack_roles": "rack_role",
122137
"rirs": "rir",
123138
"roles": "role",
139+
"services": "services",
124140
"sites": "site",
125141
"tenants": "tenant",
126142
"tenant_groups": "tenant_group",
@@ -151,6 +167,8 @@
151167

152168
VLAN_STATUS = dict(active=1, reserved=2, deprecated=3)
153169

170+
SERVICE_PROTOCOL = dict(tcp=6, udp=17)
171+
154172
RACK_TYPE = {
155173
"2-post frame": 100,
156174
"4-post frame": 200,
@@ -226,11 +244,13 @@
226244
INTF_MODE = {"access": 100, "tagged": 200, "tagged all": 300}
227245

228246
ALLOWED_QUERY_PARAMS = {
247+
"aggregate": set(["prefix", "rir"]),
229248
"device": set(["name"]),
230249
"device_role": set(["slug"]),
231250
"device_type": set(["slug"]),
232251
"interface": set(["name", "device"]),
233252
"ip_address": set(["address", "vrf"]),
253+
"ip_addresses": set(["address", "vrf", "device"]),
234254
"lag": set(["name"]),
235255
"manufacturer": set(["name", "slug"]),
236256
"nat_inside": set(["vrf", "address"]),
@@ -241,6 +261,7 @@
241261
"rack_role": set(["slug"]),
242262
"rir": set(["slug"]),
243263
"role": set(["slug"]),
264+
"services": set(["device", "virtual_machine", "name"]),
244265
"site": set(["slug"]),
245266
"tagged_vlans": set(["name", "site", "vlan_group", "tenant"]),
246267
"tenant": set(["name"]),
@@ -251,7 +272,9 @@
251272
"vrf": set(["name", "tenant"]),
252273
}
253274

254-
QUERY_PARAMS_IDS = set(["device", "group", "vrf", "site", "vlan_group", "tenant"])
275+
QUERY_PARAMS_IDS = set(
276+
["device", "group", "rir", "vrf", "site", "vlan_group", "tenant"]
277+
)
255278

256279
# This is used when converting static choices to an ID value acceptable to Netbox API
257280
REQUIRED_ID_FIND = {
@@ -261,6 +284,7 @@
261284
"ip_addresses": [{"status": IP_ADDRESS_STATUS, "role": IP_ADDRESS_ROLE}],
262285
"prefixes": [{"status": PREFIX_STATUS}],
263286
"racks": [{"status": RACK_STATUS, "outer_unit": RACK_UNIT, "type": RACK_TYPE}],
287+
"services": [{"protocol": SERVICE_PROTOCOL}],
264288
"sites": [{"status": SITE_STATUS}],
265289
"vlans": [{"status": VLAN_STATUS}],
266290
}
@@ -420,6 +444,12 @@ def _build_query_params(self, parent, module_data, child=None):
420444
elif parent == "prefix" and module_data.get("parent"):
421445
query_dict.update({"prefix": module_data["parent"]})
422446

447+
elif parent == "ip_addreses":
448+
if isinstance(module_data["device"], int):
449+
query_dict.update({"device_id": module_data["device"]})
450+
else:
451+
query_dict.update({"device": module_data["device"]})
452+
423453
return query_dict
424454

425455
def _change_choices_id(self, endpoint, data):

plugins/modules/netbox_aggregate.py

Lines changed: 149 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,149 @@
1+
#!/usr/bin/python
2+
# -*- coding: utf-8 -*-
3+
# Copyright: (c) 2019, Mikhail Yohman (@FragmentedPacket) <mikhail.yohman@gmail.com>
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_aggregate
19+
short_description: Creates or removes aggregates from Netbox
20+
description:
21+
- Creates or removes aggregates 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+
- Mikhail Yohman (@FragmentedPacket)
27+
requirements:
28+
- pynetbox
29+
version_added: '0.1.0'
30+
options:
31+
netbox_url:
32+
description:
33+
- URL of the Netbox instance resolvable by Ansible control host
34+
required: true
35+
netbox_token:
36+
description:
37+
- The token created within Netbox to authorize API access
38+
required: true
39+
data:
40+
description:
41+
- Defines the aggregate configuration
42+
suboptions:
43+
prefix:
44+
description:
45+
- The aggregate prefix
46+
rir:
47+
description:
48+
- The RIR the aggregate will be assigned to
49+
date_added:
50+
description:
51+
- Date added, format: YYYY-MM-DD
52+
description:
53+
description:
54+
- The description of the aggregate
55+
tags:
56+
description:
57+
- Any tags that the aggregate may need to be associated with
58+
custom_fields:
59+
description:
60+
- must exist in Netbox
61+
required: true
62+
state:
63+
description:
64+
- The state of the aggregate
65+
choices: [ present, absent ]
66+
default: present
67+
validate_certs:
68+
description:
69+
- If C(no), SSL certificates will not be validated. This should only be used on personally controlled sites using self-signed certificates.
70+
default: 'yes'
71+
type: bool
72+
"""
73+
74+
EXAMPLES = r"""
75+
- name: "Test Netbox aggregate module"
76+
connection: local
77+
hosts: localhost
78+
gather_facts: False
79+
80+
tasks:
81+
- name: Create aggregate within Netbox with only required information
82+
netbox_aggregate:
83+
netbox_url: http://netbox.local
84+
netbox_token: thisIsMyToken
85+
data:
86+
prefix: 192.168.0.0/16
87+
rir: Test RIR
88+
state: present
89+
90+
- name: Create aggregate with several specified options
91+
netbox_aggregate:
92+
netbox_url: http://netbox.local
93+
netbox_token: thisIsMyToken
94+
data:
95+
prefix: 192.168.0.0/16
96+
rir: Test RIR
97+
date_added: 1989-01-18
98+
description: Test description
99+
tags:
100+
- Schnozzberry
101+
state: present
102+
103+
- name: Delete aggregate within netbox
104+
netbox_aggregate:
105+
netbox_url: http://netbox.local
106+
netbox_token: thisIsMyToken
107+
data:
108+
prefix: 192.168.0.0/16
109+
state: absent
110+
"""
111+
112+
RETURN = r"""
113+
aggregate:
114+
description: Serialized object as created or already existent within Netbox
115+
returned: on creation
116+
type: dict
117+
msg:
118+
description: Message indicating failure or info about what has been achieved
119+
returned: always
120+
type: str
121+
"""
122+
123+
from ansible.module_utils.basic import AnsibleModule
124+
from ansible_collections.fragmentedpacket.netbox_modules.plugins.module_utils.netbox_ipam import (
125+
NetboxIpamModule,
126+
NB_AGGREGATES,
127+
)
128+
129+
130+
def main():
131+
"""
132+
Main entry point for module execution
133+
"""
134+
argument_spec = dict(
135+
netbox_url=dict(type="str", required=True),
136+
netbox_token=dict(type="str", required=True, no_log=True),
137+
data=dict(type="dict", required=True),
138+
state=dict(required=False, default="present", choices=["present", "absent"]),
139+
validate_certs=dict(type="bool", default=True),
140+
)
141+
142+
module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True)
143+
144+
netbox_aggregate = NetboxIpamModule(module, NB_AGGREGATES)
145+
netbox_aggregate.run()
146+
147+
148+
if __name__ == "__main__":
149+
main()

0 commit comments

Comments
 (0)