From c0deb11a5c0e678f1a2b3d4b34d3ee40db6478dc Mon Sep 17 00:00:00 2001 From: Christian Breunig Date: Thu, 6 Nov 2025 21:28:42 +0100 Subject: smoketest: T7996: vrf CLI path is always deleted in tearDown() --- smoketest/scripts/cli/test_vrf.py | 1 - 1 file changed, 1 deletion(-) (limited to 'smoketest/scripts/cli') diff --git a/smoketest/scripts/cli/test_vrf.py b/smoketest/scripts/cli/test_vrf.py index 456295b49..0c77e899d 100755 --- a/smoketest/scripts/cli/test_vrf.py +++ b/smoketest/scripts/cli/test_vrf.py @@ -834,7 +834,6 @@ class VRFTest(VyOSUnitTestSHIM.TestCase): self.cli_delete(['interfaces', 'virtual-ethernet']) self.cli_delete(['service', 'dhcp-server']) - self.cli_delete(['vrf', 'name', vrf_name]) def test_dhcpv6_single_pool(self): # Prepare the vrf and other options -- cgit v1.2.3 From 874eabd1bcaa1f37388020ec2f0f3a13624619ad Mon Sep 17 00:00:00 2001 From: Christian Breunig Date: Thu, 6 Nov 2025 21:31:38 +0100 Subject: smoketest: T7996: fix hardcoded "vrf red" search path in FRR config Commit 186900f7165b2 ("smoketest: T7927: test DHCP route preservation") which was added to validate a bugfix for DHCP default routes added it's own little regression. Tests defined a VRF named red15, but when reading in the FRR configuration we have had a hardcoded search for "vrf red" instead. This has been fixed to re-use the defined VRF variable name we perform our test on. --- smoketest/scripts/cli/test_vrf.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'smoketest/scripts/cli') diff --git a/smoketest/scripts/cli/test_vrf.py b/smoketest/scripts/cli/test_vrf.py index 0c77e899d..e1897eb8d 100755 --- a/smoketest/scripts/cli/test_vrf.py +++ b/smoketest/scripts/cli/test_vrf.py @@ -819,7 +819,7 @@ class VRFTest(VyOSUnitTestSHIM.TestCase): # We need to wait until DHCP client has started and an IP address has been received sleep(8) - frrconfig = self.getFRRconfig('^vrf red', stop_section='^exit-vrf') + frrconfig = self.getFRRconfig(f'^vrf {vrf_name}', stop_section='^exit-vrf') self.assertIn(f' ip route 0.0.0.0/0 {default_gateway} {dhcp_if_client} '\ f'tag 210 {default_distance}', frrconfig) @@ -828,7 +828,7 @@ class VRFTest(VyOSUnitTestSHIM.TestCase): self.cli_set(['protocols', 'static', 'route', '10.0.0.0/24', 'blackhole']) self.cli_commit() - frrconfig = self.getFRRconfig('^vrf red', stop_section='^exit-vrf') + frrconfig = self.getFRRconfig(f'^vrf {vrf_name}', stop_section='^exit-vrf') self.assertIn(f' ip route 0.0.0.0/0 {default_gateway} {dhcp_if_client} '\ f'tag 210 {default_distance}', frrconfig) -- cgit v1.2.3 From da679f0cf8fe048bae7d648a4f447db47032f3c0 Mon Sep 17 00:00:00 2001 From: Christian Breunig Date: Thu, 6 Nov 2025 21:33:59 +0100 Subject: smoketest: T7996: replace hardcoded sleep(8) in VRF test with wait_for() The original VRF DHCP test case, introduced in commit 186900f7165b2 ("smoketest: T7927: test DHCP route preservation"), used a fixed delay of 8 seconds to wait for the DHCP server and client to initialize. This approach was unreliable and could cause unnecessary test delays. Since commit 354517677f ("wlb: T7977: Updated smoketest to validate nft vmap weight buckets"), the "vyos.utils.misc.wait_for()" helper provides a more efficient busy-wait loop with an early-exit condition. This test case now uses wait_for() to detect when the DHCP-assigned default route becomes available, eliminating the fixed sleep and reducing test runtime. --- smoketest/scripts/cli/test_vrf.py | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) (limited to 'smoketest/scripts/cli') diff --git a/smoketest/scripts/cli/test_vrf.py b/smoketest/scripts/cli/test_vrf.py index e1897eb8d..f941867e1 100755 --- a/smoketest/scripts/cli/test_vrf.py +++ b/smoketest/scripts/cli/test_vrf.py @@ -20,7 +20,6 @@ import unittest from json import loads from jmespath import search -from time import sleep from base_vyostest_shim import VyOSUnitTestSHIM @@ -28,6 +27,7 @@ from vyos.configsession import ConfigSessionError from vyos.ifconfig import Interface from vyos.ifconfig import Section from vyos.utils.file import read_file +from vyos.utils.misc import wait_for from vyos.utils.network import get_interface_config from vyos.utils.network import get_vrf_tableid from vyos.utils.network import is_intf_addr_assigned @@ -783,8 +783,7 @@ class VRFTest(VyOSUnitTestSHIM.TestCase): def test_dhcp_vrf_default_route(self): # T7927 - when retrieving a default route via DHCP, check that additional # calls into FRRender() keep the DHCP route in place - - vrf_name = 'red15' + vrf_name = 'red-16' default_gateway = '192.0.2.1' dhcp_if_server = 'veth0' dhcp_if_client = 'veth1' @@ -816,12 +815,18 @@ class VRFTest(VyOSUnitTestSHIM.TestCase): self.cli_set(['interfaces', 'virtual-ethernet', dhcp_if_client, 'address', 'dhcp']) self.cli_commit() - # We need to wait until DHCP client has started and an IP address has been received - sleep(8) + # define helper for the string we are looking for in FRR configuration + # the leading whitespace is required as this lives under a VRF context! + test_ok_string = f' ip route 0.0.0.0/0 {default_gateway} {dhcp_if_client}'\ + f' tag 210 {default_distance}' - frrconfig = self.getFRRconfig(f'^vrf {vrf_name}', stop_section='^exit-vrf') - self.assertIn(f' ip route 0.0.0.0/0 {default_gateway} {dhcp_if_client} '\ - f'tag 210 {default_distance}', frrconfig) + def test_callback(self, vrf_name, string) -> bool: + tmp = self.getFRRconfig(f'^vrf {vrf_name}', stop_section='^exit-vrf') + return bool(string in tmp) + + # We need to wait until DHCP client has started and an IP address has been received + tmp = wait_for(test_callback, self, vrf_name, test_ok_string, timeout=20.0) + self.assertTrue(tmp) # Change anything in FRR to re-trigger config generation. DHCP route # must still be present @@ -829,8 +834,7 @@ class VRFTest(VyOSUnitTestSHIM.TestCase): self.cli_commit() frrconfig = self.getFRRconfig(f'^vrf {vrf_name}', stop_section='^exit-vrf') - self.assertIn(f' ip route 0.0.0.0/0 {default_gateway} {dhcp_if_client} '\ - f'tag 210 {default_distance}', frrconfig) + self.assertIn(test_ok_string, frrconfig) self.cli_delete(['interfaces', 'virtual-ethernet']) self.cli_delete(['service', 'dhcp-server']) -- cgit v1.2.3 From 316b31e304db92d87e63321628be21f9f4cd1387 Mon Sep 17 00:00:00 2001 From: Christian Breunig Date: Fri, 7 Nov 2025 16:41:14 +0100 Subject: smoketest: T7966: perform full regex match with ^ and $ Commit 9775bb49e ("frr: T7664: drop BASH/SED implementation in smoketest getFRRconfig()") changed how we searched strings using a regex. In the past we searched at the beginning of a line ^ till the end $. THis logic was dropped in commit 9775bb49e marking some tests failing as they matched, when they should not match. Example: getFRRconfig('vrf red') showed output for both VRF red and red15 as both started with "red". This has been fixed. --- smoketest/scripts/cli/base_vyostest_shim.py | 6 ++++-- smoketest/scripts/cli/test_policy.py | 24 ++++++++++++------------ smoketest/scripts/cli/test_protocols_static.py | 17 +++++++---------- smoketest/scripts/cli/test_system_ip.py | 6 ++++-- smoketest/scripts/cli/test_system_ipv6.py | 2 +- 5 files changed, 28 insertions(+), 27 deletions(-) (limited to 'smoketest/scripts/cli') diff --git a/smoketest/scripts/cli/base_vyostest_shim.py b/smoketest/scripts/cli/base_vyostest_shim.py index 1dcb18d4b..cf3324a15 100644 --- a/smoketest/scripts/cli/base_vyostest_shim.py +++ b/smoketest/scripts/cli/base_vyostest_shim.py @@ -140,12 +140,14 @@ class VyOSUnitTestSHIM: pprint.pprint(out) return out - def getFRRconfig(self, start_section:str=None, stop_section='^!', + def getFRRconfig(self, start_section:str=None, end_marker='$', stop_section='^!', start_subsection:str=None, stop_subsection='^ exit') -> str: """ Retrieve current "running configuration" from FRR start_section: search for a specific start string in the configuration + end_marker: override default "line end $" marker to match on an + "open end" string stop_section: end of the configuration start_subsection: search section under the result found by string stop_subsection: end of the subsection (usually something with "exit") @@ -158,7 +160,7 @@ class VyOSUnitTestSHIM: in_section = False for line in frr_config.splitlines(): if not in_section: - if re.match(start_section, line): + if re.match(f'^{start_section}{end_marker}', line): in_section = True extracted.append(line) else: diff --git a/smoketest/scripts/cli/test_policy.py b/smoketest/scripts/cli/test_policy.py index 5a700ddc1..ad3cc325b 100755 --- a/smoketest/scripts/cli/test_policy.py +++ b/smoketest/scripts/cli/test_policy.py @@ -123,7 +123,7 @@ class TestPolicy(VyOSUnitTestSHIM.TestCase): self.cli_commit() - config = self.getFRRconfig('access-list') + config = self.getFRRconfig('access-list', end_marker='') for acl, acl_config in acls.items(): for rule, rule_config in acl_config['rule'].items(): tmp = f'access-list {acl} seq {rule}' @@ -214,7 +214,7 @@ class TestPolicy(VyOSUnitTestSHIM.TestCase): self.cli_commit() - config = self.getFRRconfig('ipv6 access-list') + config = self.getFRRconfig('ipv6 access-list', end_marker='') for acl, acl_config in acls.items(): for rule, rule_config in acl_config['rule'].items(): tmp = f'ipv6 access-list {acl} seq {rule}' @@ -312,7 +312,7 @@ class TestPolicy(VyOSUnitTestSHIM.TestCase): self.cli_commit() - config = self.getFRRconfig('bgp as-path access-list') + config = self.getFRRconfig('bgp as-path access-list', end_marker='') for as_path, as_path_config in test_data.items(): if 'rule' not in as_path_config: continue @@ -370,7 +370,7 @@ class TestPolicy(VyOSUnitTestSHIM.TestCase): self.cli_commit() - config = self.getFRRconfig('bgp community-list') + config = self.getFRRconfig('bgp community-list', end_marker='') for comm_list, comm_list_config in test_data.items(): if 'rule' not in comm_list_config: continue @@ -428,7 +428,7 @@ class TestPolicy(VyOSUnitTestSHIM.TestCase): self.cli_commit() - config = self.getFRRconfig('bgp extcommunity-list') + config = self.getFRRconfig('bgp extcommunity-list', end_marker='') for comm_list, comm_list_config in test_data.items(): if 'rule' not in comm_list_config: continue @@ -493,7 +493,7 @@ class TestPolicy(VyOSUnitTestSHIM.TestCase): self.cli_commit() - config = self.getFRRconfig('bgp large-community-list') + config = self.getFRRconfig('bgp large-community-list', end_marker='') for comm_list, comm_list_config in test_data.items(): if 'rule' not in comm_list_config: continue @@ -571,7 +571,7 @@ class TestPolicy(VyOSUnitTestSHIM.TestCase): self.cli_commit() - config = self.getFRRconfig('ip prefix-list') + config = self.getFRRconfig('ip prefix-list', end_marker='') for prefix_list, prefix_list_config in test_data.items(): if 'rule' not in prefix_list_config: continue @@ -654,7 +654,7 @@ class TestPolicy(VyOSUnitTestSHIM.TestCase): self.cli_commit() - config = self.getFRRconfig('ipv6 prefix-list') + config = self.getFRRconfig('ipv6 prefix-list', end_marker='') for prefix_list, prefix_list_config in test_data.items(): if 'rule' not in prefix_list_config: continue @@ -705,7 +705,7 @@ class TestPolicy(VyOSUnitTestSHIM.TestCase): self.cli_commit() - config = self.getFRRconfig('ip prefix-list') + config = self.getFRRconfig('ip prefix-list', end_marker='') for rule in test_range: tmp = f'ip prefix-list {prefix_list} seq {rule} permit {prefix} le {rule}' self.assertIn(tmp, config) @@ -842,7 +842,7 @@ class TestPolicy(VyOSUnitTestSHIM.TestCase): self.assertIn(name, config) if 'set' in rule_config: - #Check community + # Check community if 'community' in rule_config['set']: if 'none' in rule_config['set']['community']: tmp = f'set community none' @@ -855,7 +855,7 @@ class TestPolicy(VyOSUnitTestSHIM.TestCase): values = ' '.join(rule_config['set']['community']['add']) tmp = f'set community {values} additive' self.assertIn(tmp, config) - #Check large-community + # Check large-community if 'large-community' in rule_config['set']: if 'none' in rule_config['set']['large-community']: tmp = f'set large-community none' @@ -868,7 +868,7 @@ class TestPolicy(VyOSUnitTestSHIM.TestCase): values = ' '.join(rule_config['set']['large-community']['add']) tmp = f'set large-community {values} additive' self.assertIn(tmp, config) - #Check extcommunity + # Check extcommunity if 'extcommunity' in rule_config['set']: if 'none' in rule_config['set']['extcommunity']: tmp = 'set extcommunity none' diff --git a/smoketest/scripts/cli/test_protocols_static.py b/smoketest/scripts/cli/test_protocols_static.py index 77a45e333..017618cbb 100755 --- a/smoketest/scripts/cli/test_protocols_static.py +++ b/smoketest/scripts/cli/test_protocols_static.py @@ -254,7 +254,7 @@ class TestProtocolsStatic(VyOSUnitTestSHIM.TestCase): self.cli_commit() # Verify FRR bgpd configuration - frrconfig = self.getFRRconfig('ip route') + frrconfig = self.getFRRconfig('ip route', end_marker='') # Verify routes for route, route_config in routes.items(): @@ -368,7 +368,7 @@ class TestProtocolsStatic(VyOSUnitTestSHIM.TestCase): self.cli_commit() # Verify FRR bgpd configuration - frrconfig = self.getFRRconfig('ip route') + frrconfig = self.getFRRconfig('ip route', end_marker='') for table in tables: # Verify routes @@ -558,7 +558,7 @@ class TestProtocolsStatic(VyOSUnitTestSHIM.TestCase): self.cli_commit() # Verify FRR configuration - frrconfig = self.getFRRconfig('ip mroute') + frrconfig = self.getFRRconfig('ip mroute', end_marker='') for route, route_config in multicast_routes.items(): if 'next_hop' in route_config: for next_hop, next_hop_config in route_config['next_hop'].items(): @@ -712,15 +712,12 @@ class TestProtocolsStatic(VyOSUnitTestSHIM.TestCase): self.assertIsNotNone(router, 'DHCP router should be available') # Verify FRR configuration contains the static routes with DHCP router - frrconfig = self.getFRRconfig('ip route') + frrconfig = self.getFRRconfig('ip route', end_marker='') for route in dhcp_routes.keys(): expected_route = f'ip route {route} {router} {dhcp_interface}' - self.assertIn( - expected_route, - frrconfig, - f'Static route {route} with dhcp-interface should be in FRR config', - ) + self.assertIn(expected_route, frrconfig, f'Static route {route} '\ + 'with dhcp-interface should be in FRR config') # Test table-based routes with dhcp-interface table_id = '100' @@ -730,7 +727,7 @@ class TestProtocolsStatic(VyOSUnitTestSHIM.TestCase): self.cli_commit() # Verify table route in FRR config - frrconfig = self.getFRRconfig('ip route') + frrconfig = self.getFRRconfig('ip route', end_marker='') expected_table_route = ( f'ip route {table_route} {router} {dhcp_interface} table {table_id}' ) diff --git a/smoketest/scripts/cli/test_system_ip.py b/smoketest/scripts/cli/test_system_ip.py index fadbdec47..3784d4630 100755 --- a/smoketest/scripts/cli/test_system_ip.py +++ b/smoketest/scripts/cli/test_system_ip.py @@ -86,14 +86,16 @@ class TestSystemIP(VyOSUnitTestSHIM.TestCase): protocols = ['any', 'babel', 'bgp', 'connected', 'eigrp', 'isis', 'kernel', 'ospf', 'rip', 'static', 'table'] + rule_num = '10' + for protocol in protocols: - self.cli_set(['policy', 'route-map', f'route-map-{protocol}', 'rule', '10', 'action', 'permit']) + self.cli_set(['policy', 'route-map', f'route-map-{protocol}', 'rule', rule_num, 'action', 'permit']) self.cli_set(base_path + ['protocol', protocol, 'route-map', f'route-map-{protocol}']) self.cli_commit() # Verify route-map properly applied to FRR - frrconfig = self.getFRRconfig('ip protocol', stop_section='^end') + frrconfig = self.getFRRconfig('ip protocol', end_marker='', stop_section='^end') for protocol in protocols: self.assertIn(f'ip protocol {protocol} route-map route-map-{protocol}', frrconfig) diff --git a/smoketest/scripts/cli/test_system_ipv6.py b/smoketest/scripts/cli/test_system_ipv6.py index edf479fa4..0f94765bd 100755 --- a/smoketest/scripts/cli/test_system_ipv6.py +++ b/smoketest/scripts/cli/test_system_ipv6.py @@ -109,7 +109,7 @@ class TestSystemIPv6(VyOSUnitTestSHIM.TestCase): self.cli_commit() # Verify route-map properly applied to FRR - frrconfig = self.getFRRconfig('ipv6 protocol', stop_section='^end') + frrconfig = self.getFRRconfig('ipv6 protocol', end_marker='', stop_section='^end') for protocol in protocols: # VyOS and FRR use a different name for OSPFv3 (IPv6) if protocol == 'ospfv3': -- cgit v1.2.3 From b50808ac8245aa75bdca5b1996847125d1969dc3 Mon Sep 17 00:00:00 2001 From: Christian Breunig Date: Fri, 7 Nov 2025 16:45:58 +0100 Subject: smoketest: T7996: drop frr-reload.py implementation when reading running config Commit 9775bb49e ("frr: T7664: drop BASH/SED implementation in smoketest getFRRconfig()") dropped a custom BASH/SED based implementation of how we interacted with FRR to make use of the utility helpers from FRR team. This changed added some arbitray warnings when executing about unclosed files handles. ResourceWarning: unclosed file <_io.BufferedReader name=5> Instead of importing the frr-reload Python module, we simply call popen() by ourself. --- smoketest/scripts/cli/base_vyostest_shim.py | 19 +++++-------------- 1 file changed, 5 insertions(+), 14 deletions(-) (limited to 'smoketest/scripts/cli') diff --git a/smoketest/scripts/cli/base_vyostest_shim.py b/smoketest/scripts/cli/base_vyostest_shim.py index cf3324a15..08639f31b 100644 --- a/smoketest/scripts/cli/base_vyostest_shim.py +++ b/smoketest/scripts/cli/base_vyostest_shim.py @@ -12,12 +12,10 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see . -import importlib.util import os import paramiko import pprint import re -import sys import unittest from time import sleep @@ -56,17 +54,6 @@ class VyOSUnitTestSHIM: @classmethod def setUpClass(cls): - # Import frr-reload.py functionality - file_path = '/usr/lib/frr/frr-reload.py' - module_name = 'frr_reload' - - spec = importlib.util.spec_from_file_location(module_name, file_path) - module = importlib.util.module_from_spec(spec) - sys.modules[module_name] = module - spec.loader.exec_module(module) - Vtysh = getattr(module, 'Vtysh') - cls._vtysh = Vtysh(bindir='/usr/bin', confdir='/etc/frr') - cls._session = ConfigSession(os.getpid()) cls._session.save_config(save_config) cls.debug = cls.debug_on() @@ -152,7 +139,11 @@ class VyOSUnitTestSHIM: start_subsection: search section under the result found by string stop_subsection: end of the subsection (usually something with "exit") """ - frr_config = self._vtysh.mark_show_run() + from vyos.utils.process import rc_cmd + + rc, frr_config = rc_cmd('vtysh -c "show running-config no-header"') + self.assertEqual(rc, 0) + if not start_section: return frr_config -- cgit v1.2.3