diff --git a/docs/cisco.nxos.nxos_spanning_tree_global_module.rst b/docs/cisco.nxos.nxos_spanning_tree_global_module.rst new file mode 100644 index 000000000..e69de29bb diff --git a/plugins/cache/__init__.py b/plugins/cache/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/plugins/lookup/__init__.py b/plugins/lookup/__init__.py new file mode 100644 index 000000000..e69de29bb 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/nxos/argspec/spanning_tree_global/__init__.py b/plugins/module_utils/network/nxos/argspec/spanning_tree_global/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/plugins/module_utils/network/nxos/argspec/spanning_tree_global/spanning_tree_global.py b/plugins/module_utils/network/nxos/argspec/spanning_tree_global/spanning_tree_global.py new file mode 100644 index 000000000..0ecd94a36 --- /dev/null +++ b/plugins/module_utils/network/nxos/argspec/spanning_tree_global/spanning_tree_global.py @@ -0,0 +1,79 @@ +# -*- 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_spanning_tree_global module +""" + + +class Spanning_tree_globalArgs(object): # pylint: disable=R0903 + """The arg spec for the nxos_spanning_tree_global module + """ + + argument_spec = { + "config": { + "type": "dict", + "options": { + "bridge_assurance": {"type": "bool"}, + "bridge_domain": {"type": "str"}, + "fcoe": {"type": "bool"}, + "lc_issu": { + "type": "str", + "choices": ["auto", "disruptive", "non-disruptive"], + }, + "loopguard_default": {"type": "bool"}, + "mode": {"type": "str", "choices": ["mst", "rapid-pvst"]}, + "pathcost_method": {"type": "str", "choices": ["long", "short"]}, + "port_type": { + "type": "dict", + "mutually_exclusive": [["edge", "network", "default"]], + "options": { + "edge": { + "type": "str", + "choices": ["bpdufilter", "bpduguard", "default"], + }, + "network": {"type": "bool"}, + "default": {"type": "bool"}, + }, + }, + "vlan": {"type": "str"}, + }, + }, + "running_config": {"type": "str"}, + "state": { + "choices": [ + "merged", + "replaced", + "overridden", + "deleted", + "rendered", + "gathered", + "purged", + "parsed", + ], + "default": "merged", + "type": "str", + }, + } # pylint: disable=C0301 diff --git a/plugins/module_utils/network/nxos/config/spanning_tree_global/__init__.py b/plugins/module_utils/network/nxos/config/spanning_tree_global/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/plugins/module_utils/network/nxos/config/spanning_tree_global/spanning_tree_global.py b/plugins/module_utils/network/nxos/config/spanning_tree_global/spanning_tree_global.py new file mode 100644 index 000000000..533773294 --- /dev/null +++ b/plugins/module_utils/network/nxos/config/spanning_tree_global/spanning_tree_global.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 nxos_spanning_tree_global 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.nxos.nxos.plugins.module_utils.network.nxos.facts.facts import ( + Facts, +) +from ansible_collections.cisco.nxos.nxos.plugins.module_utils.network.nxos.rm_templates.spanning_tree_global import ( + Spanning_tree_globalTemplate, +) + + +class Spanning_tree_global(ResourceModule): + """ + The nxos_spanning_tree_global config class + """ + + def __init__(self, module): + super(Spanning_tree_global, self).__init__( + empty_fact_val={}, + facts_module=Facts(module), + module=module, + resource="spanning_tree_global", + tmplt=Spanning_tree_globalTemplate(), + ) + 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 Spanning_tree_global network resource. + """ + self.compare(parsers=self.parsers, want=want, have=have) diff --git a/plugins/module_utils/network/nxos/facts/spanning_tree_global/__init__.py b/plugins/module_utils/network/nxos/facts/spanning_tree_global/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/plugins/module_utils/network/nxos/facts/spanning_tree_global/spanning_tree_global.py b/plugins/module_utils/network/nxos/facts/spanning_tree_global/spanning_tree_global.py new file mode 100644 index 000000000..660374104 --- /dev/null +++ b/plugins/module_utils/network/nxos/facts/spanning_tree_global/spanning_tree_global.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 nxos spanning_tree_global 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.nxos.nxos.plugins.module_utils.network.nxos.rm_templates.spanning_tree_global import ( + Spanning_tree_globalTemplate, +) +from ansible_collections.cisco.nxos.nxos.plugins.module_utils.network.nxos.argspec.spanning_tree_global.spanning_tree_global import ( + Spanning_tree_globalArgs, +) + +class Spanning_tree_globalFacts(object): + """ The nxos spanning_tree_global facts class + """ + + def __init__(self, module, subspec='config', options='options'): + self._module = module + self.argument_spec = Spanning_tree_globalArgs.argument_spec + + def populate_facts(self, connection, ansible_facts, data=None): + """ Populate the facts for Spanning_tree_global 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 Spanning_tree_global template + spanning_tree_global_parser = Spanning_tree_globalTemplate(lines=data.splitlines(), module=self._module) + objs = list(spanning_tree_global_parser.parse().values()) + + ansible_facts['ansible_network_resources'].pop('spanning_tree_global', None) + + params = utils.remove_empties( + spanning_tree_global_parser.validate_config(self.argument_spec, {"config": objs}, redact=True) + ) + + facts['spanning_tree_global'] = params['config'] + ansible_facts['ansible_network_resources'].update(facts) + + return ansible_facts diff --git a/plugins/module_utils/network/nxos/rm_templates/spanning_tree_global.py b/plugins/module_utils/network/nxos/rm_templates/spanning_tree_global.py new file mode 100644 index 000000000..3c0b1aeff --- /dev/null +++ b/plugins/module_utils/network/nxos/rm_templates/spanning_tree_global.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 Spanning_tree_global 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 Spanning_tree_globalTemplate(NetworkTemplate): + def __init__(self, lines=None, module=None): + super(Spanning_tree_globalTemplate, 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/nxos_spanning_tree_global.py b/plugins/modules/nxos_spanning_tree_global.py new file mode 100644 index 000000000..3215af314 --- /dev/null +++ b/plugins/modules/nxos_spanning_tree_global.py @@ -0,0 +1,212 @@ +#!/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_spanning_tree_global +""" + +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + +DOCUMENTATION = """ +module: nxos_spanning_tree_global +extends_documentation_fragment: +- cisco.nxos.nxos +short_description: + - Resource module to configure spanning tree. +description: + - This module configures and manages the attributes of Spanning-tree on Cisco NXOS. +version_added: 6.0.3 +author: Vinay Mulugund (@roverflow) +notes: + - Tested against NX-OS 9.3.6. + - This module works with connection C(network_cli) and C(httpapi). + See U(https://docs.ansible.com/ansible/latest/network/user_guide/platform_nxos.html) +options: + config: + description: A dict of Spanning-tree options. + type: dict + suboptions: + bridge_assurance: + description: Enable bridge assurance. + type: bool + bridge_domain: + decsription: Bridge-Domain Spanning Trees range. + type: str + fcoe: + description: Enable STP for FCoE VLANs. + type: bool + lc_issu: + description: Configure Linecard ISSU type. + type: str + choices: + - auto + - disruptive + - non-disruptive + loopguard_default: + description: Spanning tree loopguard . + type: bool + mode: + description: Spanning tree mode. + type: str + choices: + - mst + - rapid-pvst + pathcost_method: + description: Spanning tree pathcost options. + type: str + choices: + - long + - short + port_type: + description: Spanning tree port type. + type: dict + mutually_exclusive: [["edge", "network", "default"]] + suboptions: + edge: + description: Enable edge port type. + type: str + choices: + - bpdufilter + - bpduguard + - default + network: + description: Enable network port type. + type: bool + default: + description: Enable default port type. + type: bool + vlan: + description: Spanning tree VLAN range. + 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 NXOS device by + executing the command B(show running-config | section ^spanning-tree). + - 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: + choices: + - merged + - replaced + - overridden + - deleted + - rendered + - gathered + - purged + - parsed + default: merged + 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. + - The state I(purged) negates virtual/logical interfaces that are specified in task + from running-config. + type: str +""" + +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.nxos.plugins.module_utils.network.nxos.argspec.spanning_tree_global.spanning_tree_global import ( + Spanning_tree_globalArgs, +) +from ansible_collections.cisco.nxos.nxos.plugins.module_utils.network.nxos.config.spanning_tree_global.spanning_tree_global import ( + Spanning_tree_global, +) + + +def main(): + """ + Main entry point for module execution + + :returns: the result form module invocation + """ + module = AnsibleModule( + argument_spec=Spanning_tree_globalArgs.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 = Spanning_tree_global(module).execute_module() + module.exit_json(**result) + + +if __name__ == "__main__": + main() diff --git a/plugins/plugin_utils/__init__.py b/plugins/plugin_utils/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/plugins/test/__init__.py b/plugins/test/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/tests/__init__.py b/tests/__init__.py new file mode 100644 index 000000000..e69de29bb