From ca66fb54eb9427919d5254f3820a9bd9bccc7e4b Mon Sep 17 00:00:00 2001 From: Ruchi Pakhle Date: Mon, 2 Dec 2024 02:39:01 +0530 Subject: [PATCH 1/6] Add nxos_vrf_interfaces module --- plugins/action/vrf_interfaces.py | 1 + .../nxos/argspec/vrf_interfaces/__init__.py | 0 .../argspec/vrf_interfaces/vrf_interfaces.py | 58 ++++++ .../nxos/config/vrf_interfaces/__init__.py | 0 .../config/vrf_interfaces/vrf_interfaces.py | 100 +++++++++++ .../module_utils/network/nxos/facts/facts.py | 5 +- .../nxos/facts/vrf_interfaces/__init__.py | 0 .../facts/vrf_interfaces/vrf_interfaces.py | 69 ++++++++ .../nxos/rm_templates/vrf_interfaces.py | 60 +++++++ plugins/modules/nxos_vrf_interfaces.py | 167 ++++++++++++++++++ 10 files changed, 459 insertions(+), 1 deletion(-) create mode 120000 plugins/action/vrf_interfaces.py create mode 100644 plugins/module_utils/network/nxos/argspec/vrf_interfaces/__init__.py create mode 100644 plugins/module_utils/network/nxos/argspec/vrf_interfaces/vrf_interfaces.py create mode 100644 plugins/module_utils/network/nxos/config/vrf_interfaces/__init__.py create mode 100644 plugins/module_utils/network/nxos/config/vrf_interfaces/vrf_interfaces.py create mode 100644 plugins/module_utils/network/nxos/facts/vrf_interfaces/__init__.py create mode 100644 plugins/module_utils/network/nxos/facts/vrf_interfaces/vrf_interfaces.py create mode 100644 plugins/module_utils/network/nxos/rm_templates/vrf_interfaces.py create mode 100644 plugins/modules/nxos_vrf_interfaces.py diff --git a/plugins/action/vrf_interfaces.py b/plugins/action/vrf_interfaces.py new file mode 120000 index 000000000..a69e27103 --- /dev/null +++ b/plugins/action/vrf_interfaces.py @@ -0,0 +1 @@ +nxos.py \ No newline at end of file diff --git a/plugins/module_utils/network/nxos/argspec/vrf_interfaces/__init__.py b/plugins/module_utils/network/nxos/argspec/vrf_interfaces/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/plugins/module_utils/network/nxos/argspec/vrf_interfaces/vrf_interfaces.py b/plugins/module_utils/network/nxos/argspec/vrf_interfaces/vrf_interfaces.py new file mode 100644 index 000000000..02bc64440 --- /dev/null +++ b/plugins/module_utils/network/nxos/argspec/vrf_interfaces/vrf_interfaces.py @@ -0,0 +1,58 @@ +# -*- coding: utf-8 -*- +# Copyright 2024 Red Hat +# GNU General Public License v3.0+ +# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + +############################################# +# WARNING # +############################################# +# +# This file is auto generated by the +# ansible.content_builder. +# +# Manually editing this file is not advised. +# +# To update the argspec make the desired changes +# in the documentation in the module file and re-run +# ansible.content_builder commenting out +# the path to external 'docstring' in build.yaml. +# +############################################## + +""" +The arg spec for the nxos_vrf_interfaces module +""" + + +class Vrf_interfacesArgs(object): # pylint: disable=R0903 + """The arg spec for the nxos_vrf_interfaces module + """ + + argument_spec = { + "config": { + "type": "list", + "elements": "dict", + "options": { + "name": {"type": "str", "required": True}, + "vrf_name": {"type": "str", "required": True}, + }, + }, + "running_config": {"type": "str"}, + "state": { + "type": "str", + "choices": [ + "merged", + "replaced", + "overridden", + "deleted", + "gathered", + "rendered", + "parsed", + ], + "default": "merged", + }, + } # pylint: disable=C0301 diff --git a/plugins/module_utils/network/nxos/config/vrf_interfaces/__init__.py b/plugins/module_utils/network/nxos/config/vrf_interfaces/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/plugins/module_utils/network/nxos/config/vrf_interfaces/vrf_interfaces.py b/plugins/module_utils/network/nxos/config/vrf_interfaces/vrf_interfaces.py new file mode 100644 index 000000000..d94e52a25 --- /dev/null +++ b/plugins/module_utils/network/nxos/config/vrf_interfaces/vrf_interfaces.py @@ -0,0 +1,100 @@ +# +# -*- coding: utf-8 -*- +# Copyright 2024 Red Hat +# GNU General Public License v3.0+ +# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +# + +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + +""" +The nxos_vrf_interfaces config file. +It is in this file where the current configuration (as dict) +is compared to the provided configuration (as dict) and the command set +necessary to bring the current configuration to its desired end-state is +created. +""" + + +from ansible.module_utils.six import iteritems +from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.utils import ( + dict_merge, +) +from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.rm_base.resource_module import ( + ResourceModule, +) +from ansible_collections.cisco.nxos.plugins.module_utils.network.nxos.facts.facts import ( + Facts, +) +from ansible_collections.cisco.nxos.plugins.module_utils.network.nxos.rm_templates.vrf_interfaces import ( + Vrf_interfacesTemplate, +) + + +class Vrf_interfaces(ResourceModule): + """ + The nxos_vrf_interfaces config class + """ + + def __init__(self, module): + super(Vrf_interfaces, self).__init__( + empty_fact_val={}, + facts_module=Facts(module), + module=module, + resource="vrf_interfaces", + tmplt=Vrf_interfacesTemplate(), + ) + self.parsers = [ + "interface", + ] + + def execute_module(self): + """ Execute the module + + :rtype: A dictionary + :returns: The result from module execution + """ + if self.state not in ["parsed", "gathered"]: + self.generate_commands() + self.run_commands() + return self.result + + def generate_commands(self): + """ Generate configuration commands to send based on + want, have and desired state. + """ + wantd = {entry['name']: entry for entry in self.want} + haved = {entry['name']: entry for entry in self.have} + + # if state is merged, merge want onto have and then compare + if self.state == "merged": + wantd = dict_merge(haved, wantd) + + # if state is deleted, empty out wantd and set haved to wantd + if self.state == "deleted": + haved = { + k: v for k, v in iteritems(haved) if k in wantd or not wantd + } + wantd = {} + + # remove superfluous config for overridden and deleted + if self.state in ["overridden", "deleted"]: + for k, have in iteritems(haved): + if k not in wantd: + self._compare(want={}, have=have) + + for k, want in iteritems(wantd): + self._compare(want=want, have=haved.pop(k, {})) + + def _compare(self, want, have): + """Leverages the base class `compare()` method and + populates the list of commands to be run by comparing + the `want` and `have` data with the `parsers` defined + for the Vrf_interfaces network resource. + """ + begin = len(self.commands) + self.compare(parsers=self.parsers, want=want, have=have) + if len(self.commands) != begin: + self.commands.insert(begin, self._tmplt.render(want or have, "interface", False)) diff --git a/plugins/module_utils/network/nxos/facts/facts.py b/plugins/module_utils/network/nxos/facts/facts.py index 4d1e38f92..3600cbc7c 100644 --- a/plugins/module_utils/network/nxos/facts/facts.py +++ b/plugins/module_utils/network/nxos/facts/facts.py @@ -114,7 +114,9 @@ from ansible_collections.cisco.nxos.plugins.module_utils.network.nxos.facts.vrf_global.vrf_global import ( Vrf_globalFacts, ) - +from ansible_collections.cisco.nxos.plugins.module_utils.network.nxos.facts.vrf_interfaces.vrf_interfaces import ( + Vrf_interfacesFacts, +) FACT_LEGACY_SUBSETS = dict( default=Default, @@ -154,6 +156,7 @@ hostname=HostnameFacts, bgp_templates=Bgp_templatesFacts, vrf_global=Vrf_globalFacts, + vrf_interfaces=Vrf_interfacesFacts, ) MDS_FACT_RESOURCE_SUBSETS = dict( fc_interfaces=Fc_interfacesFacts, diff --git a/plugins/module_utils/network/nxos/facts/vrf_interfaces/__init__.py b/plugins/module_utils/network/nxos/facts/vrf_interfaces/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/plugins/module_utils/network/nxos/facts/vrf_interfaces/vrf_interfaces.py b/plugins/module_utils/network/nxos/facts/vrf_interfaces/vrf_interfaces.py new file mode 100644 index 000000000..a5448c5a5 --- /dev/null +++ b/plugins/module_utils/network/nxos/facts/vrf_interfaces/vrf_interfaces.py @@ -0,0 +1,69 @@ +# -*- coding: utf-8 -*- +# Copyright 2024 Red Hat +# GNU General Public License v3.0+ +# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + +""" +The nxos vrf_interfaces fact class +It is in this file the configuration is collected from the device +for a given resource, parsed, and the facts tree is populated +based on the configuration. +""" + + +from ansible_collections.ansible.netcommon.plugins.module_utils.network.common import ( + utils, +) +from ansible_collections.cisco.nxos.plugins.module_utils.network.nxos.rm_templates.vrf_interfaces import ( + Vrf_interfacesTemplate, +) +from ansible_collections.cisco.nxos.plugins.module_utils.network.nxos.argspec.vrf_interfaces.vrf_interfaces import ( + Vrf_interfacesArgs, +) + + +class Vrf_interfacesFacts(object): + """ The nxos vrf_interfaces facts class + """ + + def __init__(self, module, subspec='config', options='options'): + self._module = module + self.argument_spec = Vrf_interfacesArgs.argument_spec + + def get_device_data(self, connection): + return connection.get_config(flags="interface") + + def populate_facts(self, connection, ansible_facts, data=None): + """ Populate the facts for Vrf_interfaces network resource + + :param connection: the device connection + :param ansible_facts: Facts dictionary + :param data: previously collected conf + + :rtype: dictionary + :returns: facts + """ + facts = {} + objs = [] + + if not data: + data = self.get_device_data(connection) + + # parse native config using the Vrf_interfaces template + vrf_interfaces_parser = Vrf_interfacesTemplate(lines=data.splitlines(), module=self._module) + objs = list(vrf_interfaces_parser.parse().values()) + + ansible_facts['ansible_network_resources'].pop('vrf_interfaces', None) + + params = utils.remove_empties( + vrf_interfaces_parser.validate_config(self.argument_spec, {"config": objs}, redact=True) + ) + + facts['vrf_interfaces'] = params['config'] + ansible_facts['ansible_network_resources'].update(facts) + + return ansible_facts diff --git a/plugins/module_utils/network/nxos/rm_templates/vrf_interfaces.py b/plugins/module_utils/network/nxos/rm_templates/vrf_interfaces.py new file mode 100644 index 000000000..32017a203 --- /dev/null +++ b/plugins/module_utils/network/nxos/rm_templates/vrf_interfaces.py @@ -0,0 +1,60 @@ +# -*- coding: utf-8 -*- +# Copyright 2024 Red Hat +# GNU General Public License v3.0+ +# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + +""" +The Vrf_interfaces parser templates file. This contains +a list of parser definitions and associated functions that +facilitates both facts gathering and native command generation for +the given network resource. +""" + +import re +from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.rm_base.network_template import ( + NetworkTemplate, +) + + +class Vrf_interfacesTemplate(NetworkTemplate): + def __init__(self, lines=None, module=None): + super(Vrf_interfacesTemplate, self).__init__(lines=lines, tmplt=self, module=module) + + # fmt: off + PARSERS = [ + { + 'name': 'interface', + 'getval': re.compile( + r''' + ^interface\s + (?P\S+)$''', re.VERBOSE, + ), + 'setval': 'interface {{ name }}', + 'result': { + '{{ name }}': { + 'name': '{{ name }}', + }, + }, + 'shared': True, + }, + { + "name": "vrf_name", + "getval": re.compile( + r""" + \s+vrf\smember\s(?P\S+)$ + """, + re.VERBOSE, + ), + "setval": "vrf member {{ vrf_name }}", + "result": { + '{{ name }}': { + 'vrf_name': '{{ vrf_name }}', + }, + }, + }, + ] + # fmt: on diff --git a/plugins/modules/nxos_vrf_interfaces.py b/plugins/modules/nxos_vrf_interfaces.py new file mode 100644 index 000000000..389b760b2 --- /dev/null +++ b/plugins/modules/nxos_vrf_interfaces.py @@ -0,0 +1,167 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# Copyright 2024 Red Hat +# GNU General Public License v3.0+ +# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +""" +The module file for nxos_vrf_interfaces +""" + +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + +DOCUMENTATION = """ +module: nxos_vrf_interfaces +short_description: Resource module to configure VRF interfaces. +description: This module configures and manages the VRF configuration in interface on NX-OS platforms. +version_added: 9.2.1 +author: Ruchi Pakhle (@Ruchip16) +notes: + - Tested against Cisco NX-OS. + - This module works with connection C(network_cli). +options: + config: + description: A list of VRF interfaces options. + type: list + elements: dict + suboptions: + name: + description: + - Full name of the interface excluding any logical unit number, + i.e. Ethernet1/1. + type: str + required: true + vrf_name: + description: + - Vrf that is to be added to the interface. + type: str + required: true + running_config: + description: + - This option is used only with state I(parsed). + - The value of this option should be the output received from the NX-OS + device by executing the command B(sh running-config interface). + - The state I(parsed) reads the configuration from C(running_config) + option and transforms it into Ansible structured data as per the + resource module's argspec and the value is then returned in the + I(parsed) key within the result. + type: str + state: + description: + - The state the configuration should be left in + - The states I(rendered), I(gathered) and I(parsed) does not perform any + change on the device. + - The state I(rendered) will transform the configuration in C(config) + option to platform specific CLI commands which will be returned in the + I(rendered) key within the result. For state I(rendered) active + connection to remote host is not required. + - The state I(gathered) will fetch the running configuration from device + and transform it into structured data in the format as per the resource + module argspec and the value is returned in the I(gathered) key within + the result. + - The state I(parsed) reads the configuration from C(running_config) + option and transforms it into JSON format as per the resource module + parameters and the value is returned in the I(parsed) key within the + result. The value of C(running_config) option should be the same format + as the output of command I(show running-config | include ip route|ipv6 + route) executed on device. For state I(parsed) active connection to + remote host is not required. + type: str + choices: + - merged + - replaced + - overridden + - deleted + - gathered + - rendered + - parsed + default: merged +""" + +EXAMPLES = """ + +""" + +RETURN = """ +before: + description: The configuration prior to the module execution. + returned: when I(state) is C(merged), C(replaced), C(overridden), C(deleted) or C(purged) + type: dict + sample: > + This output will always be in the same format as the + module argspec. +after: + description: The resulting configuration after module execution. + returned: when changed + type: dict + sample: > + This output will always be in the same format as the + module argspec. +commands: + description: The set of commands pushed to the remote device. + returned: when I(state) is C(merged), C(replaced), C(overridden), C(deleted) or C(purged) + type: list + sample: + - sample command 1 + - sample command 2 + - sample command 3 +rendered: + description: The provided configuration in the task rendered in device-native format (offline). + returned: when I(state) is C(rendered) + type: list + sample: + - sample command 1 + - sample command 2 + - sample command 3 +gathered: + description: Facts about the network resource gathered from the remote device as structured data. + returned: when I(state) is C(gathered) + type: list + sample: > + This output will always be in the same format as the + module argspec. +parsed: + description: The device native config provided in I(running_config) option parsed into structured data as per module argspec. + returned: when I(state) is C(parsed) + type: list + sample: > + This output will always be in the same format as the + module argspec. +""" + +from ansible.module_utils.basic import AnsibleModule +from ansible_collections.cisco.nxos.plugins.module_utils.network.nxos.argspec.vrf_interfaces.vrf_interfaces import ( + Vrf_interfacesArgs, +) +from ansible_collections.cisco.nxos.plugins.module_utils.network.nxos.config.vrf_interfaces.vrf_interfaces import ( + Vrf_interfaces, +) + + +def main(): + """ + Main entry point for module execution + + :returns: the result form module invocation + """ + module = AnsibleModule( + argument_spec=Vrf_interfacesArgs.argument_spec, + mutually_exclusive=[["config", "running_config"]], + required_if=[ + ["state", "merged", ["config"]], + ["state", "replaced", ["config"]], + ["state", "overridden", ["config"]], + ["state", "rendered", ["config"]], + ["state", "parsed", ["running_config"]], + ], + supports_check_mode=True, + ) + + result = Vrf_interfaces(module).execute_module() + module.exit_json(**result) + + +if __name__ == "__main__": + main() From bd67f4708d134021f8fee12ca4fa50e8948f633c Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Sun, 1 Dec 2024 21:11:36 +0000 Subject: [PATCH 2/6] chore: auto fixes from pre-commit.com hooks --- README.md | 1 + .../argspec/vrf_interfaces/vrf_interfaces.py | 4 +-- .../config/vrf_interfaces/vrf_interfaces.py | 30 +++++++++---------- .../module_utils/network/nxos/facts/facts.py | 1 + .../facts/vrf_interfaces/vrf_interfaces.py | 27 +++++++++-------- .../nxos/rm_templates/vrf_interfaces.py | 2 ++ plugins/modules/nxos_vrf_interfaces.py | 2 ++ 7 files changed, 36 insertions(+), 31 deletions(-) diff --git a/README.md b/README.md index a11a7450d..6e8b10133 100644 --- a/README.md +++ b/README.md @@ -141,6 +141,7 @@ Name | Description [cisco.nxos.nxos_vrf_af](https://github.com/ansible-collections/cisco.nxos/blob/main/docs/cisco.nxos.nxos_vrf_af_module.rst)|Manages VRF AF. [cisco.nxos.nxos_vrf_global](https://github.com/ansible-collections/cisco.nxos/blob/main/docs/cisco.nxos.nxos_vrf_global_module.rst)|Resource module to configure VRF definitions. [cisco.nxos.nxos_vrf_interface](https://github.com/ansible-collections/cisco.nxos/blob/main/docs/cisco.nxos.nxos_vrf_interface_module.rst)|Manages interface specific VRF configuration. +[cisco.nxos.nxos_vrf_interfaces](https://github.com/ansible-collections/cisco.nxos/blob/main/docs/cisco.nxos.nxos_vrf_interfaces_module.rst)|Resource module to configure VRF interfaces. [cisco.nxos.nxos_vrrp](https://github.com/ansible-collections/cisco.nxos/blob/main/docs/cisco.nxos.nxos_vrrp_module.rst)|Manages VRRP configuration on NX-OS switches. [cisco.nxos.nxos_vsan](https://github.com/ansible-collections/cisco.nxos/blob/main/docs/cisco.nxos.nxos_vsan_module.rst)|Configuration of vsan for Cisco NXOS MDS Switches. [cisco.nxos.nxos_vtp_domain](https://github.com/ansible-collections/cisco.nxos/blob/main/docs/cisco.nxos.nxos_vtp_domain_module.rst)|Manages VTP domain configuration. diff --git a/plugins/module_utils/network/nxos/argspec/vrf_interfaces/vrf_interfaces.py b/plugins/module_utils/network/nxos/argspec/vrf_interfaces/vrf_interfaces.py index 02bc64440..0306c7a0d 100644 --- a/plugins/module_utils/network/nxos/argspec/vrf_interfaces/vrf_interfaces.py +++ b/plugins/module_utils/network/nxos/argspec/vrf_interfaces/vrf_interfaces.py @@ -5,6 +5,7 @@ from __future__ import absolute_import, division, print_function + __metaclass__ = type ############################################# @@ -29,8 +30,7 @@ class Vrf_interfacesArgs(object): # pylint: disable=R0903 - """The arg spec for the nxos_vrf_interfaces module - """ + """The arg spec for the nxos_vrf_interfaces module""" argument_spec = { "config": { diff --git a/plugins/module_utils/network/nxos/config/vrf_interfaces/vrf_interfaces.py b/plugins/module_utils/network/nxos/config/vrf_interfaces/vrf_interfaces.py index d94e52a25..89635880b 100644 --- a/plugins/module_utils/network/nxos/config/vrf_interfaces/vrf_interfaces.py +++ b/plugins/module_utils/network/nxos/config/vrf_interfaces/vrf_interfaces.py @@ -7,6 +7,7 @@ from __future__ import absolute_import, division, print_function + __metaclass__ = type """ @@ -19,15 +20,14 @@ from ansible.module_utils.six import iteritems -from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.utils import ( - dict_merge, -) from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.rm_base.resource_module import ( ResourceModule, ) -from ansible_collections.cisco.nxos.plugins.module_utils.network.nxos.facts.facts import ( - Facts, +from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.utils import ( + dict_merge, ) + +from ansible_collections.cisco.nxos.plugins.module_utils.network.nxos.facts.facts import Facts from ansible_collections.cisco.nxos.plugins.module_utils.network.nxos.rm_templates.vrf_interfaces import ( Vrf_interfacesTemplate, ) @@ -51,7 +51,7 @@ def __init__(self, module): ] def execute_module(self): - """ Execute the module + """Execute the module :rtype: A dictionary :returns: The result from module execution @@ -62,11 +62,11 @@ def execute_module(self): return self.result def generate_commands(self): - """ Generate configuration commands to send based on - want, have and desired state. + """Generate configuration commands to send based on + want, have and desired state. """ - wantd = {entry['name']: entry for entry in self.want} - haved = {entry['name']: entry for entry in self.have} + wantd = {entry["name"]: entry for entry in self.want} + haved = {entry["name"]: entry for entry in self.have} # if state is merged, merge want onto have and then compare if self.state == "merged": @@ -74,9 +74,7 @@ def generate_commands(self): # if state is deleted, empty out wantd and set haved to wantd if self.state == "deleted": - haved = { - k: v for k, v in iteritems(haved) if k in wantd or not wantd - } + haved = {k: v for k, v in iteritems(haved) if k in wantd or not wantd} wantd = {} # remove superfluous config for overridden and deleted @@ -90,9 +88,9 @@ def generate_commands(self): def _compare(self, want, have): """Leverages the base class `compare()` method and - populates the list of commands to be run by comparing - the `want` and `have` data with the `parsers` defined - for the Vrf_interfaces network resource. + populates the list of commands to be run by comparing + the `want` and `have` data with the `parsers` defined + for the Vrf_interfaces network resource. """ begin = len(self.commands) self.compare(parsers=self.parsers, want=want, have=have) diff --git a/plugins/module_utils/network/nxos/facts/facts.py b/plugins/module_utils/network/nxos/facts/facts.py index 3600cbc7c..7f28e15bc 100644 --- a/plugins/module_utils/network/nxos/facts/facts.py +++ b/plugins/module_utils/network/nxos/facts/facts.py @@ -118,6 +118,7 @@ Vrf_interfacesFacts, ) + FACT_LEGACY_SUBSETS = dict( default=Default, legacy=Legacy, diff --git a/plugins/module_utils/network/nxos/facts/vrf_interfaces/vrf_interfaces.py b/plugins/module_utils/network/nxos/facts/vrf_interfaces/vrf_interfaces.py index a5448c5a5..73708688d 100644 --- a/plugins/module_utils/network/nxos/facts/vrf_interfaces/vrf_interfaces.py +++ b/plugins/module_utils/network/nxos/facts/vrf_interfaces/vrf_interfaces.py @@ -5,6 +5,7 @@ from __future__ import absolute_import, division, print_function + __metaclass__ = type """ @@ -15,22 +16,20 @@ """ -from ansible_collections.ansible.netcommon.plugins.module_utils.network.common import ( - utils, +from ansible_collections.ansible.netcommon.plugins.module_utils.network.common import utils + +from ansible_collections.cisco.nxos.plugins.module_utils.network.nxos.argspec.vrf_interfaces.vrf_interfaces import ( + Vrf_interfacesArgs, ) from ansible_collections.cisco.nxos.plugins.module_utils.network.nxos.rm_templates.vrf_interfaces import ( Vrf_interfacesTemplate, ) -from ansible_collections.cisco.nxos.plugins.module_utils.network.nxos.argspec.vrf_interfaces.vrf_interfaces import ( - Vrf_interfacesArgs, -) class Vrf_interfacesFacts(object): - """ The nxos vrf_interfaces facts class - """ + """The nxos vrf_interfaces facts class""" - def __init__(self, module, subspec='config', options='options'): + def __init__(self, module, subspec="config", options="options"): self._module = module self.argument_spec = Vrf_interfacesArgs.argument_spec @@ -38,7 +37,7 @@ def get_device_data(self, connection): return connection.get_config(flags="interface") def populate_facts(self, connection, ansible_facts, data=None): - """ Populate the facts for Vrf_interfaces network resource + """Populate the facts for Vrf_interfaces network resource :param connection: the device connection :param ansible_facts: Facts dictionary @@ -57,13 +56,15 @@ def populate_facts(self, connection, ansible_facts, data=None): vrf_interfaces_parser = Vrf_interfacesTemplate(lines=data.splitlines(), module=self._module) objs = list(vrf_interfaces_parser.parse().values()) - ansible_facts['ansible_network_resources'].pop('vrf_interfaces', None) + ansible_facts["ansible_network_resources"].pop("vrf_interfaces", None) params = utils.remove_empties( - vrf_interfaces_parser.validate_config(self.argument_spec, {"config": objs}, redact=True) + vrf_interfaces_parser.validate_config( + self.argument_spec, {"config": objs}, redact=True + ), ) - facts['vrf_interfaces'] = params['config'] - ansible_facts['ansible_network_resources'].update(facts) + facts["vrf_interfaces"] = params["config"] + ansible_facts["ansible_network_resources"].update(facts) return ansible_facts diff --git a/plugins/module_utils/network/nxos/rm_templates/vrf_interfaces.py b/plugins/module_utils/network/nxos/rm_templates/vrf_interfaces.py index 32017a203..cf0373e33 100644 --- a/plugins/module_utils/network/nxos/rm_templates/vrf_interfaces.py +++ b/plugins/module_utils/network/nxos/rm_templates/vrf_interfaces.py @@ -5,6 +5,7 @@ from __future__ import absolute_import, division, print_function + __metaclass__ = type """ @@ -15,6 +16,7 @@ """ import re + from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.rm_base.network_template import ( NetworkTemplate, ) diff --git a/plugins/modules/nxos_vrf_interfaces.py b/plugins/modules/nxos_vrf_interfaces.py index 389b760b2..2a0c7175d 100644 --- a/plugins/modules/nxos_vrf_interfaces.py +++ b/plugins/modules/nxos_vrf_interfaces.py @@ -10,6 +10,7 @@ from __future__ import absolute_import, division, print_function + __metaclass__ = type DOCUMENTATION = """ @@ -132,6 +133,7 @@ """ from ansible.module_utils.basic import AnsibleModule + from ansible_collections.cisco.nxos.plugins.module_utils.network.nxos.argspec.vrf_interfaces.vrf_interfaces import ( Vrf_interfacesArgs, ) From 7b781af5095eb8bf4bc982917ab707bb84c6a0ee Mon Sep 17 00:00:00 2001 From: Ruchi Pakhle Date: Mon, 9 Dec 2024 15:16:07 +0530 Subject: [PATCH 3/6] add changelog and update config side code --- changelogs/fragments/add_vrf_interfaces.yaml | 3 +++ meta/runtime.yml | 2 ++ .../nxos/argspec/vrf_interfaces/vrf_interfaces.py | 2 +- .../nxos/config/vrf_interfaces/vrf_interfaces.py | 4 +++- .../nxos/facts/vrf_interfaces/vrf_interfaces.py | 2 +- .../network/nxos/rm_templates/vrf_interfaces.py | 15 +++++++++++++++ plugins/modules/nxos_vrf_interfaces.py | 1 - 7 files changed, 25 insertions(+), 4 deletions(-) create mode 100644 changelogs/fragments/add_vrf_interfaces.yaml diff --git a/changelogs/fragments/add_vrf_interfaces.yaml b/changelogs/fragments/add_vrf_interfaces.yaml new file mode 100644 index 000000000..3d77cbfd2 --- /dev/null +++ b/changelogs/fragments/add_vrf_interfaces.yaml @@ -0,0 +1,3 @@ +--- +minor_changes: + - Added nxos_vrf_interfaces resource module, that helps with configuration of vrfs within interface in favor of nxos_vrf_interface module. diff --git a/meta/runtime.yml b/meta/runtime.yml index 40dfbf1fc..a703ed5fc 100644 --- a/meta/runtime.yml +++ b/meta/runtime.yml @@ -205,3 +205,5 @@ plugin_routing: redirect: cisco.nxos.nxos_zone_zoneset vrf_global: redirect: cisco.nxos.nxos_vrf_global + vrf_interfaces: + redirect: cisco.nxos.nxos_vrf_interfaces diff --git a/plugins/module_utils/network/nxos/argspec/vrf_interfaces/vrf_interfaces.py b/plugins/module_utils/network/nxos/argspec/vrf_interfaces/vrf_interfaces.py index 02bc64440..729c05692 100644 --- a/plugins/module_utils/network/nxos/argspec/vrf_interfaces/vrf_interfaces.py +++ b/plugins/module_utils/network/nxos/argspec/vrf_interfaces/vrf_interfaces.py @@ -38,7 +38,7 @@ class Vrf_interfacesArgs(object): # pylint: disable=R0903 "elements": "dict", "options": { "name": {"type": "str", "required": True}, - "vrf_name": {"type": "str", "required": True}, + "vrf_name": {"type": "str"}, }, }, "running_config": {"type": "str"}, diff --git a/plugins/module_utils/network/nxos/config/vrf_interfaces/vrf_interfaces.py b/plugins/module_utils/network/nxos/config/vrf_interfaces/vrf_interfaces.py index d94e52a25..449783d3f 100644 --- a/plugins/module_utils/network/nxos/config/vrf_interfaces/vrf_interfaces.py +++ b/plugins/module_utils/network/nxos/config/vrf_interfaces/vrf_interfaces.py @@ -48,6 +48,8 @@ def __init__(self, module): ) self.parsers = [ "interface", + "vrf_name", + "vrf_context", ] def execute_module(self): @@ -97,4 +99,4 @@ def _compare(self, want, have): begin = len(self.commands) self.compare(parsers=self.parsers, want=want, have=have) if len(self.commands) != begin: - self.commands.insert(begin, self._tmplt.render(want or have, "interface", False)) + self.commands.insert(begin, self._tmplt.render(want or have, "interface", False)) \ No newline at end of file diff --git a/plugins/module_utils/network/nxos/facts/vrf_interfaces/vrf_interfaces.py b/plugins/module_utils/network/nxos/facts/vrf_interfaces/vrf_interfaces.py index a5448c5a5..5aa0af805 100644 --- a/plugins/module_utils/network/nxos/facts/vrf_interfaces/vrf_interfaces.py +++ b/plugins/module_utils/network/nxos/facts/vrf_interfaces/vrf_interfaces.py @@ -63,7 +63,7 @@ def populate_facts(self, connection, ansible_facts, data=None): vrf_interfaces_parser.validate_config(self.argument_spec, {"config": objs}, redact=True) ) - facts['vrf_interfaces'] = params['config'] + facts["vrf_interfaces"] = params.get("config", []) ansible_facts['ansible_network_resources'].update(facts) return ansible_facts diff --git a/plugins/module_utils/network/nxos/rm_templates/vrf_interfaces.py b/plugins/module_utils/network/nxos/rm_templates/vrf_interfaces.py index 32017a203..1fd217f2f 100644 --- a/plugins/module_utils/network/nxos/rm_templates/vrf_interfaces.py +++ b/plugins/module_utils/network/nxos/rm_templates/vrf_interfaces.py @@ -56,5 +56,20 @@ def __init__(self, lines=None, module=None): }, }, }, + { + "name": "vrf_context", + "getval": re.compile( + r""" + \s+vrf\scontext\s(?P\S+)$ + """, + re.VERBOSE, + ), + "setval": "vrf context {{ vrf_context}}", + "result": { + '{{ name }}': { + 'vrf_context': '{{ vrf_context }}', + }, + }, + }, ] # fmt: on diff --git a/plugins/modules/nxos_vrf_interfaces.py b/plugins/modules/nxos_vrf_interfaces.py index 389b760b2..23f696788 100644 --- a/plugins/modules/nxos_vrf_interfaces.py +++ b/plugins/modules/nxos_vrf_interfaces.py @@ -37,7 +37,6 @@ description: - Vrf that is to be added to the interface. type: str - required: true running_config: description: - This option is used only with state I(parsed). From fa0f26b2541489dd296b3c78252b889efa4675d3 Mon Sep 17 00:00:00 2001 From: Ruchi Pakhle Date: Wed, 11 Dec 2024 01:58:30 +0530 Subject: [PATCH 4/6] add tests & examples --- .../config/vrf_interfaces/vrf_interfaces.py | 7 +- .../nxos/rm_templates/vrf_interfaces.py | 15 - plugins/modules/nxos_vrf_interfaces.py | 465 ++++++++++++++++-- .../nxos_vrf_interfaces/defaults/main.yaml | 2 + .../targets/nxos_vrf_interfaces/meta/main.yml | 3 + .../nxos_vrf_interfaces/tasks/cli.yaml | 31 ++ .../nxos_vrf_interfaces/tasks/main.yaml | 12 + .../nxos_vrf_interfaces/tasks/nxapi.yaml | 31 ++ .../tests/common/_parsed.cfg | 7 + .../tests/common/_populate_config.yaml | 11 + .../tests/common/_remove_config.yaml | 9 + .../tests/common/deleted.yaml | 51 ++ .../tests/common/empty_config.yaml | 61 +++ .../tests/common/gathered.yaml | 22 + .../tests/common/merged.yaml | 43 ++ .../tests/common/overridden.yaml | 45 ++ .../tests/common/parsed.yaml | 14 + .../tests/common/rendered.yaml | 20 + .../tests/common/replaced.yaml | 42 ++ .../nxos_vrf_interfaces/tests/common/rtt.yaml | 51 ++ .../nxos_vrf_interfaces/vars/main.yaml | 95 ++++ 21 files changed, 980 insertions(+), 57 deletions(-) create mode 100644 tests/integration/targets/nxos_vrf_interfaces/defaults/main.yaml create mode 100644 tests/integration/targets/nxos_vrf_interfaces/meta/main.yml create mode 100644 tests/integration/targets/nxos_vrf_interfaces/tasks/cli.yaml create mode 100644 tests/integration/targets/nxos_vrf_interfaces/tasks/main.yaml create mode 100644 tests/integration/targets/nxos_vrf_interfaces/tasks/nxapi.yaml create mode 100644 tests/integration/targets/nxos_vrf_interfaces/tests/common/_parsed.cfg create mode 100644 tests/integration/targets/nxos_vrf_interfaces/tests/common/_populate_config.yaml create mode 100644 tests/integration/targets/nxos_vrf_interfaces/tests/common/_remove_config.yaml create mode 100644 tests/integration/targets/nxos_vrf_interfaces/tests/common/deleted.yaml create mode 100644 tests/integration/targets/nxos_vrf_interfaces/tests/common/empty_config.yaml create mode 100644 tests/integration/targets/nxos_vrf_interfaces/tests/common/gathered.yaml create mode 100644 tests/integration/targets/nxos_vrf_interfaces/tests/common/merged.yaml create mode 100644 tests/integration/targets/nxos_vrf_interfaces/tests/common/overridden.yaml create mode 100644 tests/integration/targets/nxos_vrf_interfaces/tests/common/parsed.yaml create mode 100644 tests/integration/targets/nxos_vrf_interfaces/tests/common/rendered.yaml create mode 100644 tests/integration/targets/nxos_vrf_interfaces/tests/common/replaced.yaml create mode 100644 tests/integration/targets/nxos_vrf_interfaces/tests/common/rtt.yaml create mode 100644 tests/integration/targets/nxos_vrf_interfaces/vars/main.yaml diff --git a/plugins/module_utils/network/nxos/config/vrf_interfaces/vrf_interfaces.py b/plugins/module_utils/network/nxos/config/vrf_interfaces/vrf_interfaces.py index d89b84fda..88c465bb2 100644 --- a/plugins/module_utils/network/nxos/config/vrf_interfaces/vrf_interfaces.py +++ b/plugins/module_utils/network/nxos/config/vrf_interfaces/vrf_interfaces.py @@ -49,7 +49,6 @@ def __init__(self, module): self.parsers = [ "interface", "vrf_name", - "vrf_context", ] def execute_module(self): @@ -70,6 +69,10 @@ def generate_commands(self): wantd = {entry["name"]: entry for entry in self.want} haved = {entry["name"]: entry for entry in self.have} + # Filter out mgmt0 interface + wantd = {k: v for k, v in wantd.items() if k != "mgmt0"} + haved = {k: v for k, v in haved.items() if k != "mgmt0"} + # if state is merged, merge want onto have and then compare if self.state == "merged": wantd = dict_merge(haved, wantd) @@ -97,4 +100,4 @@ def _compare(self, want, have): begin = len(self.commands) self.compare(parsers=self.parsers, want=want, have=have) if len(self.commands) != begin: - self.commands.insert(begin, self._tmplt.render(want or have, "interface", False)) \ No newline at end of file + self.commands.insert(begin, self._tmplt.render(want or have, "interface", False)) diff --git a/plugins/module_utils/network/nxos/rm_templates/vrf_interfaces.py b/plugins/module_utils/network/nxos/rm_templates/vrf_interfaces.py index 42e761d99..cf0373e33 100644 --- a/plugins/module_utils/network/nxos/rm_templates/vrf_interfaces.py +++ b/plugins/module_utils/network/nxos/rm_templates/vrf_interfaces.py @@ -58,20 +58,5 @@ def __init__(self, lines=None, module=None): }, }, }, - { - "name": "vrf_context", - "getval": re.compile( - r""" - \s+vrf\scontext\s(?P\S+)$ - """, - re.VERBOSE, - ), - "setval": "vrf context {{ vrf_context}}", - "result": { - '{{ name }}': { - 'vrf_context': '{{ vrf_context }}', - }, - }, - }, ] # fmt: on diff --git a/plugins/modules/nxos_vrf_interfaces.py b/plugins/modules/nxos_vrf_interfaces.py index 6130818c6..47452dc5a 100644 --- a/plugins/modules/nxos_vrf_interfaces.py +++ b/plugins/modules/nxos_vrf_interfaces.py @@ -16,15 +16,15 @@ DOCUMENTATION = """ module: nxos_vrf_interfaces short_description: Resource module to configure VRF interfaces. -description: This module configures and manages the VRF configuration in interface on NX-OS platforms. -version_added: 9.2.1 +description: This module configures and manages the VRF configuration on interfaces on NX-OS platforms. +version_added: 1.0.0 author: Ruchi Pakhle (@Ruchip16) notes: - Tested against Cisco NX-OS. - This module works with connection C(network_cli). options: config: - description: A list of VRF interfaces options. + description: A list of interface VRF configurations. type: list elements: dict suboptions: @@ -36,13 +36,14 @@ required: true vrf_name: description: - - Vrf that is to be added to the interface. + - Name of the VRF to be configured on the interface. + - When configured, applies 'vrf member ' under the interface. type: str running_config: description: - This option is used only with state I(parsed). - The value of this option should be the output received from the NX-OS - device by executing the command B(sh running-config interface). + device by executing the command B(show running-config interface). - The state I(parsed) reads the configuration from C(running_config) option and transforms it into Ansible structured data as per the resource module's argspec and the value is then returned in the @@ -51,23 +52,6 @@ state: description: - The state the configuration should be left in - - The states I(rendered), I(gathered) and I(parsed) does not perform any - change on the device. - - The state I(rendered) will transform the configuration in C(config) - option to platform specific CLI commands which will be returned in the - I(rendered) key within the result. For state I(rendered) active - connection to remote host is not required. - - The state I(gathered) will fetch the running configuration from device - and transform it into structured data in the format as per the resource - module argspec and the value is returned in the I(gathered) key within - the result. - - The state I(parsed) reads the configuration from C(running_config) - option and transforms it into JSON format as per the resource module - parameters and the value is returned in the I(parsed) key within the - result. The value of C(running_config) option should be the same format - as the output of command I(show running-config | include ip route|ipv6 - route) executed on device. For state I(parsed) active connection to - remote host is not required. type: str choices: - merged @@ -81,54 +65,455 @@ """ EXAMPLES = """ +# Using merged + +# Before state: +# ------------- +# +# nxos#show running-config interface +# interface Ethernet1/1 +# no switchport +# interface Ethernet1/2 +# description test +# no switchport +# no shutdown +# interface Ethernet1/3 +# interface Ethernet1/4 +# no switchport +# speed 1000 +# no shutdown + +- name: Merge provided configuration with device configuration + cisco.nxos.nxos_vrf_interfaces: + config: + - name: Ethernet1/1 + - name: Ethernet1/2 + vrf_name: test + - name: Ethernet1/3 + - name:Ethernet1/4 + state: merged + +# Task Output: +# ------------ +# +# before: +# - name: "Ethernet1/1" +# - name: "Ethernet1/2" +# - name: "Ethernet1/3" +# - name: "Ethernet1/4" +# +# commands: +# - interface Ethernet1/2 +# - vrf member test +# +# after: +# - name: "Ethernet1/1" +# - name: "Ethernet1/2" +# vrf_name: "test2" +# - name: "Ethernet1/3" +# - name: "Ethernet1/4" + +# After state: +# ------------ +# +# nxos#show running-config interface +# interface Ethernet1/1 +# no ip address +# interface Ethernet1/2 +# vrf member test +# no ip address +# shutdown +# negotiation auto +# interface Ethernet1/3 +# no ip address +# negotiation auto +# interfaceEthernet1/4 +# no ip address +# shutdown +# negotiation auto + +# Using overridden + +# Before state: +# ------------- +# +# nxos#show running-config interface +# interface Ethernet1/1 +# no ip address +# interface Ethernet1/1 +# ip address dhcp +# negotiation auto +# interface Ethernet1/2 +# vrf member vrf_B +# no ip address +# shutdown +# negotiation auto +# interface Ethernet1/3 +# no ip address +# negotiation auto +# interface Ethernet1/4 +# no ip address +# shutdown +# negotiation auto + +- name: Override device configuration with provided configuration + cisco.nxos.nxos_vrf_interfaces: + config: + - name: Ethernet1/1 + - name: Ethernet1/2 + - name: Ethernet1/3 + - name: Ethernet1/4 + state: overridden + +# Task Output: +# ------------ +# +# before: +# - name: "Ethernet1/1" +# - name: "Ethernet1/2" +# vrf_name: "vrf_B" +# - name: "Ethernet1/3" +# - name: "Ethernet1/4" +# +# commands: +# - interface Ethernet1/2 +# - no vrf member vrf_B +# +# after: +# - name: "Ethernet1/1" +# - name: "Ethernet1/2" +# - name: "Ethernet1/3" +# - name: "Ethernet1/4" + +# After state: +# ------------ +# +# nxos#show running-config interface +# interface Ethernet1/1 +# no ip address +# interface Ethernet1/2 +# no ip address +# shutdown +# negotiation auto +# interface Ethernet1/3 +# no ip address +# negotiation auto +# interface Ethernet1/4 +# no ip address +# shutdown +# negotiation auto + +# Using gathered + +# Before state: +# ------------- +# +# nxos#show running-config interface +# interface Ethernet1/1 +# no ip address +# interface Ethernet1/2 +# vrf member vrf_B +# no ip address +# shutdown +# negotiation auto +# interface Ethernet1/3 +# no ip address +# negotiation auto +# interfaceEthernet1/4 +# no ip address +# shutdown +# negotiation auto + +- name: Gather listed VRF interfaces + cisco.nxos.nxos_vrf_interfaces: + state: gathered + +# Task Output: +# ------------ +# +# gathered: +# - name: "Ethernet1/1" +# - name: "Ethernet1/2" +# vrf_name: "vrf_B" +# - name: "Ethernet1/3" + +# Using rendered + +- name: Render VRF configuration + cisco.nxos.nxos_vrf_interfaces: + config: + - name: Ethernet1/1 + - name: Ethernet1/2 + vrf_name: test + - name: Ethernet1/3 + - name: Ethernet1/4 + state: rendered + +# Task Output: +# ------------ +# +# rendered: +# - interface Ethernet1/2 +# - vrf member test + +# Using parsed +# File: parsed.cfg +# --------------- +# +# interface Ethernet1/2 +# no switchport +# vrf member VRF1 +# interface Ethernet1/6 +# no switchport +# speed 1000 +# vrf member TEST_VRF + +- name: Parse configuration from device running config + cisco.nxos.nxos_vrf_interfaces: + running_config: "{{ lookup('file', 'parsed.cfg') }}" + state: parsed + +# Task Output: +# ------------ +# +# parsed: +# - name: "Ethernet1/2" +# vrf_name: "VRF1" +# - name: "Ethernet1/6" +# vrf_name: "TEST_VRF" + +# Using replaced + +# Before state: +# ------------- +# +# nxos#show running-config interface +# interface Ethernet1/1 +# no ip address +# interface Ethernet1/2 +# vrf member vrf_B +# no ip address +# shutdown +# interface Ethernet1/3 +# no ip address +# interfaceEthernet1/4 +# vrf member vrf_C +# no ip address +# shutdown + +- name: Replace device configuration of listed VRF interfaces with provided configuration + cisco.nxos.nxos_vrf_interfaces: + config: + - name: Ethernet1/1 + vrf_name: test + - name: Ethernet1/2 + vrf_name: vrf_E + state: replaced + +# Task Output: +# ------------ +# +# before: +# - name: "Ethernet1/1" +# vrf_name: "vrf_A" +# - name: "Ethernet1/2" +# vrf_name: "vrf_B" +# - name: "Ethernet1/3" +# - name: "Ethernet1/4" +# vrf_name: "vrf_C" +# +# commands: +# - interface Ethernet1/1 +# - no vrf member vrf_A +# - vrf member test +# - interface Ethernet1/2 +# - no vrf member vrf_B +# - vrf member vrf_E +# +# after: +# - name: "Ethernet1/1" +# vrf_name: "test" +# - name: "Ethernet1/2" +# vrf_name: "vrf_E" +# - name: "Ethernet1/3" +# - name: "Ethernet1/4" +# vrf_name: "vrf_C" + +# Using deleted + +# Before state: +# ------------- +# +# nxos#show running-config interface +# interface Ethernet1/1 +# vrf member vrf_A +# ip address dhcp +# interface Ethernet1/2 +# vrf member vrf_B +# no ip address +# shutdown +# interface Ethernet1/3 +# no ip address +# interfaceEthernet1/4 +# vrf member vrf_C +# no ip address +# shutdown + +- name: Delete VRF configuration of specified interfaces + cisco.nxos.nxos_vrf_interfaces: + config: + - name: Ethernet1/1 + - name: Ethernet1/2 + state: deleted + +# Task Output: +# ------------ +# +# before: +# - name: "Ethernet1/1" +# vrf_name: "vrf_A" +# - name: "Ethernet1/2" +# vrf_name: "vrf_B" +# - name: "Ethernet1/3" +# - name: "Ethernet1/4" +# vrf_name: "vrf_C" +# +# commands: +# - interface Ethernet1/1 +# - no vrf member vrf_A +# - interface Ethernet1/2 +# - no vrf member vrf_B +# +# after: +# - name: "Ethernet1/1" +# - name: "Ethernet1/1" +# - name: "Ethernet1/2" +# - name: "Ethernet1/3" +# - name: "Ethernet1/4" +# vrf_name: "vrf_C" + +# After state: +# ------------ +# +# nxos#show running-config interface +# interface Ethernet1/1 +# ip address dhcp +# interface Ethernet1/2 +# no ip address +# shutdown +# interface Ethernet1/3 +# no ip address +# interfaceEthernet1/4 +# vrf member vrf_C +# no ip address +# shutdown """ RETURN = """ before: description: The configuration prior to the module execution. - returned: when I(state) is C(merged), C(replaced), C(overridden), C(deleted) or C(purged) - type: dict + returned: when I(state) is C(merged), C(replaced), C(overridden), C(deleted) + type: list sample: > - This output will always be in the same format as the - module argspec. + [ + { + "name": "Ethernet1/1" + }, + { + "name": "Ethernet1/2", + "vrf_name": "test" + }, + { + "name": "Ethernet1/3" + }, + { + "name": "Ethernet1/4" + } + ] + after: description: The resulting configuration after module execution. returned: when changed - type: dict + type: list sample: > - This output will always be in the same format as the - module argspec. + [ + { + "name": "Ethernet1/1" + }, + { + "name": "Ethernet1/2", + "vrf_name": "test" + }, + { + "name": "Ethernet1/3" + }, + { + "name": "Ethernet1/4" + } + ] + commands: description: The set of commands pushed to the remote device. - returned: when I(state) is C(merged), C(replaced), C(overridden), C(deleted) or C(purged) + returned: when I(state) is C(merged), C(replaced), C(overridden), C(deleted) type: list sample: - - sample command 1 - - sample command 2 - - sample command 3 + - "interface Ethernet1/2" + - "vrf member test" + - "no vrf member vrf_B" + rendered: description: The provided configuration in the task rendered in device-native format (offline). returned: when I(state) is C(rendered) type: list sample: - - sample command 1 - - sample command 2 - - sample command 3 + - "interface Ethernet1/1" + - "vrf member vrf_C" + - "interface Ethernet1/2" + - "vrf member test" + gathered: description: Facts about the network resource gathered from the remote device as structured data. returned: when I(state) is C(gathered) type: list sample: > - This output will always be in the same format as the - module argspec. + [ + { + "name": "Ethernet1/1" + }, + { + "name": "Ethernet1/2", + "vrf_name": "vrf_B" + }, + { + "name": "Ethernet1/3" + }, + { + "name": "Ethernet1/4" + } + ] + parsed: description: The device native config provided in I(running_config) option parsed into structured data as per module argspec. returned: when I(state) is C(parsed) type: list sample: > - This output will always be in the same format as the - module argspec. + [ + { + "name": "Ethernet1/1", + "vrf_name": "vrf_C" + }, + { + "name": "Ethernet1/2", + "vrf_name": "test" + }, + { + "name": "Ethernet1/3" + }, + { + "name": "Ethernet1/4" + } + ] """ from ansible.module_utils.basic import AnsibleModule diff --git a/tests/integration/targets/nxos_vrf_interfaces/defaults/main.yaml b/tests/integration/targets/nxos_vrf_interfaces/defaults/main.yaml new file mode 100644 index 000000000..5f709c5aa --- /dev/null +++ b/tests/integration/targets/nxos_vrf_interfaces/defaults/main.yaml @@ -0,0 +1,2 @@ +--- +testcase: "*" diff --git a/tests/integration/targets/nxos_vrf_interfaces/meta/main.yml b/tests/integration/targets/nxos_vrf_interfaces/meta/main.yml new file mode 100644 index 000000000..f504a6ab2 --- /dev/null +++ b/tests/integration/targets/nxos_vrf_interfaces/meta/main.yml @@ -0,0 +1,3 @@ +--- +dependencies: + - prepare_nxos_tests diff --git a/tests/integration/targets/nxos_vrf_interfaces/tasks/cli.yaml b/tests/integration/targets/nxos_vrf_interfaces/tasks/cli.yaml new file mode 100644 index 000000000..d3d521f2a --- /dev/null +++ b/tests/integration/targets/nxos_vrf_interfaces/tasks/cli.yaml @@ -0,0 +1,31 @@ +--- +- name: Collect common test cases + ansible.builtin.find: + paths: "{{ role_path }}/tests/common" + patterns: "{{ testcase }}.yaml" + connection: local + register: test_cases + +- name: Collect CLI test cases + ansible.builtin.find: + paths: "{{ role_path }}/tests/cli" + patterns: "{{ testcase }}.yaml" + connection: local + register: cli_cases + +- name: Set a fact for 'test_cases' + ansible.builtin.set_fact: + test_cases: + files: "{{ test_cases.files + cli_cases.files }}" + +- name: Set test_items + ansible.builtin.set_fact: + test_items: "{{ test_cases.files | map(attribute='path') | list }}" + +- name: Run test cases with connection network_cli + ansible.builtin.include_tasks: "{{ test_case_to_run }}" + with_items: "{{ test_items }}" + loop_control: + loop_var: test_case_to_run + vars: + ansible_connection: ansible.netcommon.network_cli diff --git a/tests/integration/targets/nxos_vrf_interfaces/tasks/main.yaml b/tests/integration/targets/nxos_vrf_interfaces/tasks/main.yaml new file mode 100644 index 000000000..c9e70304e --- /dev/null +++ b/tests/integration/targets/nxos_vrf_interfaces/tasks/main.yaml @@ -0,0 +1,12 @@ +--- +- name: Run the CLI and NX-API tests + block: + - name: Include the CLI tasks + ansible.builtin.include_tasks: cli.yaml + tags: + - cli + always: + - name: Include the NX-API tasks + ansible.builtin.include_tasks: nxapi.yaml + tags: + - nxapi diff --git a/tests/integration/targets/nxos_vrf_interfaces/tasks/nxapi.yaml b/tests/integration/targets/nxos_vrf_interfaces/tasks/nxapi.yaml new file mode 100644 index 000000000..5fec0f43b --- /dev/null +++ b/tests/integration/targets/nxos_vrf_interfaces/tasks/nxapi.yaml @@ -0,0 +1,31 @@ +--- +- name: Collect common test cases + ansible.builtin.find: + paths: "{{ role_path }}/tests/common" + patterns: "{{ testcase }}.yaml" + connection: local + register: test_cases + +- name: Collect NX-API test cases + ansible.builtin.find: + paths: "{{ role_path }}/tests/nxapi" + patterns: "{{ testcase }}.yaml" + connection: local + register: nxapi_cases + +- name: Set a fact for 'test_cases' + ansible.builtin.set_fact: + test_cases: + files: "{{ test_cases.files + nxapi_cases.files }}" + +- name: Set test_items + ansible.builtin.set_fact: + test_items: "{{ test_cases.files | map(attribute='path') | list }}" + +- name: Run test cases with connection httpapi + ansible.builtin.include_tasks: "{{ test_case_to_run }}" + with_items: "{{ test_items }}" + loop_control: + loop_var: test_case_to_run + vars: + ansible_connection: ansible.netcommon.httpapi diff --git a/tests/integration/targets/nxos_vrf_interfaces/tests/common/_parsed.cfg b/tests/integration/targets/nxos_vrf_interfaces/tests/common/_parsed.cfg new file mode 100644 index 000000000..5c20d514b --- /dev/null +++ b/tests/integration/targets/nxos_vrf_interfaces/tests/common/_parsed.cfg @@ -0,0 +1,7 @@ +interface Ethernet1/2 + no switchport + vrf member VRF1 +interface Ethernet1/6 + no switchport + speed 1000 + vrf member TEST_VRF diff --git a/tests/integration/targets/nxos_vrf_interfaces/tests/common/_populate_config.yaml b/tests/integration/targets/nxos_vrf_interfaces/tests/common/_populate_config.yaml new file mode 100644 index 000000000..17cc5ddbe --- /dev/null +++ b/tests/integration/targets/nxos_vrf_interfaces/tests/common/_populate_config.yaml @@ -0,0 +1,11 @@ +--- +- name: Populate with simple overridden + cisco.nxos.nxos_vrf_interfaces: + state: overridden + config: + - name: Ethernet1/2 + vrf_name: test + - name: Ethernet1/6 + vrf_name: test2 + vars: + ansible_connection: ansible.netcommon.network_cli diff --git a/tests/integration/targets/nxos_vrf_interfaces/tests/common/_remove_config.yaml b/tests/integration/targets/nxos_vrf_interfaces/tests/common/_remove_config.yaml new file mode 100644 index 000000000..a76e3c679 --- /dev/null +++ b/tests/integration/targets/nxos_vrf_interfaces/tests/common/_remove_config.yaml @@ -0,0 +1,9 @@ +--- +- name: Override existing running configuration + cisco.nxos.nxos_vrf_interfaces: + config: + - name: Ethernet1/2 + - name: Ethernet1/6 + state: overridden + vars: + ansible_connection: ansible.netcommon.network_cli diff --git a/tests/integration/targets/nxos_vrf_interfaces/tests/common/deleted.yaml b/tests/integration/targets/nxos_vrf_interfaces/tests/common/deleted.yaml new file mode 100644 index 000000000..41a695b1a --- /dev/null +++ b/tests/integration/targets/nxos_vrf_interfaces/tests/common/deleted.yaml @@ -0,0 +1,51 @@ +--- +- ansible.builtin.debug: + msg: Start Deleted integration state for nxos_vrf_interfaces ansible_connection={{ ansible_connection }} + +- ansible.builtin.include_tasks: _remove_config.yaml +- ansible.builtin.include_tasks: _populate_config.yaml + +- block: + - name: Delete provided VRF interfaces + register: result + cisco.nxos.nxos_vrf_interfaces: &id001 + config: + - name: Ethernet1/2 + vrf: test + state: deleted + + - name: Assert that correct set of commands were generated + ansible.builtin.assert: + that: + - "{{ deleted['commands'] | symmetric_difference(result['commands']) | length == 0 }}" + + - name: Delete provided VRF interfaces (idempotent) + register: result + cisco.nxos.nxos_vrf_interfaces: *id001 + - name: Assert that the previous task was idempotent + ansible.builtin.assert: + that: + - result.changed == false + + - ansible.builtin.include_tasks: _populate_config.yaml + + - name: Delete provided VRF interfaces without any configuration + register: result + cisco.nxos.nxos_vrf_interfaces: &id002 + state: deleted + + - name: Assert that correct set of commands were generated + ansible.builtin.assert: + that: + - "{{ deleted['commands'] | symmetric_difference(result['commands']) | length == 0 }}" + + - name: Delete provided VRF interfaces without any configuration (idempotent) + register: result + cisco.nxos.nxos_vrf_interfaces: *id002 + - name: Assert that the delete task was idempotent + ansible.builtin.assert: + that: + - result.changed == false + + always: + - ansible.builtin.include_tasks: _remove_config.yaml diff --git a/tests/integration/targets/nxos_vrf_interfaces/tests/common/empty_config.yaml b/tests/integration/targets/nxos_vrf_interfaces/tests/common/empty_config.yaml new file mode 100644 index 000000000..077b6d9dd --- /dev/null +++ b/tests/integration/targets/nxos_vrf_interfaces/tests/common/empty_config.yaml @@ -0,0 +1,61 @@ +--- +- ansible.builtin.debug: + msg: START nxos_vrf_interfaces empty_config integration tests on connection={{ ansible_connection }} + +- name: Merged with empty configuration should give appropriate error message + register: result + ignore_errors: true + cisco.nxos.nxos_vrf_interfaces: + config: + state: merged + +- ansible.builtin.assert: + that: + - result.msg == 'value of config parameter must not be empty for state merged' + +- name: Replaced with empty configuration should give appropriate error message + register: result + ignore_errors: true + cisco.nxos.nxos_vrf_interfaces: + config: + state: replaced + +- ansible.builtin.assert: + that: + - result.msg == 'value of config parameter must not be empty for state replaced' + +- name: Overridden with empty configuration should give appropriate error message + register: result + ignore_errors: true + cisco.nxos.nxos_vrf_interfaces: + config: + state: overridden + +- ansible.builtin.assert: + that: + - result.msg == 'value of config parameter must not be empty for state overridden' + +- name: Rendered with empty configuration should give appropriate error message + register: result + ignore_errors: true + cisco.nxos.nxos_vrf_interfaces: + config: + state: rendered + +- ansible.builtin.assert: + that: + - result.msg == 'value of config parameter must not be empty for state rendered' + +- name: Parsed with empty configuration should give appropriate error message + register: result + ignore_errors: true + cisco.nxos.nxos_vrf_interfaces: + running_config: + state: parsed + +- ansible.builtin.assert: + that: + - result.msg == 'value of running_config parameter must not be empty for state parsed' + +- ansible.builtin.debug: + msg: END nxos_vrf_interfaces empty_config integration tests on connection={{ ansible_connection }} diff --git a/tests/integration/targets/nxos_vrf_interfaces/tests/common/gathered.yaml b/tests/integration/targets/nxos_vrf_interfaces/tests/common/gathered.yaml new file mode 100644 index 000000000..2c96fe709 --- /dev/null +++ b/tests/integration/targets/nxos_vrf_interfaces/tests/common/gathered.yaml @@ -0,0 +1,22 @@ +--- +- name: START nxos_vrf_interfaces gathered integration tests + ansible.builtin.debug: + msg: START nxos_vrf_interfaces gathered integration tests on connection={{ ansible_connection }} + +- ansible.builtin.include_tasks: _populate_config.yaml + +- block: + - name: Gather the provided configuration + register: result + cisco.nxos.nxos_vrf_interfaces: + config: + state: gathered + + - name: Assert + ansible.builtin.assert: + that: + - not result.changed + - "{{ gathered['config'] | symmetric_difference(result['gathered']) |length == 0 }}" + + always: + - ansible.builtin.include_tasks: _remove_config.yaml diff --git a/tests/integration/targets/nxos_vrf_interfaces/tests/common/merged.yaml b/tests/integration/targets/nxos_vrf_interfaces/tests/common/merged.yaml new file mode 100644 index 000000000..3bec76054 --- /dev/null +++ b/tests/integration/targets/nxos_vrf_interfaces/tests/common/merged.yaml @@ -0,0 +1,43 @@ +--- +- ansible.builtin.debug: + msg: START Merged nxos_vrf_interfaces state for integration tests on connection={{ ansible_connection }} + +- ansible.builtin.include_tasks: _remove_config.yaml + +- block: + - name: Merge provided configuration with device configuration + register: result + cisco.nxos.nxos_vrf_interfaces: &id001 + config: + - name: Ethernet1/2 + vrf_name: test + - name: Ethernet1/6 + vrf_name: test2 + state: merged + + - name: Assert that correct set of commands were generated + ansible.builtin.assert: + that: + - "{{ merged['commands'] | symmetric_difference(result['commands']) | length == 0 }}" + + - name: Assert that before dicts are correctly generated + ansible.builtin.assert: + that: + - "{{ merged['before'] | symmetric_difference(result['before']) | length == 0 }}" + + - name: Assert that after dict is correctly generated + ansible.builtin.assert: + that: + - "{{ merged['after'] | symmetric_difference(result['after']) | length == 0 }}" + + - name: Merge provided configuration with device configuration (idempotent) + register: result + cisco.nxos.nxos_vrf_interfaces: *id001 + + - name: Assert that the previous task was idempotent + ansible.builtin.assert: + that: + - result['changed'] == false + + always: + - ansible.builtin.include_tasks: _remove_config.yaml diff --git a/tests/integration/targets/nxos_vrf_interfaces/tests/common/overridden.yaml b/tests/integration/targets/nxos_vrf_interfaces/tests/common/overridden.yaml new file mode 100644 index 000000000..039504dfd --- /dev/null +++ b/tests/integration/targets/nxos_vrf_interfaces/tests/common/overridden.yaml @@ -0,0 +1,45 @@ +--- +- ansible.builtin.debug: + msg: START Overridden nxos_vrf_interfaces state for integration tests on connection={{ ansible_connection }} + +- ansible.builtin.include_tasks: _populate_config.yaml + +- block: + - name: Override provided configuration with device configuration + register: result + cisco.nxos.nxos_vrf_interfaces: &id001 + config: + - name: Ethernet1/2 + vrf_name: VRF8 + - name: Ethernet1/6 + vrf_name: VRF9 + - name: Ethernet1/4 + vrf_name: vrf_C + state: overridden + + - name: Assert that correct set of commands were generated + ansible.builtin.assert: + that: + - "{{ overridden['commands'] | symmetric_difference(result['commands']) | length == 0 }}" + + - name: Assert that before dicts are correctly generated + ansible.builtin.assert: + that: + - overridden['before'] == result['before'] + + - name: Assert that after dict is correctly generated + ansible.builtin.assert: + that: + - overridden['after'] == result['after'] + + - name: Override provided configuration with device configuration (idempotent) + register: result + cisco.nxos.nxos_vrf_interfaces: *id001 + + - name: Assert that the previous task was idempotent + ansible.builtin.assert: + that: + - result['changed'] == false + + always: + - ansible.builtin.include_tasks: _remove_config.yaml diff --git a/tests/integration/targets/nxos_vrf_interfaces/tests/common/parsed.yaml b/tests/integration/targets/nxos_vrf_interfaces/tests/common/parsed.yaml new file mode 100644 index 000000000..ce0594a28 --- /dev/null +++ b/tests/integration/targets/nxos_vrf_interfaces/tests/common/parsed.yaml @@ -0,0 +1,14 @@ +--- +- ansible.builtin.debug: + msg: START nxos_vrf_interfaces parsed integration tests on connection={{ ansible_connection }} + +- name: Parse externally provided route-policy configuration + register: result + cisco.nxos.nxos_vrf_interfaces: + running_config: "{{ lookup('file', '_parsed.cfg') }}" + state: parsed + +- name: Assert that configuration was correctly parsed + ansible.builtin.assert: + that: + - parsed['after'] == result['parsed'] diff --git a/tests/integration/targets/nxos_vrf_interfaces/tests/common/rendered.yaml b/tests/integration/targets/nxos_vrf_interfaces/tests/common/rendered.yaml new file mode 100644 index 000000000..5812ce24c --- /dev/null +++ b/tests/integration/targets/nxos_vrf_interfaces/tests/common/rendered.yaml @@ -0,0 +1,20 @@ +--- +- ansible.builtin.debug: + msg: START nxos_vrf_interfaces rendered integration tests on connection={{ ansible_connection }} + +- ansible.builtin.include_tasks: _remove_config.yaml + +- name: Render route-policy configuration + register: result + cisco.nxos.nxos_vrf_interfaces: + state: rendered + config: + - name: Ethernet1/2 + vrf_name: test + - name: Ethernet1/6 + vrf_name: test2 + +- name: Assert that correct set of commands were rendered + ansible.builtin.assert: + that: + - merged['commands'] == result['rendered'] diff --git a/tests/integration/targets/nxos_vrf_interfaces/tests/common/replaced.yaml b/tests/integration/targets/nxos_vrf_interfaces/tests/common/replaced.yaml new file mode 100644 index 000000000..bc683f9ab --- /dev/null +++ b/tests/integration/targets/nxos_vrf_interfaces/tests/common/replaced.yaml @@ -0,0 +1,42 @@ +--- +- ansible.builtin.debug: + msg: START Replaced nxos_vrf_interfaces state for integration tests on connection={{ ansible_connection }} + +- ansible.builtin.include_tasks: _remove_config.yaml +- ansible.builtin.include_tasks: _populate_config.yaml + +- block: + - name: Replace provided VRF interfaces configuration + register: result + cisco.nxos.nxos_vrf_interfaces: &id001 + config: + - name: Ethernet1/2 + vrf_name: test2 + state: replaced + + - name: Assert that correct set of commands were generated + ansible.builtin.assert: + that: + - "{{ replaced['commands'] | symmetric_difference(result['commands']) | length == 0 }}" + + - name: Assert that before dicts are correctly generated + ansible.builtin.assert: + that: + - replaced['before'] == result['before'] + + - name: Assert that after dict is correctly generated + ansible.builtin.assert: + that: + - replaced['after'] == result['after'] + + - name: Replace provided VRF interfaces configuration (idempotent) + register: result + cisco.nxos.nxos_vrf_interfaces: *id001 + + - name: Assert that task was idempotent + ansible.builtin.assert: + that: + - result['changed'] == false + + always: + - ansible.builtin.include_tasks: _remove_config.yaml diff --git a/tests/integration/targets/nxos_vrf_interfaces/tests/common/rtt.yaml b/tests/integration/targets/nxos_vrf_interfaces/tests/common/rtt.yaml new file mode 100644 index 000000000..ebd6770c3 --- /dev/null +++ b/tests/integration/targets/nxos_vrf_interfaces/tests/common/rtt.yaml @@ -0,0 +1,51 @@ +--- +- ansible.builtin.debug: + msg: START nxos_vrf_interfaces round trip integration tests on connection={{ ansible_connection }} + +- ansible.builtin.include_tasks: _remove_config.yaml + +- block: + - name: Apply the provided configuration (base config) + register: base_config + cisco.nxos.nxos_vrf_interfaces: + config: + - name: Ethernet1/2 + - name: Ethernet1/6 + vrf_name: vrf_B + state: merged + + - name: Gather VRF interfaces facts + cisco.ios.ios_facts: + gather_subset: + - "!all" + - "!min" + gather_network_resources: + - vrf_interfaces + + - name: Apply the provided configuration (config to be reverted) + register: result + cisco.nxos.nxos_vrf_interfaces: + config: + - name: Ethernet1/2 + - name: Ethernet1/6 + vrf_name: vrf_C + state: overridden + + - ansible.builtin.assert: + that: + - result.changed == true + - result.commands|symmetric_difference(overridden.commands) == [] + + - name: Revert back to base configuration using facts round trip + register: revert + cisco.nxos.nxos_vrf_interfaces: + config: "{{ ansible_facts['network_resources']['vrf_interfaces'] }}" + state: overridden + + - ansible.builtin.assert: + that: + - revert.changed == true + - revert.commands|symmetric_difference(rtt.commands) == [] + + always: + - ansible.builtin.include_tasks: _remove_config.yaml diff --git a/tests/integration/targets/nxos_vrf_interfaces/vars/main.yaml b/tests/integration/targets/nxos_vrf_interfaces/vars/main.yaml new file mode 100644 index 000000000..780e1551f --- /dev/null +++ b/tests/integration/targets/nxos_vrf_interfaces/vars/main.yaml @@ -0,0 +1,95 @@ +--- +gathered: + config: + - name: "Ethernet1/1" + - name: "Ethernet1/2" + - name: "Ethernet1/3" + - name: "Ethernet1/4" + +merged: + commands: + - interface Ethernet1/2 + - vrf member test + - interface Ethernet1/6 + - vrf member test2 + after: + - name: "Ethernet1/2" + vrf_name: "test" + - name: "Ethernet1/6" + vrf_name: "test2" + before: + - name: "Ethernet1/1" + - name: "Ethernet1/2" + - name: "Ethernet1/3" + - name: "Ethernet1/4" + +overridden: + commands: + - interface GigabitEthernet2 + - no vrf forwarding vrf_B + - interface GigabitEthernet4 + - vrf forwarding vrf_C + after: + - name: "Loopback24" + - name: "GigabitEthernet1" + - name: "GigabitEthernet2" + - name: "GigabitEthernet3" + - name: "GigabitEthernet4" + vrf_name: "vrf_C" + before: + - name: "Ethernet1/1" + - name: "Ethernet1/2" + vrf_name: "vrf_B" + - name: "GigabitEthernet3" + - name: "GigabitEthernet4" + +parsed: + after: + - name: "Ethernet1/2" + vrf_name: "VRF1" + - name: "GigabitEthernet1/6" + vrf_name: "TEST_VRF" + +replaced: + commands: + - interface Ethernet1/2 + - vrf member test2 + - interface Ethernet1/6 + - vrf member test6 + before: + - name: "Ethernet1/1" + - name: "Ethernet1/2" + vrf_name: "test" + - name: "Ethernet1/3" + - name: "Ethernet1/4" + after: + - name: "Ethernet1/1" + - name: "Ethernet1/2" + vrf_name: "test2" + - name: "Ethernet1/3" + - name: "Ethernet1/4" + +deleted: + commands: + - interface GigabitEthernet2 + - no vrf forwarding vrf_B + before: + - name: "Loopback24" + - name: "GigabitEthernet1" + - name: "GigabitEthernet2" + vrf_name: "vrf_B" + - name: "GigabitEthernet3" + - name: "GigabitEthernet4" + after: + - name: "Loopback24" + - name: "GigabitEthernet1" + - name: "GigabitEthernet2" + - name: "GigabitEthernet3" + - name: "GigabitEthernet4" + +rtt: + commands: + - interface GigabitEthernet2 + - vrf forwarding vrf_B + - interface GigabitEthernet4 + - no vrf forwarding vrf_C From 1e56f2c9ab1ee74e1571a647f833debbc31575c7 Mon Sep 17 00:00:00 2001 From: Ruchi Pakhle Date: Wed, 11 Dec 2024 22:54:47 +0530 Subject: [PATCH 5/6] add unit tests --- .../tests/common/_populate_config.yaml | 2 +- .../tests/common/deleted.yaml | 1 - .../tests/common/overridden.yaml | 2 - .../tests/common/replaced.yaml | 4 +- .../nxos_vrf_interfaces/tests/common/rtt.yaml | 8 +- .../nxos_vrf_interfaces/vars/main.yaml | 80 ++--- .../network/nxos/test_nxos_vrf_interfaces.py | 331 ++++++++++++++++++ 7 files changed, 381 insertions(+), 47 deletions(-) create mode 100644 tests/unit/modules/network/nxos/test_nxos_vrf_interfaces.py diff --git a/tests/integration/targets/nxos_vrf_interfaces/tests/common/_populate_config.yaml b/tests/integration/targets/nxos_vrf_interfaces/tests/common/_populate_config.yaml index 17cc5ddbe..c3dea6c15 100644 --- a/tests/integration/targets/nxos_vrf_interfaces/tests/common/_populate_config.yaml +++ b/tests/integration/targets/nxos_vrf_interfaces/tests/common/_populate_config.yaml @@ -1,5 +1,5 @@ --- -- name: Populate with simple overridden +- name: Merge provided configuration with device configuration cisco.nxos.nxos_vrf_interfaces: state: overridden config: diff --git a/tests/integration/targets/nxos_vrf_interfaces/tests/common/deleted.yaml b/tests/integration/targets/nxos_vrf_interfaces/tests/common/deleted.yaml index 41a695b1a..16338228f 100644 --- a/tests/integration/targets/nxos_vrf_interfaces/tests/common/deleted.yaml +++ b/tests/integration/targets/nxos_vrf_interfaces/tests/common/deleted.yaml @@ -11,7 +11,6 @@ cisco.nxos.nxos_vrf_interfaces: &id001 config: - name: Ethernet1/2 - vrf: test state: deleted - name: Assert that correct set of commands were generated diff --git a/tests/integration/targets/nxos_vrf_interfaces/tests/common/overridden.yaml b/tests/integration/targets/nxos_vrf_interfaces/tests/common/overridden.yaml index 039504dfd..01800c8d5 100644 --- a/tests/integration/targets/nxos_vrf_interfaces/tests/common/overridden.yaml +++ b/tests/integration/targets/nxos_vrf_interfaces/tests/common/overridden.yaml @@ -13,8 +13,6 @@ vrf_name: VRF8 - name: Ethernet1/6 vrf_name: VRF9 - - name: Ethernet1/4 - vrf_name: vrf_C state: overridden - name: Assert that correct set of commands were generated diff --git a/tests/integration/targets/nxos_vrf_interfaces/tests/common/replaced.yaml b/tests/integration/targets/nxos_vrf_interfaces/tests/common/replaced.yaml index bc683f9ab..3a3240a08 100644 --- a/tests/integration/targets/nxos_vrf_interfaces/tests/common/replaced.yaml +++ b/tests/integration/targets/nxos_vrf_interfaces/tests/common/replaced.yaml @@ -11,7 +11,9 @@ cisco.nxos.nxos_vrf_interfaces: &id001 config: - name: Ethernet1/2 - vrf_name: test2 + vrf_name: TEST_VRF2 + - name: Ethernet1/6 + vrf_name: TEST_VRF3 state: replaced - name: Assert that correct set of commands were generated diff --git a/tests/integration/targets/nxos_vrf_interfaces/tests/common/rtt.yaml b/tests/integration/targets/nxos_vrf_interfaces/tests/common/rtt.yaml index ebd6770c3..f5890e29a 100644 --- a/tests/integration/targets/nxos_vrf_interfaces/tests/common/rtt.yaml +++ b/tests/integration/targets/nxos_vrf_interfaces/tests/common/rtt.yaml @@ -9,13 +9,14 @@ register: base_config cisco.nxos.nxos_vrf_interfaces: config: + - name: Ethernet1/1 - name: Ethernet1/2 - name: Ethernet1/6 - vrf_name: vrf_B + vrf_name: test state: merged - name: Gather VRF interfaces facts - cisco.ios.ios_facts: + cisco.nxos.nxos_facts: gather_subset: - "!all" - "!min" @@ -26,9 +27,10 @@ register: result cisco.nxos.nxos_vrf_interfaces: config: + - name: Ethernet1/1 - name: Ethernet1/2 + vrf_name: test2 - name: Ethernet1/6 - vrf_name: vrf_C state: overridden - ansible.builtin.assert: diff --git a/tests/integration/targets/nxos_vrf_interfaces/vars/main.yaml b/tests/integration/targets/nxos_vrf_interfaces/vars/main.yaml index 780e1551f..be5c063ba 100644 --- a/tests/integration/targets/nxos_vrf_interfaces/vars/main.yaml +++ b/tests/integration/targets/nxos_vrf_interfaces/vars/main.yaml @@ -12,36 +12,38 @@ merged: - vrf member test - interface Ethernet1/6 - vrf member test2 - after: + before: + - name: "Ethernet1/1" - name: "Ethernet1/2" - vrf_name: "test" + - name: "Ethernet1/3" - name: "Ethernet1/6" - vrf_name: "test2" - before: + after: - name: "Ethernet1/1" - name: "Ethernet1/2" + vrf_name: "test" - name: "Ethernet1/3" - - name: "Ethernet1/4" + - name: "Ethernet1/6" + vrf_name: "test2" overridden: commands: - - interface GigabitEthernet2 - - no vrf forwarding vrf_B - - interface GigabitEthernet4 - - vrf forwarding vrf_C - after: - - name: "Loopback24" - - name: "GigabitEthernet1" - - name: "GigabitEthernet2" - - name: "GigabitEthernet3" - - name: "GigabitEthernet4" - vrf_name: "vrf_C" + - interface Ethernet1/2 + - vrf member VRF8 + - interface Ethernet1/6 + - vrf member VRF9 before: - name: "Ethernet1/1" - name: "Ethernet1/2" vrf_name: "vrf_B" - - name: "GigabitEthernet3" - - name: "GigabitEthernet4" + - name: "Ethernet1/3" + - name: "Ethernet1/6" + after: + - name: "Ethernet1/1" + - name: "Ethernet1/2" + vrf_name: "VRF8" + - name: "Ethernet1/3" + - name: "Ethernet1/6" + vrf_name: "VRF9" parsed: after: @@ -53,43 +55,43 @@ parsed: replaced: commands: - interface Ethernet1/2 - - vrf member test2 + - vrf member TEST_VRF2 - interface Ethernet1/6 - - vrf member test6 + - vrf member TEST_VRF3 before: - name: "Ethernet1/1" - name: "Ethernet1/2" vrf_name: "test" - name: "Ethernet1/3" - - name: "Ethernet1/4" + - name: "Ethernet1/6" + vrf_name: "test2" after: - name: "Ethernet1/1" - name: "Ethernet1/2" - vrf_name: "test2" + vrf_name: "TEST_VRF2" - name: "Ethernet1/3" - - name: "Ethernet1/4" + - name: "Ethernet1/6" + vrf_name: "TEST_VRF3" deleted: commands: - - interface GigabitEthernet2 - - no vrf forwarding vrf_B + - interface Ethernet1/2 + - no vrf member test before: - - name: "Loopback24" - - name: "GigabitEthernet1" - - name: "GigabitEthernet2" + - name: "Ethernet1/1" + - name: "Ethernet1/2" vrf_name: "vrf_B" - - name: "GigabitEthernet3" - - name: "GigabitEthernet4" + - name: "Ethernet1/3" + - name: "Ethernet1/4" after: - - name: "Loopback24" - - name: "GigabitEthernet1" - - name: "GigabitEthernet2" - - name: "GigabitEthernet3" - - name: "GigabitEthernet4" + - name: "Ethernet1/1" + - name: "Ethernet1/2" + - name: "Ethernet1/3" + - name: "Ethernet1/4" rtt: commands: - - interface GigabitEthernet2 - - vrf forwarding vrf_B - - interface GigabitEthernet4 - - no vrf forwarding vrf_C + - interface "Ethernet1/6" + - vrf member test + - interface Ethernet1/2 + - no vrf member test2 diff --git a/tests/unit/modules/network/nxos/test_nxos_vrf_interfaces.py b/tests/unit/modules/network/nxos/test_nxos_vrf_interfaces.py new file mode 100644 index 000000000..77ebc5f48 --- /dev/null +++ b/tests/unit/modules/network/nxos/test_nxos_vrf_interfaces.py @@ -0,0 +1,331 @@ +# (c) 2024 Red Hat Inc. +# +# This file is part of Ansible +# +# Ansible is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Ansible is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Ansible. If not, see . + +from __future__ import absolute_import, division, print_function + + +__metaclass__ = type +from textwrap import dedent +from unittest.mock import patch + +from ansible_collections.cisco.nxos.plugins.modules import nxos_vrf_interfaces +from .nxos_module import TestNxosModule, set_module_args + + +class TestNxosVrfInterfacesModule(TestNxosModule): + """Test the nxos_vrf_interfaces module.""" + module = nxos_vrf_interfaces + + def setUp(self): + """Set up for nxos_vrf_interfaces module tests""" + super(TestNxosVrfInterfacesModule, self).setUp() + + self.mock_get_resource_connection_facts = patch( + "ansible_collections.ansible.netcommon.plugins.module_utils.network.common.rm_base.resource_module_base." + "get_resource_connection", + ) + self.get_resource_connection_facts = self.mock_get_resource_connection_facts.start() + + self.mock_execute_show_command = patch( + "ansible_collections.cisco.nxos.plugins.module_utils.network.nxos.facts.vrf_interfaces.vrf_interfaces." + "Vrf_interfacesFacts.get_device_data", + ) + self.execute_show_command = self.mock_execute_show_command.start() + + def tearDown(self): + super(TestNxosVrfInterfacesModule, self).tearDown() + self.mock_get_resource_connection_facts.stop() + self.mock_execute_show_command.stop() + + def test_nxos_vrf_interfaces_merged_idempotent(self): + self.execute_show_command.return_value = dedent( + """\ + interface Ethernet1/1 + interface Ethernet1/2 + no switchport + vrf member test + interface Ethernet1/6 + no switchport + speed 1000 + vrf member test2 + """, + ) + set_module_args( + dict( + config=[ + {"name": "Ethernet1/1"}, + {"name": "Ethernet1/2", "vrf_name": "test"}, + {"name": "Ethernet1/6", "vrf_name": "test2"}, + ], + state="merged", + ), + ) + self.execute_module(changed=False, commands=[]) + + def test_nxos_vrf_interfaces_merged(self): + self.execute_show_command.return_value = dedent( + """\ + interface Ethernet1/1 + interface Ethernet1/2 + no switchport + interface Ethernet1/6 + no switchport + speed 1000 + """, + ) + set_module_args( + dict( + config=[ + {"name": "Ethernet1/1"}, + {"name": "Ethernet1/2", "vrf_name": "test"}, + {"name": "Ethernet1/6", "vrf_name": "test2"}, + ], + state="merged", + ), + ) + commands = [ + "interface Ethernet1/2", + "vrf member test", + "interface Ethernet1/6", + "vrf member test2", + ] + result = self.execute_module(changed=True) + self.assertEqual(sorted(result["commands"]), sorted(commands)) + + def test_nxos_vrf_interfaces_replaced(self): + self.execute_show_command.return_value = dedent( + """\ + interface Ethernet1/1 + interface Ethernet1/2 + no switchport + interface Ethernet1/6 + no switchport + speed 1000 + """, + ) + set_module_args( + dict( + config=[ + {"name": "Ethernet1/1"}, + {"name": "Ethernet1/2", "vrf_name": "VRF8"}, + {"name": "Ethernet1/6", "vrf_name": "VRF6"}, + ], + state="replaced", + ), + ) + commands = [ + "interface Ethernet1/2", + "vrf member VRF8", + "interface Ethernet1/6", + "vrf member VRF6", + ] + result = self.execute_module(changed=True) + self.assertEqual(sorted(result["commands"]), sorted(commands)) + + def test_nxos_vrf_interfaces_deleted(self): + self.execute_show_command.return_value = dedent( + """\ + interface Ethernet1/1 + interface Ethernet1/2 + no switchport + vrf member test + interface Ethernet1/6 + no switchport + vrf member test2 + speed 1000 + """, + ) + set_module_args( + dict( + config=[ + {"name": "Ethernet1/1"}, + {"name": "Ethernet1/2"}, + {"name": "Ethernet1/3"}, + {"name": "Ethernet1/6"}, + ], + state="replaced", + ), + ) + commands = [ + "interface Ethernet1/2", + "no vrf member test", + "interface Ethernet1/6", + "no vrf member test2", + ] + result = self.execute_module(changed=True) + self.assertEqual(sorted(result["commands"]), sorted(commands)) + + def test_nxos_vrf_interfaces_parsed(self): + set_module_args( + dict( + running_config=dedent( + """\ + interface Ethernet1/1 + interface Ethernet1/2 + no switchport + vrf member VRF1 + interface Ethernet1/6 + no switchport + speed 1000 + vrf member TEST_VRF + + """, + ), + state="parsed", + ), + ) + parsed_list = [ + {"name": "Ethernet1/1"}, + {"name": "Ethernet1/2", "vrf_name": "VRF1"}, + {"name": "Ethernet1/6", "vrf_name": "TEST_VRF"}, + ] + result = self.execute_module(changed=False) + + self.assertEqual(result["parsed"], parsed_list) + + def test_nxos_vrf_interfaces_overridden(self): + self.execute_show_command.return_value = dedent( + """\ + interface Ethernet1/1 + interface Ethernet1/2 + no switchport + vrf member VRF1 + interface Ethernet1/6 + no switchport + speed 1000 + vrf member TEST_VRF + """, + ) + set_module_args( + dict( + config=[ + {"name": "Ethernet1/1"}, + {"name": "Ethernet1/2", "vrf_name": "test"}, + {"name": "Ethernet1/6", "vrf_name": "test_vrf"}, + ], + state="replaced", + ), + ) + commands = [ + "interface Ethernet1/2", + "vrf member test", + "interface Ethernet1/6", + "vrf member test_vrf", + ] + result = self.execute_module(changed=True) + self.assertEqual(sorted(result["commands"]), sorted(commands)) + + def test_nxos_vrf_interfaces_replaced_idempotent(self): + self.execute_show_command.return_value = dedent( + """\ + interface Ethernet1/1 + interface Ethernet1/2 + no switchport + vrf member test_vrf1 + interface Ethernet1/6 + no switchport + speed 1000 + vrf member test_vrf2 + """, + ) + set_module_args( + dict( + config=[ + {"name": "Ethernet1/1"}, + {"name": "Ethernet1/2", "vrf_name": "test_vrf1"}, + {"name": "Ethernet1/6", "vrf_name": "test_vrf2"}, + ], + state="replaced", + ), + ) + result = self.execute_module(changed=False) + self.assertEqual(result["commands"], []) + + def test_nxos_vrf_interfaces_overridden_idempotent(self): + self.execute_show_command.return_value = dedent( + """\ + interface Ethernet1/1 + interface Ethernet1/2 + no switchport + vrf member VRF1 + interface Ethernet1/6 + no switchport + speed 1000 + vrf member TEST_VRF + """, + ) + set_module_args( + dict( + config=[ + {"name": "Ethernet1/1"}, + {"name": "Ethernet1/2", "vrf_name": "VRF1"}, + {"name": "Ethernet1/6", "vrf_name": "TEST_VRF"}, + ], + state="overridden", + ), + ) + result = self.execute_module(changed=False) + self.assertEqual(result["commands"], []) + + def test_nxos_vrf_interfaces_gathered(self): + self.execute_show_command.return_value = dedent( + """\ + interface Ethernet1/1 + interface Ethernet1/2 + no switchport + vrf member VRF1 + interface Ethernet1/3 + interface Ethernet1/4 + interface Ethernet1/5 + interface Ethernet1/6 + no switchport + speed 1000 + vrf member TEST_VRF + """, + ) + set_module_args(dict(state="gathered")) + gathered_list = [ + {"name": "Ethernet1/1"}, + {"name": "Ethernet1/2", "vrf_name": "VRF1"}, + {"name": "Ethernet1/3"}, + {"name": "Ethernet1/4"}, + {"name": "Ethernet1/5"}, + {"name": "Ethernet1/6", "vrf_name": "TEST_VRF"}, + ] + result = self.execute_module(changed=False) + self.assertEqual(result["gathered"], gathered_list) + + def test_nxos_vrf_interfaces_rendered(self): + self.execute_show_command.return_value = None + set_module_args( + dict( + config=[ + {"name": "Ethernet1/1"}, + {"name": "Ethernet1/2", "vrf_name": "test"}, + {"name": "Ethernet1/6", "vrf_name": "test2"}, + ], + state="rendered", + ), + ) + commands = [ + "interface Ethernet1/2", + "vrf member test", + "interface Ethernet1/6", + "vrf member test2", + ] + result = self.execute_module(changed=False) + self.assertEqual(sorted(result["rendered"]), sorted(commands)) From c87127444eab38b59f0df9f73f59a1f614ae9ed5 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Wed, 11 Dec 2024 17:27:53 +0000 Subject: [PATCH 6/6] chore: auto fixes from pre-commit.com hooks --- .../network/nxos/facts/vrf_interfaces/vrf_interfaces.py | 6 ++++-- tests/unit/modules/network/nxos/test_nxos_vrf_interfaces.py | 2 ++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/plugins/module_utils/network/nxos/facts/vrf_interfaces/vrf_interfaces.py b/plugins/module_utils/network/nxos/facts/vrf_interfaces/vrf_interfaces.py index 41155c0a5..71a2e1f6f 100644 --- a/plugins/module_utils/network/nxos/facts/vrf_interfaces/vrf_interfaces.py +++ b/plugins/module_utils/network/nxos/facts/vrf_interfaces/vrf_interfaces.py @@ -60,11 +60,13 @@ def populate_facts(self, connection, ansible_facts, data=None): params = utils.remove_empties( vrf_interfaces_parser.validate_config( - self.argument_spec, {"config": objs}, redact=True + self.argument_spec, + {"config": objs}, + redact=True, ), ) facts["vrf_interfaces"] = params.get("config", []) - ansible_facts['ansible_network_resources'].update(facts) + ansible_facts["ansible_network_resources"].update(facts) return ansible_facts diff --git a/tests/unit/modules/network/nxos/test_nxos_vrf_interfaces.py b/tests/unit/modules/network/nxos/test_nxos_vrf_interfaces.py index 77ebc5f48..a9bb8860a 100644 --- a/tests/unit/modules/network/nxos/test_nxos_vrf_interfaces.py +++ b/tests/unit/modules/network/nxos/test_nxos_vrf_interfaces.py @@ -23,11 +23,13 @@ from unittest.mock import patch from ansible_collections.cisco.nxos.plugins.modules import nxos_vrf_interfaces + from .nxos_module import TestNxosModule, set_module_args class TestNxosVrfInterfacesModule(TestNxosModule): """Test the nxos_vrf_interfaces module.""" + module = nxos_vrf_interfaces def setUp(self):