From f9d31a3aaae6f72eb3c10b65e79349c92344a0b1 Mon Sep 17 00:00:00 2001 From: AAYUSH ANAND Date: Thu, 7 Nov 2024 20:18:56 +0530 Subject: [PATCH 1/2] vrf_interface module added --- plugins/module_utils/common/__init__.py | 0 .../ios/argspec/vrf_interface/__init__.py | 0 .../argspec/vrf_interface/vrf_interface.py | 58 +++++++ .../ios/config/vrf_interface/__init__.py | 0 .../ios/config/vrf_interface/vrf_interface.py | 97 +++++++++++ .../ios/facts/vrf_interface/__init__.py | 0 .../ios/facts/vrf_interface/vrf_interface.py | 67 ++++++++ .../network/ios/rm_templates/vrf_interface.py | 50 ++++++ plugins/modules/ios_vrf_interface.py | 154 ++++++++++++++++++ 9 files changed, 426 insertions(+) create mode 100644 plugins/module_utils/common/__init__.py create mode 100644 plugins/module_utils/network/ios/argspec/vrf_interface/__init__.py create mode 100644 plugins/module_utils/network/ios/argspec/vrf_interface/vrf_interface.py create mode 100644 plugins/module_utils/network/ios/config/vrf_interface/__init__.py create mode 100644 plugins/module_utils/network/ios/config/vrf_interface/vrf_interface.py create mode 100644 plugins/module_utils/network/ios/facts/vrf_interface/__init__.py create mode 100644 plugins/module_utils/network/ios/facts/vrf_interface/vrf_interface.py create mode 100644 plugins/module_utils/network/ios/rm_templates/vrf_interface.py create mode 100644 plugins/modules/ios_vrf_interface.py diff --git a/plugins/module_utils/common/__init__.py b/plugins/module_utils/common/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/plugins/module_utils/network/ios/argspec/vrf_interface/__init__.py b/plugins/module_utils/network/ios/argspec/vrf_interface/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/plugins/module_utils/network/ios/argspec/vrf_interface/vrf_interface.py b/plugins/module_utils/network/ios/argspec/vrf_interface/vrf_interface.py new file mode 100644 index 000000000..a20276bf4 --- /dev/null +++ b/plugins/module_utils/network/ios/argspec/vrf_interface/vrf_interface.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 ios_vrf_interface module +""" + + +class Vrf_interfaceArgs(object): # pylint: disable=R0903 + """The arg spec for the ios_vrf_interface module + """ + + argument_spec = { + "config": { + "type": "list", + "elements": "dict", + "options": { + "name": {"type": "str", "required": True}, + "vrf": {"type": "str"}, + }, + }, + "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/ios/config/vrf_interface/__init__.py b/plugins/module_utils/network/ios/config/vrf_interface/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/plugins/module_utils/network/ios/config/vrf_interface/vrf_interface.py b/plugins/module_utils/network/ios/config/vrf_interface/vrf_interface.py new file mode 100644 index 000000000..4020c3b73 --- /dev/null +++ b/plugins/module_utils/network/ios/config/vrf_interface/vrf_interface.py @@ -0,0 +1,97 @@ +# +# -*- 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 ios_vrf_interface 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 copy import deepcopy + +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.ios.plugins.module_utils.network.ios.facts.facts import ( + Facts, +) +from ansible_collections.cisco.ios.plugins.module_utils.network.ios.rm_templates.vrf_interface import ( + Vrf_interfaceTemplate, +) + + +class Vrf_interface(ResourceModule): + """ + The ios_vrf_interface config class + """ + + def __init__(self, module): + super(Vrf_interface, self).__init__( + empty_fact_val={}, + facts_module=Facts(module), + module=module, + resource="vrf_interface", + tmplt=Vrf_interfaceTemplate(), + ) + self.parsers = [ + ] + + 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_interface network resource. + """ + self.compare(parsers=self.parsers, want=want, have=have) diff --git a/plugins/module_utils/network/ios/facts/vrf_interface/__init__.py b/plugins/module_utils/network/ios/facts/vrf_interface/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/plugins/module_utils/network/ios/facts/vrf_interface/vrf_interface.py b/plugins/module_utils/network/ios/facts/vrf_interface/vrf_interface.py new file mode 100644 index 000000000..754fc7179 --- /dev/null +++ b/plugins/module_utils/network/ios/facts/vrf_interface/vrf_interface.py @@ -0,0 +1,67 @@ +# -*- 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 ios vrf_interface 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 copy import deepcopy + +from ansible.module_utils.six import iteritems +from ansible_collections.ansible.netcommon.plugins.module_utils.network.common import ( + utils, +) +from ansible_collections.cisco.ios.plugins.module_utils.network.ios.rm_templates.vrf_interface import ( + Vrf_interfaceTemplate, +) +from ansible_collections.cisco.ios.plugins.module_utils.network.ios.argspec.vrf_interface.vrf_interface import ( + Vrf_interfaceArgs, +) + +class Vrf_interfaceFacts(object): + """ The ios vrf_interface facts class + """ + + def __init__(self, module, subspec='config', options='options'): + self._module = module + self.argument_spec = Vrf_interfaceArgs.argument_spec + + def populate_facts(self, connection, ansible_facts, data=None): + """ Populate the facts for Vrf_interface 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 = connection.get() + + # parse native config using the Vrf_interface template + vrf_interface_parser = Vrf_interfaceTemplate(lines=data.splitlines(), module=self._module) + objs = list(vrf_interface_parser.parse().values()) + + ansible_facts['ansible_network_resources'].pop('vrf_interface', None) + + params = utils.remove_empties( + vrf_interface_parser.validate_config(self.argument_spec, {"config": objs}, redact=True) + ) + + facts['vrf_interface'] = params['config'] + ansible_facts['ansible_network_resources'].update(facts) + + return ansible_facts diff --git a/plugins/module_utils/network/ios/rm_templates/vrf_interface.py b/plugins/module_utils/network/ios/rm_templates/vrf_interface.py new file mode 100644 index 000000000..d6e33e927 --- /dev/null +++ b/plugins/module_utils/network/ios/rm_templates/vrf_interface.py @@ -0,0 +1,50 @@ +# -*- 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_interface 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_interfaceTemplate(NetworkTemplate): + def __init__(self, lines=None, module=None): + super(Vrf_interfaceTemplate, self).__init__(lines=lines, tmplt=self, module=module) + + # fmt: off + PARSERS = [ + { + "name": "key_a", + "getval": re.compile( + r""" + ^key_a\s(?P\S+) + $""", re.VERBOSE), + "setval": "", + "result": { + }, + "shared": True + }, + { + "name": "key_b", + "getval": re.compile( + r""" + \s+key_b\s(?P\S+) + $""", re.VERBOSE), + "setval": "", + "result": { + }, + }, + ] + # fmt: on diff --git a/plugins/modules/ios_vrf_interface.py b/plugins/modules/ios_vrf_interface.py new file mode 100644 index 000000000..94380313c --- /dev/null +++ b/plugins/modules/ios_vrf_interface.py @@ -0,0 +1,154 @@ +#!/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 ios_vrf_interface +""" + +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + +DOCUMENTATION = """ +--- +module: ios_vrf_interfaces +extends_documentation_fragment: + - cisco.ios.ios +short_description: Manages VRF configuration on interfaces. +description: + - Manages Virtual Routing and Forwarding (VRF) configuration on interfaces of Cisco IOS devices. +version_added: "1.0.0" +author: "AAYUSH ANAND (@username)" +notes: + - Tested against Cisco IOS XE Version X.X + - VRF must exist before assigning to an interface + - When removing VRF from interface, associated IP addresses will be removed +options: + config: + description: A list of interface VRF configurations. + type: list + elements: dict + suboptions: + name: + description: + - Full name of the interface to be configured. + - Example - GigabitEthernet0/1, FastEthernet0/0 + type: str + required: true + vrf: + description: + - Name of the VRF to be configured on the interface. + - When configured, applies 'vrf forwarding ' 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 IOS device by executing + the command B(show running-config | section ^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. + 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.ios.plugins.module_utils.network.ios.argspec.vrf_interface.vrf_interface import ( + Vrf_interfaceArgs, +) +from ansible_collections.cisco.ios.plugins.module_utils.network.ios.config.vrf_interface.vrf_interface import ( + Vrf_interface, +) + + +def main(): + """ + Main entry point for module execution + + :returns: the result form module invocation + """ + module = AnsibleModule( + argument_spec=Vrf_interfaceArgs.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_interface(module).execute_module() + module.exit_json(**result) + + +if __name__ == "__main__": + main() From 7d8f40ff62bf2f5cf23b5458b97e74d4d5d98479 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Thu, 7 Nov 2024 14:53:57 +0000 Subject: [PATCH 2/2] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- README.md | 1 + .../argspec/vrf_interface/vrf_interface.py | 4 +-- .../ios/config/vrf_interface/vrf_interface.py | 33 +++++++++---------- .../ios/facts/vrf_interface/vrf_interface.py | 26 +++++++-------- .../network/ios/rm_templates/vrf_interface.py | 11 +++++-- plugins/modules/ios_vrf_interface.py | 2 ++ 6 files changed, 41 insertions(+), 36 deletions(-) diff --git a/README.md b/README.md index afb9d4302..58187e9ec 100644 --- a/README.md +++ b/README.md @@ -93,6 +93,7 @@ Name | Description [cisco.ios.ios_vlans](https://github.com/ansible-collections/cisco.ios/blob/main/docs/cisco.ios.ios_vlans_module.rst)|Resource module to configure VLANs. [cisco.ios.ios_vrf](https://github.com/ansible-collections/cisco.ios/blob/main/docs/cisco.ios.ios_vrf_module.rst)|Module to configure VRF definitions. [cisco.ios.ios_vrf_global](https://github.com/ansible-collections/cisco.ios/blob/main/docs/cisco.ios.ios_vrf_global_module.rst)|Resource module to configure global VRF definitions. +[cisco.ios.ios_vrf_interfaces](https://github.com/ansible-collections/cisco.ios/blob/main/docs/cisco.ios.ios_vrf_interfaces_module.rst)|Manages VRF configuration on interfaces. [cisco.ios.ios_vxlan_vtep](https://github.com/ansible-collections/cisco.ios/blob/main/docs/cisco.ios.ios_vxlan_vtep_module.rst)|Resource module to configure VXLAN VTEP interface. diff --git a/plugins/module_utils/network/ios/argspec/vrf_interface/vrf_interface.py b/plugins/module_utils/network/ios/argspec/vrf_interface/vrf_interface.py index a20276bf4..9d42f28d2 100644 --- a/plugins/module_utils/network/ios/argspec/vrf_interface/vrf_interface.py +++ b/plugins/module_utils/network/ios/argspec/vrf_interface/vrf_interface.py @@ -5,6 +5,7 @@ from __future__ import absolute_import, division, print_function + __metaclass__ = type ############################################# @@ -29,8 +30,7 @@ class Vrf_interfaceArgs(object): # pylint: disable=R0903 - """The arg spec for the ios_vrf_interface module - """ + """The arg spec for the ios_vrf_interface module""" argument_spec = { "config": { diff --git a/plugins/module_utils/network/ios/config/vrf_interface/vrf_interface.py b/plugins/module_utils/network/ios/config/vrf_interface/vrf_interface.py index 4020c3b73..126e0ae4e 100644 --- a/plugins/module_utils/network/ios/config/vrf_interface/vrf_interface.py +++ b/plugins/module_utils/network/ios/config/vrf_interface/vrf_interface.py @@ -7,6 +7,7 @@ from __future__ import absolute_import, division, print_function + __metaclass__ = type """ @@ -20,15 +21,14 @@ from copy import deepcopy 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.ios.plugins.module_utils.network.ios.facts.facts import ( - Facts, +from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.utils import ( + dict_merge, ) + +from ansible_collections.cisco.ios.plugins.module_utils.network.ios.facts.facts import Facts from ansible_collections.cisco.ios.plugins.module_utils.network.ios.rm_templates.vrf_interface import ( Vrf_interfaceTemplate, ) @@ -47,11 +47,10 @@ def __init__(self, module): resource="vrf_interface", tmplt=Vrf_interfaceTemplate(), ) - self.parsers = [ - ] + self.parsers = [] def execute_module(self): - """ Execute the module + """Execute the module :rtype: A dictionary :returns: The result from module execution @@ -62,11 +61,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 +73,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,8 +87,8 @@ 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_interface network resource. + populates the list of commands to be run by comparing + the `want` and `have` data with the `parsers` defined + for the Vrf_interface network resource. """ self.compare(parsers=self.parsers, want=want, have=have) diff --git a/plugins/module_utils/network/ios/facts/vrf_interface/vrf_interface.py b/plugins/module_utils/network/ios/facts/vrf_interface/vrf_interface.py index 754fc7179..2a3a705fc 100644 --- a/plugins/module_utils/network/ios/facts/vrf_interface/vrf_interface.py +++ b/plugins/module_utils/network/ios/facts/vrf_interface/vrf_interface.py @@ -5,6 +5,7 @@ from __future__ import absolute_import, division, print_function + __metaclass__ = type """ @@ -17,26 +18,25 @@ from copy import deepcopy from ansible.module_utils.six import iteritems -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.ios.plugins.module_utils.network.ios.argspec.vrf_interface.vrf_interface import ( + Vrf_interfaceArgs, ) from ansible_collections.cisco.ios.plugins.module_utils.network.ios.rm_templates.vrf_interface import ( Vrf_interfaceTemplate, ) -from ansible_collections.cisco.ios.plugins.module_utils.network.ios.argspec.vrf_interface.vrf_interface import ( - Vrf_interfaceArgs, -) + class Vrf_interfaceFacts(object): - """ The ios vrf_interface facts class - """ + """The ios vrf_interface 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_interfaceArgs.argument_spec def populate_facts(self, connection, ansible_facts, data=None): - """ Populate the facts for Vrf_interface network resource + """Populate the facts for Vrf_interface network resource :param connection: the device connection :param ansible_facts: Facts dictionary @@ -55,13 +55,13 @@ def populate_facts(self, connection, ansible_facts, data=None): vrf_interface_parser = Vrf_interfaceTemplate(lines=data.splitlines(), module=self._module) objs = list(vrf_interface_parser.parse().values()) - ansible_facts['ansible_network_resources'].pop('vrf_interface', None) + ansible_facts["ansible_network_resources"].pop("vrf_interface", None) params = utils.remove_empties( - vrf_interface_parser.validate_config(self.argument_spec, {"config": objs}, redact=True) + vrf_interface_parser.validate_config(self.argument_spec, {"config": objs}, redact=True), ) - facts['vrf_interface'] = params['config'] - ansible_facts['ansible_network_resources'].update(facts) + facts["vrf_interface"] = params["config"] + ansible_facts["ansible_network_resources"].update(facts) return ansible_facts diff --git a/plugins/module_utils/network/ios/rm_templates/vrf_interface.py b/plugins/module_utils/network/ios/rm_templates/vrf_interface.py index d6e33e927..65c1e8c76 100644 --- a/plugins/module_utils/network/ios/rm_templates/vrf_interface.py +++ b/plugins/module_utils/network/ios/rm_templates/vrf_interface.py @@ -5,6 +5,7 @@ from __future__ import absolute_import, division, print_function + __metaclass__ = type """ @@ -15,10 +16,12 @@ """ import re + from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.rm_base.network_template import ( NetworkTemplate, ) + class Vrf_interfaceTemplate(NetworkTemplate): def __init__(self, lines=None, module=None): super(Vrf_interfaceTemplate, self).__init__(lines=lines, tmplt=self, module=module) @@ -30,18 +33,20 @@ def __init__(self, lines=None, module=None): "getval": re.compile( r""" ^key_a\s(?P\S+) - $""", re.VERBOSE), + $""", re.VERBOSE, + ), "setval": "", "result": { }, - "shared": True + "shared": True, }, { "name": "key_b", "getval": re.compile( r""" \s+key_b\s(?P\S+) - $""", re.VERBOSE), + $""", re.VERBOSE, + ), "setval": "", "result": { }, diff --git a/plugins/modules/ios_vrf_interface.py b/plugins/modules/ios_vrf_interface.py index 94380313c..23ef4cc36 100644 --- a/plugins/modules/ios_vrf_interface.py +++ b/plugins/modules/ios_vrf_interface.py @@ -10,6 +10,7 @@ from __future__ import absolute_import, division, print_function + __metaclass__ = type DOCUMENTATION = """ @@ -119,6 +120,7 @@ """ from ansible.module_utils.basic import AnsibleModule + from ansible_collections.cisco.ios.plugins.module_utils.network.ios.argspec.vrf_interface.vrf_interface import ( Vrf_interfaceArgs, )