diff options
| author | ansible-zuul[bot] <48994755+ansible-zuul[bot]@users.noreply.github.com> | 2020-05-11 13:35:11 +0000 | 
|---|---|---|
| committer | GitHub <noreply@github.com> | 2020-05-11 13:35:11 +0000 | 
| commit | 62ddab1affb33cb83b7a31ae6076e73c23dd1d0a (patch) | |
| tree | b3de8652c72a4c5e99e51459530d18b059c3ffc8 | |
| parent | eff143edbc1347e608e4f462093bbcb9985bb57f (diff) | |
| parent | 44a2e8c885b1d050f9a36fc095403c1568cc1cfd (diff) | |
| download | vyos.vyos-62ddab1affb33cb83b7a31ae6076e73c23dd1d0a.tar.gz vyos.vyos-62ddab1affb33cb83b7a31ae6076e73c23dd1d0a.zip | |
Merge pull request #17 from rohitthakur2590/vyos_ospfv3
VyOS: OSPFv3 Resource Module
Reviewed-by: https://github.com/apps/ansible-zuul
30 files changed, 2473 insertions, 2 deletions
| diff --git a/plugins/module_utils/network/vyos/argspec/ospfv3/__init__.py b/plugins/module_utils/network/vyos/argspec/ospfv3/__init__.py new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/plugins/module_utils/network/vyos/argspec/ospfv3/__init__.py diff --git a/plugins/module_utils/network/vyos/argspec/ospfv3/ospfv3.py b/plugins/module_utils/network/vyos/argspec/ospfv3/ospfv3.py new file mode 100644 index 00000000..66aaa8c4 --- /dev/null +++ b/plugins/module_utils/network/vyos/argspec/ospfv3/ospfv3.py @@ -0,0 +1,94 @@ +# +# -*- 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 arg spec for the vyos_ospfv3 module +""" + + +class Ospfv3Args(object):  # pylint: disable=R0903 +    """The arg spec for the vyos_ospfv3 module +    """ + +    def __init__(self, **kwargs): +        pass + +    argument_spec = { +        "config": { +            "options": { +                "areas": { +                    "elements": "dict", +                    "options": { +                        "area_id": {"type": "str"}, +                        "export_list": {"type": "str"}, +                        "import_list": {"type": "str"}, +                        "range": { +                            "elements": "dict", +                            "options": { +                                "address": {"type": "str"}, +                                "advertise": {"type": "bool"}, +                                "not_advertise": {"type": "bool"}, +                            }, +                            "type": "list", +                        }, +                    }, +                    "type": "list", +                }, +                "parameters": { +                    "options": {"router_id": {"type": "str"}}, +                    "type": "dict", +                }, +                "redistribute": { +                    "elements": "dict", +                    "options": { +                        "route_map": {"type": "str"}, +                        "route_type": { +                            "choices": [ +                                "bgp", +                                "connected", +                                "kernel", +                                "ripng", +                                "static", +                            ], +                            "type": "str", +                        }, +                    }, +                    "type": "list", +                }, +            }, +            "type": "dict", +        }, +        "running_config": {"type": "str"}, +        "state": { +            "choices": [ +                "merged", +                "replaced", +                "deleted", +                "parsed", +                "gathered", +                "rendered", +            ], +            "default": "merged", +            "type": "str", +        }, +    }  # pylint: disable=C0301 diff --git a/plugins/module_utils/network/vyos/config/ospfv3/__init__.py b/plugins/module_utils/network/vyos/config/ospfv3/__init__.py new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/plugins/module_utils/network/vyos/config/ospfv3/__init__.py diff --git a/plugins/module_utils/network/vyos/config/ospfv3/ospfv3.py b/plugins/module_utils/network/vyos/config/ospfv3/ospfv3.py new file mode 100644 index 00000000..acda3801 --- /dev/null +++ b/plugins/module_utils/network/vyos/config/ospfv3/ospfv3.py @@ -0,0 +1,464 @@ +# +# -*- 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_ospfv3 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 copy import deepcopy +from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.cfg.base import ( +    ConfigBase, +) +from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.utils import ( +    to_list, +    remove_empties, +    search_obj_in_list, +) +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 ( +    _in_target, +    _is_w_same, +    _bool_to_str, +) + + +class Ospfv3(ConfigBase): +    """ +    The vyos_ospfv3 class +    """ + +    gather_subset = [ +        "!all", +        "!min", +    ] + +    gather_network_resources = [ +        "ospfv3", +    ] + +    def __init__(self, module): +        super(Ospfv3, self).__init__(module) + +    def get_ospfv3_facts(self, data=None): +        """ 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, data=data +        ) +        ospfv3_facts = facts["ansible_network_resources"].get("ospfv3", {}) +        return ospfv3_facts + +    def execute_module(self): +        """ Execute the module + +        :rtype: A dictionary +        :returns: The result from module execution +        """ +        result = {"changed": False} +        warnings = list() +        commands = list() + +        if self.state in self.ACTION_STATES: +            existing_ospfv3_facts = self.get_ospfv3_facts() +        else: +            existing_ospfv3_facts = {} + +        if self.state in self.ACTION_STATES or self.state == "rendered": +            commands.extend(self.set_config(existing_ospfv3_facts)) + +        if commands and self.state in self.ACTION_STATES: +            if not self._module.check_mode: +                self._connection.edit_config(commands) +            result["changed"] = True + +        if self.state in self.ACTION_STATES: +            result["commands"] = commands + +        if self.state in self.ACTION_STATES or self.state == "gathered": +            changed_ospfv3_facts = self.get_ospfv3_facts() +        elif self.state == "rendered": +            result["rendered"] = commands +        elif self.state == "parsed": +            running_config = self._module.params["running_config"] +            if not running_config: +                self._module.fail_json( +                    msg="value of running_config parameter must not be empty for state parsed" +                ) +            result["parsed"] = self.get_ospfv3_facts(data=running_config) +        else: +            changed_ospfv3_facts = {} + +        if self.state in self.ACTION_STATES: +            result["before"] = existing_ospfv3_facts +            if result["changed"]: +                result["after"] = changed_ospfv3_facts +        elif self.state == "gathered": +            result["gathered"] = changed_ospfv3_facts + +        result["warnings"] = warnings +        return result + +    def set_config(self, existing_ospfv3_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_ospfv3_facts +        resp = self.set_state(want, have) +        return to_list(resp) + +    def set_state(self, w, h): +        """ 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 = [] +        if ( +            self.state in ("merged", "replaced", "overridden", "rendered") +            and not w +        ): +            self._module.fail_json( +                msg="value of config parameter must not be empty for state {0}".format( +                    self.state +                ) +            ) +        if self.state == "deleted": +            commands.extend(self._state_deleted(w, h)) +        elif self.state in ("merged", "rendered"): +            commands.extend(self._state_merged(w, h)) +        elif self.state == "replaced": +            commands.extend(self._state_replaced(w, h)) +        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_ospf_param(have, want, opr=False)) +        commands.extend(self._render_ospf_param(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_ospf_param(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 have: +            commands.append("delete protocols ospfv3") +        return commands + +    def _render_ospf_param(self, want, have, opr=True): +        """ +        This function forms the set/delete commands for ospf leaf attributes +        and triggers the process for other child attributes. +        for firewall_global attributes. +        :param w: the desired config. +        :param h: the target config. +        :param opr: True/False. +        :return: generated commands list. +        """ +        commands = [] +        w = deepcopy(remove_empties(want)) +        if w: +            for key, val in iteritems(w): +                commands.extend(self._render_child_param(w, have, key, opr)) +        return commands + +    def _render_child_param(self, w, h, key, opr=True): +        """ +        This function invoke the function to extend commands +        based on the key. +        :param w: the desired configuration. +        :param h: the current configuration. +        :param key: attribute name. +        :param opr: operation. +        :return: list of commands. +        """ +        commands = [] +        if key == "areas": +            commands.extend(self._render_areas(key, w, h, opr=opr)) +        elif key == "parameters": +            commands.extend(self._render_dict_param(key, w, h, opr=opr)) +        elif key == "redistribute": +            commands.extend(self._render_list_dict_param(key, w, h, opr=opr)) +        return commands + +    def _render_dict_param(self, attr, want, have, opr=True): +        """ +        This function generate the commands for dictionary elements. +        :param attr: attribute name. +        :param w: the desired configuration. +        :param h: the target config. +        :param opr: True/False. +        :return: generated list of commands. +        """ +        commands = [] +        h = {} +        if have: +            h = have.get(attr) or {} +        if not opr and not h: +            commands.append(self._form_attr_cmd(attr=attr, opr=opr)) +        elif want[attr]: +            leaf_dict = {"parameters": "router_id"} +            leaf = leaf_dict[attr] +            for item, value in iteritems(want[attr]): +                if ( +                    opr +                    and item in leaf +                    and not _is_w_same(want[attr], h, item) +                ): +                    commands.append( +                        self._form_attr_cmd( +                            key=attr, attr=item, val=value, opr=opr +                        ) +                    ) +                elif not opr and item in leaf and not _in_target(h, item): +                    commands.append( +                        self._form_attr_cmd(key=attr, attr=item, opr=opr) +                    ) +        return commands + +    def _render_list_dict_param(self, attr, want, have, cmd=None, opr=True): +        """ +        This function forms the set/delete commands based on the 'opr' type +        for attributes with in desired list of dictionary. +        :param attr: attribute name. +        :param w: the desired config. +        :param h: the target config. +        :param cmd: commands to be prepend. +        :param opr: True/False. +        :return: generated commands list. +        """ +        commands = [] +        h = [] +        name = { +            "redistribute": "route_type", +            "range": "address", +        } +        leaf_dict = { +            "redistribute": ("route_map", "route_type"), +            "range": ("address", "advertise", "not_advertise"), +        } +        leaf = leaf_dict[attr] +        w = want.get(attr) or [] +        if have: +            h = have.get(attr) or [] +        if not opr and not h: +            commands.append(self._compute_command(attr=attr, opr=opr)) +        elif w: +            for w_item in w: +                for key, val in iteritems(w_item): +                    if not cmd: +                        cmd = self._compute_command(opr=opr) +                    h_item = search_obj_in_list( +                        w_item[name[attr]], h, name[attr] +                    ) +                    if ( +                        opr +                        and key in leaf +                        and not _is_w_same(w_item, h_item, key) +                    ): +                        if key == "route_type" or ( +                            key == "address" +                            and "advertise" not in w_item +                            and "not-advertise" not in w_item +                        ): +                            if not val: +                                cmd = cmd.replace("set", "delete") +                            commands.append(cmd + attr + " " + str(val)) +                        elif key in leaf_dict["range"] and key != "address": +                            commands.append( +                                cmd +                                + attr +                                + " " +                                + w_item[name[attr]] +                                + " " +                                + key.replace("_", "-") +                            ) +                        elif key == "route_map": +                            commands.append( +                                cmd +                                + attr +                                + " " +                                + w_item[name[attr]] +                                + " " +                                + key.replace("_", "-") +                                + " " +                                + str(val) +                            ) +                    elif ( +                        not opr and key in leaf and not _in_target(h_item, key) +                    ): +                        if key in ("route_type", "address"): +                            commands.append(cmd + attr + " " + str(val)) +                        else: +                            commands.append( +                                cmd +                                + (attr + " " + w_item[name[attr]] + " " + key) +                            ) +        return commands + +    def _render_areas(self, attr, want, have, opr=True): +        """ +        This function forms the set/delete commands based on the 'opr' type +        for ospf area attributes. +        :param attr: attribute name. +        :param w: the desired config. +        :param h: the target config. +        :param opr: True/False. +        :return: generated commands list. +        """ +        commands = [] +        h_lst = {} +        w_lst = want.get(attr) or [] +        l_set = ("area_id", "export_list", "import_list") +        if have: +            h_lst = have.get(attr) or [] +        if not opr and not h_lst: +            commands.append(self._form_attr_cmd(attr="area", opr=opr)) +        elif w_lst: +            for w_area in w_lst: +                cmd = ( +                    self._compute_command( +                        key="area", +                        attr=_bool_to_str(w_area["area_id"]), +                        opr=opr, +                    ) +                    + " " +                ) +                h_area = search_obj_in_list( +                    w_area["area_id"], h_lst, "area_id" +                ) +                if not opr and not h_area: +                    commands.append( +                        self._form_attr_cmd( +                            key="area", attr=w_area["area_id"], opr=opr +                        ) +                    ) +                else: +                    for key, val in iteritems(w_area): +                        if ( +                            opr +                            and key in l_set +                            and not _is_w_same(w_area, h_area, key) +                        ): +                            if key == "area_id": +                                commands.append( +                                    self._form_attr_cmd( +                                        attr="area", +                                        val=_bool_to_str(val), +                                        opr=opr, +                                    ) +                                ) +                            else: +                                commands.append( +                                    cmd +                                    + key.replace("_", "-") +                                    + " " +                                    + _bool_to_str(val).replace("_", "-") +                                ) +                        elif not opr and key in l_set: +                            if key == "area_id" and not _in_target( +                                h_area, key +                            ): +                                commands.append(cmd) +                                continue +                            elif key != "area_id" and not _in_target( +                                h_area, key +                            ): +                                commands.append(cmd + val + " " + key) +                        elif key == "range": +                            commands.extend( +                                self._render_list_dict_param( +                                    key, w_area, h_area, cmd, opr +                                ) +                            ) +        return commands + +    def _form_attr_cmd(self, key=None, attr=None, val=None, opr=True): +        """ +        This function forms the command for leaf attribute. +        :param key: parent key. +        :param attr: attribute name +        :param value: value +        :param opr: True/False. +        :return: generated command. +        """ +        return self._compute_command( +            key, attr=self._map_attrib(attr), val=val, opr=opr +        ) + +    def _compute_command( +        self, key=None, attr=None, val=None, remove=False, opr=True +    ): +        """ +        This function construct the add/delete command based on passed attributes. +        :param key: parent key. +        :param attr: attribute name +        :param value: value +        :param opr: True/False. +        :return: generated command. +        """ +        if remove or not opr: +            cmd = "delete protocols ospfv3 " +        else: +            cmd = "set protocols ospfv3 " +        if key: +            cmd += key.replace("_", "-") + " " +        if attr: +            cmd += attr.replace("_", "-") +        if val and opr: +            cmd += " '" + str(val) + "'" +        return cmd + +    def _map_attrib(self, attrib): +        """ +        - This function construct the regex string. +        - replace the underscore with hyphen. +        :param attrib: attribute +        :return: regex string +        """ +        return "disable" if attrib == "disabled" else attrib.replace("_", "-") diff --git a/plugins/module_utils/network/vyos/facts/facts.py b/plugins/module_utils/network/vyos/facts/facts.py index ff3d0988..3c87be6b 100644 --- a/plugins/module_utils/network/vyos/facts/facts.py +++ b/plugins/module_utils/network/vyos/facts/facts.py @@ -40,6 +40,9 @@ from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.facts.firew  from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.facts.firewall_interfaces.firewall_interfaces import (      Firewall_interfacesFacts,  ) +from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.facts.ospfv3.ospfv3 import ( +    Ospfv3Facts, +)  from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.facts.legacy.base import (      Default,      Neighbors, @@ -58,6 +61,7 @@ FACT_RESOURCE_SUBSETS = dict(      firewall_rules=Firewall_rulesFacts,      firewall_global=Firewall_globalFacts,      firewall_interfaces=Firewall_interfacesFacts, +    ospfv3=Ospfv3Facts,  ) diff --git a/plugins/module_utils/network/vyos/facts/ospfv3/__init__.py b/plugins/module_utils/network/vyos/facts/ospfv3/__init__.py new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/plugins/module_utils/network/vyos/facts/ospfv3/__init__.py diff --git a/plugins/module_utils/network/vyos/facts/ospfv3/ospfv3.py b/plugins/module_utils/network/vyos/facts/ospfv3/ospfv3.py new file mode 100644 index 00000000..457a9636 --- /dev/null +++ b/plugins/module_utils/network/vyos/facts/ospfv3/ospfv3.py @@ -0,0 +1,213 @@ +# +# -*- 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 ospfv3 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_collections.ansible.netcommon.plugins.module_utils.network.common import ( +    utils, +) +from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.argspec.ospfv3.ospfv3 import ( +    Ospfv3Args, +) + + +class Ospfv3Facts(object): +    """ The vyos ospfv3 fact class +    """ + +    def __init__(self, module, subspec="config", options="options"): +        self._module = module +        self.argument_spec = Ospfv3Args.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 get_device_data(self, connection): +        return connection.get_config() + +    def populate_facts(self, connection, ansible_facts, data=None): +        """ Populate the facts for ospfv3 +        :param connection: the device connection +        :param ansible_facts: Facts dictionary +        :param data: previously collected conf +        :rtype: dictionary +        :returns: facts +        """ +        if not data: +            data = self.get_device_data(connection) +            # typically data is populated from the current device configuration +            # data = connection.get('show running-config | section ^interface') +            # using mock data instead +        objs = {} +        ospfv3 = findall(r"^set protocols ospfv3 (.+)", data, M) +        if ospfv3: +            objs = self.render_config(ospfv3) +        facts = {} +        params = utils.validate_config(self.argument_spec, {"config": objs}) +        facts["ospfv3"] = 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 + +        :param conf: The configuration +        :returns: The generated config +        """ +        conf = "\n".join(filter(lambda x: x, conf)) +        config = {} +        config["parameters"] = self.parse_attrib( +            conf, "parameters", "parameters" +        ) +        config["areas"] = self.parse_attrib_list(conf, "area", "area_id") +        config["redistribute"] = self.parse_attrib_list( +            conf, "redistribute", "route_type" +        ) +        return config + +    def parse_attrib_list(self, conf, attrib, param): +        """ +        This function forms the regex to fetch the listed attributes +        from config +        :param conf: configuration data +        :param attrib: attribute name +        :param param: parameter data +        :return: generated rule list configuration +        """ +        r_lst = [] +        if attrib == "area": +            items = findall(r"^" + attrib + " (?:'*)(\\S+)(?:'*)", conf, M) +        else: +            items = findall(r"" + attrib + " (?:'*)(\\S+)(?:'*)", conf, M) +        if items: +            a_lst = [] +            for item in set(items): +                i_regex = r" %s .+$" % item +                cfg = "\n".join(findall(i_regex, conf, M)) +                if attrib == "area": +                    obj = self.parse_area(cfg, item) +                else: +                    obj = self.parse_attrib(cfg, attrib) +                obj[param] = item.strip("'") +                if obj: +                    a_lst.append(obj) +            r_lst = sorted(a_lst, key=lambda i: i[param]) +        return r_lst + +    def parse_area(self, conf, area_id): +        """ +        This function triggers the parsing of 'area' attributes. +        :param conf: configuration data +        :param area_id: area identity +        :return: generated rule configuration dictionary. +        """ + +        rule = self.parse_attrib(conf, "area_id", match=area_id) +        r_sub = {"range": self.parse_attrib_list(conf, "range", "address")} +        rule.update(r_sub) +        return rule + +    def parse_attrib(self, conf, param, match=None): +        """ +        This function triggers the parsing of 'ospf' attributes +        :param conf: configuration data +        :return: generated configuration dictionary +        """ +        param_lst = { +            "area_id": ["export_list", "import_list"], +            "redistribute": ["route_map"], +            "range": ["advertise", "not_advertise"], +            "parameters": ["router_id"], +        } +        cfg_dict = self.parse_attr(conf, param_lst[param], match) +        return cfg_dict + +    def parse_attr(self, conf, attr_list, match=None): +        """ +        This function peforms the following: +        - Form the regex to fetch the required attribute config. +        - Type cast the output in desired format. +        :param conf: configuration. +        :param attr_list: list of attributes. +        :param match: parent node/attribute name. +        :return: generated config dictionary. +        """ +        config = {} +        for attrib in attr_list: +            regex = self.map_regex(attrib) +            if match: +                regex = match.replace("_", "-") + " " + regex +            if conf: +                if self.is_bool(attrib): +                    out = conf.find(attrib.replace("_", "-")) +                    dis = conf.find(attrib.replace("_", "-") + " 'disable'") +                    if match: +                        en = conf.find(match + " 'enable'") +                    if out >= 1: +                        if dis >= 1: +                            config[attrib] = False +                        else: +                            config[attrib] = True +                    elif match and en >= 1: +                        config[attrib] = True +                else: +                    out = search(r"^.*" + regex + " (.+)", conf, M) +                    if out: +                        val = out.group(1).strip("'") +                        if self.is_num(attrib): +                            val = int(val) +                        config[attrib] = val +        return config + +    def map_regex(self, attrib): +        """ +        - This function construct the regex string. +        - replace the underscore with hyphen. +        :param attrib: attribute +        :return: regex string +        """ +        return ( +            "disable" +            if attrib == "disabled" +            else "enable" +            if attrib == "enabled" +            else attrib.replace("_", "-") +        ) + +    def is_bool(self, attrib): +        """ +        This function looks for the attribute in predefined bool type set. +        :param attrib: attribute. +        :return: True/False +        """ +        bool_set = ("enabled", "advertise", "not_advertise") +        return True if attrib in bool_set else False + +    def is_num(self, attrib): +        """ +        This function looks for the attribute in predefined integer type set. +        :param attrib: attribute. +        :return: True/false. +        """ +        num_set = "ospf" +        return True if attrib in num_set else False diff --git a/plugins/module_utils/network/vyos/utils/utils.py b/plugins/module_utils/network/vyos/utils/utils.py index 4635234c..96feddd9 100644 --- a/plugins/module_utils/network/vyos/utils/utils.py +++ b/plugins/module_utils/network/vyos/utils/utils.py @@ -113,7 +113,7 @@ def get_lst_same_for_dicts(want, have, lst):  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: @@ -230,3 +230,40 @@ def get_route_type(address):          return "route6"      elif version == 4:          return "route" + + +def _bool_to_str(val): +    """ +    This function converts the bool value into string. +    :param val: bool value. +    :return: enable/disable. +    """ +    return ( +        "enable" +        if str(val) == "True" +        else "disable" +        if str(val) == "False" +        else val +    ) + + +def _is_w_same(w, h, key): +    """ +    This function checks whether the key value is same in desired and +    target config dictionary. +    :param w: base config. +    :param h: target config. +    :param key:attribute name. +    :return: True/False. +    """ +    return True if h and key in h and h[key] == w[key] else False + + +def _in_target(h, key): +    """ +    This function checks whether the target exist and key present in target config. +    :param h: target config. +    :param key: attribute name. +    :return: True/False. +    """ +    return True if h and key in h else False diff --git a/plugins/modules/vyos_facts.py b/plugins/modules/vyos_facts.py index 4a640663..5849519c 100644 --- a/plugins/modules/vyos_facts.py +++ b/plugins/modules/vyos_facts.py @@ -48,7 +48,7 @@ options:        used with an initial C(M(!)) to specify that a specific subset should not be        collected. Valid subsets are 'all', 'interfaces', 'l3_interfaces', 'lag_interfaces',        'lldp_global', 'lldp_interfaces', 'static_routes', 'firewall_rules', 'firewall_global', -      'firewall_interfaces'. +      'firewall_interfaces', 'ospfv3'.      required: false  """ diff --git a/plugins/modules/vyos_ospfv3.py b/plugins/modules/vyos_ospfv3.py new file mode 100644 index 00000000..e2d3ff7f --- /dev/null +++ b/plugins/modules/vyos_ospfv3.py @@ -0,0 +1,667 @@ +#!/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_ospfv3 +""" + +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + +ANSIBLE_METADATA = {"metadata_version": "1.1", "supported_by": "Ansible"} + +DOCUMENTATION = """ +--- +module: vyos_ospfv3 +version_added: 2.10 +short_description: OSPFV3 resource module. +description: This resource module configures and manages attributes of OSPFv3 routes on VyOS network devices. +version_added: "1.0.0" +notes: +  - Tested against VyOS 1.1.8 (helium). +  - This module works with connection C(network_cli). See L(the VyOS OS Platform Options,../network/user_guide/platform_vyos.html). +author: +- Rohit Thakur (@rohitthakur2590) +options: +  config: +    description: A provided OSPFv3 route configuration. +    type: dict +    suboptions: +      areas: +        description: OSPFv3 area. +        type: list +        elements: dict +        suboptions: +          area_id: +            description: OSPFv3 Area name/identity. +            type: str +          export_list: +            description: Name of export-list. +            type: str +          import_list: +            description: Name of import-list. +            type: str +          range: +            description: Summarize routes matching prefix (border routers only). +            type: list +            elements: dict +            suboptions: +              address: +                description: border router IPv4 address. +                type: str +              advertise: +                description: Advertise this range. +                type: bool +              not_advertise: +                description: Don't advertise this range. +                type: bool +      parameters: +        descriptions: OSPFv3 specific parameters. +        type: dict +        suboptions: +         router_id: +           description: Override the default router identifier. +           type: str +      redistribute: +        description: Redistribute information from another routing protocol. +        type: list +        elements: dict +        suboptions: +          route_type: +            description: Route type to redistribute. +            type: str +            choices: ['bgp', 'connected', 'kernel', 'ripng', 'static'] +          route_map: +            description: Route map references. +            type: str +  running_config: +    description: +      - This option is used only with state I(parsed). +      - The value of this option should be the output received from the VyOS device by executing +        the command B(show configuration commands | grep ospfv3). +      - The state I(parsed) reads the configuration from C(running_config) option and transforms +        it into Ansible structured data as per the resource module's argspec and the value is then +        returned in the I(parsed) key within the result. +    type: str +  state: +    description: +      - The state the configuration should be left in. +    type: str +    choices: +    - merged +    - replaced +    - deleted +    - parsed +    - gathered +    - rendered +    default: merged +""" +EXAMPLES = """ +# Using merged +# +# Before state: +# ------------- +# +# vyos@vyos# run show  configuration commands | grep ospfv3 +# +# +- name: Merge the provided configuration with the exisiting running configuration +  vyos.vyos.vyos_ospfv3: +    config: +      redistribute: +        - route_type: 'bgp' +      parameters: +        router_id: '192.0.2.10' +      areas: +        - area_id: '2' +          export_list: 'export1' +          import_list: 'import1' +          range: +            - address: '2001:db10::/32' +            - address: '2001:db20::/32' +            - address: '2001:db30::/32' +        - area_id: '3' +          range: +            - address: '2001:db40::/32' +    state: merged +# +# +# ------------------------- +# Module Execution Result +# ------------------------- +# +# before": {} +# +#    "commands": [ +#       "set protocols ospfv3 redistribute bgp", +#       "set protocols ospfv3 parameters router-id '192.0.2.10'", +#       "set protocols ospfv3 area 2 range 2001:db10::/32", +#       "set protocols ospfv3 area 2 range 2001:db20::/32", +#       "set protocols ospfv3 area 2 range 2001:db30::/32", +#       "set protocols ospfv3 area '2'", +#       "set protocols ospfv3 area 2 export-list export1", +#       "set protocols ospfv3 area 2 import-list import1", +#       "set protocols ospfv3 area '3'", +#       "set protocols ospfv3 area 3 range 2001:db40::/32" +#    ] +# +# "after": { +#        "areas": [ +#            { +#                "area_id": "2", +#                "export_list": "export1", +#                "import_list": "import1", +#                "range": [ +#                    { +#                        "address": "2001:db10::/32" +#                    }, +#                    { +#                        "address": "2001:db20::/32" +#                    }, +#                    { +#                        "address": "2001:db30::/32" +#                    } +#                ] +#            }, +#            { +#                "area_id": "3", +#                "range": [ +#                    { +#                        "address": "2001:db40::/32" +#                    } +#                ] +#            } +#        ], +#        "parameters": { +#            "router_id": "192.0.2.10" +#        }, +#        "redistribute": [ +#            { +#                "route_type": "bgp" +#            } +#        ] +#    } +# +# After state: +# ------------- +# +# vyos@192# run show configuration commands | grep ospfv3 +# set protocols ospfv3 area 2 export-list 'export1' +# set protocols ospfv3 area 2 import-list 'import1' +# set protocols ospfv3 area 2 range '2001:db10::/32' +# set protocols ospfv3 area 2 range '2001:db20::/32' +# set protocols ospfv3 area 2 range '2001:db30::/32' +# set protocols ospfv3 area 3 range '2001:db40::/32' +# set protocols ospfv3 parameters router-id '192.0.2.10' +# set protocols ospfv3 redistribute 'bgp' + + +# Using replaced +# +# Before state: +# ------------- +# +# vyos@192# run show configuration commands | grep ospfv3 +# set protocols ospfv3 area 2 export-list 'export1' +# set protocols ospfv3 area 2 import-list 'import1' +# set protocols ospfv3 area 2 range '2001:db10::/32' +# set protocols ospfv3 area 2 range '2001:db20::/32' +# set protocols ospfv3 area 2 range '2001:db30::/32' +# set protocols ospfv3 area 3 range '2001:db40::/32' +# set protocols ospfv3 parameters router-id '192.0.2.10' +# set protocols ospfv3 redistribute 'bgp' +# +- name: Replace ospfv3 routes attributes configuration. +  vyos.vyos.vyos_ospfv3: +    config: +      redistribute: +        - route_type: 'bgp' +      parameters: +        router_id: '192.0.2.10' +      areas: +        - area_id: '2' +          export_list: 'export1' +          import_list: 'import1' +          range: +            - address: '2001:db10::/32' +            - address: '2001:db30::/32' +            - address: '2001:db50::/32' +        - area_id: '4' +          range: +            - address: '2001:db60::/32' +    state: replaced +# +# +# ------------------------- +# Module Execution Result +# ------------------------- +# +#    "before": { +#        "areas": [ +#            { +#                "area_id": "2", +#                "export_list": "export1", +#                "import_list": "import1", +#                "range": [ +#                    { +#                        "address": "2001:db10::/32" +#                    }, +#                    { +#                        "address": "2001:db20::/32" +#                    }, +#                    { +#                        "address": "2001:db30::/32" +#                    } +#                ] +#            }, +#            { +#                "area_id": "3", +#                "range": [ +#                    { +#                        "address": "2001:db40::/32" +#                    } +#                ] +#            } +#        ], +#        "parameters": { +#            "router_id": "192.0.2.10" +#        }, +#        "redistribute": [ +#            { +#                "route_type": "bgp" +#            } +#        ] +#    } +# +# "commands": [ +#     "delete protocols ospfv3 area 2 range 2001:db20::/32", +#     "delete protocols ospfv3 area 3", +#     "set protocols ospfv3 area 2 range 2001:db50::/32", +#     "set protocols ospfv3 area '4'", +#     "set protocols ospfv3 area 4 range 2001:db60::/32" +#    ] +# +#    "after": { +#        "areas": [ +#            { +#                "area_id": "2", +#                "export_list": "export1", +#                "import_list": "import1", +#                "range": [ +#                    { +#                        "address": "2001:db10::/32" +#                    }, +#                    { +#                        "address": "2001:db30::/32" +#                    }, +#                    { +#                        "address": "2001:db50::/32" +#                    } +#                ] +#            }, +#            { +#                "area_id": "4", +#                "range": [ +#                    { +#                        "address": "2001:db60::/32" +#                    } +#                ] +#            } +#        ], +#        "parameters": { +#            "router_id": "192.0.2.10" +#        }, +#        "redistribute": [ +#            { +#                "route_type": "bgp" +#            } +#        ] +#    } +# +# After state: +# ------------- +# +# vyos@192# run show configuration commands | grep ospfv3 +# set protocols ospfv3 area 2 export-list 'export1' +# set protocols ospfv3 area 2 import-list 'import1' +# set protocols ospfv3 area 2 range '2001:db10::/32' +# set protocols ospfv3 area 2 range '2001:db30::/32' +# set protocols ospfv3 area 2 range '2001:db50::/32' +# set protocols ospfv3 area 4 range '2001:db60::/32' +# set protocols ospfv3 parameters router-id '192.0.2.10' +# set protocols ospfv3 redistribute 'bgp' + + +# Using rendered +# +# +- name: Render the commands for provided  configuration +  vyos.vyos.vyos_ospfv3: +    config: +      redistribute: +        - route_type: 'bgp' +      parameters: +        router_id: '192.0.2.10' +      areas: +        - area_id: '2' +          export_list: 'export1' +          import_list: 'import1' +          range: +            - address: '2001:db10::/32' +            - address: '2001:db20::/32' +            - address: '2001:db30::/32' +        - area_id: '3' +          range: +            - address: '2001:db40::/32' +    state: rendered +# +# +# ------------------------- +# Module Execution Result +# ------------------------- +# +# +# "rendered": [ +#        [ +#       "set protocols ospfv3 redistribute bgp", +#       "set protocols ospfv3 parameters router-id '192.0.2.10'", +#       "set protocols ospfv3 area 2 range 2001:db10::/32", +#       "set protocols ospfv3 area 2 range 2001:db20::/32", +#       "set protocols ospfv3 area 2 range 2001:db30::/32", +#       "set protocols ospfv3 area '2'", +#       "set protocols ospfv3 area 2 export-list export1", +#       "set protocols ospfv3 area 2 import-list import1", +#       "set protocols ospfv3 area '3'", +#       "set protocols ospfv3 area 3 range 2001:db40::/32" +#    ] + + +# Using parsed +# +# +- name: Parse the commands to provide structured configuration. +  vyos.vyos.vyos_ospfv3: +    running_config: +      "set protocols ospfv3 area 2 export-list 'export1' +set protocols ospfv3 area 2 import-list 'import1' +set protocols ospfv3 area 2 range '2001:db10::/32' +set protocols ospfv3 area 2 range '2001:db20::/32' +set protocols ospfv3 area 2 range '2001:db30::/32' +set protocols ospfv3 area 3 range '2001:db40::/32' +set protocols ospfv3 parameters router-id '192.0.2.10' +set protocols ospfv3 redistribute 'bgp'" +    state: parsed +# +# +# ------------------------- +# Module Execution Result +# ------------------------- +# +# +# "parsed": { +#        "areas": [ +#            { +#                "area_id": "2", +#                "export_list": "export1", +#                "import_list": "import1", +#                "range": [ +#                    { +#                        "address": "2001:db10::/32" +#                    }, +#                    { +#                        "address": "2001:db20::/32" +#                    }, +#                    { +#                        "address": "2001:db30::/32" +#                    } +#                ] +#            }, +#            { +#                "area_id": "3", +#                "range": [ +#                    { +#                        "address": "2001:db40::/32" +#                    } +#                ] +#            } +#        ], +#        "parameters": { +#            "router_id": "192.0.2.10" +#        }, +#        "redistribute": [ +#            { +#                "route_type": "bgp" +#            } +#        ] +#    } + + +# Using gathered +# +# Before state: +# ------------- +# +# vyos@192# run show configuration commands | grep ospfv3 +# set protocols ospfv3 area 2 export-list 'export1' +# set protocols ospfv3 area 2 import-list 'import1' +# set protocols ospfv3 area 2 range '2001:db10::/32' +# set protocols ospfv3 area 2 range '2001:db20::/32' +# set protocols ospfv3 area 2 range '2001:db30::/32' +# set protocols ospfv3 area 3 range '2001:db40::/32' +# set protocols ospfv3 parameters router-id '192.0.2.10' +# set protocols ospfv3 redistribute 'bgp' +# +- name: Gather ospfv3 routes config with provided configurations +  vyos.vyos.vyos_ospfv3: +    config: +    state: gathered +# +# +# ------------------------- +# Module Execution Result +# ------------------------- +# +#    "gathered": { +#        "areas": [ +#            { +#                "area_id": "2", +#                "export_list": "export1", +#                "import_list": "import1", +#                "range": [ +#                    { +#                        "address": "2001:db10::/32" +#                    }, +#                    { +#                        "address": "2001:db20::/32" +#                    }, +#                    { +#                        "address": "2001:db30::/32" +#                    } +#                ] +#            }, +#            { +#                "area_id": "3", +#                "range": [ +#                    { +#                        "address": "2001:db40::/32" +#                    } +#                ] +#            } +#        ], +#        "parameters": { +#            "router_id": "192.0.2.10" +#        }, +#        "redistribute": [ +#            { +#                "route_type": "bgp" +#            } +#        ] +#    } +# +# After state: +# ------------- +# +# vyos@192# run show configuration commands | grep ospfv3 +# set protocols ospfv3 area 2 export-list 'export1' +# set protocols ospfv3 area 2 import-list 'import1' +# set protocols ospfv3 area 2 range '2001:db10::/32' +# set protocols ospfv3 area 2 range '2001:db20::/32' +# set protocols ospfv3 area 2 range '2001:db30::/32' +# set protocols ospfv3 area 3 range '2001:db40::/32' +# set protocols ospfv3 parameters router-id '192.0.2.10' +# set protocols ospfv3 redistribute 'bgp' + + +# Using deleted +# +# Before state +# ------------- +# +# vyos@192# run show configuration commands | grep ospfv3 +# set protocols ospfv3 area 2 export-list 'export1' +# set protocols ospfv3 area 2 import-list 'import1' +# set protocols ospfv3 area 2 range '2001:db10::/32' +# set protocols ospfv3 area 2 range '2001:db20::/32' +# set protocols ospfv3 area 2 range '2001:db30::/32' +# set protocols ospfv3 area 3 range '2001:db40::/32' +# set protocols ospfv3 parameters router-id '192.0.2.10' +# set protocols ospfv3 redistribute 'bgp' +# +- name: Delete attributes of ospfv3 routes. +  vyos.vyos.vyos_ospfv3: +    config: +    state: deleted +# +# +# ------------------------ +# Module Execution Results +# ------------------------ +# +#    "before": { +#        "areas": [ +#            { +#                "area_id": "2", +#                "export_list": "export1", +#                "import_list": "import1", +#                "range": [ +#                    { +#                        "address": "2001:db10::/32" +#                    }, +#                    { +#                        "address": "2001:db20::/32" +#                    }, +#                    { +#                        "address": "2001:db30::/32" +#                    } +#                ] +#            }, +#            { +#                "area_id": "3", +#                "range": [ +#                    { +#                        "address": "2001:db40::/32" +#                    } +#                ] +#            } +#        ], +#        "parameters": { +#            "router_id": "192.0.2.10" +#        }, +#        "redistribute": [ +#            { +#                "route_type": "bgp" +#            } +#        ] +#    } +# "commands": [ +#        "delete protocols ospfv3" +#    ] +# +# "after": {} +# After state +# ------------ +# vyos@192# run show configuration commands | grep ospfv3 + + +""" +RETURN = """ +before: +  description: The configuration prior to the model invocation. +  returned: always +  type: dict +  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: dict +  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 protocols ospf parameters router-id 192.0.1.1', +           'set protocols ospfv3 area 2 range '2001:db10::/32'] +""" + + +from ansible.module_utils.basic import AnsibleModule +from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.argspec.ospfv3.ospfv3 import ( +    Ospfv3Args, +) +from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.config.ospfv3.ospfv3 import ( +    Ospfv3, +) + + +def main(): +    """ +    Main entry point for module execution + +    :returns: the result form module invocation +    """ +    required_if = [ +        ("state", "merged", ("config",)), +        ("state", "replaced", ("config",)), +        ("state", "rendered", ("config",)), +        ("state", "parsed", ("running_config",)), +    ] +    mutually_exclusive = [("config", "running_config")] +    module = AnsibleModule( +        argument_spec=Ospfv3Args.argument_spec, +        required_if=required_if, +        supports_check_mode=True, +        mutually_exclusive=mutually_exclusive, +    ) + +    result = Ospfv3(module).execute_module() +    module.exit_json(**result) + + +if __name__ == "__main__": +    main() diff --git a/tests/integration/targets/vyos_ospfv3/defaults/main.yaml b/tests/integration/targets/vyos_ospfv3/defaults/main.yaml new file mode 100644 index 00000000..852a6bee --- /dev/null +++ b/tests/integration/targets/vyos_ospfv3/defaults/main.yaml @@ -0,0 +1,3 @@ +--- +testcase: '[^_].*' +test_items: [] diff --git a/tests/integration/targets/vyos_ospfv3/meta/main.yaml b/tests/integration/targets/vyos_ospfv3/meta/main.yaml new file mode 100644 index 00000000..7413320e --- /dev/null +++ b/tests/integration/targets/vyos_ospfv3/meta/main.yaml @@ -0,0 +1,3 @@ +--- +dependencies: +  - prepare_vyos_tests diff --git a/tests/integration/targets/vyos_ospfv3/tasks/cli.yaml b/tests/integration/targets/vyos_ospfv3/tasks/cli.yaml new file mode 100644 index 00000000..93eb2fe4 --- /dev/null +++ b/tests/integration/targets/vyos_ospfv3/tasks/cli.yaml @@ -0,0 +1,19 @@ +--- +- name: Collect all cli test cases +  find: +    paths: '{{ role_path }}/tests/cli' +    patterns: '{{ testcase }}.yaml' +    use_regex: true +  register: test_cases +  delegate_to: localhost + +- name: Set test_items +  set_fact: test_items="{{ test_cases.files | map(attribute='path') | list }}" + +- name: Run test case (connection=ansible.netcommon.network_cli) +  include: '{{ test_case_to_run }}' +  vars: +    ansible_connection: ansible.netcommon.network_cli +  with_items: '{{ test_items }}' +  loop_control: +    loop_var: test_case_to_run diff --git a/tests/integration/targets/vyos_ospfv3/tasks/main.yaml b/tests/integration/targets/vyos_ospfv3/tasks/main.yaml new file mode 100644 index 00000000..a3db933e --- /dev/null +++ b/tests/integration/targets/vyos_ospfv3/tasks/main.yaml @@ -0,0 +1,4 @@ +--- +- include: cli.yaml +  tags: +    - cli diff --git a/tests/integration/targets/vyos_ospfv3/tests/cli/_parsed_config.cfg b/tests/integration/targets/vyos_ospfv3/tests/cli/_parsed_config.cfg new file mode 100644 index 00000000..5e012d5a --- /dev/null +++ b/tests/integration/targets/vyos_ospfv3/tests/cli/_parsed_config.cfg @@ -0,0 +1,8 @@ +set protocols ospfv3 area 2 export-list 'export1' +set protocols ospfv3 area 2 import-list 'import1' +set protocols ospfv3 area 2 range '2001:db10::/32' +set protocols ospfv3 area 2 range '2001:db20::/32' +set protocols ospfv3 area 2 range '2001:db30::/32' +set protocols ospfv3 area 3 range '2001:db40::/32' +set protocols ospfv3 parameters router-id '192.0.2.10' +set protocols ospfv3 redistribute 'bgp' diff --git a/tests/integration/targets/vyos_ospfv3/tests/cli/_populate.yaml b/tests/integration/targets/vyos_ospfv3/tests/cli/_populate.yaml new file mode 100644 index 00000000..fb66d0a5 --- /dev/null +++ b/tests/integration/targets/vyos_ospfv3/tests/cli/_populate.yaml @@ -0,0 +1,13 @@ +--- +- name: Setup +  vars: +    lines: "set protocols ospfv3 area 2 export-list 'export1' \n +            set protocols ospfv3 area 2 import-list 'import1' \n +            set protocols ospfv3 area 2 range '2001:db10::/32' \n +            set protocols ospfv3 area 2 range '2001:db20::/32' \n +            set protocols ospfv3 area 2 range '2001:db30::/32' \n +            set protocols ospfv3 area 3 range '2001:db40::/32' \n +            set protocols ospfv3 parameters router-id '192.0.2.10' \n +            set protocols ospfv3 redistribute 'bgp'" +  ansible.netcommon.cli_config: +    config: '{{ lines }}' diff --git a/tests/integration/targets/vyos_ospfv3/tests/cli/_remove_config.yaml b/tests/integration/targets/vyos_ospfv3/tests/cli/_remove_config.yaml new file mode 100644 index 00000000..2a475050 --- /dev/null +++ b/tests/integration/targets/vyos_ospfv3/tests/cli/_remove_config.yaml @@ -0,0 +1,6 @@ +--- +- name: Remove Config +  vars: +    lines: "delete protocols ospfv3\n" +  ansible.netcommon.cli_config: +    config: '{{ lines }}' diff --git a/tests/integration/targets/vyos_ospfv3/tests/cli/deleted.yaml b/tests/integration/targets/vyos_ospfv3/tests/cli/deleted.yaml new file mode 100644 index 00000000..55bec184 --- /dev/null +++ b/tests/integration/targets/vyos_ospfv3/tests/cli/deleted.yaml @@ -0,0 +1,48 @@ +--- +- debug: +    msg: Start vyos_ospfv3 deleted integration tests ansible_connection={{ +      ansible_connection }} + +- include_tasks: _populate.yaml + +- block: + +    - name: Delete ospfv3 routes +      register: result +      vyos.vyos.vyos_ospfv3: &id001 +        config: +        state: deleted + +    - name: Assert that the before dicts were correctly generated +      assert: +        that: +          - "{{ populate == result['before'] }}" + +    - name: Assert that the correct set of commands were generated +      assert: +        that: +          - "{{ deleted['commands'] | symmetric_difference(result['commands']) |length\ +            \ == 0 }}" + +    - name: Assert that the after dicts were correctly generated +      assert: +        that: +          - "{{ deleted['after'] == result['after'] }}" + +    - name: Delete ospfv3 routes (IDEMPOTENT) +      register: result +      vyos.vyos.vyos_ospfv3: *id001 + +    - name: Assert that the previous task was idempotent +      assert: +        that: +          - result.changed == false +          - result.commands|length == 0 + +    - name: Assert that the before dicts were correctly generated +      assert: +        that: +          - "{{ deleted['after'] == result['before'] }}" +  always: + +    - include_tasks: _remove_config.yaml diff --git a/tests/integration/targets/vyos_ospfv3/tests/cli/empty_config.yaml b/tests/integration/targets/vyos_ospfv3/tests/cli/empty_config.yaml new file mode 100644 index 00000000..fec61abf --- /dev/null +++ b/tests/integration/targets/vyos_ospfv3/tests/cli/empty_config.yaml @@ -0,0 +1,49 @@ +--- +- debug: +    msg: START vyos_ospfv3 empty_config integration tests on connection={{ +      ansible_connection }} + +- name: Merged with empty config should give appropriate error message +  register: result +  ignore_errors: true +  vyos.vyos.vyos_ospfv3: +    config: +    state: merged + +- assert: +    that: +      - result.msg == 'value of config parameter must not be empty for state merged' + +- name: Replaced with empty config should give appropriate error message +  register: result +  ignore_errors: true +  vyos.vyos.vyos_ospfv3: +    config: +    state: replaced + +- assert: +    that: +      - result.msg == 'value of config parameter must not be empty for state replaced' + +- name: Parsed with empty running_config should give appropriate error message +  register: result +  ignore_errors: true +  vyos.vyos.vyos_ospfv3: +    running_config: +    state: parsed + +- assert: +    that: +      - result.msg == 'value of running_config parameter must not be empty for state +        parsed' + +- name: Rendered with empty config should give appropriate error message +  register: result +  ignore_errors: true +  vyos.vyos.vyos_ospfv3: +    config: +    state: rendered + +- assert: +    that: +      - result.msg == 'value of config parameter must not be empty for state rendered' diff --git a/tests/integration/targets/vyos_ospfv3/tests/cli/gathered.yaml b/tests/integration/targets/vyos_ospfv3/tests/cli/gathered.yaml new file mode 100644 index 00000000..6645b99f --- /dev/null +++ b/tests/integration/targets/vyos_ospfv3/tests/cli/gathered.yaml @@ -0,0 +1,25 @@ +--- +- debug: +    msg: START vyos_ospfv3 gathered integration tests on connection={{ +      ansible_connection }} + +- include_tasks: _remove_config.yaml + +- include_tasks: _populate.yaml + +- block: + +    - name: Gather the provided configuration with the exisiting running configuration +      register: result +      vyos.vyos.vyos_ospfv3: +        config: +        state: gathered + +    - name: Assert that gathered dicts was correctly generated +      assert: +        that: +          - "{{ populate  == result['gathered'] }}" + +  always: + +    - include_tasks: _remove_config.yaml diff --git a/tests/integration/targets/vyos_ospfv3/tests/cli/merged.yaml b/tests/integration/targets/vyos_ospfv3/tests/cli/merged.yaml new file mode 100644 index 00000000..93095009 --- /dev/null +++ b/tests/integration/targets/vyos_ospfv3/tests/cli/merged.yaml @@ -0,0 +1,62 @@ +--- +- debug: +    msg: START vyos_ospfv3 merged integration tests on connection={{ ansible_connection +      }} + +- include_tasks: _remove_config.yaml + +- block: + +    - name: Merge the provided configuration with the exisiting running configuration +      register: result +      vyos.vyos.vyos_ospfv3: &id001 +        config: +          areas: +            - area_id: '2' +              export_list: 'export1' +              import_list: 'import1' +              range: +                - address: '2001:db10::/32' +                - address: '2001:db20::/32' +                - address: '2001:db30::/32' +            - area_id: '3' +              range: +                - address: '2001:db40::/32' +          parameters: +            router_id: '192.0.2.10' +          redistribute: +            - route_type: 'bgp' +        state: merged + +    - name: Assert that before dicts were correctly generated +      assert: +        that: "{{ merged['before'] == result['before'] }}" + +    - name: Assert that correct set of commands were generated +      assert: +        that: +          - "{{ merged['commands'] | symmetric_difference(result['commands']) |length\ +            \ == 0 }}" + +    - name: Assert that after dicts was correctly generated +      assert: +        that: +          - "{{ merged['after'] == result['after'] }}" + +    - name: Merge the provided configuration with the existing running configuration +        (IDEMPOTENT) +      register: result +      vyos.vyos.vyos_ospfv3: *id001 + +    - name: Assert that the previous task was idempotent +      assert: +        that: +          - result['changed'] == false + +    - name: Assert that before dicts were correctly generated +      assert: +        that: +          - "{{ merged['after'] == result['before'] }}" +  always: + +    - include_tasks: _remove_config.yaml diff --git a/tests/integration/targets/vyos_ospfv3/tests/cli/merged_update.yaml b/tests/integration/targets/vyos_ospfv3/tests/cli/merged_update.yaml new file mode 100644 index 00000000..0d506b37 --- /dev/null +++ b/tests/integration/targets/vyos_ospfv3/tests/cli/merged_update.yaml @@ -0,0 +1,61 @@ +--- +- debug: +    msg: START vyos_ospfv3 merged integration tests on connection={{ ansible_connection +      }} + +- include_tasks: _remove_config.yaml + +- include_tasks: _populate.yaml + +- block: + +    - name: Merge the provided configuration with the exisiting running configuration +      register: result +      vyos.vyos.vyos_ospfv3: &id001 +        config: +          areas: +            - area_id: '2' +              range: +                - address: '2001:db10::/32' +            - area_id: '3' +              range: +                - address: '2001:db40::/32' +                - address: '2001:db70::/32' +          parameters: +            router_id: '192.0.2.10' +          redistribute: +            - route_type: 'bgp' +        state: merged + +    - name: Assert that before dicts were correctly generated +      assert: +        that: "{{ populate == result['before'] }}" + +    - name: Assert that correct set of commands were generated +      assert: +        that: +          - "{{ merged_update['commands'] | symmetric_difference(result['commands']) |length\ +            \ == 0 }}" + +    - name: Assert that after dicts was correctly generated +      assert: +        that: +          - "{{ merged_update['after'] == result['after'] }}" + +    - name: Merge the provided configuration with the existing running configuration +        (IDEMPOTENT) +      register: result +      vyos.vyos.vyos_ospfv3: *id001 + +    - name: Assert that the previous task was idempotent +      assert: +        that: +          - result['changed'] == false + +    - name: Assert that before dicts were correctly generated +      assert: +        that: +          - "{{ merged_update['after'] == result['before'] }}" +  always: + +    - include_tasks: _remove_config.yaml diff --git a/tests/integration/targets/vyos_ospfv3/tests/cli/parsed.yaml b/tests/integration/targets/vyos_ospfv3/tests/cli/parsed.yaml new file mode 100644 index 00000000..62870831 --- /dev/null +++ b/tests/integration/targets/vyos_ospfv3/tests/cli/parsed.yaml @@ -0,0 +1,15 @@ +--- +- debug: +    msg: START vyos_ospfv3 parsed integration tests on connection={{ ansible_connection +      }} + +- name: Parse externally provided ospfv3 config to agnostic model +  register: result +  vyos.vyos.vyos_ospfv3: +    running_config: "{{ lookup('file', '_parsed_config.cfg') }}" +    state: parsed + +- name: Assert that config was correctly parsed +  assert: +    that: +      - "{{ parsed['after'] == result['parsed'] }}" diff --git a/tests/integration/targets/vyos_ospfv3/tests/cli/rendered.yaml b/tests/integration/targets/vyos_ospfv3/tests/cli/rendered.yaml new file mode 100644 index 00000000..3f714ced --- /dev/null +++ b/tests/integration/targets/vyos_ospfv3/tests/cli/rendered.yaml @@ -0,0 +1,38 @@ +--- +- debug: +    msg: START vyos_ospfv3 rendered integration tests on connection={{ +      ansible_connection }} + +- include_tasks: _remove_config.yaml + +- block: + +    - name: Structure provided configuration into device specific commands +      register: result +      vyos.vyos.vyos_ospfv3: +        config: +          redistribute: +            - route_type: 'bgp' +          parameters: +            router_id: '192.0.2.10' +          areas: +            - area_id: '2' +              export_list: 'export1' +              import_list: 'import1' +              range: +                - address: '2001:db10::/32' +                - address: '2001:db20::/32' +                - address: '2001:db30::/32' +            - area_id: '3' +              range: +                - address: '2001:db40::/32' +        state: rendered + +    - name: Assert that correct set of commands were generated +      assert: +        that: +          - "{{ rendered['commands'] | symmetric_difference(result['rendered'])\ +            \ |length == 0 }}" + +- debug: +    msg: END vyos_ospfv3 rendered integration tests on connection={{ ansible_connection }} diff --git a/tests/integration/targets/vyos_ospfv3/tests/cli/replaced.yaml b/tests/integration/targets/vyos_ospfv3/tests/cli/replaced.yaml new file mode 100644 index 00000000..74d25dbf --- /dev/null +++ b/tests/integration/targets/vyos_ospfv3/tests/cli/replaced.yaml @@ -0,0 +1,66 @@ +--- +- debug: +    msg: START vyos_ospfv3 replaced integration tests on connection={{ +      ansible_connection }} + +- include_tasks: _remove_config.yaml + +- include_tasks: _populate.yaml + +- block: + +    - name: Replace device configurations of listed ospfv3 routes with provided configurations +      register: result +      vyos.vyos.vyos_ospfv3: &id001 +        config: +          redistribute: +            - route_type: 'bgp' +          parameters: +            router_id: '192.0.2.10' +          areas: +            - area_id: '2' +              export_list: 'export1' +              import_list: 'import1' + +              range: +                - address: '2001:db10::/32' +                - address: '2001:db30::/32' +                - address: '2001:db50::/32' +            - area_id: '4' +              range: +                - address: '2001:db60::/32' +        state: replaced + +    - name: Assert that correct set of commands were generated +      assert: +        that: +          - "{{ replaced['commands'] | symmetric_difference(result['commands'])\ +            \ |length == 0 }}" + +    - name: Assert that before dicts are correctly generated +      assert: +        that: +          - "{{ populate == result['before'] }}" + +    - name: Assert that after dict is correctly generated +      assert: +        that: +          - "{{ replaced['after'] == result['after'] }}" + +    - name: Replace device configurations of listed ospfv3 routes with provided configurarions +        (IDEMPOTENT) +      register: result +      vyos.vyos.vyos_ospfv3: *id001 + +    - name: Assert that task was idempotent +      assert: +        that: +          - result['changed'] == false + +    - name: Assert that before dict is correctly generated +      assert: +        that: +          - "{{ replaced['after'] == result['before'] }}" +  always: + +    - include_tasks: _remove_config.yaml diff --git a/tests/integration/targets/vyos_ospfv3/tests/cli/rtt.yaml b/tests/integration/targets/vyos_ospfv3/tests/cli/rtt.yaml new file mode 100644 index 00000000..d8175540 --- /dev/null +++ b/tests/integration/targets/vyos_ospfv3/tests/cli/rtt.yaml @@ -0,0 +1,75 @@ +--- +- debug: +    msg: START vyos_ospfv3 round trip integration tests on connection={{ +      ansible_connection }} + +- include_tasks: _remove_config.yaml + +- block: + +    - name: Apply the provided configuration (base config) +      register: base_config +      vyos.vyos.vyos_ospfv3: +        config: +          areas: +            - area_id: '2' +              export_list: 'export1' +              import_list: 'import1' +              range: +                - address: '2001:db10::/32' +                - address: '2001:db20::/32' +                - address: '2001:db30::/32' +            - area_id: '3' +              range: +                - address: '2001:db40::/32' +          parameters: +            router_id: '192.0.2.10' +          redistribute: +            - route_type: 'bgp' +        state: merged + +    - name: Gather ospfv3 facts +      vyos.vyos.vyos_facts: +        gather_subset: +          - default +        gather_network_resources: +          - ospfv3 + +    - name: Apply the provided configuration (config to be reverted) +      register: result +      vyos.vyos.vyos_ospfv3: +        config: +          redistribute: +            - route_type: 'bgp' +          parameters: +            router_id: '192.0.2.10' +          areas: +            - area_id: '2' +              export_list: 'export1' +              import_list: 'import1' + +              range: +                - address: '2001:db10::/32' +                - address: '2001:db30::/32' +                - address: '2001:db50::/32' +            - area_id: '4' +              range: +                - address: '2001:db60::/32' +        state: replaced + +    - name: Assert that changes were applied +      assert: +        that: "{{ round_trip['after'] == result['after'] }}" + +    - name: Revert back to base config using facts round trip +      register: revert +      vyos.vyos.vyos_ospfv3: +        config: "{{ ansible_facts['network_resources']['ospfv3'] }}" +        state: replaced + +    - name: Assert that config was reverted +      assert: +        that: "{{ base_config['after'] == revert['after']}}" +  always: + +    - include_tasks: _remove_config.yaml diff --git a/tests/integration/targets/vyos_ospfv3/vars/main.yaml b/tests/integration/targets/vyos_ospfv3/vars/main.yaml new file mode 100644 index 00000000..6ded89a8 --- /dev/null +++ b/tests/integration/targets/vyos_ospfv3/vars/main.yaml @@ -0,0 +1,142 @@ +--- +merged: +  before: {} +  commands: +    - set protocols ospfv3 redistribute bgp +    - set protocols ospfv3 parameters router-id '192.0.2.10' +    - set protocols ospfv3 area 2 range 2001:db10::/32 +    - set protocols ospfv3 area 2 range 2001:db20::/32 +    - set protocols ospfv3 area 2 range 2001:db30::/32 +    - set protocols ospfv3 area '2' +    - set protocols ospfv3 area 2 export-list export1 +    - set protocols ospfv3 area 2 import-list import1 +    - set protocols ospfv3 area '3' +    - set protocols ospfv3 area 3 range 2001:db40::/32 +  after: +    areas: +      - area_id: '2' +        export_list: 'export1' +        import_list: 'import1' +        range: +          - address: '2001:db10::/32' +          - address: '2001:db20::/32' +          - address: '2001:db30::/32' +      - area_id: '3' +        range: +          - address: '2001:db40::/32' +    parameters: +      router_id: '192.0.2.10' +    redistribute: +      - route_type: 'bgp' + + +merged_update: +  commands: +    - set protocols ospfv3 area 3 range 2001:db70::/32 +  after: +    areas: +      - area_id: '2' +        export_list: 'export1' +        import_list: 'import1' +        range: +          - address: '2001:db10::/32' +          - address: '2001:db20::/32' +          - address: '2001:db30::/32' +      - area_id: '3' +        range: +          - address: '2001:db40::/32' +          - address: '2001:db70::/32' +    parameters: +      router_id: '192.0.2.10' +    redistribute: +      - route_type: 'bgp' + +populate: +  areas: +    - area_id: '2' +      export_list: 'export1' +      import_list: 'import1' +      range: +        - address: '2001:db10::/32' +        - address: '2001:db20::/32' +        - address: '2001:db30::/32' +    - area_id: '3' +      range: +        - address: '2001:db40::/32' +  parameters: +    router_id: '192.0.2.10' +  redistribute: +    - route_type: 'bgp' +replaced: +  commands: +    - delete protocols ospfv3 area 2 range 2001:db20::/32 +    - delete protocols ospfv3 area 3 +    - set protocols ospfv3 area 2 range 2001:db50::/32 +    - set protocols ospfv3 area '4' +    - set protocols ospfv3 area 4 range 2001:db60::/32 +  after: +    areas: +      - area_id: '2' +        export_list: 'export1' +        import_list: 'import1' +        range: +          - address: '2001:db10::/32' +          - address: '2001:db30::/32' +          - address: '2001:db50::/32' +      - area_id: '4' +        range: +          - address: '2001:db60::/32' +    parameters: +      router_id: '192.0.2.10' +    redistribute: +      - route_type: 'bgp' +rendered: +  commands: +    - set protocols ospfv3 redistribute bgp +    - set protocols ospfv3 parameters router-id '192.0.2.10' +    - set protocols ospfv3 area 2 range 2001:db10::/32 +    - set protocols ospfv3 area 2 range 2001:db20::/32 +    - set protocols ospfv3 area 2 range 2001:db30::/32 +    - set protocols ospfv3 area '2' +    - set protocols ospfv3 area 2 export-list export1 +    - set protocols ospfv3 area 2 import-list import1 +    - set protocols ospfv3 area '3' +    - set protocols ospfv3 area 3 range 2001:db40::/32 +parsed: +  after: +    areas: +      - area_id: '2' +        export_list: 'export1' +        import_list: 'import1' +        range: +          - address: '2001:db10::/32' +          - address: '2001:db20::/32' +          - address: '2001:db30::/32' +      - area_id: '3' +        range: +          - address: '2001:db40::/32' +    parameters: +      router_id: '192.0.2.10' +    redistribute: +      - route_type: 'bgp' +deleted: +  commands: +    - 'delete protocols ospfv3' +  after: {} +round_trip: +  after: +    areas: +      - area_id: '2' +        export_list: 'export1' +        import_list: 'import1' +        range: +          - address: '2001:db10::/32' +          - address: '2001:db30::/32' +          - address: '2001:db50::/32' +      - area_id: '4' +        range: +          - address: '2001:db60::/32' +    parameters: +      router_id: '192.0.2.10' +    redistribute: +      - route_type: 'bgp' diff --git a/tests/unit/modules/network/vyos/fixtures/vyos_ospfv3_config.cfg b/tests/unit/modules/network/vyos/fixtures/vyos_ospfv3_config.cfg new file mode 100644 index 00000000..060b9b33 --- /dev/null +++ b/tests/unit/modules/network/vyos/fixtures/vyos_ospfv3_config.cfg @@ -0,0 +1,6 @@ +set protocols ospfv3 area 12 export-list 'export1' +set protocols ospfv3 area 12 import-list 'import1' +set protocols ospfv3 area 12 range '2001:db11::/32' +set protocols ospfv3 area 12 range '2001:db22::/32' +set protocols ospfv3 area 12 range '2001:db33::/32' +set protocols ospfv3 area 13 range '2001:db44::/32'
\ No newline at end of file diff --git a/tests/unit/modules/network/vyos/test_vyos_ospfv3.py b/tests/unit/modules/network/vyos/test_vyos_ospfv3.py new file mode 100644 index 00000000..1d9cb3ab --- /dev/null +++ b/tests/unit/modules/network/vyos/test_vyos_ospfv3.py @@ -0,0 +1,348 @@ +# (c) 2016 Red Hat Inc. +# +# This file is part of Ansible +# +# Ansible is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Ansible is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Ansible.  If not, see <http://www.gnu.org/licenses/>. + +# Make coding more python3-ish +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + +from ansible_collections.vyos.vyos.tests.unit.compat.mock import patch +from ansible_collections.vyos.vyos.plugins.modules import vyos_ospfv3 +from ansible_collections.vyos.vyos.tests.unit.modules.utils import ( +    set_module_args, +) +from .vyos_module import TestVyosModule, load_fixture + + +class TestVyosFirewallRulesModule(TestVyosModule): + +    module = vyos_ospfv3 + +    def setUp(self): +        super(TestVyosFirewallRulesModule, self).setUp() +        self.mock_get_config = patch( +            "ansible_collections.ansible.netcommon.plugins.module_utils.network.common.network.Config.get_config" +        ) +        self.get_config = self.mock_get_config.start() + +        self.mock_load_config = patch( +            "ansible_collections.ansible.netcommon.plugins.module_utils.network.common.network.Config.load_config" +        ) +        self.load_config = self.mock_load_config.start() + +        self.mock_get_resource_connection_config = patch( +            "ansible_collections.ansible.netcommon.plugins.module_utils.network.common.cfg.base.get_resource_connection" +        ) +        self.get_resource_connection_config = ( +            self.mock_get_resource_connection_config.start() +        ) + +        self.mock_get_resource_connection_facts = patch( +            "ansible_collections.ansible.netcommon.plugins.module_utils.network.common.facts.facts.get_resource_connection" +        ) +        self.get_resource_connection_facts = ( +            self.mock_get_resource_connection_facts.start() +        ) + +        self.mock_execute_show_command = patch( +            "ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.facts.ospfv3.ospfv3.Ospfv3Facts.get_device_data" +        ) + +        self.execute_show_command = self.mock_execute_show_command.start() + +    def tearDown(self): +        super(TestVyosFirewallRulesModule, self).tearDown() +        self.mock_get_resource_connection_config.stop() +        self.mock_get_resource_connection_facts.stop() +        self.mock_get_config.stop() +        self.mock_load_config.stop() +        self.mock_execute_show_command.stop() + +    def load_fixtures(self, commands=None, transport="cli", filename=None): +        if filename is None: +            filename = "vyos_ospfv3_config.cfg" + +        def load_from_file(*args, **kwargs): +            output = load_fixture(filename) +            return output + +        self.execute_show_command.side_effect = load_from_file + +    def test_vyos_ospfv3_merged_new_config(self): +        set_module_args( +            dict( +                config=dict( +                    redistribute=[dict(route_type="bgp")], +                    parameters=dict(router_id="192.0.2.10"), +                    areas=[ +                        dict( +                            area_id="2", +                            export_list="export1", +                            import_list="import1", +                            range=[ +                                dict(address="2001:db10::/32"), +                                dict(address="2001:db20::/32"), +                                dict(address="2001:db30::/32"), +                            ], +                        ), +                        dict( +                            area_id="3", +                            range=[dict(address="2001:db40::/32"),], +                        ), +                    ], +                ), +                state="merged", +            ) +        ) +        commands = [ +            "set protocols ospfv3 redistribute bgp", +            "set protocols ospfv3 parameters router-id '192.0.2.10'", +            "set protocols ospfv3 area 2 range 2001:db10::/32", +            "set protocols ospfv3 area 2 range 2001:db20::/32", +            "set protocols ospfv3 area 2 range 2001:db30::/32", +            "set protocols ospfv3 area '2'", +            "set protocols ospfv3 area 2 export-list export1", +            "set protocols ospfv3 area 2 import-list import1", +            "set protocols ospfv3 area '3'", +            "set protocols ospfv3 area 3 range 2001:db40::/32", +        ] +        self.execute_module(changed=True, commands=commands) + +    def test_vyos_ospfv3_merged_idem(self): +        set_module_args( +            dict( +                config=dict( +                    areas=[ +                        dict( +                            area_id="12", +                            export_list="export1", +                            import_list="import1", +                            range=[ +                                dict(address="2001:db11::/32"), +                                dict(address="2001:db22::/32"), +                                dict(address="2001:db33::/32"), +                            ], +                        ), +                        dict( +                            area_id="13", +                            range=[dict(address="2001:db44::/32"),], +                        ), +                    ], +                ), +                state="merged", +            ) +        ) +        self.execute_module(changed=False, commands=[]) + +    def test_vyos_ospfv3_merged_update_existing(self): +        set_module_args( +            dict( +                config=dict( +                    redistribute=[dict(route_type="bgp")], +                    parameters=dict(router_id="192.0.2.10"), +                    areas=[ +                        dict( +                            area_id="12", +                            export_list="export1", +                            import_list="import1", +                            range=[ +                                dict(address="2001:db11::/32"), +                                dict(address="2001:db22::/32"), +                                dict(address="2001:db33::/32"), +                            ], +                        ), +                        dict( +                            area_id="13", +                            range=[ +                                dict(address="2001:db44::/32"), +                                dict(address="2001:db55::/32"), +                            ], +                        ), +                    ], +                ), +                state="merged", +            ) +        ) +        commands = [ +            "set protocols ospfv3 redistribute bgp", +            "set protocols ospfv3 parameters router-id '192.0.2.10'", +            "set protocols ospfv3 area 13 range 2001:db55::/32", +        ] +        self.execute_module(changed=True, commands=commands) + +    def test_vyos_ospfv3_replaced(self): +        set_module_args( +            dict( +                config=dict( +                    redistribute=[dict(route_type="bgp")], +                    parameters=dict(router_id="192.0.2.10"), +                    areas=[ +                        dict( +                            area_id="12", +                            export_list="export1", +                            import_list="import1", +                            range=[ +                                dict(address="2001:db10::/32"), +                                dict(address="2001:db22::/32"), +                                dict(address="2001:db33::/32"), +                            ], +                        ), +                        dict( +                            area_id="14", +                            range=[dict(address="2001:db40::/32"),], +                        ), +                    ], +                ), +                state="replaced", +            ) +        ) +        commands = [ +            "set protocols ospfv3 redistribute bgp", +            "set protocols ospfv3 parameters router-id '192.0.2.10'", +            "delete protocols ospfv3 area 12 range 2001:db11::/32", +            "set protocols ospfv3 area 12 range 2001:db10::/32", +            "delete protocols ospfv3 area 13", +            "set protocols ospfv3 area '14'", +            "set protocols ospfv3 area 14 range 2001:db40::/32", +        ] +        self.execute_module(changed=True, commands=commands) + +    def test_vyos_ospfv3_replaced_idem(self): +        set_module_args( +            dict( +                config=dict( +                    areas=[ +                        dict( +                            area_id="12", +                            export_list="export1", +                            import_list="import1", +                            range=[ +                                dict(address="2001:db11::/32"), +                                dict(address="2001:db22::/32"), +                                dict(address="2001:db33::/32"), +                            ], +                        ), +                        dict( +                            area_id="13", +                            range=[dict(address="2001:db44::/32"),], +                        ), +                    ], +                ), +                state="replaced", +            ) +        ) +        self.execute_module(changed=False, commands=[]) + +    def test_vyos_ospfv3_deleted_no_config(self): +        set_module_args(dict(config=None, state="deleted")) +        commands = ["delete protocols ospfv3"] +        self.execute_module(changed=True, commands=commands) + +    def test_vyos_ospfv3_gathered(self): +        set_module_args(dict(state="gathered")) +        result = self.execute_module( +            changed=False, filename="vyos_ospfv3_config.cfg" +        ) +        gather_dict = { +            "areas": [ +                { +                    "area_id": "12", +                    "export_list": "export1", +                    "import_list": "import1", +                    "range": [ +                        {"address": "2001:db11::/32"}, +                        {"address": "2001:db22::/32"}, +                        {"address": "2001:db33::/32"}, +                    ], +                }, +                {"area_id": "13", "range": [{"address": "2001:db44::/32"}]}, +            ], +        } +        self.assertEqual(sorted(gather_dict), sorted(result["gathered"])) + +    def test_vyos_ospfv3_parsed(self): +        parsed_str = """set protocols ospfv3 area 2 export-list 'export1' +set protocols ospfv3 area 2 import-list 'import1' +set protocols ospfv3 area 2 range '2001:db10::/32' +set protocols ospfv3 area 2 range '2001:db20::/32' +set protocols ospfv3 area 2 range '2001:db30::/32' +set protocols ospfv3 area 3 range '2001:db40::/32' +set protocols ospfv3 parameters router-id '192.0.2.10' +set protocols ospfv3 redistribute 'bgp'""" +        set_module_args(dict(running_config=parsed_str, state="parsed")) +        result = self.execute_module(changed=False) +        parsed_dict = { +            "areas": [ +                { +                    "area_id": "2", +                    "export_list": "export1", +                    "import_list": "import1", +                    "range": [ +                        {"address": "2001:db10::/32"}, +                        {"address": "2001:db20::/32"}, +                        {"address": "2001:db30::/32"}, +                    ], +                }, +                {"area_id": "3", "range": [{"address": "2001:db40::/32"}]}, +            ], +            "parameters": {"router_id": "192.0.2.10"}, +            "redistribute": [{"route_type": "bgp"}], +        } +        self.assertEqual(sorted(parsed_dict), sorted(result["parsed"])) + +    def test_vyos_ospfv3_rendered(self): +        set_module_args( +            dict( +                config=dict( +                    redistribute=[dict(route_type="bgp")], +                    parameters=dict(router_id="192.0.2.10"), +                    areas=[ +                        dict( +                            area_id="2", +                            export_list="export1", +                            import_list="import1", +                            range=[ +                                dict(address="2001:db10::/32"), +                                dict(address="2001:db20::/32"), +                                dict(address="2001:db30::/32"), +                            ], +                        ), +                        dict( +                            area_id="3", +                            range=[dict(address="2001:db40::/32"),], +                        ), +                    ], +                ), +                state="rendered", +            ) +        ) +        commands = [ +            "set protocols ospfv3 redistribute bgp", +            "set protocols ospfv3 parameters router-id '192.0.2.10'", +            "set protocols ospfv3 area 2 range 2001:db10::/32", +            "set protocols ospfv3 area 2 range 2001:db20::/32", +            "set protocols ospfv3 area 2 range 2001:db30::/32", +            "set protocols ospfv3 area '2'", +            "set protocols ospfv3 area 2 export-list export1", +            "set protocols ospfv3 area 2 import-list import1", +            "set protocols ospfv3 area '3'", +            "set protocols ospfv3 area 3 range 2001:db40::/32", +        ] +        result = self.execute_module(changed=False) +        self.assertEqual( +            sorted(result["rendered"]), sorted(commands), result["rendered"] +        ) diff --git a/tests/unit/modules/network/vyos/vyos_module.py b/tests/unit/modules/network/vyos/vyos_module.py index fb15c715..49d46522 100644 --- a/tests/unit/modules/network/vyos/vyos_module.py +++ b/tests/unit/modules/network/vyos/vyos_module.py @@ -60,6 +60,7 @@ class TestVyosModule(ModuleTestCase):          commands=None,          sort=True,          defaults=False, +        filename=None,      ):          self.load_fixtures(commands) | 
