From d3f981148e78c0dd31d35063f3407530278aa3a1 Mon Sep 17 00:00:00 2001 From: Yuriy Andamasov Date: Mon, 27 Apr 2026 16:47:01 +0300 Subject: T8512: fix isort import ordering violations (#454) * T8512: fix isort import ordering violations * T8512: add changelog fragment Co-Authored-By: Claude Sonnet 4.6 --------- Co-authored-by: omnom62 <75066712+omnom62@users.noreply.github.com> Co-authored-by: Claude Sonnet 4.6 --- .../network/vyos/facts/bgp_address_family/bgp_address_family.py | 6 +++--- plugins/module_utils/network/vyos/facts/bgp_global/bgp_global.py | 7 +++---- .../module_utils/network/vyos/rm_templates/ospf_interfaces_14.py | 1 + plugins/module_utils/network/vyos/utils/version.py | 2 ++ 4 files changed, 9 insertions(+), 7 deletions(-) (limited to 'plugins') diff --git a/plugins/module_utils/network/vyos/facts/bgp_address_family/bgp_address_family.py b/plugins/module_utils/network/vyos/facts/bgp_address_family/bgp_address_family.py index 3386bd66..31839c5d 100644 --- a/plugins/module_utils/network/vyos/facts/bgp_address_family/bgp_address_family.py +++ b/plugins/module_utils/network/vyos/facts/bgp_address_family/bgp_address_family.py @@ -28,11 +28,11 @@ from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.rm_template 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.utils.version import ( + LooseVersion, +) from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.vyos import get_os_version -from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.utils.version import LooseVersion - class Bgp_address_familyFacts(object): """The vyos bgp_address_family facts class""" diff --git a/plugins/module_utils/network/vyos/facts/bgp_global/bgp_global.py b/plugins/module_utils/network/vyos/facts/bgp_global/bgp_global.py index dd793681..2883cc2d 100644 --- a/plugins/module_utils/network/vyos/facts/bgp_global/bgp_global.py +++ b/plugins/module_utils/network/vyos/facts/bgp_global/bgp_global.py @@ -25,15 +25,14 @@ from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.argspec.bgp from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.rm_templates.bgp_global import ( Bgp_globalTemplate, ) - 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.utils.version import ( + LooseVersion, +) from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.vyos import get_os_version -from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.utils.version import LooseVersion - class Bgp_globalFacts(object): """The vyos bgp_global facts class""" 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 43fae1e9..0d3aa5a7 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 @@ -5,6 +5,7 @@ from __future__ import absolute_import, division, print_function + __metaclass__ = type """ diff --git a/plugins/module_utils/network/vyos/utils/version.py b/plugins/module_utils/network/vyos/utils/version.py index cc3028c3..6d84ef1c 100644 --- a/plugins/module_utils/network/vyos/utils/version.py +++ b/plugins/module_utils/network/vyos/utils/version.py @@ -7,6 +7,8 @@ """Provide version object to compare version numbers.""" from __future__ import absolute_import, division, print_function + + __metaclass__ = type -- cgit v1.2.3 From a2ee09579a75165ae691efcbf3e952db83145b83 Mon Sep 17 00:00:00 2001 From: Yuriy Andamasov Date: Fri, 1 May 2026 21:43:03 +0300 Subject: T8520: fix vlan purge generating invalid commands for bare interfaces (#463) Co-authored-by: Daniil Baturin --- changelogs/fragments/fix-vlan-purge.yml | 3 + plugins/modules/vyos_vlan.py | 12 +-- tests/unit/modules/network/vyos/test_vyos_vlan.py | 119 ++++++++++++++++++++++ 3 files changed, 126 insertions(+), 8 deletions(-) create mode 100644 changelogs/fragments/fix-vlan-purge.yml create mode 100644 tests/unit/modules/network/vyos/test_vyos_vlan.py (limited to 'plugins') diff --git a/changelogs/fragments/fix-vlan-purge.yml b/changelogs/fragments/fix-vlan-purge.yml new file mode 100644 index 00000000..bbc1d08a --- /dev/null +++ b/changelogs/fragments/fix-vlan-purge.yml @@ -0,0 +1,3 @@ +--- +bugfixes: + - vyos_vlan - fix purge generating invalid ``delete ... vif None`` commands for bare interfaces without VLAN sub-interfaces. diff --git a/plugins/modules/vyos_vlan.py b/plugins/modules/vyos_vlan.py index f0b68bc9..9d23cc7c 100644 --- a/plugins/modules/vyos_vlan.py +++ b/plugins/modules/vyos_vlan.py @@ -279,15 +279,11 @@ def map_config_to_obj(module): obj = {} eth = splitted_line[0].strip("'") - if eth.startswith("eth"): + if eth.startswith("eth") and "." in eth: obj["interfaces"] = [] - if "." in eth: - interface = eth.split(".")[0] - obj["interfaces"].append(interface) - obj["vlan_id"] = eth.split(".")[-1] - else: - obj["interfaces"].append(eth) - obj["vlan_id"] = None + interface = eth.split(".")[0] + obj["interfaces"].append(interface) + obj["vlan_id"] = eth.split(".")[-1] if splitted_line[1].strip("'") != "-": obj["address"] = splitted_line[1].strip("'") diff --git a/tests/unit/modules/network/vyos/test_vyos_vlan.py b/tests/unit/modules/network/vyos/test_vyos_vlan.py new file mode 100644 index 00000000..4f2ea69a --- /dev/null +++ b/tests/unit/modules/network/vyos/test_vyos_vlan.py @@ -0,0 +1,119 @@ +# (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 . + +from __future__ import absolute_import, division, print_function + + +__metaclass__ = type + +from unittest.mock import patch + +from ansible_collections.vyos.vyos.plugins.modules import vyos_vlan +from ansible_collections.vyos.vyos.tests.unit.modules.utils import set_module_args + +from .vyos_module import TestVyosModule + + +SHOW_INTERFACES_OUTPUT = """\ +Codes: S - State, L - Link, u - Up, D - Down, A - Admin Down +Interface IP Address S/L Description +--------- ---------- --- ----------- +eth0 10.0.2.15/24 u/u +eth0.100 - u/u vlan-100 +eth1 - u/u +eth1.200 192.0.2.1/24 u/u vlan-200 +eth2 - u/u +lo 127.0.0.1/8 u/u + ::1/128 +""" + + +class TestVyosVlanModule(TestVyosModule): + module = vyos_vlan + + def setUp(self): + super(TestVyosVlanModule, self).setUp() + + self.mock_load_config = patch( + "ansible_collections.vyos.vyos.plugins.modules.vyos_vlan.load_config", + ) + self.load_config = self.mock_load_config.start() + + self.mock_run_commands = patch( + "ansible_collections.vyos.vyos.plugins.modules.vyos_vlan.run_commands", + ) + self.run_commands = self.mock_run_commands.start() + + def tearDown(self): + super(TestVyosVlanModule, self).tearDown() + self.mock_load_config.stop() + self.mock_run_commands.stop() + + def load_fixtures(self, commands=None, filename=None): + self.load_config.return_value = dict(diff=None, session="session") + self.run_commands.return_value = [SHOW_INTERFACES_OUTPUT] + + def test_vyos_vlan_purge_no_bare_interfaces(self): + """Purge should only delete VLANs, not bare interfaces without vlan_id.""" + set_module_args( + dict( + vlan_id=100, + interfaces=["eth0"], + state="present", + purge=True, + ), + ) + result = self.execute_module(changed=True) + # Should only delete eth1.200, not bare eth0/eth1/eth2 with vif None + for cmd in result.get("commands", []): + self.assertNotIn( + "vif None", + cmd, + "Purge generated 'vif None' command for bare interface: {0}".format(cmd), + ) + # eth1.200 should be purged since it's not in the desired state + self.assertIn( + "delete interfaces ethernet eth1 vif 200", + result.get("commands", []), + ) + + def test_vyos_vlan_present(self): + set_module_args( + dict( + vlan_id=300, + name="vlan-300", + interfaces=["eth2"], + state="present", + ), + ) + commands = [ + "set interfaces ethernet eth2 vif 300 description vlan-300", + ] + self.execute_module(changed=True, commands=commands) + + def test_vyos_vlan_absent(self): + set_module_args( + dict( + vlan_id=100, + interfaces=["eth0"], + state="absent", + ), + ) + commands = [ + "delete interfaces ethernet eth0 vif 100", + ] + self.execute_module(changed=True, commands=commands) -- cgit v1.2.3 From be77e3b4b870ae2fb8ec4a75794a960c422a8449 Mon Sep 17 00:00:00 2001 From: Yuriy Andamasov Date: Wed, 13 May 2026 16:23:39 +0300 Subject: T8515: remove pre-1.3 deprecated code artifacts from vyos_bgp_global (#461) * T8515: remove commented-out pre-1.3 parameter artifacts from vyos_bgp_global docs * T8515: remove stale vrf.old backup file * T8515: add changelog fragment for deprecated code cleanup * T8515: fix grammar in ebgp_multihop description Co-Authored-By: Claude Sonnet 4.6 --------- Co-authored-by: Claude Sonnet 4.6 Co-authored-by: omnom62 <75066712+omnom62@users.noreply.github.com> --- changelogs/fragments/deprecated-cleanup.yml | 3 + .../module_utils/network/vyos/config/vrf/vrf.old | 313 --------------------- plugins/modules/vyos_bgp_global.py | 139 +-------- 3 files changed, 4 insertions(+), 451 deletions(-) create mode 100644 changelogs/fragments/deprecated-cleanup.yml delete mode 100644 plugins/module_utils/network/vyos/config/vrf/vrf.old (limited to 'plugins') diff --git a/changelogs/fragments/deprecated-cleanup.yml b/changelogs/fragments/deprecated-cleanup.yml new file mode 100644 index 00000000..cf361adc --- /dev/null +++ b/changelogs/fragments/deprecated-cleanup.yml @@ -0,0 +1,3 @@ +--- +minor_changes: + - vyos_bgp_global - remove commented-out pre-1.3 deprecated parameter documentation artifacts. diff --git a/plugins/module_utils/network/vyos/config/vrf/vrf.old b/plugins/module_utils/network/vyos/config/vrf/vrf.old deleted file mode 100644 index b9f56cc6..00000000 --- a/plugins/module_utils/network/vyos/config/vrf/vrf.old +++ /dev/null @@ -1,313 +0,0 @@ -# -# -*- 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 vyos_vrf config file. -It is in this file where the current configuration (as dict) -is compared to the provided configuration (as dict) and the command set -necessary to bring the current configuration to its desired end-state is -created. -""" - -import importlib - -from copy import deepcopy - -from ansible.module_utils.six import iteritems -from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.rm_base.resource_module import ( - ResourceModule, -) - -from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.config.bgp_global.bgp_global import ( - Bgp_global, -) -from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.facts.facts import Facts -from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.rm_templates.vrf import ( - VrfTemplate, -) -from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.utils.utils import combine -from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.utils.version import ( - LooseVersion, -) -from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.vyos import get_os_version - - -# from ansible.plugins.filter.core import combine - - -class Vrf(ResourceModule): - """ - The vyos_vrf config class - """ - - def __init__(self, module): - super(Vrf, self).__init__( - empty_fact_val={}, - facts_module=Facts(module), - module=module, - resource="vrf", - tmplt=VrfTemplate(), - ) - self.parsers = [ - "bind_to_all", - ] - self.bgp = Bgp_global(module) - - def _validate_template(self): - version = get_os_version(self._module) - if LooseVersion(version) >= LooseVersion("1.4"): - self._tmplt = VrfTemplate() - else: - self._module.fail_json(msg="VRF is not supported in this version of VyOS") - - def parse(self): - """override parse to check template""" - self._validate_template() - return super().parse() - - def get_parser(self, name): - """get_parsers""" - self._validate_template() - return super().get_parser(name) - - def execute_module(self): - """Execute the module - - :rtype: A dictionary - :returns: The result from module execution - """ - if self.state not in ["parsed", "gathered"]: - self.generate_commands() - self.run_commands() - - return self.result - - def generate_commands(self): - """Generate configuration commands to send based on - want, have and desired state. - """ - wantd = {} - haved = {} - wantd = deepcopy(self.want) - haved = deepcopy(self.have) - - # self._module.fail_json(msg="WanT: " + str(self.want) + "**** H: " + str(self.have)) - - # if state is merged, merge want onto have and then compare - if self.state in ["merged", "replaced"]: - # wantd = dict_merge(wantd, haved) - # wantd = haved | combine(wantd, recursive=True) - wantd = combine(haved, wantd, recursive=True) - # self._module.fail_json(msg="Want: " + str(wantd) + "**** H: " + str(haved)) - - # if state is deleted, delete and empty out wantd - if self.state == "deleted": - w = deepcopy(wantd) - if w == {} and haved != {}: - self.commands = ["delete vrf"] - return - for k, want in iteritems(w): - if not (k in haved and haved[k]): - del wantd[k] - else: - if isinstance(want, list): - for entry in want: - wname = entry.get("name") - haved["instances"] = [ - i for i in haved.get("instances", []) if i.get("name") != wname - ] - self.commands.append("delete vrf name {}".format(wname)) - else: - self.commands.append("delete vrf {}".format(k.replace("_", "-"))) - del wantd[k] - - if self.state == "overridden": - w = deepcopy(wantd) - h = deepcopy(haved) - for k, want in iteritems(w): - if k in haved and haved[k] != want: - if isinstance(want, list): - for entry in want: - wname = entry.get("name") - hdict = next( - (inst for inst in haved["instances"] if inst["name"] == wname), - None, - ) - if entry != hdict: - # self._module.fail_json(msg="Want: " + str(entry) + "**** H: " + str(hdict)) - haved["instances"] = [ - i for i in haved.get("instances", []) if i.get("name") != wname - ] - self.commands.append("delete vrf name {}".format(wname)) - self.commands.append("commit") - - for k, want in iteritems(wantd): - if isinstance(want, list): - self._compare_instances(want=want, have=haved.pop(k, {})) - self.compare( - parsers=self.parsers, - want={k: want}, - have={k: haved.pop(k, {})}, - ) - self._module.fail_json(msg=self.commands) - - def _compare_instances(self, want, have): - """Compare the instances of the VRF""" - parsers = [ - "table_id", - "vni", - "description", - "disable_vrf", - ] - # self._module.fail_json(msg="want: " + str(want) + "**** have: " + str(have)) - - for entry in want: - h = {} - wname = entry.get("name") - # h = next((vrf for vrf in have if vrf["name"] == wname), {}) - h = { - k: v - for vrf in have - if vrf.get("name") == wname - for k, v in vrf.items() - if k != "address_family" - } - self.compare(parsers=parsers, want=entry, have=h) - - if "address_family" in entry: - wafi = {"name": wname, "address_family": entry.get("address_family", [])} - # hdict = next((item for item in have if item["name"] == wname), None) - hdict = next((d for d in have if d.get("name") == wname), None) - - hafi = { - "name": (hdict or {"name": wname})["name"], - "address_family": hdict.get("address_family", []) if hdict else [], - } - - # self._module.fail_json(msg="wafi: " + str(wafi) + "**** hafi: " + str(hafi)) - - self._compare_addr_family(wafi, hafi) - - if "protocols" in entry: - for protocol_name in entry["protocols"]: - protocol_module = self._load_protocol_module(protocol_name) - w_p_dict = entry["protocols"][protocol_name] - h_p_dict = next( - ( - v.get("protocols", {}).get(protocol_name) - for v in have - if v.get("name") == wname - ), - {}, - ) - if protocol_name == "bgp": - protocol_module._validate_template() - protocol_module.want = w_p_dict - protocol_module.have = h_p_dict - protocol_module.generate_commands() - elif protocol_name in [ - # "ospf", - # "ospfv3", - "static", - ]: - self._module.fail_json(msg=str(protocol_module)) - protocol_module._module.params["config"] = w_p_dict - protocol_module.state = self.state - self._module.fail_json(msg=str(protocol_module.set_config(h_p_dict))) - - protocol_module.commands = protocol_module.set_config(h_p_dict) - self.commands.extend( - [ - cmd.replace("protocols", "vrf name " + wname + " protocols", 1) - for cmd in protocol_module.commands - ], - ) - protocol_module = None # Clear the module to free resources - - def _compare_addr_family(self, want, have): - """Compare the address families of the VRF""" - afi_parsers = [ - # "address_family", - "disable_forwarding", - "disable_nht", - ] - # self._module.fail_json(msg="wAfi: " + str(want) + "**** hAfi: " + str(have)) - - wafi = self.afi_to_list(want) - hafi = self.afi_to_list(have) - - lookup = {(d["name"], d["afi"]): d for d in hafi} - pairs = [(d1, lookup.get((d1["name"], d1["afi"]), {})) for d1 in wafi] - - for wafd, hafd in pairs: - # self._module.fail_json(msg="wAfd: " + str(wafd) + "**** hAfd: " + str(hafd)) - if "route_maps" in wafd: - self._compare_route_maps(wafd, hafd) - self.compare(parsers=afi_parsers, want=wafd, have=hafd) - # self.compare(parsers=afi_parsers, want=wafi, have=hafi) - - def afi_to_list(self, data): - """Convert address family dict to list""" - - return [ - {"name": data["name"], **{**af, "afi": "ip" if af["afi"] == "ipv4" else af["afi"]}} - for af in data["address_family"] - ] - - def _compare_route_maps(self, wafd, hafd): - want_rms = wafd.get("route_maps", []) - have_rms = hafd.get("route_maps", []) - - for want in want_rms: - match = next( - ( - h - for h in have_rms - if h["rm_name"] == want["rm_name"] and h["protocol"] == want["protocol"] - ), - {}, - ) - base = {"name": wafd["name"], "afi": wafd["afi"]} - - self.compare( - parsers="route_maps", - want={**base, "route_maps": want}, - have={**base, "route_maps": match}, - ) - - def _load_protocol_module(self, protocol_name): - if protocol_name == "bgp": - from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.config.bgp_global.bgp_global import ( - Bgp_global, - ) - - return Bgp_global(self._module) - elif protocol_name == "ospf": - from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.config.ospfv2.ospfv2 import ( - Ospfv2, - ) - - return Ospfv2(self._module) - elif protocol_name == "ospfv3": - from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.config.ospfv3.ospfv3 import ( - Ospfv3, - ) - - return Ospfv3(self._module) - elif protocol_name == "static": - from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.config.static_routes.static_routes import ( - Static_routes, - ) - - return Static_routes(self._module) - else: - self._module.fail_json(msg="The protocol is not supported") diff --git a/plugins/modules/vyos_bgp_global.py b/plugins/modules/vyos_bgp_global.py index fe14bc0f..7e9f63b1 100644 --- a/plugins/modules/vyos_bgp_global.py +++ b/plugins/modules/vyos_bgp_global.py @@ -74,37 +74,6 @@ options: description: - Minimum interval for sending routing updates. type: int - # bfd: # <-- added in 1.3 - # description: Enable Bidirectional Forwarding Detection (BFD) support - # type: dict - # suboptions: - # check-control-plane-failure: - # description: - # - Allow to write CBIT independence in BFD outgoing packets - # and read both C-BIT value of BFD and lookup BGP peer status - # type: bool - # allowas_in: --> Moved to address-family before 1.3 - # description: - # - Number of occurrences of AS number. - # type: int - # as_override: --> Moved to address-family before 1.3 - # description: - # - AS for routes sent to this neighbor to be the local AS. - # type: bool - # attribute_unchanged: --> Moved to address-family before 1.3 - # description: - # - BGP attributes are sent unchanged. - # type: dict - # suboptions: - # as_path: - # description: as_path - # type: bool - # med: - # description: med - # type: bool - # next_hop: - # description: next_hop - # type: bool capability: description: - Advertise capabilities to this neighbor. @@ -118,13 +87,6 @@ options: description: - Advertise extended nexthop capability to this neighbor. type: bool - # orf: --> Removed before 1.3 - # description: - # - Advertise ORF capability to this neighbor. - # type: str - # choices: - # - send - # - receive default_originate: description: - Send default route to this neighbor @@ -146,70 +108,14 @@ options: - Disable sending community attributes to this neighbor. type: str choices: ['extended', 'standard'] - # distribute_list: --> Moved to address-family before 1.3 - # description: Access-list to filter route updates to/from this neighbor. - # type: list - # elements: dict - # suboptions: - # action: - # description: Access-list to filter outgoing/incoming route updates to this neighbor - # type: str - # choices: ['export', 'import'] - # acl: - # description: Access-list number. - # type: int ebgp_multihop: description: - Allow this EBGP neighbor to not be on a directly connected network. Specify - the number hops. + the number of hops. type: int - # interface: # <-- added in 1.3 - # description: interface parameters - # type: dict - # suboptions: - # peer_group: - # description: Peer group for this neighbor - # type: str - # remote_as: - # description: - # - Remote AS number - # - Or 'external' for any number except this AS number - # - or 'internal' for this AS number - # type: str - # v6only: - # description: Enable BGP with v6 link-local only - # type: dict - # suboptions: - # peer_group: - # description: Peer group for this neighbor - # type: str - # remote_as: - # description: - # - Remote AS number - # - Or 'external' for any number except this AS number - # - or 'internal' for this AS number - # filter_list: --> Moved to address-family before 1.3 - # description: As-path-list to filter route updates to/from this neighbor. - # type: list - # elements: dict - # suboptions: - # action: - # description: filter outgoing/incoming route updates - # type: str - # choices: ['export', 'import'] - # path_list: - # description: As-path-list to filter - # type: str local_as: description: local as number not to be prepended to updates from EBGP peers type: int - # maximum_prefix: --> Moved to address-family before 1.3 - # description: Maximum number of prefixes to accept from this neighbor - # nexthop-self Nexthop for routes sent to this neighbor to be the local router. - # type: int - # nexthop_self: --> Moved to address-family before 1.3 - # description: Nexthop for routes sent to this neighbor to be the local router. - # type: bool override_capability: description: Ignore capability negotiation with specified neighbor. type: bool @@ -228,61 +134,18 @@ options: port: description: Neighbor's BGP port type: int - # prefix_list: --> Moved to address-family before 1.3 - # description: Prefix-list to filter route updates to/from this neighbor. - # type: list - # elements: dict - # suboptions: - # action: - # description: filter outgoing/incoming route updates - # type: str - # choices: ['export', 'import'] - # prefix_list: - # description: Prefix-list to filter - # type: str remote_as: description: Neighbor BGP AS number type: int - # remove_private_as: --> Moved to address-family before 1.3 - # description: Remove private AS numbers from AS path in outbound route updates - # type: bool - # route_map: --> Moved to address-family before 1.3 - # description: Route-map to filter route updates to/from this neighbor. - # type: list - # elements: dict - # suboptions: - # action: - # description: filter outgoing/incoming route updates - # type: str - # choices: ['export', 'import'] - # route_map: - # description: route-map to filter - # type: str - # route_reflector_client: --> Moved to address-family before 1.3 - # description: Neighbor as a route reflector client - # type: bool - # route_server_client: --> Removed prior to 1.3 - # description: Neighbor is route server client - # type: bool shutdown: description: Administratively shut down neighbor type: bool - # soft_reconfiguration: --> Moved to address-family before 1.3 - # description: Soft reconfiguration for neighbor - # type: bool solo: # <-- added in 1.3 description: Do not send back prefixes learned from the neighbor type: bool strict_capability_match: description: Enable strict capability negotiation type: bool - # unsuppress_map: --> Moved to address-family before 1.3 - # description: Route-map to selectively unsuppress suppressed routes - # type: str - - # weight: --> Moved to address-family before 1.3 - # description: Default weight for routes from this neighbor - # type: int timers: description: Neighbor timers type: dict -- cgit v1.2.3 From 29e47bb4b43d1888c79f54de2fbee90224e9652b Mon Sep 17 00:00:00 2001 From: stronkbyte <262002943+stronkbyte@users.noreply.github.com> Date: Mon, 25 May 2026 13:44:54 +0200 Subject: T6818: Add argument to vyos_config for controlling password filtering (#466) This commit adds the argument `allow_password_change` in order to control whether any configuration lines which would make changes to user passwords should be filtered out or not. Co-authored-by: Daniil Baturin Co-authored-by: omnom62 <75066712+omnom62@users.noreply.github.com> --- changelogs/fragments/t6818_password_filtering.yml | 2 + plugins/modules/vyos_config.py | 47 +++++++++++++++++----- .../vyos_config/tests/cli/check_config.yaml | 34 ++++++++++++++++ 3 files changed, 73 insertions(+), 10 deletions(-) create mode 100644 changelogs/fragments/t6818_password_filtering.yml (limited to 'plugins') diff --git a/changelogs/fragments/t6818_password_filtering.yml b/changelogs/fragments/t6818_password_filtering.yml new file mode 100644 index 00000000..d52283b9 --- /dev/null +++ b/changelogs/fragments/t6818_password_filtering.yml @@ -0,0 +1,2 @@ +minor_changes: + - plugins/modules/vyos_config.py - Added an argument to control password filtering in vyos_config. Current filtering behavior is still the default. diff --git a/plugins/modules/vyos_config.py b/plugins/modules/vyos_config.py index a9774638..2407ce01 100644 --- a/plugins/modules/vyos_config.py +++ b/plugins/modules/vyos_config.py @@ -142,6 +142,20 @@ options: in C(filename) within I(backup) directory. type: path type: dict + allow_password_change: + description: + - The C(allow_password_change) argument specifies whether any configuration lines which + would change a user's password should be filtered out. By default only plaintext + password changes are allowed and any encrypted-password keys are filtered out. In + order to allow all password updates, both plaintext and encrypted, set this argument + to C(all). + type: str + default: plaintext + choices: + - all + - plaintext + - encrypted + - none """ EXAMPLES = """ @@ -233,9 +247,7 @@ from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.vyos import DEFAULT_COMMENT = "configured by vyos_config" -CONFIG_FILTERS = [ - re.compile(r"set system login user \S+ authentication encrypted-password"), -] +PASSWORD_NEEDLE = re.compile(r"set system login user \S+ authentication (encrypted|plaintext)-password") def get_candidate(module): @@ -294,14 +306,26 @@ def diff_config(commands, config): return list(updates) -def sanitize_config(config, result): +def sanitize_config(config, result, allow): result["filtered"] = list() + + if allow == "all": + return + index_to_filter = list() - for regex in CONFIG_FILTERS: - for index, line in enumerate(list(config)): - if regex.search(line): - result["filtered"].append(line) - index_to_filter.append(index) + + for index, line in enumerate(list(config)): + found = PASSWORD_NEEDLE.search(line) + + if found is None: + continue + + if allow == found[1]: + continue + + result["filtered"].append(line) + index_to_filter.append(index) + # Delete all filtered configs for filter_index in sorted(index_to_filter, reverse=True): del config[filter_index] @@ -328,7 +352,9 @@ def run(module, result): module.fail_json(msg=to_text(exc, errors="surrogate_then_replace")) commands = response.get("config_diff") - sanitize_config(commands, result) + + allow_password_change = module.params["allow_password_change"] + sanitize_config(commands, result, allow=allow_password_change) result["commands"] = commands @@ -368,6 +394,7 @@ def main(): backup=dict(type="bool", default=False), backup_options=dict(type="dict", options=backup_spec), save=dict(type="bool", default=False), + allow_password_change=dict(default="plaintext", choices=["all", "encrypted", "plaintext", "none"]) ) mutually_exclusive = [("lines", "src")] diff --git a/tests/integration/targets/vyos_config/tests/cli/check_config.yaml b/tests/integration/targets/vyos_config/tests/cli/check_config.yaml index 8e2e8372..83a62197 100644 --- a/tests/integration/targets/vyos_config/tests/cli/check_config.yaml +++ b/tests/integration/targets/vyos_config/tests/cli/check_config.yaml @@ -49,9 +49,43 @@ - set system login user esa authentication encrypted-password '!abc!' - set system login user vyos full-name 'VyOS admin' - set system login user vyos authentication encrypted-password 'abc' + - set system login user john full-name 'John' + - set system login user john authentication plaintext-password 'xyz' - assert: that: - result.filtered|length == 2 +- name: check multiple line config filter is working + register: result + vyos.vyos.vyos_config: + allow_password_change: none + lines: + - set system login user esa full-name 'ESA admin' + - set system login user esa authentication encrypted-password '!abc!' + - set system login user vyos full-name 'VyOS admin' + - set system login user vyos authentication encrypted-password 'abc' + - set system login user john full-name 'John' + - set system login user john authentication plaintext-password 'xyz' + +- assert: + that: + - result.filtered|length == 3 + +- name: check multiple line config filter is working + register: result + vyos.vyos.vyos_config: + allow_password_change: all + lines: + - set system login user esa full-name 'ESA admin' + - set system login user esa authentication encrypted-password '!abc!' + - set system login user vyos full-name 'VyOS admin' + - set system login user vyos authentication encrypted-password 'abc' + - set system login user john full-name 'John' + - set system login user john authentication plaintext-password 'xyz' + +- assert: + that: + - result.filtered|length == 0 + - debug: msg="END cli/config_check.yaml on connection={{ ansible_connection }}" -- cgit v1.2.3 From 5b80cd0cbddd014e54b01e7fa1cd0c0777d94724 Mon Sep 17 00:00:00 2001 From: Robert Navarro Date: Fri, 19 Jun 2026 06:02:27 -0700 Subject: rm_templates: T8609: fix slow parse() from group-quantifier patterns (#470) * rm_templates: T8609: fix slow parse() from group-quantifier patterns Running an Ansible playbook that manages BGP route-maps on my VyOS 1.4 edge routers, the vyos.vyos.vyos_route_maps task (state=gathered or state=merged) takes ~50 seconds per host, sometimes 100s+, against devices with only a handful of route-maps configured. The persistent connection times out before the module finishes and the failure surfaces as a misleading "socket path does not exist". Three related quantifier shapes in nine rm_templates files cause O(2^n) regex backtracking on inputs that share a parser's prefix but don't match overall. parse() time on a representative 12-line route-map config drops from ~50s to <1ms post-fix. * Trailing form (188 sites): `(?P\S+)\n *$"""` -> `(?P\S+)\s*$"""`. Under re.VERBOSE the literal newline+indent between `\S+` and `*$` is stripped at compile time, so the source compiled to `(\S+)*$` with the `*` quantifying the named group. * Mid-pattern `(group containing \S+)*` (22 sites in snmp_server.py with a couple in bgp_global*.py): e.g. `(?Pprotocol\s\S+)*` -> `(?Pprotocol\s\S+)?`. Different position from the trailing form, but the same shape underneath (a group whose content includes \S+, quantified with `*`), so the same O(2^n) backtracking on prefix-sharing inputs. * Mid-pattern `(literal-only group)*` (14 sites in snmp_server.py, bgp_address_family*.py, bgp_global*.py): e.g. `(?Pas-set)*` -> `(?Pas-set)?`. No \S+ inside the quantified group, so the backtracking exposure is much smaller. On the inputs these patterns actually receive (no device line carries duplicate flags) `*` and `?` accept identical input sets, so changing to `?` is behavior-preserving. The first draft of this fix made set_comm_list_delete's `(?P\S+)` group required. The parser's setval emits `set comm-list delete` with no token after `delete`, so the parser stopped matching its own output (no existing fixture covered this case, which is why the regression initially shipped). CodeRabbit caught it during review. Replaced `delete(?P\S+)\s*$` with `\s(?Pdelete)\s*$` so the named group captures the literal word `delete`; the result template `{{True if delete is defined}}` continues to evaluate True. Affects: route_maps[/_14], bgp_global[/_14], bgp_address_family[/_14], snmp_server, ospf_interfaces[/_14]. Adds tests/unit/modules/network/vyos/test_rm_templates_perf.py with a 1-second budget against fixture inputs that have realistic-length identifiers, plus a round-trip test asserting set_comm_list_delete matches its own setval-generated line, plus a Bgp_address_familyTemplate14 budget test for symmetry with the other "hot" template families. * Fix regex backtracking issues in parse() method Fix slow parse() to prevent regex backtracking on prefix-sharing inputs across multiple files. Add unit test for the bugfixes. * Refactor bug fixes for regex backtracking improvements Updated bug fixes to include details on regex backtracking issues in multiple files. * Fix typo in bugfixes section of changelog * Update bugfixes for regex backtracking issues * rm_templates: T8609: route_maps.py: fix remaining trailing `*$` patterns Five sites in route_maps.py still had the `(?P...)\n *$` shape that collapses to `(?P...)*$` under `re.VERBOSE`, parsers `sequence`, `on_match_next`, `set_atomic_aggregate`, `set_extcommunity_bandwidth_non_transitive`, and `match_community_exact_match`. Collapsed each to `\s*$` on the same line as the named group, matching the rest of the PR. * rm_templates: T8609: route_maps.py: split overlong getval to satisfy E501 Line 517 was 161 chars (`set_extcommunity_bandwidth_non_transitive` parser) and tripped pycodestyle's E501 sanity test in CI. Split the regex source across two lines at the `\d+)` boundary; under `re.VERBOSE` the literal newline and indent between regex tokens are stripped at compile time, so the engine sees the same pattern. `\s*$` stays on the same line as the closing capture group, so the group-quantifier shape this PR fixes elsewhere isn't reintroduced. --------- Co-authored-by: omnom62 <75066712+omnom62@users.noreply.github.com> --- .../T8609_rm_templates_regex_backtracking.yml | 12 ++ .../vyos/rm_templates/bgp_address_family.py | 49 +++---- .../vyos/rm_templates/bgp_address_family_14.py | 49 +++---- .../network/vyos/rm_templates/bgp_global.py | 95 ++++-------- .../network/vyos/rm_templates/bgp_global_14.py | 95 ++++-------- .../network/vyos/rm_templates/ospf_interfaces.py | 9 +- .../vyos/rm_templates/ospf_interfaces_14.py | 12 +- .../network/vyos/rm_templates/route_maps.py | 145 +++++++----------- .../network/vyos/rm_templates/route_maps_14.py | 123 ++++++---------- .../network/vyos/rm_templates/snmp_server.py | 78 +++++----- .../modules/network/vyos/test_rm_templates_perf.py | 163 +++++++++++++++++++++ 11 files changed, 405 insertions(+), 425 deletions(-) create mode 100644 changelogs/fragments/T8609_rm_templates_regex_backtracking.yml create mode 100644 tests/unit/modules/network/vyos/test_rm_templates_perf.py (limited to 'plugins') 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/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 @@ -293,8 +293,8 @@ class Bgp_address_familyTemplate(NetworkTemplate): \s+(?P\S+)-unicast \s+aggregate-address \s+(?P
\S+) - \s*(?Pas-set)* - \s*(?Psummary-only)* + \s*(?Pas-set)? + \s*(?Psummary-only)? $""", re.VERBOSE, ), @@ -397,8 +397,7 @@ class Bgp_address_familyTemplate(NetworkTemplate): \s+network \s+(?P
\S+) \s+path-limit - \s+(?P\S+) - *$""", + \s+(?P\S+)\s*$""", re.VERBOSE, ), "setval": _tmplt_bgp_af_network, @@ -432,8 +431,7 @@ class Bgp_address_familyTemplate(NetworkTemplate): \s+network \s+(?P
\S+) \s+route-map - \s+(?P\S+) - *$""", + \s+(?P\S+)\s*$""", re.VERBOSE, ), "setval": _tmplt_bgp_af_network, @@ -499,8 +497,7 @@ class Bgp_address_familyTemplate(NetworkTemplate): \s+redistribute \s+(?P\S+) \s+metric - \s+(?P\S+) - *$""", + \s+(?P\S+)\s*$""", re.VERBOSE, ), "setval": _tmplt_bgp_af_redistribute, @@ -534,8 +531,7 @@ class Bgp_address_familyTemplate(NetworkTemplate): \s+redistribute \s+(?P\S+) \s+route-map - \s+(?P\S+) - *$""", + \s+(?P\S+)\s*$""", re.VERBOSE, ), "setval": _tmplt_bgp_af_redistribute, @@ -568,8 +564,7 @@ class Bgp_address_familyTemplate(NetworkTemplate): \s+(?P\S+)-unicast \s+redistribute \s+table - \s+(?P\S+) - *$""", + \s+(?P\S+)\s*$""", re.VERBOSE, ), "setval": _tmplt_bgp_af_redistribute, @@ -659,8 +654,7 @@ class Bgp_address_familyTemplate(NetworkTemplate): \s+(?P\S+)-unicast \s+allowas-in \s+number - \s+(?P\S+) - *$""", + \s+(?P\S+)\s*$""", re.VERBOSE, ), "setval": _tmplt_bgp_af_neighbor, @@ -877,8 +871,7 @@ class Bgp_address_familyTemplate(NetworkTemplate): \s+(?P\S+)-unicast \s+capability \s+prefix-list - \s+(?P\S+) - *$""", + \s+(?P\S+)\s*$""", re.VERBOSE, ), "setval": _tmplt_bgp_af_neighbor, @@ -915,8 +908,7 @@ class Bgp_address_familyTemplate(NetworkTemplate): \s+(?P\S+)-unicast \s+default-originate \s+route-map - \s+(?P\S+) - *$""", + \s+(?P\S+)\s*$""", re.VERBOSE, ), "setval": _tmplt_bgp_af_neighbor, @@ -992,8 +984,7 @@ class Bgp_address_familyTemplate(NetworkTemplate): \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, @@ -1033,8 +1024,7 @@ class Bgp_address_familyTemplate(NetworkTemplate): \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, @@ -1073,8 +1063,7 @@ class Bgp_address_familyTemplate(NetworkTemplate): \s+address-family \s+(?P\S+)-unicast \s+maximum-prefix - \s+(?P\S+) - *$""", + \s+(?P\S+)\s*$""", re.VERBOSE, ), "setval": _tmplt_bgp_af_neighbor, @@ -1176,8 +1165,7 @@ class Bgp_address_familyTemplate(NetworkTemplate): \s+address-family \s+(?P\S+)-unicast \s+peer-group - \s+(?P\S+) - *$""", + \s+(?P\S+)\s*$""", re.VERBOSE, ), "setval": _tmplt_bgp_af_neighbor, @@ -1246,8 +1234,7 @@ class Bgp_address_familyTemplate(NetworkTemplate): \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, @@ -1389,8 +1376,7 @@ class Bgp_address_familyTemplate(NetworkTemplate): \s+address-family \s+(?P\S+)-unicast \s+unsuppress-map - \s+(?P\S+) - *$""", + \s+(?P\S+)\s*$""", re.VERBOSE, ), "setval": _tmplt_bgp_af_neighbor, @@ -1424,8 +1410,7 @@ class Bgp_address_familyTemplate(NetworkTemplate): \s+address-family \s+(?P\S+)-unicast \s+weight - \s+(?P\S+) - *$""", + \s+(?P\S+)\s*$""", re.VERBOSE, ), "setval": _tmplt_bgp_af_neighbor, 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 @@ -309,8 +309,8 @@ class Bgp_address_familyTemplate14(NetworkTemplate): \s+(?P\S+)-unicast \s+aggregate-address \s+(?P
\S+) - \s*(?Pas-set)* - \s*(?Psummary-only)* + \s*(?Pas-set)? + \s*(?Psummary-only)? $""", re.VERBOSE, ), @@ -410,8 +410,7 @@ class Bgp_address_familyTemplate14(NetworkTemplate): \s+network \s+(?P
\S+) \s+path-limit - \s+(?P\S+) - *$""", + \s+(?P\S+)\s*$""", re.VERBOSE, ), "setval": _tmplt_bgp_af_network, @@ -444,8 +443,7 @@ class Bgp_address_familyTemplate14(NetworkTemplate): \s+network \s+(?P
\S+) \s+route-map - \s+(?P\S+) - *$""", + \s+(?P\S+)\s*$""", re.VERBOSE, ), "setval": _tmplt_bgp_af_network, @@ -508,8 +506,7 @@ class Bgp_address_familyTemplate14(NetworkTemplate): \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, @@ -542,8 +539,7 @@ class Bgp_address_familyTemplate14(NetworkTemplate): \s+redistribute \s+(?P\S+) \s+route-map - \s+(?P\S+) - *$""", + \s+(?P\S+)\s*$""", re.VERBOSE, ), "setval": _tmplt_bgp_af_redistribute, @@ -575,8 +571,7 @@ class Bgp_address_familyTemplate14(NetworkTemplate): \s+(?P\S+)-unicast \s+redistribute \s+table - \s+(?P\S+) - *$""", + \s+(?P\S+)\s*$""", re.VERBOSE, ), "setval": _tmplt_bgp_af_redistribute, @@ -663,8 +658,7 @@ class Bgp_address_familyTemplate14(NetworkTemplate): \s+(?P\S+)-unicast \s+allowas-in \s+number - \s+(?P\S+) - *$""", + \s+(?P\S+)\s*$""", re.VERBOSE, ), "setval": _tmplt_bgp_af_neighbor, @@ -875,8 +869,7 @@ class Bgp_address_familyTemplate14(NetworkTemplate): \s+(?P\S+)-unicast \s+capability \s+prefix-list - \s+(?P\S+) - *$""", + \s+(?P\S+)\s*$""", re.VERBOSE, ), "setval": _tmplt_bgp_af_neighbor, @@ -912,8 +905,7 @@ class Bgp_address_familyTemplate14(NetworkTemplate): \s+(?P\S+)-unicast \s+default-originate \s+route-map - \s+(?P\S+) - *$""", + \s+(?P\S+)\s*$""", re.VERBOSE, ), "setval": _tmplt_bgp_af_neighbor, @@ -987,8 +979,7 @@ class Bgp_address_familyTemplate14(NetworkTemplate): \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, @@ -1027,8 +1018,7 @@ class Bgp_address_familyTemplate14(NetworkTemplate): \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, @@ -1066,8 +1056,7 @@ class Bgp_address_familyTemplate14(NetworkTemplate): \s+address-family \s+(?P\S+)-unicast \s+maximum-prefix - \s+(?P\S+) - *$""", + \s+(?P\S+)\s*$""", re.VERBOSE, ), "setval": _tmplt_bgp_af_neighbor, @@ -1166,8 +1155,7 @@ class Bgp_address_familyTemplate14(NetworkTemplate): \s+address-family \s+(?P\S+)-unicast \s+peer-group - \s+(?P\S+) - *$""", + \s+(?P\S+)\s*$""", re.VERBOSE, ), "setval": _tmplt_bgp_af_neighbor, @@ -1234,8 +1222,7 @@ class Bgp_address_familyTemplate14(NetworkTemplate): \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, @@ -1373,8 +1360,7 @@ class Bgp_address_familyTemplate14(NetworkTemplate): \s+address-family \s+(?P\S+)-unicast \s+unsuppress-map - \s+(?P\S+) - *$""", + \s+(?P\S+)\s*$""", re.VERBOSE, ), "setval": _tmplt_bgp_af_neighbor, @@ -1407,8 +1393,7 @@ class Bgp_address_familyTemplate14(NetworkTemplate): \s+address-family \s+(?P\S+)-unicast \s+weight - \s+(?P\S+) - *$""", + \s+(?P\S+)\s*$""", re.VERBOSE, ), "setval": _tmplt_bgp_af_neighbor, 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 @@ -237,8 +237,7 @@ class Bgp_globalTemplate(NetworkTemplate): \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 }}", @@ -437,8 +436,7 @@ class Bgp_globalTemplate(NetworkTemplate): \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 }}", @@ -467,8 +465,7 @@ class Bgp_globalTemplate(NetworkTemplate): \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 }}", @@ -494,8 +491,7 @@ class Bgp_globalTemplate(NetworkTemplate): \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 }}", @@ -573,8 +569,7 @@ class Bgp_globalTemplate(NetworkTemplate): \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 }}", @@ -633,8 +628,7 @@ class Bgp_globalTemplate(NetworkTemplate): \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 }}", @@ -661,8 +655,7 @@ class Bgp_globalTemplate(NetworkTemplate): \s+(?P
\S+) \s+filter-list \s+(?Pexport|import) - \s+(?P\S+) - *$""", + \s+(?P\S+)\s*$""", re.VERBOSE, ), "setval": _tmplt_bgp_neighbor_filter_list, @@ -721,8 +714,7 @@ class Bgp_globalTemplate(NetworkTemplate): \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 }}", @@ -826,8 +818,7 @@ class Bgp_globalTemplate(NetworkTemplate): \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 }}", @@ -853,8 +844,7 @@ class Bgp_globalTemplate(NetworkTemplate): \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 }}", @@ -880,8 +870,7 @@ class Bgp_globalTemplate(NetworkTemplate): \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 }}", @@ -908,8 +897,7 @@ class Bgp_globalTemplate(NetworkTemplate): \s+(?P
\S+) \s+prefix-list \s+(?Pexport|import) - \s+(?P\S+) - *$""", + \s+(?P\S+)\s*$""", re.VERBOSE, ), "setval": _tmplt_bgp_neighbor_prefix_list, @@ -940,8 +928,7 @@ class Bgp_globalTemplate(NetworkTemplate): \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 }}", @@ -994,8 +981,7 @@ class Bgp_globalTemplate(NetworkTemplate): \s+(?P
\S+) \s+route-map \s+(?Pexport|import) - \s+(?P\S+) - *$""", + \s+(?P\S+)\s*$""", re.VERBOSE, ), "setval": _tmplt_bgp_neighbor_route_map, @@ -1157,8 +1143,7 @@ class Bgp_globalTemplate(NetworkTemplate): \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 }}", @@ -1184,8 +1169,7 @@ class Bgp_globalTemplate(NetworkTemplate): \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 }}", @@ -1211,8 +1195,7 @@ class Bgp_globalTemplate(NetworkTemplate): \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 }}", @@ -1238,8 +1221,7 @@ class Bgp_globalTemplate(NetworkTemplate): \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 }}", @@ -1266,8 +1248,7 @@ class Bgp_globalTemplate(NetworkTemplate): \s+(?P
\S+) \s+timers \s+(?Pconnect|holdtime|keepalive) - \s+(?P\S+) - *$""", + \s+(?P\S+)\s*$""", re.VERBOSE, ), "setval": _tmplt_bgp_neighbor_timers, @@ -1295,8 +1276,7 @@ class Bgp_globalTemplate(NetworkTemplate): \s+(?P\d+) \s+timers \s+(?P\S+) - \s+(?P\S+) - *$""", + \s+(?P\S+)\s*$""", re.VERBOSE, ), "setval": _tmplt_bgp_timers, @@ -1418,8 +1398,7 @@ class Bgp_globalTemplate(NetworkTemplate): \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 }}", @@ -1442,8 +1421,7 @@ class Bgp_globalTemplate(NetworkTemplate): \s+parameters \s+confederation \s+(?Pidentifier|peers) - \s+(?P\S+) - *$""", + \s+(?P\S+)\s*$""", re.VERBOSE, ), "setval": _tmplt_bgp_params_confederation, @@ -1471,8 +1449,7 @@ class Bgp_globalTemplate(NetworkTemplate): \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}}", @@ -1497,8 +1474,7 @@ class Bgp_globalTemplate(NetworkTemplate): \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}}", @@ -1523,8 +1499,7 @@ class Bgp_globalTemplate(NetworkTemplate): \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}}", @@ -1549,8 +1524,7 @@ class Bgp_globalTemplate(NetworkTemplate): \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}}", @@ -1574,9 +1548,8 @@ class Bgp_globalTemplate(NetworkTemplate): \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, @@ -1648,8 +1621,7 @@ class Bgp_globalTemplate(NetworkTemplate): \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 }}", @@ -1678,8 +1650,7 @@ class Bgp_globalTemplate(NetworkTemplate): \s+parameters \s+distance\sglobal \s+(?P\S+) - \s+(?P\S+) - *$""", + \s+(?P\S+)\s*$""", re.VERBOSE, ), "setval": _tmplt_bgp_params_distance, @@ -1729,8 +1700,7 @@ class Bgp_globalTemplate(NetworkTemplate): \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 }}", @@ -1818,8 +1788,7 @@ class Bgp_globalTemplate(NetworkTemplate): \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 }}", 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 @@ -234,8 +234,7 @@ class Bgp_globalTemplate14(NetworkTemplate): \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 }}", @@ -427,8 +426,7 @@ class Bgp_globalTemplate14(NetworkTemplate): \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 }}", @@ -456,8 +454,7 @@ class Bgp_globalTemplate14(NetworkTemplate): \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 }}", @@ -482,8 +479,7 @@ class Bgp_globalTemplate14(NetworkTemplate): \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 }}", @@ -558,8 +554,7 @@ class Bgp_globalTemplate14(NetworkTemplate): \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 }}", @@ -616,8 +611,7 @@ class Bgp_globalTemplate14(NetworkTemplate): \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 }}", @@ -643,8 +637,7 @@ class Bgp_globalTemplate14(NetworkTemplate): \s+(?P
\S+) \s+filter-list \s+(?Pexport|import) - \s+(?P\S+) - *$""", + \s+(?P\S+)\s*$""", re.VERBOSE, ), "setval": _tmplt_bgp_neighbor_filter_list, @@ -701,8 +694,7 @@ class Bgp_globalTemplate14(NetworkTemplate): \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 }}", @@ -802,8 +794,7 @@ class Bgp_globalTemplate14(NetworkTemplate): \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 }}", @@ -828,8 +819,7 @@ class Bgp_globalTemplate14(NetworkTemplate): \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 }}", @@ -854,8 +844,7 @@ class Bgp_globalTemplate14(NetworkTemplate): \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 }}", @@ -881,8 +870,7 @@ class Bgp_globalTemplate14(NetworkTemplate): \s+(?P
\S+) \s+prefix-list \s+(?Pexport|import) - \s+(?P\S+) - *$""", + \s+(?P\S+)\s*$""", re.VERBOSE, ), "setval": _tmplt_bgp_neighbor_prefix_list, @@ -912,8 +900,7 @@ class Bgp_globalTemplate14(NetworkTemplate): \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 }}", @@ -964,8 +951,7 @@ class Bgp_globalTemplate14(NetworkTemplate): \s+(?P
\S+) \s+route-map \s+(?Pexport|import) - \s+(?P\S+) - *$""", + \s+(?P\S+)\s*$""", re.VERBOSE, ), "setval": _tmplt_bgp_neighbor_route_map, @@ -1121,8 +1107,7 @@ class Bgp_globalTemplate14(NetworkTemplate): \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 }}", @@ -1147,8 +1132,7 @@ class Bgp_globalTemplate14(NetworkTemplate): \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 }}", @@ -1173,8 +1157,7 @@ class Bgp_globalTemplate14(NetworkTemplate): \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 }}", @@ -1199,8 +1182,7 @@ class Bgp_globalTemplate14(NetworkTemplate): \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 }}", @@ -1226,8 +1208,7 @@ class Bgp_globalTemplate14(NetworkTemplate): \s+(?P
\S+) \s+timers \s+(?Pconnect|holdtime|keepalive) - \s+(?P\S+) - *$""", + \s+(?P\S+)\s*$""", re.VERBOSE, ), "setval": _tmplt_bgp_neighbor_timers, @@ -1254,8 +1235,7 @@ class Bgp_globalTemplate14(NetworkTemplate): \s+bgp \s+timers \s+(?P\S+) - \s+(?P\S+) - *$""", + \s+(?P\S+)\s*$""", re.VERBOSE, ), "setval": _tmplt_bgp_timers, @@ -1372,8 +1352,7 @@ class Bgp_globalTemplate14(NetworkTemplate): \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 }}", @@ -1395,8 +1374,7 @@ class Bgp_globalTemplate14(NetworkTemplate): \s+parameters \s+confederation \s+(?Pidentifier|peers) - \s+(?P\S+) - *$""", + \s+(?P\S+)\s*$""", re.VERBOSE, ), "setval": _tmplt_bgp_params_confederation, @@ -1423,8 +1401,7 @@ class Bgp_globalTemplate14(NetworkTemplate): \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}}", @@ -1448,8 +1425,7 @@ class Bgp_globalTemplate14(NetworkTemplate): \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}}", @@ -1473,8 +1449,7 @@ class Bgp_globalTemplate14(NetworkTemplate): \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}}", @@ -1498,8 +1473,7 @@ class Bgp_globalTemplate14(NetworkTemplate): \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}}", @@ -1522,9 +1496,8 @@ class Bgp_globalTemplate14(NetworkTemplate): \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, @@ -1593,8 +1566,7 @@ class Bgp_globalTemplate14(NetworkTemplate): \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 }}", @@ -1622,8 +1594,7 @@ class Bgp_globalTemplate14(NetworkTemplate): \s+parameters \s+distance\sglobal \s+(?P\S+) - \s+(?P\S+) - *$""", + \s+(?P\S+)\s*$""", re.VERBOSE, ), "setval": _tmplt_bgp_params_distance, @@ -1671,8 +1642,7 @@ class Bgp_globalTemplate14(NetworkTemplate): \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 }}", @@ -1756,8 +1726,7 @@ class Bgp_globalTemplate14(NetworkTemplate): \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 }}", 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 @@ -365,8 +365,7 @@ class Ospf_interfacesTemplate(NetworkTemplate): \s+(?Pospf|ospfv3) \s+authentication \s+plaintext-password - \s+(?P\S+) - *$""", + \s+(?P\S+)\s*$""", re.VERBOSE, ), "setval": _tmplt_ospf_int_auth_password, @@ -399,8 +398,7 @@ class Ospf_interfacesTemplate(NetworkTemplate): \s+key-id \s+(?P\d+) \s+md5-key - \s+(?P\S+) - *$""", + \s+(?P\S+)\s*$""", re.VERBOSE, ), "setval": _tmplt_ospf_int_auth_md5, @@ -572,8 +570,7 @@ class Ospf_interfacesTemplate(NetworkTemplate): \s+(?Pip|ipv6) \s+(?Pospf|ospfv3) \s+network - \s+(?P\S+) - *$""", + \s+(?P\S+)\s*$""", re.VERBOSE, ), "setval": _tmplt_ospf_int_network, 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 @@ -240,8 +240,7 @@ class Ospf_interfacesTemplate14(NetworkTemplate): \s+protocols \s+(?Pospf|ospfv3) \s+interface - \s+(?P\S+) - *$""", + \s+(?P\S+)\s*$""", re.VERBOSE, ), "remval": _tmplt_ospf_int_delete, @@ -266,8 +265,7 @@ class Ospf_interfacesTemplate14(NetworkTemplate): \s+(?P\S+) \s+authentication \s+plaintext-password - \s+(?P\S+) - *$""", + \s+(?P\S+)\s*$""", re.VERBOSE, ), "setval": _tmplt_ospf_int_auth_password, @@ -298,8 +296,7 @@ class Ospf_interfacesTemplate14(NetworkTemplate): \s+key-id \s+(?P\d+) \s+md5-key - \s+(?P\S+) - *$""", + \s+(?P\S+)\s*$""", re.VERBOSE, ), "setval": _tmplt_ospf_int_auth_md5, @@ -459,8 +456,7 @@ class Ospf_interfacesTemplate14(NetworkTemplate): \s+interface \s+(?P\S+) \s+network - \s+(?P\S+) - *$""", + \s+(?P\S+)\s*$""", re.VERBOSE, ), "setval": _tmplt_ospf_int_network, 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 @@ -33,8 +33,7 @@ class Route_mapsTemplate(NetworkTemplate): "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", @@ -51,8 +50,7 @@ class Route_mapsTemplate(NetworkTemplate): "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", @@ -75,8 +73,7 @@ class Route_mapsTemplate(NetworkTemplate): "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}}", @@ -99,8 +96,7 @@ class Route_mapsTemplate(NetworkTemplate): "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}}", @@ -123,8 +119,7 @@ class Route_mapsTemplate(NetworkTemplate): "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}}", @@ -147,8 +142,7 @@ class Route_mapsTemplate(NetworkTemplate): "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}}", @@ -171,8 +165,7 @@ class Route_mapsTemplate(NetworkTemplate): "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", @@ -198,8 +191,7 @@ class Route_mapsTemplate(NetworkTemplate): "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", @@ -225,8 +217,7 @@ class Route_mapsTemplate(NetworkTemplate): "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", @@ -254,8 +245,7 @@ class Route_mapsTemplate(NetworkTemplate): "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", @@ -283,8 +273,7 @@ class Route_mapsTemplate(NetworkTemplate): "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", @@ -337,8 +326,7 @@ class Route_mapsTemplate(NetworkTemplate): "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", @@ -364,8 +352,7 @@ class Route_mapsTemplate(NetworkTemplate): "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", @@ -392,8 +379,7 @@ class Route_mapsTemplate(NetworkTemplate): "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", @@ -420,8 +406,7 @@ class Route_mapsTemplate(NetworkTemplate): "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", @@ -448,8 +433,7 @@ class Route_mapsTemplate(NetworkTemplate): "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", @@ -476,8 +460,7 @@ class Route_mapsTemplate(NetworkTemplate): "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", @@ -504,8 +487,7 @@ class Route_mapsTemplate(NetworkTemplate): "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", @@ -532,8 +514,8 @@ class Route_mapsTemplate(NetworkTemplate): "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", @@ -560,8 +542,7 @@ class Route_mapsTemplate(NetworkTemplate): "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", @@ -590,8 +571,7 @@ class Route_mapsTemplate(NetworkTemplate): 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", @@ -621,8 +601,7 @@ class Route_mapsTemplate(NetworkTemplate): "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", @@ -649,8 +628,7 @@ class Route_mapsTemplate(NetworkTemplate): "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", @@ -677,8 +655,7 @@ class Route_mapsTemplate(NetworkTemplate): "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", @@ -705,8 +682,7 @@ class Route_mapsTemplate(NetworkTemplate): "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", @@ -733,8 +709,7 @@ class Route_mapsTemplate(NetworkTemplate): "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", @@ -761,8 +736,7 @@ class Route_mapsTemplate(NetworkTemplate): "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", @@ -789,8 +763,7 @@ class Route_mapsTemplate(NetworkTemplate): "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", @@ -817,8 +790,7 @@ class Route_mapsTemplate(NetworkTemplate): "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", @@ -845,8 +817,7 @@ class Route_mapsTemplate(NetworkTemplate): "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", @@ -873,8 +844,7 @@ class Route_mapsTemplate(NetworkTemplate): "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", @@ -901,8 +871,7 @@ class Route_mapsTemplate(NetworkTemplate): "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", @@ -931,8 +900,7 @@ class Route_mapsTemplate(NetworkTemplate): "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", @@ -959,8 +927,7 @@ class Route_mapsTemplate(NetworkTemplate): "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", @@ -987,8 +954,7 @@ class Route_mapsTemplate(NetworkTemplate): "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", @@ -1015,8 +981,7 @@ class Route_mapsTemplate(NetworkTemplate): "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", @@ -1043,8 +1008,7 @@ class Route_mapsTemplate(NetworkTemplate): "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", @@ -1071,8 +1035,7 @@ class Route_mapsTemplate(NetworkTemplate): "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", @@ -1099,8 +1062,7 @@ class Route_mapsTemplate(NetworkTemplate): "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", @@ -1127,8 +1089,7 @@ class Route_mapsTemplate(NetworkTemplate): "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", @@ -1155,8 +1116,7 @@ class Route_mapsTemplate(NetworkTemplate): "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", @@ -1185,8 +1145,7 @@ class Route_mapsTemplate(NetworkTemplate): 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", @@ -1219,8 +1178,7 @@ class Route_mapsTemplate(NetworkTemplate): 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", @@ -1253,8 +1211,7 @@ class Route_mapsTemplate(NetworkTemplate): 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", @@ -1287,8 +1244,7 @@ class Route_mapsTemplate(NetworkTemplate): 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", @@ -1320,8 +1276,7 @@ class Route_mapsTemplate(NetworkTemplate): "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", @@ -1349,8 +1304,7 @@ class Route_mapsTemplate(NetworkTemplate): "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", @@ -1377,8 +1331,7 @@ class Route_mapsTemplate(NetworkTemplate): "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", 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 @@ -33,8 +33,7 @@ class Route_mapsTemplate14(NetworkTemplate): "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", @@ -75,8 +74,7 @@ class Route_mapsTemplate14(NetworkTemplate): "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}}", @@ -99,8 +97,7 @@ class Route_mapsTemplate14(NetworkTemplate): "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}}", @@ -123,8 +120,7 @@ class Route_mapsTemplate14(NetworkTemplate): "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}}", @@ -147,8 +143,7 @@ class Route_mapsTemplate14(NetworkTemplate): "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}}", @@ -198,8 +193,7 @@ class Route_mapsTemplate14(NetworkTemplate): "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", @@ -225,8 +219,7 @@ class Route_mapsTemplate14(NetworkTemplate): "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", @@ -254,8 +247,7 @@ class Route_mapsTemplate14(NetworkTemplate): "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", @@ -283,8 +275,7 @@ class Route_mapsTemplate14(NetworkTemplate): "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", @@ -364,8 +355,7 @@ class Route_mapsTemplate14(NetworkTemplate): "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", @@ -392,8 +382,7 @@ class Route_mapsTemplate14(NetworkTemplate): "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", @@ -420,8 +409,7 @@ class Route_mapsTemplate14(NetworkTemplate): "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", @@ -448,8 +436,7 @@ class Route_mapsTemplate14(NetworkTemplate): "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", @@ -476,8 +463,7 @@ class Route_mapsTemplate14(NetworkTemplate): "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", @@ -504,8 +490,7 @@ class Route_mapsTemplate14(NetworkTemplate): "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", @@ -560,8 +545,7 @@ class Route_mapsTemplate14(NetworkTemplate): "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", @@ -590,8 +574,7 @@ class Route_mapsTemplate14(NetworkTemplate): 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", @@ -649,8 +632,7 @@ class Route_mapsTemplate14(NetworkTemplate): "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", @@ -677,8 +659,7 @@ class Route_mapsTemplate14(NetworkTemplate): "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", @@ -705,8 +686,7 @@ class Route_mapsTemplate14(NetworkTemplate): "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", @@ -733,8 +713,7 @@ class Route_mapsTemplate14(NetworkTemplate): "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", @@ -761,8 +740,7 @@ class Route_mapsTemplate14(NetworkTemplate): "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", @@ -789,8 +767,7 @@ class Route_mapsTemplate14(NetworkTemplate): "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", @@ -817,8 +794,7 @@ class Route_mapsTemplate14(NetworkTemplate): "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", @@ -845,8 +821,7 @@ class Route_mapsTemplate14(NetworkTemplate): "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", @@ -873,8 +848,7 @@ class Route_mapsTemplate14(NetworkTemplate): "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", @@ -931,8 +905,7 @@ class Route_mapsTemplate14(NetworkTemplate): "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", @@ -959,8 +932,7 @@ class Route_mapsTemplate14(NetworkTemplate): "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", @@ -1015,8 +987,7 @@ class Route_mapsTemplate14(NetworkTemplate): "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", @@ -1043,8 +1014,7 @@ class Route_mapsTemplate14(NetworkTemplate): "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", @@ -1071,8 +1041,7 @@ class Route_mapsTemplate14(NetworkTemplate): "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", @@ -1099,8 +1068,7 @@ class Route_mapsTemplate14(NetworkTemplate): "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", @@ -1127,8 +1095,7 @@ class Route_mapsTemplate14(NetworkTemplate): "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", @@ -1155,8 +1122,7 @@ class Route_mapsTemplate14(NetworkTemplate): "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", @@ -1185,8 +1151,7 @@ class Route_mapsTemplate14(NetworkTemplate): 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", @@ -1219,8 +1184,7 @@ class Route_mapsTemplate14(NetworkTemplate): 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", @@ -1253,8 +1217,7 @@ class Route_mapsTemplate14(NetworkTemplate): 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", @@ -1287,8 +1250,7 @@ class Route_mapsTemplate14(NetworkTemplate): 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", @@ -1320,8 +1282,7 @@ class Route_mapsTemplate14(NetworkTemplate): "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", @@ -1349,8 +1310,7 @@ class Route_mapsTemplate14(NetworkTemplate): "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", @@ -1377,8 +1337,7 @@ class Route_mapsTemplate14(NetworkTemplate): "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", 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 @@ -140,9 +140,9 @@ class Snmp_serverTemplate(NetworkTemplate): 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, ), @@ -164,8 +164,7 @@ class Snmp_serverTemplate(NetworkTemplate): "getval": re.compile( r""" ^set\sservice\ssnmp\scontact - \s+(?P\S+) - *$""", + \s+(?P\S+)\s*$""", re.VERBOSE, ), "setval": "service snmp contact {{ contact }}", @@ -179,8 +178,7 @@ class Snmp_serverTemplate(NetworkTemplate): "getval": re.compile( r""" ^set\sservice\ssnmp\sdescription - \s+(?P\S+) - *$""", + \s+(?P\S+)\s*$""", re.VERBOSE, ), "setval": "service snmp description {{ description }}", @@ -195,8 +193,8 @@ class Snmp_serverTemplate(NetworkTemplate): r""" ^set\sservice\ssnmp\slisten-address \s+(?P\S+) - \s*(port)* - \s*(?P\d+)* + \s*(port)? + \s*(?P\d+)? $""", re.VERBOSE, ), @@ -232,8 +230,7 @@ class Snmp_serverTemplate(NetworkTemplate): "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 }}", @@ -247,8 +244,7 @@ class Snmp_serverTemplate(NetworkTemplate): "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 }}", @@ -263,9 +259,8 @@ class Snmp_serverTemplate(NetworkTemplate): 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, @@ -283,8 +278,7 @@ class Snmp_serverTemplate(NetworkTemplate): "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 }}", @@ -301,9 +295,9 @@ class Snmp_serverTemplate(NetworkTemplate): 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, ), @@ -329,9 +323,9 @@ class Snmp_serverTemplate(NetworkTemplate): ^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, ), @@ -358,8 +352,7 @@ class Snmp_serverTemplate(NetworkTemplate): 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 }}", @@ -381,7 +374,7 @@ class Snmp_serverTemplate(NetworkTemplate): r""" ^set\sservice\ssnmp\sv3\strap-target \s+(?P\S+) - \s+(?Pprotocol\s\S+)* + \s+(?Pprotocol\s\S+)? $""", re.VERBOSE, ), @@ -404,7 +397,7 @@ class Snmp_serverTemplate(NetworkTemplate): r""" ^set\sservice\ssnmp\sv3\strap-target \s+(?P\S+) - \s+(?Ptype\s\S+)* + \s+(?Ptype\s\S+)? $""", re.VERBOSE, ), @@ -427,7 +420,7 @@ class Snmp_serverTemplate(NetworkTemplate): r""" ^set\sservice\ssnmp\sv3\strap-target \s+(?P\S+) - \s+(?Puser\s\S+)* + \s+(?Puser\s\S+)? $""", re.VERBOSE, ), @@ -451,9 +444,9 @@ class Snmp_serverTemplate(NetworkTemplate): ^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, ), @@ -481,9 +474,9 @@ class Snmp_serverTemplate(NetworkTemplate): ^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, ), @@ -511,9 +504,9 @@ class Snmp_serverTemplate(NetworkTemplate): ^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, ), @@ -540,8 +533,7 @@ class Snmp_serverTemplate(NetworkTemplate): 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 }}", @@ -563,7 +555,7 @@ class Snmp_serverTemplate(NetworkTemplate): r""" ^set\sservice\ssnmp\sv3\suser \s+(?P\S+) - \s+(?Pmode\s\S+)* + \s+(?Pmode\s\S+)? $""", re.VERBOSE, ), @@ -587,8 +579,8 @@ class Snmp_serverTemplate(NetworkTemplate): ^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, ), 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." + ) -- cgit v1.2.3 From 6d7a2184e970624f74f333931f7f70a1f900f7b5 Mon Sep 17 00:00:00 2001 From: Stavros Kroustouris Date: Thu, 25 Jun 2026 22:30:57 +0300 Subject: T2295: vyos_user: quote plaintext-password in generated set commands (#480) * vyos_user: quote plaintext-password in generated set commands VyOS requires quoted values for passwords with special characters. Align with encrypted-password and integration test conventions. Co-authored-by: Cursor * T2295: escape plaintext-password values in vyos_user set commands Quote passwords for VyOS special-character handling and escape embedded single quotes. Update RETURN sample, add unit tests, refresh changelog. Co-authored-by: Cursor * T2295: shorten changelog fragment for ansible-lint line-length Co-authored-by: Cursor * T2295: use shlex.quote() for plaintext-password values Replace custom _quote_config_value() with stdlib shlex.quote() per review feedback; update unit tests and RETURN sample accordingly. Co-authored-by: Cursor * T2295: add complex plaintext-password quoting unit test Cover spaces, shell metacharacters, embedded quotes, and backslashes in one password; assert command output matches shlex.quote(). Co-authored-by: Cursor * T2295: assert explicit quoting in complex password unit test Replace shlex.quote()-derived expectation with a fixed command string, matching the other password quoting tests. Co-authored-by: Cursor * Fix RETURN doc sample, add docstrings and workflow permissions - RETURN sample was missing the username token in the example command - Add docstrings to all undocumented module-level functions to bring docstring coverage above the 80% threshold - Add explicit permissions: contents: read to codecoverage.yml Co-Authored-By: Claude Sonnet 4.6 * Revert "Fix RETURN doc sample, add docstrings and workflow permissions" This reverts commit 827809ee49cf472a8bf30ec0b24d347a75fcb083. --------- Co-authored-by: Cursor Co-authored-by: omnom62 <75066712+omnom62@users.noreply.github.com> Co-authored-by: Claude Sonnet 4.6 --- .../vyos-user-quote-plaintext-password.yml | 3 +++ plugins/modules/vyos_user.py | 4 ++- tests/unit/modules/network/vyos/test_vyos_user.py | 30 ++++++++++++++++++++++ 3 files changed, 36 insertions(+), 1 deletion(-) create mode 100644 changelogs/fragments/vyos-user-quote-plaintext-password.yml (limited to 'plugins') 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/modules/vyos_user.py b/plugins/modules/vyos_user.py index d2f23509..e47f5a05 100644 --- a/plugins/modules/vyos_user.py +++ b/plugins/modules/vyos_user.py @@ -205,6 +205,7 @@ commands: """ import re +import shlex from copy import deepcopy from functools import partial @@ -276,7 +277,8 @@ def spec_to_commands(updates, module): add( commands, want, - "authentication plaintext-password %s" % want["configured_password"], + "authentication plaintext-password %s" + % shlex.quote(want["configured_password"]), ) return commands 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 @@ -62,6 +62,36 @@ class TestVyosUserModule(TestVyosModule): ["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) -- cgit v1.2.3 From 0e10d136ef280ca147b6f1e332072f6ba14c8844 Mon Sep 17 00:00:00 2001 From: Yuriy Andamasov Date: Tue, 30 Jun 2026 14:18:50 +0300 Subject: T8522: fix parse_icmp_attr() split delimiter and UnboundLocalError (#464) * Add easy-wins improvement spec for vyos.vyos collection Covers five phases: formatting compliance, runtime.yml redirect fix, deprecated feature cleanup, missing unit tests, and template deduplication. Co-Authored-By: Claude Opus 4.6 (1M context) * Add implementation plan for easy-wins improvements 15 tasks across 5 phases: formatting compliance, runtime.yml bugfix, deprecated code cleanup, missing unit tests, template deduplication. Co-Authored-By: Claude Opus 4.6 (1M context) * Update spec and plan with architect review corrections Key changes: - Defer Phase 5 (template deduplication) to v7.0.0: route_maps are not identical, BGP dedup blocked by Python module-level scoping, OSPF has fundamentally different command paradigms - Add .git-blame-ignore-revs step to Phase 1 - Add missing test cases: overridden/rendered for resource modules, aggregate/purge/with_address for vyos_vlan - Fix incorrect claim that version.py LooseVersion is unused - Add sequential merge requirement to preamble Co-Authored-By: Claude Opus 4.6 (1M context) * chore: add .worktrees/ and .claude/ to .gitignore * T8522: fix parse_icmp_attr() split delimiter and UnboundLocalError - Use val.split("/") instead of val.split(".") when parsing type/code pairs - In the numeric-only branch, use int(val) instead of the undefined type_no variable - Cast both type and code to int for consistent typing Co-Authored-By: Claude Sonnet 4.6 * T8522: remove unrelated planning docs and gitignore changes These files were included from local main branch commits unrelated to this bugfix. This commit removes them to keep the PR scoped. Co-Authored-By: Claude Sonnet 4.6 * T8522: add parsed test for legacy type/code ICMP format Co-Authored-By: Claude Sonnet 4.6 --------- Co-authored-by: Claude Opus 4.6 (1M context) Co-authored-by: omnom62 <75066712+omnom62@users.noreply.github.com> --- changelogs/fragments/fix-icmp-parse-attr.yml | 5 +++++ .../network/vyos/facts/firewall_rules/firewall_rules.py | 8 ++++---- .../modules/network/vyos/test_vyos_firewall_rules13.py | 14 ++++++++++++++ 3 files changed, 23 insertions(+), 4 deletions(-) create mode 100644 changelogs/fragments/fix-icmp-parse-attr.yml (limited to 'plugins') 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/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 @@ -412,11 +412,11 @@ class Firewall_rulesFacts(object): # <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 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 @@ -1576,3 +1576,17 @@ class TestVyosFirewallRulesModule13(TestVyosModule): ] 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) -- cgit v1.2.3