diff --git a/plugins/module_utils/network/vyos/argspec/ospfv3/ospfv3.py b/plugins/module_utils/network/vyos/argspec/ospfv3/ospfv3.py index b0166d8..60e208c 100644 --- a/plugins/module_utils/network/vyos/argspec/ospfv3/ospfv3.py +++ b/plugins/module_utils/network/vyos/argspec/ospfv3/ospfv3.py @@ -1,106 +1,108 @@ # # -*- 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': { - 'elements': 'dict', 'options': { - 'ospf_area': { + 'areas': { 'elements': 'dict', 'options': { - 'area': { + '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': 'list' + 'type': 'dict' + }, + 'running_config': { + 'type': 'str' }, "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/ospfv3.py b/plugins/module_utils/network/vyos/config/ospfv3/ospfv3.py index fa869da..3875763 100644 --- a/plugins/module_utils/network/vyos/config/ospfv3/ospfv3.py +++ b/plugins/module_utils/network/vyos/config/ospfv3/ospfv3.py @@ -1,446 +1,414 @@ # # -*- 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 +import q + 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 ( list_diff_want_only, _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') if not ospfv3_facts: return [] 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 == "overridden": commands.extend(self._state_overridden(w, h)) elif self.state == "deleted": commands.extend(self._state_deleted(w, h)) - elif w: - if self.state == "merged" or self.state == "rendered": - for w_item in w: - commands.extend(self._state_merged(w_item, h)) - elif self.state == "replaced": - for w_item in w: - commands.extend(self._state_replaced(w_item, 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 search_obj_in_have(self, have, w_name, key): """ This function returns the rule-set/rule if it is present in target config. :param have: target config. :param w_name: rule-set name. :param type: rule_sets/rule/r_list. :return: rule-set/rule. """ if have: for item in have: if item[key] == w_name[key]: return item return None + def search_obj_in_list(name, lst, key="name"): + if not lst: + return None + else: + for item in lst: + if item.get(key) == name: + return item + ''' + 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 = [] - h_item = {} if have: - h_item = have[0] - commands.extend(self._render_ospf_param(h_item, want, opr=False)) - commands.extend(self._render_ospf_param(want, h_item)) + 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 = [] - h_item = {} - if have: - h_item = have[0] - commands.extend(self._render_ospf_param(want, h_item)) + 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 want: - for w in want: + if have: if have: - h = have[0] - if h: - for key, val in iteritems(w): - if key in h: - if key == 'ospf_area': - key = 'area' - commands.append(self._compute_command(attr=key, opr=False)) - elif have and have[0]: + for key, val in iteritems(want): + if key in have: + if key == 'areas': + key = 'area' + commands.append(self._compute_command(attr=key, opr=False)) + elif 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 == 'ospf_area': - commands.extend(self._render_ospf_area(key, w, h, opr=opr)) + 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_param(self, attr, want, have, cmd=None, opr=True): - """ - This function forms the commands for passed target list attributes'. - :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 list of commands. - """ - commands = [] - h = [] - if want: - w = want.get(attr) or [] - if have: - h = have.get(attr) or [] - if not cmd: - cmd = self._compute_command(opr=opr) - if w: - if opr: - members = list_diff_want_only(w, h) - for member in members: - command = cmd + attr.replace("_","-") + " " - if attr == 'network': - command += member['address'] - else: - command += member - commands.append(command) - elif not opr: - if h: - for member in w: - if attr == 'network': - if not self.search_obj_in_have(h, member, 'address'): - commands.append(cmd + attr.replace("_","-") + ' ' + member['address']) - elif member not in h: - commands.append(cmd + attr.replace("_","-") + ' ' + member) - else: - commands.append(cmd + " " + attr.replace("_","-")) - 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): + q(key) + q(val) + q(name[attr]) + q(w_item) + q(attr) if not cmd: cmd = self._compute_command(opr=opr) - h_item = self.search_obj_in_have(h, w_item, name[attr]) + 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 in ('route_type', 'address'): + if key == 'route_type' or (key == 'address' and not ('advertise', 'not-advertise') not in w_item): commands.append(cmd + attr + ' ' + str(val)) - elif key in leaf_dict['range']: - commands.append(cmd + attr + ' ' + w_item[name[attr]] + ' ' + key.replace("_","-")) - else: + 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)) + q(commands) return commands - def _render_ospf_area(self, attr, want, have, opr=True): + 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") + 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']), opr=opr) + ' ' - h_area = self.search_obj_in_have(h_lst, w_area, 'area') + 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'], opr=opr)) + 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': - commands.append(self._form_attr_cmd(attr=key, val=_bool_to_str(val), opr=opr)) + if key == 'area_id': + commands.append(self._form_attr_cmd(attr='area', val=_bool_to_str(val), opr=opr)) else: - commands.append(cmd + key + ' ' + _bool_to_str(val).replace("_","-")) + commands.append(cmd + key.replace("_", "-") + ' ' + _bool_to_str(val).replace("_", "-")) elif not opr and key in l_set: - if key == 'area' and not _in_target(h_area, key): + if key == 'area_id' and not _in_target(h_area, key): commands.append(cmd) continue - elif key != 'area' and not _in_target(h_area, key): + 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/ospfv3/ospfv3.py b/plugins/module_utils/network/vyos/facts/ospfv3/ospfv3.py index 9bb7c0a..a26f9e7 100644 --- a/plugins/module_utils/network/vyos/facts/ospfv3/ospfv3.py +++ b/plugins/module_utils/network/vyos/facts/ospfv3/ospfv3.py @@ -1,193 +1,197 @@ # # -*- 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 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["ospf_area"] = self.parse_attrib_list(conf, "area", "area") + 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. """ - cfg_dict = {"range": self.parse_attrib_list(conf, "range", "address")} - return cfg_dict + + 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/modules/vyos_ospfv3.py b/plugins/modules/vyos_ospfv3.py index 5b4b846..e620fe1 100644 --- a/plugins/modules/vyos_ospfv3.py +++ b/plugins/modules/vyos_ospfv3.py @@ -1,181 +1,184 @@ #!/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', 'status': ['preview'], 'supported_by': 'network' } DOCUMENTATION = """ --- module: vyos_ospfv3 version_added: 2.10 -short_description: Manages attributes of OSPF IPv6 routes on VyOS network devices. -description: This module manages attributes of OSPF IPv6 routes on VyOS network devices. +short_description: OSPFv3 resource module. +description: This resource module configures and manages attributes of OSPFv3 routes on VyOS network devices. author: Rohit Thakur (@rohitthakur2590) options: config: - description: A provided OSPF route configuration. - type: list - elements: dict + description: A provided OSPFv3 route configuration. + type: dict suboptions: - ospf_area: - description: OSPF area. + areas: + description: OSPFv3 area. type: list elements: dict suboptions: - area: - description: Area name/identity. + 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: + - The configuration to be parsed. + type: str state: description: - The state the configuration should be left in. type: str choices: - merged - replaced - deleted - parsed - gathered - rendered default: merged """ EXAMPLES = """ """ RETURN = """ before: description: The configuration prior to the model invocation. returned: always 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 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: ['command 1', 'command 2', 'command 3'] """ 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", "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()