diff --git a/changelogs/fragments/nxos_nxapi.yaml b/changelogs/fragments/nxos_nxapi.yaml new file mode 100644 index 000000000..61b28627f --- /dev/null +++ b/changelogs/fragments/nxos_nxapi.yaml @@ -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" diff --git a/docs/cisco.nxos.nxos_nxapi_module.rst b/docs/cisco.nxos.nxos_nxapi_module.rst index 182fe1516..96a605baa 100644 --- a/docs/cisco.nxos.nxos_nxapi_module.rst +++ b/docs/cisco.nxos.nxos_nxapi_module.rst @@ -220,6 +220,21 @@ Parameters
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.
+ + +
+ vrf + +
+ string +
+ + + + +
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.
+ +
diff --git a/plugins/module_utils/network/nxos/utils/utils.py b/plugins/module_utils/network/nxos/utils/utils.py index 01468edd5..156f13f3f 100644 --- a/plugins/module_utils/network/nxos/utils/utils.py +++ b/plugins/module_utils/network/nxos/utils/utils.py @@ -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) diff --git a/plugins/modules/nxos_nxapi.py b/plugins/modules/nxos_nxapi.py index 400a7a5f5..3a19c18f6 100644 --- a/plugins/modules/nxos_nxapi.py +++ b/plugins/modules/nxos_nxapi.py @@ -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 = """ @@ -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"] @@ -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() @@ -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] @@ -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: @@ -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) @@ -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 @@ -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 @@ -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) diff --git a/tests/unit/modules/network/nxos/test_nxos_nxapi.py b/tests/unit/modules/network/nxos/test_nxos_nxapi.py index 12ceeac82..734f256e3 100644 --- a/tests/unit/modules/network/nxos/test_nxos_nxapi.py +++ b/tests/unit/modules/network/nxos/test_nxos_nxapi.py @@ -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 "], + )