diff options
| author | Bradley A. Thornton <bthornto@thethorntons.net> | 2019-08-19 07:56:36 -0700 | 
|---|---|---|
| committer | Bradley A. Thornton <bthornto@thethorntons.net> | 2019-08-19 07:56:36 -0700 | 
| commit | 7d4127b40ce899b43180df68d84ec6adcda20c0e (patch) | |
| tree | b5d5a7a85b6aa288ea4d183e129d00d2b9b8d527 /plugins/module_utils/network | |
| parent | 3fabcd898a415a724048f445dfc35e29f895fe2e (diff) | |
| download | vyos.vyos-7d4127b40ce899b43180df68d84ec6adcda20c0e.tar.gz vyos.vyos-7d4127b40ce899b43180df68d84ec6adcda20c0e.zip | |
based on ansible/ansible 843a51628b49d7aaa1447616fe0fcdf6a4ec7b1a
Diffstat (limited to 'plugins/module_utils/network')
10 files changed, 457 insertions, 17 deletions
| diff --git a/plugins/module_utils/network/vyos/argspec/facts/facts.py b/plugins/module_utils/network/vyos/argspec/facts/facts.py index 624d2fdb..31b1aa9a 100644 --- a/plugins/module_utils/network/vyos/argspec/facts/facts.py +++ b/plugins/module_utils/network/vyos/argspec/facts/facts.py @@ -24,6 +24,8 @@ class FactsArgs(object):  # pylint: disable=R0903          "!l3_interfaces",          "lag_interfaces",          "!lag_interfaces", +        "lldp_global", +        "!lldp_global",      ]      argument_spec = { diff --git a/plugins/module_utils/network/vyos/argspec/lldp_global/__init__.py b/plugins/module_utils/network/vyos/argspec/lldp_global/__init__.py new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/plugins/module_utils/network/vyos/argspec/lldp_global/__init__.py diff --git a/plugins/module_utils/network/vyos/argspec/lldp_global/lldp_global.py b/plugins/module_utils/network/vyos/argspec/lldp_global/lldp_global.py new file mode 100644 index 00000000..84bbc00c --- /dev/null +++ b/plugins/module_utils/network/vyos/argspec/lldp_global/lldp_global.py @@ -0,0 +1,56 @@ +# Copyright 2019 Red Hat +# GNU General Public License v3.0+ +# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +############################################# +#                WARNING                    # +############################################# +# +# This file is auto generated by the resource +#   module builder playbook. +# +# Do not edit this file manually. +# +# Changes to this file will be over written +#   by the resource module builder. +# +# Changes should be made in the model used to +#   generate this file or in the resource module +#   builder template. +# +############################################# + +""" +The arg spec for the vyos_lldp_global module +""" +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + + +class Lldp_globalArgs(object):  # pylint: disable=R0903 +    """The arg spec for the vyos_lldp_global module +    """ + +    def __init__(self, **kwargs): +        pass + +    argument_spec = { +        "config": { +            "options": { +                "address": {"type": "str"}, +                "enable": {"type": "bool"}, +                "legacy_protocols": { +                    "choices": ["cdp", "edp", "fdp", "sonmp"], +                    "type": "list", +                }, +                "snmp": {"type": "str"}, +            }, +            "type": "dict", +        }, +        "state": { +            "choices": ["merged", "replaced", "deleted"], +            "default": "merged", +            "type": "str", +        }, +    }  # pylint: disable=C0301 diff --git a/plugins/module_utils/network/vyos/config/lldp_global/__init__.py b/plugins/module_utils/network/vyos/config/lldp_global/__init__.py new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/plugins/module_utils/network/vyos/config/lldp_global/__init__.py diff --git a/plugins/module_utils/network/vyos/config/lldp_global/lldp_global.py b/plugins/module_utils/network/vyos/config/lldp_global/lldp_global.py new file mode 100644 index 00000000..54606fab --- /dev/null +++ b/plugins/module_utils/network/vyos/config/lldp_global/lldp_global.py @@ -0,0 +1,248 @@ +# Copyright 2019 Red Hat +# GNU General Public License v3.0+ +# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +""" +The vyos_lldp_global class +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 it's desired end-state is +created +""" +from __future__ import absolute_import, division, print_function + +__metaclass__ = type +from ansible.module_utils.network.common.cfg.base import ConfigBase +from ansible.module_utils.network.common.utils import to_list, dict_diff +from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.facts.facts import ( +    Facts, +) +from ansible.module_utils.six import iteritems +from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.utils.utils import ( +    get_lst_diff_for_dicts, +    list_diff_have_only, +) + + +class Lldp_global(ConfigBase): +    """ +    The vyos_lldp_global class +    """ + +    gather_subset = ["!all", "!min"] + +    gather_network_resources = ["lldp_global"] + +    params = ["enable", "address", "snmp", "legacy_protocols"] + +    def __init__(self, module): +        super(Lldp_global, self).__init__(module) + +    def get_lldp_global_facts(self): +        """ Get the 'facts' (the current configuration) + +        :rtype: A dictionary +        :returns: The current configuration as a dictionary +        """ +        facts, _warnings = Facts(self._module).get_facts( +            self.gather_subset, self.gather_network_resources +        ) +        lldp_global_facts = facts["ansible_network_resources"].get( +            "lldp_global" +        ) +        if not lldp_global_facts: +            return {} +        return lldp_global_facts + +    def execute_module(self): +        """ Execute the module + +        :rtype: A dictionary +        :returns: The result from module execution +        """ +        result = {"changed": False} +        commands = list() +        warnings = list() + +        existing_lldp_global_facts = self.get_lldp_global_facts() +        commands.extend(self.set_config(existing_lldp_global_facts)) +        if commands: +            if not self._module.check_mode: +                self._connection.edit_config(commands) +            result["changed"] = True +        result["commands"] = commands + +        changed_lldp_global_facts = self.get_lldp_global_facts() + +        result["before"] = existing_lldp_global_facts +        if result["changed"]: +            result["after"] = changed_lldp_global_facts + +        result["warnings"] = warnings +        return result + +    def set_config(self, existing_lldp_global_facts): +        """ Collect the configuration from the args passed to the module, +            collect the current configuration (as a dict from facts) + +        :rtype: A list +        :returns: the commands necessary to migrate the current configuration +                  to the desired configuration +        """ +        want = self._module.params["config"] +        have = existing_lldp_global_facts +        resp = self.set_state(want, have) +        return to_list(resp) + +    def set_state(self, want, have): +        """ Select the appropriate function based on the state provided + +        :param want: the desired configuration as a dictionary +        :param have: the current configuration as a dictionary +        :rtype: A list +        :returns: the commands necessary to migrate the current configuration +                  to the desired configuration +        """ +        commands = [] +        state = self._module.params["state"] +        if state == "deleted": +            commands.extend(self._state_deleted(want=None, have=have)) +        elif state == "merged": +            commands.extend(self._state_merged(want=want, have=have)) +        elif state == "replaced": +            commands.extend(self._state_replaced(want=want, have=have)) +        return commands + +    def _state_replaced(self, want, have): +        """ The command generator when state is replaced + +        :rtype: A list +        :returns: the commands necessary to migrate the current configuration +                  to the desired configuration +        """ +        commands = [] +        if have: +            commands.extend(self._state_deleted(want, have)) +        commands.extend(self._state_merged(want, have)) +        return commands + +    def _state_merged(self, want, have): +        """ The command generator when state is merged + +        :rtype: A list +        :returns: the commands necessary to merge the provided into +                  the current configuration +        """ +        commands = [] +        commands.extend(self._render_updates(want, have)) +        return commands + +    def _state_deleted(self, want, have): +        """ The command generator when state is deleted + +        :rtype: A list +        :returns: the commands necessary to remove the current configuration +                  of the provided objects +        """ +        commands = [] +        if want: +            for item in Lldp_global.params: +                if item == "legacy_protocols": +                    commands.extend(self._update_lldp_protocols(want, have)) +                elif ( +                    have.get(item) and not want.get(item) and item != "enable" +                ): +                    commands.append(Lldp_global.del_cmd + item) +        elif have: +            for item in Lldp_global.params: +                if have.get(item): +                    if item == "legacy_protocols": +                        commands.append( +                            self._compute_command( +                                "legacy-protocols", remove=True +                            ) +                        ) +                    elif item == "address": +                        commands.append( +                            self._compute_command( +                                "management-address", remove=True +                            ) +                        ) +                    elif item == "snmp": +                        commands.append( +                            self._compute_command(item, remove=True) +                        ) + +        return commands + +    def _render_updates(self, want, have): +        commands = [] +        if have: +            temp_have_legacy_protos = have.pop("legacy_protocols", None) +        else: +            have = {} +            temp_want_legacy_protos = want.pop("legacy_protocols", None) + +        updates = dict_diff(have, want) + +        if have and temp_have_legacy_protos: +            have["legacy_protocols"] = temp_have_legacy_protos +        if not have and temp_want_legacy_protos: +            want["legacy_protocols"] = temp_want_legacy_protos + +        commands.extend(self._add_lldp_protocols(want, have)) + +        if updates: +            for key, value in iteritems(updates): +                if value: +                    if key == "enable": +                        commands.append(self._compute_command()) +                    elif key == "address": +                        commands.append( +                            self._compute_command( +                                "management-address", str(value) +                            ) +                        ) +                    elif key == "snmp": +                        if value == "disable": +                            commands.append( +                                self._compute_command(key, remove=True) +                            ) +                        else: +                            commands.append( +                                self._compute_command(key, str(value)) +                            ) +        return commands + +    def _add_lldp_protocols(self, want, have): +        commands = [] +        diff_members = get_lst_diff_for_dicts(want, have, "legacy_protocols") +        for key in diff_members: +            commands.append(self._compute_command("legacy-protocols", key)) +        return commands + +    def _update_lldp_protocols(self, want_item, have_item): +        commands = [] +        want_protocols = want_item.get("legacy_protocols") or [] +        have_protocols = have_item.get("legacy_protocols") or [] + +        members_diff = list_diff_have_only(want_protocols, have_protocols) +        if members_diff: +            for member in members_diff: +                commands.append( +                    self._compute_command( +                        "legacy-protocols", member, remove=True +                    ) +                ) +        return commands + +    def _compute_command(self, key=None, value=None, remove=False): +        if remove: +            cmd = "delete service lldp" +        else: +            cmd = "set service lldp" +        if key: +            cmd += " " + key + +        if value: +            cmd += " '" + value + "'" +        return cmd diff --git a/plugins/module_utils/network/vyos/facts/facts.py b/plugins/module_utils/network/vyos/facts/facts.py index 9c389c91..fb05f2ac 100644 --- a/plugins/module_utils/network/vyos/facts/facts.py +++ b/plugins/module_utils/network/vyos/facts/facts.py @@ -6,12 +6,9 @@ The facts class for vyos  this file validates each subset of facts and selectively  calls the appropriate facts gathering function  """ -  from __future__ import absolute_import, division, print_function  __metaclass__ = type - -  from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.argspec.facts.facts import (      FactsArgs,  ) @@ -25,6 +22,9 @@ from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.facts.l3_in  from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.facts.lag_interfaces.lag_interfaces import (      Lag_interfacesFacts,  ) +from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.facts.lldp_global.lldp_global import ( +    Lldp_globalFacts, +)  from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.facts.legacy.base import (      Default,      Neighbors, @@ -37,6 +37,7 @@ FACT_RESOURCE_SUBSETS = dict(      interfaces=InterfacesFacts,      l3_interfaces=L3_interfacesFacts,      lag_interfaces=Lag_interfacesFacts, +    lldp_global=Lldp_globalFacts,  ) @@ -71,7 +72,6 @@ class Facts(FactsBase):                  resource_facts_type,                  data,              ) -          if self.VALID_LEGACY_GATHER_SUBSETS:              self.get_network_legacy_facts(                  FACT_LEGACY_SUBSETS, legacy_facts_type diff --git a/plugins/module_utils/network/vyos/facts/legacy/base.py b/plugins/module_utils/network/vyos/facts/legacy/base.py index 34992b1b..dce93aae 100644 --- a/plugins/module_utils/network/vyos/facts/legacy/base.py +++ b/plugins/module_utils/network/vyos/facts/legacy/base.py @@ -12,8 +12,6 @@ based on the configuration.  from __future__ import absolute_import, division, print_function  __metaclass__ = type - -  import platform  import re  from ansible.module_utils.network.vyos.vyos import ( diff --git a/plugins/module_utils/network/vyos/facts/lldp_global/__init__.py b/plugins/module_utils/network/vyos/facts/lldp_global/__init__.py new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/plugins/module_utils/network/vyos/facts/lldp_global/__init__.py diff --git a/plugins/module_utils/network/vyos/facts/lldp_global/lldp_global.py b/plugins/module_utils/network/vyos/facts/lldp_global/lldp_global.py new file mode 100644 index 00000000..89543932 --- /dev/null +++ b/plugins/module_utils/network/vyos/facts/lldp_global/lldp_global.py @@ -0,0 +1,114 @@ +# +# -*- coding: utf-8 -*- +# Copyright 2019 Red Hat +# GNU General Public License v3.0+ +# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +""" +The vyos lldp_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 __future__ import absolute_import, division, print_function + +__metaclass__ = type + +from re import findall, M +from copy import deepcopy + +from ansible.module_utils.network.common import utils +from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.argspec.lldp_global.lldp_global import ( +    Lldp_globalArgs, +) + + +class Lldp_globalFacts(object): +    """ The vyos lldp_global fact class +    """ + +    def __init__(self, module, subspec="config", options="options"): +        self._module = module +        self.argument_spec = Lldp_globalArgs.argument_spec +        spec = deepcopy(self.argument_spec) +        if subspec: +            if options: +                facts_argument_spec = spec[subspec][options] +            else: +                facts_argument_spec = spec[subspec] +        else: +            facts_argument_spec = spec + +        self.generated_spec = utils.generate_dict(facts_argument_spec) + +    def populate_facts(self, connection, ansible_facts, data=None): +        """ Populate the facts for lldp_global +        :param connection: the device connection +        :param ansible_facts: Facts dictionary +        :param data: previously collected conf +        :rtype: dictionary +        :returns: facts +        """ +        if not data: +            data = connection.get_config() + +        objs = {} +        lldp_output = findall(r"^set service lldp (\S+)", data, M) +        if lldp_output: +            for item in set(lldp_output): +                lldp_regex = r" %s .+$" % item +                cfg = findall(lldp_regex, data, M) +                obj = self.render_config(cfg) +                if obj: +                    objs.update(obj) +        lldp_service = findall(r"^set service (lldp)?('lldp')", data, M) +        if lldp_service or lldp_output: +            lldp_obj = {} +            lldp_obj["enable"] = True +            objs.update(lldp_obj) + +        facts = {} +        params = utils.validate_config(self.argument_spec, {"config": objs}) +        facts["lldp_global"] = utils.remove_empties(params["config"]) + +        ansible_facts["ansible_network_resources"].update(facts) + +        return ansible_facts + +    def render_config(self, conf): +        """ +         Render config as dictionary structure and delete keys +           from spec for null values +         :param spec: The facts tree, generated from the argspec +         :param conf: The configuration +         :rtype: dictionary +         :returns: The generated config +         """ +        protocol_conf = "\n".join( +            filter(lambda x: ("legacy-protocols" in x), conf) +        ) +        att_conf = "\n".join( +            filter(lambda x: ("legacy-protocols" not in x), conf) +        ) +        config = self.parse_attribs(["snmp", "address"], att_conf) +        config["legacy_protocols"] = self.parse_protocols(protocol_conf) +        return utils.remove_empties(config) + +    def parse_protocols(self, conf): +        protocol_support = None +        if conf: +            protocols = findall(r"^.*legacy-protocols (.+)", conf, M) +            if protocols: +                protocol_support = [] +                for protocol in protocols: +                    protocol_support.append(protocol.strip("'")) +        return protocol_support + +    def parse_attribs(self, attribs, conf): +        config = {} +        for item in attribs: +            value = utils.parse_conf_arg(conf, item) +            if value: +                config[item] = value.strip("'") +            else: +                config[item] = None +        return utils.remove_empties(config) diff --git a/plugins/module_utils/network/vyos/utils/utils.py b/plugins/module_utils/network/vyos/utils/utils.py index d6c11bdc..1968cccd 100644 --- a/plugins/module_utils/network/vyos/utils/utils.py +++ b/plugins/module_utils/network/vyos/utils/utils.py @@ -67,7 +67,33 @@ def diff_list_of_dicts(want, have):      return diff +def get_lst_diff_for_dicts(want, have, lst): +    """ +    This function generates a list containing values +    that are only in want and not in list in have dict +    :param want: dict object to want +    :param have: dict object to have +    :param lst: list the diff on +    :return: new list object with values which are only in want. +    """ +    if not have: +        diff = want.get(lst) or [] + +    else: +        want_elements = want.get(lst) or {} +        have_elements = have.get(lst) or {} +        diff = list_diff_want_only(want_elements, have_elements) +    return diff + +  def list_diff_have_only(want_list, have_list): +    """ +    This function generated the list containing values +    that are only in have list. +    :param want_list: +    :param have_list: +    :return: new list with values which are only in have list +    """      if have_list and not want_list:          diff = have_list      elif not have_list: @@ -82,6 +108,13 @@ def list_diff_have_only(want_list, have_list):  def list_diff_want_only(want_list, have_list): +    """ +    This function generated the list containing values +    that are only in want list. +    :param want_list: +    :param have_list: +    :return: new list with values which are only in want list +    """      if have_list and not want_list:          diff = None      elif not have_list: @@ -93,14 +126,3 @@ def list_diff_want_only(want_list, have_list):              if i in want_list and i not in have_list          ]      return diff - - -def get_lst_diff_for_dicts(want, have, lst): -    if not have: -        diff = want.get(lst) or [] - -    else: -        want_elements = want.get(lst) or {} -        have_elements = have.get(lst) or {} -        diff = list_diff_want_only(want_elements, have_elements) -    return diff | 
