Skip to content

Commit 6578217

Browse files
authored
Feature: L2vpn termination module (#994)
* Added netbox_l2vps_termination module * Added tests for netbox_l2vps_termination module * Added L2VPNs creation to netbox-deploy.py
1 parent 24fd6bc commit 6578217

File tree

9 files changed

+402
-1
lines changed

9 files changed

+402
-1
lines changed

meta/runtime.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ action_groups:
4747
- netbox_ipam_role
4848
- netbox_journal_entry
4949
- netbox_l2vpn
50+
- netbox_l2vpn_termination
5051
- netbox_location
5152
- netbox_manufacturer
5253
- netbox_module_type

plugins/module_utils/netbox_ipam.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -198,6 +198,12 @@ def run(self):
198198
data.get("interface_type"),
199199
data.get("interface_id"),
200200
)
201+
elif self.endpoint == "l2vpn_terminations":
202+
name = "l2vpn %s <> %s %s" % (
203+
data.get("l2vpn"),
204+
data.get("assigned_object_type"),
205+
data.get("assigned_object_id"),
206+
)
201207
else:
202208
name = data.get("name")
203209

plugins/module_utils/netbox_utils.py

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,7 @@
140140
inventory_item_role="name",
141141
import_targets="name",
142142
l2vpn="name",
143+
l2vpn_termination="id",
143144
location="slug",
144145
manufacturer="slug",
145146
module_type="model",
@@ -329,6 +330,7 @@
329330
"inventory_item_roles": "inventory_item_role",
330331
"ip_addresses": "ip_address",
331332
"l2vpns": "l2vpn",
333+
"l2vpn_terminations": "l2vpn_termination",
332334
"locations": "location",
333335
"manufacturers": "manufacturer",
334336
"module_types": "module_type",
@@ -440,6 +442,9 @@
440442
["address", "vrf", "device", "interface", "assigned_object", "virtual_machine"]
441443
),
442444
"l2vpn": set(["name"]),
445+
"l2vpn_termination": set(
446+
["l2vpn", "assigned_object_type", "interface_id", "vlan_id", "vminterface_id"]
447+
),
443448
"lag": set(["name"]),
444449
"location": set(["name", "slug", "site"]),
445450
"module_type": set(["model"]),
@@ -1004,7 +1009,19 @@ def _build_query_params(
10041009
"name": module_data.get("power_port_template"),
10051010
}
10061011
query_dict.update(power_port_template)
1007-
1012+
elif parent == "l2vpn_termination":
1013+
query_param_mapping = {
1014+
"dcim.interface": "interface_id",
1015+
"ipam.vlan": "vlan_id",
1016+
"virtualization.vminterface": "vminterface_id",
1017+
}
1018+
query_key = query_param_mapping[module_data.get("assigned_object_type")]
1019+
query_dict.update(
1020+
{
1021+
"l2vpn_id": query_dict.pop("l2vpn"),
1022+
query_key: module_data.get("assigned_object_id"),
1023+
}
1024+
)
10081025
elif "_template" in parent:
10091026
if query_dict.get("device_type"):
10101027
query_dict["devicetype_id"] = query_dict.pop("device_type")
Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,154 @@
1+
#!/usr/bin/python
2+
# -*- coding: utf-8 -*-
3+
# Copyright: (c) 2023, Andrii Konts (@andrii-konts) <andrew.konts@uk2group.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+
DOCUMENTATION = r"""
11+
---
12+
module: netbox_l2vpn_termination
13+
short_description: Create, update or delete L2VPNs terminations within NetBox
14+
description:
15+
- Creates, updates or removes L2VPNs terminations from NetBox
16+
notes:
17+
- Tags should be defined as a YAML list
18+
- This should be ran with connection C(local) and hosts C(localhost)
19+
author:
20+
- Andrii Konts (@andrii-konts)
21+
requirements:
22+
- pynetbox
23+
seealso:
24+
- name: FHRP Group Model reference
25+
description: NetBox Documentation for FHRP Group Model.
26+
link: https://docs.netbox.dev/en/stable/models/ipam/l2vpntermination/
27+
version_added: '3.13.0'
28+
extends_documentation_fragment:
29+
- netbox.netbox.common
30+
options:
31+
data:
32+
type: dict
33+
description:
34+
- Defines the L2VPN termination configuration
35+
suboptions:
36+
l2vpn:
37+
description:
38+
- L2vpn object id
39+
required: true
40+
type: int
41+
assigned_object_type:
42+
description:
43+
- Assigned object type
44+
required: true
45+
choices:
46+
- dcim.interface
47+
- ipam.vlan
48+
- virtualization.vminterface
49+
type: str
50+
assigned_object_id:
51+
description:
52+
- Assigned object id
53+
required: true
54+
type: int
55+
tags:
56+
description:
57+
- Any tags that the L2VPN termination may need to be associated with
58+
required: false
59+
type: list
60+
elements: raw
61+
custom_fields:
62+
description:
63+
- Must exist in NetBox
64+
required: false
65+
type: dict
66+
required: true
67+
"""
68+
69+
EXAMPLES = r"""
70+
- hosts: localhost
71+
connection: local
72+
module_defaults:
73+
group/netbox.netbox.netbox:
74+
netbox_url: "http://netbox.local"
75+
netbox_token: "thisIsMyToken"
76+
tasks:
77+
- name: Create L2VPN termination within NetBox with only required information
78+
netbox.netbox.netbox_l2vpn_termination:
79+
data:
80+
l2vpn: 1
81+
assigned_object_type: dcim.interface
82+
assigned_object_id: 32
83+
state: present
84+
85+
- name: Delete L2VPN termination within netbox
86+
netbox.netbox.netbox_l2vpn_termination:
87+
data:
88+
l2vpn: 1
89+
assigned_object_type: dcim.interface
90+
assigned_object_id: 32
91+
state: absent
92+
93+
"""
94+
95+
RETURN = r"""
96+
l2vpn_termination:
97+
description: Serialized object as created or already existent within NetBox
98+
returned: success (when I(state=present))
99+
type: dict
100+
msg:
101+
description: Message indicating failure or info about what has been achieved
102+
returned: always
103+
type: str
104+
"""
105+
106+
from ansible_collections.netbox.netbox.plugins.module_utils.netbox_utils import (
107+
NetboxAnsibleModule,
108+
NETBOX_ARG_SPEC,
109+
)
110+
111+
from ansible_collections.netbox.netbox.plugins.module_utils.netbox_ipam import (
112+
NetboxIpamModule,
113+
NB_L2VPN_TERMINATIONS,
114+
)
115+
116+
117+
from copy import deepcopy
118+
119+
120+
def main():
121+
"""
122+
Main entry point for module execution
123+
"""
124+
argument_spec = deepcopy(NETBOX_ARG_SPEC)
125+
argument_spec.update(
126+
dict(
127+
data=dict(
128+
type="dict",
129+
required=True,
130+
options=dict(
131+
l2vpn=dict(required=True, type="int"),
132+
assigned_object_type=dict(
133+
required=True,
134+
choices=[
135+
"dcim.interface",
136+
"ipam.vlan",
137+
"virtualization.vminterface",
138+
],
139+
),
140+
assigned_object_id=dict(required=True, type="int"),
141+
tags=dict(required=False, type="list", elements="raw"),
142+
custom_fields=dict(required=False, type="dict"),
143+
),
144+
),
145+
)
146+
)
147+
148+
module = NetboxAnsibleModule(argument_spec=argument_spec, supports_check_mode=True)
149+
netbox_l2vpn_termination = NetboxIpamModule(module, NB_L2VPN_TERMINATIONS)
150+
netbox_l2vpn_termination.run()
151+
152+
153+
if __name__ == "__main__":
154+
main()

tests/integration/netbox-deploy.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -546,6 +546,23 @@ def make_netbox_calls(endpoint, payload):
546546
]
547547
created_route_targets = make_netbox_calls(nb.ipam.route_targets, route_targets)
548548

549+
## Create L2VPNs
550+
l2vpns = [
551+
{
552+
"identifier": 111111,
553+
"name": "Test L2VPN 1",
554+
"slug": "Test_L2VPN_1",
555+
"type": "vxlan",
556+
},
557+
{
558+
"identifier": 222222,
559+
"name": "Test L2VPN 2",
560+
"slug": "Test_L2VPN_2",
561+
"type": "vxlan",
562+
},
563+
]
564+
created_l2vpns = make_netbox_calls(nb.ipam.l2vpns, l2vpns)
565+
549566
if ERRORS:
550567
sys.exit(
551568
"Errors have occurred when creating objects, and should have been printed out. Check previous output."

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

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -247,6 +247,15 @@
247247
tags:
248248
- netbox_l2vpn
249249

250+
- name: "NETBOX_L2VPN_TERMINATION TESTS"
251+
include_tasks:
252+
file: "netbox_l2vpn_termination.yml"
253+
apply:
254+
tags:
255+
- netbox_l2vpn_termination
256+
tags:
257+
- netbox_l2vpn_termination
258+
250259
- name: "NETBOX_INVENTORY_ITEM_ROLE TESTS"
251260
include_tasks:
252261
file: "netbox_inventory_item_role.yml"
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
---
2+
##
3+
##
4+
### NETBOX_L2VPN_TERMINATION
5+
##
6+
##
7+
- name: "L2VPN_TERMINATION 1: Necessary info creation"
8+
netbox.netbox.netbox_l2vpn_termination:
9+
netbox_url: http://localhost:32768
10+
netbox_token: 0123456789abcdef0123456789abcdef01234567
11+
data:
12+
l2vpn: 1
13+
assigned_object_type: dcim.interface
14+
assigned_object_id: 1
15+
state: present
16+
register: test_one
17+
18+
- name: "L2VPN_TERMINATION 1: ASSERT - Necessary info creation"
19+
ansible.builtin.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['l2vpn_termination']['l2vpn'] == 1
25+
- test_one['l2vpn_termination']['assigned_object_type'] == "dcim.interface"
26+
- test_one['l2vpn_termination']['assigned_object_id'] == 1
27+
- test_one['msg'] == "l2vpn_termination l2vpn 1 <> dcim.interface 1 created"
28+
29+
- name: "L2VPN_TERMINATION 2: Create duplicate"
30+
netbox.netbox.netbox_l2vpn_termination:
31+
netbox_url: http://localhost:32768
32+
netbox_token: 0123456789abcdef0123456789abcdef01234567
33+
data:
34+
l2vpn: 1
35+
assigned_object_type: dcim.interface
36+
assigned_object_id: 1
37+
state: present
38+
register: test_two
39+
40+
- name: "L2VPN_TERMINATION 2: ASSERT - Create duplicate"
41+
ansible.builtin.assert:
42+
that:
43+
- not test_two['changed']
44+
- test_two['l2vpn_termination']['l2vpn'] == 1
45+
- test_two['l2vpn_termination']['assigned_object_type'] == "dcim.interface"
46+
- test_two['l2vpn_termination']['assigned_object_id'] == 1
47+
- test_two['msg'] == "l2vpn_termination l2vpn 1 <> dcim.interface 1 already exists"
48+
49+
- name: "L2VPN_TERMINATION 3: Update"
50+
netbox.netbox.netbox_l2vpn_termination:
51+
netbox_url: http://localhost:32768
52+
netbox_token: 0123456789abcdef0123456789abcdef01234567
53+
data:
54+
l2vpn: 1
55+
assigned_object_type: dcim.interface
56+
assigned_object_id: 1
57+
tags:
58+
- "Schnozzberry"
59+
state: present
60+
register: test_three
61+
62+
- name: "L2VPN_TERMINATION 3: ASSERT - Updated"
63+
ansible.builtin.assert:
64+
that:
65+
- test_three is changed
66+
- test_three['diff']['after']['tags'][0] == 4
67+
- test_three['l2vpn_termination']['l2vpn'] == 1
68+
- test_three['l2vpn_termination']['assigned_object_type'] == "dcim.interface"
69+
- test_three['l2vpn_termination']['assigned_object_id'] == 1
70+
- test_three['l2vpn_termination']['tags'][0] == 4
71+
- test_three['msg'] == "l2vpn_termination l2vpn 1 <> dcim.interface 1 updated"
72+
73+
- name: "L2VPN_TERMINATION 4: Delete"
74+
netbox.netbox.netbox_l2vpn_termination:
75+
netbox_url: http://localhost:32768
76+
netbox_token: 0123456789abcdef0123456789abcdef01234567
77+
data:
78+
l2vpn: 1
79+
assigned_object_type: dcim.interface
80+
assigned_object_id: 1
81+
state: absent
82+
register: test_four
83+
84+
- name: "L2VPN_TERMINATION 4: ASSERT - Delete"
85+
ansible.builtin.assert:
86+
that:
87+
- test_four is changed
88+
- test_four['diff']['before']['state'] == "present"
89+
- test_four['diff']['after']['state'] == "absent"
90+
- test_four['l2vpn_termination']['l2vpn'] == 1
91+
- test_four['l2vpn_termination']['assigned_object_type'] == "dcim.interface"
92+
- test_four['l2vpn_termination']['assigned_object_id'] == 1
93+
- test_four['l2vpn_termination']['tags'][0] == 4
94+
- test_four['msg'] == "l2vpn_termination l2vpn 1 <> dcim.interface 1 deleted"

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

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -247,6 +247,15 @@
247247
tags:
248248
- netbox_l2vpn
249249

250+
- name: "NETBOX_L2VPN_TERMINATION TESTS"
251+
include_tasks:
252+
file: "netbox_l2vpn_termination.yml"
253+
apply:
254+
tags:
255+
- netbox_l2vpn_termination
256+
tags:
257+
- netbox_l2vpn_termination
258+
250259
- name: "NETBOX_INVENTORY_ITEM_ROLE TESTS"
251260
include_tasks:
252261
file: "netbox_inventory_item_role.yml"

0 commit comments

Comments
 (0)