diff options
Diffstat (limited to 'plugins')
30 files changed, 1577 insertions, 338 deletions
| diff --git a/plugins/module_utils/network/vyos/argspec/facts/facts.py b/plugins/module_utils/network/vyos/argspec/facts/facts.py index fc9d438e..624d2fdb 100644 --- a/plugins/module_utils/network/vyos/argspec/facts/facts.py +++ b/plugins/module_utils/network/vyos/argspec/facts/facts.py @@ -4,8 +4,6 @@  """  The arg spec for the vyos facts module.  """ - -  from __future__ import absolute_import, division, print_function  __metaclass__ = type @@ -24,6 +22,8 @@ class FactsArgs(object):  # pylint: disable=R0903          "!interfaces",          "l3_interfaces",          "!l3_interfaces", +        "lag_interfaces", +        "!lag_interfaces",      ]      argument_spec = { diff --git a/plugins/module_utils/network/vyos/argspec/lag_interfaces/__init__.py b/plugins/module_utils/network/vyos/argspec/lag_interfaces/__init__.py new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/plugins/module_utils/network/vyos/argspec/lag_interfaces/__init__.py diff --git a/plugins/module_utils/network/vyos/argspec/lag_interfaces/lag_interfaces.py b/plugins/module_utils/network/vyos/argspec/lag_interfaces/lag_interfaces.py new file mode 100644 index 00000000..97c5d5a2 --- /dev/null +++ b/plugins/module_utils/network/vyos/argspec/lag_interfaces/lag_interfaces.py @@ -0,0 +1,80 @@ +# 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_lag_interfaces module +""" +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + + +class Lag_interfacesArgs(object):  # pylint: disable=R0903 +    """The arg spec for the vyos_lag_interfaces module +    """ + +    def __init__(self, **kwargs): +        pass + +    argument_spec = { +        "config": { +            "elements": "dict", +            "options": { +                "arp_monitor": { +                    "options": { +                        "interval": {"type": "int"}, +                        "target": {"type": "list"}, +                    }, +                    "type": "dict", +                }, +                "hash_policy": { +                    "choices": ["layer2", "layer2+3", "layer3+4"], +                    "type": "str", +                }, +                "members": { +                    "elements": "dict", +                    "options": {"member": {"type": "str"}}, +                    "type": "list", +                }, +                "mode": { +                    "choices": [ +                        "802.3ad", +                        "active-backup", +                        "broadcast", +                        "round-robin", +                        "transmit-load-balance", +                        "adaptive-load-balance", +                        "xor-hash", +                    ], +                    "type": "str", +                }, +                "name": {"required": True, "type": "str"}, +                "primary": {"type": "str"}, +            }, +            "type": "list", +        }, +        "state": { +            "choices": ["merged", "replaced", "overridden", "deleted"], +            "default": "merged", +            "type": "str", +        }, +    }  # pylint: disable=C0301 diff --git a/plugins/module_utils/network/vyos/config/interfaces/interfaces.py b/plugins/module_utils/network/vyos/config/interfaces/interfaces.py index adf61d78..e5724f52 100644 --- a/plugins/module_utils/network/vyos/config/interfaces/interfaces.py +++ b/plugins/module_utils/network/vyos/config/interfaces/interfaces.py @@ -25,7 +25,6 @@ from ansible.module_utils.six import iteritems  from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.facts.facts import (      Facts,  ) -  from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.utils.utils import (      search_obj_in_list,      get_interface_type, diff --git a/plugins/module_utils/network/vyos/config/l3_interfaces/l3_interfaces.py b/plugins/module_utils/network/vyos/config/l3_interfaces/l3_interfaces.py index a69db052..2bd04b69 100644 --- a/plugins/module_utils/network/vyos/config/l3_interfaces/l3_interfaces.py +++ b/plugins/module_utils/network/vyos/config/l3_interfaces/l3_interfaces.py @@ -23,7 +23,6 @@ from ansible.module_utils.six import iteritems  from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.facts.facts import (      Facts,  ) -  from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.utils.utils import (      search_obj_in_list,      get_interface_type, diff --git a/plugins/module_utils/network/vyos/config/lag_interfaces/__init__.py b/plugins/module_utils/network/vyos/config/lag_interfaces/__init__.py new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/plugins/module_utils/network/vyos/config/lag_interfaces/__init__.py diff --git a/plugins/module_utils/network/vyos/config/lag_interfaces/lag_interfaces.py b/plugins/module_utils/network/vyos/config/lag_interfaces/lag_interfaces.py new file mode 100644 index 00000000..44a8a62e --- /dev/null +++ b/plugins/module_utils/network/vyos/config/lag_interfaces/lag_interfaces.py @@ -0,0 +1,410 @@ +# Copyright 2019 Red Hat +# GNU General Public License v3.0+ +# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +""" +The vyos_lag_interfaces 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_collections.vyos.vyos.plugins.module_utils.network.vyos.facts.facts import ( +    Facts, +) +from ansible.module_utils.network.common.utils import to_list, dict_diff +from ansible.module_utils.six import iteritems +from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.utils.utils import ( +    search_obj_in_list, +    get_lst_diff_for_dicts, +    list_diff_want_only, +    list_diff_have_only, +) + + +class Lag_interfaces(ConfigBase): +    """ +    The vyos_lag_interfaces class +    """ + +    gather_subset = ["!all", "!min"] + +    gather_network_resources = ["lag_interfaces"] + +    params = [ +        "arp_monitor", +        "hash_policy", +        "members", +        "mode", +        "name", +        "primary", +    ] + +    def __init__(self, module): +        super(Lag_interfaces, self).__init__(module) + +    def get_lag_interfaces_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 +        ) +        lag_interfaces_facts = facts["ansible_network_resources"].get( +            "lag_interfaces" +        ) +        if not lag_interfaces_facts: +            return [] +        return lag_interfaces_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_lag_interfaces_facts = self.get_lag_interfaces_facts() +        commands.extend(self.set_config(existing_lag_interfaces_facts)) +        if commands: +            if self._module.check_mode: +                resp = self._connection.edit_config(commands, commit=False) +            else: +                resp = self._connection.edit_config(commands) +            result["changed"] = True + +        result["commands"] = commands + +        if self._module._diff: +            result["diff"] = resp["diff"] if result["changed"] else None + +        changed_lag_interfaces_facts = self.get_lag_interfaces_facts() + +        result["before"] = existing_lag_interfaces_facts +        if result["changed"]: +            result["after"] = changed_lag_interfaces_facts + +        result["warnings"] = warnings +        return result + +    def set_config(self, existing_lag_interfaces_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_lag_interfaces_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 == "overridden": +            commands.extend(self._state_overridden(want, have)) +        elif state == "deleted": +            if want: +                for want_item in want: +                    name = want_item["name"] +                    obj_in_have = search_obj_in_list(name, have) +                    commands.extend(self._state_deleted(obj_in_have)) +            else: +                for have_item in have: +                    commands.extend(self._state_deleted(have_item)) +        else: +            for want_item in want: +                name = want_item["name"] +                obj_in_have = search_obj_in_list(name, have) +                if state == "merged": +                    commands.extend(self._state_merged(want_item, obj_in_have)) +                elif state == "replaced": +                    commands.extend( +                        self._state_replaced(want_item, obj_in_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._render_del_commands(want, have)) +        commands.extend(self._state_merged(want, have)) +        return commands + +    def _state_overridden(self, want, have): +        """ The command generator when state is overridden + +        :rtype: A list +        :returns: the commands necessary to migrate the current configuration +                  to the desired configuration +        """ +        commands = [] +        for have_item in have: +            lag_name = have_item["name"] +            obj_in_want = search_obj_in_list(lag_name, want) +            if not obj_in_want: +                commands.extend(self._purge_attribs(have_item)) + +        for want_item in want: +            name = want_item["name"] +            obj_in_have = search_obj_in_list(name, have) +            commands.extend(self._state_replaced(want_item, obj_in_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 = [] +        if have: +            commands.extend(self._render_updates(want, have)) +        else: +            commands.extend(self._render_set_commands(want)) +        return commands + +    def _state_deleted(self, 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 have: +            commands.extend(self._purge_attribs(have)) +        return commands + +    def _render_updates(self, want, have): +        commands = [] + +        temp_have_members = have.pop("members", None) +        temp_want_members = want.pop("members", None) + +        updates = dict_diff(have, want) + +        if temp_have_members: +            have["members"] = temp_have_members +        if temp_want_members: +            want["members"] = temp_want_members + +        commands.extend(self._add_bond_members(want, have)) + +        if updates: +            for key, value in iteritems(updates): +                if value: +                    if key == "arp_monitor": +                        commands.extend( +                            self._add_arp_monitor(updates, key, want, have) +                        ) +                    else: +                        commands.append( +                            self._compute_command( +                                have["name"], key, str(value) +                            ) +                        ) +        return commands + +    def _render_set_commands(self, want): +        commands = [] +        have = [] + +        params = Lag_interfaces.params + +        for attrib in params: +            value = want[attrib] +            if value: +                if attrib == "arp_monitor": +                    commands.extend( +                        self._add_arp_monitor(want, attrib, want, have) +                    ) +                elif attrib == "members": +                    commands.extend(self._add_bond_members(want, have)) +                elif attrib != "name": +                    commands.append( +                        self._compute_command( +                            want["name"], attrib, value=str(value) +                        ) +                    ) +        return commands + +    def _purge_attribs(self, have): +        commands = [] +        for item in Lag_interfaces.params: +            if have.get(item): +                if item == "members": +                    commands.extend(self._delete_bond_members(have)) +                elif item != "name": +                    commands.append( +                        self._compute_command( +                            have["name"], attrib=item, remove=True +                        ) +                    ) +        return commands + +    def _render_del_commands(self, want, have): +        commands = [] + +        params = Lag_interfaces.params +        for attrib in params: +            if attrib == "members": +                commands.extend(self._update_bond_members(attrib, want, have)) +            elif attrib == "arp_monitor": +                commands.extend(self._update_arp_monitor(attrib, want, have)) +            elif have.get(attrib) and not want.get(attrib): +                commands.append( +                    self._compute_command(have["name"], attrib, remove=True) +                ) +        return commands + +    def _add_bond_members(self, want, have): +        commands = [] +        diff_members = get_lst_diff_for_dicts(want, have, "members") +        if diff_members: +            for key in diff_members: +                commands.append( +                    self._compute_command( +                        key["member"], +                        "bond-group", +                        want["name"], +                        type="ethernet", +                    ) +                ) +        return commands + +    def _add_arp_monitor(self, updates, key, want, have): +        commands = [] +        arp_monitor = updates.get(key) or {} +        diff_targets = self._get_arp_monitor_target_diff( +            want, have, key, "target" +        ) + +        if "interval" in arp_monitor: +            commands.append( +                self._compute_command( +                    key, "interval", str(arp_monitor["interval"]) +                ) +            ) +        if diff_targets: +            for target in diff_targets: +                commands.append(self._compute_commands(key, "target", target)) +        return commands + +    def _delete_bond_members(self, have): +        commands = [] +        for member in have["members"]: +            commands.append( +                self._compute_command( +                    member["member"], +                    "bond-group", +                    have["name"], +                    remove=True, +                    type="ethernet", +                ) +            ) +        return commands + +    def _update_arp_monitor(self, key, want, have): +        commands = [] +        want_arp_target = [] +        have_arp_target = [] +        want_arp_monitor = want.get(key) or {} +        have_arp_monitor = have.get(key) or {} +        del_cmd = "delete interface bonding " + have["name"] + +        if want_arp_monitor and "target" in want_arp_monitor: +            want_arp_target = want_arp_monitor["target"] + +        if have_arp_monitor and "target" in have_arp_monitor: +            have_arp_target = have_arp_monitor["target"] + +        if "interval" in have_arp_monitor and not want_arp_monitor: +            commands.append(del_cmd + " " + key + " interval") +        if "target" in have_arp_monitor: +            target_diff = list_diff_have_only(want_arp_target, have_arp_target) +            if target_diff: +                for target in target_diff: +                    commands.append(del_cmd + " " + key + " target " + target) + +        return commands + +    def _update_bond_members(self, key, want, have): +        commands = [] +        want_members = want.get(key) or [] +        have_members = have.get(key) or [] + +        members_diff = list_diff_have_only(want_members, have_members) +        if members_diff: +            for member in members_diff: +                commands.append( +                    self._compute_command( +                        member[key], +                        "bond-group", +                        have["name"], +                        False, +                        "ethernet", +                    ) +                ) +        return commands + +    def _get_arp_monitor_target_diff( +        self, want_list, have_list, dict_name, lst +    ): +        want_arp_target = [] +        have_arp_target = [] + +        want_arp_monitor = want_list.get(dict_name) or {} +        if want_arp_monitor and lst in want_arp_monitor: +            want_arp_target = want_arp_monitor[lst] + +        if not have_list: +            diff = want_arp_target +        else: +            have_arp_monitor = have_list.get(dict_name) or {} +            if have_arp_monitor and lst in have_arp_monitor: +                have_arp_target = have_arp_monitor[lst] + +            diff = list_diff_want_only(want_arp_target, have_arp_target) +        return diff + +    def _compute_command( +        self, key, attrib, value=None, remove=False, type="bonding" +    ): +        if remove: +            cmd = "delete interfaces " + type +        else: +            cmd = "set interfaces " + type +        cmd += " " + key +        if attrib == "arp_monitor": +            attrib = "arp-monitor" +        elif attrib == "hash_policy": +            attrib = "hash-policy" +        cmd += " " + attrib +        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 eae9489f..9c389c91 100644 --- a/plugins/module_utils/network/vyos/facts/facts.py +++ b/plugins/module_utils/network/vyos/facts/facts.py @@ -15,16 +15,16 @@ __metaclass__ = type  from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.argspec.facts.facts import (      FactsArgs,  ) -  from ansible.module_utils.network.common.facts.facts import FactsBase  from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.facts.interfaces.interfaces import (      InterfacesFacts,  ) -  from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.facts.l3_interfaces.l3_interfaces import (      L3_interfacesFacts,  ) - +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.legacy.base import (      Default,      Neighbors, @@ -34,7 +34,9 @@ from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.facts.legac  FACT_LEGACY_SUBSETS = dict(default=Default, neighbors=Neighbors, config=Config)  FACT_RESOURCE_SUBSETS = dict( -    interfaces=InterfacesFacts, l3_interfaces=L3_interfacesFacts +    interfaces=InterfacesFacts, +    l3_interfaces=L3_interfacesFacts, +    lag_interfaces=Lag_interfacesFacts,  ) diff --git a/plugins/module_utils/network/vyos/facts/lag_interfaces/__init__.py b/plugins/module_utils/network/vyos/facts/lag_interfaces/__init__.py new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/plugins/module_utils/network/vyos/facts/lag_interfaces/__init__.py diff --git a/plugins/module_utils/network/vyos/facts/lag_interfaces/lag_interfaces.py b/plugins/module_utils/network/vyos/facts/lag_interfaces/lag_interfaces.py new file mode 100644 index 00000000..6ae780f4 --- /dev/null +++ b/plugins/module_utils/network/vyos/facts/lag_interfaces/lag_interfaces.py @@ -0,0 +1,150 @@ +# +# -*- 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 lag_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 __future__ import absolute_import, division, print_function + +__metaclass__ = type +from re import findall, search, M +from copy import deepcopy + +from ansible.module_utils.network.common import utils +from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.argspec.lag_interfaces.lag_interfaces import ( +    Lag_interfacesArgs, +) + + +class Lag_interfacesFacts(object): +    """ The vyos lag_interfaces fact class +    """ + +    def __init__(self, module, subspec="config", options="options"): +        self._module = module +        self.argument_spec = Lag_interfacesArgs.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 lag_interfaces +        :param module: the module instance +        :param connection: the device connection +        :param data: previously collected conf +        :rtype: dictionary +        :returns: facts +        """ +        if not data: +            data = connection.get_config() + +        objs = [] +        lag_names = findall(r"^set interfaces bonding (\S+)", data, M) +        if lag_names: +            for lag in set(lag_names): +                lag_regex = r" %s .+$" % lag +                cfg = findall(lag_regex, data, M) +                obj = self.render_config(cfg) + +                output = connection.run_commands( +                    ["show interfaces bonding " + lag + " slaves"] +                ) +                lines = output[0].splitlines() +                members = [] +                member = {} +                if len(lines) > 1: +                    for line in lines[2:]: +                        splitted_line = line.split() + +                        if len(splitted_line) > 1: +                            member["member"] = splitted_line[0] +                            members.append(member) +                        else: +                            members = [] +                        member = {} +                obj["name"] = lag.strip("'") +                if members: +                    obj["members"] = members + +                if obj: +                    objs.append(obj) + +        facts = {} +        if objs: +            facts["lag_interfaces"] = [] +            params = utils.validate_config( +                self.argument_spec, {"config": objs} +            ) +            for cfg in params["config"]: +                facts["lag_interfaces"].append(utils.remove_empties(cfg)) + +        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 +        """ +        arp_monitor_conf = "\n".join( +            filter(lambda x: ("arp-monitor" in x), conf) +        ) +        hash_policy_conf = "\n".join( +            filter(lambda x: ("hash-policy" in x), conf) +        ) +        lag_conf = "\n".join(filter(lambda x: ("bond" in x), conf)) +        config = self.parse_attribs(["mode", "primary"], lag_conf) +        config["arp_monitor"] = self.parse_arp_monitor(arp_monitor_conf) +        config["hash_policy"] = self.parse_hash_policy(hash_policy_conf) + +        return utils.remove_empties(config) + +    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) + +    def parse_arp_monitor(self, conf): +        arp_monitor = None +        if conf: +            arp_monitor = {} +            target_list = [] +            interval = search(r"^.*arp-monitor interval (.+)", conf, M) +            targets = findall(r"^.*arp-monitor target '(.+)'", conf, M) +            if targets: +                for target in targets: +                    target_list.append(target) +                arp_monitor["target"] = target_list +            if interval: +                value = interval.group(1).strip("'") +                arp_monitor["interval"] = int(value) +        return arp_monitor + +    def parse_hash_policy(self, conf): +        hash_policy = None +        if conf: +            hash_policy = search(r"^.*hash-policy (.+)", conf, M) +            hash_policy = hash_policy.group(1).strip("'") +        return hash_policy diff --git a/plugins/module_utils/network/vyos/utils/utils.py b/plugins/module_utils/network/vyos/utils/utils.py index 5fd0da24..d6c11bdc 100644 --- a/plugins/module_utils/network/vyos/utils/utils.py +++ b/plugins/module_utils/network/vyos/utils/utils.py @@ -4,8 +4,6 @@  # (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)  # utils - -  from __future__ import absolute_import, division, print_function  __metaclass__ = type @@ -67,3 +65,42 @@ def diff_list_of_dicts(want, have):          diff.append(dict((x, y) for x, y in element))      return diff + + +def list_diff_have_only(want_list, have_list): +    if have_list and not want_list: +        diff = have_list +    elif not have_list: +        diff = None +    else: +        diff = [ +            i +            for i in have_list + want_list +            if i in have_list and i not in want_list +        ] +    return diff + + +def list_diff_want_only(want_list, have_list): +    if have_list and not want_list: +        diff = None +    elif not have_list: +        diff = want_list +    else: +        diff = [ +            i +            for i in have_list + want_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 diff --git a/plugins/modules/_vyos_interface.py b/plugins/modules/_vyos_interface.py index 51285746..71a98c5d 100644 --- a/plugins/modules/_vyos_interface.py +++ b/plugins/modules/_vyos_interface.py @@ -183,7 +183,6 @@ from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.vyos import      load_config,      get_config,  ) -  from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.vyos import (      vyos_argument_spec,  ) diff --git a/plugins/modules/_vyos_l3_interface.py b/plugins/modules/_vyos_l3_interface.py index a504e7c8..054d810f 100644 --- a/plugins/modules/_vyos_l3_interface.py +++ b/plugins/modules/_vyos_l3_interface.py @@ -110,7 +110,6 @@ from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.vyos import      load_config,      run_commands,  ) -  from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.vyos import (      vyos_argument_spec,  ) diff --git a/plugins/modules/_vyos_linkagg.py b/plugins/modules/_vyos_linkagg.py new file mode 100644 index 00000000..95fbae91 --- /dev/null +++ b/plugins/modules/_vyos_linkagg.py @@ -0,0 +1,317 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +# (c) 2017, Ansible by Red Hat, inc +# +# This file is part of Ansible by Red Hat +# +# 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 <http://www.gnu.org/licenses/>. +# + +ANSIBLE_METADATA = { +    "metadata_version": "1.1", +    "status": ["deprecated"], +    "supported_by": "network", +} + + +DOCUMENTATION = """ +--- +module: vyos_linkagg +version_added: "2.4" +author: "Ricardo Carrillo Cruz (@rcarrillocruz)" +short_description: Manage link aggregation groups on VyOS network devices +description: +  - This module provides declarative management of link aggregation groups +    on VyOS network devices. +deprecated: +  removed_in: '2.13' +  alternative: vyos_lag_interfaces +  why: Updated modules released with more functionality. +notes: +  - Tested against VYOS 1.1.7 +options: +  name: +    description: +      - Name of the link aggregation group. +    required: true +    type: str +  mode: +    description: +      - Mode of the link aggregation group. +    choices: ['802.3ad', 'active-backup', 'broadcast', +              'round-robin', 'transmit-load-balance', +              'adaptive-load-balance', 'xor-hash', 'on'] +    type: str +  members: +    description: +      - List of members of the link aggregation group. +    type: list +  aggregate: +    description: List of link aggregation definitions. +    type: list +  state: +    description: +      - State of the link aggregation group. +    default: present +    choices: ['present', 'absent', 'up', 'down'] +    type: str +extends_documentation_fragment: vyos +""" + +EXAMPLES = """ +- name: configure link aggregation group +  vyos_linkagg: +    name: bond0 +    members: +      - eth0 +      - eth1 + +- name: remove configuration +  vyos_linkagg: +    name: bond0 +    state: absent + +- name: Create aggregate of linkagg definitions +  vyos_linkagg: +    aggregate: +        - { name: bond0, members: [eth1] } +        - { name: bond1, members: [eth2] } + +- name: Remove aggregate of linkagg definitions +  vyos_linkagg: +    aggregate: +      - name: bond0 +      - name: bond1 +    state: absent +""" + +RETURN = """ +commands: +  description: The list of configuration mode commands to send to the device +  returned: always, except for the platforms that use Netconf transport to manage the device. +  type: list +  sample: +    - set interfaces bonding bond0 +    - set interfaces ethernet eth0 bond-group 'bond0' +    - set interfaces ethernet eth1 bond-group 'bond0' +""" +from copy import deepcopy + +from ansible.module_utils.basic import AnsibleModule +from ansible.module_utils.network.common.utils import remove_default_spec +from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.vyos import ( +    load_config, +    run_commands, +) +from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.vyos import ( +    vyos_argument_spec, +) + + +def search_obj_in_list(name, lst): +    for o in lst: +        if o["name"] == name: +            return o + +    return None + + +def map_obj_to_commands(updates, module): +    commands = list() +    want, have = updates + +    for w in want: +        name = w["name"] +        members = w.get("members") or [] +        mode = w["mode"] + +        if mode == "on": +            mode = "802.3ad" + +        state = w["state"] + +        obj_in_have = search_obj_in_list(name, have) + +        if state == "absent": +            if obj_in_have: +                for m in obj_in_have["members"]: +                    commands.append( +                        "delete interfaces ethernet " + m + " bond-group" +                    ) + +                commands.append("delete interfaces bonding " + name) +        else: +            if not obj_in_have: +                commands.append( +                    "set interfaces bonding " + name + " mode " + mode +                ) + +                for m in members: +                    commands.append( +                        "set interfaces ethernet " + m + " bond-group " + name +                    ) + +                if state == "down": +                    commands.append( +                        "set interfaces bonding " + name + " disable" +                    ) +            else: +                if mode != obj_in_have["mode"]: +                    commands.append( +                        "set interfaces bonding " + name + " mode " + mode +                    ) + +                missing_members = list( +                    set(members) - set(obj_in_have["members"]) +                ) +                for m in missing_members: +                    commands.append( +                        "set interfaces ethernet " + m + " bond-group " + name +                    ) + +                if state == "down" and obj_in_have["state"] == "up": +                    commands.append( +                        "set interfaces bonding " + name + " disable" +                    ) +                elif state == "up" and obj_in_have["state"] == "down": +                    commands.append( +                        "delete interfaces bonding " + name + " disable" +                    ) + +    return commands + + +def map_config_to_obj(module): +    obj = [] +    output = run_commands(module, ["show interfaces bonding slaves"]) +    lines = output[0].splitlines() + +    if len(lines) > 1: +        for line in lines[1:]: +            splitted_line = line.split() + +            name = splitted_line[0] +            mode = splitted_line[1] +            state = splitted_line[2] + +            if len(splitted_line) > 4: +                members = splitted_line[4:] +            else: +                members = [] + +            obj.append( +                { +                    "name": name, +                    "mode": mode, +                    "members": members, +                    "state": state, +                } +            ) + +    return obj + + +def map_params_to_obj(module): +    obj = [] +    aggregate = module.params.get("aggregate") +    if aggregate: +        for item in aggregate: +            for key in item: +                if item.get(key) is None: +                    item[key] = module.params[key] + +            obj.append(item.copy()) +    else: +        obj.append( +            { +                "name": module.params["name"], +                "mode": module.params["mode"], +                "members": module.params["members"], +                "state": module.params["state"], +            } +        ) + +    return obj + + +def main(): +    """ main entry point for module execution +    """ +    element_spec = dict( +        name=dict(), +        mode=dict( +            choices=[ +                "802.3ad", +                "active-backup", +                "broadcast", +                "round-robin", +                "transmit-load-balance", +                "adaptive-load-balance", +                "xor-hash", +                "on", +            ], +            default="802.3ad", +        ), +        members=dict(type="list"), +        state=dict( +            default="present", choices=["present", "absent", "up", "down"] +        ), +    ) + +    aggregate_spec = deepcopy(element_spec) +    aggregate_spec["name"] = dict(required=True) + +    # remove default in aggregate spec, to handle common arguments +    remove_default_spec(aggregate_spec) + +    argument_spec = dict( +        aggregate=dict(type="list", elements="dict", options=aggregate_spec) +    ) + +    argument_spec.update(element_spec) +    argument_spec.update(vyos_argument_spec) + +    required_one_of = [["name", "aggregate"]] +    mutually_exclusive = [["name", "aggregate"]] +    module = AnsibleModule( +        argument_spec=argument_spec, +        required_one_of=required_one_of, +        mutually_exclusive=mutually_exclusive, +        supports_check_mode=True, +    ) + +    warnings = list() + +    result = {"changed": False} + +    if warnings: +        result["warnings"] = warnings + +    want = map_params_to_obj(module) +    have = map_config_to_obj(module) + +    commands = map_obj_to_commands((want, have), module) +    result["commands"] = commands + +    if commands: +        commit = not module.check_mode +        load_config(module, commands, commit=commit) +        result["changed"] = True + +    module.exit_json(**result) + + +if __name__ == "__main__": +    main() diff --git a/plugins/modules/vyos_banner.py b/plugins/modules/vyos_banner.py index 447c174b..39801b55 100644 --- a/plugins/modules/vyos_banner.py +++ b/plugins/modules/vyos_banner.py @@ -92,7 +92,6 @@ from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.vyos import      get_config,      load_config,  ) -  from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.vyos import (      vyos_argument_spec,  ) diff --git a/plugins/modules/vyos_command.py b/plugins/modules/vyos_command.py index b812fae4..892e853a 100644 --- a/plugins/modules/vyos_command.py +++ b/plugins/modules/vyos_command.py @@ -150,7 +150,6 @@ from ansible.module_utils.network.common.utils import (  from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.vyos import (      run_commands,  ) -  from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.vyos import (      vyos_argument_spec,  ) diff --git a/plugins/modules/vyos_config.py b/plugins/modules/vyos_config.py index 29560632..9ffc654c 100644 --- a/plugins/modules/vyos_config.py +++ b/plugins/modules/vyos_config.py @@ -194,7 +194,6 @@ from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.vyos import      get_config,      run_commands,  ) -  from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.vyos import (      vyos_argument_spec,      get_connection, diff --git a/plugins/modules/vyos_facts.py b/plugins/modules/vyos_facts.py index 1fa52146..6ceb2343 100644 --- a/plugins/modules/vyos_facts.py +++ b/plugins/modules/vyos_facts.py @@ -29,6 +29,7 @@ description:  author:    - Nathaniel Case (@qalthos)    - Nilashish Chakraborty (@Nilashishc) +  - Rohit Thakur (@rohitthakur2590)  extends_documentation_fragment: vyos  notes:    - Tested against VyOS 1.1.8 @@ -53,7 +54,7 @@ options:          specific subset should not be collected.      required: false      version_added: "2.9" -    choices: ['all', 'interfaces', '!interfaces', 'l3_interfaces', '!l3_interfaces'] +    choices: ['all', 'interfaces', '!interfaces', 'l3_interfaces', '!l3_interfaces', 'lag_interfaces', '!lag_interfaces']  """  EXAMPLES = """ @@ -140,11 +141,9 @@ from ansible.module_utils.basic import AnsibleModule  from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.argspec.facts.facts import (      FactsArgs,  ) -  from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.facts.facts import (      Facts,  ) -  from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.vyos import (      vyos_argument_spec,  ) diff --git a/plugins/modules/vyos_interfaces.py b/plugins/modules/vyos_interfaces.py index ca61f4d6..bc179ed4 100644 --- a/plugins/modules/vyos_interfaces.py +++ b/plugins/modules/vyos_interfaces.py @@ -859,7 +859,6 @@ from ansible.module_utils.basic import AnsibleModule  from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.argspec.interfaces.interfaces import (      InterfacesArgs,  ) -  from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.config.interfaces.interfaces import (      Interfaces,  ) diff --git a/plugins/modules/vyos_l3_interfaces.py b/plugins/modules/vyos_l3_interfaces.py index 1a2e4536..25a57d30 100644 --- a/plugins/modules/vyos_l3_interfaces.py +++ b/plugins/modules/vyos_l3_interfaces.py @@ -355,7 +355,6 @@ from ansible.module_utils.basic import AnsibleModule  from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.argspec.l3_interfaces.l3_interfaces import (      L3_interfacesArgs,  ) -  from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.config.l3_interfaces.l3_interfaces import (      L3_interfaces,  ) diff --git a/plugins/modules/vyos_lag_interfaces.py b/plugins/modules/vyos_lag_interfaces.py new file mode 100644 index 00000000..9707f2e0 --- /dev/null +++ b/plugins/modules/vyos_lag_interfaces.py @@ -0,0 +1,570 @@ +#!/usr/bin/python +# -*- 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) + +############################################# +#                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 module file for vyos_lag_interfaces +""" + +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + +ANSIBLE_METADATA = { +    "metadata_version": "1.1", +    "status": ["preview"], +    "supported_by": "network", +} + +DOCUMENTATION = """ +--- +module: vyos_lag_interfaces +version_added: 2.9 +short_description: Manages attributes of link aggregation groups on VyOS network devices. +description: This module manages attributes of link aggregation groups on VyOS network devices. +notes: +  - Tested against VyOS 1.1.8 (helium). +  - This module works with connection C(network_cli). +author: Rohit Thakur (@rohitthakur2590) +options: +  config: +    description: A list of link aggregation group configurations. +    type: list +    suboptions: +      name: +        description: +          - Name of the link aggregation group (LAG) or bond. +        type: str +        required: True +      mode: +        description: +          - LAG or bond mode. +        type: str +        choices: +          - 802.3ad +          - active-backup +          - broadcast +          - round-robin +          - transmit-load-balance +          - adaptive-load-balance +          - xor-hash +      members: +        description: +          - List of member interfaces for the LAG (bond). +        type: list +        suboptions: +          member: +            description: +              - Name of the member interface. +            type: str +      primary: +        description: +          - Primary device interfaces for the LAG (bond). +        type: str +      hash_policy: +        description: +          - LAG or bonding transmit hash policy. +        type: str +        choices: +          - layer2 +          - layer2+3 +          - layer3+4 +      arp_monitor: +        description: +          - ARP Link monitoring parameters. +        type: dict +        suboptions: +          interval: +            description: +              - ARP link monitoring frequency in milliseconds. +            type: int +          target: +            description: +              -  IP address to use for ARP monitoring. +            type: list +  state: +    description: +      - The state the configuration should be left in. +    type: str +    choices: +    - merged +    - replaced +    - overridden +    - deleted +    default: merged + +""" +EXAMPLES = """ +# Using merged +# +# Before state: +# ------------- +# +# vyos@vyos:~$ show configuration  commands | grep bond +# set interfaces bonding bond2 +# set interfaces bonding bond3 +# +- name: Merge provided configuration with device configuration +  vyos_lag_interfaces: +    config: +      - name: bond2 +        mode: active-backup +        members: +         - member: eth2 +         - member: eth1 +        hash_policy: layer2 +        primary: eth2 + +      - name: 'bond3' +        mode: 'active-backup' +        hash_policy: 'layer2+3' +        members: +         - member: eth3 +        primary: 'eth3' +    state: merged +# +# +# ------------------------- +# Module Execution Result +# ------------------------- +# +#    "before": [ +#        { +#            "name": "bond2" +#        }, +#        { +#            "name": "bond3" +#        } +#    ], +# +# "commands": [ +#        "set interfaces bonding bond2 hash-policy 'layer2'", +#        "set interfaces bonding bond2 mode 'active-backup'", +#        "set interfaces ethernet eth2 bond-group bond2", +#        "set interfaces ethernet eth1 bond-group bond2", +#        "set interfaces bonding bond2 primary 'eth2'", +#        "set interfaces bonding bond3 hash-policy 'layer2+3'", +#        "set interfaces bonding bond3 mode 'active-backup'", +#        "set interfaces ethernet eth3 bond-group bond3", +#        "set interfaces bonding bond3 primary 'eth3'" +#    ] +# +#     "after": [ +#        { +#            "hash_policy": "layer2", +#            "members": [ +#                { +#                    "member": "eth1" +#                }, +#                { +#                    "member": "eth2" +#                } +#            ], +#            "mode": "active-backup", +#            "name": "bond2", +#            "primary": "eth2" +#        }, +#        { +#            "hash_policy": "layer2+3", +#            "members": [ +#                { +#                    "member": "eth3" +#                } +#            ], +#            "mode": "active-backup", +#            "name": "bond3", +#            "primary": "eth3" +#        } +#    ] +# +# After state: +# ------------- +# +# vyos@vyos:~$ show configuration  commands | grep bond +# set interfaces bonding bond2 hash-policy 'layer2' +# set interfaces bonding bond2 mode 'active-backup' +# set interfaces bonding bond2 primary 'eth2' +# set interfaces bonding bond3 hash-policy 'layer2+3' +# set interfaces bonding bond3 mode 'active-backup' +# set interfaces bonding bond3 primary 'eth3' +# set interfaces ethernet eth1 bond-group 'bond2' +# set interfaces ethernet eth2 bond-group 'bond2' +# set interfaces ethernet eth3 bond-group 'bond3' + + +# Using replaced +# +# Before state: +# ------------- +# +# vyos@vyos:~$ show configuration  commands | grep bond +# set interfaces bonding bond2 hash-policy 'layer2' +# set interfaces bonding bond2 mode 'active-backup' +# set interfaces bonding bond2 primary 'eth2' +# set interfaces bonding bond3 hash-policy 'layer2+3' +# set interfaces bonding bond3 mode 'active-backup' +# set interfaces bonding bond3 primary 'eth3' +# set interfaces ethernet eth1 bond-group 'bond2' +# set interfaces ethernet eth2 bond-group 'bond2' +# set interfaces ethernet eth3 bond-group 'bond3' +# +- name: Replace device configurations of listed LAGs with provided configurations +  vyos_lag_interfaces: +    config: +      - name: bond3 +        mode: '802.3ad' +        hash_policy: 'layer2' +        members: +         - member: eth3 +    state: replaced +# +# +# ------------------------- +# Module Execution Result +# ------------------------- +# +#    "before": [ +#        { +#            "hash_policy": "layer2", +#            "members": [ +#                { +#                    "member": "eth1" +#                }, +#                { +#                    "member": "eth2" +#                } +#            ], +#            "mode": "active-backup", +#            "name": "bond2", +#            "primary": "eth2" +#        }, +#        { +#            "hash_policy": "layer2+3", +#            "members": [ +#                { +#                    "member": "eth3" +#                } +#            ], +#            "mode": "active-backup", +#            "name": "bond3", +#            "primary": "eth3" +#        } +#    ], +# +# "commands": [ +#        "delete interfaces bonding bond3 primary", +#        "set interfaces bonding bond3 hash-policy 'layer2'", +#        "set interfaces bonding bond3 mode '802.3ad'" +#    ], +# +# "after": [ +#        { +#            "hash_policy": "layer2", +#            "members": [ +#                { +#                    "member": "eth1" +#                }, +#                { +#                    "member": "eth2" +#                } +#            ], +#            "mode": "active-backup", +#            "name": "bond2", +#            "primary": "eth2" +#        }, +#        { +#            "hash_policy": "layer2", +#            "members": [ +#                { +#                    "member": "eth3" +#                } +#            ], +#            "mode": "802.3ad", +#            "name": "bond3" +#        } +#    ], +# +# After state: +# ------------- +# +# vyos@vyos:~$ show configuration  commands | grep bond +# set interfaces bonding bond2 hash-policy 'layer2' +# set interfaces bonding bond2 mode 'active-backup' +# set interfaces bonding bond2 primary 'eth2' +# set interfaces bonding bond3 hash-policy 'layer2' +# set interfaces bonding bond3 mode '802.3ad' +# set interfaces ethernet eth1 bond-group 'bond2' +# set interfaces ethernet eth2 bond-group 'bond2' +# set interfaces ethernet eth3 bond-group 'bond3' + + +# Using overridden +# +# Before state +# -------------- +# +# vyos@vyos:~$ show configuration  commands | grep bond +# set interfaces bonding bond2 hash-policy 'layer2' +# set interfaces bonding bond2 mode 'active-backup' +# set interfaces bonding bond2 primary 'eth2' +# set interfaces bonding bond3 hash-policy 'layer2' +# set interfaces bonding bond3 mode '802.3ad' +# set interfaces ethernet eth1 bond-group 'bond2' +# set interfaces ethernet eth2 bond-group 'bond2' +# set interfaces ethernet eth3 bond-group 'bond3' +# +- name: Overrides all device configuration with provided configuration +  vyos_lag_interfaces: +    config: +      - name: bond3 +        mode: active-backup +        members: +         - member: eth1 +         - member: eth2 +         - member: eth3 +        primary: eth3 +        hash_policy: layer2 +    state: overridden +# +# +# ------------------------- +# Module Execution Result +# ------------------------- +# +#    "before": [ +#        { +#            "hash_policy": "layer2", +#            "members": [ +#                { +#                    "member": "eth1" +#                }, +#                { +#                    "member": "eth2" +#                } +#            ], +#            "mode": "active-backup", +#            "name": "bond2", +#            "primary": "eth2" +#        }, +#        { +#            "hash_policy": "layer2", +#            "members": [ +#                { +#                    "member": "eth3" +#                } +#            ], +#            "mode": "802.3ad", +#            "name": "bond3" +#        } +#    ], +# +#    "commands": [ +#        "delete interfaces bonding bond2 hash-policy", +#        "delete interfaces ethernet eth1 bond-group bond2", +#        "delete interfaces ethernet eth2 bond-group bond2", +#        "delete interfaces bonding bond2 mode", +#        "delete interfaces bonding bond2 primary", +#        "set interfaces bonding bond3 mode 'active-backup'", +#        "set interfaces ethernet eth1 bond-group bond3", +#        "set interfaces ethernet eth2 bond-group bond3", +#        "set interfaces bonding bond3 primary 'eth3'" +#    ], +# +# "after": [ +#        { +#            "name": "bond2" +#        }, +#        { +#            "hash_policy": "layer2", +#            "members": [ +#                { +#                    "member": "eth1" +#                }, +#                { +#                    "member": "eth2" +#                }, +#                { +#                    "member": "eth3" +#                } +#            ], +#            "mode": "active-backup", +#            "name": "bond3", +#            "primary": "eth3" +#        } +#    ], +# +# +# After state +# ------------ +# +# vyos@vyos:~$ show configuration  commands | grep bond +# set interfaces bonding bond2 +# set interfaces bonding bond3 hash-policy 'layer2' +# set interfaces bonding bond3 mode 'active-backup' +# set interfaces bonding bond3 primary 'eth3' +# set interfaces ethernet eth1 bond-group 'bond3' +# set interfaces ethernet eth2 bond-group 'bond3' +# set interfaces ethernet eth3 bond-group 'bond3' + + +# Using deleted +# +# Before state +# ------------- +# +# vyos@vyos:~$ show configuration  commands | grep bond +# set interfaces bonding bond2 hash-policy 'layer2' +# set interfaces bonding bond2 mode 'active-backup' +# set interfaces bonding bond2 primary 'eth2' +# set interfaces bonding bond3 hash-policy 'layer2+3' +# set interfaces bonding bond3 mode 'active-backup' +# set interfaces bonding bond3 primary 'eth3' +# set interfaces ethernet eth1 bond-group 'bond2' +# set interfaces ethernet eth2 bond-group 'bond2' +# set interfaces ethernet eth3 bond-group 'bond3' +# +- name: Delete LAG attributes of given interfaces (Note This won't delete the interface itself) +  vyos_lag_interfaces: +    config: +      - name: bond2 +      - name: bond3 +    state: deleted +# +# +# ------------------------ +# Module Execution Results +# ------------------------ +# +# "before": [ +#        { +#            "hash_policy": "layer2", +#            "members": [ +#                { +#                    "member": "eth1" +#                }, +#                { +#                    "member": "eth2" +#                } +#            ], +#            "mode": "active-backup", +#            "name": "bond2", +#            "primary": "eth2" +#        }, +#        { +#            "hash_policy": "layer2+3", +#            "members": [ +#                { +#                    "member": "eth3" +#                } +#            ], +#            "mode": "active-backup", +#            "name": "bond3", +#            "primary": "eth3" +#        } +#    ], +# "commands": [ +#        "delete interfaces bonding bond2 hash-policy", +#        "delete interfaces ethernet eth1 bond-group bond2", +#        "delete interfaces ethernet eth2 bond-group bond2", +#        "delete interfaces bonding bond2 mode", +#        "delete interfaces bonding bond2 primary", +#        "delete interfaces bonding bond3 hash-policy", +#        "delete interfaces ethernet eth3 bond-group bond3", +#        "delete interfaces bonding bond3 mode", +#        "delete interfaces bonding bond3 primary" +#    ], +# +# "after": [ +#        { +#            "name": "bond2" +#        }, +#        { +#            "name": "bond3" +#        } +#    ], +# +# After state +# ------------ +# vyos@vyos:~$ show configuration  commands | grep bond +# set interfaces bonding bond2 +# set interfaces bonding bond3 + + +""" +RETURN = """ +before: +  description: The configuration prior to the model invocation. +  returned: always +  type: list +  sample: > +    The configuration returned will always be in the same format +     of the parameters above. +after: +  description: The resulting configuration model invocation. +  returned: when changed +  type: list +  sample: > +    The configuration returned will always be in the same format +     of the parameters above. +commands: +  description: The set of commands pushed to the remote device. +  returned: always +  type: list +  sample: +    - 'set interfaces bonding bond2' +    - 'set interfaces bonding bond2 hash-policy layer2' +""" + + +from ansible.module_utils.basic import AnsibleModule +from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.argspec.lag_interfaces.lag_interfaces import ( +    Lag_interfacesArgs, +) +from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.config.lag_interfaces.lag_interfaces import ( +    Lag_interfaces, +) + + +def main(): +    """ +    Main entry point for module execution + +    :returns: the result form module invocation +    """ +    required_if = [ +        ("state", "merged", ("config",)), +        ("state", "replaced", ("config",)), +        ("state", "overridden", ("config",)), +    ] +    module = AnsibleModule( +        argument_spec=Lag_interfacesArgs.argument_spec, +        required_if=required_if, +        supports_check_mode=True, +    ) + +    result = Lag_interfaces(module).execute_module() +    module.exit_json(**result) + + +if __name__ == "__main__": +    main() diff --git a/plugins/modules/vyos_linkagg.py b/plugins/modules/vyos_linkagg.py index 2fc8d668..294bec1b 100644..120000 --- a/plugins/modules/vyos_linkagg.py +++ b/plugins/modules/vyos_linkagg.py @@ -1,309 +1 @@ -#!/usr/bin/python -# -*- coding: utf-8 -*- - -# (c) 2017, Ansible by Red Hat, inc -# -# This file is part of Ansible by Red Hat -# -# 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 <http://www.gnu.org/licenses/>. -# - -ANSIBLE_METADATA = { -    "metadata_version": "1.1", -    "status": ["preview"], -    "supported_by": "network", -} - - -DOCUMENTATION = """ ---- -module: vyos_linkagg -version_added: "2.4" -author: "Ricardo Carrillo Cruz (@rcarrillocruz)" -short_description: Manage link aggregation groups on VyOS network devices -description: -  - This module provides declarative management of link aggregation groups -    on VyOS network devices. -notes: -  - Tested against VYOS 1.1.7 -options: -  name: -    description: -      - Name of the link aggregation group. -    required: true -  mode: -    description: -      - Mode of the link aggregation group. -    choices: ['802.3ad', 'active-backup', 'broadcast', -              'round-robin', 'transmit-load-balance', -              'adaptive-load-balance', 'xor-hash', 'on'] -  members: -    description: -      - List of members of the link aggregation group. -  aggregate: -    description: List of link aggregation definitions. -  state: -    description: -      - State of the link aggregation group. -    default: present -    choices: ['present', 'absent', 'up', 'down'] -extends_documentation_fragment: vyos -""" - -EXAMPLES = """ -- name: configure link aggregation group -  vyos_linkagg: -    name: bond0 -    members: -      - eth0 -      - eth1 - -- name: remove configuration -  vyos_linkagg: -    name: bond0 -    state: absent - -- name: Create aggregate of linkagg definitions -  vyos_linkagg: -    aggregate: -        - { name: bond0, members: [eth1] } -        - { name: bond1, members: [eth2] } - -- name: Remove aggregate of linkagg definitions -  vyos_linkagg: -    aggregate: -      - name: bond0 -      - name: bond1 -    state: absent -""" - -RETURN = """ -commands: -  description: The list of configuration mode commands to send to the device -  returned: always, except for the platforms that use Netconf transport to manage the device. -  type: list -  sample: -    - set interfaces bonding bond0 -    - set interfaces ethernet eth0 bond-group 'bond0' -    - set interfaces ethernet eth1 bond-group 'bond0' -""" -from copy import deepcopy - -from ansible.module_utils.basic import AnsibleModule -from ansible.module_utils.network.common.utils import remove_default_spec -from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.vyos import ( -    load_config, -    run_commands, -) - -from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.vyos import ( -    vyos_argument_spec, -) - - -def search_obj_in_list(name, lst): -    for o in lst: -        if o["name"] == name: -            return o - -    return None - - -def map_obj_to_commands(updates, module): -    commands = list() -    want, have = updates - -    for w in want: -        name = w["name"] -        members = w.get("members") or [] -        mode = w["mode"] - -        if mode == "on": -            mode = "802.3ad" - -        state = w["state"] - -        obj_in_have = search_obj_in_list(name, have) - -        if state == "absent": -            if obj_in_have: -                for m in obj_in_have["members"]: -                    commands.append( -                        "delete interfaces ethernet " + m + " bond-group" -                    ) - -                commands.append("delete interfaces bonding " + name) -        else: -            if not obj_in_have: -                commands.append( -                    "set interfaces bonding " + name + " mode " + mode -                ) - -                for m in members: -                    commands.append( -                        "set interfaces ethernet " + m + " bond-group " + name -                    ) - -                if state == "down": -                    commands.append( -                        "set interfaces bonding " + name + " disable" -                    ) -            else: -                if mode != obj_in_have["mode"]: -                    commands.append( -                        "set interfaces bonding " + name + " mode " + mode -                    ) - -                missing_members = list( -                    set(members) - set(obj_in_have["members"]) -                ) -                for m in missing_members: -                    commands.append( -                        "set interfaces ethernet " + m + " bond-group " + name -                    ) - -                if state == "down" and obj_in_have["state"] == "up": -                    commands.append( -                        "set interfaces bonding " + name + " disable" -                    ) -                elif state == "up" and obj_in_have["state"] == "down": -                    commands.append( -                        "delete interfaces bonding " + name + " disable" -                    ) - -    return commands - - -def map_config_to_obj(module): -    obj = [] -    output = run_commands(module, ["show interfaces bonding slaves"]) -    lines = output[0].splitlines() - -    if len(lines) > 1: -        for line in lines[1:]: -            splitted_line = line.split() - -            name = splitted_line[0] -            mode = splitted_line[1] -            state = splitted_line[2] - -            if len(splitted_line) > 4: -                members = splitted_line[4:] -            else: -                members = [] - -            obj.append( -                { -                    "name": name, -                    "mode": mode, -                    "members": members, -                    "state": state, -                } -            ) - -    return obj - - -def map_params_to_obj(module): -    obj = [] -    aggregate = module.params.get("aggregate") -    if aggregate: -        for item in aggregate: -            for key in item: -                if item.get(key) is None: -                    item[key] = module.params[key] - -            obj.append(item.copy()) -    else: -        obj.append( -            { -                "name": module.params["name"], -                "mode": module.params["mode"], -                "members": module.params["members"], -                "state": module.params["state"], -            } -        ) - -    return obj - - -def main(): -    """ main entry point for module execution -    """ -    element_spec = dict( -        name=dict(), -        mode=dict( -            choices=[ -                "802.3ad", -                "active-backup", -                "broadcast", -                "round-robin", -                "transmit-load-balance", -                "adaptive-load-balance", -                "xor-hash", -                "on", -            ], -            default="802.3ad", -        ), -        members=dict(type="list"), -        state=dict( -            default="present", choices=["present", "absent", "up", "down"] -        ), -    ) - -    aggregate_spec = deepcopy(element_spec) -    aggregate_spec["name"] = dict(required=True) - -    # remove default in aggregate spec, to handle common arguments -    remove_default_spec(aggregate_spec) - -    argument_spec = dict( -        aggregate=dict(type="list", elements="dict", options=aggregate_spec) -    ) - -    argument_spec.update(element_spec) -    argument_spec.update(vyos_argument_spec) - -    required_one_of = [["name", "aggregate"]] -    mutually_exclusive = [["name", "aggregate"]] -    module = AnsibleModule( -        argument_spec=argument_spec, -        required_one_of=required_one_of, -        mutually_exclusive=mutually_exclusive, -        supports_check_mode=True, -    ) - -    warnings = list() - -    result = {"changed": False} - -    if warnings: -        result["warnings"] = warnings - -    want = map_params_to_obj(module) -    have = map_config_to_obj(module) - -    commands = map_obj_to_commands((want, have), module) -    result["commands"] = commands - -    if commands: -        commit = not module.check_mode -        load_config(module, commands, commit=commit) -        result["changed"] = True - -    module.exit_json(**result) - - -if __name__ == "__main__": -    main() +_vyos_linkagg.py
\ No newline at end of file diff --git a/plugins/modules/vyos_lldp.py b/plugins/modules/vyos_lldp.py index 18a013f3..fdec8149 100644 --- a/plugins/modules/vyos_lldp.py +++ b/plugins/modules/vyos_lldp.py @@ -69,7 +69,6 @@ from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.vyos import      get_config,      load_config,  ) -  from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.vyos import (      vyos_argument_spec,  ) diff --git a/plugins/modules/vyos_lldp_interface.py b/plugins/modules/vyos_lldp_interface.py index 5d25ea3a..494fac46 100644 --- a/plugins/modules/vyos_lldp_interface.py +++ b/plugins/modules/vyos_lldp_interface.py @@ -99,7 +99,6 @@ from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.vyos import      get_config,      load_config,  ) -  from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.vyos import (      vyos_argument_spec,  ) diff --git a/plugins/modules/vyos_logging.py b/plugins/modules/vyos_logging.py index fa0d1cf7..8eb5777a 100644 --- a/plugins/modules/vyos_logging.py +++ b/plugins/modules/vyos_logging.py @@ -116,7 +116,6 @@ from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.vyos import      get_config,      load_config,  ) -  from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.vyos import (      vyos_argument_spec,  ) diff --git a/plugins/modules/vyos_ping.py b/plugins/modules/vyos_ping.py index c770804d..4b21927c 100644 --- a/plugins/modules/vyos_ping.py +++ b/plugins/modules/vyos_ping.py @@ -136,11 +136,9 @@ from ansible.module_utils.basic import AnsibleModule  from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.vyos import (      run_commands,  ) -  from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.vyos import (      vyos_argument_spec,  ) -  import re diff --git a/plugins/modules/vyos_static_route.py b/plugins/modules/vyos_static_route.py index 734a1b08..b7307ef4 100644 --- a/plugins/modules/vyos_static_route.py +++ b/plugins/modules/vyos_static_route.py @@ -114,7 +114,6 @@ from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.vyos import      get_config,      load_config,  ) -  from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.vyos import (      vyos_argument_spec,  ) diff --git a/plugins/modules/vyos_system.py b/plugins/modules/vyos_system.py index 3f306f8a..9fee88f6 100644 --- a/plugins/modules/vyos_system.py +++ b/plugins/modules/vyos_system.py @@ -98,7 +98,6 @@ from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.vyos import      get_config,      load_config,  ) -  from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.vyos import (      vyos_argument_spec,  ) diff --git a/plugins/modules/vyos_user.py b/plugins/modules/vyos_user.py index 2bccd494..2a1181a6 100644 --- a/plugins/modules/vyos_user.py +++ b/plugins/modules/vyos_user.py @@ -143,7 +143,6 @@ from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.vyos import      get_config,      load_config,  ) -  from ansible.module_utils.six import iteritems  from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.vyos import (      vyos_argument_spec, diff --git a/plugins/modules/vyos_vlan.py b/plugins/modules/vyos_vlan.py index 6c0fad8c..10eaecd6 100644 --- a/plugins/modules/vyos_vlan.py +++ b/plugins/modules/vyos_vlan.py @@ -129,7 +129,6 @@ from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.vyos import      load_config,      run_commands,  ) -  from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.vyos import (      vyos_argument_spec,  ) | 
