diff options
Diffstat (limited to 'plugins')
| -rw-r--r-- | plugins/module_utils/network/vyos/argspec/ospfv3/__init__.py | 0 | ||||
| -rw-r--r-- | plugins/module_utils/network/vyos/argspec/ospfv3/ospfv3.py | 94 | ||||
| -rw-r--r-- | plugins/module_utils/network/vyos/config/ospfv3/__init__.py | 0 | ||||
| -rw-r--r-- | plugins/module_utils/network/vyos/config/ospfv3/ospfv3.py | 464 | ||||
| -rw-r--r-- | plugins/module_utils/network/vyos/facts/facts.py | 4 | ||||
| -rw-r--r-- | plugins/module_utils/network/vyos/facts/ospfv3/__init__.py | 0 | ||||
| -rw-r--r-- | plugins/module_utils/network/vyos/facts/ospfv3/ospfv3.py | 213 | ||||
| -rw-r--r-- | plugins/module_utils/network/vyos/utils/utils.py | 39 | ||||
| -rw-r--r-- | plugins/modules/vyos_facts.py | 2 | ||||
| -rw-r--r-- | plugins/modules/vyos_ospfv3.py | 667 | 
10 files changed, 1481 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() | 
