diff --git a/.git-blame-ignore-revs b/.git-blame-ignore-revs new file mode 100644 index 00000000..dedbdc55 --- /dev/null +++ b/.git-blame-ignore-revs @@ -0,0 +1,4 @@ +# Formatting commits - ignore in git blame +# style: apply black formatting across entire codebase +# NOTE: Update this hash after the formatting PR is merged +221ac461e4b3dcf37629f4cce89e45a59ace873c diff --git a/.github/workflows/codecoverage.yml b/.github/workflows/codecoverage.yml index 8ce3af36..ee71e179 100644 --- a/.github/workflows/codecoverage.yml +++ b/.github/workflows/codecoverage.yml @@ -1,71 +1,71 @@ --- name: Code Coverage # cloned from ansible-network/github_actions/.github/workflows/coverage_network_devices.yml@main # in order to deal with token issue in codecov on: # yamllint disable-line rule:truthy push: pull_request: branches: [main] jobs: codecoverage: env: PY_COLORS: "1" source_directory: "./source" python_version: "3.10" ansible_version: "latest" os: "ubuntu-latest" collection_pre_install: >- git+https://github.com/ansible-collections/ansible.utils.git git+https://github.com/ansible-collections/ansible.netcommon.git runs-on: ubuntu-latest name: "Code Coverage | Python 3.10" steps: - name: Checkout the collection repository uses: ansible-network/github_actions/.github/actions/checkout_dependency@main with: path: ${{ env.source_directory }} ref: ${{ github.event.pull_request.head.sha }} fetch-depth: "0" - name: Set up Python ${{ env.python_version }} uses: actions/setup-python@v6 with: python-version: ${{ env.python_version }} - name: Install ansible-core (${{ env.ansible-version }}) run: python3 -m pip install ansible-core pytest pytest-cov pytest-ansible-units pytest-forked pytest-xdist - name: Read collection metadata from galaxy.yml id: identify uses: ansible-network/github_actions/.github/actions/identify_collection@main with: source_path: ${{ env.source_directory }} - name: Build and install the collection uses: ansible-network/github_actions/.github/actions/build_install_collection@main with: install_python_dependencies: true source_path: ${{ env.source_directory }} collection_path: ${{ steps.identify.outputs.collection_path }} tar_file: ${{ steps.identify.outputs.tar_file }} - name: Print the ansible version run: ansible --version - name: Print the python dependencies run: python3 -m pip list - name: Run Coverage tests run: | pytest tests/unit -v --cov-report xml --cov=./ working-directory: ${{ steps.identify.outputs.collection_path }} - name: Upload coverage report to Codecov - uses: codecov/codecov-action@v6 + uses: codecov/codecov-action@v7 with: directory: ${{ steps.identify.outputs.collection_path }} fail_ci_if_error: false token: ${{ secrets.CODECOV_TOKEN }} env: CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml new file mode 100644 index 00000000..b83b94e0 --- /dev/null +++ b/.github/workflows/codeql.yml @@ -0,0 +1,30 @@ +name: "Perform CodeQL Analysis" + +on: + push: + branches: + - main + paths: + - '**' + - '!.github/**' + - '!**/*.md' + pull_request: + branches: + - main + paths: + - '**' + - '!.github/**' + - '!**/*.md' + schedule: + - cron: '52 13 * * 0' + +permissions: + actions: read + contents: read + security-events: write + +jobs: + codeql-analysis-call: + uses: vyos/.github/.github/workflows/codeql-analysis.yml@production + with: + languages: "['python']" diff --git a/changelogs/fragments/T8609_rm_templates_regex_backtracking.yml b/changelogs/fragments/T8609_rm_templates_regex_backtracking.yml new file mode 100644 index 00000000..b02dbf19 --- /dev/null +++ b/changelogs/fragments/T8609_rm_templates_regex_backtracking.yml @@ -0,0 +1,12 @@ +--- +bugfixes: + - bgp_address_family.py - Fix slow parse() to stop regex backtracking on prefix-sharing inputs. + - bgp_address_family_14.py - Fix slow parse() to stop regex backtracking on prefix-sharing inputs. + - bgp_global.py - Fix slow parse() to stop regex backtracking on prefix-sharing inputs. + - bgp_global_14.py - Fix slow parse() to stop regex backtracking on prefix-sharing inputs. + - ospf_interfaces.py - Fix slow parse() to stop regex backtracking on prefix-sharing inputs. + - ospf_interfaces_14.py - Fix slow parse() to stop regex backtracking on prefix-sharing inputs. + - route_maps.py - Fix slow parse() to stop regex backtracking on prefix-sharing inputs. + - route_maps_14.py - Fix slow parse() to stop regex backtracking on prefix-sharing inputs. + - snmp_server.py - Fix slow parse() to stop regex backtracking on prefix-sharing inputs. + - test_rm_templates_perf.py - Add unit test for the bugfixes diff --git a/changelogs/fragments/T9082-codeql-workflow.yml b/changelogs/fragments/T9082-codeql-workflow.yml new file mode 100644 index 00000000..5d09acd7 --- /dev/null +++ b/changelogs/fragments/T9082-codeql-workflow.yml @@ -0,0 +1,2 @@ +trivial: + - Add CodeQL analysis workflow calling the VyOS org-wide central reusable (T9082). diff --git a/changelogs/fragments/fix-icmp-parse-attr.yml b/changelogs/fragments/fix-icmp-parse-attr.yml new file mode 100644 index 00000000..5cf0e199 --- /dev/null +++ b/changelogs/fragments/fix-icmp-parse-attr.yml @@ -0,0 +1,5 @@ +--- +bugfixes: + - firewall_rules - fix parse_icmp_attr() using wrong split delimiter ('.' instead of '/') + and referencing undefined variable type_no in the numeric-only branch, which caused + ValueError or UnboundLocalError when gathering firewall rules with ICMP type conditions. diff --git a/changelogs/fragments/formatting-compliance.yml b/changelogs/fragments/formatting-compliance.yml new file mode 100644 index 00000000..d48896a9 --- /dev/null +++ b/changelogs/fragments/formatting-compliance.yml @@ -0,0 +1,3 @@ +--- +trivial: + - Add .git-blame-ignore-revs to exclude bulk formatting commits from git blame output. diff --git a/changelogs/fragments/vyos-user-quote-plaintext-password.yml b/changelogs/fragments/vyos-user-quote-plaintext-password.yml new file mode 100644 index 00000000..487b592a --- /dev/null +++ b/changelogs/fragments/vyos-user-quote-plaintext-password.yml @@ -0,0 +1,3 @@ +--- +bugfixes: + - vyos_user - Quote and escape plaintext-password values in set commands so VyOS accepts special characters and embedded single quotes. diff --git a/plugins/module_utils/network/vyos/facts/firewall_rules/firewall_rules.py b/plugins/module_utils/network/vyos/facts/firewall_rules/firewall_rules.py index 270b4a62..f8f02e7a 100644 --- a/plugins/module_utils/network/vyos/facts/firewall_rules/firewall_rules.py +++ b/plugins/module_utils/network/vyos/facts/firewall_rules/firewall_rules.py @@ -1,544 +1,544 @@ # # -*- 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 firewall_rules 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 copy import deepcopy from re import M, findall, search from ansible_collections.ansible.netcommon.plugins.module_utils.network.common import utils from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.argspec.firewall_rules.firewall_rules import ( Firewall_rulesArgs, ) class Firewall_rulesFacts(object): """The vyos firewall_rules fact class""" def __init__(self, module, subspec="config", options="options"): self._module = module self.argument_spec = Firewall_rulesArgs.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 firewall_rules :param connection: the device connection :param ansible_facts: Facts dictionary :param data: previously collected conf :rtype: dictionary :returns: facts """ if not data: # typically data is populated from the current device configuration # data = connection.get('show running-config | section ^interface') # using mock data instead data = self.get_device_data(connection) # split the config into instances of the resource objs = [] # check 1.4+ first new_rules = True v6_rules = findall( r"^set firewall ipv6 (name|forward|input|output) (?:\'*)(\S+)(?:\'*)", data, M, ) if not v6_rules: v6_rules = findall(r"^set firewall ipv6-name (?:\'*)(\S+)(?:\'*)", data, M) if v6_rules: new_rules = False v4_rules = findall( r"^set firewall ipv4 (name|forward|input|output) (?:\'*)(\S+)(?:\'*)", data, M, ) if not v4_rules: v4_rules = findall(r"^set firewall name (?:\'*)(\S+)(?:\'*)", data, M) if v4_rules: new_rules = False if v6_rules: if new_rules: config = self.get_rules_post_1_4(data, v6_rules, type="ipv6") else: config = self.get_rules(data, v6_rules, type="ipv6") if config: config = utils.remove_empties(config) objs.append(config) if v4_rules: if new_rules: config = self.get_rules_post_1_4(data, v4_rules, type="ipv4") else: config = self.get_rules(data, v4_rules, type="ipv4") if config: config = utils.remove_empties(config) objs.append(config) ansible_facts["ansible_network_resources"].pop("firewall_rules", None) facts = {} if objs: facts["firewall_rules"] = [] params = utils.validate_config(self.argument_spec, {"config": objs}) for cfg in params["config"]: facts["firewall_rules"].append(utils.remove_empties(cfg)) ansible_facts["ansible_network_resources"].update(facts) return ansible_facts def get_rules(self, data, rules, type): """ This function performs following: - Form regex to fetch 'rule-sets' specific config from data. - Form the rule-set list based on ip address. :param data: configuration. :param rules: list of rule-sets. :param type: ip address type. :return: generated rule-sets configuration. """ r_v4 = [] r_v6 = [] for r in set(rules): name_key = "ipv6-name" if type == "ipv6" else "name" rule_regex = r" %s %s .+$" % (name_key, r.strip("'")) cfg = findall(rule_regex, data, M) fr = self.render_config(cfg, r.strip("'")) fr["name"] = r.strip("'") if type == "ipv6": r_v6.append(fr) else: r_v4.append(fr) if r_v4: config = {"afi": "ipv4", "rule_sets": r_v4} if r_v6: config = {"afi": "ipv6", "rule_sets": r_v6} return config def get_rules_post_1_4(self, data, rules, type): """ This function performs following: - Form regex to fetch 'rule-sets' specific config from data. - Form the rule-set list based on ip address. Specifically for v1.4+ version. :param data: configuration. :param rules: list of rule-sets. :param type: ip address type. :return: generated rule-sets configuration. """ r_v4 = [] r_v6 = [] for kind, name in set(rules): rule_regex = r" %s %s %s .+$" % (type, kind, name.strip("'")) cfg = findall(rule_regex, data, M) fr = self.render_config(cfg, name.strip("'")) if kind == "name": fr["name"] = name.strip("'") elif kind in ("forward", "input", "output"): fr["filter"] = kind else: raise ValueError("Unknown rule kind: %s %s" % kind, name) if type == "ipv6": r_v6.append(fr) else: r_v4.append(fr) if r_v4: config = {"afi": "ipv4", "rule_sets": r_v4} if r_v6: config = {"afi": "ipv6", "rule_sets": r_v6} return config def render_config(self, conf, match): """ Render config as dictionary structure and delete keys from spec for null values :param spec: The facts tree, generated from the argspec :param conf: The configuration :rtype: dictionary :returns: The generated config """ conf = "\n".join(filter(lambda x: x, conf)) a_lst = [ "description", "default_action", "default_jump_target", "enable_default_log", "default_log", ] config = self.parse_attr(conf, a_lst, match) if not config: config = {} if "default_log" in config: config["enable_default_log"] = config.pop("default_log") config["rules"] = self.parse_rules_lst(conf) return config def parse_rules_lst(self, conf): """ This function forms the regex to fetch the 'rules' with in 'rule-sets' :param conf: configuration data. :return: generated rule list configuration. """ r_lst = [] rules = findall(r"rule (?:\'*)(\d+)(?:\'*)", conf, M) if rules: rules_lst = [] for r in set(rules): r_regex = r" %s .+$" % r cfg = "\n".join(findall(r_regex, conf, M)) obj = self.parse_rules(cfg) obj["number"] = int(r) if obj: rules_lst.append(obj) r_lst = sorted(rules_lst, key=lambda i: i["number"]) return r_lst def parse_rules(self, conf): """ This function triggers the parsing of 'rule' attributes. a_lst is a list having rule attributes which doesn't have further sub attributes. :param conf: configuration :return: generated rule configuration dictionary. """ a_lst = [ "ipsec", "log", "action", "protocol", "fragment", "disable", "description", "icmp", "jump_target", "offload_target", "queue", "queue_options", ] rule = self.parse_attr(conf, a_lst) r_sub = { "tcp": self.parse_tcp(conf), "icmp": self.parse_icmp(conf, "icmp"), "time": self.parse_time(conf, "time"), "limit": self.parse_limit(conf, "limit"), "state": self.parse_state(conf, "state"), "recent": self.parse_recent(conf, "recent"), "source": self.parse_src_or_dest(conf, "source"), "destination": self.parse_src_or_dest(conf, "destination"), "inbound_interface": self.parse_interface(conf, "inbound-interface"), "outbound_interface": self.parse_interface(conf, "outbound-interface"), "packet_length": self.parse_packet_length(conf, "packet-length"), "packet_length_exclude": self.parse_packet_length(conf, "packet-length-exclude"), } rule.update(r_sub) return rule def parse_interface(self, conf, attrib): """ This function triggers the parsing of 'interface' attributes. :param conf: configuration. :param attrib: 'interface'. :return: generated config dictionary. """ a_lst = ["name", "group"] cfg_dict = self.parse_attr(conf, a_lst, match=attrib) return cfg_dict def parse_packet_length(self, conf, attrib=None): """ This function triggers the parsing of 'packet-length' attributes. :param conf: configuration. :param attrib: 'packet-length'. :return: generated config dictionary. """ lengths = [] rule_regex = r"%s (.+)$" % attrib found_lengths = findall(rule_regex, conf, M) if found_lengths: lengths = [] for pplen in set(found_lengths): obj = {"length": pplen.strip("'")} lengths.append(obj) return lengths def parse_src_or_dest(self, conf, attrib=None): """ This function triggers the parsing of 'source or destination' attributes. :param conf: configuration. :param attrib:'source/destination'. :return:generated source/destination configuration dictionary. """ a_lst = ["port", "address", "mac_address"] cfg_dict = self.parse_attr(conf, a_lst, match=attrib) cfg_dict["group"] = self.parse_group(conf, attrib + " group") return cfg_dict def parse_recent(self, conf, attrib=None): """ This function triggers the parsing of 'recent' attributes :param conf: configuration. :param attrib: 'recent'. :return: generated config dictionary. """ a_lst = ["time", "count"] cfg_dict = self.parse_attr(conf, a_lst, match=attrib) return cfg_dict def parse_tcp(self, conf): """ This function triggers the parsing of 'tcp' attributes. :param conf: configuration. :param attrib: 'tcp'. :return: generated config dictionary. """ f_lst = [] flags = findall(r"tcp flags (not )?(?:\'*)([\w!,]+)(?:\'*)", conf, M) # for pre 1.4, this is a string including possible commas # and ! as an inverter. For 1.4+ this is a single flag per # command and 'not' as the inverter if flags: flag_lst = [] for n, f in set(flags): f = f.strip("'").lower() if "," in f: # pre 1.4 version with multiple flags fs = f.split(",") for f in fs: if "!" in f: obj = {"flag": f.strip("'!"), "invert": True} else: obj = {"flag": f.strip("'")} flag_lst.append(obj) elif "!" in f: obj = {"flag": f.strip("'!"), "invert": True} flag_lst.append(obj) else: obj = {"flag": f.strip("'")} if n: obj["invert"] = True flag_lst.append(obj) f_lst = sorted(flag_lst, key=lambda i: i["flag"]) return {"flags": f_lst} def parse_time(self, conf, attrib=None): """ This function triggers the parsing of 'time' attributes. :param conf: configuration. :param attrib: 'time'. :return: generated config dictionary. """ a_lst = [ "stopdate", "stoptime", "weekdays", "monthdays", "startdate", "starttime", ] cfg_dict = self.parse_attr(conf, a_lst, match=attrib) return cfg_dict def parse_state(self, conf, attrib=None): """ This function triggers the parsing of 'state' attributes. :param conf: configuration :param attrib: 'state'. :return: generated config dictionary. """ a_lst = ["new", "invalid", "related", "established"] cfg_dict = self.parse_attr(conf, a_lst, match=attrib) return cfg_dict def parse_group(self, conf, attrib=None): """ This function triggers the parsing of 'group' attributes. :param conf: configuration. :param attrib: 'group'. :return: generated config dictionary. """ a_lst = ["port_group", "address_group", "network_group"] cfg_dict = self.parse_attr(conf, a_lst, match=attrib) return cfg_dict def parse_icmp_attr(self, conf, match): """ This function peforms the following: - parse ICMP arguemnts for firewall rules - consider that older versions may need numbers or letters in type, newer ones are more specific :param conf: configuration. :param match: parent node/attribute name. :return: generated config dictionary. """ config = {} if not conf: return config for attrib in ("code", "type", "type-name"): regex = self.map_regex(attrib) if match: regex = match + " " + regex out = search(r"^.*" + regex + " (.+)", conf, M) if out: val = out.group(1).strip("'") if attrib == "type-name": config["type_name"] = val if attrib == "code": config["code"] = int(val) if attrib == "type": # <1.3 could be # (type), #/# (type/code) or 'type' (type_name) # recent this is only for strings if "/" in val: # type/code - (type_no, code) = val.split(".") - config["type"] = type_no - config["code"] = code + (type_no, code) = val.split("/") + config["type"] = int(type_no) + config["code"] = int(code) elif val.isnumeric(): - config["type"] = type_no + config["type"] = int(val) else: config["type_name"] = val return config def parse_icmp(self, conf, attrib=None): """ This function triggers the parsing of 'icmp' attributes. :param conf: configuration to be parsed. :param attrib: 'icmp'. :return: generated config dictionary. """ cfg_dict = self.parse_icmp_attr(conf, "icmp") if len(cfg_dict) == 0: cfg_dict = self.parse_icmp_attr(conf, "icmpv6") return cfg_dict def parse_limit(self, conf, attrib=None): """ This function triggers the parsing of 'limit' attributes. :param conf: configuration to be parsed. :param attrib: 'limit' :return: generated config dictionary. """ cfg_dict = self.parse_attr(conf, ["burst"], match=attrib) cfg_dict["rate"] = self.parse_rate(conf, "rate") 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 + " " + regex if conf: if self.is_bool(attrib): out = conf.find(attrib.replace("_", "-")) dis = conf.find(attrib.replace("_", "-") + " 'disable'") if out >= 1: if dis >= 1: config[attrib] = False else: config[attrib] = True else: out = search(r"^.*" + regex + " (.+)", conf, M) if not out: if attrib == "disable": out = search(r"^.*\d+" + " (disable$)", conf, M) if attrib == "log": out = search(r"^.*\d+" + " (log$)", conf, M) if out: val = out.group(1).strip("'") if self.is_num(attrib): val = int(val) if attrib == "disable": val = True if attrib == "log": val = "enable" 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 """ regex = attrib.replace("_", "-") if attrib == "disabled": regex = "disable" return regex def is_bool(self, attrib): """ This function looks for the attribute in predefined bool type set. :param attrib: attribute. :return: True/False """ bool_set = ( "new", "invalid", "related", "disabled", "established", "enable_default_log", "default_log", ) 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 = ("time", "code", "type", "count", "burst", "number") return True if attrib in num_set else False def parse_rate(self, conf, match): """ This function triggers the parsing of 'rate' attributes. :param conf: configuration. :param attrib: 'rate' :return: generated config dictionary. """ config = {} out = search(r"^.*" + match + " (.+)", conf, M) if out: val = out.group(1).strip("'") if "/" in val: # number/unit (number, unit) = val.split("/") config["number"] = number config["unit"] = unit return config diff --git a/plugins/module_utils/network/vyos/rm_templates/bgp_address_family.py b/plugins/module_utils/network/vyos/rm_templates/bgp_address_family.py index f8f86cd2..fccfc9c2 100644 --- a/plugins/module_utils/network/vyos/rm_templates/bgp_address_family.py +++ b/plugins/module_utils/network/vyos/rm_templates/bgp_address_family.py @@ -1,1450 +1,1435 @@ # -*- coding: utf-8 -*- # Copyright 2021 Red Hat # GNU General Public License v3.0+ # (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) from __future__ import absolute_import, division, print_function __metaclass__ = type """ The Bgp_address_family parser templates file. This contains a list of parser definitions and associated functions that facilitates both facts gathering and native command generation for the given network resource. """ import re from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.rm_base.network_template import ( NetworkTemplate, ) def _tmplt_bgp_af_aggregate_address(config_data): afi = config_data["address_family"]["afi"] + "-unicast" command = "protocols bgp {as_number} address-family ".format(**config_data) config_data = config_data["address_family"] if config_data["aggregate_address"].get("as_set"): command += afi + " aggregate-address {prefix} as-set".format( **config_data["aggregate_address"], ) if config_data["aggregate_address"].get("summary_only"): command += afi + " aggregate-address {prefix} summary-only".format( **config_data["aggregate_address"], ) return command def _tmplt_bgp_af_redistribute(config_data): afi = config_data["address_family"]["afi"] + "-unicast" command = "protocols bgp {as_number} address-family ".format(**config_data) config_data = config_data["address_family"]["redistribute"] command += afi + " redistribute {protocol}".format(**config_data) if config_data.get("metric"): command += " metric {metric}".format(**config_data) elif config_data.get("route_map"): command += " route-map {route_map}".format(**config_data) elif config_data.get("table"): command += " table {table}".format(**config_data) return command def _tmplt_bgp_af_redistribute_delete(config_data): afi = config_data["address_family"]["afi"] + "-unicast" command = "protocols bgp {as_number} address-family ".format(**config_data) config_data = config_data["address_family"]["redistribute"] command += afi + " redistribute {protocol}".format(**config_data) if config_data.get("metric"): command += " metric" elif config_data.get("route_map"): command += " route-map" elif config_data.get("table"): command += " table" return command def _tmplt_bgp_af_neighbor_distribute_list(config_data): command = [] afi = config_data["neighbors"]["address_family"]["afi"] + "-unicast" cmd = "protocols bgp {as_number} neighbor ".format(**config_data) cmd += "{neighbor_address} address-family ".format(**config_data["neighbors"]) config_data = config_data["neighbors"]["address_family"] for list_el in config_data["distribute_list"]: command.append( cmd + afi + " distribute-list " + list_el["action"] + " " + str(list_el["acl"]), ) return command def _tmplt_bgp_af_neighbor_route_map(config_data): command = [] afi = config_data["neighbors"]["address_family"]["afi"] + "-unicast" cmd = "protocols bgp {as_number} neighbor ".format(**config_data) cmd += "{neighbor_address} address-family ".format(**config_data["neighbors"]) config_data = config_data["neighbors"]["address_family"] for list_el in config_data["route_map"]: command.append( cmd + afi + " route-map " + list_el["action"] + " " + str(list_el["route_map"]), ) return command def _tmplt_bgp_af_neighbor_prefix_list(config_data): command = [] afi = config_data["neighbors"]["address_family"]["afi"] + "-unicast" cmd = "protocols bgp {as_number} neighbor ".format(**config_data) cmd += "{neighbor_address} address-family ".format(**config_data["neighbors"]) config_data = config_data["neighbors"]["address_family"] for list_el in config_data["prefix_list"]: command.append( cmd + afi + " prefix-list " + list_el["action"] + " " + str(list_el["prefix_list"]), ) return command def _tmplt_bgp_af_neighbor_filter_list(config_data): command = [] afi = config_data["neighbors"]["address_family"]["afi"] + "-unicast" cmd = "protocols bgp {as_number} neighbor ".format(**config_data) cmd += "{neighbor_address} address-family ".format(**config_data["neighbors"]) config_data = config_data["neighbors"]["address_family"] for list_el in config_data["filter_list"]: command.append( cmd + afi + " filter-list " + list_el["action"] + " " + str(list_el["path_list"]), ) return command def _tmplt_bgp_af_neighbor_attribute(config_data): command = [] afi = config_data["neighbors"]["address_family"]["afi"] + "-unicast" cmd = "protocols bgp {as_number} neighbor ".format(**config_data) cmd += "{neighbor_address} address-family ".format(**config_data["neighbors"]) config_data = config_data["neighbors"]["address_family"] for k in config_data["attribute_unchanged"].keys(): if config_data["attribute_unchanged"][k]: k = re.sub("_", "-", k) c = cmd + afi + " attribute-unchanged " + k command.append(c) return command def _tmplt_bgp_af_neighbor_delete(config_data): afi = config_data["neighbors"]["address_family"]["afi"] + "-unicast" command = "protocols bgp {as_number} ".format(**config_data) command += ( "neighbor {neighbor_address} address-family ".format(**config_data["neighbors"]) + afi ) config_data = config_data["neighbors"]["address_family"] if config_data.get("allowas_in"): command += " allowas-in" elif config_data.get("as_override"): command += " as-override" elif config_data.get("attribute_unchanged"): command += " attribute-unchanged" elif config_data.get("capability"): command += " capability" elif config_data.get("default_originate"): command += " default-originate" elif config_data.get("maximum_prefix"): command += " maximum-prefix" elif config_data.get("nexthop_local"): command += " nexthop-local" elif config_data.get("nexthop_self"): command += " nexthop-self" elif config_data.get("peer_group"): command += " peer-group" elif config_data.get("remote_private_as"): command += " remote-private-as" elif config_data.get("route_reflector_client"): command += " route-reflector-client" elif config_data.get("route_server_client"): command += " route-server-client" elif config_data.get("soft_reconfiguration"): command += " soft-reconfiguration" elif config_data.get("unsuppress_map"): command += " unsuppress-map" elif config_data.get("weight"): command += " weight" elif config_data.get("filter_list"): command += " filter-list" elif config_data.get("prefix_list"): command += " prefix-list" elif config_data.get("distribute_list"): command += " distribute-list" elif config_data.get("route_map"): command += " route-map" return command def _tmplt_bgp_af_neighbor(config_data): afi = config_data["neighbors"]["address_family"]["afi"] + "-unicast" command = "protocols bgp {as_number} ".format(**config_data) command += ( "neighbor {neighbor_address} address-family ".format(**config_data["neighbors"]) + afi ) config_data = config_data["neighbors"]["address_family"] if config_data.get("allowas_in"): command += " allowas-in number {allowas_in}".format(**config_data) elif config_data.get("as_override"): command += " as-override" elif config_data.get("capability"): command += " capability " if config_data["capability"].get("dynamic"): command += "dynamic" elif config_data["capability"].get("orf"): command += " prefix-list {orf}".format(**config_data["capability"]) elif config_data.get("default_originate"): command += " default-originate route-map {default_originate}".format(**config_data) elif config_data.get("maximum_prefix"): command += " maximum-prefix {maximum_prefix}".format(**config_data) elif config_data.get("nexthop_local"): command += " nexthop-local" elif config_data.get("nexthop_self"): command += " nexthop-self" elif config_data.get("peer_group"): command += " peer-group {peer_group}".format(**config_data) elif config_data.get("remote_private_as"): command += " remote-private-as" elif config_data.get("route_reflector_client"): command += " route-reflector-client" elif config_data.get("route_server_client"): command += " route-server-client" elif config_data.get("soft_reconfiguration"): command += " soft-reconfiguration inbound" elif config_data.get("unsuppress_map"): command += " unsuppress-map {unsuppress_map}".format(**config_data) elif config_data.get("weight"): command += " weight {weight}".format(**config_data) return command def _tmplt_bgp_af_network(config_data): afi = config_data["address_family"]["afi"] + "-unicast" command = "protocols bgp {as_number} address-family ".format(**config_data) config_data = config_data["address_family"]["networks"] command += afi + " network {prefix}".format(**config_data) if config_data.get("backdoor"): command += " backdoor" elif config_data.get("route_map"): command += " route-map {route_map}".format(**config_data) return command def _tmplt_bgp_af_network_delete(config_data): afi = config_data["address_family"]["afi"] + "-unicast" command = "protocols bgp {as_number} address-family ".format(**config_data) config_data = config_data["address_family"]["networks"] command += afi + " network {prefix}".format(**config_data) if config_data.get("backdoor"): command += " backdoor" elif config_data.get("route_map"): command += " route_map" return command class Bgp_address_familyTemplate(NetworkTemplate): def __init__(self, lines=None, module=None): prefix = {"set": "set", "remove": "delete"} super(Bgp_address_familyTemplate, self).__init__( lines=lines, tmplt=self, prefix=prefix, module=module, ) # fmt: off PARSERS = [ { "name": "address_family", "getval": re.compile( r""" ^set \s+protocols \s+bgp \s+(?P\d+) \s+address-family \s+(?P\S+)-unicast *$""", re.VERBOSE, ), "setval": "protocols bgp {{ as_number }} address-family {{ address_family.afi }}-unicast", "compval": "as_number", "result": { "as_number": "{{ as_num }}", "address_family": { "{{ afi }}": { "afi": "{{ afi }}", }, }, }, }, { "name": "aggregate_address", "getval": re.compile( r""" ^set \s+protocols \s+bgp \s+(?P\d+) \s+address-family \s+(?P\S+)-unicast \s+aggregate-address \s+(?P
\S+) - \s*(?Pas-set)* - \s*(?Psummary-only)* + \s*(?Pas-set)? + \s*(?Psummary-only)? $""", re.VERBOSE, ), "setval": _tmplt_bgp_af_aggregate_address, "remval": "protocols bgp {{ as_number }} address-family {{ address_family.afi }}-unicast aggregate-address" + " {{ address_family.aggregate_address.prefix }}", "compval": "address_family.aggregate_address", "result": { "as_number": "{{ as_num }}", "address_family": { "{{ afi }}": { "afi": "{{ afi }}", "aggregate_address": [ { "prefix": "{{ address }}", "as_set": "{{ True if as_set is defined }}", "summary_only": "{{ True if summary_only is defined }}", }, ], }, }, }, }, { "name": "network", "getval": re.compile( r""" ^set \s+protocols \s+bgp \s+(?P\d+) \s+address-family \s+(?P\S+)-unicast \s+network \s+(?P
\S+) $""", re.VERBOSE, ), "setval": _tmplt_bgp_af_network, "remval": "protocols bgp {{ as_number }} address-family {{ address_family.afi }}-unicast network {{ address_family.networks.prefix }}", "compval": "address_family.networks.prefix", "result": { "as_number": "{{ as_num }}", "address_family": { "{{ afi }}": { "afi": "{{ afi }}", "networks": [ { "prefix": "{{ address }}", }, ], }, }, }, }, { "name": "network.backdoor", "getval": re.compile( r""" ^set \s+protocols \s+bgp \s+(?P\d+) \s+address-family \s+(?P\S+)-unicast \s+network \s+(?P
\S+) \s+backdoor *$""", re.VERBOSE, ), "setval": _tmplt_bgp_af_network, "remval": _tmplt_bgp_af_network_delete, "compval": "address_family.networks.backdoor", "result": { "as_number": "{{ as_num }}", "address_family": { "{{ afi }}": { "afi": "{{ afi }}", "networks": [ { "prefix": "{{ address }}", "backdoor": "{{ True }}", }, ], }, }, }, }, { "name": "network.path_limit", "getval": re.compile( r""" ^set \s+protocols \s+bgp \s+(?P\d+) \s+address-family \s+(?P\S+)-unicast \s+network \s+(?P
\S+) \s+path-limit - \s+(?P\S+) - *$""", + \s+(?P\S+)\s*$""", re.VERBOSE, ), "setval": _tmplt_bgp_af_network, "remval": _tmplt_bgp_af_network_delete, "compval": "address_family.networks.path_limit", "result": { "as_number": "{{ as_num }}", "address_family": { "{{ afi }}": { "afi": "{{ afi }}", "networks": [ { "prefix": "{{ address }}", "path_limit": "{{ limit|int }}", }, ], }, }, }, }, { "name": "network.route_map", "getval": re.compile( r""" ^set \s+protocols \s+bgp \s+(?P\d+) \s+address-family \s+(?P\S+)-unicast \s+network \s+(?P
\S+) \s+route-map - \s+(?P\S+) - *$""", + \s+(?P\S+)\s*$""", re.VERBOSE, ), "setval": _tmplt_bgp_af_network, "remval": _tmplt_bgp_af_network_delete, "compval": "address_family.networks.route_map", "result": { "as_number": "{{ as_num }}", "address_family": { "{{ afi }}": { "afi": "{{ afi }}", "networks": [ { "prefix": "{{ address }}", "route_map": "{{ map }}", }, ], }, }, }, }, { "name": "redistribute", "getval": re.compile( r""" ^set \s+protocols \s+bgp \s+(?P\d+) \s+address-family \s+(?P\S+)-unicast \s+redistribute \s+(?P\S+) $""", re.VERBOSE, ), "setval": _tmplt_bgp_af_redistribute, "remval": "protocols bgp {{ as_number }} address-family {{ address_family.afi }}-unicast redistribute {{ address_family.redistribute.protocol }}", "compval": "address_family.redistribute.protocol", "result": { "as_number": "{{ as_num }}", "address_family": { "{{ afi }}": { "afi": "{{ afi }}", "redistribute": [ { "protocol": "{{ proto }}", }, ], }, }, }, }, { "name": "redistribute.metric", "getval": re.compile( r""" ^set \s+protocols \s+bgp \s+(?P\d+) \s+address-family \s+(?P\S+)-unicast \s+redistribute \s+(?P\S+) \s+metric - \s+(?P\S+) - *$""", + \s+(?P\S+)\s*$""", re.VERBOSE, ), "setval": _tmplt_bgp_af_redistribute, "remval": _tmplt_bgp_af_redistribute_delete, "compval": "address_family.redistribute.metric", "result": { "as_number": "{{ as_num }}", "address_family": { "{{ afi }}": { "afi": "{{ afi }}", "redistribute": [ { "protocol": "{{ proto }}", "metric": "{{ val|int }}", }, ], }, }, }, }, { "name": "redistribute.route_map", "getval": re.compile( r""" ^set \s+protocols \s+bgp \s+(?P\d+) \s+address-family \s+(?P\S+)-unicast \s+redistribute \s+(?P\S+) \s+route-map - \s+(?P\S+) - *$""", + \s+(?P\S+)\s*$""", re.VERBOSE, ), "setval": _tmplt_bgp_af_redistribute, "remval": _tmplt_bgp_af_redistribute_delete, "compval": "address_family.redistribute.route_map", "result": { "as_number": "{{ as_num }}", "address_family": { "{{ afi }}": { "afi": "{{ afi }}", "redistribute": [ { "protocol": "{{ proto }}", "route_map": "{{ map }}", }, ], }, }, }, }, { "name": "redistribute.table", "getval": re.compile( r""" ^set \s+protocols \s+bgp \s+(?P\d+) \s+address-family \s+(?P\S+)-unicast \s+redistribute \s+table - \s+(?P\S+) - *$""", + \s+(?P\S+)\s*$""", re.VERBOSE, ), "setval": _tmplt_bgp_af_redistribute, "remval": _tmplt_bgp_af_redistribute_delete, "compval": "address_family.redistribute.table", "result": { "as_number": "{{ as_num }}", "address_family": { "{{ afi }}": { "afi": "{{ afi }}", "redistribute": [ { "table": "{{ tab }}", }, ], }, }, }, }, { "name": "neighbors", "getval": re.compile( r""" ^set \s+protocols \s+bgp \s+(?P\d+) \s+neighbor \s+(?P
\S+) \s+address-family *$""", re.VERBOSE, ), "setval": "protocols bgp {{ as_number }} neighbor {{ neighbors.neighbor_address }} address-family", "compval": "neighbors", "result": { "as_number": "{{ as_num }}", "neighbors": { "{{ address }}": { "neighbor_address": "{{ address }}", }, }, }, }, { "name": "neighbors.address_family", "getval": re.compile( r""" ^set \s+protocols \s+bgp \s+(?P\d+) \s+neighbor \s+(?P
\S+) \s+address-family \s+(?P\S+)-unicast *$""", re.VERBOSE, ), "setval": "protocols bgp {{ as_number }} neighbor {{ neighbors.neighbor_address }} address-family {{ neighbors.address_family.afi }}-unicast", "compval": "neighbors", "result": { "as_number": "{{ as_num }}", "neighbors": { "{{ address }}": { "neighbor_address": "{{ address }}", "address_family": { "{{ afi }}": { "afi": "{{ afi }}", }, }, }, }, }, }, { "name": "neighbors.allowas_in", "getval": re.compile( r""" ^set \s+protocols \s+bgp \s+(?P\d+) \s+neighbor \s+(?P
\S+) \s+address-family \s+(?P\S+)-unicast \s+allowas-in \s+number - \s+(?P\S+) - *$""", + \s+(?P\S+)\s*$""", re.VERBOSE, ), "setval": _tmplt_bgp_af_neighbor, "remval": _tmplt_bgp_af_neighbor_delete, "compval": "neighbors.address_family.allowas_in", "result": { "as_number": "{{ as_num }}", "neighbors": { "{{ address }}": { "neighbor_address": "{{ address }}", "address_family": { "{{ afi }}": { "afi": "{{ afi }}", "allowas_in": "{{ num }}", }, }, }, }, }, }, { "name": "neighbors.as_override", "getval": re.compile( r""" ^set \s+protocols \s+bgp \s+(?P\d+) \s+neighbor \s+(?P
\S+) \s+address-family \s+(?P\S+)-unicast \s+as-override *$""", re.VERBOSE, ), "setval": _tmplt_bgp_af_neighbor, "remval": _tmplt_bgp_af_neighbor_delete, "compval": "neighbors.address_family.as_override", "result": { "as_number": "{{ as_num }}", "neighbors": { "{{ address }}": { "neighbor_address": "{{ address }}", "address_family": { "{{ afi }}": { "afi": "{{ afi }}", "as_override": "{{ True }}", }, }, }, }, }, }, { "name": "neighbors.attribute_unchanged.as_path", "getval": re.compile( r""" ^set \s+protocols \s+bgp \s+(?P\d+) \s+neighbor \s+(?P
\S+) \s+address-family \s+(?P\S+)-unicast \s+attribute-unchanged \s+(?Pas-path) *$""", re.VERBOSE, ), "setval": _tmplt_bgp_af_neighbor_attribute, "remval": _tmplt_bgp_af_neighbor_delete, "compval": "neighbors.address_family.attribute_unchanged.as_path", "result": { "as_number": "{{ as_num }}", "neighbors": { "{{ address }}": { "neighbor_address": "{{ address }}", "address_family": { "{{ afi }}": { "afi": "{{ afi }}", "attribute_unchanged": { "as_path": "{{ True }}", }, }, }, }, }, }, }, { "name": "neighbors.attribute_unchanged.med", "getval": re.compile( r""" ^set \s+protocols \s+bgp \s+(?P\d+) \s+neighbor \s+(?P
\S+) \s+address-family \s+(?P\S+)-unicast \s+attribute-unchanged \s+(?Pmed) *$""", re.VERBOSE, ), "setval": _tmplt_bgp_af_neighbor_attribute, "remval": _tmplt_bgp_af_neighbor_delete, "compval": "neighbors.address_family.attribute_unchanged.med", "result": { "as_number": "{{ as_num }}", "neighbors": { "{{ address }}": { "neighbor_address": "{{ address }}", "address_family": { "{{ afi }}": { "afi": "{{ afi }}", "attribute_unchanged": { "med": "{{ True }}", }, }, }, }, }, }, }, { "name": "neighbors.attribute_unchanged.next_hop", "getval": re.compile( r""" ^set \s+protocols \s+bgp \s+(?P\d+) \s+neighbor \s+(?P
\S+) \s+address-family \s+(?P\S+)-unicast \s+attribute-unchanged \s+(?Pnext-hop) *$""", re.VERBOSE, ), "setval": _tmplt_bgp_af_neighbor_attribute, "remval": _tmplt_bgp_af_neighbor_delete, "compval": "neighbors.address_family.attribute_unchanged.next_hop", "result": { "as_number": "{{ as_num }}", "neighbors": { "{{ address }}": { "neighbor_address": "{{ address }}", "address_family": { "{{ afi }}": { "afi": "{{ afi }}", "attribute_unchanged": { "next_hop": "{{ True }}", }, }, }, }, }, }, }, { "name": "neighbors.capability_dynamic", "getval": re.compile( r""" ^set \s+protocols \s+bgp \s+(?P\d+) \s+neighbor \s+(?P
\S+) \s+address-family \s+(?P\S+)-unicast \s+capability \s+dynamic *$""", re.VERBOSE, ), "setval": _tmplt_bgp_af_neighbor, "remval": _tmplt_bgp_af_neighbor_delete, "compval": "neighbors.address_family.capability.dynamic", "result": { "as_number": "{{ as_num }}", "neighbors": { "{{ address }}": { "neighbor_address": "{{ address }}", "address_family": { "{{ afi }}": { "afi": "{{ afi }}", "capability": { "dynamic": "{{ true }}", }, }, }, }, }, }, }, { "name": "neighbors.capability_orf", "getval": re.compile( r""" ^set \s+protocols \s+bgp \s+(?P\d+) \s+neighbor \s+(?P
\S+) \s+address-family \s+(?P\S+)-unicast \s+capability \s+prefix-list - \s+(?P\S+) - *$""", + \s+(?P\S+)\s*$""", re.VERBOSE, ), "setval": _tmplt_bgp_af_neighbor, "remval": _tmplt_bgp_af_neighbor_delete, "compval": "neighbors.address_family.capability.orf", "result": { "as_number": "{{ as_num }}", "neighbors": { "{{ address }}": { "neighbor_address": "{{ address }}", "address_family": { "{{ afi }}": { "afi": "{{ afi }}", "capability": { "orf": "{{ orf }}", }, }, }, }, }, }, }, { "name": "neighbors.default_originate", "getval": re.compile( r""" ^set \s+protocols \s+bgp \s+(?P\d+) \s+neighbor \s+(?P
\S+) \s+address-family \s+(?P\S+)-unicast \s+default-originate \s+route-map - \s+(?P\S+) - *$""", + \s+(?P\S+)\s*$""", re.VERBOSE, ), "setval": _tmplt_bgp_af_neighbor, "remval": _tmplt_bgp_af_neighbor_delete, "compval": "neighbors.address_family.default_originate", "result": { "as_number": "{{ as_num }}", "neighbors": { "{{ address }}": { "neighbor_address": "{{ address }}", "address_family": { "{{ afi }}": { "afi": "{{ afi }}", "default_originate": "{{ map }}", }, }, }, }, }, }, { "name": "neighbors.distribute_list", "getval": re.compile( r""" ^set \s+protocols \s+bgp \s+(?P\d+) \s+neighbor \s+(?P
\S+) \s+address-family \s+(?P\S+)-unicast \s+distribute-list \s+(?Pexport|import) \s+(?P\d+) *$""", re.VERBOSE, ), "setval": _tmplt_bgp_af_neighbor_distribute_list, "remval": _tmplt_bgp_af_neighbor_delete, "compval": "neighbors.address_family.distribute_list", "result": { "as_number": "{{ as_num }}", "neighbors": { "{{ address }}": { "neighbor_address": "{{ address }}", "address_family": { "{{ afi }}": { "afi": "{{ afi }}", "distribute_list": [ { "action": "{{ action }}", "acl": "{{ list }}", }, ], }, }, }, }, }, }, { "name": "neighbors.prefix_list", "getval": re.compile( r""" ^set \s+protocols \s+bgp \s+(?P\d+) \s+neighbor \s+(?P
\S+) \s+address-family \s+(?P\S+)-unicast \s+prefix-list \s+(?Pexport|import) - \s+(?P\S+) - *$""", + \s+(?P\S+)\s*$""", re.VERBOSE, ), "setval": _tmplt_bgp_af_neighbor_prefix_list, "remval": _tmplt_bgp_af_neighbor_delete, "compval": "neighbors.address_family.prefix_list", "result": { "as_number": "{{ as_num }}", "neighbors": { "{{ address }}": { "neighbor_address": "{{ address }}", "address_family": { "{{ afi }}": { "afi": "{{ afi }}", "prefix_list": [ { "action": "{{ action }}", "prefix_list": "{{ list }}", }, ], }, }, }, }, }, }, { "name": "neighbors.filter_list", "getval": re.compile( r""" ^set \s+protocols \s+bgp \s+(?P\d+) \s+neighbor \s+(?P
\S+) \s+address-family \s+(?P\S+)-unicast \s+filter-list \s+(?Pexport|import) - \s+(?P\S+) - *$""", + \s+(?P\S+)\s*$""", re.VERBOSE, ), "setval": _tmplt_bgp_af_neighbor_filter_list, "remval": _tmplt_bgp_af_neighbor_delete, "compval": "neighbors.address_family.filter_list", "result": { "as_number": "{{ as_num }}", "neighbors": { "{{ address }}": { "neighbor_address": "{{ address }}", "address_family": { "{{ afi }}": { "afi": "{{ afi }}", "filter_list": [ { "action": "{{ action }}", "path_list": "{{ list }}", }, ], }, }, }, }, }, }, { "name": "neighbors.maximum_prefix", "getval": re.compile( r""" ^set \s+protocols \s+bgp \s+(?P\d+) \s+neighbor \s+(?P
\S+) \s+address-family \s+(?P\S+)-unicast \s+maximum-prefix - \s+(?P\S+) - *$""", + \s+(?P\S+)\s*$""", re.VERBOSE, ), "setval": _tmplt_bgp_af_neighbor, "remval": _tmplt_bgp_af_neighbor_delete, "compval": "neighbors.address_family.maximum_prefix", "result": { "as_number": "{{ as_num }}", "neighbors": { "{{ address }}": { "neighbor_address": "{{ address }}", "address_family": { "{{ afi }}": { "afi": "{{ afi }}", "maximum_prefix": "{{ num }}", }, }, }, }, }, }, { "name": "neighbors.nexthop_local", "getval": re.compile( r""" ^set \s+protocols \s+bgp \s+(?P\d+) \s+neighbor \s+(?P
\S+) \s+address-family \s+(?P\S+)-unicast \s+nexthop-local *$""", re.VERBOSE, ), "setval": _tmplt_bgp_af_neighbor, "remval": _tmplt_bgp_af_neighbor_delete, "compval": "neighbors.address_family.nexthop_local", "result": { "as_number": "{{ as_num }}", "neighbors": { "{{ address }}": { "neighbor_address": "{{ address }}", "address_family": { "{{ afi }}": { "afi": "{{ afi }}", "nexthop_local": "{{ True }}", }, }, }, }, }, }, { "name": "neighbors.nexthop_self", "getval": re.compile( r""" ^set \s+protocols \s+bgp \s+(?P\d+) \s+neighbor \s+(?P
\S+) \s+address-family \s+(?P\S+)-unicast \s+nexthop-self *$""", re.VERBOSE, ), "setval": _tmplt_bgp_af_neighbor, "remval": _tmplt_bgp_af_neighbor_delete, "compval": "neighbors.address_family.nexthop_self", "result": { "as_number": "{{ as_num }}", "neighbors": { "{{ address }}": { "neighbor_address": "{{ address }}", "address_family": { "{{ afi }}": { "afi": "{{ afi }}", "nexthop_self": "{{ True }}", }, }, }, }, }, }, { "name": "neighbors.peer_group", "getval": re.compile( r""" ^set \s+protocols \s+bgp \s+(?P\d+) \s+neighbor \s+(?P
\S+) \s+address-family \s+(?P\S+)-unicast \s+peer-group - \s+(?P\S+) - *$""", + \s+(?P\S+)\s*$""", re.VERBOSE, ), "setval": _tmplt_bgp_af_neighbor, "remval": _tmplt_bgp_af_neighbor_delete, "compval": "neighbors.address_family.peer_group", "result": { "as_number": "{{ as_num }}", "neighbors": { "{{ address }}": { "neighbor_address": "{{ address }}", "address_family": { "{{ afi }}": { "afi": "{{ afi }}", "peer_group": "{{ name }}", }, }, }, }, }, }, { "name": "neighbors.remove_private_as", "getval": re.compile( r""" ^set \s+protocols \s+bgp \s+(?P\d+) \s+neighbor \s+(?P
\S+) \s+address-family \s+(?P\S+)-unicast \s+remove-private-as *$""", re.VERBOSE, ), "setval": _tmplt_bgp_af_neighbor, "remval": _tmplt_bgp_af_neighbor_delete, "compval": "neighbors.address_family.remove_private_as", "result": { "as_number": "{{ as_num }}", "neighbors": { "{{ address }}": { "neighbor_address": "{{ address }}", "address_family": { "{{ afi }}": { "afi": "{{ afi }}", "remove_private_as": "{{ True }}", }, }, }, }, }, }, { "name": "neighbors.route_map", "getval": re.compile( r""" ^set \s+protocols \s+bgp \s+(?P\d+) \s+neighbor \s+(?P
\S+) \s+address-family \s+(?P\S+)-unicast \s+route-map \s+(?Pexport|import) - \s+(?P\S+) - *$""", + \s+(?P\S+)\s*$""", re.VERBOSE, ), "setval": _tmplt_bgp_af_neighbor_route_map, "remval": _tmplt_bgp_af_neighbor_delete, "compval": "neighbors.address_family.route_map", "result": { "as_number": "{{ as_num }}", "neighbors": { "{{ address }}": { "neighbor_address": "{{ address }}", "address_family": { "{{ afi }}": { "afi": "{{ afi }}", "route_map": [ { "action": "{{ action }}", "route_map": "{{ map }}", }, ], }, }, }, }, }, }, { "name": "neighbors.route_reflector_client", "getval": re.compile( r""" ^set \s+protocols \s+bgp \s+(?P\d+) \s+neighbor \s+(?P
\S+) \s+address-family \s+(?P\S+)-unicast \s+route-reflector-client *$""", re.VERBOSE, ), "setval": _tmplt_bgp_af_neighbor, "remval": _tmplt_bgp_af_neighbor_delete, "compval": "neighbors.address_family.route_reflector_client", "result": { "as_number": "{{ as_num }}", "neighbors": { "{{ address }}": { "neighbor_address": "{{ address }}", "address_family": { "{{ afi }}": { "afi": "{{ afi }}", "route_reflector_client": "{{ True }}", }, }, }, }, }, }, { "name": "neighbors.route_server_client", "getval": re.compile( r""" ^set \s+protocols \s+bgp \s+(?P\d+) \s+neighbor \s+(?P
\S+) \s+address-family \s+(?P\S+)-unicast \s+route-server-client *$""", re.VERBOSE, ), "setval": _tmplt_bgp_af_neighbor, "remval": _tmplt_bgp_af_neighbor_delete, "compval": "neighbors.address_family.route_server_client", "result": { "as_number": "{{ as_num }}", "neighbors": { "{{ address }}": { "neighbor_address": "{{ address }}", "address_family": { "{{ afi }}": { "afi": "{{ afi }}", "route_server_client": "{{ True }}", }, }, }, }, }, }, { "name": "neighbors.soft_reconfiguration", "getval": re.compile( r""" ^set \s+protocols \s+bgp \s+(?P\d+) \s+neighbor \s+(?P
\S+) \s+address-family \s+(?P\S+)-unicast \s+soft-reconfiguration \s+inbound *$""", re.VERBOSE, ), "setval": _tmplt_bgp_af_neighbor, "remval": _tmplt_bgp_af_neighbor_delete, "compval": "neighbors.address_family.soft_reconfiguration", "result": { "as_number": "{{ as_num }}", "neighbors": { "{{ address }}": { "neighbor_address": "{{ address }}", "address_family": { "{{ afi }}": { "afi": "{{ afi }}", "soft_reconfiguration": "{{ True }}", }, }, }, }, }, }, { "name": "neighbors.unsuppress_map", "getval": re.compile( r""" ^set \s+protocols \s+bgp \s+(?P\d+) \s+neighbor \s+(?P
\S+) \s+address-family \s+(?P\S+)-unicast \s+unsuppress-map - \s+(?P\S+) - *$""", + \s+(?P\S+)\s*$""", re.VERBOSE, ), "setval": _tmplt_bgp_af_neighbor, "remval": _tmplt_bgp_af_neighbor_delete, "compval": "neighbors.address_family.unsuppress_map", "result": { "as_number": "{{ as_num }}", "neighbors": { "{{ address }}": { "neighbor_address": "{{ address }}", "address_family": { "{{ afi }}": { "afi": "{{ afi }}", "unsuppress_map": "{{ map }}", }, }, }, }, }, }, { "name": "neighbors.weight", "getval": re.compile( r""" ^set \s+protocols \s+bgp \s+(?P\d+) \s+neighbor \s+(?P
\S+) \s+address-family \s+(?P\S+)-unicast \s+weight - \s+(?P\S+) - *$""", + \s+(?P\S+)\s*$""", re.VERBOSE, ), "setval": _tmplt_bgp_af_neighbor, "remval": _tmplt_bgp_af_neighbor_delete, "compval": "neighbors.address_family.weight", "result": { "as_number": "{{ as_num }}", "neighbors": { "{{ address }}": { "neighbor_address": "{{ address }}", "address_family": { "{{ afi }}": { "afi": "{{ afi }}", "weight": "{{ num }}", }, }, }, }, }, }, ] # fmt: on diff --git a/plugins/module_utils/network/vyos/rm_templates/bgp_address_family_14.py b/plugins/module_utils/network/vyos/rm_templates/bgp_address_family_14.py index fd4c9de9..09cd41a7 100644 --- a/plugins/module_utils/network/vyos/rm_templates/bgp_address_family_14.py +++ b/plugins/module_utils/network/vyos/rm_templates/bgp_address_family_14.py @@ -1,1433 +1,1418 @@ # -*- coding: utf-8 -*- # Copyright 2021 Red Hat # GNU General Public License v3.0+ # (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) from __future__ import absolute_import, division, print_function __metaclass__ = type """ The Bgp_address_family parser templates file. This contains a list of parser definitions and associated functions that facilitates both facts gathering and native command generation for the given network resource. """ import re from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.rm_base.network_template import ( NetworkTemplate, ) def _tmplt_bgp_af_aggregate_address(config_data): afi = config_data["address_family"]["afi"] + "-unicast" command = "protocols bgp address-family ".format(**config_data) config_data = config_data["address_family"] if config_data["aggregate_address"].get("as_set"): command += afi + " aggregate-address {prefix} as-set".format( **config_data["aggregate_address"], ) if config_data["aggregate_address"].get("summary_only"): command += afi + " aggregate-address {prefix} summary-only".format( **config_data["aggregate_address"], ) return command def _tmplt_bgp_af_redistribute(config_data): afi = config_data["address_family"]["afi"] + "-unicast" command = "protocols bgp address-family ".format(**config_data) config_data = config_data["address_family"]["redistribute"] command += afi + " redistribute {protocol}".format(**config_data) if config_data.get("metric"): command += " metric {metric}".format(**config_data) elif config_data.get("route_map"): command += " route-map {route_map}".format(**config_data) elif config_data.get("table"): command += " table {table}".format(**config_data) return command def _tmplt_bgp_af_redistribute_delete(config_data): afi = config_data["address_family"]["afi"] + "-unicast" command = "protocols bgp address-family ".format(**config_data) config_data = config_data["address_family"]["redistribute"] command += afi + " redistribute {protocol}".format(**config_data) if config_data.get("metric"): command += " metric" elif config_data.get("route_map"): command += " route-map" elif config_data.get("table"): command += " table" return command def _tmplt_bgp_af_neighbor_distribute_list(config_data): command = [] afi = config_data["neighbors"]["address_family"]["afi"] + "-unicast" cmd = "protocols bgp neighbor ".format(**config_data) cmd += "{neighbor_address} address-family ".format(**config_data["neighbors"]) config_data = config_data["neighbors"]["address_family"] for list_el in config_data["distribute_list"]: command.append( cmd + afi + " distribute-list " + list_el["action"] + " " + str(list_el["acl"]), ) return command def _tmplt_bgp_af_neighbor_route_map(config_data): command = [] afi = config_data["neighbors"]["address_family"]["afi"] + "-unicast" cmd = "protocols bgp neighbor ".format(**config_data) cmd += "{neighbor_address} address-family ".format(**config_data["neighbors"]) config_data = config_data["neighbors"]["address_family"] for list_el in config_data["route_map"]: command.append( cmd + afi + " route-map " + list_el["action"] + " " + str(list_el["route_map"]), ) return command def _tmplt_bgp_af_neighbor_prefix_list(config_data): command = [] afi = config_data["neighbors"]["address_family"]["afi"] + "-unicast" cmd = "protocols bgp neighbor ".format(**config_data) cmd += "{neighbor_address} address-family ".format(**config_data["neighbors"]) config_data = config_data["neighbors"]["address_family"] for list_el in config_data["prefix_list"]: command.append( cmd + afi + " prefix-list " + list_el["action"] + " " + str(list_el["prefix_list"]), ) return command def _tmplt_bgp_af_neighbor_filter_list(config_data): command = [] afi = config_data["neighbors"]["address_family"]["afi"] + "-unicast" cmd = "protocols bgp neighbor ".format(**config_data) cmd += "{neighbor_address} address-family ".format(**config_data["neighbors"]) config_data = config_data["neighbors"]["address_family"] for list_el in config_data["filter_list"]: command.append( cmd + afi + " filter-list " + list_el["action"] + " " + str(list_el["path_list"]), ) return command def _tmplt_bgp_af_neighbor_attribute(config_data): command = [] afi = config_data["neighbors"]["address_family"]["afi"] + "-unicast" cmd = "protocols bgp neighbor ".format(**config_data) cmd += "{neighbor_address} address-family ".format(**config_data["neighbors"]) config_data = config_data["neighbors"]["address_family"] for k in config_data["attribute_unchanged"].keys(): if config_data["attribute_unchanged"][k]: k = re.sub("_", "-", k) c = cmd + afi + " attribute-unchanged " + k command.append(c) return command def _tmplt_bgp_af_neighbor_delete(config_data): afi = config_data["neighbors"]["address_family"]["afi"] + "-unicast" command = "protocols bgp ".format(**config_data) command += ( "neighbor {neighbor_address} address-family ".format(**config_data["neighbors"]) + afi ) config_data = config_data["neighbors"]["address_family"] if config_data.get("allowas_in"): command += " allowas-in" elif config_data.get("as_override"): command += " as-override" elif config_data.get("attribute_unchanged"): command += " attribute-unchanged" elif config_data.get("capability"): command += " capability" elif config_data.get("default_originate"): command += " default-originate" elif config_data.get("maximum_prefix"): command += " maximum-prefix" elif config_data.get("nexthop_local"): command += " nexthop-local" elif config_data.get("nexthop_self"): command += " nexthop-self" elif config_data.get("peer_group"): command += " peer-group" elif config_data.get("remote_private_as"): command += " remote-private-as" elif config_data.get("route_reflector_client"): command += " route-reflector-client" elif config_data.get("route_server_client"): command += " route-server-client" elif config_data.get("soft_reconfiguration"): command += " soft-reconfiguration" elif config_data.get("unsuppress_map"): command += " unsuppress-map" elif config_data.get("weight"): command += " weight" elif config_data.get("filter_list"): command += " filter-list" elif config_data.get("prefix_list"): command += " prefix-list" elif config_data.get("distribute_list"): command += " distribute-list" elif config_data.get("route_map"): command += " route-map" return command def _tmplt_bgp_af_neighbor(config_data): afi = config_data["neighbors"]["address_family"]["afi"] + "-unicast" command = "protocols bgp ".format(**config_data) command += ( "neighbor {neighbor_address} address-family ".format(**config_data["neighbors"]) + afi ) config_data = config_data["neighbors"]["address_family"] if config_data.get("allowas_in"): command += " allowas-in number {allowas_in}".format(**config_data) elif config_data.get("as_override"): command += " as-override" elif config_data.get("capability"): command += " capability " if config_data["capability"].get("dynamic"): command += "dynamic" elif config_data["capability"].get("orf"): command += " prefix-list {orf}".format(**config_data["capability"]) elif config_data.get("default_originate"): command += " default-originate route-map {default_originate}".format(**config_data) elif config_data.get("maximum_prefix"): command += " maximum-prefix {maximum_prefix}".format(**config_data) elif config_data.get("nexthop_local"): command += " nexthop-local" elif config_data.get("nexthop_self"): command += " nexthop-self" elif config_data.get("peer_group"): command += " peer-group {peer_group}".format(**config_data) elif config_data.get("remote_private_as"): command += " remote-private-as" elif config_data.get("route_reflector_client"): command += " route-reflector-client" elif config_data.get("route_server_client"): command += " route-server-client" elif config_data.get("soft_reconfiguration"): command += " soft-reconfiguration inbound" elif config_data.get("unsuppress_map"): command += " unsuppress-map {unsuppress_map}".format(**config_data) elif config_data.get("weight"): command += " weight {weight}".format(**config_data) return command def _tmplt_bgp_af_network(config_data): afi = config_data["address_family"]["afi"] + "-unicast" command = "protocols bgp address-family ".format(**config_data) config_data = config_data["address_family"]["networks"] command += afi + " network {prefix}".format(**config_data) if config_data.get("backdoor"): command += " backdoor" elif config_data.get("route_map"): command += " route-map {route_map}".format(**config_data) return command def _tmplt_bgp_af_network_delete(config_data): afi = config_data["address_family"]["afi"] + "-unicast" command = "protocols bgp address-family ".format(**config_data) config_data = config_data["address_family"]["networks"] command += afi + " network {prefix}".format(**config_data) if config_data.get("backdoor"): command += " backdoor" elif config_data.get("route_map"): command += " route_map" return command class Bgp_address_familyTemplate14(NetworkTemplate): def __init__(self, lines=None, module=None): prefix = {"set": "set", "remove": "delete"} super(Bgp_address_familyTemplate14, self).__init__( lines=lines, tmplt=self, prefix=prefix, module=module, ) # fmt: off PARSERS = [ { "name": "system_as", "getval": re.compile( r""" ^set \s+protocols \s+bgp \s+system-as \s+(?P\d+) *$""", re.VERBOSE, ), "setval": "protocols bgp system-as {{ as_number }}", "compval": "as_number", "result": { "as_number": "{{ as_num }}", }, }, { "name": "address_family", "getval": re.compile( r""" ^set \s+protocols \s+bgp \s+address-family \s+(?P\S+)-unicast *$""", re.VERBOSE, ), "setval": "protocols bgp address-family {{ address_family.afi }}-unicast", "compval": "as_number", "result": { "as_number": "{{ as_num }}", "address_family": { "{{ afi }}": { "afi": "{{ afi }}", }, }, }, }, { "name": "aggregate_address", "getval": re.compile( r""" ^set \s+protocols \s+bgp \s+address-family \s+(?P\S+)-unicast \s+aggregate-address \s+(?P
\S+) - \s*(?Pas-set)* - \s*(?Psummary-only)* + \s*(?Pas-set)? + \s*(?Psummary-only)? $""", re.VERBOSE, ), "setval": _tmplt_bgp_af_aggregate_address, "remval": "protocols bgp address-family {{ address_family.afi }}-unicast aggregate-address" + " {{ address_family.aggregate_address.prefix }}", "compval": "address_family.aggregate_address", "result": { "as_number": "{{ as_num }}", "address_family": { "{{ afi }}": { "afi": "{{ afi }}", "aggregate_address": [ { "prefix": "{{ address }}", "as_set": "{{ True if as_set is defined }}", "summary_only": "{{ True if summary_only is defined }}", }, ], }, }, }, }, { "name": "network", "getval": re.compile( r""" ^set \s+protocols \s+bgp \s+address-family \s+(?P\S+)-unicast \s+network \s+(?P
\S+) $""", re.VERBOSE, ), "setval": _tmplt_bgp_af_network, "remval": "protocols bgp address-family {{ address_family.afi }}-unicast network {{ address_family.networks.prefix }}", "compval": "address_family.networks.prefix", "result": { "as_number": "{{ as_num }}", "address_family": { "{{ afi }}": { "afi": "{{ afi }}", "networks": [ { "prefix": "{{ address }}", }, ], }, }, }, }, { "name": "network.backdoor", "getval": re.compile( r""" ^set \s+protocols \s+bgp \s+address-family \s+(?P\S+)-unicast \s+network \s+(?P
\S+) \s+backdoor *$""", re.VERBOSE, ), "setval": _tmplt_bgp_af_network, "remval": _tmplt_bgp_af_network_delete, "compval": "address_family.networks.backdoor", "result": { "as_number": "{{ as_num }}", "address_family": { "{{ afi }}": { "afi": "{{ afi }}", "networks": [ { "prefix": "{{ address }}", "backdoor": "{{ True }}", }, ], }, }, }, }, { "name": "network.path_limit", "getval": re.compile( r""" ^set \s+protocols \s+bgp \s+address-family \s+(?P\S+)-unicast \s+network \s+(?P
\S+) \s+path-limit - \s+(?P\S+) - *$""", + \s+(?P\S+)\s*$""", re.VERBOSE, ), "setval": _tmplt_bgp_af_network, "remval": _tmplt_bgp_af_network_delete, "compval": "address_family.networks.path_limit", "result": { "as_number": "{{ as_num }}", "address_family": { "{{ afi }}": { "afi": "{{ afi }}", "networks": [ { "prefix": "{{ address }}", "path_limit": "{{ limit|int }}", }, ], }, }, }, }, { "name": "network.route_map", "getval": re.compile( r""" ^set \s+protocols \s+bgp \s+address-family \s+(?P\S+)-unicast \s+network \s+(?P
\S+) \s+route-map - \s+(?P\S+) - *$""", + \s+(?P\S+)\s*$""", re.VERBOSE, ), "setval": _tmplt_bgp_af_network, "remval": _tmplt_bgp_af_network_delete, "compval": "address_family.networks.route_map", "result": { "as_number": "{{ as_num }}", "address_family": { "{{ afi }}": { "afi": "{{ afi }}", "networks": [ { "prefix": "{{ address }}", "route_map": "{{ map }}", }, ], }, }, }, }, { "name": "redistribute", "getval": re.compile( r""" ^set \s+protocols \s+bgp \s+address-family \s+(?P\S+)-unicast \s+redistribute \s+(?P\S+) $""", re.VERBOSE, ), "setval": _tmplt_bgp_af_redistribute, "remval": "protocols bgp address-family {{ address_family.afi }}-unicast redistribute {{ address_family.redistribute.protocol }}", "compval": "address_family.redistribute.protocol", "result": { "as_number": "{{ as_num }}", "address_family": { "{{ afi }}": { "afi": "{{ afi }}", "redistribute": [ { "protocol": "{{ proto }}", }, ], }, }, }, }, { "name": "redistribute.metric", "getval": re.compile( r""" ^set \s+protocols \s+bgp \s+address-family \s+(?P\S+)-unicast \s+redistribute \s+(?P\S+) - \s+metric\s+(?P\S+) - *$""", + \s+metric\s+(?P\S+)\s*$""", re.VERBOSE, ), "setval": _tmplt_bgp_af_redistribute, "remval": _tmplt_bgp_af_redistribute_delete, "compval": "address_family.redistribute.metric", "result": { "as_number": "{{ as_num }}", "address_family": { "{{ afi }}": { "afi": "{{ afi }}", "redistribute": [ { "protocol": "{{ proto }}", "metric": "{{ val }}", }, ], }, }, }, }, { "name": "redistribute.route_map", "getval": re.compile( r""" ^set \s+protocols \s+bgp \s+address-family \s+(?P\S+)-unicast \s+redistribute \s+(?P\S+) \s+route-map - \s+(?P\S+) - *$""", + \s+(?P\S+)\s*$""", re.VERBOSE, ), "setval": _tmplt_bgp_af_redistribute, "remval": _tmplt_bgp_af_redistribute_delete, "compval": "address_family.redistribute.route_map", "result": { "as_number": "{{ as_num }}", "address_family": { "{{ afi }}": { "afi": "{{ afi }}", "redistribute": [ { "protocol": "{{ proto }}", "route_map": "{{ map }}", }, ], }, }, }, }, { "name": "redistribute.table", "getval": re.compile( r""" ^set \s+protocols \s+bgp \s+address-family \s+(?P\S+)-unicast \s+redistribute \s+table - \s+(?P\S+) - *$""", + \s+(?P\S+)\s*$""", re.VERBOSE, ), "setval": _tmplt_bgp_af_redistribute, "remval": _tmplt_bgp_af_redistribute_delete, "compval": "address_family.redistribute.table", "result": { "as_number": "{{ as_num }}", "address_family": { "{{ afi }}": { "afi": "{{ afi }}", "redistribute": [ { "table": "{{ tab }}", }, ], }, }, }, }, { "name": "neighbors", "getval": re.compile( r""" ^set \s+protocols \s+bgp \s+neighbor \s+(?P
\S+) \s+address-family *$""", re.VERBOSE, ), "setval": "protocols bgp neighbor {{ neighbors.neighbor_address }} address-family", "compval": "neighbors", "result": { "as_number": "{{ as_num }}", "neighbors": { "{{ address }}": { "neighbor_address": "{{ address }}", }, }, }, }, { "name": "neighbors.address_family", "getval": re.compile( r""" ^set \s+protocols \s+bgp \s+neighbor \s+(?P
\S+) \s+address-family \s+(?P\S+)-unicast *$""", re.VERBOSE, ), "setval": "protocols bgp neighbor {{ neighbors.neighbor_address }} address-family {{ neighbors.address_family.afi }}-unicast", "compval": "neighbors", "result": { "as_number": "{{ as_num }}", "neighbors": { "{{ address }}": { "neighbor_address": "{{ address }}", "address_family": { "{{ afi }}": { "afi": "{{ afi }}", }, }, }, }, }, }, { "name": "neighbors.allowas_in", "getval": re.compile( r""" ^set \s+protocols \s+bgp \s+neighbor \s+(?P
\S+) \s+address-family \s+(?P\S+)-unicast \s+allowas-in \s+number - \s+(?P\S+) - *$""", + \s+(?P\S+)\s*$""", re.VERBOSE, ), "setval": _tmplt_bgp_af_neighbor, "remval": _tmplt_bgp_af_neighbor_delete, "compval": "neighbors.address_family.allowas_in", "result": { "as_number": "{{ as_num }}", "neighbors": { "{{ address }}": { "neighbor_address": "{{ address }}", "address_family": { "{{ afi }}": { "afi": "{{ afi }}", "allowas_in": "{{ num }}", }, }, }, }, }, }, { "name": "neighbors.as_override", "getval": re.compile( r""" ^set \s+protocols \s+bgp \s+neighbor \s+(?P
\S+) \s+address-family \s+(?P\S+)-unicast \s+as-override *$""", re.VERBOSE, ), "setval": _tmplt_bgp_af_neighbor, "remval": _tmplt_bgp_af_neighbor_delete, "compval": "neighbors.address_family.as_override", "result": { "as_number": "{{ as_num }}", "neighbors": { "{{ address }}": { "neighbor_address": "{{ address }}", "address_family": { "{{ afi }}": { "afi": "{{ afi }}", "as_override": "{{ True }}", }, }, }, }, }, }, { "name": "neighbors.attribute_unchanged.as_path", "getval": re.compile( r""" ^set \s+protocols \s+bgp \s+neighbor \s+(?P
\S+) \s+address-family \s+(?P\S+)-unicast \s+attribute-unchanged \s+(?Pas-path) *$""", re.VERBOSE, ), "setval": _tmplt_bgp_af_neighbor_attribute, "remval": _tmplt_bgp_af_neighbor_delete, "compval": "neighbors.address_family.attribute_unchanged.as_path", "result": { "as_number": "{{ as_num }}", "neighbors": { "{{ address }}": { "neighbor_address": "{{ address }}", "address_family": { "{{ afi }}": { "afi": "{{ afi }}", "attribute_unchanged": { "as_path": "{{ True }}", }, }, }, }, }, }, }, { "name": "neighbors.attribute_unchanged.med", "getval": re.compile( r""" ^set \s+protocols \s+bgp \s+neighbor \s+(?P
\S+) \s+address-family \s+(?P\S+)-unicast \s+attribute-unchanged \s+(?Pmed) *$""", re.VERBOSE, ), "setval": _tmplt_bgp_af_neighbor_attribute, "remval": _tmplt_bgp_af_neighbor_delete, "compval": "neighbors.address_family.attribute_unchanged.med", "result": { "as_number": "{{ as_num }}", "neighbors": { "{{ address }}": { "neighbor_address": "{{ address }}", "address_family": { "{{ afi }}": { "afi": "{{ afi }}", "attribute_unchanged": { "med": "{{ True }}", }, }, }, }, }, }, }, { "name": "neighbors.attribute_unchanged.next_hop", "getval": re.compile( r""" ^set \s+protocols \s+bgp \s+neighbor \s+(?P
\S+) \s+address-family \s+(?P\S+)-unicast \s+attribute-unchanged \s+(?Pnext-hop) *$""", re.VERBOSE, ), "setval": _tmplt_bgp_af_neighbor_attribute, "remval": _tmplt_bgp_af_neighbor_delete, "compval": "neighbors.address_family.attribute_unchanged.next_hop", "result": { "as_number": "{{ as_num }}", "neighbors": { "{{ address }}": { "neighbor_address": "{{ address }}", "address_family": { "{{ afi }}": { "afi": "{{ afi }}", "attribute_unchanged": { "next_hop": "{{ True }}", }, }, }, }, }, }, }, { "name": "neighbors.capability_dynamic", "getval": re.compile( r""" ^set \s+protocols \s+bgp \s+neighbor \s+(?P
\S+) \s+address-family \s+(?P\S+)-unicast \s+capability \s+dynamic *$""", re.VERBOSE, ), "setval": _tmplt_bgp_af_neighbor, "remval": _tmplt_bgp_af_neighbor_delete, "compval": "neighbors.address_family.capability.dynamic", "result": { "as_number": "{{ as_num }}", "neighbors": { "{{ address }}": { "neighbor_address": "{{ address }}", "address_family": { "{{ afi }}": { "afi": "{{ afi }}", "capability": { "dynamic": "{{ true }}", }, }, }, }, }, }, }, { "name": "neighbors.capability_orf", "getval": re.compile( r""" ^set \s+protocols \s+bgp \s+neighbor \s+(?P
\S+) \s+address-family \s+(?P\S+)-unicast \s+capability \s+prefix-list - \s+(?P\S+) - *$""", + \s+(?P\S+)\s*$""", re.VERBOSE, ), "setval": _tmplt_bgp_af_neighbor, "remval": _tmplt_bgp_af_neighbor_delete, "compval": "neighbors.address_family.capability.orf", "result": { "as_number": "{{ as_num }}", "neighbors": { "{{ address }}": { "neighbor_address": "{{ address }}", "address_family": { "{{ afi }}": { "afi": "{{ afi }}", "capability": { "orf": "{{ orf }}", }, }, }, }, }, }, }, { "name": "neighbors.default_originate", "getval": re.compile( r""" ^set \s+protocols \s+bgp \s+neighbor \s+(?P
\S+) \s+address-family \s+(?P\S+)-unicast \s+default-originate \s+route-map - \s+(?P\S+) - *$""", + \s+(?P\S+)\s*$""", re.VERBOSE, ), "setval": _tmplt_bgp_af_neighbor, "remval": _tmplt_bgp_af_neighbor_delete, "compval": "neighbors.address_family.default_originate", "result": { "as_number": "{{ as_num }}", "neighbors": { "{{ address }}": { "neighbor_address": "{{ address }}", "address_family": { "{{ afi }}": { "afi": "{{ afi }}", "default_originate": "{{ map }}", }, }, }, }, }, }, { "name": "neighbors.distribute_list", "getval": re.compile( r""" ^set \s+protocols \s+bgp \s+neighbor \s+(?P
\S+) \s+address-family \s+(?P\S+)-unicast \s+distribute-list \s+(?Pexport|import) \s+(?P\d+) *$""", re.VERBOSE, ), "setval": _tmplt_bgp_af_neighbor_distribute_list, "remval": _tmplt_bgp_af_neighbor_delete, "compval": "neighbors.address_family.distribute_list", "result": { "as_number": "{{ as_num }}", "neighbors": { "{{ address }}": { "neighbor_address": "{{ address }}", "address_family": { "{{ afi }}": { "afi": "{{ afi }}", "distribute_list": [ { "action": "{{ action }}", "acl": "{{ list }}", }, ], }, }, }, }, }, }, { "name": "neighbors.prefix_list", "getval": re.compile( r""" ^set \s+protocols \s+bgp \s+neighbor \s+(?P
\S+) \s+address-family \s+(?P\S+)-unicast \s+prefix-list \s+(?Pexport|import) - \s+(?P\S+) - *$""", + \s+(?P\S+)\s*$""", re.VERBOSE, ), "setval": _tmplt_bgp_af_neighbor_prefix_list, "remval": _tmplt_bgp_af_neighbor_delete, "compval": "neighbors.address_family.prefix_list", "result": { "as_number": "{{ as_num }}", "neighbors": { "{{ address }}": { "neighbor_address": "{{ address }}", "address_family": { "{{ afi }}": { "afi": "{{ afi }}", "prefix_list": [ { "action": "{{ action }}", "prefix_list": "{{ list }}", }, ], }, }, }, }, }, }, { "name": "neighbors.filter_list", "getval": re.compile( r""" ^set \s+protocols \s+bgp \s+neighbor \s+(?P
\S+) \s+address-family \s+(?P\S+)-unicast \s+filter-list \s+(?Pexport|import) - \s+(?P\S+) - *$""", + \s+(?P\S+)\s*$""", re.VERBOSE, ), "setval": _tmplt_bgp_af_neighbor_filter_list, "remval": _tmplt_bgp_af_neighbor_delete, "compval": "neighbors.address_family.filter_list", "result": { "as_number": "{{ as_num }}", "neighbors": { "{{ address }}": { "neighbor_address": "{{ address }}", "address_family": { "{{ afi }}": { "afi": "{{ afi }}", "filter_list": [ { "action": "{{ action }}", "path_list": "{{ list }}", }, ], }, }, }, }, }, }, { "name": "neighbors.maximum_prefix", "getval": re.compile( r""" ^set \s+protocols \s+bgp \s+neighbor \s+(?P
\S+) \s+address-family \s+(?P\S+)-unicast \s+maximum-prefix - \s+(?P\S+) - *$""", + \s+(?P\S+)\s*$""", re.VERBOSE, ), "setval": _tmplt_bgp_af_neighbor, "remval": _tmplt_bgp_af_neighbor_delete, "compval": "neighbors.address_family.maximum_prefix", "result": { "as_number": "{{ as_num }}", "neighbors": { "{{ address }}": { "neighbor_address": "{{ address }}", "address_family": { "{{ afi }}": { "afi": "{{ afi }}", "maximum_prefix": "{{ num }}", }, }, }, }, }, }, { "name": "neighbors.nexthop_local", "getval": re.compile( r""" ^set \s+protocols \s+bgp \s+neighbor \s+(?P
\S+) \s+address-family \s+(?P\S+)-unicast \s+nexthop-local *$""", re.VERBOSE, ), "setval": _tmplt_bgp_af_neighbor, "remval": _tmplt_bgp_af_neighbor_delete, "compval": "neighbors.address_family.nexthop_local", "result": { "as_number": "{{ as_num }}", "neighbors": { "{{ address }}": { "neighbor_address": "{{ address }}", "address_family": { "{{ afi }}": { "afi": "{{ afi }}", "nexthop_local": "{{ True }}", }, }, }, }, }, }, { "name": "neighbors.nexthop_self", "getval": re.compile( r""" ^set \s+protocols \s+bgp \s+neighbor \s+(?P
\S+) \s+address-family \s+(?P\S+)-unicast \s+nexthop-self *$""", re.VERBOSE, ), "setval": _tmplt_bgp_af_neighbor, "remval": _tmplt_bgp_af_neighbor_delete, "compval": "neighbors.address_family.nexthop_self", "result": { "as_number": "{{ as_num }}", "neighbors": { "{{ address }}": { "neighbor_address": "{{ address }}", "address_family": { "{{ afi }}": { "afi": "{{ afi }}", "nexthop_self": "{{ True }}", }, }, }, }, }, }, { "name": "neighbors.peer_group", "getval": re.compile( r""" ^set \s+protocols \s+bgp \s+neighbor \s+(?P
\S+) \s+address-family \s+(?P\S+)-unicast \s+peer-group - \s+(?P\S+) - *$""", + \s+(?P\S+)\s*$""", re.VERBOSE, ), "setval": _tmplt_bgp_af_neighbor, "remval": _tmplt_bgp_af_neighbor_delete, "compval": "neighbors.address_family.peer_group", "result": { "as_number": "{{ as_num }}", "neighbors": { "{{ address }}": { "neighbor_address": "{{ address }}", "address_family": { "{{ afi }}": { "afi": "{{ afi }}", "peer_group": "{{ name }}", }, }, }, }, }, }, { "name": "neighbors.remove_private_as", "getval": re.compile( r""" ^set \s+protocols \s+bgp \s+neighbor \s+(?P
\S+) \s+address-family \s+(?P\S+)-unicast \s+remove-private-as *$""", re.VERBOSE, ), "setval": _tmplt_bgp_af_neighbor, "remval": _tmplt_bgp_af_neighbor_delete, "compval": "neighbors.address_family.remove_private_as", "result": { "as_number": "{{ as_num }}", "neighbors": { "{{ address }}": { "neighbor_address": "{{ address }}", "address_family": { "{{ afi }}": { "afi": "{{ afi }}", "remove_private_as": "{{ True }}", }, }, }, }, }, }, { "name": "neighbors.route_map", "getval": re.compile( r""" ^set \s+protocols \s+bgp \s+neighbor \s+(?P
\S+) \s+address-family \s+(?P\S+)-unicast \s+route-map \s+(?Pexport|import) - \s+(?P\S+) - *$""", + \s+(?P\S+)\s*$""", re.VERBOSE, ), "setval": _tmplt_bgp_af_neighbor_route_map, "remval": _tmplt_bgp_af_neighbor_delete, "compval": "neighbors.address_family.route_map", "result": { "as_number": "{{ as_num }}", "neighbors": { "{{ address }}": { "neighbor_address": "{{ address }}", "address_family": { "{{ afi }}": { "afi": "{{ afi }}", "route_map": [ { "action": "{{ action }}", "route_map": "{{ map }}", }, ], }, }, }, }, }, }, { "name": "neighbors.route_reflector_client", "getval": re.compile( r""" ^set \s+protocols \s+bgp \s+neighbor \s+(?P
\S+) \s+address-family \s+(?P\S+)-unicast \s+route-reflector-client *$""", re.VERBOSE, ), "setval": _tmplt_bgp_af_neighbor, "remval": _tmplt_bgp_af_neighbor_delete, "compval": "neighbors.address_family.route_reflector_client", "result": { "as_number": "{{ as_num }}", "neighbors": { "{{ address }}": { "neighbor_address": "{{ address }}", "address_family": { "{{ afi }}": { "afi": "{{ afi }}", "route_reflector_client": "{{ True }}", }, }, }, }, }, }, { "name": "neighbors.route_server_client", "getval": re.compile( r""" ^set \s+protocols \s+bgp \s+neighbor \s+(?P
\S+) \s+address-family \s+(?P\S+)-unicast \s+route-server-client *$""", re.VERBOSE, ), "setval": _tmplt_bgp_af_neighbor, "remval": _tmplt_bgp_af_neighbor_delete, "compval": "neighbors.address_family.route_server_client", "result": { "as_number": "{{ as_num }}", "neighbors": { "{{ address }}": { "neighbor_address": "{{ address }}", "address_family": { "{{ afi }}": { "afi": "{{ afi }}", "route_server_client": "{{ True }}", }, }, }, }, }, }, { "name": "neighbors.soft_reconfiguration", "getval": re.compile( r""" ^set \s+protocols \s+bgp \s+neighbor \s+(?P
\S+) \s+address-family \s+(?P\S+)-unicast \s+soft-reconfiguration \s+inbound *$""", re.VERBOSE, ), "setval": _tmplt_bgp_af_neighbor, "remval": _tmplt_bgp_af_neighbor_delete, "compval": "neighbors.address_family.soft_reconfiguration", "result": { "as_number": "{{ as_num }}", "neighbors": { "{{ address }}": { "neighbor_address": "{{ address }}", "address_family": { "{{ afi }}": { "afi": "{{ afi }}", "soft_reconfiguration": "{{ True }}", }, }, }, }, }, }, { "name": "neighbors.unsuppress_map", "getval": re.compile( r""" ^set \s+protocols \s+bgp \s+neighbor \s+(?P
\S+) \s+address-family \s+(?P\S+)-unicast \s+unsuppress-map - \s+(?P\S+) - *$""", + \s+(?P\S+)\s*$""", re.VERBOSE, ), "setval": _tmplt_bgp_af_neighbor, "remval": _tmplt_bgp_af_neighbor_delete, "compval": "neighbors.address_family.unsuppress_map", "result": { "as_number": "{{ as_num }}", "neighbors": { "{{ address }}": { "neighbor_address": "{{ address }}", "address_family": { "{{ afi }}": { "afi": "{{ afi }}", "unsuppress_map": "{{ map }}", }, }, }, }, }, }, { "name": "neighbors.weight", "getval": re.compile( r""" ^set \s+protocols \s+bgp \s+neighbor \s+(?P
\S+) \s+address-family \s+(?P\S+)-unicast \s+weight - \s+(?P\S+) - *$""", + \s+(?P\S+)\s*$""", re.VERBOSE, ), "setval": _tmplt_bgp_af_neighbor, "remval": _tmplt_bgp_af_neighbor_delete, "compval": "neighbors.address_family.weight", "result": { "as_number": "{{ as_num }}", "neighbors": { "{{ address }}": { "neighbor_address": "{{ address }}", "address_family": { "{{ afi }}": { "afi": "{{ afi }}", "weight": "{{ num }}", }, }, }, }, }, }, ] # fmt: on diff --git a/plugins/module_utils/network/vyos/rm_templates/bgp_global.py b/plugins/module_utils/network/vyos/rm_templates/bgp_global.py index 8c2e2f55..03f6265b 100644 --- a/plugins/module_utils/network/vyos/rm_templates/bgp_global.py +++ b/plugins/module_utils/network/vyos/rm_templates/bgp_global.py @@ -1,1859 +1,1828 @@ # -*- coding: utf-8 -*- # Copyright 2021 Red Hat # GNU General Public License v3.0+ # (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) from __future__ import absolute_import, division, print_function __metaclass__ = type """ The Bgp_global parser templates file. This contains a list of parser definitions and associated functions that facilitates both facts gathering and native command generation for the given network resource. """ import re from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.rm_base.network_template import ( NetworkTemplate, ) def _tmplt_bgp_params_confederation(config_data): command = [] for list_el in config_data["bgp_params"]["confederation"]: for k, v in list_el.items(): command.append( "protocols bgp {as_number} parameters confederation ".format(**config_data) + k + " " + str(v), ) return command def _tmplt_bgp_maximum_paths(config_data): command = [] for list_el in config_data["maximum_paths"]: command.append( "protocols bgp {as_number} maximum-paths ".format(**config_data) + list_el["path"] + " " + str(list_el["count"]), ) return command def _tmplt_delete_bgp_maximum_paths(config_data): command = "protocols bgp {as_number} maximum-paths".format(**config_data) return command def _tmplt_bgp_params_default(config_data): command = "protocols bgp {as_number} parameters default".format(**config_data) if config_data["bgp_params"]["default"].get("no_ipv4_unicast"): command += " no-ipv4-unicast" if config_data["bgp_params"]["default"].get("local_pref"): command += " local-pref {local_pref}".format(**config_data["bgp_params"]["default"]) return command def _tmplt_bgp_neighbor_timers(config_data): command = [] for k, v in config_data["neighbor"]["timers"].items(): command.append( "protocols bgp {as_number} neighbor ".format(**config_data) + config_data["neighbor"]["address"] + " timers " + k + " " + str(v), ) return command def _tmplt_bgp_timers(config_data): command = [] for k, v in config_data["timers"].items(): command.append( "protocols bgp {as_number} ".format(**config_data) + "timers " + k + " " + str(v), ) return command def _tmplt_bgp_neighbor_attribute_unchanged_as_path(config_data): command = "protocols bgp {as_number} ".format( **config_data, ) + "neighbor {address} attribute-unchanged as-path".format(**config_data["neighbor"]) return command def _tmplt_bgp_neighbor_attribute_unchanged_med(config_data): command = "protocols bgp {as_number} ".format( **config_data, ) + "neighbor {address} attribute-unchanged med".format(**config_data["neighbor"]) return command def _tmplt_bgp_neighbor_attribute_unchanged_next_hop(config_data): command = "protocols bgp {as_number} ".format( **config_data, ) + "neighbor {address} attribute-unchanged next-hop".format(**config_data["neighbor"]) return command def _tmplt_bgp_neighbor_distribute_list(config_data): command = [] for list_el in config_data["neighbor"]["distribute_list"]: command.append( "protocols bgp {as_number} ".format(**config_data) + "neighbor {address} distribute-list ".format(**config_data["neighbor"]) + list_el["action"] + " " + str(list_el["acl"]), ) return command def _tmplt_bgp_neighbor_route_map(config_data): command = [] for list_el in config_data["neighbor"]["route_map"]: command.append( "protocols bgp {as_number} ".format(**config_data) + "neighbor {address} route-map ".format(**config_data["neighbor"]) + list_el["action"] + " " + str(list_el["route_map"]), ) return command def _tmplt_bgp_neighbor_prefix_list(config_data): command = [] for list_el in config_data["neighbor"]["prefix_list"]: command.append( "protocols bgp {as_number} ".format(**config_data) + "neighbor {address} prefix-list ".format(**config_data["neighbor"]) + list_el["action"] + " " + str(list_el["prefix_list"]), ) return command def _tmplt_bgp_neighbor_filter_list(config_data): command = [] for list_el in config_data["neighbor"]["filter_list"]: command.append( "protocols bgp {as_number} ".format(**config_data) + "neighbor {address} filter-list ".format(**config_data["neighbor"]) + list_el["action"] + " " + str(list_el["path_list"]), ) return command def _tmplt_bgp_params_distance(config_data): command = ( "protocols bgp {as_number} parameters distance global ".format(**config_data) + config_data["bgp_params"]["distance"]["type"] + " " + str(config_data["bgp_params"]["distance"]["value"]) ) return command class Bgp_globalTemplate(NetworkTemplate): def __init__(self, lines=None, module=None): prefix = {"set": "set", "remove": "delete"} super(Bgp_globalTemplate, self).__init__( lines=lines, tmplt=self, prefix=prefix, module=module, ) # fmt: off PARSERS = [ { "name": "router", "getval": re.compile( r""" ^set \s+protocols \s+bgp \s+(?P\d+) *$""", re.VERBOSE, ), "setval": "protocols bgp {{ as_number }}", "compval": "as_number", "result": { "as_number": "{{ as_num }}", }, }, { "name": "maximum_paths", "getval": re.compile( r""" ^set \s+protocols \s+bgp \s+(?P\d+) \s+maximum-paths \s+(?Pebgp|ibgp) \s+(?P\d+) *$""", re.VERBOSE, ), "setval": _tmplt_bgp_maximum_paths, "remval": _tmplt_delete_bgp_maximum_paths, "compval": "maximum_paths", "result": { "as_number": "{{ as_num }}", "maximum_paths": [ { "path": "{{ path }}", "count": "{{ count }}", }, ], }, }, { "name": "neighbor.advertisement_interval", "getval": re.compile( r""" ^set \s+protocols \s+bgp \s+(?P\d+) \s+neighbor \s+(?P
\S+) \s+advertisement-interval - \s+(?P\S+) - *$""", + \s+(?P\S+)\s*$""", re.VERBOSE, ), "setval": "protocols bgp {{ as_number }} neighbor {{ neighbor.address }} advertisement-interval {{ neighbor.advertisement_interval }}", "remval": "protocols bgp {{ as_number }} neighbor {{ neighbor.address }} advertisement-interval", "compval": "neighbor.advertisement_interval", "result": { "as_number": "{{ as_num }}", "neighbor": { "{{ address }}": { "address": "{{ address }}", "advertisement_interval": "{{ interval }}", }, }, }, }, { "name": "neighbor.allowas_in", "getval": re.compile( r""" ^set \s+protocols \s+bgp \s+(?P\d+) \s+neighbor \s+(?P
\S+) \s+allowas-in \s+number \s+(?P\'\d+\') *$""", re.VERBOSE, ), "setval": "protocols bgp {{ as_number }} neighbor {{ neighbor.address }} allowas-in number {{ neighbor.allowas_in }}", "compval": "neighbor.allowas_in", "result": { "as_number": "{{ as_num }}", "neighbor": { "{{ address }}": { "address": "{{ address }}", "allowas_in": "{{ count }}", }, }, }, }, { "name": "neighbor.as_override", "getval": re.compile( r""" ^set \s+protocols \s+bgp \s+(?P\d+) \s+neighbor \s+(?P
\S+) \s+as-override *$""", re.VERBOSE, ), "setval": "protocols bgp {{ as_number }} neighbor {{ neighbor.address }} as-override", "compval": "neighbor.as_override", "result": { "as_number": "{{ as_num }}", "neighbor": { "{{ address }}": { "address": "{{ address }}", "as_override": "{{ True }}", }, }, }, }, { "name": "neighbor.attribute_unchanged.as_path", "getval": re.compile( r""" ^set \s+protocols \s+bgp \s+(?P\d+) \s+neighbor \s+(?P
\S+) \s+attribute-unchanged \s+(?Pas-path) *$""", re.VERBOSE, ), "setval": _tmplt_bgp_neighbor_attribute_unchanged_as_path, "compval": "neighbor.attribute_unchanged", "result": { "as_number": "{{ as_num }}", "neighbor": { "{{ address }}": { "address": "{{ address }}", "attribute_unchanged": { "{{ 'as_path' }}": "{{ True }}", }, }, }, }, }, { "name": "neighbor.attribute_unchanged.med", "getval": re.compile( r""" ^set \s+protocols \s+bgp \s+(?P\d+) \s+neighbor \s+(?P
\S+) \s+attribute-unchanged \s+(?Pmed) *$""", re.VERBOSE, ), "setval": _tmplt_bgp_neighbor_attribute_unchanged_med, "compval": "neighbor.attribute_unchanged", "result": { "as_number": "{{ as_num }}", "neighbor": { "{{ address }}": { "address": "{{ address }}", "attribute_unchanged": { "{{ 'med' }}": "{{ True }}", }, }, }, }, }, { "name": "neighbor.attribute_unchanged.next_hop", "getval": re.compile( r""" ^set \s+protocols \s+bgp \s+(?P\d+) \s+neighbor \s+(?P
\S+) \s+attribute-unchanged \s+(?Pnext-hop) *$""", re.VERBOSE, ), "setval": _tmplt_bgp_neighbor_attribute_unchanged_next_hop, "compval": "neighbor.attribute_unchanged", "result": { "as_number": "{{ as_num }}", "neighbor": { "{{ address }}": { "address": "{{ address }}", "attribute_unchanged": { "{{ 'next_hop' }}": "{{ True }}", }, }, }, }, }, { "name": "neighbor.capability_dynamic", "getval": re.compile( r""" ^set \s+protocols \s+bgp \s+(?P\d+) \s+neighbor \s+(?P
\S+) \s+capability \s+(?Pdynamic) *$""", re.VERBOSE, ), "setval": "protocols bgp {{ as_number }} neighbor {{ neighbor.address }} capability dynamic", "compval": "neighbor.capability.dynamic", "result": { "as_number": "{{ as_num }}", "neighbor": { "{{ address }}": { "address": "{{ address }}", "capability": { "dynamic": "{{ True if dynamic is defined}}", }, }, }, }, }, { "name": "neighbor.capability_orf", "getval": re.compile( r""" ^set \s+protocols \s+bgp \s+(?P\d+) \s+neighbor \s+(?P
\S+) \s+capability \s+orf \s+prefix-list - \s+(?P\S+) - *$""", + \s+(?P\S+)\s*$""", re.VERBOSE, ), "setval": "protocols bgp {{ as_number }} neighbor {{ neighbor.address }} capability orf prefix-list {{ neighbor.capability.orf }}", "compval": "neighbor.capability.orf", "result": { "as_number": "{{ as_num }}", "neighbor": { "{{ address }}": { "address": "{{ address }}", "capability": { "orf": "{{ orf }}", }, }, }, }, }, { "name": "neighbor.default_originate", "getval": re.compile( r""" ^set \s+protocols \s+bgp \s+(?P\d+) \s+neighbor \s+(?P
\S+) \s+default-originate \s+route-map - \s+(?P\S+) - *$""", + \s+(?P\S+)\s*$""", re.VERBOSE, ), "setval": "protocols bgp {{ as_number }} neighbor {{ neighbor.address }} default-originate route-map {{ neighbor.default_originate }}", "compval": "neighbor.advertisement_interval", "result": { "as_number": "{{ as_num }}", "neighbor": { "{{ address }}": { "address": "{{ address }}", "default_originate": "{{ map }}", }, }, }, }, { "name": "neighbor.description", "getval": re.compile( r""" ^set \s+protocols \s+bgp \s+(?P\d+) \s+neighbor \s+(?P
\S+) \s+description - \s+(?P\S+) - *$""", + \s+(?P\S+)\s*$""", re.VERBOSE, ), "setval": "protocols bgp {{ as_number }} neighbor {{ neighbor.address }} description {{ neighbor.description }}", "compval": "neighbor.description", "result": { "as_number": "{{ as_num }}", "neighbor": { "{{ address }}": { "address": "{{ address }}", "description": "{{ desc }}", }, }, }, }, { "name": "neighbor.disable_capability_negotiation", "getval": re.compile( r""" ^set \s+protocols \s+bgp \s+(?P\d+) \s+neighbor \s+(?P
\S+) \s+disable-capability-negotiation *$""", re.VERBOSE, ), "setval": "protocols bgp {{ as_number }} neighbor {{ neighbor.address }} disable-capability-negotiation", "compval": "neighbor.disable_capability_negotiation", "result": { "as_number": "{{ as_num }}", "neighbor": { "{{ address }}": { "address": "{{ address }}", "disable_capability_negotiation": "{{ True }}", }, }, }, }, { "name": "neighbor.disable_connected_check", "getval": re.compile( r""" ^set \s+protocols \s+bgp \s+(?P\d+) \s+neighbor \s+(?P
\S+) \s+disable-connected-check *$""", re.VERBOSE, ), "setval": "protocols bgp {{ as_number }} neighbor {{ neighbor.address }} disable-connected-check", "compval": "neighbor.disable_connected_check", "result": { "as_number": "{{ as_num }}", "neighbor": { "{{ address }}": { "address": "{{ address }}", "disable_connected_check": "{{ True }}", }, }, }, }, { "name": "neighbor.disable_send_community", "getval": re.compile( r""" ^set \s+protocols \s+bgp \s+(?P\d+) \s+neighbor \s+(?P
\S+) \s+disable-send-community - \s+(?P\S+) - *$""", + \s+(?P\S+)\s*$""", re.VERBOSE, ), "setval": "protocols bgp {{ as_number }} neighbor {{ neighbor.address }} disable-send-community {{ neighbor.disable_send_community }}", "compval": "neighbor.disable_send_community", "result": { "as_number": "{{ as_num }}", "neighbor": { "{{ address }}": { "address": "{{ address }}", "disable_send_community": "{{ comm }}", }, }, }, }, { "name": "neighbor.distribute_list", "getval": re.compile( r""" ^set \s+protocols \s+bgp \s+(?P\d+) \s+neighbor \s+(?P
\S+) \s+distribute-list \s+(?Pexport|import) \s+(?P\d+) *$""", re.VERBOSE, ), "setval": _tmplt_bgp_neighbor_distribute_list, "compval": "neighbor.distribute_list", "result": { "as_number": "{{ as_num }}", "neighbor": { "{{ address }}": { "address": "{{ address }}", "distribute_list": [ { "action": "{{ action }}", "acl": "{{ list }}", }, ], }, }, }, }, { "name": "neighbor.ebgp_multihop", "getval": re.compile( r""" ^set \s+protocols \s+bgp \s+(?P\d+) \s+neighbor \s+(?P
\S+) \s+ebgp-multihop - \s+(?P\S+) - *$""", + \s+(?P\S+)\s*$""", re.VERBOSE, ), "setval": "protocols bgp {{ as_number }} neighbor {{ neighbor.address }} ebgp-multihop {{ neighbor.ebgp_multihop }}", "compval": "neighbor.ebgp_multihop", "result": { "as_number": "{{ as_num }}", "neighbor": { "{{ address }}": { "address": "{{ address }}", "ebgp_multihop": "{{ hop|int }}", }, }, }, }, { "name": "neighbor.filter_list", "getval": re.compile( r""" ^set \s+protocols \s+bgp \s+(?P\d+) \s+neighbor \s+(?P
\S+) \s+filter-list \s+(?Pexport|import) - \s+(?P\S+) - *$""", + \s+(?P\S+)\s*$""", re.VERBOSE, ), "setval": _tmplt_bgp_neighbor_filter_list, "compval": "neighbor.filter_list", "result": { "as_number": "{{ as_num }}", "neighbor": { "{{ address }}": { "address": "{{ address }}", "filter_list": [ { "action": "{{ action }}", "path_list": "{{ list }}", }, ], }, }, }, }, { "name": "neighbor.local_as", "getval": re.compile( r""" ^set \s+protocols \s+bgp \s+(?P\d+) \s+neighbor \s+(?P
\S+) \s+local-as \s+(?P\S+) \s+no-prepend *$""", re.VERBOSE, ), "setval": "protocols bgp {{ as_number }} neighbor {{ neighbor.address }} local-as {{ neighbor.local_as }} no-prepend", "compval": "neighbor.local_as", "result": { "as_number": "{{ as_num }}", "neighbor": { "{{ address }}": { "address": "{{ address }}", "local_as": "{{ as }}", }, }, }, }, { "name": "neighbor.maximum_prefix", "getval": re.compile( r""" ^set \s+protocols \s+bgp \s+(?P\d+) \s+neighbor \s+(?P
\S+) \s+maximum-prefix - \s+(?P\S+) - *$""", + \s+(?P\S+)\s*$""", re.VERBOSE, ), "setval": "protocols bgp {{ as_number }} neighbor {{ neighbor.address }} maximum-prefix {{ neighbor.maximum_prefix }}", "compval": "neighbor.maximum_prefix", "result": { "as_number": "{{ as_num }}", "neighbor": { "{{ address }}": { "address": "{{ address }}", "maximum_prefix": "{{ num }}", }, }, }, }, { "name": "neighbor.nexthop_self", "getval": re.compile( r""" ^set \s+protocols \s+bgp \s+(?P\d+) \s+neighbor \s+(?P
\S+) \s+nexthop-self *$""", re.VERBOSE, ), "setval": "protocols bgp {{ as_number }} neighbor {{ neighbor.address }} nexthop-self", "compval": "neighbor.nexthop_self", "result": { "as_number": "{{ as_num }}", "neighbor": { "{{ address }}": { "address": "{{ address }}", "nexthop_self": "{{ True }}", }, }, }, }, { "name": "neighbor.override_capability", "getval": re.compile( r""" ^set \s+protocols \s+bgp \s+(?P\d+) \s+neighbor \s+(?P
\S+) \s+override-capability *$""", re.VERBOSE, ), "setval": "protocols bgp {{ as_number }} neighbor {{ neighbor.address }} override-capability", "compval": "neighbor.override_capability", "result": { "as_number": "{{ as_num }}", "neighbor": { "{{ address }}": { "address": "{{ address }}", "override_capability": "{{ True }}", }, }, }, }, { "name": "neighbor.passive", "getval": re.compile( r""" ^set \s+protocols \s+bgp \s+(?P\d+) \s+neighbor \s+(?P
\S+) \s+passive *$""", re.VERBOSE, ), "setval": "protocols bgp {{ as_number }} neighbor {{ neighbor.address }} passive", "compval": "neighbor.passive", "result": { "as_number": "{{ as_num }}", "neighbor": { "{{ address }}": { "address": "{{ address }}", "passive": "{{ True }}", }, }, }, }, { "name": "neighbor.password", "getval": re.compile( r""" ^set \s+protocols \s+bgp \s+(?P\d+) \s+neighbor \s+(?P
\S+) \s+password - \s+(?P\S+) - *$""", + \s+(?P\S+)\s*$""", re.VERBOSE, ), "setval": "protocols bgp {{ as_number }} neighbor {{ neighbor.address }} password {{ neighbor.password }}", "compval": "neighbor.password", "result": { "as_number": "{{ as_num }}", "neighbor": { "{{ address }}": { "address": "{{ address }}", "password": "{{ pwd }}", }, }, }, }, { "name": "neighbor.peer_group_name", "getval": re.compile( r""" ^set \s+protocols \s+bgp \s+(?P\d+) \s+neighbor \s+(?P
\S+) \s+peer-group - \s+(?P\S+) - *$""", + \s+(?P\S+)\s*$""", re.VERBOSE, ), "setval": "protocols bgp {{ as_number }} neighbor {{ neighbor.address }} peer-group {{ neighbor.peer_group_name }}", "compval": "neighbor.peer_group_name", "result": { "as_number": "{{ as_num }}", "neighbor": { "{{ address }}": { "address": "{{ address }}", "peer_group_name": "{{ name }}", }, }, }, }, { "name": "neighbor.port", "getval": re.compile( r""" ^set \s+protocols \s+bgp \s+(?P\d+) \s+neighbor \s+(?P
\S+) \s+port - \s+(?P\S+) - *$""", + \s+(?P\S+)\s*$""", re.VERBOSE, ), "setval": "protocols bgp {{ as_number }} neighbor {{ neighbor.address }} port {{ neighbor.port }}", "compval": "neighbor.port", "result": { "as_number": "{{ as_num }}", "neighbor": { "{{ address }}": { "address": "{{ address }}", "port": "{{ num|int }}", }, }, }, }, { "name": "neighbor.prefix_list", "getval": re.compile( r""" ^set \s+protocols \s+bgp \s+(?P\d+) \s+neighbor \s+(?P
\S+) \s+prefix-list \s+(?Pexport|import) - \s+(?P\S+) - *$""", + \s+(?P\S+)\s*$""", re.VERBOSE, ), "setval": _tmplt_bgp_neighbor_prefix_list, "compval": "neighbor.prefix_list", "result": { "as_number": "{{ as_num }}", "neighbor": { "{{ address }}": { "address": "{{ address }}", "prefix_list": [ { "action": "{{ action }}", "prefix_list": "{{ list }}", }, ], }, }, }, }, { "name": "neighbor.remote_as", "getval": re.compile( r""" ^set \s+protocols \s+bgp \s+(?P\d+) \s+neighbor \s+(?P
\S+) \s+remote-as - \s+(?P\S+) - *$""", + \s+(?P\S+)\s*$""", re.VERBOSE, ), "setval": "protocols bgp {{ as_number }} neighbor {{ neighbor.address }} remote-as {{ neighbor.remote_as }}", "compval": "neighbor.remote_as", "result": { "as_number": "{{ as_num }}", "neighbor": { "{{ address }}": { "address": "{{ address }}", "remote_as": "{{ num|int }}", }, }, }, }, { "name": "neighbor.remove_private_as", "getval": re.compile( r""" ^set \s+protocols \s+bgp \s+(?P\d+) \s+neighbor \s+(?P
\S+) \s+remote-private-as *$""", re.VERBOSE, ), "setval": "protocols bgp {{ as_number }} neighbor {{ neighbor.address }} remote-private-as", "compval": "neighbor.remove_private_as", "result": { "as_number": "{{ as_num }}", "neighbor": { "{{ address }}": { "address": "{{ address }}", "remove_private_as": "{{ True }}", }, }, }, }, { "name": "neighbor.route_map", "getval": re.compile( r""" ^set \s+protocols \s+bgp \s+(?P\d+) \s+neighbor \s+(?P
\S+) \s+route-map \s+(?Pexport|import) - \s+(?P\S+) - *$""", + \s+(?P\S+)\s*$""", re.VERBOSE, ), "setval": _tmplt_bgp_neighbor_route_map, "compval": "neighbor.route_map", "result": { "as_number": "{{ as_num }}", "neighbor": { "{{ address }}": { "address": "{{ address }}", "route_map": [ { "action": "{{ action }}", "route_map": "{{ map }}", }, ], }, }, }, }, { "name": "neighbor.route_reflector_client", "getval": re.compile( r""" ^set \s+protocols \s+bgp \s+(?P\d+) \s+neighbor \s+(?P
\S+) \s+route-reflector-client *$""", re.VERBOSE, ), "setval": "protocols bgp {{ as_number }} neighbor {{ neighbor.address }} router-reflector-client", "compval": "neighbor.route_reflector_client", "result": { "as_number": "{{ as_num }}", "neighbor": { "{{ address }}": { "address": "{{ address }}", "route_reflector_client": "{{ True }}", }, }, }, }, { "name": "neighbor.route_server_client", "getval": re.compile( r""" ^set \s+protocols \s+bgp \s+(?P\d+) \s+neighbor \s+(?P
\S+) \s+route-server-client *$""", re.VERBOSE, ), "setval": "protocols bgp {{ as_number }} neighbor {{ neighbor.address }} route-server-client", "compval": "neighbor.route_server_client", "result": { "as_number": "{{ as_num }}", "neighbor": { "{{ address }}": { "address": "{{ address }}", "route_server_client": "{{ True }}", }, }, }, }, { "name": "neighbor.shutdown", "getval": re.compile( r""" ^set \s+protocols \s+bgp \s+(?P\d+) \s+neighbor \s+(?P
\S+) \s+shutdown *$""", re.VERBOSE, ), "setval": "protocols bgp {{ as_number }} neighbor {{ neighbor.address }} shutdown", "compval": "neighbor.shutdown", "result": { "as_number": "{{ as_num }}", "neighbor": { "{{ address }}": { "address": "{{ address }}", "shutdown": "{{ True }}", }, }, }, }, { "name": "neighbor.soft_reconfiguration", "getval": re.compile( r""" ^set \s+protocols \s+bgp \s+(?P\d+) \s+neighbor \s+(?P
\S+) \s+soft-reconfiguration \s+inbound *$""", re.VERBOSE, ), "setval": "protocols bgp {{ as_number }} neighbor {{ neighbor.address }} soft-reconfiguration", "compval": "neighbor.soft_reconfiguration", "result": { "as_number": "{{ as_num }}", "neighbor": { "{{ address }}": { "address": "{{ address }}", "soft_reconfiguration": "{{ True }}", }, }, }, }, { "name": "neighbor.strict_capability_match", "getval": re.compile( r""" ^set \s+protocols \s+bgp \s+(?P\d+) \s+neighbor \s+(?P
\S+) \s+strict-capability-match *$""", re.VERBOSE, ), "setval": "protocols bgp {{ as_number }} neighbor {{ neighbor.address }} strict-capability-match", "compval": "neighbor.strict_capability_match", "result": { "as_number": "{{ as_num }}", "neighbor": { "{{ address }}": { "address": "{{ address }}", "strict_capability_match": "{{ True }}", }, }, }, }, { "name": "neighbor.unsuppress_map", "getval": re.compile( r""" ^set \s+protocols \s+bgp \s+(?P\d+) \s+neighbor \s+(?P
\S+) \s+unsuppress-map - \s+(?P\S+) - *$""", + \s+(?P\S+)\s*$""", re.VERBOSE, ), "setval": "protocols bgp {{ as_number }} neighbor {{ neighbor.address }} unsuppress-map {{ neighbor.unsuppress_map }}", "compval": "neighbor.unsuppress_map", "result": { "as_number": "{{ as_num }}", "neighbor": { "{{ address }}": { "address": "{{ address }}", "unsuppress_map": "{{ map }}", }, }, }, }, { "name": "neighbor.update_source", "getval": re.compile( r""" ^set \s+protocols \s+bgp \s+(?P\d+) \s+neighbor \s+(?P
\S+) \s+update-source - \s+(?P\S+) - *$""", + \s+(?P\S+)\s*$""", re.VERBOSE, ), "setval": "protocols bgp {{ as_number }} neighbor {{ neighbor.address }} update-source {{ neighbor.update_source }}", "compval": "neighbor.update_source", "result": { "as_number": "{{ as_num }}", "neighbor": { "{{ address }}": { "address": "{{ address }}", "update_source": "{{ src }}", }, }, }, }, { "name": "neighbor.weight", "getval": re.compile( r""" ^set \s+protocols \s+bgp \s+(?P\d+) \s+neighbor \s+(?P
\S+) \s+weight - \s+(?P\S+) - *$""", + \s+(?P\S+)\s*$""", re.VERBOSE, ), "setval": "protocols bgp {{ as_number }} neighbor {{ neighbor.address }} weight {{ neighbor.weight }}", "compval": "neighbor.weight", "result": { "as_number": "{{ as_num }}", "neighbor": { "{{ address }}": { "address": "{{ address }}", "weight": "{{ num }}", }, }, }, }, { "name": "neighbor.ttl_security", "getval": re.compile( r""" ^set \s+protocols \s+bgp \s+(?P\d+) \s+neighbor \s+(?P
\S+) \s+ttl-security - \s+(?P\S+) - *$""", + \s+(?P\S+)\s*$""", re.VERBOSE, ), "setval": "protocols bgp {{ as_number }} neighbor {{ neighbor.address }} ttl-security {{ neighbor.ttl_security }}", "compval": "neighbor.ttl_security", "result": { "as_number": "{{ as_num }}", "neighbor": { "{{ address }}": { "address": "{{ address }}", "ttl_security": "{{ ttl|int }}", }, }, }, }, { "name": "neighbor.timers", "getval": re.compile( r""" ^set \s+protocols \s+bgp \s+(?P\d+) \s+neighbor \s+(?P
\S+) \s+timers \s+(?Pconnect|holdtime|keepalive) - \s+(?P\S+) - *$""", + \s+(?P\S+)\s*$""", re.VERBOSE, ), "setval": _tmplt_bgp_neighbor_timers, "remval": "protocols bgp {{ as_number }} neighbor {{ neighbor.address }} timers", "compval": "neighbor.timers", "result": { "as_number": "{{ as_num }}", "neighbor": { "{{ address }}": { "address": "{{ address }}", "timers": { "{{ type }}": "{{ sec }}", }, }, }, }, }, { "name": "timers", "getval": re.compile( r""" ^set \s+protocols \s+bgp \s+(?P\d+) \s+timers \s+(?P\S+) - \s+(?P\S+) - *$""", + \s+(?P\S+)\s*$""", re.VERBOSE, ), "setval": _tmplt_bgp_timers, "remval": "protocols bgp {{ as_number }} timers", "compval": "timers", "result": { "as_number": "{{ as_num }}", "timers": { "{{ type }}": "{{ val }}", }, }, }, { "name": "bgp_params.always_compare_med", "getval": re.compile( r""" ^set \s+protocols \s+bgp \s+(?P\d+) \s+parameters \s+always-compare-med *$""", re.VERBOSE, ), "setval": "protocols bgp {{ as_number }} parameters always-compare-med", "compval": "bgp_params.always_compare_med", "result": { "as_number": "{{ as_num }}", "bgp_params": { "always_compare_med": "{{ True }}", }, }, }, { "name": "bgp_params.bestpath.as_path", "getval": re.compile( r""" ^set \s+protocols \s+bgp \s+(?P\d+) \s+parameters \s+bestpath \s+as-path \s+(?Pconfed|ignore) *$""", re.VERBOSE, ), "setval": "protocols bgp {{ as_number }} parameters bestpath as-path {{ bgp_params.bestpath.as_path }}", "compval": "bgp_params.bestpath.as_path", "result": { "as_number": "{{ as_num }}", "bgp_params": { "bestpath": { "as_path": "{{ path }}", }, }, }, }, { "name": "bgp_params.bestpath.compare_routerid", "getval": re.compile( r""" ^set \s+protocols \s+bgp \s+(?P\d+) \s+parameters \s+bestpath \s+compare-routerid *$""", re.VERBOSE, ), "setval": "protocols bgp {{ as_number }} parameters bestpath compare-routerid", "compval": "bgp_params.bestpath.compare_routerid", "result": { "as_number": "{{ as_num }}", "bgp_params": { "bestpath": { "compare_routerid": "{{ True }}", }, }, }, }, { "name": "bgp_params.bestpath.med", "getval": re.compile( r""" ^set \s+protocols \s+bgp \s+(?P\d+) \s+parameters \s+bestpath \s+med \s+(?Pconfed|missing-as-worst) *$""", re.VERBOSE, ), "setval": "protocols bgp {{ as_number }} parameters bestpath med {{ bestpath.med }}", "compval": "bgp_params.bestpath.med", "result": { "as_number": "{{ as_num }}", "bgp_params": { "bestpath": { "med": "{{ path }}", }, }, }, }, { "name": "bgp_params.cluster_id", "getval": re.compile( r""" ^set \s+protocols \s+bgp \s+(?P\d+) \s+parameters \s+cluster-id - \s+(?P\S+) - *$""", + \s+(?P\S+)\s*$""", re.VERBOSE, ), "setval": "protocols bgp {{ as_number }} parameters cluster-id {{ bgp_params.cluster_id }}", "compval": "bgp_params.cluster_id", "result": { "as_number": "{{ as_num }}", "bgp_params": { "cluster_id": "{{ id }}", }, }, }, { "name": "bgp_params.confederation", "getval": re.compile( r""" ^set \s+protocols \s+bgp \s+(?P\d+) \s+parameters \s+confederation \s+(?Pidentifier|peers) - \s+(?P\S+) - *$""", + \s+(?P\S+)\s*$""", re.VERBOSE, ), "setval": _tmplt_bgp_params_confederation, "compval": "bgp_params.always_compare_med", "result": { "as_number": "{{ as_num }}", "bgp_params": { "confederation": [ { "peers": "{{ val if type == 'peers' }}", "identifier": "{{ val if type == 'identifier' }}", }, ], }, }, }, { "name": "bgp_params.dampening_half_life", "getval": re.compile( r""" ^set \s+protocols \s+bgp \s+(?P\d+) \s+parameters \s+dampening \s+half-life - \s+(?P\S+) - *$""", + \s+(?P\S+)\s*$""", re.VERBOSE, ), "setval": "protocols bgp {{ as_number }} parameters dampening half-life {{ bgp_params.dampening.half_life}}", "compval": "bgp_params.dampening.half_life", "result": { "as_number": "{{ as_num }}", "bgp_params": { "dampening": { "half_life": "{{ val }}", }, }, }, }, { "name": "bgp_params.dampening_max_suppress_time", "getval": re.compile( r""" ^set \s+protocols \s+bgp \s+(?P\d+) \s+parameters \s+dampening \s+max-suppress-time - \s+(?P\S+) - *$""", + \s+(?P\S+)\s*$""", re.VERBOSE, ), "setval": "protocols bgp {{ as_number }} parameters dampening max-suppress-time {{ bgp_params.dampening.max_suppress_time}}", "compval": "bgp_params.dampening.max_suppress_time", "result": { "as_number": "{{ as_num }}", "bgp_params": { "dampening": { "max_suppress_time": "{{ val }}", }, }, }, }, { "name": "bgp_params.dampening_re_use", "getval": re.compile( r""" ^set \s+protocols \s+bgp \s+(?P\d+) \s+parameters \s+dampening \s+re-use - \s+(?P\S+) - *$""", + \s+(?P\S+)\s*$""", re.VERBOSE, ), "setval": "protocols bgp {{ as_number }} parameters dampening re-use {{ bgp_params.dampening.re_use}}", "compval": "bgp_params.dampening.re_use", "result": { "as_number": "{{ as_num }}", "bgp_params": { "dampening": { "re_use": "{{ val }}", }, }, }, }, { "name": "bgp_params.dampening_start_suppress_time", "getval": re.compile( r""" ^set \s+protocols \s+bgp \s+(?P\d+) \s+parameters \s+dampening \s+start-suppress-time - \s+(?P\S+) - *$""", + \s+(?P\S+)\s*$""", re.VERBOSE, ), "setval": "protocols bgp {{ as_number }} parameters dampening start-suppress-time {{ bgp_params.dampening.start_suppress_time}}", "compval": "bgp_params.dampening.start_suppress_time", "result": { "as_number": "{{ as_num }}", "bgp_params": { "dampening": { "start_suppress_time": "{{ val }}", }, }, }, }, { "name": "bgp_params.default", "getval": re.compile( r""" ^set \s+protocols \s+bgp \s+(?P\d+) \s+parameters \s+default - \s*(?Pno-ipv4-unicast)* - \s*(?Plocal-pref\s\S+) - *$""", + \s*(?Pno-ipv4-unicast)? + \s*(?Plocal-pref\s\S+)?\s*$""", re.VERBOSE, ), "setval": _tmplt_bgp_params_default, "remval": "protocols bgp {{ as_number }} parameters default", "compval": "bgp_params.default", "result": { "as_number": "{{ as_num }}", "bgp_params": { "default": { "no_ipv4_unicast": "{{ True if no_ipv4_unicast is defined }}", "local_pref": "{{ local_pref.split(" " )[1] if local_pref is defined }}", }, }, }, }, { "name": "bgp_params.deterministic_med", "getval": re.compile( r""" ^set \s+protocols \s+bgp \s+(?P\d+) \s+parameters \s+deterministic-med *$""", re.VERBOSE, ), "setval": "protocols bgp {{ as_number }} parameters deterministic-med", "compval": "bgp_params.deterministic_med", "result": { "as_number": "{{ as_num }}", "bgp_params": { "deterministic_med": "{{ True }}", }, }, }, { "name": "bgp_params.disbale_network_import_check", "getval": re.compile( r""" ^set \s+protocols \s+bgp \s+(?P\d+) \s+parameters \s+disable-network-import-check *$""", re.VERBOSE, ), "setval": "protocols bgp {{ as_number }} parameters disable-network-import-check", "compval": "bgp_params.disable_network_import_check", "result": { "as_number": "{{ as_num }}", "bgp_params": { "disable_network_import_check": "{{ True }}", }, }, }, { "name": "bgp_params.distance.prefix", "getval": re.compile( r""" ^set \s+protocols \s+bgp \s+(?P\d+) \s+parameters \s+distance\sprefix \s+(?P\S+) \s+distance - \s+(?P\S+) - *$""", + \s+(?P\S+)\s*$""", re.VERBOSE, ), "setval": "protocols bgp {{ as_number }} parameters distance prefix {{ bgp_params.distance.prefix }} distance {{ bgp_params.distance.value }}", "compval": "bgp_params.distance.prefix", "remval": "protocols bgp {{ as_number }} parameters distance prefix", "result": { "as_number": "{{ as_num }}", "bgp_params": { "distance": [ { "prefix": "{{ prefix }}", "value": "{{ val }}", }, ], }, }, }, { "name": "bgp_params.distance.global", "getval": re.compile( r""" ^set \s+protocols \s+bgp \s+(?P\d+) \s+parameters \s+distance\sglobal \s+(?P\S+) - \s+(?P\S+) - *$""", + \s+(?P\S+)\s*$""", re.VERBOSE, ), "setval": _tmplt_bgp_params_distance, "remval": "protocols bgp {{ as_number }} parameters distance global", "compval": "bgp_params.distance", "result": { "as_number": "{{ as_num }}", "bgp_params": { "distance": [ { "type": "{{ type }}", "value": "{{ val }}", }, ], }, }, }, { "name": "bgp_params.enforce_first_as", "getval": re.compile( r""" ^set \s+protocols \s+bgp \s+(?P\d+) \s+parameters \s+enforce-first-as *$""", re.VERBOSE, ), "setval": "protocols bgp {{ as_number }} parameters enforce-first-as", "compval": "bgp_params.enforce_first_as", "result": { "as_number": "{{ as_num }}", "bgp_params": { "enforce_first_as": "{{ True }}", }, }, }, { "name": "bgp_params.graceful_restart", "getval": re.compile( r""" ^set \s+protocols \s+bgp \s+(?P\d+) \s+parameters \s+graceful-restart\s+stalepath-time - \s+(?P\S+) - *$""", + \s+(?P\S+)\s*$""", re.VERBOSE, ), "setval": "protocols bgp {{ as_number }} parameters graceful-restart stalepath-time {{ bgp_params.graceful_restart }}", "compval": "bgp_params.graceful_restart", "result": { "as_number": "{{ as_num }}", "bgp_params": { "graceful_restart": "{{ val }}", }, }, }, { "name": "bgp_params.log_neighbor_changes", "getval": re.compile( r""" ^set \s+protocols \s+bgp \s+(?P\d+) \s+parameters \s+log-neighbor-changes *$""", re.VERBOSE, ), "setval": "protocols bgp {{ as_number }} parameters log-neighbor-changes", "compval": "bgp_params.log_neighbor_changes", "result": { "as_number": "{{ as_num }}", "bgp_params": { "log_neighbor_changes": "{{ True }}", }, }, }, { "name": "bgp_params.no_client_to_client_reflection", "getval": re.compile( r""" ^set \s+protocols \s+bgp \s+(?P\d+) \s+parameters \s+no-client-to-client-reflection *$""", re.VERBOSE, ), "setval": "protocols bgp {{ as_number }} parameters no-client-to-client-reflection", "compval": "bgp_params.log_neighbor_changes", "result": { "as_number": "{{ as_num }}", "bgp_params": { "no_client_to_client_reflection": "{{ True }}", }, }, }, { "name": "bgp_params.no_fast_external_failover", "getval": re.compile( r""" ^set \s+protocols \s+bgp \s+(?P\d+) \s+parameters \s+no-fast-external-failover *$""", re.VERBOSE, ), "setval": "protocols bgp {{ as_number }} parameters no-fast-external-failover", "compval": "bgp_params.no_fast_external_failover", "result": { "as_number": "{{ as_num }}", "bgp_params": { "no_fast_external_failover": "{{ True }}", }, }, }, { "name": "bgp_params.routerid", "getval": re.compile( r""" ^set \s+protocols \s+bgp \s+(?P\d+) \s+parameters \s+router-id - \s+(?P\S+) - *$""", + \s+(?P\S+)\s*$""", re.VERBOSE, ), "setval": "protocols bgp {{ as_number }} parameters router-id {{ bgp_params.router_id }}", "compval": "bgp_params.router_id", "result": { "as_number": "{{ as_num }}", "bgp_params": { "router_id": "{{ id }}", }, }, }, { "name": "bgp_params.scan_time", "getval": re.compile( r""" ^set \s+protocols \s+bgp \s+(?P\d+) \s+parameters \s+scan-time \s+(?P\d+) *$""", re.VERBOSE, ), "setval": "protocols bgp {{ as_number }} parameters scan-time {{ bgp_params.scan_time }}", "compval": "bgp_params.scan_time", "result": { "as_number": "{{ as_num }}", "bgp_params": { "scan_time": "{{ val }}", }, }, }, ] # fmt: on diff --git a/plugins/module_utils/network/vyos/rm_templates/bgp_global_14.py b/plugins/module_utils/network/vyos/rm_templates/bgp_global_14.py index 39855c1c..cbe21e3a 100644 --- a/plugins/module_utils/network/vyos/rm_templates/bgp_global_14.py +++ b/plugins/module_utils/network/vyos/rm_templates/bgp_global_14.py @@ -1,1795 +1,1764 @@ # -*- coding: utf-8 -*- # Copyright 2021 Red Hat # GNU General Public License v3.0+ # (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) from __future__ import absolute_import, division, print_function __metaclass__ = type """ The Bgp_global parser templates file. This contains a list of parser definitions and associated functions that facilitates both facts gathering and native command generation for the given network resource. """ import re from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.rm_base.network_template import ( NetworkTemplate, ) def _tmplt_bgp_params_confederation(config_data): command = [] for list_el in config_data["bgp_params"]["confederation"]: for k, v in list_el.items(): command.append( "protocols bgp parameters confederation ".format(**config_data) + k + " " + str(v), ) return command def _tmplt_bgp_maximum_paths(config_data): command = [] for list_el in config_data["maximum_paths"]: command.append( "protocols bgp maximum-paths ".format(**config_data) + list_el["path"] + " " + str(list_el["count"]), ) return command def _tmplt_delete_bgp_maximum_paths(config_data): command = "protocols bgp maximum-paths".format(**config_data) return command def _tmplt_bgp_params_default(config_data): command = "protocols bgp parameters default".format(**config_data) if config_data["bgp_params"]["default"].get("no_ipv4_unicast"): command += " no-ipv4-unicast" if config_data["bgp_params"]["default"].get("local_pref"): command += " local-pref {local_pref}".format(**config_data["bgp_params"]["default"]) return command def _tmplt_bgp_neighbor_timers(config_data): command = [] for k, v in config_data["neighbor"]["timers"].items(): command.append( "protocols bgp neighbor ".format(**config_data) + config_data["neighbor"]["address"] + " timers " + k + " " + str(v), ) return command def _tmplt_bgp_timers(config_data): command = [] for k, v in config_data["timers"].items(): command.append( "protocols bgp ".format(**config_data) + "timers " + k + " " + str(v), ) return command def _tmplt_bgp_neighbor_attribute_unchanged_as_path(config_data): command = "protocols bgp ".format( **config_data, ) + "neighbor {address} attribute-unchanged as-path".format(**config_data["neighbor"]) return command def _tmplt_bgp_neighbor_attribute_unchanged_med(config_data): command = "protocols bgp ".format( **config_data, ) + "neighbor {address} attribute-unchanged med".format(**config_data["neighbor"]) return command def _tmplt_bgp_neighbor_attribute_unchanged_next_hop(config_data): command = "protocols bgp ".format( **config_data, ) + "neighbor {address} attribute-unchanged next-hop".format(**config_data["neighbor"]) return command def _tmplt_bgp_neighbor_distribute_list(config_data): command = [] for list_el in config_data["neighbor"]["distribute_list"]: command.append( "protocols bgp ".format(**config_data) + "neighbor {address} distribute-list ".format(**config_data["neighbor"]) + list_el["action"] + " " + str(list_el["acl"]), ) return command def _tmplt_bgp_neighbor_route_map(config_data): command = [] for list_el in config_data["neighbor"]["route_map"]: command.append( "protocols bgp ".format(**config_data) + "neighbor {address} route-map ".format(**config_data["neighbor"]) + list_el["action"] + " " + str(list_el["route_map"]), ) return command def _tmplt_bgp_neighbor_prefix_list(config_data): command = [] for list_el in config_data["neighbor"]["prefix_list"]: command.append( "protocols bgp ".format(**config_data) + "neighbor {address} prefix-list ".format(**config_data["neighbor"]) + list_el["action"] + " " + str(list_el["prefix_list"]), ) return command def _tmplt_bgp_neighbor_filter_list(config_data): command = [] for list_el in config_data["neighbor"]["filter_list"]: command.append( "protocols bgp ".format(**config_data) + "neighbor {address} filter-list ".format(**config_data["neighbor"]) + list_el["action"] + " " + str(list_el["path_list"]), ) return command def _tmplt_bgp_params_distance(config_data): command = ( "protocols bgp parameters distance global ".format(**config_data) + config_data["bgp_params"]["distance"]["type"] + " " + str(config_data["bgp_params"]["distance"]["value"]) ) return command class Bgp_globalTemplate14(NetworkTemplate): def __init__(self, lines=None, module=None): prefix = {"set": "set", "remove": "delete"} super(Bgp_globalTemplate14, self).__init__( lines=lines, tmplt=self, prefix=prefix, module=module, ) # fmt: off PARSERS = [ { "name": "router", "getval": re.compile( r""" ^set \s+protocols \s+bgp \s*system-as \s+(?P\d+) *$""", re.VERBOSE, ), "setval": "protocols bgp system-as {{ as_number }}", "remval": "protocols bgp", "compval": "as_number", "result": { "as_number": "{{ as_num }}", }, }, { "name": "maximum_paths", "getval": re.compile( r""" ^set \s+protocols \s+bgp \s+maximum-paths \s+(?Pebgp|ibgp) \s+(?P\d+) *$""", re.VERBOSE, ), "setval": _tmplt_bgp_maximum_paths, "remval": _tmplt_delete_bgp_maximum_paths, "compval": "maximum_paths", "result": { "as_number": "{{ as_num }}", "maximum_paths": [ { "path": "{{ path }}", "count": "{{ count }}", }, ], }, }, { "name": "neighbor.advertisement_interval", "getval": re.compile( r""" ^set \s+protocols \s+bgp \s+neighbor \s+(?P
\S+) \s+advertisement-interval - \s+(?P\S+) - *$""", + \s+(?P\S+)\s*$""", re.VERBOSE, ), "setval": "protocols bgp neighbor {{ neighbor.address }} advertisement-interval {{ neighbor.advertisement_interval }}", "remval": "protocols bgp neighbor {{ neighbor.address }} advertisement-interval", "compval": "neighbor.advertisement_interval", "result": { "as_number": "{{ as_num }}", "neighbor": { "{{ address }}": { "address": "{{ address }}", "advertisement_interval": "{{ interval }}", }, }, }, }, { "name": "neighbor.allowas_in", "getval": re.compile( r""" ^set \s+protocols \s+bgp \s+neighbor \s+(?P
\S+) \s+allowas-in \s+number \s+(?P\'\d+\') *$""", re.VERBOSE, ), "setval": "protocols bgp neighbor {{ neighbor.address }} allowas-in number {{ neighbor.allowas_in }}", "compval": "neighbor.allowas_in", "result": { "as_number": "{{ as_num }}", "neighbor": { "{{ address }}": { "address": "{{ address }}", "allowas_in": "{{ count }}", }, }, }, }, { "name": "neighbor.as_override", "getval": re.compile( r""" ^set \s+protocols \s+bgp \s+neighbor \s+(?P
\S+) \s+as-override *$""", re.VERBOSE, ), "setval": "protocols bgp neighbor {{ neighbor.address }} as-override", "compval": "neighbor.as_override", "result": { "as_number": "{{ as_num }}", "neighbor": { "{{ address }}": { "address": "{{ address }}", "as_override": "{{ True }}", }, }, }, }, { "name": "neighbor.attribute_unchanged.as_path", "getval": re.compile( r""" ^set \s+protocols \s+bgp \s+neighbor \s+(?P
\S+) \s+attribute-unchanged \s+(?Pas-path) *$""", re.VERBOSE, ), "setval": _tmplt_bgp_neighbor_attribute_unchanged_as_path, "compval": "neighbor.attribute_unchanged", "result": { "as_number": "{{ as_num }}", "neighbor": { "{{ address }}": { "address": "{{ address }}", "attribute_unchanged": { "{{ 'as_path' }}": "{{ True }}", }, }, }, }, }, { "name": "neighbor.attribute_unchanged.med", "getval": re.compile( r""" ^set \s+protocols \s+bgp \s+neighbor \s+(?P
\S+) \s+attribute-unchanged \s+(?Pmed) *$""", re.VERBOSE, ), "setval": _tmplt_bgp_neighbor_attribute_unchanged_med, "compval": "neighbor.attribute_unchanged", "result": { "as_number": "{{ as_num }}", "neighbor": { "{{ address }}": { "address": "{{ address }}", "attribute_unchanged": { "{{ 'med' }}": "{{ True }}", }, }, }, }, }, { "name": "neighbor.attribute_unchanged.next_hop", "getval": re.compile( r""" ^set \s+protocols \s+bgp \s+neighbor \s+(?P
\S+) \s+attribute-unchanged \s+(?Pnext-hop) *$""", re.VERBOSE, ), "setval": _tmplt_bgp_neighbor_attribute_unchanged_next_hop, "compval": "neighbor.attribute_unchanged", "result": { "as_number": "{{ as_num }}", "neighbor": { "{{ address }}": { "address": "{{ address }}", "attribute_unchanged": { "{{ 'next_hop' }}": "{{ True }}", }, }, }, }, }, { "name": "neighbor.capability_dynamic", "getval": re.compile( r""" ^set \s+protocols \s+bgp \s+neighbor \s+(?P
\S+) \s+capability \s+(?Pdynamic) *$""", re.VERBOSE, ), "setval": "protocols bgp neighbor {{ neighbor.address }} capability dynamic", "compval": "neighbor.capability.dynamic", "result": { "as_number": "{{ as_num }}", "neighbor": { "{{ address }}": { "address": "{{ address }}", "capability": { "dynamic": "{{ True if dynamic is defined}}", }, }, }, }, }, { "name": "neighbor.capability_orf", "getval": re.compile( r""" ^set \s+protocols \s+bgp \s+neighbor \s+(?P
\S+) \s+capability \s+orf \s+prefix-list - \s+(?P\S+) - *$""", + \s+(?P\S+)\s*$""", re.VERBOSE, ), "setval": "protocols bgp neighbor {{ neighbor.address }} capability orf prefix-list {{ neighbor.capability.orf }}", "compval": "neighbor.capability.orf", "result": { "as_number": "{{ as_num }}", "neighbor": { "{{ address }}": { "address": "{{ address }}", "capability": { "orf": "{{ orf }}", }, }, }, }, }, { "name": "neighbor.default_originate", "getval": re.compile( r""" ^set \s+protocols \s+bgp \s+neighbor \s+(?P
\S+) \s+default-originate \s+route-map - \s+(?P\S+) - *$""", + \s+(?P\S+)\s*$""", re.VERBOSE, ), "setval": "protocols bgp neighbor {{ neighbor.address }} default-originate route-map {{ neighbor.default_originate }}", "compval": "neighbor.advertisement_interval", "result": { "as_number": "{{ as_num }}", "neighbor": { "{{ address }}": { "address": "{{ address }}", "default_originate": "{{ map }}", }, }, }, }, { "name": "neighbor.description", "getval": re.compile( r""" ^set \s+protocols \s+bgp \s+neighbor \s+(?P
\S+) \s+description - \s+(?P\S+) - *$""", + \s+(?P\S+)\s*$""", re.VERBOSE, ), "setval": "protocols bgp neighbor {{ neighbor.address }} description {{ neighbor.description }}", "compval": "neighbor.description", "result": { "as_number": "{{ as_num }}", "neighbor": { "{{ address }}": { "address": "{{ address }}", "description": "{{ desc }}", }, }, }, }, { "name": "neighbor.disable_capability_negotiation", "getval": re.compile( r""" ^set \s+protocols \s+bgp \s+neighbor \s+(?P
\S+) \s+disable-capability-negotiation *$""", re.VERBOSE, ), "setval": "protocols bgp neighbor {{ neighbor.address }} disable-capability-negotiation", "compval": "neighbor.disable_capability_negotiation", "result": { "as_number": "{{ as_num }}", "neighbor": { "{{ address }}": { "address": "{{ address }}", "disable_capability_negotiation": "{{ True }}", }, }, }, }, { "name": "neighbor.disable_connected_check", "getval": re.compile( r""" ^set \s+protocols \s+bgp \s+neighbor \s+(?P
\S+) \s+disable-connected-check *$""", re.VERBOSE, ), "setval": "protocols bgp neighbor {{ neighbor.address }} disable-connected-check", "compval": "neighbor.disable_connected_check", "result": { "as_number": "{{ as_num }}", "neighbor": { "{{ address }}": { "address": "{{ address }}", "disable_connected_check": "{{ True }}", }, }, }, }, { "name": "neighbor.disable_send_community", "getval": re.compile( r""" ^set \s+protocols \s+bgp \s+neighbor \s+(?P
\S+) \s+disable-send-community - \s+(?P\S+) - *$""", + \s+(?P\S+)\s*$""", re.VERBOSE, ), "setval": "protocols bgp neighbor {{ neighbor.address }} disable-send-community {{ neighbor.disable_send_community }}", "compval": "neighbor.disable_send_community", "result": { "as_number": "{{ as_num }}", "neighbor": { "{{ address }}": { "address": "{{ address }}", "disable_send_community": "{{ comm }}", }, }, }, }, { "name": "neighbor.distribute_list", "getval": re.compile( r""" ^set \s+protocols \s+bgp \s+neighbor \s+(?P
\S+) \s+distribute-list \s+(?Pexport|import) \s+(?P\d+) *$""", re.VERBOSE, ), "setval": _tmplt_bgp_neighbor_distribute_list, "compval": "neighbor.distribute_list", "result": { "as_number": "{{ as_num }}", "neighbor": { "{{ address }}": { "address": "{{ address }}", "distribute_list": [ { "action": "{{ action }}", "acl": "{{ list }}", }, ], }, }, }, }, { "name": "neighbor.ebgp_multihop", "getval": re.compile( r""" ^set \s+protocols \s+bgp \s+neighbor \s+(?P
\S+) \s+ebgp-multihop - \s+(?P\S+) - *$""", + \s+(?P\S+)\s*$""", re.VERBOSE, ), "setval": "protocols bgp neighbor {{ neighbor.address }} ebgp-multihop {{ neighbor.ebgp_multihop }}", "compval": "neighbor.ebgp_multihop", "result": { "as_number": "{{ as_num }}", "neighbor": { "{{ address }}": { "address": "{{ address }}", "ebgp_multihop": "{{ hop|int }}", }, }, }, }, { "name": "neighbor.filter_list", "getval": re.compile( r""" ^set \s+protocols \s+bgp \s+neighbor \s+(?P
\S+) \s+filter-list \s+(?Pexport|import) - \s+(?P\S+) - *$""", + \s+(?P\S+)\s*$""", re.VERBOSE, ), "setval": _tmplt_bgp_neighbor_filter_list, "compval": "neighbor.filter_list", "result": { "as_number": "{{ as_num }}", "neighbor": { "{{ address }}": { "address": "{{ address }}", "filter_list": [ { "action": "{{ action }}", "path_list": "{{ list }}", }, ], }, }, }, }, { "name": "neighbor.local_as", "getval": re.compile( r""" ^set \s+protocols \s+bgp \s+neighbor \s+(?P
\S+) \s+local-as \s+(?P\S+) \s+no-prepend *$""", re.VERBOSE, ), "setval": "protocols bgp neighbor {{ neighbor.address }} local-as {{ neighbor.local_as }} no-prepend", "compval": "neighbor.local_as", "result": { "as_number": "{{ as_num }}", "neighbor": { "{{ address }}": { "address": "{{ address }}", "local_as": "{{ as }}", }, }, }, }, { "name": "neighbor.maximum_prefix", "getval": re.compile( r""" ^set \s+protocols \s+bgp \s+neighbor \s+(?P
\S+) \s+maximum-prefix - \s+(?P\S+) - *$""", + \s+(?P\S+)\s*$""", re.VERBOSE, ), "setval": "protocols bgp neighbor {{ neighbor.address }} maximum-prefix {{ neighbor.maximum_prefix }}", "compval": "neighbor.maximum_prefix", "result": { "as_number": "{{ as_num }}", "neighbor": { "{{ address }}": { "address": "{{ address }}", "maximum_prefix": "{{ num }}", }, }, }, }, { "name": "neighbor.nexthop_self", "getval": re.compile( r""" ^set \s+protocols \s+bgp \s+neighbor \s+(?P
\S+) \s+nexthop-self *$""", re.VERBOSE, ), "setval": "protocols bgp neighbor {{ neighbor.address }} nexthop-self", "compval": "neighbor.nexthop_self", "result": { "as_number": "{{ as_num }}", "neighbor": { "{{ address }}": { "address": "{{ address }}", "nexthop_self": "{{ True }}", }, }, }, }, { "name": "neighbor.override_capability", "getval": re.compile( r""" ^set \s+protocols \s+bgp \s+neighbor \s+(?P
\S+) \s+override-capability *$""", re.VERBOSE, ), "setval": "protocols bgp neighbor {{ neighbor.address }} override-capability", "compval": "neighbor.override_capability", "result": { "as_number": "{{ as_num }}", "neighbor": { "{{ address }}": { "address": "{{ address }}", "override_capability": "{{ True }}", }, }, }, }, { "name": "neighbor.passive", "getval": re.compile( r""" ^set \s+protocols \s+bgp \s+neighbor \s+(?P
\S+) \s+passive *$""", re.VERBOSE, ), "setval": "protocols bgp neighbor {{ neighbor.address }} passive", "compval": "neighbor.passive", "result": { "as_number": "{{ as_num }}", "neighbor": { "{{ address }}": { "address": "{{ address }}", "passive": "{{ True }}", }, }, }, }, { "name": "neighbor.password", "getval": re.compile( r""" ^set \s+protocols \s+bgp \s+neighbor \s+(?P
\S+) \s+password - \s+(?P\S+) - *$""", + \s+(?P\S+)\s*$""", re.VERBOSE, ), "setval": "protocols bgp neighbor {{ neighbor.address }} password {{ neighbor.password }}", "compval": "neighbor.password", "result": { "as_number": "{{ as_num }}", "neighbor": { "{{ address }}": { "address": "{{ address }}", "password": "{{ pwd }}", }, }, }, }, { "name": "neighbor.peer_group_name", "getval": re.compile( r""" ^set \s+protocols \s+bgp \s+neighbor \s+(?P
\S+) \s+peer-group - \s+(?P\S+) - *$""", + \s+(?P\S+)\s*$""", re.VERBOSE, ), "setval": "protocols bgp neighbor {{ neighbor.address }} peer-group {{ neighbor.peer_group_name }}", "compval": "neighbor.peer_group_name", "result": { "as_number": "{{ as_num }}", "neighbor": { "{{ address }}": { "address": "{{ address }}", "peer_group_name": "{{ name }}", }, }, }, }, { "name": "neighbor.port", "getval": re.compile( r""" ^set \s+protocols \s+bgp \s+neighbor \s+(?P
\S+) \s+port - \s+(?P\S+) - *$""", + \s+(?P\S+)\s*$""", re.VERBOSE, ), "setval": "protocols bgp neighbor {{ neighbor.address }} port {{ neighbor.port }}", "compval": "neighbor.port", "result": { "as_number": "{{ as_num }}", "neighbor": { "{{ address }}": { "address": "{{ address }}", "port": "{{ num|int }}", }, }, }, }, { "name": "neighbor.prefix_list", "getval": re.compile( r""" ^set \s+protocols \s+bgp \s+neighbor \s+(?P
\S+) \s+prefix-list \s+(?Pexport|import) - \s+(?P\S+) - *$""", + \s+(?P\S+)\s*$""", re.VERBOSE, ), "setval": _tmplt_bgp_neighbor_prefix_list, "compval": "neighbor.prefix_list", "result": { "as_number": "{{ as_num }}", "neighbor": { "{{ address }}": { "address": "{{ address }}", "prefix_list": [ { "action": "{{ action }}", "prefix_list": "{{ list }}", }, ], }, }, }, }, { "name": "neighbor.remote_as", "getval": re.compile( r""" ^set \s+protocols \s+bgp \s+neighbor \s+(?P
\S+) \s+remote-as - \s+(?P\S+) - *$""", + \s+(?P\S+)\s*$""", re.VERBOSE, ), "setval": "protocols bgp neighbor {{ neighbor.address }} remote-as {{ neighbor.remote_as }}", "compval": "neighbor.remote_as", "result": { "as_number": "{{ as_num }}", "neighbor": { "{{ address }}": { "address": "{{ address }}", "remote_as": "{{ num|int }}", }, }, }, }, { "name": "neighbor.remove_private_as", "getval": re.compile( r""" ^set \s+protocols \s+bgp \s+neighbor \s+(?P
\S+) \s+remote-private-as *$""", re.VERBOSE, ), "setval": "protocols bgp neighbor {{ neighbor.address }} remote-private-as", "compval": "neighbor.remove_private_as", "result": { "as_number": "{{ as_num }}", "neighbor": { "{{ address }}": { "address": "{{ address }}", "remove_private_as": "{{ True }}", }, }, }, }, { "name": "neighbor.route_map", "getval": re.compile( r""" ^set \s+protocols \s+bgp \s+neighbor \s+(?P
\S+) \s+route-map \s+(?Pexport|import) - \s+(?P\S+) - *$""", + \s+(?P\S+)\s*$""", re.VERBOSE, ), "setval": _tmplt_bgp_neighbor_route_map, "compval": "neighbor.route_map", "result": { "as_number": "{{ as_num }}", "neighbor": { "{{ address }}": { "address": "{{ address }}", "route_map": [ { "action": "{{ action }}", "route_map": "{{ map }}", }, ], }, }, }, }, { "name": "neighbor.route_reflector_client", "getval": re.compile( r""" ^set \s+protocols \s+bgp \s+neighbor \s+(?P
\S+) \s+route-reflector-client *$""", re.VERBOSE, ), "setval": "protocols bgp neighbor {{ neighbor.address }} router-reflector-client", "compval": "neighbor.route_reflector_client", "result": { "as_number": "{{ as_num }}", "neighbor": { "{{ address }}": { "address": "{{ address }}", "route_reflector_client": "{{ True }}", }, }, }, }, { "name": "neighbor.route_server_client", "getval": re.compile( r""" ^set \s+protocols \s+bgp \s+neighbor \s+(?P
\S+) \s+route-server-client *$""", re.VERBOSE, ), "setval": "protocols bgp neighbor {{ neighbor.address }} route-server-client", "compval": "neighbor.route_server_client", "result": { "as_number": "{{ as_num }}", "neighbor": { "{{ address }}": { "address": "{{ address }}", "route_server_client": "{{ True }}", }, }, }, }, { "name": "neighbor.shutdown", "getval": re.compile( r""" ^set \s+protocols \s+bgp \s+neighbor \s+(?P
\S+) \s+shutdown *$""", re.VERBOSE, ), "setval": "protocols bgp neighbor {{ neighbor.address }} shutdown", "compval": "neighbor.shutdown", "result": { "as_number": "{{ as_num }}", "neighbor": { "{{ address }}": { "address": "{{ address }}", "shutdown": "{{ True }}", }, }, }, }, { "name": "neighbor.soft_reconfiguration", "getval": re.compile( r""" ^set \s+protocols \s+bgp \s+neighbor \s+(?P
\S+) \s+soft-reconfiguration \s+inbound *$""", re.VERBOSE, ), "setval": "protocols bgp neighbor {{ neighbor.address }} soft-reconfiguration", "compval": "neighbor.soft_reconfiguration", "result": { "as_number": "{{ as_num }}", "neighbor": { "{{ address }}": { "address": "{{ address }}", "soft_reconfiguration": "{{ True }}", }, }, }, }, { "name": "neighbor.strict_capability_match", "getval": re.compile( r""" ^set \s+protocols \s+bgp \s+neighbor \s+(?P
\S+) \s+strict-capability-match *$""", re.VERBOSE, ), "setval": "protocols bgp neighbor {{ neighbor.address }} strict-capability-match", "compval": "neighbor.strict_capability_match", "result": { "as_number": "{{ as_num }}", "neighbor": { "{{ address }}": { "address": "{{ address }}", "strict_capability_match": "{{ True }}", }, }, }, }, { "name": "neighbor.unsuppress_map", "getval": re.compile( r""" ^set \s+protocols \s+bgp \s+neighbor \s+(?P
\S+) \s+unsuppress-map - \s+(?P\S+) - *$""", + \s+(?P\S+)\s*$""", re.VERBOSE, ), "setval": "protocols bgp neighbor {{ neighbor.address }} unsuppress-map {{ neighbor.unsuppress_map }}", "compval": "neighbor.unsuppress_map", "result": { "as_number": "{{ as_num }}", "neighbor": { "{{ address }}": { "address": "{{ address }}", "unsuppress_map": "{{ map }}", }, }, }, }, { "name": "neighbor.update_source", "getval": re.compile( r""" ^set \s+protocols \s+bgp \s+neighbor \s+(?P
\S+) \s+update-source - \s+(?P\S+) - *$""", + \s+(?P\S+)\s*$""", re.VERBOSE, ), "setval": "protocols bgp neighbor {{ neighbor.address }} update-source {{ neighbor.update_source }}", "compval": "neighbor.update_source", "result": { "as_number": "{{ as_num }}", "neighbor": { "{{ address }}": { "address": "{{ address }}", "update_source": "{{ src }}", }, }, }, }, { "name": "neighbor.weight", "getval": re.compile( r""" ^set \s+protocols \s+bgp \s+neighbor \s+(?P
\S+) \s+weight - \s+(?P\S+) - *$""", + \s+(?P\S+)\s*$""", re.VERBOSE, ), "setval": "protocols bgp neighbor {{ neighbor.address }} weight {{ neighbor.weight }}", "compval": "neighbor.weight", "result": { "as_number": "{{ as_num }}", "neighbor": { "{{ address }}": { "address": "{{ address }}", "weight": "{{ num }}", }, }, }, }, { "name": "neighbor.ttl_security", "getval": re.compile( r""" ^set \s+protocols \s+bgp \s+neighbor \s+(?P
\S+) \s+ttl-security - \s+(?P\S+) - *$""", + \s+(?P\S+)\s*$""", re.VERBOSE, ), "setval": "protocols bgp neighbor {{ neighbor.address }} ttl-security {{ neighbor.ttl_security }}", "compval": "neighbor.ttl_security", "result": { "as_number": "{{ as_num }}", "neighbor": { "{{ address }}": { "address": "{{ address }}", "ttl_security": "{{ ttl|int }}", }, }, }, }, { "name": "neighbor.timers", "getval": re.compile( r""" ^set \s+protocols \s+bgp \s+neighbor \s+(?P
\S+) \s+timers \s+(?Pconnect|holdtime|keepalive) - \s+(?P\S+) - *$""", + \s+(?P\S+)\s*$""", re.VERBOSE, ), "setval": _tmplt_bgp_neighbor_timers, "remval": "protocols bgp neighbor {{ neighbor.address }} timers", "compval": "neighbor.timers", "result": { "as_number": "{{ as_num }}", "neighbor": { "{{ address }}": { "address": "{{ address }}", "timers": { "{{ type }}": "{{ sec }}", }, }, }, }, }, { "name": "timers", "getval": re.compile( r""" ^set \s+protocols \s+bgp \s+timers \s+(?P\S+) - \s+(?P\S+) - *$""", + \s+(?P\S+)\s*$""", re.VERBOSE, ), "setval": _tmplt_bgp_timers, "remval": "protocols bgp timers", "compval": "timers", "result": { "as_number": "{{ as_num }}", "timers": { "{{ type }}": "{{ val }}", }, }, }, { "name": "bgp_params.always_compare_med", "getval": re.compile( r""" ^set \s+protocols \s+bgp \s+parameters \s+always-compare-med *$""", re.VERBOSE, ), "setval": "protocols bgp parameters always-compare-med", "compval": "bgp_params.always_compare_med", "result": { "as_number": "{{ as_num }}", "bgp_params": { "always_compare_med": "{{ True }}", }, }, }, { "name": "bgp_params.bestpath.as_path", "getval": re.compile( r""" ^set \s+protocols \s+bgp \s+parameters \s+bestpath \s+as-path \s+(?Pconfed|ignore) *$""", re.VERBOSE, ), "setval": "protocols bgp parameters bestpath as-path {{ bgp_params.bestpath.as_path }}", "compval": "bgp_params.bestpath.as_path", "result": { "as_number": "{{ as_num }}", "bgp_params": { "bestpath": { "as_path": "{{ path }}", }, }, }, }, { "name": "bgp_params.bestpath.compare_routerid", "getval": re.compile( r""" ^set \s+protocols \s+bgp \s+parameters \s+bestpath \s+compare-routerid *$""", re.VERBOSE, ), "setval": "protocols bgp parameters bestpath compare-routerid", "compval": "bgp_params.bestpath.compare_routerid", "result": { "as_number": "{{ as_num }}", "bgp_params": { "bestpath": { "compare_routerid": "{{ True }}", }, }, }, }, { "name": "bgp_params.bestpath.med", "getval": re.compile( r""" ^set \s+protocols \s+bgp \s+parameters \s+bestpath \s+med \s+(?Pconfed|missing-as-worst) *$""", re.VERBOSE, ), "setval": "protocols bgp parameters bestpath med {{ bestpath.med }}", "compval": "bgp_params.bestpath.med", "result": { "as_number": "{{ as_num }}", "bgp_params": { "bestpath": { "med": "{{ path }}", }, }, }, }, { "name": "bgp_params.cluster_id", "getval": re.compile( r""" ^set \s+protocols \s+bgp \s+parameters \s+cluster-id - \s+(?P\S+) - *$""", + \s+(?P\S+)\s*$""", re.VERBOSE, ), "setval": "protocols bgp parameters cluster-id {{ bgp_params.cluster_id }}", "compval": "bgp_params.cluster_id", "result": { "as_number": "{{ as_num }}", "bgp_params": { "cluster_id": "{{ id }}", }, }, }, { "name": "bgp_params.confederation", "getval": re.compile( r""" ^set \s+protocols \s+bgp \s+parameters \s+confederation \s+(?Pidentifier|peers) - \s+(?P\S+) - *$""", + \s+(?P\S+)\s*$""", re.VERBOSE, ), "setval": _tmplt_bgp_params_confederation, "compval": "bgp_params.always_compare_med", "result": { "as_number": "{{ as_num }}", "bgp_params": { "confederation": [ { "peers": "{{ val if type == 'peers' }}", "identifier": "{{ val if type == 'identifier' }}", }, ], }, }, }, { "name": "bgp_params.dampening_half_life", "getval": re.compile( r""" ^set \s+protocols \s+bgp \s+parameters \s+dampening \s+half-life - \s+(?P\S+) - *$""", + \s+(?P\S+)\s*$""", re.VERBOSE, ), "setval": "protocols bgp parameters dampening half-life {{ bgp_params.dampening.half_life}}", "compval": "bgp_params.dampening.half_life", "result": { "as_number": "{{ as_num }}", "bgp_params": { "dampening": { "half_life": "{{ val }}", }, }, }, }, { "name": "bgp_params.dampening_max_suppress_time", "getval": re.compile( r""" ^set \s+protocols \s+bgp \s+parameters \s+dampening \s+max-suppress-time - \s+(?P\S+) - *$""", + \s+(?P\S+)\s*$""", re.VERBOSE, ), "setval": "protocols bgp parameters dampening max-suppress-time {{ bgp_params.dampening.max_suppress_time}}", "compval": "bgp_params.dampening.max_suppress_time", "result": { "as_number": "{{ as_num }}", "bgp_params": { "dampening": { "max_suppress_time": "{{ val }}", }, }, }, }, { "name": "bgp_params.dampening_re_use", "getval": re.compile( r""" ^set \s+protocols \s+bgp \s+parameters \s+dampening \s+re-use - \s+(?P\S+) - *$""", + \s+(?P\S+)\s*$""", re.VERBOSE, ), "setval": "protocols bgp parameters dampening re-use {{ bgp_params.dampening.re_use}}", "compval": "bgp_params.dampening.re_use", "result": { "as_number": "{{ as_num }}", "bgp_params": { "dampening": { "re_use": "{{ val }}", }, }, }, }, { "name": "bgp_params.dampening_start_suppress_time", "getval": re.compile( r""" ^set \s+protocols \s+bgp \s+parameters \s+dampening \s+start-suppress-time - \s+(?P\S+) - *$""", + \s+(?P\S+)\s*$""", re.VERBOSE, ), "setval": "protocols bgp parameters dampening start-suppress-time {{ bgp_params.dampening.start_suppress_time}}", "compval": "bgp_params.dampening.start_suppress_time", "result": { "as_number": "{{ as_num }}", "bgp_params": { "dampening": { "start_suppress_time": "{{ val }}", }, }, }, }, { "name": "bgp_params.default", "getval": re.compile( r""" ^set \s+protocols \s+bgp \s+parameters \s+default - \s*(?Pno-ipv4-unicast)* - \s*(?Plocal-pref\s\S+) - *$""", + \s*(?Pno-ipv4-unicast)? + \s*(?Plocal-pref\s\S+)?\s*$""", re.VERBOSE, ), "setval": _tmplt_bgp_params_default, "remval": "protocols bgp parameters default", "compval": "bgp_params.default", "result": { "as_number": "{{ as_num }}", "bgp_params": { "default": { "no_ipv4_unicast": "{{ True if no_ipv4_unicast is defined }}", "local_pref": "{{ local_pref.split(" " )[1] if local_pref is defined }}", }, }, }, }, { "name": "bgp_params.deterministic_med", "getval": re.compile( r""" ^set \s+protocols \s+bgp \s+parameters \s+deterministic-med *$""", re.VERBOSE, ), "setval": "protocols bgp parameters deterministic-med", "compval": "bgp_params.deterministic_med", "result": { "as_number": "{{ as_num }}", "bgp_params": { "deterministic_med": "{{ True }}", }, }, }, { "name": "bgp_params.disbale_network_import_check", "getval": re.compile( r""" ^set \s+protocols \s+bgp \s+parameters \s+disable-network-import-check *$""", re.VERBOSE, ), "setval": "protocols bgp parameters disable-network-import-check", "compval": "bgp_params.disable_network_import_check", "result": { "as_number": "{{ as_num }}", "bgp_params": { "disable_network_import_check": "{{ True }}", }, }, }, { "name": "bgp_params.distance.prefix", "getval": re.compile( r""" ^set \s+protocols \s+bgp \s+parameters \s+distance\sprefix \s+(?P\S+) \s+distance - \s+(?P\S+) - *$""", + \s+(?P\S+)\s*$""", re.VERBOSE, ), "setval": "protocols bgp parameters distance prefix {{ bgp_params.distance.prefix }} distance {{ bgp_params.distance.value }}", "compval": "bgp_params.distance.prefix", "remval": "protocols bgp parameters distance prefix", "result": { "as_number": "{{ as_num }}", "bgp_params": { "distance": [ { "prefix": "{{ prefix }}", "value": "{{ val }}", }, ], }, }, }, { "name": "bgp_params.distance.global", "getval": re.compile( r""" ^set \s+protocols \s+bgp \s+parameters \s+distance\sglobal \s+(?P\S+) - \s+(?P\S+) - *$""", + \s+(?P\S+)\s*$""", re.VERBOSE, ), "setval": _tmplt_bgp_params_distance, "remval": "protocols bgp parameters distance global", "compval": "bgp_params.distance", "result": { "as_number": "{{ as_num }}", "bgp_params": { "distance": [ { "type": "{{ type }}", "value": "{{ val }}", }, ], }, }, }, { "name": "bgp_params.enforce_first_as", "getval": re.compile( r""" ^set \s+protocols \s+bgp \s+parameters \s+enforce-first-as *$""", re.VERBOSE, ), "setval": "protocols bgp parameters enforce-first-as", "compval": "bgp_params.enforce_first_as", "result": { "as_number": "{{ as_num }}", "bgp_params": { "enforce_first_as": "{{ True }}", }, }, }, { "name": "bgp_params.graceful_restart", "getval": re.compile( r""" ^set \s+protocols \s+bgp \s+parameters \s+graceful-restart\s+stalepath-time - \s+(?P\S+) - *$""", + \s+(?P\S+)\s*$""", re.VERBOSE, ), "setval": "protocols bgp parameters graceful-restart stalepath-time {{ bgp_params.graceful_restart }}", "compval": "bgp_params.graceful_restart", "result": { "as_number": "{{ as_num }}", "bgp_params": { "graceful_restart": "{{ val }}", }, }, }, { "name": "bgp_params.log_neighbor_changes", "getval": re.compile( r""" ^set \s+protocols \s+bgp \s+parameters \s+log-neighbor-changes *$""", re.VERBOSE, ), "setval": "protocols bgp parameters log-neighbor-changes", "compval": "bgp_params.log_neighbor_changes", "result": { "as_number": "{{ as_num }}", "bgp_params": { "log_neighbor_changes": "{{ True }}", }, }, }, { "name": "bgp_params.no_client_to_client_reflection", "getval": re.compile( r""" ^set \s+protocols \s+bgp \s+parameters \s+no-client-to-client-reflection *$""", re.VERBOSE, ), "setval": "protocols bgp parameters no-client-to-client-reflection", "compval": "bgp_params.log_neighbor_changes", "result": { "as_number": "{{ as_num }}", "bgp_params": { "no_client_to_client_reflection": "{{ True }}", }, }, }, { "name": "bgp_params.no_fast_external_failover", "getval": re.compile( r""" ^set \s+protocols \s+bgp \s+parameters \s+no-fast-external-failover *$""", re.VERBOSE, ), "setval": "protocols bgp parameters no-fast-external-failover", "compval": "bgp_params.no_fast_external_failover", "result": { "as_number": "{{ as_num }}", "bgp_params": { "no_fast_external_failover": "{{ True }}", }, }, }, { "name": "bgp_params.routerid", "getval": re.compile( r""" ^set \s+protocols \s+bgp \s+parameters \s+router-id - \s+(?P\S+) - *$""", + \s+(?P\S+)\s*$""", re.VERBOSE, ), "setval": "protocols bgp parameters router-id {{ bgp_params.router_id }}", "compval": "bgp_params.router_id", "result": { "as_number": "{{ as_num }}", "bgp_params": { "router_id": "{{ id }}", }, }, }, { "name": "bgp_params.scan_time", "getval": re.compile( r""" ^set \s+protocols \s+bgp \s+parameters \s+scan-time \s+(?P\d+) *$""", re.VERBOSE, ), "setval": "protocols bgp parameters scan-time {{ bgp_params.scan_time }}", "compval": "bgp_params.scan_time", "result": { "as_number": "{{ as_num }}", "bgp_params": { "scan_time": "{{ val }}", }, }, }, ] # fmt: on diff --git a/plugins/module_utils/network/vyos/rm_templates/ospf_interfaces.py b/plugins/module_utils/network/vyos/rm_templates/ospf_interfaces.py index 134effca..af04da3b 100644 --- a/plugins/module_utils/network/vyos/rm_templates/ospf_interfaces.py +++ b/plugins/module_utils/network/vyos/rm_templates/ospf_interfaces.py @@ -1,776 +1,773 @@ # -*- coding: utf-8 -*- # Copyright 2020 Red Hat # GNU General Public License v3.0+ # (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) from __future__ import absolute_import, division, print_function __metaclass__ = type """ The Ospf_interfaces parser templates file. This contains a list of parser definitions and associated functions that facilitates both facts gathering and native command generation for the given network resource. """ import re from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.rm_base.network_template import ( NetworkTemplate, ) from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.utils.utils import ( get_interface_type, get_interface_with_vif, ) def _get_parameters(data): if data["afi"] == "ipv6": val = ["ospfv3", "ipv6"] else: val = ["ospf", "ip"] return val def _tmplt_ospf_int_delete(config_data): int_type = get_interface_type(config_data["name"]) name = get_interface_with_vif(config_data["name"]) params = _get_parameters(config_data["address_family"]) command = "interfaces " + int_type + " " + name + " " + params[1] + " " + params[0] return command def _tmplt_ospf_int_cost(config_data): int_type = get_interface_type(config_data["name"]) name = get_interface_with_vif(config_data["name"]) params = _get_parameters(config_data["address_family"]) command = ( "interfaces " + int_type + " " + name + " " + params[1] + " " + params[0] + " cost {cost}".format(**config_data["address_family"]) ) return command def _tmplt_ospf_int_auth_password(config_data): int_type = get_interface_type(config_data["name"]) name = get_interface_with_vif(config_data["name"]) params = _get_parameters(config_data["address_family"]) command = ( "interfaces " + int_type + " " + name + " " + params[1] + " " + params[0] + " authentication plaintext-password {plaintext_password}".format( **config_data["address_family"]["authentication"], ) ) return command def _tmplt_ospf_int_auth_md5(config_data): int_type = get_interface_type(config_data["name"]) name = get_interface_with_vif(config_data["name"]) params = _get_parameters(config_data["address_family"]) command = ( "interfaces " + int_type + " " + name + " " + params[1] + " " + params[0] + " authentication md5 key-id {key_id} ".format( **config_data["address_family"]["authentication"]["md5_key"], ) + "md5-key {key}".format(**config_data["address_family"]["authentication"]["md5_key"]) ) return command def _tmplt_ospf_int_auth_md5_delete(config_data): int_type = get_interface_type(config_data["name"]) name = get_interface_with_vif(config_data["name"]) params = _get_parameters(config_data["address_family"]) command = ( "interfaces " + int_type + " " + name + " " + params[1] + " " + params[0] + " authentication" ) return command def _tmplt_ospf_int_bw(config_data): int_type = get_interface_type(config_data["name"]) name = get_interface_with_vif(config_data["name"]) params = _get_parameters(config_data["address_family"]) command = ( "interfaces " + int_type + " " + name + " " + params[1] + " " + params[0] + " bandwidth {bandwidth}".format(**config_data["address_family"]) ) return command def _tmplt_ospf_int_hello_interval(config_data): int_type = get_interface_type(config_data["name"]) name = get_interface_with_vif(config_data["name"]) params = _get_parameters(config_data["address_family"]) command = ( "interfaces " + int_type + " " + name + " " + params[1] + " " + params[0] + " hello-interval {hello_interval}".format(**config_data["address_family"]) ) return command def _tmplt_ospf_int_dead_interval(config_data): int_type = get_interface_type(config_data["name"]) name = get_interface_with_vif(config_data["name"]) params = _get_parameters(config_data["address_family"]) command = ( "interfaces " + int_type + " " + name + " " + params[1] + " " + params[0] + " dead-interval {dead_interval}".format(**config_data["address_family"]) ) return command def _tmplt_ospf_int_mtu_ignore(config_data): int_type = get_interface_type(config_data["name"]) name = get_interface_with_vif(config_data["name"]) params = _get_parameters(config_data["address_family"]) command = ( "interfaces " + int_type + " " + name + " " + params[1] + " " + params[0] + " mtu-ignore" ) return command def _tmplt_ospf_int_network(config_data): int_type = get_interface_type(config_data["name"]) name = get_interface_with_vif(config_data["name"]) params = _get_parameters(config_data["address_family"]) command = ( "interfaces " + int_type + " " + name + " " + params[1] + " " + params[0] + " network {network}".format(**config_data["address_family"]) ) return command def _tmplt_ospf_int_priority(config_data): int_type = get_interface_type(config_data["name"]) name = get_interface_with_vif(config_data["name"]) params = _get_parameters(config_data["address_family"]) command = ( "interfaces " + int_type + " " + name + " " + params[1] + " " + params[0] + " priority {priority}".format(**config_data["address_family"]) ) return command def _tmplt_ospf_int_retransmit_interval(config_data): int_type = get_interface_type(config_data["name"]) name = get_interface_with_vif(config_data["name"]) params = _get_parameters(config_data["address_family"]) command = ( "interfaces " + int_type + " " + name + " " + params[1] + " " + params[0] + " retransmit-interval {retransmit_interval}".format(**config_data["address_family"]) ) return command def _tmplt_ospf_int_transmit_delay(config_data): int_type = get_interface_type(config_data["name"]) name = get_interface_with_vif(config_data["name"]) params = _get_parameters(config_data["address_family"]) command = ( "interfaces " + int_type + " " + name + " " + params[1] + " " + params[0] + " transmit-delay {transmit_delay}".format(**config_data["address_family"]) ) return command def _tmplt_ospf_int_ifmtu(config_data): int_type = get_interface_type(config_data["name"]) name = get_interface_with_vif(config_data["name"]) params = _get_parameters(config_data["address_family"]) command = ( "interfaces " + int_type + " " + name + " " + params[1] + " " + params[0] + " ifmtu {ifmtu}".format(**config_data["address_family"]) ) return command def _tmplt_ospf_int_instance(config_data): int_type = get_interface_type(config_data["name"]) name = get_interface_with_vif(config_data["name"]) params = _get_parameters(config_data["address_family"]) command = ( "interfaces " + int_type + " " + name + " " + params[1] + " " + params[0] + " instance-id {instance}".format(**config_data["address_family"]) ) return command def _tmplt_ospf_int_passive(config_data): int_type = get_interface_type(config_data["name"]) name = get_interface_with_vif(config_data["name"]) params = _get_parameters(config_data["address_family"]) command = "interfaces " + int_type + " " + name + " " + params[1] + " " + params[0] + " passive" return command class Ospf_interfacesTemplate(NetworkTemplate): def __init__(self, lines=None, module=None): prefix = {"set": "set", "remove": "delete"} super(Ospf_interfacesTemplate, self).__init__( lines=lines, tmplt=self, prefix=prefix, module=module, ) # fmt: off PARSERS = [ { "name": "ip_ospf", "getval": re.compile( r""" ^set \s+interfaces \s+(?P\S+) \s+(?P\S+) (?:\s+vif\s+(?P\d+))? \s+(?Pip|ipv6) \s+(?Pospf|ospfv3) *$""", re.VERBOSE, ), "remval": _tmplt_ospf_int_delete, "compval": "address_family", "result": { "name": "{{ name + '.' + vif if vif is defined else name }}", "address_family": { "{{ afi }}": { "afi": '{{ "ipv4" if afi == "ip" else "ipv6" }}', }, }, }, }, { "name": "authentication_password", "getval": re.compile( r""" ^set \s+interfaces \s+(?P\S+) \s+(?P\S+) (?:\s+vif\s+(?P\d+))? \s+(?Pip|ipv6) \s+(?Pospf|ospfv3) \s+authentication \s+plaintext-password - \s+(?P\S+) - *$""", + \s+(?P\S+)\s*$""", re.VERBOSE, ), "setval": _tmplt_ospf_int_auth_password, "compval": "address_family.authentication", "result": { "name": "{{ name + '.' + vif if vif is defined else name }}", "address_family": { "{{ afi }}": { "afi": '{{ "ipv4" if afi == "ip" else "ipv6" }}', "authentication": { "plaintext_password": "{{ text }}", }, }, }, }, }, { "name": "authentication_md5", "getval": re.compile( r""" ^set \s+interfaces \s+(?P\S+) \s+(?P\S+) (?:\s+vif\s+(?P\d+))? \s+(?Pip|ipv6) \s+(?Pospf|ospfv3) \s+authentication \s+md5 \s+key-id \s+(?P\d+) \s+md5-key - \s+(?P\S+) - *$""", + \s+(?P\S+)\s*$""", re.VERBOSE, ), "setval": _tmplt_ospf_int_auth_md5, "remval": _tmplt_ospf_int_auth_md5_delete, "compval": "address_family.authentication", "result": { "name": "{{ name + '.' + vif if vif is defined else name }}", "address_family": { "{{ afi }}": { "afi": '{{ "ipv4" if afi == "ip" else "ipv6" }}', "authentication": { "md5_key": { "key_id": "{{ id }}", "key": "{{ text }}", }, }, }, }, }, }, { "name": "bandwidth", "getval": re.compile( r""" ^set \s+interfaces \s+(?P\S+) \s+(?P\S+) (?:\s+vif\s+(?P\d+))? \s+(?Pip|ipv6) \s+(?Pospf|ospfv3) \s+bandwidth \s+(?P\'\d+\') *$""", re.VERBOSE, ), "setval": _tmplt_ospf_int_bw, "compval": "address_family.bandwidth", "result": { "name": "{{ name + '.' + vif if vif is defined else name }}", "address_family": { "{{ afi }}": { "afi": '{{ "ipv4" if afi == "ip" else "ipv6" }}', "bandwidth": "{{ bw }}", }, }, }, }, { "name": "cost", "getval": re.compile( r""" ^set \s+interfaces \s+(?P\S+) \s+(?P\S+) (?:\s+vif\s+(?P\d+))? \s+(?Pip|ipv6) \s+(?Pospf|ospfv3) \s+cost \s+(?P\'\d+\') *$""", re.VERBOSE, ), "setval": _tmplt_ospf_int_cost, "compval": "address_family.cost", "result": { "name": "{{ name + '.' + vif if vif is defined else name }}", "address_family": { "{{ afi }}": { "afi": '{{ "ipv4" if afi == "ip" else "ipv6" }}', "cost": "{{ val }}", }, }, }, }, { "name": "hello_interval", "getval": re.compile( r""" ^set \s+interfaces \s+(?P\S+) \s+(?P\S+) (?:\s+vif\s+(?P\d+))? \s+(?Pip|ipv6) \s+(?Pospf|ospfv3) \s+hello-interval \s+(?P\'\d+\') *$""", re.VERBOSE, ), "setval": _tmplt_ospf_int_hello_interval, "compval": "address_family.hello_interval", "result": { "name": "{{ name + '.' + vif if vif is defined else name }}", "address_family": { "{{ afi }}": { "afi": '{{ "ipv4" if afi == "ip" else "ipv6" }}', "hello_interval": "{{ val }}", }, }, }, }, { "name": "dead_interval", "getval": re.compile( r""" ^set \s+interfaces \s+(?P\S+) \s+(?P\S+) (?:\s+vif\s+(?P\d+))? \s+(?Pip|ipv6) \s+(?Pospf|ospfv3) \s+dead-interval \s+(?P\'\d+\') *$""", re.VERBOSE, ), "setval": _tmplt_ospf_int_dead_interval, "compval": "address_family.dead_interval", "result": { "name": "{{ name + '.' + vif if vif is defined else name }}", "address_family": { "{{ afi }}": { "afi": '{{ "ipv4" if afi == "ip" else "ipv6" }}', "dead_interval": "{{ val }}", }, }, }, }, { "name": "mtu_ignore", "getval": re.compile( r""" ^set \s+interfaces \s+(?P\S+) \s+(?P\S+) (?:\s+vif\s+(?P\d+))? \s+(?Pip|ipv6) \s+(?Pospf|ospfv3) \s+(?Pmtu-ignore) *$""", re.VERBOSE, ), "setval": _tmplt_ospf_int_mtu_ignore, "compval": "address_family.mtu_ignore", "result": { "name": "{{ name + '.' + vif if vif is defined else name }}", "address_family": { "{{ afi }}": { "afi": '{{ "ipv4" if afi == "ip" else "ipv6" }}', "mtu_ignore": "{{ True if mtu is defined }}", }, }, }, }, { "name": "network", "getval": re.compile( r""" ^set \s+interfaces \s+(?P\S+) \s+(?P\S+) (?:\s+vif\s+(?P\d+))? \s+(?Pip|ipv6) \s+(?Pospf|ospfv3) \s+network - \s+(?P\S+) - *$""", + \s+(?P\S+)\s*$""", re.VERBOSE, ), "setval": _tmplt_ospf_int_network, "compval": "address_family.network", "result": { "name": "{{ name + '.' + vif if vif is defined else name }}", "address_family": { "{{ afi }}": { "afi": '{{ "ipv4" if afi == "ip" else "ipv6" }}', "network": "{{ val }}", }, }, }, }, { "name": "priority", "getval": re.compile( r""" ^set \s+interfaces \s+(?P\S+) \s+(?P\S+) (?:\s+vif\s+(?P\d+))? \s+(?Pip|ipv6) \s+(?Pospf|ospfv3) \s+priority \s+(?P\'\d+\') *$""", re.VERBOSE, ), "setval": _tmplt_ospf_int_priority, "compval": "address_family.priority", "result": { "name": "{{ name + '.' + vif if vif is defined else name }}", "address_family": { "{{ afi }}": { "afi": '{{ "ipv4" if afi == "ip" else "ipv6" }}', "priority": "{{ val }}", }, }, }, }, { "name": "retransmit_interval", "getval": re.compile( r""" ^set \s+interfaces \s+(?P\S+) \s+(?P\S+) (?:\s+vif\s+(?P\d+))? \s+(?Pip|ipv6) \s+(?Pospf|ospfv3) \s+retransmit-interval \s+(?P\'\d+\') *$""", re.VERBOSE, ), "setval": _tmplt_ospf_int_retransmit_interval, "compval": "address_family.retransmit_interval", "result": { "name": "{{ name + '.' + vif if vif is defined else name }}", "address_family": { "{{ afi }}": { "afi": '{{ "ipv4" if afi == "ip" else "ipv6" }}', "retransmit_interval": "{{ val }}", }, }, }, }, { "name": "transmit_delay", "getval": re.compile( r""" ^set \s+interfaces \s+(?P\S+) \s+(?P\S+) (?:\s+vif\s+(?P\d+))? \s+(?Pip|ipv6) \s+(?Pospf|ospfv3) \s+transmit-delay \s+(?P\'\d+\') *$""", re.VERBOSE, ), "setval": _tmplt_ospf_int_transmit_delay, "compval": "address_family.transmit_delay", "result": { "name": "{{ name + '.' + vif if vif is defined else name }}", "address_family": { "{{ afi }}": { "afi": '{{ "ipv4" if afi == "ip" else "ipv6" }}', "transmit_delay": "{{ val }}", }, }, }, }, { "name": "ifmtu", "getval": re.compile( r""" ^set \s+interfaces \s+(?P\S+) \s+(?P\S+) (?:\s+vif\s+(?P\d+))? \s+(?Pip|ipv6) \s+(?Pospf|ospfv3) \s+ifmtu \s+(?P\'\d+\') *$""", re.VERBOSE, ), "setval": _tmplt_ospf_int_ifmtu, "compval": "address_family.ifmtu", "result": { "name": "{{ name + '.' + vif if vif is defined else name }}", "address_family": { "{{ afi }}": { "afi": '{{ "ipv4" if afi == "ip" else "ipv6" }}', "ifmtu": "{{ val }}", }, }, }, }, { "name": "instance", "getval": re.compile( r""" ^set \s+interfaces \s+(?P\S+) \s+(?P\S+) (?:\s+vif\s+(?P\d+))? \s+(?Pip|ipv6) \s+(?Pospf|ospfv3) \s+instance-id \s+(?P\'\d+\') *$""", re.VERBOSE, ), "setval": _tmplt_ospf_int_instance, "compval": "address_family.instance", "result": { "name": "{{ name + '.' + vif if vif is defined else name }}", "address_family": { "{{ afi }}": { "afi": '{{ "ipv4" if afi == "ip" else "ipv6" }}', "instance": "{{ val }}", }, }, }, }, { "name": "passive", "getval": re.compile( r""" ^set \s+interfaces \s+(?P\S+) \s+(?P\S+) (?:\s+vif\s+(?P\d+))? \s+(?Pip|ipv6) \s+(?Pospf|ospfv3) \s+(?Ppassive) *$""", re.VERBOSE, ), "setval": _tmplt_ospf_int_passive, "compval": "address_family.passive", "result": { "name": "{{ name + '.' + vif if vif is defined else name }}", "address_family": { "{{ afi }}": { "afi": '{{ "ipv4" if afi == "ip" else "ipv6" }}', "passive": "{{ True if pass is defined }}", }, }, }, }, { "name": "interface_name", "getval": re.compile( r""" ^set \s+interfaces \s+(?P\S+) \s+(?P\S+) (?:\s+vif\s+(?P\d+))? .*$""", re.VERBOSE, ), "setval": "set interface {{ type }} {{ name }}", "result": { "name": "{{ name + '.' + vif if vif is defined else name }}", }, }, ] # fmt: on diff --git a/plugins/module_utils/network/vyos/rm_templates/ospf_interfaces_14.py b/plugins/module_utils/network/vyos/rm_templates/ospf_interfaces_14.py index 0d3aa5a7..484d7c44 100644 --- a/plugins/module_utils/network/vyos/rm_templates/ospf_interfaces_14.py +++ b/plugins/module_utils/network/vyos/rm_templates/ospf_interfaces_14.py @@ -1,651 +1,647 @@ # -*- coding: utf-8 -*- # Copyright 2020 Red Hat # GNU General Public License v3.0+ # (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) from __future__ import absolute_import, division, print_function __metaclass__ = type """ The Ospf_interfaces parser templates file. This contains a list of parser definitions and associated functions that facilitates both facts gathering and native command generation for the given network resource. """ import re from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.rm_base.network_template import ( NetworkTemplate, ) def _get_parameters(data): if data["afi"] == "ipv6": val = ["ospfv3", "ipv6"] else: val = ["ospf", "ip"] return val def _tmplt_ospf_int_delete(config_data): params = _get_parameters(config_data["address_family"]) command = ( "protocols " + params[0] + " interface {name}".format(**config_data) ) return command def _tmplt_ospf_int_cost(config_data): params = _get_parameters(config_data["address_family"]) command = ( "protocols " + params[0] + " interface {name}".format(**config_data) + " cost {cost}".format(**config_data["address_family"]) ) return command def _tmplt_ospf_int_auth_password(config_data): params = _get_parameters(config_data["address_family"]) command = ( "protocols " + params[0] + " interface {name}".format(**config_data) + " authentication plaintext-password {plaintext_password}".format( **config_data["address_family"]["authentication"] ) ) return command def _tmplt_ospf_int_auth_md5(config_data): params = _get_parameters(config_data["address_family"]) command = ( "protocols " + params[0] + " interface {name}".format(**config_data) + " authentication md5 key-id {key_id} ".format( **config_data["address_family"]["authentication"]["md5_key"] ) + "md5-key {key}".format(**config_data["address_family"]["authentication"]["md5_key"]) ) return command def _tmplt_ospf_int_auth_md5_delete(config_data): params = _get_parameters(config_data["address_family"]) command = ( "protocols " + params[0] + " interface {name}".format(**config_data) + " authentication" ) return command def _tmplt_ospf_int_bw(config_data): params = _get_parameters(config_data["address_family"]) command = ( "protocols " + params[0] + " interface {name}".format(**config_data) + " bandwidth {bandwidth}".format(**config_data["address_family"]) ) return command def _tmplt_ospf_int_hello_interval(config_data): params = _get_parameters(config_data["address_family"]) command = ( "protocols " + params[0] + " interface {name}".format(**config_data) + " hello-interval {hello_interval}".format(**config_data["address_family"]) ) return command def _tmplt_ospf_int_dead_interval(config_data): params = _get_parameters(config_data["address_family"]) command = ( "protocols " + params[0] + " interface {name}".format(**config_data) + " dead-interval {dead_interval}".format(**config_data["address_family"]) ) return command def _tmplt_ospf_int_mtu_ignore(config_data): params = _get_parameters(config_data["address_family"]) command = ( "protocols " + params[0] + " interface {name}".format(**config_data) + " mtu-ignore" ) return command def _tmplt_ospf_int_network(config_data): params = _get_parameters(config_data["address_family"]) command = ( "protocols " + params[0] + " interface {name}".format(**config_data) + " network {network}".format(**config_data["address_family"]) ) return command def _tmplt_ospf_int_priority(config_data): params = _get_parameters(config_data["address_family"]) command = ( "protocols " + params[0] + " interface {name}".format(**config_data) + " priority {priority}".format(**config_data["address_family"]) ) return command def _tmplt_ospf_int_retransmit_interval(config_data): params = _get_parameters(config_data["address_family"]) command = ( "protocols " + params[0] + " interface {name}".format(**config_data) + " retransmit-interval {retransmit_interval}".format(**config_data["address_family"]) ) return command def _tmplt_ospf_int_transmit_delay(config_data): params = _get_parameters(config_data["address_family"]) command = ( "protocols " + params[0] + " interface {name}".format(**config_data) + " transmit-delay {transmit_delay}".format(**config_data["address_family"]) ) return command def _tmplt_ospf_int_ifmtu(config_data): params = _get_parameters(config_data["address_family"]) command = ( "protocols " + params[0] + " interface {name}".format(**config_data) + " ifmtu {ifmtu}".format(**config_data["address_family"]) ) return command def _tmplt_ospf_int_instance(config_data): params = _get_parameters(config_data["address_family"]) command = ( "protocols " + params[0] + " interface {name}".format(**config_data) + " instance-id {instance}".format(**config_data["address_family"]) ) return command def _tmplt_ospf_int_passive(config_data): params = _get_parameters(config_data["address_family"]) command = ( "protocols " + params[0] + " interface {name}".format(**config_data) + " passive" ) return command class Ospf_interfacesTemplate14(NetworkTemplate): def __init__(self, lines=None, module=None): prefix = {"set": "set", "remove": "delete"} super(Ospf_interfacesTemplate14, self).__init__( lines=lines, tmplt=self, prefix=prefix, module=module ) # fmt: off PARSERS = [ { "name": "ip_ospf", "getval": re.compile( r""" ^set \s+protocols \s+(?Pospf|ospfv3) \s+interface - \s+(?P\S+) - *$""", + \s+(?P\S+)\s*$""", re.VERBOSE, ), "remval": _tmplt_ospf_int_delete, "compval": "address_family", "result": { "name": "{{ name }}", "address_family": { '{{ "ipv4" if proto == "ospf" else "ipv6" }}': { "afi": '{{ "ipv4" if proto == "ospf" else "ipv6" }}', } } } }, { "name": "authentication_password", "getval": re.compile( r""" ^set \s+protocols \s+(?Pospf|ospfv3) \s+interface \s+(?P\S+) \s+authentication \s+plaintext-password - \s+(?P\S+) - *$""", + \s+(?P\S+)\s*$""", re.VERBOSE, ), "setval": _tmplt_ospf_int_auth_password, "compval": "address_family.authentication", "result": { "name": "{{ name }}", "address_family": { '{{ "ipv4" if proto == "ospf" else "ipv6" }}': { "afi": '{{ "ipv4" if proto == "ospf" else "ipv6" }}', "authentication": { "plaintext_password": "{{ text }}" } } } } }, { "name": "authentication_md5", "getval": re.compile( r""" ^set \s+protocols \s+(?Pospf|ospfv3) \s+interface \s+(?P\S+) \s+authentication \s+md5 \s+key-id \s+(?P\d+) \s+md5-key - \s+(?P\S+) - *$""", + \s+(?P\S+)\s*$""", re.VERBOSE, ), "setval": _tmplt_ospf_int_auth_md5, "remval": _tmplt_ospf_int_auth_md5_delete, "compval": "address_family.authentication", "result": { "name": "{{ name }}", "address_family": { '{{ "ipv4" if proto == "ospf" else "ipv6" }}': { "afi": '{{ "ipv4" if proto == "ospf" else "ipv6" }}', "authentication": { "md5_key": { "key_id": "{{ id }}", "key": "{{ text }}" } } } } } }, { "name": "bandwidth", "getval": re.compile( r""" ^set \s+protocols \s+(?Pospf|ospfv3) \s+interface \s+(?P\S+) \s+bandwidth \s+(?P\'\d+\') *$""", re.VERBOSE, ), "setval": _tmplt_ospf_int_bw, "compval": "address_family.bandwidth", "result": { "name": "{{ name }}", "address_family": { '{{ "ipv4" if proto == "ospf" else "ipv6" }}': { "afi": '{{ "ipv4" if proto == "ospf" else "ipv6" }}', "bandwidth": "{{ bw }}" } } } }, { "name": "cost", "getval": re.compile( r""" ^set \s+protocols \s+(?Pospf|ospfv3) \s+interface \s+(?P\S+) \s+cost \s+(?P\'\d+\') *$""", re.VERBOSE, ), "setval": _tmplt_ospf_int_cost, "compval": "address_family.cost", "result": { "name": "{{ name }}", "address_family": { '{{ "ipv4" if proto == "ospf" else "ipv6" }}': { "afi": '{{ "ipv4" if proto == "ospf" else "ipv6" }}', "cost": "{{ val }}" } } } }, { "name": "hello_interval", "getval": re.compile( r""" ^set \s+protocols \s+(?Pospf|ospfv3) \s+interface \s+(?P\S+) \s+hello-interval \s+(?P\'\d+\') *$""", re.VERBOSE, ), "setval": _tmplt_ospf_int_hello_interval, "compval": "address_family.hello_interval", "result": { "name": "{{ name }}", "address_family": { '{{ "ipv4" if proto == "ospf" else "ipv6" }}': { "afi": '{{ "ipv4" if proto == "ospf" else "ipv6" }}', "hello_interval": "{{ val }}" } } } }, { "name": "dead_interval", "getval": re.compile( r""" ^set \s+protocols \s+(?Pospf|ospfv3) \s+interface \s+(?P\S+) \s+dead-interval \s+(?P\'\d+\') *$""", re.VERBOSE, ), "setval": _tmplt_ospf_int_dead_interval, "compval": "address_family.dead_interval", "result": { "name": "{{ name }}", "address_family": { '{{ "ipv4" if proto == "ospf" else "ipv6" }}': { "afi": '{{ "ipv4" if proto == "ospf" else "ipv6" }}', "dead_interval": "{{ val }}" } } } }, { "name": "mtu_ignore", "getval": re.compile( r""" ^set \s+protocols \s+(?Pospf|ospfv3) \s+interface \s+(?P\S+) \s+(?Pmtu-ignore) *$""", re.VERBOSE, ), "setval": _tmplt_ospf_int_mtu_ignore, "compval": "address_family.mtu_ignore", "result": { "name": "{{ name }}", "address_family": { '{{ "ipv4" if proto == "ospf" else "ipv6" }}': { "afi": '{{ "ipv4" if proto == "ospf" else "ipv6" }}', "mtu_ignore": "{{ True if mtu is defined }}" } } } }, { "name": "network", "getval": re.compile( r""" ^set \s+protocols \s+(?Pospf|ospfv3) \s+interface \s+(?P\S+) \s+network - \s+(?P\S+) - *$""", + \s+(?P\S+)\s*$""", re.VERBOSE, ), "setval": _tmplt_ospf_int_network, "compval": "address_family.network", "result": { "name": "{{ name }}", "address_family": { '{{ "ipv4" if proto == "ospf" else "ipv6" }}': { "afi": '{{ "ipv4" if proto == "ospf" else "ipv6" }}', "network": "{{ val }}" } } } }, { "name": "priority", "getval": re.compile( r""" ^set \s+protocols \s+(?Pospf|ospfv3) \s+interface \s+(?P\S+) \s+priority \s+(?P\'\d+\') *$""", re.VERBOSE, ), "setval": _tmplt_ospf_int_priority, "compval": "address_family.priority", "result": { "name": "{{ name }}", "address_family": { '{{ "ipv4" if proto == "ospf" else "ipv6" }}': { "afi": '{{ "ipv4" if proto == "ospf" else "ipv6" }}', "priority": "{{ val }}" } } } }, { "name": "retransmit_interval", "getval": re.compile( r""" ^set \s+protocols \s+(?Pospf|ospfv3) \s+interface \s+(?P\S+) \s+retransmit-interval \s+(?P\'\d+\') *$""", re.VERBOSE, ), "setval": _tmplt_ospf_int_retransmit_interval, "compval": "address_family.retransmit_interval", "result": { "name": "{{ name }}", "address_family": { '{{ "ipv4" if proto == "ospf" else "ipv6" }}': { "afi": '{{ "ipv4" if proto == "ospf" else "ipv6" }}', "retransmit_interval": "{{ val }}" } } } }, { "name": "transmit_delay", "getval": re.compile( r""" ^set \s+protocols \s+(?Pospf|ospfv3) \s+interface \s+(?P\S+) \s+transmit-delay \s+(?P\'\d+\') *$""", re.VERBOSE, ), "setval": _tmplt_ospf_int_transmit_delay, "compval": "address_family.transmit_delay", "result": { "name": "{{ name }}", "address_family": { '{{ "ipv4" if proto == "ospf" else "ipv6" }}': { "afi": '{{ "ipv4" if proto == "ospf" else "ipv6" }}', "transmit_delay": "{{ val }}" } } } }, { "name": "ifmtu", "getval": re.compile( r""" ^set \s+protocols \s+(?Pospf|ospfv3) \s+interface \s+(?P\S+) \s+ifmtu \s+(?P\'\d+\') *$""", re.VERBOSE, ), "setval": _tmplt_ospf_int_ifmtu, "compval": "address_family.ifmtu", "result": { "name": "{{ name }}", "address_family": { '{{ "ipv4" if proto == "ospf" else "ipv6" }}': { "afi": '{{ "ipv4" if proto == "ospf" else "ipv6" }}', "ifmtu": "{{ val }}" } } } }, { "name": "instance", "getval": re.compile( r""" ^set \s+protocols \s+(?Pospf|ospfv3) \s+interface \s+(?P\S+) \s+instance-id \s+(?P\'\d+\') *$""", re.VERBOSE, ), "setval": _tmplt_ospf_int_instance, "compval": "address_family.instance", "result": { "name": "{{ name }}", "address_family": { '{{ "ipv4" if proto == "ospf" else "ipv6" }}': { "afi": '{{ "ipv4" if proto == "ospf" else "ipv6" }}', "instance": "{{ val }}" } } } }, { "name": "passive", "getval": re.compile( r""" ^set \s+protocols \s+(?Pospf|ospfv3) \s+interface \s+(?P\S+) \s+(?Ppassive) *$""", re.VERBOSE, ), "setval": _tmplt_ospf_int_passive, "compval": "address_family.passive", "result": { "name": "{{ name }}", "address_family": { '{{ "ipv4" if proto == "ospf" else "ipv6" }}': { "afi": '{{ "ipv4" if proto == "ospf" else "ipv6" }}', "passive": "{{ True if pass is defined }}" } } } }, { "name": "interface_name", "getval": re.compile( r""" ^set \s+protocols \s+(?Pospf|ospfv3) \s+interface \s+(?P\S+) .*$""", re.VERBOSE, ), "setval": "set protocols {{ proto }} interface {{ name }}", "result": { "name": "{{ name }}", } }, ] # fmt: on diff --git a/plugins/module_utils/network/vyos/rm_templates/route_maps.py b/plugins/module_utils/network/vyos/rm_templates/route_maps.py index c6b88f7b..51d0ea1c 100644 --- a/plugins/module_utils/network/vyos/rm_templates/route_maps.py +++ b/plugins/module_utils/network/vyos/rm_templates/route_maps.py @@ -1,1405 +1,1358 @@ # -*- coding: utf-8 -*- # Copyright 2021 Red Hat # GNU General Public License v3.0+ # (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) from __future__ import absolute_import, division, print_function __metaclass__ = type """ The Route_maps parser templates file. This contains a list of parser definitions and associated functions that facilitates both facts gathering and native command generation for the given network resource. """ import re from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.rm_base.network_template import ( NetworkTemplate, ) class Route_mapsTemplate(NetworkTemplate): def __init__(self, lines=None): prefix = {"set": "set", "remove": "delete"} super(Route_mapsTemplate, self).__init__(lines=lines, tmplt=self, prefix=prefix) # fmt: off PARSERS = [ { "name": "route_map", "getval": re.compile( r""" - ^set\spolicy\sroute-map\s(?P\S+) - *$""", + ^set\spolicy\sroute-map\s(?P\S+)\s*$""", re.VERBOSE, ), "compval": "route_map", "setval": "policy route-map {{route_map}}", "result": { "route_maps": { "{{ route_map }}": { "route_map": '{{ route_map }}', }, }, }, }, { "name": "sequence", "getval": re.compile( r""" - ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+) - *$""", + ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\s*$""", re.VERBOSE, ), "compval": "sequence", "setval": "policy route-map {{route_map}} rule {{sequence}}", "result": { "route_maps": { "{{ route_map }}": { "route_map": '{{ route_map }}', "entries": { "{{sequence}}": { "sequence": "{{sequence}}", }, }, }, }, }, }, { "name": "call", "getval": re.compile( r""" - ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\scall\s(?P\S+) - *$""", + ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\scall\s(?P\S+)\s*$""", re.VERBOSE, ), "setval": "policy route-map {{route_map}} rule {{sequence}} call {{call}}", "result": { "route_maps": { "{{ route_map }}": { "route_map": '{{ route_map }}', "entries": { "{{sequence}}": { "sequence": "{{sequence}}", "call": "{{call}}", }, }, }, }, }, }, { "name": "description", "getval": re.compile( r""" - ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\sdescription\s(?P\S+) - *$""", + ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\sdescription\s(?P\S+)\s*$""", re.VERBOSE, ), "setval": "policy route-map {{route_map}} rule {{sequence}} description {{description}}", "result": { "route_maps": { "{{ route_map }}": { "route_map": '{{ route_map }}', "entries": { "{{sequence}}": { "sequence": "{{sequence}}", "description": "{{description}}", }, }, }, }, }, }, { "name": "action", "getval": re.compile( r""" - ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\saction\s(?P\S+) - *$""", + ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\saction\s(?P\S+)\s*$""", re.VERBOSE, ), "setval": "policy route-map {{route_map}} rule {{sequence}} action {{action}}", "result": { "route_maps": { "{{ route_map }}": { "route_map": '{{ route_map }}', "entries": { "{{sequence}}": { "sequence": "{{sequence}}", "action": "{{action}}", }, }, }, }, }, }, { "name": "continue_sequence", "getval": re.compile( r""" - ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\scontinue\s(?P\S+) - *$""", + ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\scontinue\s(?P\S+)\s*$""", re.VERBOSE, ), "setval": "policy route-map {{route_map}} rule {{sequence}} continue {{continue_sequence}}", "result": { "route_maps": { "{{ route_map }}": { "route_map": '{{ route_map }}', "entries": { "{{sequence}}": { "sequence": "{{sequence}}", "continue_sequence": "{{continue}}", }, }, }, }, }, }, { "name": "on_match_next", "getval": re.compile( r""" - ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\son-match\s(?Pnext) - *$""", + ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\son-match\s(?Pnext)\s*$""", re.VERBOSE, ), "compval": "on_match.next", "setval": "policy route-map {{route_map}} rule {{sequence}} on-match next", "result": { "route_maps": { "{{ route_map }}": { "route_map": '{{ route_map }}', "entries": { "{{sequence}}": { "sequence": "{{sequence}}", "on_match": { "next": "{{True if next is defined}}", }, }, }, }, }, }, }, { "name": "on_match_goto", "getval": re.compile( r""" - ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\son-match\sgoto\s(?P\S+) - *$""", + ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\son-match\sgoto\s(?P\S+)\s*$""", re.VERBOSE, ), "compval": "on_match.goto", "setval": "policy route-map {{route_map}} rule {{sequence}} on-match goto {{on_match.goto}}", "result": { "route_maps": { "{{ route_map }}": { "route_map": '{{ route_map }}', "entries": { "{{sequence}}": { "sequence": "{{sequence}}", "on_match": { "goto": "{{goto}}", }, }, }, }, }, }, }, { "name": "set_aggregator_ip", "getval": re.compile( r""" - ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\sset\saggregator\sip\s(?P\S+) - *$""", + ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\sset\saggregator\sip\s(?P\S+)\s*$""", re.VERBOSE, ), "compval": "set.aggregator.ip", "setval": "policy route-map {{route_map}} rule {{sequence}} set aggregator ip {{set.aggregator.ip}}", "result": { "route_maps": { "{{ route_map }}": { "route_map": '{{ route_map }}', "entries": { "{{sequence}}": { "sequence": "{{sequence}}", "set": { "aggregator": { "ip": "{{ip}}", }, }, }, }, }, }, }, }, { "name": "set_aggregator_as", "getval": re.compile( r""" - ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\sset\saggregator\sas\s(?P\S+) - *$""", + ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\sset\saggregator\sas\s(?P\S+)\s*$""", re.VERBOSE, ), "compval": "set.aggregator.as", "setval": "policy route-map {{route_map}} rule {{sequence}} set aggregator as {{set.aggregator.as}}", "result": { "route_maps": { "{{ route_map }}": { "route_map": '{{ route_map }}', "entries": { "{{sequence}}": { "sequence": "{{sequence}}", "set": { "aggregator": { "as": "{{as}}", }, }, }, }, }, }, }, }, { "name": "set_as_path_exclude", "getval": re.compile( r""" - ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\sset\sas-path-exclude\s(?P\S+) - *$""", + ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\sset\sas-path-exclude\s(?P\S+)\s*$""", re.VERBOSE, ), "compval": "set.as_path_exclude", "setval": "policy route-map {{route_map}} rule {{sequence}} set as-path-exclude {{set.as_path_exclude}}", "result": { "route_maps": { "{{ route_map }}": { "route_map": '{{ route_map }}', "entries": { "{{sequence}}": { "sequence": "{{sequence}}", "set": { "as_path_exclude": "{{as}}", }, }, }, }, }, }, }, { "name": "set_as_path_prepend", "getval": re.compile( r""" ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\sset\sas-path-prepend\s(?P.*) $""", re.VERBOSE, ), "compval": "set.as_path_prepend", "setval": "policy route-map {{route_map}} rule {{sequence}} set as-path-prepend '{{set.as_path_prepend}}'", "result": { "route_maps": { "{{ route_map }}": { "route_map": '{{ route_map }}', "entries": { "{{sequence}}": { "sequence": "{{sequence}}", "set": { "as_path_prepend": "{{as}}", }, }, }, }, }, }, }, { "name": "set_atomic_aggregate", "getval": re.compile( r""" - ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\sset\s(?Patomic-aggregate) - *$""", + ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\sset\s(?Patomic-aggregate)\s*$""", re.VERBOSE, ), "compval": "set.atomic_aggregate", "setval": "policy route-map {{route_map}} rule {{sequence}} set atomic-aggregate", "result": { "route_maps": { "{{ route_map }}": { "route_map": '{{ route_map }}', "entries": { "{{sequence}}": { "sequence": "{{sequence}}", "set": { "atomic_aggregate": "{{True if as is defined}}", }, }, }, }, }, }, }, { "name": "set_bgp_extcommunity_rt", "getval": re.compile( r""" - ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\sset\sbgp-extcommunity-rt\s(?P\S+) - *$""", + ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\sset\sbgp-extcommunity-rt\s(?P\S+)\s*$""", re.VERBOSE, ), "compval": "set.bgp_extcommunity_rt", "setval": "policy route-map {{route_map}} rule {{sequence}} " "set bgp-extcommunity-rt {{set.bgp_extcommunity_rt}}", "result": { "route_maps": { "{{ route_map }}": { "route_map": '{{ route_map }}', "entries": { "{{sequence}}": { "sequence": "{{sequence}}", "set": { "bgp_extcommunity_rt": "{{bgp}}", }, }, }, }, }, }, }, { "name": "set_comm_list", "getval": re.compile( r""" - ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\smatch\scommunity\scommunity-list\s(?P\S+) - *$""", + ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\smatch\scommunity\scommunity-list\s(?P\S+)\s*$""", re.VERBOSE, ), "compval": "match.community.community_list", "setval": "policy route-map {{route_map}} rule {{sequence}} " "match community community-list {{set.comm_list.comm_list}}", "result": { "route_maps": { "{{ route_map }}": { "route_map": '{{ route_map }}', "entries": { "{{sequence}}": { "sequence": "{{sequence}}", "match": { "community": {"community_list": "{{comm_list}}"}, }, }, }, }, }, }, }, { "name": "set_comm_list_delete", "getval": re.compile( r""" - ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\sset\scomm-list\sdelete(?P\S+) - *$""", + ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\sset\scomm-list\s(?Pdelete)\s*$""", re.VERBOSE, ), "compval": "set.comm_list.comm_list", "setval": "policy route-map {{route_map}} rule {{sequence}} " "set comm-list delete", "result": { "route_maps": { "{{ route_map }}": { "route_map": '{{ route_map }}', "entries": { "{{sequence}}": { "sequence": "{{sequence}}", "set": { "comm_list": {"delete": "{{True if delete is defined}}"}, }, }, }, }, }, }, }, { "name": "set_extcommunity_rt", "getval": re.compile( r""" - ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\sset\sextcommunity-rt\s(?P\S+) - *$""", + ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\sset\sextcommunity-rt\s(?P\S+)\s*$""", re.VERBOSE, ), "compval": "set.extcommunity_rt", "setval": "policy route-map {{route_map}} rule {{sequence}} " "set extcommunity-rt {{set.extcommunity_rt}}", "result": { "route_maps": { "{{ route_map }}": { "route_map": '{{ route_map }}', "entries": { "{{sequence}}": { "sequence": "{{sequence}}", "set": { "extcommunity_rt": "{{extcommunity_rt}}", }, }, }, }, }, }, }, { "name": "set_extcommunity_soo", "getval": re.compile( r""" - ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\sset\sextcommunity-soo\s(?P\S+) - *$""", + ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\sset\sextcommunity-soo\s(?P\S+)\s*$""", re.VERBOSE, ), "compval": "set.extcommunity_soo", "setval": "policy route-map {{route_map}} rule {{sequence}} " "set extcommunity-soo {{set.extcommunity_soo}}", "result": { "route_maps": { "{{ route_map }}": { "route_map": '{{ route_map }}', "entries": { "{{sequence}}": { "sequence": "{{sequence}}", "set": { "extcommunity_soo": "{{set.extcommunity_soo}}", }, }, }, }, }, }, }, { "name": "set_extcommunity_bandwidth", "getval": re.compile( r""" - ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\sset\sextcommunity\sbandwidth\s(?P\S+) - *$""", + ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\sset\sextcommunity\sbandwidth\s(?P\S+)\s*$""", re.VERBOSE, ), "compval": "set.extcommunity_bandwidth", "setval": "policy route-map {{route_map}} rule {{sequence}} " "set extcommunity bandwidth {{set.extcommunity_bandwidth}}", "result": { "route_maps": { "{{ route_map }}": { "route_map": '{{ route_map }}', "entries": { "{{sequence}}": { "sequence": "{{sequence}}", "set": { "extcommunity_bandwidth": "{{extcommunity_bw}}", }, }, }, }, }, }, }, { "name": "set_extcommunity_bandwidth_non_transitive", "getval": re.compile( r""" - ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\sset\sextcommunity\s(?Pbandwidth-non-transitive) - *$""", + ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+) + \sset\sextcommunity\s(?Pbandwidth-non-transitive)\s*$""", re.VERBOSE, ), "compval": "set.extcommunity_bandwidth_non_transitive", "setval": "policy route-map {{route_map}} rule {{sequence}} " "set extcommunity bandwidth-non-transitive", "result": { "route_maps": { "{{ route_map }}": { "route_map": '{{ route_map }}', "entries": { "{{sequence}}": { "sequence": "{{sequence}}", "set": { "extcommunity_bandwidth_non_transitive": "{{True if extcommunity_bw_nt is defined}}", }, }, }, }, }, }, }, { "name": "set_ip_next_hop", "getval": re.compile( r""" - ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\sset\sip-next-hop\s(?P\S+) - *$""", + ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\sset\sip-next-hop\s(?P\S+)\s*$""", re.VERBOSE, ), "compval": "set.ip_next_hop", "setval": "policy route-map {{route_map}} rule {{sequence}} " "set ip-next-hop {{set.ip_next_hop}}", "result": { "route_maps": { "{{ route_map }}": { "route_map": '{{ route_map }}', "entries": { "{{sequence}}": { "sequence": "{{sequence}}", "set": { "ip_next_hop": "{{ip_next_hop}}", }, }, }, }, }, }, }, { "name": "set_ipv6_next_hop", "getval": re.compile( r""" ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\sset\sipv6-next-hop \s(?Pglobal|local) - \s(?P\S+) - *$""", + \s(?P\S+)\s*$""", re.VERBOSE, ), "compval": "set.ipv6_next_hop", "setval": "policy route-map {{route_map}} rule {{sequence}} " "set ipv6-next-hop {{set.ipv6_next_hop.ip_type}} {{set.ipv6_next_hop.value}}", "result": { "route_maps": { "{{ route_map }}": { "route_map": '{{ route_map }}', "entries": { "{{sequence}}": { "sequence": "{{sequence}}", "set": { "ipv6_next_hop": { "ip_type": "{{type}}", "value": "{{value}}", }, }, }, }, }, }, }, }, { "name": "set_large_community", "getval": re.compile( r""" - ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\sset\slarge-community\s(?P\S+) - *$""", + ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\sset\slarge-community\s(?P\S+)\s*$""", re.VERBOSE, ), "compval": "set.large_community", "setval": "policy route-map {{route_map}} rule {{sequence}} " "set large-community {{set.large_community}}", "result": { "route_maps": { "{{ route_map }}": { "route_map": '{{ route_map }}', "entries": { "{{sequence}}": { "sequence": "{{sequence}}", "set": { "large_community": "{{large_community}}", }, }, }, }, }, }, }, { "name": "set_local_preference", "getval": re.compile( r""" - ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\sset\slocal-preference\s(?P\S+) - *$""", + ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\sset\slocal-preference\s(?P\S+)\s*$""", re.VERBOSE, ), "compval": "set.local_preference", "setval": "policy route-map {{route_map}} rule {{sequence}} " "set local-preference {{set.local_preference}}", "result": { "route_maps": { "{{ route_map }}": { "route_map": '{{ route_map }}', "entries": { "{{sequence}}": { "sequence": "{{sequence}}", "set": { "local_preference": "{{local_preference}}", }, }, }, }, }, }, }, { "name": "set_metric", "getval": re.compile( r""" - ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\sset\smetric\s(?P\S+) - *$""", + ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\sset\smetric\s(?P\S+)\s*$""", re.VERBOSE, ), "compval": "set.metric", "setval": "policy route-map {{route_map}} rule {{sequence}} " "set metric {{set.metric}}", "result": { "route_maps": { "{{ route_map }}": { "route_map": '{{ route_map }}', "entries": { "{{sequence}}": { "sequence": "{{sequence}}", "set": { "metric": "{{metric}}", }, }, }, }, }, }, }, { "name": "set_metric_type", "getval": re.compile( r""" - ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\sset\smetric-type\s(?P\S+) - *$""", + ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\sset\smetric-type\s(?P\S+)\s*$""", re.VERBOSE, ), "compval": "set.metric_type", "setval": "policy route-map {{route_map}} rule {{sequence}} " "set metric-type {{set.metric_type}}", "result": { "route_maps": { "{{ route_map }}": { "route_map": '{{ route_map }}', "entries": { "{{sequence}}": { "sequence": "{{sequence}}", "set": { "metric_type": "{{metric_type}}", }, }, }, }, }, }, }, { "name": "set_origin", "getval": re.compile( r""" - ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\sset\sorigin\s(?P\S+) - *$""", + ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\sset\sorigin\s(?P\S+)\s*$""", re.VERBOSE, ), "compval": "set.origin", "setval": "policy route-map {{route_map}} rule {{sequence}} " "set origin {{set.origin}}", "result": { "route_maps": { "{{ route_map }}": { "route_map": '{{ route_map }}', "entries": { "{{sequence}}": { "sequence": "{{sequence}}", "set": { "origin": "{{origin}}", }, }, }, }, }, }, }, { "name": "set_originator_id", "getval": re.compile( r""" - ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\sset\soriginator-id\s(?P\S+) - *$""", + ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\sset\soriginator-id\s(?P\S+)\s*$""", re.VERBOSE, ), "compval": "set.originator_id", "setval": "policy route-map {{route_map}} rule {{sequence}} " "set originator-id {{set.originator_id}}", "result": { "route_maps": { "{{ route_map }}": { "route_map": '{{ route_map }}', "entries": { "{{sequence}}": { "sequence": "{{sequence}}", "set": { "originator_id": "{{originator_id}}", }, }, }, }, }, }, }, { "name": "set_src", "getval": re.compile( r""" - ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\sset\ssrc\s(?P\S+) - *$""", + ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\sset\ssrc\s(?P\S+)\s*$""", re.VERBOSE, ), "compval": "set.src", "setval": "policy route-map {{route_map}} rule {{sequence}} " "set src {{set.src}}", "result": { "route_maps": { "{{ route_map }}": { "route_map": '{{ route_map }}', "entries": { "{{sequence}}": { "sequence": "{{sequence}}", "set": { "src": "{{src}}", }, }, }, }, }, }, }, { "name": "set_tag", "getval": re.compile( r""" - ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\sset\stag\s(?P\S+) - *$""", + ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\sset\stag\s(?P\S+)\s*$""", re.VERBOSE, ), "compval": "set.tag", "setval": "policy route-map {{route_map}} rule {{sequence}} " "set tag {{set.tag}}", "result": { "route_maps": { "{{ route_map }}": { "route_map": '{{ route_map }}', "entries": { "{{sequence}}": { "sequence": "{{sequence}}", "set": { "tag": "{{tag}}", }, }, }, }, }, }, }, { "name": "set_weight", "getval": re.compile( r""" - ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\sset\sweight\s(?P\S+) - *$""", + ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\sset\sweight\s(?P\S+)\s*$""", re.VERBOSE, ), "compval": "set.weight", "setval": "policy route-map {{route_map}} rule {{sequence}} " "set weight {{set.weight}}", "result": { "route_maps": { "{{ route_map }}": { "route_map": '{{ route_map }}', "entries": { "{{sequence}}": { "sequence": "{{sequence}}", "set": { "weight": "{{weight}}", }, }, }, }, }, }, }, { "name": "set_table", "getval": re.compile( r""" - ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\sset\stable\s(?P\S+) - *$""", + ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\sset\stable\s(?P
\S+)\s*$""", re.VERBOSE, ), "compval": "set.weight", "setval": "policy route-map {{route_map}} rule {{sequence}} " "set table {{set.table}}", "result": { "route_maps": { "{{ route_map }}": { "route_map": '{{ route_map }}', "entries": { "{{sequence}}": { "sequence": "{{sequence}}", "set": { "table": "{{table}}", }, }, }, }, }, }, }, { "name": "set_community", "getval": re.compile( r""" - ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\sset\scommunity\s(?P\S+) - *$""", + ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\sset\scommunity\s(?P\S+)\s*$""", re.VERBOSE, ), "compval": "set.community.value", "setval": "policy route-map {{route_map}} rule {{sequence}} " "set community {{set.community.value}}", "result": { "route_maps": { "{{ route_map }}": { "route_map": '{{ route_map }}', "entries": { "{{sequence}}": { "sequence": "{{sequence}}", "set": { "community": { "value": "{{value}}", }, }, }, }, }, }, }, }, { "name": "match_as_path", "getval": re.compile( r""" - ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\smatch\sas-path\s(?P\S+) - *$""", + ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\smatch\sas-path\s(?P\S+)\s*$""", re.VERBOSE, ), "compval": "match.as_path", "setval": "policy route-map {{route_map}} rule {{sequence}} " "match as-path {{match.as_path}}", "result": { "route_maps": { "{{ route_map }}": { "route_map": '{{ route_map }}', "entries": { "{{sequence}}": { "sequence": "{{sequence}}", "match": { "as_path": "{{as_path}}", }, }, }, }, }, }, }, { "name": "match_community_community_list", "getval": re.compile( r""" - ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\smatch\scommunity\scommunity-list\s(?P\S+) - *$""", + ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\smatch\scommunity\scommunity-list\s(?P\S+)\s*$""", re.VERBOSE, ), "compval": "match.community.community_list", "setval": "policy route-map {{route_map}} rule {{sequence}} " "match community community-list {{match.community.community_list}}", "result": { "route_maps": { "{{ route_map }}": { "route_map": '{{ route_map }}', "entries": { "{{sequence}}": { "sequence": "{{sequence}}", "match": { "community": {"community_list": "{{community_list}}"}, }, }, }, }, }, }, }, { "name": "match_community_exact_match", "getval": re.compile( r""" - ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\smatch\scommunity\sexact-match(?P) - *$""", + ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\smatch\scommunity\sexact-match(?P)\s*$""", re.VERBOSE, ), "compval": "match.community.exact_match", "setval": "policy route-map {{route_map}} rule {{sequence}} " "match community exact-match", "result": { "route_maps": { "{{ route_map }}": { "route_map": '{{ route_map }}', "entries": { "{{sequence}}": { "sequence": "{{sequence}}", "match": { "community": {"exact_match": "{{True if exact_match is defined}}"}, }, }, }, }, }, }, }, { "name": "match_extcommunity", "getval": re.compile( r""" - ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\smatch\sextcommunity\s(?P\S+) - *$""", + ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\smatch\sextcommunity\s(?P\S+)\s*$""", re.VERBOSE, ), "compval": "match.extcommunity", "setval": "policy route-map {{route_map}} rule {{sequence}} " "match extcommunity {{match.extcommunity}}", "result": { "route_maps": { "{{ route_map }}": { "route_map": '{{ route_map }}', "entries": { "{{sequence}}": { "sequence": "{{sequence}}", "match": { "extcommunity": "{{extcommunity}}", }, }, }, }, }, }, }, { "name": "match_interface", "getval": re.compile( r""" - ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\smatch\sinterface\s(?P\S+) - *$""", + ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\smatch\sinterface\s(?P\S+)\s*$""", re.VERBOSE, ), "compval": "match.interface", "setval": "policy route-map {{route_map}} rule {{sequence}} " "match interface {{match.interface}}", "result": { "route_maps": { "{{ route_map }}": { "route_map": '{{ route_map }}', "entries": { "{{sequence}}": { "sequence": "{{sequence}}", "match": { "interface": "{{interface}}", }, }, }, }, }, }, }, { "name": "match_large_community_large_community_list", "getval": re.compile( r""" - ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\smatch\slarge-community\slarge-community-list\s(?P\S+) - *$""", + ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\smatch\slarge-community\slarge-community-list\s(?P\S+)\s*$""", re.VERBOSE, ), "compval": "match.large_community_large_community_list", "setval": "policy route-map {{route_map}} rule {{sequence}} " "match large-community large-community-list {{match.large_community_large_community_list}}", "result": { "route_maps": { "{{ route_map }}": { "route_map": '{{ route_map }}', "entries": { "{{sequence}}": { "sequence": "{{sequence}}", "match": { "large_community_large_community_list": "{{lc}}", }, }, }, }, }, }, }, { "name": "match_metric", "getval": re.compile( r""" - ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\smatch\smetric\s(?P\S+) - *$""", + ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\smatch\smetric\s(?P\S+)\s*$""", re.VERBOSE, ), "compval": "match.metric", "setval": "policy route-map {{route_map}} rule {{sequence}} " "match metric {{match.metric}}", "result": { "route_maps": { "{{ route_map }}": { "route_map": '{{ route_map }}', "entries": { "{{sequence}}": { "sequence": "{{sequence}}", "match": { "metric": "{{metric}}", }, }, }, }, }, }, }, { "name": "match_origin", "getval": re.compile( r""" - ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\smatch\sorigin\s(?P\S+) - *$""", + ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\smatch\sorigin\s(?P\S+)\s*$""", re.VERBOSE, ), "compval": "match.origin", "setval": "policy route-map {{route_map}} rule {{sequence}} " "match origin {{match.origin}}", "result": { "route_maps": { "{{ route_map }}": { "route_map": '{{ route_map }}', "entries": { "{{sequence}}": { "sequence": "{{sequence}}", "match": { "origin": "{{origin}}", }, }, }, }, }, }, }, { "name": "match_peer", "getval": re.compile( r""" - ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\smatch\speer\s(?P\S+) - *$""", + ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\smatch\speer\s(?P\S+)\s*$""", re.VERBOSE, ), "compval": "match.peer", "setval": "policy route-map {{route_map}} rule {{sequence}} " "match peer {{match.peer}}", "result": { "route_maps": { "{{ route_map }}": { "route_map": '{{ route_map }}', "entries": { "{{sequence}}": { "sequence": "{{sequence}}", "match": { "peer": "{{peer}}", }, }, }, }, }, }, }, { "name": "match_ip_address", "getval": re.compile( r""" ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\smatch\sip\saddress \s(?Paccess-list|prefix-list) - \s(?P\S+) - *$""", + \s(?P\S+)\s*$""", re.VERBOSE, ), "compval": "match.ip.address", "setval": "policy route-map {{route_map}} rule {{sequence}} " "match ip address {{match.ip.address.list_type}} {{match.ip.address.value}}", "result": { "route_maps": { "{{ route_map }}": { "route_map": '{{ route_map }}', "entries": { "{{sequence}}": { "sequence": "{{sequence}}", "match": { "ip": { "address": { "list_type": "{{list_type}}", "value": "{{value}}", }, }, }, }, }, }, }, }, }, { "name": "match_ip_next_hop", "getval": re.compile( r""" ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\smatch\sip\snexthop \s(?Paccess-list|prefix-list) - \s(?P\S+) - *$""", + \s(?P\S+)\s*$""", re.VERBOSE, ), "compval": "match.ip.next_hop", "setval": "policy route-map {{route_map}} rule {{sequence}} " "match ip nexthop {{match.ip.next_hop.list_type}} {{match.ip.next_hop.value}}", "result": { "route_maps": { "{{ route_map }}": { "route_map": '{{ route_map }}', "entries": { "{{sequence}}": { "sequence": "{{sequence}}", "match": { "ip": { "next_hop": { "list_type": "{{list_type}}", "value": "{{value}}", }, }, }, }, }, }, }, }, }, { "name": "match_ip_route_source", "getval": re.compile( r""" ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\smatch\sip\sroute-source \s(?Paccess-list|prefix-list) - \s(?P\S+) - *$""", + \s(?P\S+)\s*$""", re.VERBOSE, ), "compval": "match.ip.route_source", "setval": "policy route-map {{route_map}} rule {{sequence}} " "match ip route-source {{match.ip.route_source.list_type}} {{match.ip.route_source.value}}", "result": { "route_maps": { "{{ route_map }}": { "route_map": '{{ route_map }}', "entries": { "{{sequence}}": { "sequence": "{{sequence}}", "match": { "ip": { "route_source": { "list_type": "{{list_type}}", "value": "{{value}}", }, }, }, }, }, }, }, }, }, { "name": "match_ipv6_address", "getval": re.compile( r""" ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\smatch\sipv6\saddress \s(?Paccess-list|prefix-list) - \s(?P\S+) - *$""", + \s(?P\S+)\s*$""", re.VERBOSE, ), "compval": "match.ipv6.address", "setval": "policy route-map {{route_map}} rule {{sequence}} " "match ipv6 address {{match.ipv6.address.list_type}} {{match.ipv6.address.value}}", "result": { "route_maps": { "{{ route_map }}": { "route_map": '{{ route_map }}', "entries": { "{{sequence}}": { "sequence": "{{sequence}}", "match": { "ipv6": { "address": { "list_type": "{{list_type}}", "value": "{{value}}", }, }, }, }, }, }, }, }, }, { "name": "match_ipv6_nexthop", "getval": re.compile( r""" ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\smatch\sipv6\snexthop - \s(?P\S+) - *$""", + \s(?P\S+)\s*$""", re.VERBOSE, ), "compval": "match.ipv6.next_hop", "setval": "policy route-map {{route_map}} rule {{sequence}} " "match ipv6 nexthop {{match.ipv6.next_hop}}", "result": { "route_maps": { "{{ route_map }}": { "route_map": '{{ route_map }}', "entries": { "{{sequence}}": { "sequence": "{{sequence}}", "match": { "ipv6": { "next_hop": "{{value}}", }, }, }, }, }, }, }, }, { "name": "match_protocol", "getval": re.compile( r""" - ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\smatch\sprotocol\s(?P\S+) - *$""", + ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\smatch\sprotocol\s(?P\S+)\s*$""", re.VERBOSE, ), "compval": "match.protocol", "setval": "policy route-map {{route_map}} rule {{sequence}} " "match protocol {{match.protocol}}", "result": { "route_maps": { "{{ route_map }}": { "route_map": '{{ route_map }}', "entries": { "{{sequence}}": { "sequence": "{{sequence}}", "match": { "protocol": "{{value}}", }, }, }, }, }, }, }, { "name": "match_rpki", "getval": re.compile( r""" ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\smatch\srpki - \s(?P\S+) - *$""", + \s(?P\S+)\s*$""", re.VERBOSE, ), "compval": "match.rpki", "setval": "policy route-map {{route_map}} rule {{sequence}} " "match rpki {{match.rpki}}", "result": { "route_maps": { "{{ route_map }}": { "route_map": '{{ route_map }}', "entries": { "{{sequence}}": { "sequence": "{{sequence}}", "match": { "rpki": "{{value}}", }, }, }, }, }, }, }, ] # fmt: on diff --git a/plugins/module_utils/network/vyos/rm_templates/route_maps_14.py b/plugins/module_utils/network/vyos/rm_templates/route_maps_14.py index 6564280d..ea61a555 100644 --- a/plugins/module_utils/network/vyos/rm_templates/route_maps_14.py +++ b/plugins/module_utils/network/vyos/rm_templates/route_maps_14.py @@ -1,1405 +1,1364 @@ # -*- coding: utf-8 -*- # Copyright 2021 Red Hat # GNU General Public License v3.0+ # (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) from __future__ import absolute_import, division, print_function __metaclass__ = type """ The Route_maps parser templates file. This contains a list of parser definitions and associated functions that facilitates both facts gathering and native command generation for the given network resource. """ import re from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.rm_base.network_template import ( NetworkTemplate, ) class Route_mapsTemplate14(NetworkTemplate): def __init__(self, lines=None): prefix = {"set": "set", "remove": "delete"} super(Route_mapsTemplate14, self).__init__(lines=lines, tmplt=self, prefix=prefix) # fmt: off PARSERS = [ { "name": "route_map", "getval": re.compile( r""" - ^set\spolicy\sroute-map\s(?P\S+) - *$""", + ^set\spolicy\sroute-map\s(?P\S+)\s*$""", re.VERBOSE, ), "compval": "route_map", "setval": "policy route-map {{route_map}}", "result": { "route_maps": { "{{ route_map }}": { "route_map": '{{ route_map }}', }, }, }, }, { "name": "sequence", "getval": re.compile( r""" ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+) *$""", re.VERBOSE, ), "compval": "sequence", "setval": "policy route-map {{route_map}} rule {{sequence}}", "result": { "route_maps": { "{{ route_map }}": { "route_map": '{{ route_map }}', "entries": { "{{sequence}}": { "sequence": "{{sequence}}", }, }, }, }, }, }, { "name": "call", "getval": re.compile( r""" - ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\scall\s(?P\S+) - *$""", + ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\scall\s(?P\S+)\s*$""", re.VERBOSE, ), "setval": "policy route-map {{route_map}} rule {{sequence}} call {{call}}", "result": { "route_maps": { "{{ route_map }}": { "route_map": '{{ route_map }}', "entries": { "{{sequence}}": { "sequence": "{{sequence}}", "call": "{{call}}", }, }, }, }, }, }, { "name": "description", "getval": re.compile( r""" - ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\sdescription\s(?P\S+) - *$""", + ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\sdescription\s(?P\S+)\s*$""", re.VERBOSE, ), "setval": "policy route-map {{route_map}} rule {{sequence}} description {{description}}", "result": { "route_maps": { "{{ route_map }}": { "route_map": '{{ route_map }}', "entries": { "{{sequence}}": { "sequence": "{{sequence}}", "description": "{{description}}", }, }, }, }, }, }, { "name": "action", "getval": re.compile( r""" - ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\saction\s(?P\S+) - *$""", + ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\saction\s(?P\S+)\s*$""", re.VERBOSE, ), "setval": "policy route-map {{route_map}} rule {{sequence}} action {{action}}", "result": { "route_maps": { "{{ route_map }}": { "route_map": '{{ route_map }}', "entries": { "{{sequence}}": { "sequence": "{{sequence}}", "action": "{{action}}", }, }, }, }, }, }, { "name": "continue_sequence", "getval": re.compile( r""" - ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\scontinue\s(?P\S+) - *$""", + ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\scontinue\s(?P\S+)\s*$""", re.VERBOSE, ), "setval": "policy route-map {{route_map}} rule {{sequence}} continue {{continue_sequence}}", "result": { "route_maps": { "{{ route_map }}": { "route_map": '{{ route_map }}', "entries": { "{{sequence}}": { "sequence": "{{sequence}}", "continue_sequence": "{{continue}}", }, }, }, }, }, }, { "name": "on_match_next", "getval": re.compile( r""" ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\son-match\s(?Pnext) *$""", re.VERBOSE, ), "compval": "on_match.next", "setval": "policy route-map {{route_map}} rule {{sequence}} on-match next", "result": { "route_maps": { "{{ route_map }}": { "route_map": '{{ route_map }}', "entries": { "{{sequence}}": { "sequence": "{{sequence}}", "on_match": { "next": "{{True if next is defined}}", }, }, }, }, }, }, }, { "name": "on_match_goto", "getval": re.compile( r""" - ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\son-match\sgoto\s(?P\S+) - *$""", + ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\son-match\sgoto\s(?P\S+)\s*$""", re.VERBOSE, ), "compval": "on_match.goto", "setval": "policy route-map {{route_map}} rule {{sequence}} on-match goto {{on_match.goto}}", "result": { "route_maps": { "{{ route_map }}": { "route_map": '{{ route_map }}', "entries": { "{{sequence}}": { "sequence": "{{sequence}}", "on_match": { "goto": "{{goto}}", }, }, }, }, }, }, }, { "name": "set_aggregator_ip", "getval": re.compile( r""" - ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\sset\saggregator\sip\s(?P\S+) - *$""", + ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\sset\saggregator\sip\s(?P\S+)\s*$""", re.VERBOSE, ), "compval": "set.aggregator.ip", "setval": "policy route-map {{route_map}} rule {{sequence}} set aggregator ip {{set.aggregator.ip}}", "result": { "route_maps": { "{{ route_map }}": { "route_map": '{{ route_map }}', "entries": { "{{sequence}}": { "sequence": "{{sequence}}", "set": { "aggregator": { "ip": "{{ip}}", }, }, }, }, }, }, }, }, { "name": "set_aggregator_as", "getval": re.compile( r""" - ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\sset\saggregator\sas\s(?P\S+) - *$""", + ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\sset\saggregator\sas\s(?P\S+)\s*$""", re.VERBOSE, ), "compval": "set.aggregator.as", "setval": "policy route-map {{route_map}} rule {{sequence}} set aggregator as {{set.aggregator.as}}", "result": { "route_maps": { "{{ route_map }}": { "route_map": '{{ route_map }}', "entries": { "{{sequence}}": { "sequence": "{{sequence}}", "set": { "aggregator": { "as": "{{as}}", }, }, }, }, }, }, }, }, { "name": "set_as_path_exclude", "getval": re.compile( r""" - ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\sset\sas-path\sexclude\s(?P\S+) - *$""", + ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\sset\sas-path\sexclude\s(?P\S+)\s*$""", re.VERBOSE, ), "compval": "set.as_path_exclude", "setval": "policy route-map {{route_map}} rule {{sequence}} set as-path exclude {{set.as_path_exclude}}", "result": { "route_maps": { "{{ route_map }}": { "route_map": '{{ route_map }}', "entries": { "{{sequence}}": { "sequence": "{{sequence}}", "set": { "as_path_exclude": "{{as}}", }, }, }, }, }, }, }, { "name": "set_as_path_prepend", "getval": re.compile( r""" ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\sset\sas-path\sprepend\s(?P.*) $""", re.VERBOSE, ), "compval": "set.as_path_prepend", "setval": "policy route-map {{route_map}} rule {{sequence}} set as-path prepend '{{set.as_path_prepend}}'", "result": { "route_maps": { "{{ route_map }}": { "route_map": '{{ route_map }}', "entries": { "{{sequence}}": { "sequence": "{{sequence}}", "set": { "as_path_prepend": "{{as}}", }, }, }, }, }, }, }, { "name": "set_atomic_aggregate", "getval": re.compile( r""" ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\sset\s(?Patomic-aggregate) *$""", re.VERBOSE, ), "compval": "set.atomic_aggregate", "setval": "policy route-map {{route_map}} rule {{sequence}} set atomic-aggregate", "result": { "route_maps": { "{{ route_map }}": { "route_map": '{{ route_map }}', "entries": { "{{sequence}}": { "sequence": "{{sequence}}", "set": { "atomic_aggregate": "{{True if as is defined}}", }, }, }, }, }, }, }, { "name": "set_bgp_extcommunity_rt", "getval": re.compile( r""" - ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\sset\sbgp-extcommunity-rt\s(?P\S+) - *$""", + ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\sset\sbgp-extcommunity-rt\s(?P\S+)\s*$""", re.VERBOSE, ), "compval": "set.bgp_extcommunity_rt", "setval": "policy route-map {{route_map}} rule {{sequence}} " "set bgp-extcommunity-rt {{set.bgp_extcommunity_rt}}", "result": { "route_maps": { "{{ route_map }}": { "route_map": '{{ route_map }}', "entries": { "{{sequence}}": { "sequence": "{{sequence}}", "set": { "bgp_extcommunity_rt": "{{bgp}}", }, }, }, }, }, }, }, { "name": "set_comm_list", "getval": re.compile( r""" - ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\smatch\scommunity\scommunity-list\s(?P\S+) - *$""", + ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\smatch\scommunity\scommunity-list\s(?P\S+)\s*$""", re.VERBOSE, ), "compval": "match.community.community_list", "setval": "policy route-map {{route_map}} rule {{sequence}} " "match community community-list {{set.comm_list.comm_list}}", "result": { "route_maps": { "{{ route_map }}": { "route_map": '{{ route_map }}', "entries": { "{{sequence}}": { "sequence": "{{sequence}}", "match": { "community": {"community_list": "{{comm_list}}"}, }, }, }, }, }, }, }, { "name": "set_comm_list_delete", "getval": re.compile( r""" - ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\sset\scomm-list\sdelete(?P\S+) - *$""", + ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\sset\scomm-list\s(?Pdelete)\s*$""", re.VERBOSE, ), "compval": "set.comm_list.comm_list", "setval": "policy route-map {{route_map}} rule {{sequence}} " "set comm-list delete", "result": { "route_maps": { "{{ route_map }}": { "route_map": '{{ route_map }}', "entries": { "{{sequence}}": { "sequence": "{{sequence}}", "set": { "comm_list": {"delete": "{{True if delete is defined}}"}, }, }, }, }, }, }, }, { "name": "set_extcommunity_rt", "getval": re.compile( r""" - ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\sset\sextcommunity\srt\s(?P\S+) - *$""", + ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\sset\sextcommunity\srt\s(?P\S+)\s*$""", re.VERBOSE, ), "compval": "set.extcommunity_rt", "setval": "policy route-map {{route_map}} rule {{sequence}} " "set extcommunity rt {{set.extcommunity_rt}}", "result": { "route_maps": { "{{ route_map }}": { "route_map": '{{ route_map }}', "entries": { "{{sequence}}": { "sequence": "{{sequence}}", "set": { "extcommunity_rt": "{{extcommunity_rt}}", }, }, }, }, }, }, }, { "name": "set_extcommunity_soo", "getval": re.compile( r""" - ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\sset\sextcommunity\ssoo\s(?P\S+) - *$""", + ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\sset\sextcommunity\ssoo\s(?P\S+)\s*$""", re.VERBOSE, ), "compval": "set.extcommunity_soo", "setval": "policy route-map {{route_map}} rule {{sequence}} " "set extcommunity soo {{set.extcommunity_soo}}", "result": { "route_maps": { "{{ route_map }}": { "route_map": '{{ route_map }}', "entries": { "{{sequence}}": { "sequence": "{{sequence}}", "set": { "extcommunity_soo": "{{extcommunity_soo}}", }, }, }, }, }, }, }, { "name": "set_extcommunity_bandwidth", "getval": re.compile( r""" - ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\sset\sextcommunity\sbandwidth\s(?P\S+) - *$""", + ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\sset\sextcommunity\sbandwidth\s(?P\S+)\s*$""", re.VERBOSE, ), "compval": "set.extcommunity_bandwidth", "setval": "policy route-map {{route_map}} rule {{sequence}} " "set extcommunity bandwidth {{set.extcommunity_bandwidth}}", "result": { "route_maps": { "{{ route_map }}": { "route_map": '{{ route_map }}', "entries": { "{{sequence}}": { "sequence": "{{sequence}}", "set": { "extcommunity_bandwidth": "{{extcommunity_bw}}", }, }, }, }, }, }, }, { "name": "set_extcommunity_bandwidth_non_transitive", "getval": re.compile( r""" ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\sset\sextcommunity\s(?Pbandwidth-non-transitive) *$""", re.VERBOSE, ), "compval": "set.extcommunity_bandwidth_non_transitive", "setval": "policy route-map {{route_map}} rule {{sequence}} " "set extcommunity bandwidth-non-transitive", "result": { "route_maps": { "{{ route_map }}": { "route_map": '{{ route_map }}', "entries": { "{{sequence}}": { "sequence": "{{sequence}}", "set": { "extcommunity_bandwidth_non_transitive": "{{True if extcommunity_bw_nt is defined}}", }, }, }, }, }, }, }, { "name": "set_ip_next_hop", "getval": re.compile( r""" - ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\sset\sip-next-hop\s(?P\S+) - *$""", + ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\sset\sip-next-hop\s(?P\S+)\s*$""", re.VERBOSE, ), "compval": "set.ip_next_hop", "setval": "policy route-map {{route_map}} rule {{sequence}} " "set ip-next-hop {{set.ip_next_hop}}", "result": { "route_maps": { "{{ route_map }}": { "route_map": '{{ route_map }}', "entries": { "{{sequence}}": { "sequence": "{{sequence}}", "set": { "ip_next_hop": "{{ip_next_hop}}", }, }, }, }, }, }, }, { "name": "set_ipv6_next_hop", "getval": re.compile( r""" ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\sset\sipv6-next-hop \s(?Pglobal|local) - \s(?P\S+) - *$""", + \s(?P\S+)\s*$""", re.VERBOSE, ), "compval": "set.ipv6_next_hop", "setval": "policy route-map {{route_map}} rule {{sequence}} " "set ipv6-next-hop {{set.ipv6_next_hop.ip_type}} {{set.ipv6_next_hop.value}}", "result": { "route_maps": { "{{ route_map }}": { "route_map": '{{ route_map }}', "entries": { "{{sequence}}": { "sequence": "{{sequence}}", "set": { "ipv6_next_hop": { "ip_type": "{{type}}", "value": "{{value}}", }, }, }, }, }, }, }, }, { "name": "set_large_community", "getval": re.compile( r""" ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\sset\slarge-community\s(?Pnone|replace\s(?P\S+)) $""", re.VERBOSE, ), "compval": "set.large_community", "setval": "policy route-map {{route_map}} rule {{sequence}} " "set large-community {{set.large_community if set.large_community == 'none' else 'replace ' + set.large_community}}", "result": { "route_maps": { "{{ route_map }}": { "route_map": '{{ route_map }}', "entries": { "{{sequence}}": { "sequence": "{{sequence}}", "set": { "large_community": "{{op if op == 'none' else large_community}}", }, }, }, }, }, }, }, { "name": "set_local_preference", "getval": re.compile( r""" - ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\sset\slocal-preference\s(?P\S+) - *$""", + ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\sset\slocal-preference\s(?P\S+)\s*$""", re.VERBOSE, ), "compval": "set.local_preference", "setval": "policy route-map {{route_map}} rule {{sequence}} " "set local-preference {{set.local_preference}}", "result": { "route_maps": { "{{ route_map }}": { "route_map": '{{ route_map }}', "entries": { "{{sequence}}": { "sequence": "{{sequence}}", "set": { "local_preference": "{{local_preference}}", }, }, }, }, }, }, }, { "name": "set_metric", "getval": re.compile( r""" - ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\sset\smetric\s(?P\S+) - *$""", + ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\sset\smetric\s(?P\S+)\s*$""", re.VERBOSE, ), "compval": "set.metric", "setval": "policy route-map {{route_map}} rule {{sequence}} " "set metric {{set.metric}}", "result": { "route_maps": { "{{ route_map }}": { "route_map": '{{ route_map }}', "entries": { "{{sequence}}": { "sequence": "{{sequence}}", "set": { "metric": "{{metric}}", }, }, }, }, }, }, }, { "name": "set_metric_type", "getval": re.compile( r""" - ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\sset\smetric-type\s(?P\S+) - *$""", + ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\sset\smetric-type\s(?P\S+)\s*$""", re.VERBOSE, ), "compval": "set.metric_type", "setval": "policy route-map {{route_map}} rule {{sequence}} " "set metric-type {{set.metric_type}}", "result": { "route_maps": { "{{ route_map }}": { "route_map": '{{ route_map }}', "entries": { "{{sequence}}": { "sequence": "{{sequence}}", "set": { "metric_type": "{{metric_type}}", }, }, }, }, }, }, }, { "name": "set_origin", "getval": re.compile( r""" - ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\sset\sorigin\s(?P\S+) - *$""", + ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\sset\sorigin\s(?P\S+)\s*$""", re.VERBOSE, ), "compval": "set.origin", "setval": "policy route-map {{route_map}} rule {{sequence}} " "set origin {{set.origin}}", "result": { "route_maps": { "{{ route_map }}": { "route_map": '{{ route_map }}', "entries": { "{{sequence}}": { "sequence": "{{sequence}}", "set": { "origin": "{{origin}}", }, }, }, }, }, }, }, { "name": "set_originator_id", "getval": re.compile( r""" - ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\sset\soriginator-id\s(?P\S+) - *$""", + ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\sset\soriginator-id\s(?P\S+)\s*$""", re.VERBOSE, ), "compval": "set.originator_id", "setval": "policy route-map {{route_map}} rule {{sequence}} " "set originator-id {{set.originator_id}}", "result": { "route_maps": { "{{ route_map }}": { "route_map": '{{ route_map }}', "entries": { "{{sequence}}": { "sequence": "{{sequence}}", "set": { "originator_id": "{{originator_id}}", }, }, }, }, }, }, }, { "name": "set_src", "getval": re.compile( r""" - ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\sset\ssrc\s(?P\S+) - *$""", + ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\sset\ssrc\s(?P\S+)\s*$""", re.VERBOSE, ), "compval": "set.src", "setval": "policy route-map {{route_map}} rule {{sequence}} " "set src {{set.src}}", "result": { "route_maps": { "{{ route_map }}": { "route_map": '{{ route_map }}', "entries": { "{{sequence}}": { "sequence": "{{sequence}}", "set": { "src": "{{src}}", }, }, }, }, }, }, }, { "name": "set_tag", "getval": re.compile( r""" - ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\sset\stag\s(?P\S+) - *$""", + ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\sset\stag\s(?P\S+)\s*$""", re.VERBOSE, ), "compval": "set.tag", "setval": "policy route-map {{route_map}} rule {{sequence}} " "set tag {{set.tag}}", "result": { "route_maps": { "{{ route_map }}": { "route_map": '{{ route_map }}', "entries": { "{{sequence}}": { "sequence": "{{sequence}}", "set": { "tag": "{{tag}}", }, }, }, }, }, }, }, { "name": "set_weight", "getval": re.compile( r""" - ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\sset\sweight\s(?P\S+) - *$""", + ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\sset\sweight\s(?P\S+)\s*$""", re.VERBOSE, ), "compval": "set.weight", "setval": "policy route-map {{route_map}} rule {{sequence}} " "set weight {{set.weight}}", "result": { "route_maps": { "{{ route_map }}": { "route_map": '{{ route_map }}', "entries": { "{{sequence}}": { "sequence": "{{sequence}}", "set": { "weight": "{{weight}}", }, }, }, }, }, }, }, { "name": "set_table", "getval": re.compile( r""" - ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\sset\stable\s(?P
\S+) - *$""", + ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\sset\stable\s(?P
\S+)\s*$""", re.VERBOSE, ), "compval": "set.weight", "setval": "policy route-map {{route_map}} rule {{sequence}} " "set table {{set.table}}", "result": { "route_maps": { "{{ route_map }}": { "route_map": '{{ route_map }}', "entries": { "{{sequence}}": { "sequence": "{{sequence}}", "set": { "table": "{{table}}", }, }, }, }, }, }, }, { "name": "set_community", "getval": re.compile( r""" ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\sset\scommunity\s(?Pnone|replace\s(?P\S+)) $""", re.VERBOSE, ), "compval": "set.community.value", "setval": "policy route-map {{route_map}} rule {{sequence}} " "set community {{set.community.value if set.community.value == 'none' else 'replace ' + set.community.value}}", "result": { "route_maps": { "{{ route_map }}": { "route_map": '{{ route_map }}', "entries": { "{{sequence}}": { "sequence": "{{sequence}}", "set": { "community": { "value": "{{op if op == 'none' else value}}", }, }, }, }, }, }, }, }, { "name": "match_as_path", "getval": re.compile( r""" - ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\smatch\sas-path\s(?P\S+) - *$""", + ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\smatch\sas-path\s(?P\S+)\s*$""", re.VERBOSE, ), "compval": "match.as_path", "setval": "policy route-map {{route_map}} rule {{sequence}} " "match as-path {{match.as_path}}", "result": { "route_maps": { "{{ route_map }}": { "route_map": '{{ route_map }}', "entries": { "{{sequence}}": { "sequence": "{{sequence}}", "match": { "as_path": "{{as_path}}", }, }, }, }, }, }, }, { "name": "match_community_community_list", "getval": re.compile( r""" - ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\smatch\scommunity\scommunity-list\s(?P\S+) - *$""", + ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\smatch\scommunity\scommunity-list\s(?P\S+)\s*$""", re.VERBOSE, ), "compval": "match.community.community_list", "setval": "policy route-map {{route_map}} rule {{sequence}} " "match community community-list {{match.community.community_list}}", "result": { "route_maps": { "{{ route_map }}": { "route_map": '{{ route_map }}', "entries": { "{{sequence}}": { "sequence": "{{sequence}}", "match": { "community": {"community_list": "{{community_list}}"}, }, }, }, }, }, }, }, { "name": "match_community_exact_match", "getval": re.compile( r""" ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\smatch\scommunity\sexact-match(?P) *$""", re.VERBOSE, ), "compval": "match.community.exact_match", "setval": "policy route-map {{route_map}} rule {{sequence}} " "match community exact-match", "result": { "route_maps": { "{{ route_map }}": { "route_map": '{{ route_map }}', "entries": { "{{sequence}}": { "sequence": "{{sequence}}", "match": { "community": {"exact_match": "{{True if exact_match is defined}}"}, }, }, }, }, }, }, }, { "name": "match_extcommunity", "getval": re.compile( r""" - ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\smatch\sextcommunity\s(?P\S+) - *$""", + ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\smatch\sextcommunity\s(?P\S+)\s*$""", re.VERBOSE, ), "compval": "match.extcommunity", "setval": "policy route-map {{route_map}} rule {{sequence}} " "match extcommunity {{match.extcommunity}}", "result": { "route_maps": { "{{ route_map }}": { "route_map": '{{ route_map }}', "entries": { "{{sequence}}": { "sequence": "{{sequence}}", "match": { "extcommunity": "{{extcommunity}}", }, }, }, }, }, }, }, { "name": "match_interface", "getval": re.compile( r""" - ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\smatch\sinterface\s(?P\S+) - *$""", + ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\smatch\sinterface\s(?P\S+)\s*$""", re.VERBOSE, ), "compval": "match.interface", "setval": "policy route-map {{route_map}} rule {{sequence}} " "match interface {{match.interface}}", "result": { "route_maps": { "{{ route_map }}": { "route_map": '{{ route_map }}', "entries": { "{{sequence}}": { "sequence": "{{sequence}}", "match": { "interface": "{{interface}}", }, }, }, }, }, }, }, { "name": "match_large_community_large_community_list", "getval": re.compile( r""" - ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\smatch\slarge-community\slarge-community-list\s(?P\S+) - *$""", + ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\smatch\slarge-community\slarge-community-list\s(?P\S+)\s*$""", re.VERBOSE, ), "compval": "match.large_community_large_community_list", "setval": "policy route-map {{route_map}} rule {{sequence}} " "match large-community large-community-list {{match.large_community_large_community_list}}", "result": { "route_maps": { "{{ route_map }}": { "route_map": '{{ route_map }}', "entries": { "{{sequence}}": { "sequence": "{{sequence}}", "match": { "large_community_large_community_list": "{{lc}}", }, }, }, }, }, }, }, { "name": "match_metric", "getval": re.compile( r""" - ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\smatch\smetric\s(?P\S+) - *$""", + ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\smatch\smetric\s(?P\S+)\s*$""", re.VERBOSE, ), "compval": "match.metric", "setval": "policy route-map {{route_map}} rule {{sequence}} " "match metric {{match.metric}}", "result": { "route_maps": { "{{ route_map }}": { "route_map": '{{ route_map }}', "entries": { "{{sequence}}": { "sequence": "{{sequence}}", "match": { "metric": "{{metric}}", }, }, }, }, }, }, }, { "name": "match_origin", "getval": re.compile( r""" - ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\smatch\sorigin\s(?P\S+) - *$""", + ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\smatch\sorigin\s(?P\S+)\s*$""", re.VERBOSE, ), "compval": "match.origin", "setval": "policy route-map {{route_map}} rule {{sequence}} " "match origin {{match.origin}}", "result": { "route_maps": { "{{ route_map }}": { "route_map": '{{ route_map }}', "entries": { "{{sequence}}": { "sequence": "{{sequence}}", "match": { "origin": "{{origin}}", }, }, }, }, }, }, }, { "name": "match_peer", "getval": re.compile( r""" - ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\smatch\speer\s(?P\S+) - *$""", + ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\smatch\speer\s(?P\S+)\s*$""", re.VERBOSE, ), "compval": "match.peer", "setval": "policy route-map {{route_map}} rule {{sequence}} " "match peer {{match.peer}}", "result": { "route_maps": { "{{ route_map }}": { "route_map": '{{ route_map }}', "entries": { "{{sequence}}": { "sequence": "{{sequence}}", "match": { "peer": "{{peer}}", }, }, }, }, }, }, }, { "name": "match_ip_address", "getval": re.compile( r""" ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\smatch\sip\saddress \s(?Paccess-list|prefix-list) - \s(?P\S+) - *$""", + \s(?P\S+)\s*$""", re.VERBOSE, ), "compval": "match.ip.address", "setval": "policy route-map {{route_map}} rule {{sequence}} " "match ip address {{match.ip.address.list_type}} {{match.ip.address.value}}", "result": { "route_maps": { "{{ route_map }}": { "route_map": '{{ route_map }}', "entries": { "{{sequence}}": { "sequence": "{{sequence}}", "match": { "ip": { "address": { "list_type": "{{list_type}}", "value": "{{value}}", }, }, }, }, }, }, }, }, }, { "name": "match_ip_next_hop", "getval": re.compile( r""" ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\smatch\sip\snexthop \s(?Paccess-list|prefix-list) - \s(?P\S+) - *$""", + \s(?P\S+)\s*$""", re.VERBOSE, ), "compval": "match.ip.next_hop", "setval": "policy route-map {{route_map}} rule {{sequence}} " "match ip nexthop {{match.ip.next_hop.list_type}} {{match.ip.next_hop.value}}", "result": { "route_maps": { "{{ route_map }}": { "route_map": '{{ route_map }}', "entries": { "{{sequence}}": { "sequence": "{{sequence}}", "match": { "ip": { "next_hop": { "list_type": "{{list_type}}", "value": "{{value}}", }, }, }, }, }, }, }, }, }, { "name": "match_ip_route_source", "getval": re.compile( r""" ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\smatch\sip\sroute-source \s(?Paccess-list|prefix-list) - \s(?P\S+) - *$""", + \s(?P\S+)\s*$""", re.VERBOSE, ), "compval": "match.ip.route_source", "setval": "policy route-map {{route_map}} rule {{sequence}} " "match ip route-source {{match.ip.route_source.list_type}} {{match.ip.route_source.value}}", "result": { "route_maps": { "{{ route_map }}": { "route_map": '{{ route_map }}', "entries": { "{{sequence}}": { "sequence": "{{sequence}}", "match": { "ip": { "route_source": { "list_type": "{{list_type}}", "value": "{{value}}", }, }, }, }, }, }, }, }, }, { "name": "match_ipv6_address", "getval": re.compile( r""" ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\smatch\sipv6\saddress \s(?Paccess-list|prefix-list) - \s(?P\S+) - *$""", + \s(?P\S+)\s*$""", re.VERBOSE, ), "compval": "match.ipv6.address", "setval": "policy route-map {{route_map}} rule {{sequence}} " "match ipv6 address {{match.ipv6.address.list_type}} {{match.ipv6.address.value}}", "result": { "route_maps": { "{{ route_map }}": { "route_map": '{{ route_map }}', "entries": { "{{sequence}}": { "sequence": "{{sequence}}", "match": { "ipv6": { "address": { "list_type": "{{list_type}}", "value": "{{value}}", }, }, }, }, }, }, }, }, }, { "name": "match_ipv6_nexthop", "getval": re.compile( r""" ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\smatch\sipv6\snexthop - \s(?P\S+) - *$""", + \s(?P\S+)\s*$""", re.VERBOSE, ), "compval": "match.ipv6.next_hop", "setval": "policy route-map {{route_map}} rule {{sequence}} " "match ipv6 nexthop {{match.ipv6.next_hop}}", "result": { "route_maps": { "{{ route_map }}": { "route_map": '{{ route_map }}', "entries": { "{{sequence}}": { "sequence": "{{sequence}}", "match": { "ipv6": { "next_hop": "{{value}}", }, }, }, }, }, }, }, }, { "name": "match_protocol", "getval": re.compile( r""" - ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\smatch\sprotocol\s(?P\S+) - *$""", + ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\smatch\sprotocol\s(?P\S+)\s*$""", re.VERBOSE, ), "compval": "match.protocol", "setval": "policy route-map {{route_map}} rule {{sequence}} " "match protocol {{match.protocol}}", "result": { "route_maps": { "{{ route_map }}": { "route_map": '{{ route_map }}', "entries": { "{{sequence}}": { "sequence": "{{sequence}}", "match": { "protocol": "{{value}}", }, }, }, }, }, }, }, { "name": "match_rpki", "getval": re.compile( r""" ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\smatch\srpki - \s(?P\S+) - *$""", + \s(?P\S+)\s*$""", re.VERBOSE, ), "compval": "match.rpki", "setval": "policy route-map {{route_map}} rule {{sequence}} " "match rpki {{match.rpki}}", "result": { "route_maps": { "{{ route_map }}": { "route_map": '{{ route_map }}', "entries": { "{{sequence}}": { "sequence": "{{sequence}}", "match": { "rpki": "{{value}}", }, }, }, }, }, }, }, ] # fmt: on diff --git a/plugins/module_utils/network/vyos/rm_templates/snmp_server.py b/plugins/module_utils/network/vyos/rm_templates/snmp_server.py index 71753083..ff1c6465 100644 --- a/plugins/module_utils/network/vyos/rm_templates/snmp_server.py +++ b/plugins/module_utils/network/vyos/rm_templates/snmp_server.py @@ -1,610 +1,602 @@ # -*- coding: utf-8 -*- # Copyright 2022 Red Hat # GNU General Public License v3.0+ # (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) from __future__ import absolute_import, division, print_function __metaclass__ = type """ The Snmp_server parser templates file. This contains a list of parser definitions and associated functions that facilitates both facts gathering and native command generation for the given network resource. """ import re from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.rm_base.network_template import ( NetworkTemplate, ) def _tmplt_snmp_server_communities(config_data): config_data = config_data["communities"] command = [] cmd = "service snmp community {name}".format(**config_data) if "authorization_type" in config_data: auth_cmd = cmd + " authorization {authorization_type}".format(**config_data) command.append(auth_cmd) if "clients" in config_data: for c in config_data["clients"]: client_cmd = cmd + " client " + c command.append(client_cmd) if "networks" in config_data: for n in config_data["networks"]: network_command = cmd + " network " + n command.append(network_command) if not command: command.append(cmd) return command def _tmplt_snmp_server_trap_target(config_data): config_data = config_data["trap_target"] command = "service snmp trap-target {address}".format(**config_data) if "authorization_type" in config_data: command += " authorization {authorization_type}".format(**config_data) if "client" in config_data: command += " client {client}".format(**config_data) if "network" in config_data: command += " network {network}".format(**config_data) return command def _tmplt_snmp_server_v3_groups(config_data): config_data = config_data["snmp_v3"]["groups"] command = [] cmd = "service snmp v3 group {group}".format(**config_data) if "mode" in config_data: mode_cmd = cmd + " mode {mode}".format(**config_data) command.append(mode_cmd) if "seclevel" in config_data: sec_cmd = cmd + " seclevel {seclevel}".format(**config_data) command.append(sec_cmd) if "view" in config_data: view_cmd = cmd + " view {view}".format(**config_data) command.append(view_cmd) return command def _tmplt_snmp_server_v3_trap_target(config_data): config_data = config_data["snmp_v3"]["trap_targets"] command = "service snmp v3 trap-target {address} ".format(**config_data) if "authentication" in config_data: command += " auth" config_data = config_data["authentication"] if "privacy" in config_data: command += " privacy" config_data = config_data["privacy"] if "type" in config_data: command += " type {mode}".format(**config_data) if "encrypted_key" in config_data: command += " encrypted-password {encrypted_key}".format(**config_data) if "plaintext_key" in config_data: command += " plaintext-password {plaintext_key}".format(**config_data) return command def _tmplt_snmp_server_v3_user(config_data): config_data = config_data["snmp_v3"]["users"] command = [] cmd = "service snmp v3 user {user}".format(**config_data) for k in ["authentication", "privacy"]: if config_data.get(k): config = config_data[k] if k == "authentication": val = " auth" else: val = " privacy" if "type" in config: type_cmd = cmd + val + " type {type}".format(**config) command.append(type_cmd) if "encrypted_key" in config: enc_cmd = cmd + val + " encrypted-password {encrypted_key}".format(**config) command.append(enc_cmd) if "plaintext_key" in config: plain_cmd = cmd + val + " plaintext-password {plaintext_key}".format(**config) command.append(plain_cmd) return command def _tmplt_snmp_server_v3_views(config_data): config_data = config_data["snmp_v3"]["views"] command = "service snmp v3 view {view} oid {oid}".format(**config_data) if "exclude" in config_data: command += " exclude {exclude}".format(**config_data) if "mask" in config_data: command += " mask {mask}".format(**config_data) return command class Snmp_serverTemplate(NetworkTemplate): def __init__(self, lines=None, module=None): prefix = {"set": "set", "remove": "delete"} super(Snmp_serverTemplate, self).__init__( lines=lines, tmplt=self, prefix=prefix, module=module, ) # fmt: off PARSERS = [ # service snmp community <> { "name": "communities", "getval": re.compile( r""" ^set\sservice\ssnmp\scommunity \s+(?P\S+) - \s*(?Pauthorization\srw|authorization\sro)* - \s*(client\s(?P\S+))* - \s*(network\s(?P\S+))* + \s*(?Pauthorization\srw|authorization\sro)? + \s*(client\s(?P\S+))? + \s*(network\s(?P\S+))? $""", re.VERBOSE, ), "setval": _tmplt_snmp_server_communities, "result": { "communities": { "{{ name }}": { "name": "{{ name }}", "clients": ['{{ client if client is defined else "None" }}'], "networks": ['{{ network if network is defined else "None" }}'], "authorization_type": '{{ auth.split(" ")[1] if auth is defined else None }}', }, }, }, }, # service snmp contact <> { "name": "contact", "getval": re.compile( r""" ^set\sservice\ssnmp\scontact - \s+(?P\S+) - *$""", + \s+(?P\S+)\s*$""", re.VERBOSE, ), "setval": "service snmp contact {{ contact }}", "result": { "contact": "{{ name }}", }, }, # service snmp description <> { "name": "description", "getval": re.compile( r""" ^set\sservice\ssnmp\sdescription - \s+(?P\S+) - *$""", + \s+(?P\S+)\s*$""", re.VERBOSE, ), "setval": "service snmp description {{ description }}", "result": { "description": "{{ name }}", }, }, # service snmp listen-address <> port <> { "name": "listen_addresses", "getval": re.compile( r""" ^set\sservice\ssnmp\slisten-address \s+(?P\S+) - \s*(port)* - \s*(?P\d+)* + \s*(port)? + \s*(?P\d+)? $""", re.VERBOSE, ), "setval": "service snmp listen-address {{ listen_addresses.address }}" "{{ (' port ' + listen_addresses.port|string) if listen_addresses.port is defined else '' }}", "result": { "listen_addresses": { "{{ addr }}": { "address": "{{ addr }}", "port": "{{ port }}", }, }, }, }, # service snmp location <> { "name": "location", "getval": re.compile( r""" ^set\sservice\ssnmp\slocation \s(?P.*) $""", re.VERBOSE, ), "setval": "service snmp location {{ '\\'' + location + '\\''}}", "result": { "location": "{{ name }}", }, }, # service snmp smux-peer <> { "name": "smux_peer", "getval": re.compile( r""" ^set\sservice\ssnmp\ssmux-peer - \s+(?P\S+) - *$""", + \s+(?P\S+)\s*$""", re.VERBOSE, ), "setval": "service snmp smux-peer {{ smux_peer }}", "result": { "smux_peer": "{{ name }}", }, }, # service snmp trap-source <> { "name": "trap_source", "getval": re.compile( r""" ^set\sservice\ssnmp\strap-source - \s+(?P\S+) - *$""", + \s+(?P\S+)\s*$""", re.VERBOSE, ), "setval": "service snmp trap-source {{ trap_source }}", "result": { "trap_source": "{{ name }}", }, }, # service snmp trap-target <> { "name": "trap_target", "getval": re.compile( r""" ^set\sservice\ssnmp\strap-target \s+(?P\S+) - \s*(?Pcommunity\s\S+)* - \s*(?Pport\s\d+)* - $""", + \s*(?Pcommunity\s\S+)? + \s*(?Pport\s\d+)? $""", re.VERBOSE, ), "setval": _tmplt_snmp_server_trap_target, "result": { "trap_target": { "address": "{{ name }}", "community": "{{ comm.split(" ")[1] if comm is defined else None }}", "port": "{{ port.split(" ")[1] if port is defined else None }}", }, }, }, # service snmp v3 engineid <> { "name": "snmp_v3.engine_id", "getval": re.compile( r""" ^set\sservice\ssnmp\sv3\sengineid - \s+(?P\S+) - *$""", + \s+(?P\S+)\s*$""", re.VERBOSE, ), "setval": "service snmp v3 engineid {{ snmp_v3.engine_id }}", "result": { "snmp_v3": { "engine_id": "{{ name }}", }, }, }, # service snmp v3 group <> { "name": "snmp_v3.groups", "getval": re.compile( r""" ^set\sservice\ssnmp\sv3\sgroup \s+(?P\S+) - \s*(?Pmode\s\S+)* - \s*(?Pseclevel\s\S+)* - \s*(?Pview\s\S+)* + \s*(?Pmode\s\S+)? + \s*(?Pseclevel\s\S+)? + \s*(?Pview\s\S+)? $""", re.VERBOSE, ), "setval": _tmplt_snmp_server_v3_groups, "result": { "snmp_v3": { "groups": { "{{ name }}": { "group": "{{ name }}", "mode": '{{ mode.split(" ")[1] if mode is defined else None }}', "seclevel": '{{ sec.split(" ")[1] if sec is defined else None }}', "view": '{{ view.split(" ")[1] if view is defined else None }}', }, }, }, }, }, # service snmp v3 trap-target <> auth <> { "name": "snmp_v3.trap_targets.authentication", "getval": re.compile( r""" ^set\sservice\ssnmp\sv3\strap-target \s+(?P\S+) \s+auth - \s*(?Pencrypted-password\s\S+)* - \s*(?Pplaintext-password\s\S+)* - \s*(?Ptype\s\S+)* + \s*(?Pencrypted-password\s\S+)? + \s*(?Pplaintext-password\s\S+)? + \s*(?Ptype\s\S+)? $""", re.VERBOSE, ), "setval": _tmplt_snmp_server_v3_trap_target, "result": { "snmp_v3": { "trap_targets": { "{{ name }}": { "address": "{{ name }}", "authentication": { "encrypted_key": '{{ enc.split(" ")[1] if enc is defined else None }}', "plaintext_key": '{{ plain.split(" ")[1] if plain is defined else None }}', "type": '{{ type.split(" ")[1] if type is defined else None }}', }, }, }, }, }, }, # service snmp v3 trap-target <> port <> { "name": "snmp_v3.trap_targets.port", "getval": re.compile( r""" ^set\sservice\ssnmp\sv3\strap-target \s+(?P\S+) - \s+(?Pport\s\d+)* - $""", + \s+(?Pport\s\d+)? $""", re.VERBOSE, ), "setval": "service snmp v3 trap-target port {{ snmp_v3.trap_targets.port }}", "result": { "snmp_v3": { "trap_targets": { "{{ name }}": { "address": "{{ name }}", "port": "{{ port }}", }, }, }, }, }, # service snmp v3 trap-target <> protocol <> { "name": "snmp_v3.trap_targets.protocol", "getval": re.compile( r""" ^set\sservice\ssnmp\sv3\strap-target \s+(?P\S+) - \s+(?Pprotocol\s\S+)* + \s+(?Pprotocol\s\S+)? $""", re.VERBOSE, ), "setval": "service snmp v3 trap-target protocol {{ snmp_v3.trap_targets.protocol }}", "result": { "snmp_v3": { "trap_targets": { "{{ name }}": { "address": "{{ name }}", "protocol": "{{ protocol }}", }, }, }, }, }, # service snmp v3 trap-target <> type <> { "name": "snmp_v3.trap_targets.type", "getval": re.compile( r""" ^set\sservice\ssnmp\sv3\strap-target \s+(?P\S+) - \s+(?Ptype\s\S+)* + \s+(?Ptype\s\S+)? $""", re.VERBOSE, ), "setval": "service snmp v3 trap-target type {{ snmp_v3.trap_targets.type }}", "result": { "snmp_v3": { "trap_targets": { "{{ name }}": { "address": "{{ name }}", "type": "{{ type }}", }, }, }, }, }, # service snmp v3 trap-target <> user <> { "name": "snmp_v3.trap_targets.user", "getval": re.compile( r""" ^set\sservice\ssnmp\sv3\strap-target \s+(?P\S+) - \s+(?Puser\s\S+)* + \s+(?Puser\s\S+)? $""", re.VERBOSE, ), "setval": "service snmp v3 trap-target user {{ snmp_v3.trap_targets.user }}", "result": { "snmp_v3": { "trap_targets": { "{{ name }}": { "address": "{{ name }}", "user": "{{ user }}", }, }, }, }, }, # service snmp v3 trap-target <> privacy <> { "name": "snmp_v3.trap_targets.privacy", "getval": re.compile( r""" ^set\sservice\ssnmp\sv3\strap-target \s+(?P\S+) \s+privacy - \s*(?Pencrypted-password\s\S+)* - \s*(?Pplaintext-password\s\S+)* - \s*(?Ptype\s\S+)* + \s*(?Pencrypted-password\s\S+)? + \s*(?Pplaintext-password\s\S+)? + \s*(?Ptype\s\S+)? $""", re.VERBOSE, ), "setval": _tmplt_snmp_server_v3_trap_target, "result": { "snmp_v3": { "trap_targets": { "{{ name }}": { "address": "{{ name }}", "privacy": { "encrypted_key": '{{ enc.split(" ")[1] if enc is defined else None }}', "plaintext_key": '{{ plain.split(" ")[1] if plain is defined else None }}', "type": '{{ type.split(" ")[1] if type is defined else None }}', }, }, }, }, }, }, # service snmp v3 user <> auth <> { "name": "snmp_v3.users.authentication", "getval": re.compile( r""" ^set\sservice\ssnmp\sv3\suser \s+(?P\S+) \s+auth - \s*(?Pencrypted-password\s\S+)* - \s*(?Pplaintext-password\s\S+)* - \s*(?Ptype\s\S+)* + \s*(?Pencrypted-password\s\S+)? + \s*(?Pplaintext-password\s\S+)? + \s*(?Ptype\s\S+)? $""", re.VERBOSE, ), "setval": _tmplt_snmp_server_v3_user, "result": { "snmp_v3": { "users": { "{{ name }}": { "user": "{{ name }}", "authentication": { "encrypted_key": '{{ enc.split(" ")[1] if enc is defined else None }}', "plaintext_key": '{{ plain.split(" ")[1] if plain is defined else None }}', "type": '{{ type.split(" ")[1] if type is defined else None }}', }, }, }, }, }, }, # service snmp v3 user <> privacy <> { "name": "snmp_v3.users.privacy", "getval": re.compile( r""" ^set\sservice\ssnmp\sv3\suser \s+(?P\S+) \s+privacy - \s*(?Pencrypted-password\s\S+)* - \s*(?Pplaintext-password\s\S+)* - \s*(?Ptype\s\S+)* + \s*(?Pencrypted-password\s\S+)? + \s*(?Pplaintext-password\s\S+)? + \s*(?Ptype\s\S+)? $""", re.VERBOSE, ), "setval": _tmplt_snmp_server_v3_user, "result": { "snmp_v3": { "users": { "{{ name }}": { "user": "{{ name }}", "privacy": { "encrypted_key": '{{ enc.split(" ")[1] if enc is defined else None }}', "plaintext_key": '{{ plain.split(" ")[1] if plain is defined else None }}', "type": '{{ type.split(" ")[1] if type is defined else None }}', }, }, }, }, }, }, # service snmp v3 user <> group <> { "name": "snmp_v3.users.group", "getval": re.compile( r""" ^set\sservice\ssnmp\sv3\suser \s+(?P\S+) - \s+(?Pgroup\s.+)* - $""", + \s+(?Pgroup\s.+)? $""", re.VERBOSE, ), "setval": "service snmp v3 user {{ snmp_v3.users.user }} group {{ snmp_v3.users.group }}", "result": { "snmp_v3": { "users": { "{{ name }}": { "user": "{{ name }}", "group": "{{ group.split(" ")[1] if group is defined else None }}", }, }, }, }, }, # service snmp v3 user <> mode <> { "name": "snmp_v3.users.mode", "getval": re.compile( r""" ^set\sservice\ssnmp\sv3\suser \s+(?P\S+) - \s+(?Pmode\s\S+)* + \s+(?Pmode\s\S+)? $""", re.VERBOSE, ), "setval": "service snmp v3 user {{ snmp_v3.users.user }} mode {{ snmp_v3.users.mode }}", "result": { "snmp_v3": { "users": { "{{ name }}": { "user": "{{ name }}", "mode": "{{ mode }}", }, }, }, }, }, # service snmp v3 view <> { "name": "snmp_v3.views", "getval": re.compile( r""" ^set\sservice\ssnmp\sv3\sview \s+(?P\S+) \s+(?Poid\s\S+) - \s*(?Pexclude\s\S+)* - \s*(?Pmask\s\S+)* + \s*(?Pexclude\s\S+)? + \s*(?Pmask\s\S+)? $""", re.VERBOSE, ), "setval": _tmplt_snmp_server_v3_views, "result": { "snmp_v3": { "views": { "{{ name }}": { "view": "{{ name }}", "oid": '{{ oid.split(" ")[1] if oid is defined else None }}', "exclude": '{{ ex.split(" ")[1] if ex is defined else None }}', "mask": '{{ mask.split(" ")[1] if mask is defined else None }}', }, }, }, }, }, ] # fmt: on diff --git a/plugins/modules/vyos_user.py b/plugins/modules/vyos_user.py index 495dce6a..0c79ce30 100644 --- a/plugins/modules/vyos_user.py +++ b/plugins/modules/vyos_user.py @@ -1,515 +1,517 @@ #!/usr/bin/python # -*- coding: utf-8 -*- from __future__ import absolute_import, division, print_function __metaclass__ = type # (c) 2017, Ansible by Red Hat, inc # # This file is part of Ansible by Red Hat # # Ansible is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Ansible is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with Ansible. If not, see . # DOCUMENTATION = """ module: vyos_user author: Trishna Guha (@trishnaguha) short_description: Manage the collection of local users on VyOS device description: - This module provides declarative management of the local usernames configured on network devices. It allows playbooks to manage either individual usernames or the collection of usernames in the current running config. It also supports purging usernames from the configuration that are not explicitly defined. version_added: 1.0.0 extends_documentation_fragment: - vyos.vyos.vyos notes: - Tested against VyOS 1.3.8, 1.4.2, the upcoming 1.5, and the rolling release of spring 2025. - This module works with connection C(ansible.netcommon.network_cli). See L(the VyOS OS Platform Options,../network/user_guide/platform_vyos.html). options: aggregate: description: - The set of username objects to be configured on the remote VyOS device. The list entries can either be the username or a hash of username and properties. This argument is mutually exclusive with the C(name) argument. aliases: - users - collection type: list elements: dict suboptions: name: description: - The username to be configured on the VyOS device. This argument accepts a string value and is mutually exclusive with the C(aggregate) argument. required: true type: str full_name: description: - The C(full_name) argument provides the full name of the user account to be created on the remote device. This argument accepts any text string value. type: str encrypted_password: description: - The encrypted password of the user account on the remote device. Note that unlike the C(configured_password) argument, this argument ignores the C(update_password) and updates if the value is different from the one in the device running config. type: str configured_password: description: - The password to be configured on the VyOS device. The password needs to be provided in clear and it will be encrypted on the device. type: str update_password: description: - Since passwords are encrypted in the device running config, this argument will instruct the module when to change the password. When set to C(always), the password will always be updated in the device and when set to C(on_create) the password will be updated only if the username is created. type: str choices: - on_create - always state: description: - Configures the state of the username definition as it relates to the device operational configuration. When set to I(present), the username(s) should be configured in the device active configuration and when set to I(absent) the username(s) should not be in the device active configuration type: str choices: - present - absent public_keys: &public_keys description: - Public keys for authentiction over SSH. type: list elements: dict suboptions: name: description: Name of the key (usually in the form of user@hostname) required: true type: str key: description: Public key string (base64 encoded) required: true type: str type: description: Type of the key required: true type: str choices: - ssh-dss - ssh-rsa - ecdsa-sha2-nistp256 - ecdsa-sha2-nistp384 - ssh-ed25519 - ecdsa-sha2-nistp521 name: description: - The username to be configured on the VyOS device. This argument accepts a string value and is mutually exclusive with the C(aggregate) argument. type: str full_name: description: - The C(full_name) argument provides the full name of the user account to be created on the remote device. This argument accepts any text string value. type: str encrypted_password: description: - The encrypted password of the user account on the remote device. Note that unlike the C(configured_password) argument, this argument ignores the C(update_password) and updates if the value is different from the one in the device running config. type: str configured_password: description: - The password to be configured on the VyOS device. The password needs to be provided in clear and it will be encrypted on the device. type: str update_password: description: - Since passwords are encrypted in the device running config, this argument will instruct the module when to change the password. When set to C(always), the password will always be updated in the device and when set to C(on_create) the password will be updated only if the username is created. default: always type: str choices: - on_create - always public_keys: *public_keys purge: description: - Instructs the module to consider the resource definition absolute. It will remove any previously configured usernames on the device with the exception of the `admin` user (the current defined set of users). type: bool default: false state: description: - Configures the state of the username definition as it relates to the device operational configuration. When set to I(present), the username(s) should be configured in the device active configuration and when set to I(absent) the username(s) should not be in the device active configuration type: str default: present choices: - present - absent """ EXAMPLES = """ - name: create a new user vyos.vyos.vyos_user: name: ansible configured_password: password state: present - name: remove all users except admin vyos.vyos.vyos_user: purge: true - name: set multiple users to level operator vyos.vyos.vyos_user: aggregate: - name: netop - name: netend state: present - name: Change Password for User netop vyos.vyos.vyos_user: name: netop configured_password: '{{ new_password }}' update_password: always state: present """ RETURN = """ commands: description: The list of configuration mode commands to send to the device returned: always type: list sample: - set system login user authentication plaintext-password password """ import re +import shlex from copy import deepcopy from functools import partial from ansible.module_utils.basic import AnsibleModule from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.utils import ( remove_default_spec, ) from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.vyos import ( get_config, load_config, ) def spec_to_commands(updates, module): commands = list() update_password = module.params["update_password"] def needs_update(want, have, x): return want.get(x) and (want.get(x) != have.get(x)) def add(command, want, x): command.append("set system login user %s %s" % (want["name"], x)) for update in updates: want, have = update if want["state"] == "absent": commands.append("delete system login user %s" % want["name"]) continue if needs_update(want, have, "full_name"): add(commands, want, "full-name '%s'" % want["full_name"]) # look both ways for public_keys to handle replacement want_keys = want.get("public_keys") or dict() have_keys = have.get("public_keys") or dict() for key_name in want_keys: key = want_keys[key_name] if key_name not in have_keys or key != have_keys[key_name]: add( commands, want, "authentication public-keys %s key '%s'" % (key["name"], key["key"]), ) add( commands, want, "authentication public-keys %s type '%s'" % (key["name"], key["type"]), ) for key_name in have_keys: if key_name not in want_keys: commands.append( "delete system login user %s authentication public-keys %s" % (want["name"], key_name), ) if needs_update(want, have, "encrypted_password"): add( commands, want, "authentication encrypted-password '%s'" % want["encrypted_password"], ) if needs_update(want, have, "configured_password"): if update_password == "always" or not have: add( commands, want, - "authentication plaintext-password %s" % want["configured_password"], + "authentication plaintext-password %s" + % shlex.quote(want["configured_password"]), ) return commands def parse_full_name(data): match = re.search(r"full-name '(\S+)'", data, re.M) if match: full_name = match.group(1)[1:-1] return full_name def parse_key(data): match = re.search(r"key '(\S+)'", data, re.M) if match: key = match.group(1) return key def parse_key_type(data): match = re.search(r"type '(\S+)'", data, re.M) if match: key_type = match.group(1) return key_type def parse_public_keys(data): """ Parse public keys from the configuration returning dictionary of dictionaries indexed by key name """ match = re.findall(r"public-keys (\S+)", data, re.M) if not match: return dict() keys = dict() for key in set(match): regex = r" %s .+$" % key cfg = re.findall(regex, data, re.M) cfg = "\n".join(cfg) obj = { "name": key, "key": parse_key(cfg), "type": parse_key_type(cfg), } keys[key] = obj return keys def parse_encrypted_password(data): match = re.search(r"authentication encrypted-password '(\S+)'", data, re.M) if match: encrypted_password = match.group(1) return encrypted_password def config_to_dict(module): data = get_config(module) match = re.findall(r"^set system login user (\S+)", data, re.M) if not match: return list() instances = list() for user in set(match): regex = r" %s .+$" % user cfg = re.findall(regex, data, re.M) cfg = "\n".join(cfg) obj = { "name": user, "state": "present", "configured_password": None, "full_name": parse_full_name(cfg), "encrypted_password": parse_encrypted_password(cfg), "public_keys": parse_public_keys(cfg), } instances.append(obj) return instances def get_param_value(key, item, module): # if key doesn't exist in the item, get it from module.params if not item.get(key): value = module.params[key] else: value = item.get(key) # validate the param value (if validator func exists) validator = globals().get("validate_%s" % key) if all((value, validator)): validator(value, module) return value def map_key_params_to_dict(keys): """ Map the list of keys to a dictionary of dictionaries indexed by key name """ all_keys = dict() if keys is None: return all_keys for key in keys: key_name = key["name"] all_keys[key_name] = key return all_keys def map_params_to_obj(module): aggregate = module.params["aggregate"] if not aggregate: if not module.params["name"] and module.params["purge"]: return list() else: users = [{"name": module.params["name"]}] else: users = list() for item in aggregate: if not isinstance(item, dict): users.append({"name": item}) else: users.append(item) objects = list() for item in users: get_value = partial(get_param_value, item=item, module=module) item["configured_password"] = get_value("configured_password") item["encrypted_password"] = get_value("encrypted_password") item["full_name"] = get_value("full_name") item["state"] = get_value("state") item["public_keys"] = map_key_params_to_dict(get_value("public_keys")) objects.append(item) return objects def update_objects(want, have): updates = list() for entry in want: item = next((i for i in have if i["name"] == entry["name"]), None) if item is None: updates.append((entry, {})) elif item: for key, value in entry.items(): if value and value != item[key]: updates.append((entry, item)) return updates def main(): """main entry point for module execution""" public_key_spec = dict( name=dict(required=True, type="str"), key=dict(required=True, type="str", no_log=False), type=dict( required=True, type="str", choices=[ "ssh-dss", "ssh-rsa", "ecdsa-sha2-nistp256", "ecdsa-sha2-nistp384", "ssh-ed25519", "ecdsa-sha2-nistp521", ], ), ) element_spec = dict( name=dict(), full_name=dict(), configured_password=dict(no_log=True), encrypted_password=dict(no_log=False), update_password=dict(default="always", choices=["on_create", "always"]), state=dict(default="present", choices=["present", "absent"]), public_keys=dict(type="list", elements="dict", options=public_key_spec), ) aggregate_spec = deepcopy(element_spec) aggregate_spec["name"] = dict(required=True) # remove default in aggregate spec, to handle common arguments remove_default_spec(aggregate_spec) argument_spec = dict( aggregate=dict( type="list", elements="dict", options=aggregate_spec, aliases=["users", "collection"], ), purge=dict(type="bool", default=False), ) argument_spec.update(element_spec) mutually_exclusive = [ ("name", "aggregate"), ("encrypted_password", "configured_password"), ] module = AnsibleModule( argument_spec=argument_spec, mutually_exclusive=mutually_exclusive, supports_check_mode=True, ) warnings = list() result = {"changed": False, "warnings": warnings} want = map_params_to_obj(module) have = config_to_dict(module) commands = spec_to_commands(update_objects(want, have), module) if module.params["purge"]: want_users = [x["name"] for x in want] have_users = [x["name"] for x in have] for item in set(have_users).difference(want_users): commands.append("delete system login user %s" % item) result["commands"] = commands if commands: commit = not module.check_mode load_config(module, commands, commit=commit) result["changed"] = True module.exit_json(**result) if __name__ == "__main__": main() diff --git a/tests/unit/modules/network/vyos/test_rm_templates_perf.py b/tests/unit/modules/network/vyos/test_rm_templates_perf.py new file mode 100644 index 00000000..d2060f46 --- /dev/null +++ b/tests/unit/modules/network/vyos/test_rm_templates_perf.py @@ -0,0 +1,163 @@ +# -*- coding: utf-8 -*- +# Copyright 2026 Red Hat +# GNU General Public License v3.0+ +# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +"""Performance budget tests for rm_templates parsers. + +These tests guard against re-introducing catastrophic regex backtracking +in the rm_template parsers (T8609). Pre-fix, parse() over realistic +device-output input could take 50+ seconds because of `(group)*` +quantifiers on groups containing `\\S+`. Post-fix, the same input +parses in single-digit milliseconds. + +A 1-second budget is comfortably above post-fix runtime and well below +the pre-regression cliff, so the test fails sharply if the bug returns. +""" + +from __future__ import absolute_import, division, print_function + + +__metaclass__ = type + +import time + +from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.rm_templates.bgp_address_family_14 import ( + Bgp_address_familyTemplate14, +) +from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.rm_templates.bgp_global_14 import ( + Bgp_globalTemplate14, +) +from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.rm_templates.route_maps_14 import ( + Route_mapsTemplate14, +) +from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.rm_templates.snmp_server import ( + Snmp_serverTemplate, +) + + +PARSE_BUDGET_SECONDS = 1.0 + + +def _time_parse(parser_class, lines): + """Time a single ``parse()`` call against ``lines``; returns elapsed seconds.""" + parser = parser_class(lines=lines) + t0 = time.perf_counter() + parser.parse() + return time.perf_counter() - t0 + + +def test_route_maps_14_parse_budget(): + """Realistic route-map config: parse() must finish under 1s. + + Pre-T8609: ~50s. Post-fix: <50ms. Inputs use 20+ char names + because the backtracking is exponential in the first \\S+ run + after the prefix. + """ + lines = [ + "set policy route-map ADVERTISE-ANYCAST-v6 rule 10 action 'permit'", + "set policy route-map ADVERTISE-ANYCAST-v6 rule 10 match ipv6 address prefix-list 'ANYCAST-AGGREGATE-v6'", + "set policy route-map DEFAULT-ORIGINATE-SENTINEL-v6 rule 10 action 'permit'", + "set policy route-map DEFAULT-ORIGINATE-SENTINEL-v6 rule 10 match ipv6 address prefix-list 'AS64496-SENTINEL-v6'", + "set policy route-map DEFAULT-ORIGINATE-SENTINEL-v6 rule 10 set local-preference '120'", + "set policy route-map IXP-PEER-INGRESS-v4 rule 10 action 'permit'", + "set policy route-map IXP-PEER-INGRESS-v4 rule 10 match ip address prefix-list 'IXP-INBOUND-v4'", + "set policy route-map IXP-PEER-INGRESS-v4 rule 10 set community 'additive 65000:100'", + "set policy route-map TRANSIT-EGRESS-v4 rule 100 action 'permit'", + "set policy route-map TRANSIT-EGRESS-v4 rule 100 match ip address prefix-list 'CUSTOMER-PREFIXES-v4'", + "set policy route-map TRANSIT-EGRESS-v4 rule 100 set as-path prepend '65000 65000'", + "set policy route-map UPSTREAM-INGRESS-v4 rule 10 action 'permit'", + ] + elapsed = _time_parse(Route_mapsTemplate14, lines) + assert elapsed < PARSE_BUDGET_SECONDS, ( + "Route_mapsTemplate14.parse() took %.2fs (budget %.2fs); " + "possible regression of T8609 (rm_templates regex backtracking)." + % (elapsed, PARSE_BUDGET_SECONDS) + ) + + +def test_bgp_global_14_parse_budget(): + """Realistic BGP neighbor/address-family config: parse() under 1s.""" + lines = [ + "set protocols bgp 65001 neighbor 2001:db8:abcd:1234::1 remote-as '65002'", + "set protocols bgp 65001 neighbor 2001:db8:abcd:1234::1 description 'IXP-PEER-1'", + "set protocols bgp 65001 neighbor 2001:db8:abcd:1234::1 address-family ipv6-unicast route-map import 'IXP-INGRESS-v6'", + "set protocols bgp 65001 neighbor 2001:db8:abcd:1234::1 address-family ipv6-unicast route-map export 'IXP-EGRESS-v6'", + "set protocols bgp 65001 neighbor 192.0.2.1 remote-as '65003'", + "set protocols bgp 65001 neighbor 192.0.2.1 description 'TRANSIT-PROVIDER-1'", + "set protocols bgp 65001 neighbor 192.0.2.1 address-family ipv4-unicast route-map import 'TRANSIT-INGRESS-v4'", + "set protocols bgp 65001 neighbor 192.0.2.1 address-family ipv4-unicast route-map export 'TRANSIT-EGRESS-v4'", + ] + elapsed = _time_parse(Bgp_globalTemplate14, lines) + assert elapsed < PARSE_BUDGET_SECONDS, ( + "Bgp_globalTemplate14.parse() took %.2fs (budget %.2fs); " + "possible regression of T8609 (rm_templates regex backtracking)." + % (elapsed, PARSE_BUDGET_SECONDS) + ) + + +def test_snmp_server_parse_budget(): + """Realistic SNMP v3 config: parse() under 1s.""" + lines = [ + "set service snmp community PUBLIC-COMMUNITY-NAME-1 authorization 'ro'", + "set service snmp community PUBLIC-COMMUNITY-NAME-1 client '192.0.2.0/24'", + "set service snmp v3 trap-target TRAP-TARGET-LONG-NAME-1 user 'monitor'", + "set service snmp v3 trap-target TRAP-TARGET-LONG-NAME-1 protocol 'udp'", + "set service snmp v3 trap-target TRAP-TARGET-LONG-NAME-1 port '162'", + "set service snmp v3 user TRAP-USER-LONG-NAME-1 mode 'auth'", + "set service snmp v3 user TRAP-USER-LONG-NAME-1 group 'monitor'", + ] + elapsed = _time_parse(Snmp_serverTemplate, lines) + assert elapsed < PARSE_BUDGET_SECONDS, ( + "Snmp_serverTemplate.parse() took %.2fs (budget %.2fs); " + "possible regression of T8609 (rm_templates regex backtracking)." + % (elapsed, PARSE_BUDGET_SECONDS) + ) + + +def test_bgp_address_family_14_parse_budget(): + """Realistic BGP address-family aggregate config: parse() under 1s.""" + lines = [ + "set protocols bgp 65001 address-family ipv4-unicast network 198.51.100.0/24 backdoor", + "set protocols bgp 65001 address-family ipv4-unicast network 198.51.100.0/24 path-limit '4'", + "set protocols bgp 65001 address-family ipv4-unicast network 198.51.100.0/24 route-map 'NET-IN-v4'", + "set protocols bgp 65001 address-family ipv4-unicast aggregate-address 203.0.113.0/24 as-set", + "set protocols bgp 65001 address-family ipv4-unicast aggregate-address 203.0.113.0/24 summary-only", + "set protocols bgp 65001 address-family ipv6-unicast network 2001:db8:abcd:1234::/64 backdoor", + "set protocols bgp 65001 address-family ipv6-unicast network 2001:db8:abcd:1234::/64 route-map 'NET-IN-v6'", + "set protocols bgp 65001 address-family ipv6-unicast aggregate-address 2001:db8::/32 as-set", + "set protocols bgp 65001 address-family ipv6-unicast aggregate-address 2001:db8::/32 summary-only", + ] + elapsed = _time_parse(Bgp_address_familyTemplate14, lines) + assert elapsed < PARSE_BUDGET_SECONDS, ( + "Bgp_address_familyTemplate14.parse() took %.2fs (budget %.2fs); " + "possible regression of T8609 (rm_templates regex backtracking)." + % (elapsed, PARSE_BUDGET_SECONDS) + ) + + +def test_route_maps_14_set_comm_list_delete_matches_setval(): + """Round-trip check: the `set_comm_list_delete` parser must match the line its setval generates. + + `set_comm_list_delete`'s setval emits `set policy route-map X rule N set + comm-list delete` with no token after `delete`. Pre-T8609 the getval + happened to match this by accident (a `*` quantifier on the trailing + `(?P\\S+)` made the group optional after VERBOSE-strip). An + earlier draft of T8609's fix made the group required, causing the + parser to silently ignore its own output. This test guards the + round-trip. + """ + line = "set policy route-map MY-MAP rule 10 set comm-list delete" + parser = Route_mapsTemplate14(lines=[line]) + result = parser.parse() + rm = result.get("route_maps", {}).get("MY-MAP") + assert rm is not None, ( + "route_maps_14: set_comm_list_delete parser failed to match its " + "own setval-generated line %r; the parser is broken." % line + ) + entry = rm.get("entries", {}).get(10, {}) + comm_list = entry.get("set", {}).get("comm_list", {}) + assert comm_list.get("delete"), ( + "route_maps_14: set_comm_list_delete matched the line but did not " + "populate set.comm_list.delete; check the result template." + ) diff --git a/tests/unit/modules/network/vyos/test_vyos_firewall_rules13.py b/tests/unit/modules/network/vyos/test_vyos_firewall_rules13.py index 1af61752..edce123b 100644 --- a/tests/unit/modules/network/vyos/test_vyos_firewall_rules13.py +++ b/tests/unit/modules/network/vyos/test_vyos_firewall_rules13.py @@ -1,1578 +1,1592 @@ # (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 . # Make coding more python3-ish from __future__ import absolute_import, division, print_function __metaclass__ = type from unittest.mock import patch from ansible_collections.vyos.vyos.plugins.modules import vyos_firewall_rules from ansible_collections.vyos.vyos.tests.unit.modules.utils import set_module_args from .vyos_module import TestVyosModule, load_fixture class TestVyosFirewallRulesModule13(TestVyosModule): module = vyos_firewall_rules def setUp(self): super(TestVyosFirewallRulesModule13, 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.static_routes.static_routes.Static_routesFacts.get_device_data", ) self.mock_execute_show_command = patch( "ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.facts.firewall_rules.firewall_rules.Firewall_rulesFacts.get_device_data", ) self.execute_show_command = self.mock_execute_show_command.start() self.mock_get_os_version = patch( "ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.config.firewall_rules.firewall_rules.get_os_version", ) self.get_os_version = self.mock_get_os_version.start() self.get_os_version.return_value = "1.2" def tearDown(self): super(TestVyosFirewallRulesModule13, 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() self.mock_get_os_version.stop() def load_fixtures(self, commands=None, filename=None): def load_from_file(*args, **kwargs): return load_fixture("vyos_firewall_rules_config.cfg") self.execute_show_command.side_effect = load_from_file def test_vyos_firewall_rule_set_01_merged(self): set_module_args( dict( config=[ dict( afi="ipv6", rule_sets=[ dict( name="V6-INBOUND", description="This is IPv6 INBOUND rule set", default_action="reject", enable_default_log=True, rules=[], ), dict( name="V6-OUTBOUND", description="This is IPv6 OUTBOUND rule set", default_action="accept", enable_default_log=False, rules=[], ), ], ), dict( afi="ipv4", rule_sets=[ dict( name="V4-INBOUND", description="This is IPv4 INBOUND rule set", default_action="reject", enable_default_log=True, rules=[], ), dict( name="V4-OUTBOUND", description="This is IPv4 OUTBOUND rule set", default_action="accept", enable_default_log=False, rules=[], ), ], ), ], state="merged", ), ) commands = [ "set firewall ipv6-name V6-INBOUND default-action 'reject'", "set firewall ipv6-name V6-INBOUND description 'This is IPv6 INBOUND rule set'", "set firewall ipv6-name V6-INBOUND enable-default-log", "set firewall ipv6-name V6-OUTBOUND default-action 'accept'", "set firewall ipv6-name V6-OUTBOUND description 'This is IPv6 OUTBOUND rule set'", "set firewall name V4-INBOUND default-action 'reject'", "set firewall name V4-INBOUND description 'This is IPv4 INBOUND rule set'", "set firewall name V4-INBOUND enable-default-log", "set firewall name V4-OUTBOUND default-action 'accept'", "set firewall name V4-OUTBOUND description 'This is IPv4 OUTBOUND rule set'", ] self.execute_module(changed=True, commands=commands) def test_vyos_firewall_v4_rule_sets_rule_merged_01(self): """Test if plugin correctly adds new rules set and a rule with variant attributes""" set_module_args( dict( config=[ dict( afi="ipv4", rule_sets=[ dict( name="INBOUND", description="This is IPv4 INBOUND rule set", default_action="accept", enable_default_log=True, rules=[ dict( number="101", action="accept", description="Rule 101 is configured by Ansible", ipsec="match-ipsec", log="disable", protocol="icmp", fragment="match-frag", disable=True, ), dict( number="105", action="offload", offload_target="test", description="Rule 105 is configured by Ansible", protocol="udp", ), ], ), ], ), ], state="merged", ), ) commands = [ "set firewall name INBOUND default-action 'accept'", "set firewall name INBOUND description 'This is IPv4 INBOUND rule set'", "set firewall name INBOUND enable-default-log", "set firewall name INBOUND rule 101 protocol 'icmp'", "set firewall name INBOUND rule 101 description 'Rule 101 is configured by Ansible'", "set firewall name INBOUND rule 101 fragment 'match-frag'", "set firewall name INBOUND rule 101", "set firewall name INBOUND rule 101 disable", "set firewall name INBOUND rule 101 action 'accept'", "set firewall name INBOUND rule 101 ipsec 'match-ipsec'", "set firewall name INBOUND rule 101 log 'disable'", "set firewall name INBOUND rule 105", "set firewall name INBOUND rule 105 action 'offload'", "set firewall name INBOUND rule 105 offload-target 'test'", "set firewall name INBOUND rule 105 description 'Rule 105 is configured by Ansible'", "set firewall name INBOUND rule 105 protocol 'udp'", ] self.execute_module(changed=True, commands=commands) def test_vyos_firewall_v4_rule_sets_rule_merged_02(self): """Test if plugin correctly adds new rules with variant attributes within existing rule set """ set_module_args( dict( config=[ dict( afi="ipv4", rule_sets=[ dict( name="INBOUND", rules=[ dict( number="101", protocol="tcp", source=dict( address="192.0.2.0", mac_address="38:00:25:19:76:0c", port=2127, ), destination=dict(address="192.0.1.0", port=2124), limit=dict( burst=10, rate=dict(number=20, unit="second"), ), recent=dict(count=10, time=20), state=dict( established=True, related=True, invalid=True, new=True, ), ), ], ), ], ), ], state="merged", ), ) commands = [ "set firewall name INBOUND rule 101 protocol 'tcp'", "set firewall name INBOUND rule 101 destination address 192.0.1.0", "set firewall name INBOUND rule 101 destination port 2124", "set firewall name INBOUND rule 101", "set firewall name INBOUND rule 101 source address 192.0.2.0", "set firewall name INBOUND rule 101 source mac-address 38:00:25:19:76:0c", "set firewall name INBOUND rule 101 source port 2127", "set firewall name INBOUND rule 101 state new enable", "set firewall name INBOUND rule 101 state invalid enable", "set firewall name INBOUND rule 101 state related enable", "set firewall name INBOUND rule 101 state established enable", "set firewall name INBOUND rule 101 limit burst 10", "set firewall name INBOUND rule 101 limit rate 20/second", "set firewall name INBOUND rule 101 recent count 10", "set firewall name INBOUND rule 101 recent time 20", ] self.execute_module(changed=True, commands=commands) def test_vyos_firewall_v4_rule_sets_rule_merged_03(self): """Test if plugin correctly adds new rules with variant attributes within existing rule set """ set_module_args( dict( config=[ dict( afi="ipv4", rule_sets=[ dict( name="INBOUND", rules=[ dict( number="101", destination=dict( group=dict( address_group="OUT-ADDR-GROUP", network_group="OUT-NET-GROUP", port_group="OUT-PORT-GROUP", ), ), source=dict( group=dict( address_group="IN-ADDR-GROUP", network_group="IN-NET-GROUP", port_group="IN-PORT-GROUP", ), ), ), ], ), ], ), ], state="merged", ), ) commands = [ "set firewall name INBOUND rule 101 source group address-group IN-ADDR-GROUP", "set firewall name INBOUND rule 101 source group network-group IN-NET-GROUP", "set firewall name INBOUND rule 101 source group port-group IN-PORT-GROUP", "set firewall name INBOUND rule 101 destination group address-group OUT-ADDR-GROUP", "set firewall name INBOUND rule 101 destination group network-group OUT-NET-GROUP", "set firewall name INBOUND rule 101 destination group port-group OUT-PORT-GROUP", "set firewall name INBOUND rule 101", ] self.execute_module(changed=True, commands=commands) def test_vyos_firewall_v4_rule_sets_rule_merged_04(self): """Test if plugin correctly adds new rules with variant attributes within existing rule set """ set_module_args( dict( config=[ dict( afi="ipv4", rule_sets=[ dict( name="INBOUND", rules=[ dict( number="101", time=dict( monthdays="2", startdate="2020-01-24", starttime="13:20:00", stopdate="2020-01-28", stoptime="13:30:00", weekdays="!Sat,Sun", utc=True, ), tcp=dict( flags=[ dict(flag="all"), ], ), ), ], ), ], ), ], state="merged", ), ) commands = [ "set firewall name INBOUND rule 101", "set firewall name INBOUND rule 101 tcp flags ALL", "set firewall name INBOUND rule 101 time utc", "set firewall name INBOUND rule 101 time monthdays 2", "set firewall name INBOUND rule 101 time startdate 2020-01-24", "set firewall name INBOUND rule 101 time stopdate 2020-01-28", "set firewall name INBOUND rule 101 time weekdays !Sat,Sun", "set firewall name INBOUND rule 101 time stoptime 13:30:00", "set firewall name INBOUND rule 101 time starttime 13:20:00", ] self.execute_module(changed=True, commands=commands) def test_vyos_firewall_v6_rule_sets_rule_merged_01(self): """Test if plugin correctly adds new ipv6 rules set and a rule with variant attributes""" set_module_args( dict( config=[ dict( afi="ipv6", rule_sets=[ dict( name="INBOUND", description="This is IPv6 INBOUND rule set", default_action="accept", enable_default_log=True, rules=[ dict( number="101", action="accept", description="Rule 101 is configured by Ansible", ipsec="match-ipsec", protocol="icmp", disable=True, icmp=dict(type_name="echo-request"), ), ], ), ], ), ], state="merged", ), ) commands = [ "set firewall ipv6-name INBOUND default-action 'accept'", "set firewall ipv6-name INBOUND description 'This is IPv6 INBOUND rule set'", "set firewall ipv6-name INBOUND enable-default-log", "set firewall ipv6-name INBOUND rule 101 protocol 'icmp'", "set firewall ipv6-name INBOUND rule 101 description 'Rule 101 is configured by Ansible'", "set firewall ipv6-name INBOUND rule 101", "set firewall ipv6-name INBOUND rule 101 disable", "set firewall ipv6-name INBOUND rule 101 action 'accept'", "set firewall ipv6-name INBOUND rule 101 ipsec 'match-ipsec'", "set firewall ipv6-name INBOUND rule 101 icmpv6 type echo-request", ] self.execute_module(changed=True, commands=commands) def test_vyos_firewall_v6_rule_sets_rule_merged_02(self): """Test if plugin correctly adds new rules with variant attributes within existing ipv6 rule set """ set_module_args( dict( config=[ dict( afi="ipv6", rule_sets=[ dict( name="INBOUND", rules=[ dict( number="101", protocol="tcp", source=dict( address="2001:db8::12", mac_address="38:00:25:19:76:0c", port=2127, ), destination=dict(address="2001:db8::11", port=2124), limit=dict( burst=10, rate=dict(number=20, unit="second"), ), recent=dict(count=10, time=20), state=dict( established=True, related=True, invalid=True, new=True, ), ), ], ), ], ), ], state="merged", ), ) commands = [ "set firewall ipv6-name INBOUND rule 101 protocol 'tcp'", "set firewall ipv6-name INBOUND rule 101 destination address 2001:db8::11", "set firewall ipv6-name INBOUND rule 101 destination port 2124", "set firewall ipv6-name INBOUND rule 101", "set firewall ipv6-name INBOUND rule 101 source address 2001:db8::12", "set firewall ipv6-name INBOUND rule 101 source mac-address 38:00:25:19:76:0c", "set firewall ipv6-name INBOUND rule 101 source port 2127", "set firewall ipv6-name INBOUND rule 101 state new enable", "set firewall ipv6-name INBOUND rule 101 state invalid enable", "set firewall ipv6-name INBOUND rule 101 state related enable", "set firewall ipv6-name INBOUND rule 101 state established enable", "set firewall ipv6-name INBOUND rule 101 limit burst 10", "set firewall ipv6-name INBOUND rule 101 recent count 10", "set firewall ipv6-name INBOUND rule 101 recent time 20", "set firewall ipv6-name INBOUND rule 101 limit rate 20/second", ] self.execute_module(changed=True, commands=commands) def test_vyos_firewall_v6_rule_sets_rule_merged_03(self): """Test if plugin correctly adds new rules with variant attributes within existing ipv6 rule set """ set_module_args( dict( config=[ dict( afi="ipv6", rule_sets=[ dict( name="INBOUND", rules=[ dict( number="101", destination=dict( group=dict( address_group="OUT-ADDR-GROUP", network_group="OUT-NET-GROUP", port_group="OUT-PORT-GROUP", ), ), source=dict( group=dict( address_group="IN-ADDR-GROUP", network_group="IN-NET-GROUP", port_group="IN-PORT-GROUP", ), ), ), ], ), ], ), ], state="merged", ), ) commands = [ "set firewall ipv6-name INBOUND rule 101 source group address-group IN-ADDR-GROUP", "set firewall ipv6-name INBOUND rule 101 source group network-group IN-NET-GROUP", "set firewall ipv6-name INBOUND rule 101 source group port-group IN-PORT-GROUP", "set firewall ipv6-name INBOUND rule 101 destination group address-group OUT-ADDR-GROUP", "set firewall ipv6-name INBOUND rule 101 destination group network-group OUT-NET-GROUP", "set firewall ipv6-name INBOUND rule 101 destination group port-group OUT-PORT-GROUP", "set firewall ipv6-name INBOUND rule 101", ] self.execute_module(changed=True, commands=commands) def test_vyos_firewall_v6_rule_sets_rule_merged_04(self): """Test if plugin correctly adds new rules with variant attributes within existing ipv6 rule set """ set_module_args( dict( config=[ dict( afi="ipv6", rule_sets=[ dict( name="INBOUND", rules=[ dict( number="101", time=dict( monthdays="2", startdate="2020-01-24", starttime="13:20:00", stopdate="2020-01-28", stoptime="13:30:00", weekdays="!Sat,Sun", utc=True, ), tcp=dict( flags=[ dict(flag="all"), ], ), ), dict( number="102", tcp=dict( flags=[ dict(flag="ack"), dict(flag="syn"), dict(flag="fin", invert=True), ], ), ), ], ), ], ), ], state="merged", ), ) commands = [ "set firewall ipv6-name INBOUND rule 101", "set firewall ipv6-name INBOUND rule 101 tcp flags ALL", "set firewall ipv6-name INBOUND rule 101 time utc", "set firewall ipv6-name INBOUND rule 101 time monthdays 2", "set firewall ipv6-name INBOUND rule 101 time startdate 2020-01-24", "set firewall ipv6-name INBOUND rule 101 time stopdate 2020-01-28", "set firewall ipv6-name INBOUND rule 101 time weekdays !Sat,Sun", "set firewall ipv6-name INBOUND rule 101 time stoptime 13:30:00", "set firewall ipv6-name INBOUND rule 101 time starttime 13:20:00", "set firewall ipv6-name INBOUND rule 102", "set firewall ipv6-name INBOUND rule 102 tcp flags ACK,SYN,!FIN", ] self.execute_module(changed=True, commands=commands) def test_vyos_firewall_v6_rule_sets_rule_merged_icmp_01(self): """Test if plugin correctly adds new rules with variant attributes within existing ipv6 rule set """ set_module_args( dict( config=[ dict( afi="ipv6", rule_sets=[ dict( name="INBOUND", rules=[ dict( number="101", protocol="icmp", icmp=dict(type_name="port-unreachable"), ), ], ), ], ), ], state="merged", ), ) commands = [ "set firewall ipv6-name INBOUND rule 101 icmpv6 type port-unreachable", "set firewall ipv6-name INBOUND rule 101 protocol 'icmp'", "set firewall ipv6-name INBOUND rule 101", ] self.execute_module(changed=True, commands=commands) def test_vyos_firewall_v4_rule_sets_rule_merged_icmp_01(self): """Test if plugin correctly adds new rules with variant attributes within existing rule set """ set_module_args( dict( config=[ dict( afi="ipv4", rule_sets=[ dict( name="INBOUND", rules=[ dict( number="101", protocol="icmp", icmp=dict(type=1, code=1), ), ], ), ], ), ], state="merged", ), ) commands = [ "set firewall name INBOUND rule 101 icmp type 1", "set firewall name INBOUND rule 101 icmp code 1", "set firewall name INBOUND rule 101 protocol 'icmp'", "set firewall name INBOUND rule 101", ] self.execute_module(changed=True, commands=commands) def test_vyos_firewall_v4_rule_sets_rule_merged_icmp_02(self): """Test if plugin correctly adds new rules with variant attributes within existing rule set """ set_module_args( dict( config=[ dict( afi="ipv4", rule_sets=[ dict( name="INBOUND", rules=[ dict( number="101", protocol="icmp", icmp=dict(type_name="echo-request"), ), ], ), ], ), ], state="merged", ), ) commands = [ "set firewall name INBOUND rule 101 icmp type-name echo-request", "set firewall name INBOUND rule 101 protocol 'icmp'", "set firewall name INBOUND rule 101", ] self.execute_module(changed=True, commands=commands) def test_vyos_firewall_v4_rule_sets_del_01(self): """Test if plugin correctly removes existing rule set""" set_module_args( dict( config=[dict(afi="ipv4", rule_sets=[dict(name="V4-INGRESS")])], state="deleted", ), ) commands = ["delete firewall name V4-INGRESS"] self.execute_module(changed=True, commands=commands) def test_vyos_firewall_v4v6_rule_sets_del_02(self): """Test if plugin correctly removes existing rule sets, both ipv4 and ipv6""" set_module_args( dict( config=[ dict(afi="ipv4", rule_sets=[dict(name="V4-INGRESS")]), dict(afi="ipv6", rule_sets=[dict(name="V6-INGRESS")]), dict(afi="ipv4", rule_sets=[dict(name="V4-OFFLOAD")]), ], state="deleted", ), ) commands = [ "delete firewall name V4-OFFLOAD", "delete firewall name V4-INGRESS", "delete firewall ipv6-name V6-INGRESS", ] self.execute_module(changed=True, commands=commands) def test_vyos_firewall_v4v6_rule_sets_del_03(self): """Test if plugin correctly removes existing AFIs, both ipv4 and ipv6""" set_module_args(dict(config=[], state="deleted")) commands = ["delete firewall name", "delete firewall ipv6-name"] self.execute_module(changed=True, commands=commands) def test_vyos_firewall_v4v6_rule_sets_del_04(self): """Test if plugin has no effect on non-existent rule sets""" set_module_args( dict( config=[ dict(afi="ipv4", rule_sets=[dict(name="V4-ING")]), dict(afi="ipv6", rule_sets=[dict(name="V6-ING")]), ], state="deleted", ), ) self.execute_module(changed=False, commands=[]) def test_vyos_firewall_v4v6_rule_sets_rule_rep_01(self): """Test if plugin correctly replaces a particular rule set(s) without affecting the others """ set_module_args( dict( config=[ dict( afi="ipv4", rule_sets=[ dict( name="V4-INGRESS", description="This is IPv4 INGRESS rule set", default_action="accept", enable_default_log=True, rules=[ dict( number="101", action="reject", description="Rule 101 is configured by Ansible RM", ipsec="match-ipsec", protocol="tcp", fragment="match-frag", disable=False, ), dict( number="102", action="accept", description="Rule 102 is configured by Ansible RM", protocol="icmp", disable=True, ), ], ), ], ), dict( afi="ipv6", rule_sets=[ dict( name="V6-INGRESS", default_action="accept", description="This rule-set is configured by Ansible RM", ), dict( name="EGRESS", default_action="reject", description="This rule-set is configured by Ansible RM", rules=[ dict( icmp=dict(type_name="echo-request"), number=20, ), ], ), ], ), ], state="replaced", ), ) commands = [ "delete firewall name V4-INGRESS rule 101", "set firewall name V4-INGRESS rule 101", "set firewall name V4-INGRESS description 'This is IPv4 INGRESS rule set'", "set firewall name V4-INGRESS rule 101 fragment 'match-frag'", "set firewall name V4-INGRESS rule 101 ipsec 'match-ipsec'", "set firewall name V4-INGRESS rule 101 protocol 'tcp'", "set firewall name V4-INGRESS rule 101 description 'Rule 101 is configured by Ansible RM'", "set firewall name V4-INGRESS rule 101 action 'reject'", "set firewall name V4-INGRESS rule 102 disable", "set firewall name V4-INGRESS rule 102 action 'accept'", "set firewall name V4-INGRESS rule 102 protocol 'icmp'", "set firewall name V4-INGRESS rule 102 description 'Rule 102 is configured by Ansible RM'", "set firewall name V4-INGRESS rule 102", "set firewall ipv6-name V6-INGRESS description 'This rule-set is configured by Ansible RM'", "set firewall ipv6-name EGRESS description 'This rule-set is configured by Ansible RM'", ] self.execute_module(changed=True, commands=commands) def test_vyos_firewall_v4v6_rule_sets_rule_rep_02(self): """Test if plugin correctly replaces a particular rule(s) and rule set attribute(s) without affecting the others """ set_module_args( dict( config=[ dict( afi="ipv4", rule_sets=[ dict( name="V4-INGRESS", description="This is IPv4 V4-INGRESS rule set", default_action="accept", enable_default_log=False, rules=[ dict( number="101", action="accept", description="Rule 101 is configured by Ansible", ipsec="match-ipsec", protocol="icmp", fragment="match-frag", disable=True, ), ], ), ], ), dict( afi="ipv6", rule_sets=[ dict( name="V6-INGRESS", default_action="accept", ), dict( name="EGRESS", default_action="reject", rules=[ dict( icmp=dict(type_name="echo-request"), number=20, ), ], ), ], ), ], state="replaced", ), ) commands = [ "delete firewall name V4-INGRESS rule 101", "delete firewall name V4-INGRESS enable-default-log", "set firewall name V4-INGRESS rule 101", "set firewall name V4-INGRESS rule 101 action 'accept'", "set firewall name V4-INGRESS rule 101 description 'Rule 101 is configured by Ansible'", "set firewall name V4-INGRESS rule 101 disable", "set firewall name V4-INGRESS rule 101 fragment 'match-frag'", "set firewall name V4-INGRESS rule 101 ipsec 'match-ipsec'", "set firewall name V4-INGRESS rule 101 protocol 'icmp'", ] self.execute_module(changed=True, commands=commands) def test_vyos_firewall_v4v6_rule_sets_rule_rep_idem_01(self): """Test if plugin correctly has no effect if there is no change in the configuration""" set_module_args( dict( config=[ dict( afi="ipv4", rule_sets=[ dict( name="V4-INGRESS", description="This is IPv4 V4-INGRESS rule set", default_action="accept", enable_default_log=True, rules=[ dict( number="101", action="accept", description="Rule 101 is configured by Ansible", ipsec="match-ipsec", protocol="icmp", fragment="match-frag", disable=True, log="enable", ), ], ), dict( name="EGRESS", default_action="reject", ), ], ), dict( afi="ipv6", rule_sets=[ dict( name="V6-INGRESS", default_action="accept", ), dict( name="EGRESS", default_action="reject", rules=[ dict( icmp=dict(type_name="echo-request"), number=20, ), ], ), ], ), ], state="replaced", ), ) self.execute_module(changed=False, commands=[]) def test_vyos_firewall_v4v6_rule_sets_rule_rep_idem_02(self): """Test if plugin correctly has no effect if there is no change in the configuration""" set_module_args( dict( config=[ dict( afi="ipv4", rule_sets=[ dict( name="V4-INGRESS", description="This is IPv4 V4-INGRESS rule set", default_action="accept", enable_default_log=True, rules=[ dict( number="101", action="accept", description="Rule 101 is configured by Ansible", ipsec="match-ipsec", protocol="icmp", fragment="match-frag", disable=True, log="enable", ), ], ), ], ), ], state="replaced", ), ) self.execute_module(changed=False, commands=[]) def test_vyos_firewall_v4v6_rule_sets_rule_rep_idem_03(self): """Test if plugin correctly has no effect if there is no change in the configuration""" set_module_args( dict( config=[ dict( afi="ipv4", rule_sets=[ dict( name="V4-OFFLOAD", rules=[ dict( number="1", action="offload", offload_target="test", ), ], ), ], ), ], state="replaced", ), ) self.execute_module(changed=False, commands=[]) def test_vyos_firewall_v4v6_rule_sets_rule_mer_idem_01(self): """Test if plugin correctly has no effect if there is no change in the configuration""" set_module_args( dict( config=[ dict( afi="ipv4", rule_sets=[ dict( name="V4-INGRESS", description="This is IPv4 V4-INGRESS rule set", default_action="accept", enable_default_log=True, rules=[ dict( number="101", action="accept", description="Rule 101 is configured by Ansible", ipsec="match-ipsec", protocol="icmp", fragment="match-frag", disable=True, ), ], ), dict( name="EGRESS", default_action="reject", ), ], ), dict( afi="ipv6", rule_sets=[ dict( name="V6-INGRESS", default_action="accept", ), dict( name="EGRESS", default_action="reject", rules=[ dict( icmp=dict(type_name="echo-request"), number=20, ), ], ), ], ), ], state="merged", ), ) self.execute_module(changed=False, commands=[]) def test_vyos_firewall_v4v6_rule_sets_rule_mer_idem_02(self): """Test if plugin correctly has no effect if there is no change in the configuration""" set_module_args( dict( config=[ dict( afi="ipv4", rule_sets=[ dict( name="V4-INGRESS", description="This is IPv4 V4-INGRESS rule set", default_action="accept", enable_default_log=True, rules=[ dict( number="101", action="accept", description="Rule 101 is configured by Ansible", ipsec="match-ipsec", protocol="icmp", fragment="match-frag", disable=True, ), ], ), dict( name="EGRESS", default_action="reject", ), dict( name="V4-OFFLOAD", rules=[ dict( number="1", action="offload", offload_target="test", ), ], ), ], ), dict( afi="ipv6", rule_sets=[ dict( name="V6-INGRESS", default_action="accept", ), dict( name="EGRESS", default_action="reject", rules=[ dict( icmp=dict(type_name="echo-request"), number=20, ), ], ), ], ), ], state="merged", ), ) self.execute_module(changed=False, commands=[]) def test_vyos_firewall_v4v6_rule_sets_rule_ovr_01(self): """Test if plugin correctly resets the entire rule set if there is a change in the configuration""" set_module_args( dict( config=[ dict( afi="ipv4", rule_sets=[ dict( name="V4-IN", description="This is IPv4 INGRESS rule set", default_action="accept", enable_default_log=True, rules=[ dict( number="1", action="reject", description="Rule 1 is configured by Ansible RM", ipsec="match-ipsec", log="enable", protocol="tcp", fragment="match-frag", disable=False, source=dict( group=dict( address_group="IN-ADDR-GROUP", network_group="IN-NET-GROUP", port_group="IN-PORT-GROUP", ), ), ), dict( number="2", action="accept", description="Rule 102 is configured by Ansible RM", protocol="icmp", disable=True, ), ], ), dict( name="MULTIPLE-RULE", default_action="drop", rules=[ dict( number="1", action="accept", protocol="all", ), ], ), ], ), dict( afi="ipv6", rule_sets=[ dict( name="V6-IN", default_action="accept", description="This rule-set is configured by Ansible RM", ), dict( name="V6-EG", default_action="reject", description="This rule-set is configured by Ansible RM", ), ], ), ], state="overridden", ), ) commands = [ "delete firewall ipv6-name V6-INGRESS", "delete firewall ipv6-name EGRESS", "delete firewall name V4-INGRESS", "delete firewall name EGRESS", "delete firewall name MULTIPLE-RULE", "delete firewall name V4-OFFLOAD", "set firewall name MULTIPLE-RULE default-action 'drop'", "set firewall name MULTIPLE-RULE rule 1", "set firewall name MULTIPLE-RULE rule 1 action 'accept'", "set firewall name MULTIPLE-RULE rule 1 protocol 'all'", "set firewall name V4-IN default-action 'accept'", "set firewall name V4-IN description 'This is IPv4 INGRESS rule set'", "set firewall name V4-IN enable-default-log", "set firewall name V4-IN rule 1 protocol 'tcp'", "set firewall name V4-IN rule 1 log 'enable'", "set firewall name V4-IN rule 1 description 'Rule 1 is configured by Ansible RM'", "set firewall name V4-IN rule 1 fragment 'match-frag'", "set firewall name V4-IN rule 1 source group address-group IN-ADDR-GROUP", "set firewall name V4-IN rule 1 source group network-group IN-NET-GROUP", "set firewall name V4-IN rule 1 source group port-group IN-PORT-GROUP", "set firewall name V4-IN rule 1", "set firewall name V4-IN rule 1 action 'reject'", "set firewall name V4-IN rule 1 ipsec 'match-ipsec'", "set firewall name V4-IN rule 2 disable", "set firewall name V4-IN rule 2 action 'accept'", "set firewall name V4-IN rule 2 protocol 'icmp'", "set firewall name V4-IN rule 2 description 'Rule 102 is configured by Ansible RM'", "set firewall name V4-IN rule 2", "set firewall ipv6-name V6-IN default-action 'accept'", "set firewall ipv6-name V6-IN description 'This rule-set is configured by Ansible RM'", "set firewall ipv6-name V6-EG default-action 'reject'", "set firewall ipv6-name V6-EG description 'This rule-set is configured by Ansible RM'", ] self.execute_module(changed=True, commands=commands) def test_vyos_firewall_v4v6_rule_sets_rule_ovr_02(self): """Test if plugin correctly resets the entire rule set while removing the absent ones if there is a change in the configuration """ set_module_args( dict( config=[ dict( afi="ipv4", rule_sets=[ dict( name="V4-INGRESS", description="This is IPv4 INGRESS rule set", default_action="accept", enable_default_log=True, rules=[ dict( number="101", action="accept", protocol="udp", ), ], ), ], ), dict( afi="ipv6", rule_sets=[ dict( name="EGRESS", default_action="reject", description="This rule-set is configured by Ansible RM", rules=[ dict( number="20", action="accept", protocol="udp", ), ], ), ], ), ], state="overridden", ), ) commands = [ "delete firewall ipv6-name V6-INGRESS", "delete firewall ipv6-name EGRESS", "delete firewall name V4-INGRESS", "delete firewall name EGRESS", "delete firewall name MULTIPLE-RULE", "delete firewall name V4-OFFLOAD", "set firewall name V4-INGRESS rule 101", "set firewall name V4-INGRESS description 'This is IPv4 INGRESS rule set'", "set firewall name V4-INGRESS default-action 'accept'", "set firewall name V4-INGRESS enable-default-log", "set firewall name V4-INGRESS rule 101 protocol 'udp'", "set firewall name V4-INGRESS rule 101 action 'accept'", "set firewall ipv6-name EGRESS description 'This rule-set is configured by Ansible RM'", "set firewall ipv6-name EGRESS default-action 'reject'", "set firewall ipv6-name EGRESS rule 20", "set firewall ipv6-name EGRESS rule 20 protocol 'udp'", "set firewall ipv6-name EGRESS rule 20 action 'accept'", ] self.execute_module(changed=True, commands=commands) def test_vyos_firewall_v4v6_rule_sets_rule_ovr_idem_01(self): """Test if plugin correctly has no effect if there is no change in the configuration""" set_module_args( dict( config=[ dict( afi="ipv4", rule_sets=[ dict( name="V4-INGRESS", description="This is IPv4 V4-INGRESS rule set", default_action="accept", enable_default_log=True, rules=[ dict( number="101", action="accept", description="Rule 101 is configured by Ansible", ipsec="match-ipsec", protocol="icmp", fragment="match-frag", disable=True, log="enable", ), ], ), dict( name="EGRESS", default_action="reject", ), dict( name="MULTIPLE-RULE", default_action="drop", rules=[ dict( number="1", action="accept", protocol="all", ), dict( number="2", action="drop", protocol="all", ), ], ), dict( name="V4-OFFLOAD", rules=[ dict( number="1", action="offload", offload_target="test", ), ], ), ], ), dict( afi="ipv6", rule_sets=[ dict( name="V6-INGRESS", default_action="accept", ), dict( name="EGRESS", default_action="reject", rules=[ dict( icmp=dict(type_name="echo-request"), number=20, ), ], ), ], ), ], state="overridden", ), ) self.execute_module(changed=False, commands=[]) def test_vyos_firewall_v6_rule_sets_rule_merged_01_version(self): """Test if plugin correctly adds ipv6 rule set with rules""" self.get_os_version.return_value = "1.3" set_module_args( dict( config=[ dict( afi="ipv6", rule_sets=[ dict( name="INBOUND", description="This is IPv6 INBOUND rule set", default_action="accept", enable_default_log=True, rules=[ dict( number="101", action="accept", description="Rule 101 is configured by Ansible", ipsec="match-ipsec", protocol="icmp", disable=True, icmp=dict(type_name="echo-request"), log="enable", ), dict( number="102", action="reject", description="Rule 102 is configured by Ansible", protocol="ipv6-icmp", icmp=dict(type=7), ), ], ), ], ), ], state="merged", ), ) commands = [ "set firewall ipv6-name INBOUND default-action 'accept'", "set firewall ipv6-name INBOUND description 'This is IPv6 INBOUND rule set'", "set firewall ipv6-name INBOUND enable-default-log", "set firewall ipv6-name INBOUND rule 101 protocol 'icmp'", "set firewall ipv6-name INBOUND rule 101 description 'Rule 101 is configured by Ansible'", "set firewall ipv6-name INBOUND rule 101", "set firewall ipv6-name INBOUND rule 101 disable", "set firewall ipv6-name INBOUND rule 101 action 'accept'", "set firewall ipv6-name INBOUND rule 101 ipsec 'match-ipsec'", "set firewall ipv6-name INBOUND rule 101 icmpv6 type echo-request", "set firewall ipv6-name INBOUND rule 101 log 'enable'", "set firewall ipv6-name INBOUND rule 102", "set firewall ipv6-name INBOUND rule 102 action 'reject'", "set firewall ipv6-name INBOUND rule 102 description 'Rule 102 is configured by Ansible'", "set firewall ipv6-name INBOUND rule 102 protocol 'ipv6-icmp'", "set firewall ipv6-name INBOUND rule 102 icmpv6 type 7", ] self.execute_module(changed=True, commands=commands) def test_vyos_firewall_jump_rules_merged_01(self): """Test if plugin correctly adds rule set with a jump action""" set_module_args( dict( config=[ dict( afi="ipv6", rule_sets=[ dict( name="INBOUND", description="This is IPv6 INBOUND rule set with a jump action", default_action="accept", enable_default_log=True, rules=[ dict( number="101", action="jump", description="Rule 101 is configured by Ansible", ipsec="match-ipsec", protocol="icmp", icmp=dict(type_name="echo-request"), jump_target="PROTECT-RE", packet_length_exclude=[dict(length=100), dict(length=200)], ), dict( number="102", action="reject", description="Rule 102 is configured by Ansible", protocol="ipv6-icmp", icmp=dict(type=7), ), ], ), ], ), ], state="merged", ), ) commands = [ "set firewall ipv6-name INBOUND default-action 'accept'", "set firewall ipv6-name INBOUND description 'This is IPv6 INBOUND rule set with a jump action'", "set firewall ipv6-name INBOUND enable-default-log", "set firewall ipv6-name INBOUND rule 101 protocol 'icmp'", "set firewall ipv6-name INBOUND rule 101 packet-length-exclude 100", "set firewall ipv6-name INBOUND rule 101 packet-length-exclude 200", "set firewall ipv6-name INBOUND rule 101 description 'Rule 101 is configured by Ansible'", "set firewall ipv6-name INBOUND rule 101", "set firewall ipv6-name INBOUND rule 101 ipsec 'match-ipsec'", "set firewall ipv6-name INBOUND rule 101 icmpv6 type echo-request", "set firewall ipv6-name INBOUND rule 101 action 'jump'", "set firewall ipv6-name INBOUND rule 101 jump-target 'PROTECT-RE'", "set firewall ipv6-name INBOUND rule 102", "set firewall ipv6-name INBOUND rule 102 action 'reject'", "set firewall ipv6-name INBOUND rule 102 description 'Rule 102 is configured by Ansible'", "set firewall ipv6-name INBOUND rule 102 protocol 'ipv6-icmp'", "set firewall ipv6-name INBOUND rule 102 icmpv6 type 7", ] self.execute_module(changed=True, commands=commands) def test_vyos_firewall_log_merged_01(self): """Test if new stanza log is correctly applied""" set_module_args( dict( config=[ dict( afi="ipv6", rule_sets=[ dict( name="INBOUND", description="This is IPv6 INBOUND rule set with a log", default_action="accept", enable_default_log=True, rules=[ dict( number="101", action="accept", description="Rule 101 is configured by Ansible", log="enable", ), ], ), ], ), ], state="merged", ), ) commands = [ "set firewall ipv6-name INBOUND default-action 'accept'", "set firewall ipv6-name INBOUND description 'This is IPv6 INBOUND rule set with a log'", "set firewall ipv6-name INBOUND enable-default-log", "set firewall ipv6-name INBOUND rule 101 log 'enable'", "set firewall ipv6-name INBOUND rule 101 description 'Rule 101 is configured by Ansible'", "set firewall ipv6-name INBOUND rule 101", "set firewall ipv6-name INBOUND rule 101 action 'accept'", ] self.maxDiff = None self.execute_module(changed=True, commands=commands) def test_vyos_firewall_log_replace_01(self): """Test that stanza is correctly replaced without touching the other stanzas """ set_module_args( dict( config=[ dict( afi="ipv4", rule_sets=[ dict( name="V4-INGRESS", description="This is IPv4 V4-INGRESS rule set", default_action="accept", enable_default_log=True, rules=[ dict( number="101", action="accept", description="Rule 101 is configured by Ansible", packet_length_exclude=[dict(length=100), dict(length=200)], packet_length=[dict(length=22)], log="enable", ), ], ), ], ), ], state="replaced", ), ) commands = [ "delete firewall name V4-INGRESS rule 101", "set firewall name V4-INGRESS rule 101", "set firewall name V4-INGRESS rule 101 action 'accept'", "set firewall name V4-INGRESS rule 101 description 'Rule 101 is configured by Ansible'", "set firewall name V4-INGRESS rule 101 packet-length-exclude 100", "set firewall name V4-INGRESS rule 101 packet-length-exclude 200", "set firewall name V4-INGRESS rule 101 packet-length 22", "set firewall name V4-INGRESS rule 101 log 'enable'", ] self.maxDiff = None self.execute_module(changed=True, commands=commands) + + def test_vyos_firewall_rules_parsed_icmp_type_code(self): + """parse_icmp_attr: legacy 'type/code' token parses into integer type and code.""" + raw = ( + "set firewall name TEST rule 1 action 'accept'\n" + "set firewall name TEST rule 1 protocol 'icmp'\n" + "set firewall name TEST rule 1 icmp type '3/4'\n" + ) + set_module_args(dict(running_config=raw, state="parsed")) + result = self.execute_module(changed=False) + parsed = result["parsed"] + rule = parsed[0]["rule_sets"][0]["rules"][0] + self.assertEqual(rule["icmp"]["type"], 3) + self.assertEqual(rule["icmp"]["code"], 4) diff --git a/tests/unit/modules/network/vyos/test_vyos_user.py b/tests/unit/modules/network/vyos/test_vyos_user.py index d1e7f162..2cbd3820 100644 --- a/tests/unit/modules/network/vyos/test_vyos_user.py +++ b/tests/unit/modules/network/vyos/test_vyos_user.py @@ -1,279 +1,309 @@ # (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 . # Make coding more python3-ish from __future__ import absolute_import, division, print_function __metaclass__ = type from unittest.mock import patch from ansible_collections.vyos.vyos.plugins.modules import vyos_user from ansible_collections.vyos.vyos.tests.unit.modules.utils import set_module_args from .vyos_module import TestVyosModule, load_fixture class TestVyosUserModule(TestVyosModule): module = vyos_user def setUp(self): super(TestVyosUserModule, self).setUp() self.mock_get_config = patch( "ansible_collections.vyos.vyos.plugins.modules.vyos_user.get_config", ) self.get_config = self.mock_get_config.start() self.mock_load_config = patch( "ansible_collections.vyos.vyos.plugins.modules.vyos_user.load_config", ) self.load_config = self.mock_load_config.start() def tearDown(self): super(TestVyosUserModule, self).tearDown() self.mock_get_config.stop() self.mock_load_config.stop() def load_fixtures(self, commands=None, filename=None): self.get_config.return_value = load_fixture("vyos_user_config.cfg") self.load_config.return_value = dict(diff=None, session="session") def test_vyos_user_password(self): set_module_args(dict(name="ansible", configured_password="test")) result = self.execute_module(changed=True) self.assertEqual( result["commands"], ["set system login user ansible authentication plaintext-password test"], ) + def test_vyos_user_password_special_chars(self): + set_module_args(dict(name="ansible", configured_password="test$123!@")) + result = self.execute_module(changed=True) + self.assertEqual( + result["commands"], + [ + "set system login user ansible authentication plaintext-password 'test$123!@'", + ], + ) + + def test_vyos_user_password_embedded_quote(self): + set_module_args(dict(name="ansible", configured_password="pa'ss")) + result = self.execute_module(changed=True) + self.assertEqual( + result["commands"], + [ + "set system login user ansible authentication plaintext-password 'pa'\"'\"'ss'", + ], + ) + + def test_vyos_user_password_complex_special_chars(self): + set_module_args(dict(name="ansible", configured_password="P@ss w0rd!$#'xy\\")) + result = self.execute_module(changed=True) + self.assertEqual( + result["commands"], + [ + "set system login user ansible authentication plaintext-password 'P@ss w0rd!$#'\"'\"'xy\\'", + ], + ) + def test_vyos_user_delete(self): set_module_args(dict(name="ansible", state="absent")) result = self.execute_module(changed=True) self.assertEqual(result["commands"], ["delete system login user ansible"]) def test_vyos_user_purge(self): set_module_args(dict(purge=True)) result = self.execute_module(changed=True) self.assertEqual( sorted(result["commands"]), sorted( [ "delete system login user ansible", "delete system login user admin", "delete system login user ssh", ], ), ) def test_vyos_user_update_password_changed(self): set_module_args( dict( name="test", configured_password="test", update_password="on_create", ), ) result = self.execute_module(changed=True) self.assertEqual( result["commands"], ["set system login user test authentication plaintext-password test"], ) def test_vyos_user_update_password_on_create_ok(self): set_module_args( dict( name="ansible", configured_password="test", update_password="on_create", ), ) self.execute_module() def test_vyos_user_update_password_always(self): set_module_args( dict( name="ansible", configured_password="test", update_password="always", ), ) result = self.execute_module(changed=True) self.assertEqual( result["commands"], ["set system login user ansible authentication plaintext-password test"], ) def test_vyos_user_set_ssh_key(self): set_module_args( dict( name="ansible", public_keys=[ dict( name="user@host", key="AAAAC3NzaC1lZDI1NTE5AAAAIFIR0jrMvBdmvTJNY5EDhOD+eixvbOinhY1eBU2uyuhu", type="ssh-ed25519", ), ], ), ) result = self.execute_module(changed=True) self.assertEqual( result["commands"], [ "set system login user ansible authentication public-keys user@host key 'AAAAC3NzaC1lZDI1NTE5AAAAIFIR0jrMvBdmvTJNY5EDhOD+eixvbOinhY1eBU2uyuhu'", "set system login user ansible authentication public-keys user@host type 'ssh-ed25519'", ], ) def test_vyos_user_set_ssh_key_idempotent(self): set_module_args( dict( name="ssh", public_keys=[ dict( name="user@host", key="AAAAB3NzaC1yc2EAAAADAQABAAABAQD", type="ssh-rsa", ), ], ), ) self.load_fixtures() result = self.execute_module(changed=False) self.assertEqual(result["commands"], []) def test_vyos_user_set_ssh_key_change(self): set_module_args( dict( name="ssh", public_keys=[ dict( name="user@host", key="AAAAC3NzaC1lZDI1NTE5AAAAIFIR0jrMvBdmvTJNY5EDhOD+eixvbOinhY1eBU2uyuhu", type="ssh-ed25519", ), ], ), ) self.load_fixtures() result = self.execute_module( changed=True, commands=[ "set system login user ssh authentication public-keys user@host key 'AAAAC3NzaC1lZDI1NTE5AAAAIFIR0jrMvBdmvTJNY5EDhOD+eixvbOinhY1eBU2uyuhu'", "set system login user ssh authentication public-keys user@host type 'ssh-ed25519'", ], ) def test_vyos_user_set_ssh_key_add_and_remove(self): set_module_args( dict( name="ssh", public_keys=[ dict( name="noone@nowhere", key="AAAAC3NzaC1lZDI1NTE5AAAAIFIR0jrMvBdmvTJNY5EDhOD+eixvbOinhY1eBU2uyuhu", type="ssh-ed25519", ), ], ), ) self.load_fixtures() result = self.execute_module( changed=True, commands=[ "delete system login user ssh authentication public-keys user@host", "set system login user ssh authentication public-keys noone@nowhere key 'AAAAC3NzaC1lZDI1NTE5AAAAIFIR0jrMvBdmvTJNY5EDhOD+eixvbOinhY1eBU2uyuhu'", "set system login user ssh authentication public-keys noone@nowhere type 'ssh-ed25519'", ], ) def test_vyos_user_set_ssh_key_empty(self): # empty public_keys has no effect (for setting passwords, user names, etc.) set_module_args( dict( name="ssh", public_keys=[], ), ) self.load_fixtures() result = self.execute_module(changed=False) def test_vyos_user_set_encrypted_password(self): set_module_args( dict( name="ansible", encrypted_password="$6$rounds=656000$SALT$HASH", ), ) result = self.execute_module(changed=True) self.assertEqual( result["commands"], [ "set system login user ansible authentication encrypted-password '$6$rounds=656000$SALT$HASH'", ], ) def test_vyos_user_set_encrypted_password_idem(self): set_module_args( dict( name="ansible", encrypted_password="$6$ZfvSv6A50W6yNPYX$4HP5eg2sywcXYxTqhApQ7zvUvx0HsQHrI9xuJoFLy2gM/", ), ) result = self.execute_module(changed=False) def test_vyos_user_aggregate_with_public_keys(self): set_module_args( dict( aggregate=[ dict( name="user1", public_keys=[ dict( name="user1@host1", key="AAAAC3NzaC1lZDI1NTE5AAAAIFIR0jrMvBdmvTJNY5EDhOD+eixvbOinhY1eBU2u", type="ssh-ed25519", ), ], ), dict( name="user2", public_keys=[ dict( name="user2@host2", key="AAAAC3NzaC1lZDI1NTE5AAAAIFIR0jrMvBdmvTJNY5EDhOD+eixvbOinhY1eBU2u", type="ssh-ed25519", ), ], ), ], ), ) result = self.execute_module(changed=True) self.assertEqual( sorted(result["commands"]), sorted( [ "set system login user user1 authentication public-keys user1@host1 key 'AAAAC3NzaC1lZDI1NTE5AAAAIFIR0jrMvBdmvTJNY5EDhOD+eixvbOinhY1eBU2u'", "set system login user user1 authentication public-keys user1@host1 type 'ssh-ed25519'", "set system login user user2 authentication public-keys user2@host2 key 'AAAAC3NzaC1lZDI1NTE5AAAAIFIR0jrMvBdmvTJNY5EDhOD+eixvbOinhY1eBU2u'", "set system login user user2 authentication public-keys user2@host2 type 'ssh-ed25519'", ], ), )