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

[nxapi] Add vrf option to nxos_nxapi module #877

Open
wants to merge 9 commits into
base: main
Choose a base branch
from
5 changes: 5 additions & 0 deletions changelogs/fragments/nxos_nxapi.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
minor_changes:
- "nxos_nxapi - Add vrf parameter to nxos_nxapi module"
bugfixes:
- "nxos_nxapi - Fix ssl_strong_ciphers option is not working over version 10"
15 changes: 15 additions & 0 deletions docs/cisco.nxos.nxos_nxapi_module.rst
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,21 @@ Parameters
<div>Controls the use of the Transport Layer Security version 1.2 is configured. By default, this feature is disabled. To enable the use of TLSV1.2, set the value of this argument to True.</div>
</td>
</tr>
<tr>
<td colspan="1">
<div class="ansibleOptionAnchor" id="parameter-"></div>
<b>vrf</b>
<a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
<div style="font-size: small">
<span style="color: purple">string</span>
</div>
</td>
<td>
</td>
<td>
<div>Controls the vrf used to be used for NXAPI communication. By default (if not specify this parameter), all Layer 3 interfaces are used for NXAPI communication. If specify this parameter, only the Layer 3 interfaces in the specified VRF are used for NXAPI communication. The nxapi use-vrf feature is introduced in Cisco NX-OS Release 8.2(3) at N7K, and in Cisco NX-OS Release 7.0 at N3K and N9K.</div>
</td>
</tr>
</table>
<br/>

Expand Down
2 changes: 1 addition & 1 deletion plugins/module_utils/network/nxos/utils/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,7 @@ class Version:
"""Simple class to compare arbitrary versions"""

def __init__(self, version_string):
self.components = version_string.split(".")
self.components = list(map(int, version_string.split(".")))

def __eq__(self, other):
other = _coerce(other)
Expand Down
42 changes: 40 additions & 2 deletions plugins/modules/nxos_nxapi.py
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,15 @@
required: false
default: false
type: bool
vrf:
description:
- Controls the vrf used to be used for NXAPI communication.
By default (if not specify this parameter), all Layer 3 interfaces are used for NXAPI communication.
If specify this parameter, only the Layer 3 interfaces in the specified VRF are used for NXAPI communication.
The nxapi use-vrf feature is introduced in Cisco NX-OS Release 8.2(3) at N7K,
and in Cisco NX-OS Release 7.0 at N3K and N9K.
required: false
type: str
"""

EXAMPLES = """
Expand Down Expand Up @@ -178,6 +187,16 @@ def check_args(module, warnings, capabilities):
module.fail_json(
msg="sandbox or enable_sandbox is supported on NX-OS 7K series of switches",
)
os_version = extract_major_minor_version(capabilities["device_info"]["network_os_version"])
if module.params.get("vrf") and (
(os_version < "8.2" and "7K" in os_platform) or os_version < "7.0"
):
module.fail_json(
msg=(
"vrf is supported on NX-OS 7K series of switches starting from 8.2(3)"
" and on other platforms starting from 7.0"
),
)

state = module.params["state"]

Expand All @@ -202,6 +221,14 @@ def check_args(module, warnings, capabilities):
return warnings


def extract_major_minor_version(version_string):
match = re.match(r"^(\d+\.\d+)", version_string)
if match:
return Version(match.group(1))
else:
return None


def map_obj_to_commands(want, have, module, warnings, capabilities):
send_commands = list()
commands = dict()
Expand All @@ -212,7 +239,7 @@ def map_obj_to_commands(want, have, module, warnings, capabilities):
if device_info:
os_version = device_info.get("network_os_version")
if os_version:
os_version = os_version[:3]
os_version = extract_major_minor_version(os_version)
os_platform = device_info.get("network_os_platform")
if os_platform:
os_platform = os_platform[:3]
Expand Down Expand Up @@ -249,8 +276,11 @@ def needs_update(x):
if not want["sandbox"]:
commands["sandbox"] = "no %s" % commands["sandbox"]

if needs_update("vrf"):
commands["vrf"] = "nxapi use-vrf %s" % want["vrf"]

if os_platform and os_version:
if (os_platform == "N9K" or os_platform == "N3K") and Version(os_version) >= "9.2":
if (os_platform == "N9K" or os_platform == "N3K") and os_version >= "9.2":
if needs_update("ssl_strong_ciphers"):
commands["ssl_strong_ciphers"] = "nxapi ssl ciphers weak"
if want["ssl_strong_ciphers"] is True:
Expand Down Expand Up @@ -340,6 +370,11 @@ def parse_ssl_protocols(data):
return {"tlsv1_0": tlsv1_0, "tlsv1_1": tlsv1_1, "tlsv1_2": tlsv1_2}


def parse_vrf(data):
vrf = re.search(r"nxapi use-vrf (\w+)", data)
return {"vrf": vrf.group(1) if vrf else None}


def map_config_to_obj(module):
out = run_commands(module, ["show run all | inc nxapi"], check_rc=False)[0]
match = re.search(r"no feature nxapi", out, re.M)
Expand All @@ -357,6 +392,7 @@ def map_config_to_obj(module):
obj.update(parse_sandbox(out))
obj.update(parse_ssl_strong_ciphers(out))
obj.update(parse_ssl_protocols(out))
obj.update(parse_vrf(out))

return obj

Expand All @@ -373,6 +409,7 @@ def map_params_to_obj(module):
"tlsv1_0": module.params["tlsv1_0"],
"tlsv1_1": module.params["tlsv1_1"],
"tlsv1_2": module.params["tlsv1_2"],
"vrf": module.params.get("vrf", None),
}

return obj
Expand All @@ -391,6 +428,7 @@ def main():
tlsv1_0=dict(type="bool", default=True),
tlsv1_1=dict(type="bool", default=False),
tlsv1_2=dict(type="bool", default=False),
vrf=dict(type="str"),
)

module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True)
Expand Down
86 changes: 86 additions & 0 deletions tests/unit/modules/network/nxos/test_nxos_nxapi.py
Original file line number Diff line number Diff line change
Expand Up @@ -99,3 +99,89 @@ def test_nxos_nxapi_no_http(self):
changed=True,
commands=["no nxapi http", "nxapi https port 8443"],
)

def test_nxos_nxapi_use_vrf(self):
set_module_args(dict(vrf="management"))
self.execute_module_devices(changed=True, commands=["nxapi use-vrf management"])

def test_nxos_nxapi_failed_when_vrf_is_used_in_unsupported_version(self):
self.get_capabilities.return_value = {
"device_info": {
"network_os_platform": "N7K-C7018",
"network_os_version": "7.0(1)",
},
"network_api": "cliconf",
}
set_module_args(
dict(
http=True,
https=False,
http_port=80,
https_port=443,
sandbox=False,
vrf="management",
),
)
self.execute_module_devices(failed=True)

def test_nxos_nxapi_not_failed_in_old_version(self):
self.get_capabilities.return_value = {
"device_info": {
"network_os_platform": "N7K-C7018",
"network_os_version": "7.0(1)",
},
"network_api": "cliconf",
}
set_module_args(
dict(
http=True,
https=False,
http_port=80,
https_port=443,
sandbox=False,
),
)
self.execute_module_devices(changed=False, commands=[])

def test_nxos_nxapi_two_digit_version(self):
self.get_capabilities.return_value = {
"device_info": {
"network_os_platform": "N7K-C7018",
"network_os_version": "10.3(1)",
},
"network_api": "cliconf",
}
set_module_args(
dict(
http=True,
https=False,
http_port=80,
https_port=443,
sandbox=False,
vrf="default",
),
)
self.execute_module_devices(changed=True, commands=["nxapi use-vrf default"])

def test_nxos_nxapi_ssl_strong_ciphers_two_digit_version(self):
self.get_capabilities.return_value = {
"device_info": {
"network_os_platform": "N9K-C7018",
"network_os_version": "9.10(1)",
},
"network_api": "cliconf",
}
set_module_args(
dict(
http=True,
https=False,
http_port=80,
https_port=443,
sandbox=False,
ssl_strong_ciphers=True,
),
)
self.execute_module_devices(
changed=True,
commands=["no nxapi ssl ciphers weak", "nxapi ssl protocols TLSv1 "],
)
Loading