Skip to content

Commit 7111942

Browse files
authored
Add new endpoints for vpn app (#1162)
* Add new endpoints for vpn app * Update netbox_l2vpn and netbox_l2vpn_termination modules * fix in handling version checks in nb_lookup.py * Requested changes
1 parent cbc8aa5 commit 7111942

File tree

5 files changed

+242
-96
lines changed

5 files changed

+242
-96
lines changed

plugins/lookup/nb_lookup.py

Lines changed: 31 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -206,8 +206,6 @@ def get_endpoint(netbox, term):
206206
"job-results": {"endpoint": netbox.extras.job_results},
207207
"journal-entries": {"endpoint": netbox.extras.journal_entries},
208208
"locations": {"endpoint": netbox.dcim.locations},
209-
"l2vpn-terminations": {"endpoint": netbox.ipam.l2vpn_terminations},
210-
"l2vpns": {"endpoint": netbox.ipam.l2vpns},
211209
"manufacturers": {"endpoint": netbox.dcim.manufacturers},
212210
"module-bays": {"endpoint": netbox.dcim.module_bays},
213211
"module-bay-templates": {"endpoint": netbox.dcim.module_bay_templates},
@@ -257,9 +255,10 @@ def get_endpoint(netbox, term):
257255
"webhooks": {"endpoint": netbox.extras.webhooks},
258256
}
259257

260-
major, minor, patch = map(int, pynetbox.__version__.split("."))
258+
major, minor, patch = tuple(map(int, pynetbox.__version__.split(".")))
259+
netbox_versiontuple = tuple(map(int, netbox.version.split(".")))
261260

262-
if major >= 6 and minor >= 4 and patch >= 0:
261+
if (major, minor, patch) >= (6, 4):
263262
netbox_endpoint_map["wireless-lan-groups"] = {
264263
"endpoint": netbox.wireless.wireless_lan_groups
265264
}
@@ -273,17 +272,41 @@ def get_endpoint(netbox, term):
273272
"endpoint": netbox.wireless.wireless_links
274273
}
275274

276-
if major < 7 and minor >= 0 and patch >= 1:
277-
netbox_endpoint_map["secret-roles"] = {"endpoint": netbox.secrets.secret_roles}
278-
netbox_endpoint_map["secrets"] = {"endpoint": netbox.secrets.secrets}
279-
280275
else:
281276
if "wireless" in term:
282277
Display().v(
283278
"pynetbox version %d.%d.%d does not support wireless app; please update to v6.4.0 or newer."
284279
% (major, minor, patch)
285280
)
286281

282+
if (major, minor, patch) < (7, 0, 1):
283+
netbox_endpoint_map["secret-roles"] = {"endpoint": netbox.secrets.secret_roles}
284+
netbox_endpoint_map["secrets"] = {"endpoint": netbox.secrets.secrets}
285+
286+
if netbox_versiontuple >= (3, 7):
287+
if (major, minor, patch) >= (7, 3):
288+
netbox_endpoint_map["l2vpn-terminations"] = {
289+
"endpoint": netbox.vpn.l2vpn_terminations
290+
}
291+
netbox_endpoint_map["l2vpns"] = {"endpoint": netbox.vpn.l2vpns}
292+
netbox_endpoint_map["tunnel-terminations"] = {
293+
"endpoint": netbox.vpn.tunnel_terminations
294+
}
295+
netbox_endpoint_map["tunnels"] = {"endpoint": netbox.vpn.tunnels}
296+
297+
else:
298+
if "l2vpn" in term:
299+
Display().v(
300+
"pynetbox version %d.%d.%d does not support vpn app; please update to v7.3.0 or newer."
301+
% (major, minor, patch)
302+
)
303+
304+
else:
305+
netbox_endpoint_map["l2vpn-terminations"] = {
306+
"endpoint": netbox.ipam.l2vpn_terminations
307+
}
308+
netbox_endpoint_map["l2vpns"] = {"endpoint": netbox.ipam.l2vpns}
309+
287310
return netbox_endpoint_map[term]["endpoint"]
288311

289312

plugins/module_utils/netbox_utils.py

Lines changed: 110 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -32,89 +32,103 @@
3232

3333
# Used to map endpoints to applications dynamically
3434
API_APPS_ENDPOINTS = dict(
35-
circuits=[
36-
"circuits",
37-
"circuit_types",
38-
"circuit_terminations",
39-
"providers",
40-
"provider_networks",
41-
],
42-
dcim=[
43-
"cables",
44-
"console_ports",
45-
"console_port_templates",
46-
"console_server_ports",
47-
"console_server_port_templates",
48-
"device_bays",
49-
"device_bay_templates",
50-
"devices",
51-
"device_roles",
52-
"device_types",
53-
"front_ports",
54-
"front_port_templates",
55-
"interfaces",
56-
"interface_templates",
57-
"inventory_items",
58-
"inventory_item_roles",
59-
"locations",
60-
"manufacturers",
61-
"module_types",
62-
"platforms",
63-
"power_feeds",
64-
"power_outlets",
65-
"power_outlet_templates",
66-
"power_panels",
67-
"power_ports",
68-
"power_port_templates",
69-
"racks",
70-
"rack_groups",
71-
"rack_roles",
72-
"rear_ports",
73-
"rear-ports",
74-
"rear_port_templates",
75-
"regions",
76-
"sites",
77-
"site_groups",
78-
"virtual_chassis",
79-
],
80-
extras=[
81-
"config_contexts",
82-
"config_templates",
83-
"tags",
84-
"custom_fields",
85-
"custom_links",
86-
"export_templates",
87-
"journal_entries",
88-
"webhooks",
89-
],
90-
ipam=[
91-
"aggregates",
92-
"asns",
93-
"fhrp_groups",
94-
"fhrp_group_assignments",
95-
"ip_addresses",
96-
"l2vpns",
97-
"l2vpn_terminations",
98-
"prefixes",
99-
"rirs",
100-
"roles",
101-
"route_targets",
102-
"service_templates",
103-
"vlans",
104-
"vlan_groups",
105-
"vrfs",
106-
"services",
107-
],
108-
secrets=[],
109-
tenancy=["tenants", "tenant_groups", "contacts", "contact_groups", "contact_roles"],
110-
virtualization=[
111-
"cluster_groups",
112-
"cluster_types",
113-
"clusters",
114-
"virtual_machines",
115-
"virtual_disks",
116-
],
117-
wireless=["wireless_lans", "wireless_lan_groups", "wireless_links"],
35+
circuits={
36+
"circuits": {},
37+
"circuit_types": {},
38+
"circuit_terminations": {},
39+
"providers": {},
40+
"provider_networks": {},
41+
},
42+
dcim={
43+
"cables": {},
44+
"console_ports": {},
45+
"console_port_templates": {},
46+
"console_server_ports": {},
47+
"console_server_port_templates": {},
48+
"device_bays": {},
49+
"device_bay_templates": {},
50+
"devices": {},
51+
"device_roles": {},
52+
"device_types": {},
53+
"front_ports": {},
54+
"front_port_templates": {},
55+
"interfaces": {},
56+
"interface_templates": {},
57+
"inventory_items": {},
58+
"inventory_item_roles": {},
59+
"locations": {},
60+
"manufacturers": {},
61+
"module_types": {},
62+
"platforms": {},
63+
"power_feeds": {},
64+
"power_outlets": {},
65+
"power_outlet_templates": {},
66+
"power_panels": {},
67+
"power_ports": {},
68+
"power_port_templates": {},
69+
"racks": {},
70+
"rack_groups": {},
71+
"rack_roles": {},
72+
"rear_ports": {},
73+
"rear-ports": {},
74+
"rear_port_templates": {},
75+
"regions": {},
76+
"sites": {},
77+
"site_groups": {},
78+
"virtual_chassis": {},
79+
},
80+
extras={
81+
"config_contexts": {},
82+
"config_templates": {},
83+
"tags": {},
84+
"custom_fields": {},
85+
"custom_links": {},
86+
"export_templates": {},
87+
"journal_entries": {},
88+
"webhooks": {},
89+
},
90+
ipam={
91+
"aggregates": {},
92+
"asns": {},
93+
"fhrp_groups": {},
94+
"fhrp_group_assignments": {},
95+
"ip_addresses": {},
96+
"l2vpns": {"deprecated": "3.7"},
97+
"l2vpn_terminations": {"deprecated": "3.7"},
98+
"prefixes": {},
99+
"rirs": {},
100+
"roles": {},
101+
"route_targets": {},
102+
"service_templates": {},
103+
"vlans": {},
104+
"vlan_groups": {},
105+
"vrfs": {},
106+
"services": {},
107+
},
108+
secrets={},
109+
tenancy={
110+
"tenants": {},
111+
"tenant_groups": {},
112+
"contacts": {},
113+
"contact_groups": {},
114+
"contact_roles": {},
115+
},
116+
virtualization={
117+
"cluster_groups": {},
118+
"cluster_types": {},
119+
"clusters": {},
120+
"virtual_machines": {},
121+
"virtual_disks": {},
122+
},
123+
wireless={
124+
"wireless_lans": {},
125+
"wireless_lan_groups": {},
126+
"wireless_links": {},
127+
},
128+
vpn={
129+
"l2vpns": {"introduced": "3.7"},
130+
"l2vpn_terminations": {"introduced": "3.7"},
131+
},
118132
)
119133

120134
# Used to normalize data for the respective query types used to find endpoints
@@ -1122,7 +1136,19 @@ def _find_app(self, endpoint):
11221136
"""
11231137
nb_app = None
11241138
for k, v in API_APPS_ENDPOINTS.items():
1125-
if endpoint in v:
1139+
if endpoint in v.keys():
1140+
if "introduced" in v[endpoint]:
1141+
pre_introduction = self._version_check_greater(
1142+
v[endpoint]["introduced"], self.version
1143+
)
1144+
if pre_introduction:
1145+
continue
1146+
if "deprecated" in v[endpoint]:
1147+
after_deprecation = self._version_check_greater(
1148+
self.version, v[endpoint]["deprecated"], greater_or_equal=True
1149+
)
1150+
if after_deprecation:
1151+
continue
11261152
nb_app = k
11271153

11281154
if nb_app:

plugins/module_utils/netbox_vpn.py

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
# -*- coding: utf-8 -*-
2+
# Copyright: (c) 2018, Mikhail Yohman (@fragmentedpacket) <mikhail.yohman@gmail.com>
3+
# Copyright: (c) 2024, Fred De Backer (@freddebacker) <debacker.fred@gmail.com>
4+
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
5+
from __future__ import absolute_import, division, print_function
6+
7+
__metaclass__ = type
8+
9+
# Import necessary packages
10+
11+
from ansible_collections.netbox.netbox.plugins.module_utils.netbox_utils import (
12+
NetboxModule,
13+
ENDPOINT_NAME_MAPPING,
14+
SLUG_REQUIRED,
15+
)
16+
17+
18+
NB_L2VPNS = "l2vpns"
19+
NB_L2VPN_TERMINATIONS = "l2vpn_terminations"
20+
21+
22+
class NetboxVpnModule(NetboxModule):
23+
def __init__(self, module, endpoint):
24+
super().__init__(module, endpoint)
25+
26+
def run(self):
27+
"""
28+
This function should have all necessary code for endpoints within the application
29+
to create/update/delete the endpoint objects
30+
Supported endpoints:
31+
- l2vpns
32+
- l2vpn_terminations
33+
"""
34+
# Used to dynamically set key when returning results
35+
endpoint_name = ENDPOINT_NAME_MAPPING[self.endpoint]
36+
37+
self.result = {"changed": False}
38+
39+
application = self._find_app(self.endpoint)
40+
nb_app = getattr(self.nb, application)
41+
nb_endpoint = getattr(nb_app, self.endpoint)
42+
user_query_params = self.module.params.get("query_params")
43+
44+
data = self.data
45+
46+
if self.endpoint == "l2vpn_terminations":
47+
name = "l2vpn %s <> %s %s" % (
48+
data.get("l2vpn"),
49+
data.get("assigned_object_type"),
50+
data.get("assigned_object_id"),
51+
)
52+
else:
53+
name = data.get("name")
54+
55+
if self.endpoint in SLUG_REQUIRED:
56+
if not data.get("slug"):
57+
data["slug"] = self._to_slug(name)
58+
59+
object_query_params = self._build_query_params(
60+
endpoint_name, data, user_query_params
61+
)
62+
self.nb_object = self._nb_endpoint_get(nb_endpoint, object_query_params, name)
63+
64+
if self.state == "present":
65+
self._ensure_object_exists(nb_endpoint, endpoint_name, name, data)
66+
elif self.state == "absent":
67+
self._ensure_object_absent(endpoint_name, name)
68+
69+
try:
70+
serialized_object = self.nb_object.serialize()
71+
except AttributeError:
72+
serialized_object = self.nb_object
73+
74+
self.result.update({endpoint_name: serialized_object})
75+
76+
self.module.exit_json(**self.result)

plugins/modules/netbox_l2vpn.py

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -143,11 +143,16 @@
143143

144144
from ansible_collections.netbox.netbox.plugins.module_utils.netbox_utils import (
145145
NetboxAnsibleModule,
146+
NetboxModule,
146147
NETBOX_ARG_SPEC,
147148
)
148149
from ansible_collections.netbox.netbox.plugins.module_utils.netbox_ipam import (
149150
NetboxIpamModule,
150-
NB_L2VPNS,
151+
NB_L2VPNS as NB_IPAM_L2VPNS,
152+
)
153+
from ansible_collections.netbox.netbox.plugins.module_utils.netbox_vpn import (
154+
NetboxVpnModule,
155+
NB_L2VPNS as NB_VPN_L2VPNS,
151156
)
152157
from copy import deepcopy
153158

@@ -186,7 +191,12 @@ def main():
186191
argument_spec=argument_spec, supports_check_mode=True, required_if=required_if
187192
)
188193

189-
netbox_l2vpn = NetboxIpamModule(module, NB_L2VPNS)
194+
netbox_l2vpn = NetboxModule(module, "")
195+
if netbox_l2vpn._find_app(NB_IPAM_L2VPNS) == "ipam":
196+
netbox_l2vpn = NetboxIpamModule(module, NB_IPAM_L2VPNS)
197+
if netbox_l2vpn._find_app(NB_VPN_L2VPNS) == "vpn":
198+
netbox_l2vpn = NetboxVpnModule(module, NB_VPN_L2VPNS)
199+
190200
netbox_l2vpn.run()
191201

192202

0 commit comments

Comments
 (0)