Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Updated module: Added mdt parameters #912

Merged
merged 27 commits into from
Nov 20, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
419212c
Added mdt parameter
PadminiSivaraj Aug 16, 2023
904cc67
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Aug 16, 2023
5bec827
fixed testcases
PadminiSivaraj Aug 16, 2023
fa7e5fe
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Aug 16, 2023
c51e090
Update test_ios_vrf.py - fixed truthly value
PadminiSivaraj Aug 28, 2023
1d5f60b
Merge branch 'main' into fix_ios_vrf
PadminiSivaraj Aug 28, 2023
4755676
Update test_ios_vrf.py
PadminiSivaraj Aug 29, 2023
32075bf
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Aug 29, 2023
dd6594b
Update ios_vrf.py fixed missing key error
PadminiSivaraj Aug 29, 2023
320870d
Merge branch 'main' into fix_ios_vrf
PadminiSivaraj Aug 31, 2023
7fbd057
Merge branch 'main' into fix_ios_vrf
KB-perByte Sep 4, 2023
536fa0e
Merge branch 'main' into fix_ios_vrf
PadminiSivaraj Sep 15, 2023
cd17633
Update ios_vrf.py - resolved none type issue
PadminiSivaraj Sep 18, 2023
b6989b2
Merge branch 'main' into fix_ios_vrf
PadminiSivaraj Sep 19, 2023
d8c7b71
Update ios_vrf.py
PadminiSivaraj Sep 19, 2023
8e5dff2
Merge branch 'main' into fix_ios_vrf
PadminiSivaraj Sep 22, 2023
f434d43
Update test_ios_vrf.py - missing CLI
PadminiSivaraj Sep 26, 2023
c0e4180
Update ios_vrf.py
PadminiSivaraj Sep 26, 2023
fc2b7bc
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Sep 26, 2023
fd49008
Update test_ios_vrf.py - removed usused import
PadminiSivaraj Sep 26, 2023
83f0c88
Merge branch 'main' into fix_ios_vrf
PadminiSivaraj Oct 5, 2023
9f2f783
Merge branch 'main' into fix_ios_vrf
PadminiSivaraj Oct 9, 2023
c4a19d4
Merge branch 'main' into fix_ios_vrf
PadminiSivaraj Oct 10, 2023
405d258
Merge branch 'main' into fix_ios_vrf
KB-perByte Oct 31, 2023
64bc683
Merge branch 'main' into fix_ios_vrf
PadminiSivaraj Nov 8, 2023
0c1122c
Merge branch 'main' into fix_ios_vrf
PadminiSivaraj Nov 20, 2023
03c524d
Merge branch 'main' into fix_ios_vrf
KB-perByte Nov 20, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions changelogs/fragments/fix_ios_vrf.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
minor_changes:
- ios_vrf - added MDT related keys
16 changes: 16 additions & 0 deletions docs/cisco.ios.ios_vrf_module.rst
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,22 @@ Parameters
<th>Choices/<font color="blue">Defaults</font></th>
<th width="100%">Comments</th>
</tr>
<tr>
<td colspan="1">
<div class="ansibleOptionAnchor" id="parameter-"></div>
<b>address_family</b>
<a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
<div style="font-size: small">
<span style="color: purple">list</span>
/ <span style="color: purple">elements=dictionary</span>
</div>
</td>
<td>
</td>
<td>
<div>The list of address families with MDT parameters to be configured on the remote IOS device.</div>
</td>
</tr>
<tr>
<td colspan="1">
<div class="ansibleOptionAnchor" id="parameter-"></div>
Expand Down
158 changes: 152 additions & 6 deletions plugins/modules/ios_vrf.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,11 @@
VRF definition value accepts alphanumeric characters used to provide additional
information about the VRF.
type: str
address_family:
description:
- The list of address families with MDT parameters to be configured on the remote IOS device.
type: list
elements: dict
rd:
description:
- The router-distinguisher value uniquely identifies the VRF to routing processes
Expand Down Expand Up @@ -326,6 +331,39 @@ def add_command_to_vrf(name, cmd, commands):
commands.append(cmd)


KEY_TO_COMMAND_MAP = {
"auto_discovery": "mdt auto-discovery ",
"default": "mdt default vxlan ",
"data_mcast": "mdt data vxlan ",
"data_threshold": "mdt data threshold ",
"overlay": "mdt overlay ",
}


def add_mdt_commands(afi_dict, vrf_name, commands):
for key, value in afi_dict["mdt"].items():
cmd = KEY_TO_COMMAND_MAP[key]

if key in ["default", "data_mcast"]:
cmd = cmd + value["vxlan_mcast_group"]
add_command_to_vrf(vrf_name, cmd, commands)
elif key == "data_threshold":
cmd = cmd + str(value)
add_command_to_vrf(vrf_name, cmd, commands)
elif key == "auto_discovery":
if value["vxlan"]["enable"]:
cmd = cmd + "vxlan"
if value["vxlan"].get("inter_as"):
cmd = cmd + " " + "inter-as"
add_command_to_vrf(vrf_name, cmd, commands)
elif key == "overlay":
if value["use_bgp"]["enable"]:
cmd = cmd + "use-bgp"
if value["use_bgp"].get("spt_only"):
cmd = cmd + " " + "spt-only"
add_command_to_vrf(vrf_name, cmd, commands)


def map_obj_to_commands(updates, module):
commands = list()
for update in updates:
Expand Down Expand Up @@ -415,6 +453,33 @@ def needs_update(want, have, x):
add_command_to_vrf(want["name"], cmd, commands)
cmd = "exit-address-family"
add_command_to_vrf(want["name"], cmd, commands)
if needs_update(want, have, "address_family"):
for want_mdt in want["address_family"]:
afi = want_mdt["afi"]
af_dict = {}
data_dict = want_mdt["mdt"].pop("data", {})
if data_dict:
if "vxlan_mcast_group" in data_dict:
want_mdt["mdt"]["data_mcast"] = {
"vxlan_mcast_group": data_dict["vxlan_mcast_group"],
}
if "threshold" in data_dict:
want_mdt["mdt"]["data_threshold"] = data_dict["threshold"]

for key_in, value_in in want_mdt["mdt"].items():
have_mdt = next(
(i for i in have.get("address_family", {}) if i["afi"] == afi),
{},
)

if needs_update(want_mdt["mdt"], have_mdt.get("mdt", {}), key_in):
af_dict.update({key_in: value_in})
if af_dict:
cmd = "address-family" + " " + str(afi)
add_command_to_vrf(want["name"], cmd, commands)
add_mdt_commands({"mdt": af_dict}, want["name"], commands)
add_command_to_vrf(want["name"], "exit-address-family", commands)

if want["interfaces"] is not None:
for intf in set(have.get("interfaces", [])).difference(want["interfaces"]):
commands.extend(["interface %s" % intf, "no vrf forwarding %s" % want["name"]])
Expand Down Expand Up @@ -544,6 +609,81 @@ def parse_export_ipv6(configobj, name):
pass


def parse_mdt(configobj, name):
cfg = configobj["vrf definition %s" % name]
mdt_list = []

for ip in ["ipv4", "ipv6"]:
ret_dict = {}
try:
subcfg = cfg["address-family " + ip]
subcfg = "\n".join(subcfg.children)
except KeyError:
subcfg = ""
pass

re1 = re.compile(r"^mdt +auto\-discovery +(?P<option>\S+)(\s+(?P<inter_as>inter\-as))?$")
re2 = re.compile(r"^mdt +default +vxlan +(?P<mcast_group>\S+)$")
re3 = re.compile(r"^mdt +data +vxlan +(?P<mcast_group>.+)$")
re4 = re.compile(r"^mdt +data +threshold +(?P<threshold_value>\d+)$")
re5 = re.compile(r"^mdt +overlay +(?P<use_bgp>use-bgp)(\s+(?P<spt_only>spt-only))?$")

for line in subcfg.splitlines():
line = line.strip()
m = re1.match(line)
if m:
group = m.groupdict()
ret_dict.setdefault("auto_discovery", {}).setdefault(
group["option"],
{},
).setdefault("enable", True)
if group["inter_as"]:
ret_dict.setdefault("auto_discovery", {}).setdefault(
group["option"],
{},
).setdefault("inter_as", True)
continue

m = re2.match(line)
if m:
group = m.groupdict()
ret_dict.setdefault("default", {}).setdefault(
"vxlan_mcast_group",
group["mcast_group"],
)
continue

m = re3.match(line)
if m:
group = m.groupdict()
ret_dict.setdefault("data_mcast", {}).setdefault(
"vxlan_mcast_group",
group["mcast_group"],
)
continue

m = re4.match(line)
if m:
group = m.groupdict()
ret_dict.setdefault("data_threshold", int(group["threshold_value"]))

m = re5.match(line)
if m:
group = m.groupdict()
ret_dict.setdefault("overlay", {}).setdefault(
"use_bgp",
{},
).setdefault("enable", True)
if group["spt_only"]:
ret_dict.setdefault("overlay", {}).setdefault(
"use_bgp",
{},
).setdefault("spt_only", True)

mdt_list.append({"afi": ip, "mdt": ret_dict})
return mdt_list


def map_config_to_obj(module):
config = get_config(module)
configobj = NetworkConfig(indent=1, contents=config)
Expand All @@ -568,6 +708,7 @@ def map_config_to_obj(module):
"route_import_ipv6": parse_import_ipv6(configobj, item),
"route_export_ipv6": parse_export_ipv6(configobj, item),
"route_both_ipv6": parse_both(configobj, item, address_family="ipv6"),
"address_family": parse_mdt(configobj, item),
}
instances.append(obj)
return instances
Expand Down Expand Up @@ -623,6 +764,7 @@ def map_params_to_obj(module):
item["route_import_ipv6"] = get_value("route_import_ipv6")
item["route_export_ipv6"] = get_value("route_export_ipv6")
item["route_both_ipv6"] = get_value("route_both_ipv6")
item["address_family"] = get_value("address_family")
both_addresses_family = ["", "_ipv6", "_ipv4"]
for address_family in both_addresses_family:
if item["route_both%s" % address_family]:
Expand Down Expand Up @@ -650,16 +792,18 @@ def update_objects(want, have):
else:
for key, value in iteritems(entry):
if value:
try:
if isinstance(value, list):
if isinstance(value, list):
try:
if sorted(value) != sorted(item[key]):
if (entry, item) not in updates:
updates.append((entry, item))
elif value != item[key]:
if (entry, item) not in updates:
except TypeError:
if value != item[key]:
updates.append((entry, item))
except TypeError:
pass
pass
elif value != item[key]:
if (entry, item) not in updates:
updates.append((entry, item))
return updates


Expand Down Expand Up @@ -692,6 +836,7 @@ def main():
vrfs=dict(type="list", elements="raw"),
name=dict(),
description=dict(),
address_family=dict(type="list", elements="dict"),
rd=dict(),
route_export=dict(type="list", elements="str"),
route_import=dict(type="list", elements="str"),
Expand Down Expand Up @@ -719,6 +864,7 @@ def main():
result["warnings"] = warnings
want = map_params_to_obj(module)
have = map_config_to_obj(module)

commands = map_obj_to_commands(update_objects(want, have), module)
if module.params["purge"]:
want_vrfs = [x["name"] for x in want]
Expand Down
69 changes: 69 additions & 0 deletions tests/unit/modules/network/ios/test_ios_vrf.py
Original file line number Diff line number Diff line change
Expand Up @@ -388,3 +388,72 @@ def test_ios_vrf_interface_brownfield(self):
set_module_args(dict(name="test_19", interfaces=["Ethernet1"]))
commands = ["interface Ethernet1", "vrf forwarding test_19", "ip address 1.2.3.4/5"]
self.execute_module(changed=True, commands=commands, sort=False)

def test_ios_mdt(self):
set_module_args(
{
"name": "blue",
"address_family": [
{
"afi": "ipv4",
"mdt": {
"overlay": {
"use_bgp": {
"enable": True,
"spt_only": True,
},
},
"auto_discovery": {
"vxlan": {
"enable": True,
"inter_as": True,
},
},
"default": {
"vxlan_mcast_group": "239.1.1.1",
},
"data": {
"vxlan_mcast_group": "225.2.2.0 0.0.0.255",
"threshold": "112",
},
},
},
{
"afi": "ipv6",
"mdt": {
"overlay": {
"use_bgp": {
"enable": True,
"spt_only": True,
},
},
"auto_discovery": {
"vxlan": {
"enable": True,
"inter_as": True,
},
},
"default": {
"vxlan_mcast_group": "239.1.1.2",
},
},
},
],
},
)
commands = [
"vrf definition blue",
"address-family ipv4",
"mdt overlay use-bgp spt-only",
"mdt auto-discovery vxlan inter-as",
"mdt default vxlan 239.1.1.1",
"mdt data vxlan 225.2.2.0 0.0.0.255",
"mdt data threshold 112",
"exit-address-family",
"address-family ipv6",
"mdt overlay use-bgp spt-only",
"mdt auto-discovery vxlan inter-as",
"mdt default vxlan 239.1.1.2",
"exit-address-family",
]
self.execute_module(changed=True, commands=commands, sort=False)
Loading