Skip to content

Commit 9775bb4

Browse files
committed
frr: T7664: drop BASH/SED implementation in smoketest getFRRconfig()
Rathern then re-inventing the wheel by outself we import the frr-reload.py script and their read-in function of the current vtysh configuration.
1 parent 6961f73 commit 9775bb4

24 files changed

+307
-275
lines changed

smoketest/scripts/cli/base_vyostest_shim.py

Lines changed: 58 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,13 @@
1212
# You should have received a copy of the GNU General Public License
1313
# along with this program. If not, see <http://www.gnu.org/licenses/>.
1414

15+
import importlib.util
1516
import os
16-
import unittest
1717
import paramiko
1818
import pprint
19+
import re
20+
import sys
21+
import unittest
1922

2023
from time import sleep
2124
from typing import Type
@@ -36,6 +39,7 @@
3639
# Using this approach we can not render a live system useless while running any
3740
# kind of smoketest. In addition it adds debug capabilities like printing the
3841
# command used to execute the test.
42+
3943
class VyOSUnitTestSHIM:
4044
class TestCase(unittest.TestCase):
4145
# if enabled in derived class, print out each and every set/del command
@@ -50,6 +54,17 @@ def debug_on():
5054

5155
@classmethod
5256
def setUpClass(cls):
57+
# Import frr-reload.py functionality
58+
file_path = '/usr/lib/frr/frr-reload.py'
59+
module_name = 'frr_reload'
60+
61+
spec = importlib.util.spec_from_file_location(module_name, file_path)
62+
module = importlib.util.module_from_spec(spec)
63+
sys.modules[module_name] = module
64+
spec.loader.exec_module(module)
65+
Vtysh = getattr(module, 'Vtysh')
66+
cls._vtysh = Vtysh(bindir='/usr/bin', confdir='/etc/frr')
67+
5368
cls._session = ConfigSession(os.getpid())
5469
cls._session.save_config(save_config)
5570
cls.debug = cls.debug_on()
@@ -93,8 +108,7 @@ def cli_commit(self):
93108
sleep(0.250)
94109
# Return the output of commit
95110
# Necessary for testing Warning cases
96-
out = self._session.commit()
97-
return out
111+
return self._session.commit()
98112

99113
def cli_save(self, file):
100114
if self.debug:
@@ -114,37 +128,52 @@ def op_mode(self, path : list) -> None:
114128
pprint.pprint(out)
115129
return out
116130

117-
def getFRRconfig(self, string=None, end='$', endsection='^!',
118-
substring=None, endsubsection=None, empty_retry=0):
131+
def getFRRconfig(self, start_section:str=None, stop_section='^!',
132+
start_subsection:str=None, stop_subsection='^ exit') -> str:
119133
"""
120134
Retrieve current "running configuration" from FRR
121135
122-
string: search for a specific start string in the configuration
123-
end: end of the section to search for (line ending)
124-
endsection: end of the configuration
125-
substring: search section under the result found by string
126-
endsubsection: end of the subsection (usually something with "exit")
136+
start_section: search for a specific start string in the configuration
137+
stop_section: end of the configuration
138+
start_subsection: search section under the result found by string
139+
stop_subsection: end of the subsection (usually something with "exit")
127140
"""
128-
command = f'vtysh -c "show run no-header"'
129-
if string:
130-
command += f' | sed -n "/^{string}{end}/,/{endsection}/p"'
131-
if substring and endsubsection:
132-
command += f' | sed -n "/^{substring}/,/{endsubsection}/p"'
133-
out = cmd(command)
141+
frr_config = self._vtysh.mark_show_run()
142+
if not start_section:
143+
return frr_config
144+
145+
extracted = []
146+
in_section = False
147+
for line in frr_config.splitlines():
148+
if not in_section:
149+
if re.match(start_section, line):
150+
in_section = True
151+
extracted.append(line)
152+
else:
153+
extracted.append(line)
154+
if re.match(stop_section, line):
155+
break
156+
output = '\n'.join(extracted)
157+
158+
# Use extracted list when searching for optional subsection
159+
# used by e.g. BGP address-family check
160+
if start_subsection:
161+
extracted_subsection = []
162+
in_subsection = False
163+
for line in extracted:
164+
if not in_subsection:
165+
if re.match(start_subsection, line):
166+
in_subsection = True
167+
extracted_subsection.append(line)
168+
else:
169+
extracted_subsection.append(line)
170+
if re.match(stop_subsection, line):
171+
break
172+
output = '\n'.join(extracted_subsection)
173+
134174
if self.debug:
135-
print(f'\n\ncommand "{command}" returned:\n')
136-
pprint.pprint(out)
137-
if empty_retry > 0:
138-
retry_count = 0
139-
while not out and retry_count < empty_retry:
140-
if self.debug and retry_count % 10 == 0:
141-
print(f"Attempt {retry_count}: FRR config is still empty. Retrying...")
142-
retry_count += 1
143-
sleep(1)
144-
out = cmd(command)
145-
if not out:
146-
print(f'FRR configuration still empty after {empty_retry} retires!')
147-
return out
175+
print(output)
176+
return output
148177

149178
def getFRRopmode(self, command : str, json : bool=False):
150179
from json import loads

smoketest/scripts/cli/test_interfaces_bonding.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -311,7 +311,7 @@ def test_bonding_evpn_multihoming(self):
311311

312312
id = '5'
313313
for interface in self._interfaces:
314-
frrconfig = self.getFRRconfig(f'interface {interface}', endsection='^exit')
314+
frrconfig = self.getFRRconfig(f'interface {interface}', stop_section='^exit')
315315

316316
self.assertIn(f' evpn mh es-id {id}', frrconfig)
317317
self.assertIn(f' evpn mh es-df-pref {id}', frrconfig)
@@ -328,7 +328,7 @@ def test_bonding_evpn_multihoming(self):
328328

329329
id = '5'
330330
for interface in self._interfaces:
331-
frrconfig = self.getFRRconfig(f'interface {interface}', endsection='^exit')
331+
frrconfig = self.getFRRconfig(f'interface {interface}', stop_section='^exit')
332332
self.assertIn(f' evpn mh es-sys-mac 00:12:34:56:78:0{id}', frrconfig)
333333
self.assertIn(f' evpn mh uplink', frrconfig)
334334

smoketest/scripts/cli/test_interfaces_ethernet.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -229,7 +229,7 @@ def test_ethtool_evpn_uplink_tracking(self):
229229
self.cli_commit()
230230

231231
for interface in self._interfaces:
232-
frrconfig = self.getFRRconfig(f'interface {interface}', endsection='^exit')
232+
frrconfig = self.getFRRconfig(f'interface {interface}', stop_section='^exit')
233233
self.assertIn(' evpn mh uplink', frrconfig)
234234

235235
def test_switchdev(self):

smoketest/scripts/cli/test_interfaces_pppoe.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -305,7 +305,7 @@ def test_pppoe_dhcpv6pd(self):
305305
# Get corresponding PD assigned prefix for this site/connection
306306
pd_prefix = IPv6Network(f"{ipv6}/56", strict=False)
307307
# Prefix must be within the PD pool
308-
self.assertIn(pd_prefix, IPv6Network(ipv6_pool_pd))
308+
self.assertTrue(pd_prefix.subnet_of(IPv6Network(ipv6_pool_pd)))
309309
# Calculate the assigned IP address from the prefix delegation
310310
network_addr = str(pd_prefix.network_address) # 2001:db8:8003::
311311
generated_sla_addr = network_addr[:-1] + f'{sla_id}::{address}'

smoketest/scripts/cli/test_policy.py

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,7 @@ def test_access_list(self):
121121

122122
self.cli_commit()
123123

124-
config = self.getFRRconfig('access-list', end='')
124+
config = self.getFRRconfig('access-list')
125125
for acl, acl_config in acls.items():
126126
for rule, rule_config in acl_config['rule'].items():
127127
tmp = f'access-list {acl} seq {rule}'
@@ -212,7 +212,7 @@ def test_access_list6(self):
212212

213213
self.cli_commit()
214214

215-
config = self.getFRRconfig('ipv6 access-list', end='')
215+
config = self.getFRRconfig('ipv6 access-list')
216216
for acl, acl_config in acls.items():
217217
for rule, rule_config in acl_config['rule'].items():
218218
tmp = f'ipv6 access-list {acl} seq {rule}'
@@ -310,7 +310,7 @@ def test_as_path_list(self):
310310

311311
self.cli_commit()
312312

313-
config = self.getFRRconfig('bgp as-path access-list', end='')
313+
config = self.getFRRconfig('bgp as-path access-list')
314314
for as_path, as_path_config in test_data.items():
315315
if 'rule' not in as_path_config:
316316
continue
@@ -368,7 +368,7 @@ def test_community_list(self):
368368

369369
self.cli_commit()
370370

371-
config = self.getFRRconfig('bgp community-list', end='')
371+
config = self.getFRRconfig('bgp community-list')
372372
for comm_list, comm_list_config in test_data.items():
373373
if 'rule' not in comm_list_config:
374374
continue
@@ -426,7 +426,7 @@ def test_extended_community_list(self):
426426

427427
self.cli_commit()
428428

429-
config = self.getFRRconfig('bgp extcommunity-list', end='')
429+
config = self.getFRRconfig('bgp extcommunity-list')
430430
for comm_list, comm_list_config in test_data.items():
431431
if 'rule' not in comm_list_config:
432432
continue
@@ -491,7 +491,7 @@ def test_large_community_list(self):
491491

492492
self.cli_commit()
493493

494-
config = self.getFRRconfig('bgp large-community-list', end='')
494+
config = self.getFRRconfig('bgp large-community-list')
495495
for comm_list, comm_list_config in test_data.items():
496496
if 'rule' not in comm_list_config:
497497
continue
@@ -569,7 +569,7 @@ def test_prefix_list(self):
569569

570570
self.cli_commit()
571571

572-
config = self.getFRRconfig('ip prefix-list', end='')
572+
config = self.getFRRconfig('ip prefix-list')
573573
for prefix_list, prefix_list_config in test_data.items():
574574
if 'rule' not in prefix_list_config:
575575
continue
@@ -652,7 +652,7 @@ def test_prefix_list6(self):
652652

653653
self.cli_commit()
654654

655-
config = self.getFRRconfig('ipv6 prefix-list', end='')
655+
config = self.getFRRconfig('ipv6 prefix-list')
656656
for prefix_list, prefix_list_config in test_data.items():
657657
if 'rule' not in prefix_list_config:
658658
continue
@@ -703,7 +703,7 @@ def test_prefix_list_duplicates(self):
703703

704704
self.cli_commit()
705705

706-
config = self.getFRRconfig('ip prefix-list', end='')
706+
config = self.getFRRconfig('ip prefix-list')
707707
for rule in test_range:
708708
tmp = f'ip prefix-list {prefix_list} seq {rule} permit {prefix} le {rule}'
709709
self.assertIn(tmp, config)
@@ -2002,7 +2002,7 @@ def test_frr_individual_remove_T6283_T6250(self):
20022002
local_preference = base_local_preference
20032003
table = base_table
20042004
for route_map in route_maps:
2005-
config = self.getFRRconfig(f'route-map {route_map} permit {seq}', end='', endsection='^exit')
2005+
config = self.getFRRconfig(f'route-map {route_map} permit {seq}', stop_section='^exit')
20062006
self.assertIn(f' set local-preference {local_preference}', config)
20072007
self.assertIn(f' set table {table}', config)
20082008
local_preference += 20
@@ -2015,7 +2015,7 @@ def test_frr_individual_remove_T6283_T6250(self):
20152015

20162016
local_preference = base_local_preference
20172017
for route_map in route_maps:
2018-
config = self.getFRRconfig(f'route-map {route_map} permit {seq}', end='', endsection='^exit')
2018+
config = self.getFRRconfig(f'route-map {route_map} permit {seq}', stop_section='^exit')
20192019
self.assertIn(f' set local-preference {local_preference}', config)
20202020
local_preference += 20
20212021

@@ -2029,7 +2029,7 @@ def test_frr_individual_remove_T6283_T6250(self):
20292029
self.cli_commit()
20302030

20312031
for route_map in route_maps:
2032-
config = self.getFRRconfig(f'route-map {route_map} permit {seq}', end='', endsection='^exit')
2032+
config = self.getFRRconfig(f'route-map {route_map} permit {seq}', stop_section='^exit')
20332033
self.assertIn(f' set as-path prepend {prepend}', config)
20342034

20352035
for route_map in route_maps:
@@ -2038,7 +2038,7 @@ def test_frr_individual_remove_T6283_T6250(self):
20382038
self.cli_commit()
20392039

20402040
for route_map in route_maps:
2041-
config = self.getFRRconfig(f'route-map {route_map} permit {seq}', end='', endsection='^exit')
2041+
config = self.getFRRconfig(f'route-map {route_map} permit {seq}', stop_section='^exit')
20422042
self.assertNotIn(f' set', config)
20432043

20442044
def sort_ip(output):

smoketest/scripts/cli/test_protocols_babel.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ def test_01_basic(self):
6262

6363
self.cli_commit()
6464

65-
frrconfig = self.getFRRconfig('router babel', endsection='^exit')
65+
frrconfig = self.getFRRconfig('router babel', stop_section='^exit')
6666
self.assertIn(f' babel diversity', frrconfig)
6767
self.assertIn(f' babel diversity-factor {diversity_factor}', frrconfig)
6868
self.assertIn(f' babel resend-delay {resend_delay}', frrconfig)
@@ -81,7 +81,7 @@ def test_02_redistribute(self):
8181

8282
self.cli_commit()
8383

84-
frrconfig = self.getFRRconfig('router babel', endsection='^exit', empty_retry=5)
84+
frrconfig = self.getFRRconfig('router babel', stop_section='^exit')
8585
for protocol in ipv4_protos:
8686
self.assertIn(f' redistribute ipv4 {protocol}', frrconfig)
8787
for protocol in ipv6_protos:
@@ -150,7 +150,7 @@ def test_03_distribute_list(self):
150150

151151
self.cli_commit()
152152

153-
frrconfig = self.getFRRconfig('router babel', endsection='^exit')
153+
frrconfig = self.getFRRconfig('router babel', stop_section='^exit')
154154
self.assertIn(f' distribute-list {access_list_in4} in', frrconfig)
155155
self.assertIn(f' distribute-list {access_list_out4} out', frrconfig)
156156
self.assertIn(f' ipv6 distribute-list {access_list_in6} in', frrconfig)
@@ -198,11 +198,11 @@ def test_04_interfaces(self):
198198

199199
self.cli_commit()
200200

201-
frrconfig = self.getFRRconfig('router babel', endsection='^exit')
201+
frrconfig = self.getFRRconfig('router babel', stop_section='^exit')
202202
for interface in self._interfaces:
203203
self.assertIn(f' network {interface}', frrconfig)
204204

205-
iface_config = self.getFRRconfig(f'interface {interface}', endsection='^exit')
205+
iface_config = self.getFRRconfig(f'interface {interface}', stop_section='^exit')
206206
self.assertIn(f' babel channel {channel}', iface_config)
207207
self.assertIn(f' babel enable-timestamps', iface_config)
208208
self.assertIn(f' babel update-interval {def_update_interval}', iface_config)

smoketest/scripts/cli/test_protocols_bfd.py

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,7 @@ def test_bfd_peer(self):
131131
self.cli_commit()
132132

133133
# Verify FRR bgpd configuration
134-
frrconfig = self.getFRRconfig('bfd', endsection='^exit')
134+
frrconfig = self.getFRRconfig('bfd', stop_section='^exit')
135135
for peer, peer_config in peers.items():
136136
tmp = f'peer {peer}'
137137
if 'multihop' in peer_config:
@@ -144,8 +144,9 @@ def test_bfd_peer(self):
144144
tmp += f' vrf {peer_config["vrf"]}'
145145

146146
self.assertIn(tmp, frrconfig)
147-
peerconfig = self.getFRRconfig('bfd', endsection='^exit', substring=f' peer {peer}',
148-
endsubsection='^ exit')
147+
peerconfig = self.getFRRconfig('bfd', stop_section='^exit',
148+
start_subsection=f' peer {peer}',
149+
stop_subsection='^ exit')
149150
if 'echo_mode' in peer_config:
150151
self.assertIn(f'echo-mode', peerconfig)
151152
if 'intv_echo' in peer_config:
@@ -207,8 +208,8 @@ def test_bfd_profile(self):
207208

208209
# Verify FRR bgpd configuration
209210
for profile, profile_config in profiles.items():
210-
config = self.getFRRconfig('bfd', endsection='^exit',
211-
substring=f' profile {profile}', endsubsection='^ exit',)
211+
config = self.getFRRconfig('bfd', stop_section='^exit',
212+
start_subsection=f' profile {profile}', stop_subsection='^ exit',)
212213
if 'echo_mode' in profile_config:
213214
self.assertIn(f' echo-mode', config)
214215
if 'intv_echo' in profile_config:
@@ -230,8 +231,8 @@ def test_bfd_profile(self):
230231
self.assertNotIn(f'shutdown', config)
231232

232233
for peer, peer_config in peers.items():
233-
peerconfig = self.getFRRconfig('bfd', endsection='^exit',
234-
substring=f' peer {peer}', endsubsection='^ exit')
234+
peerconfig = self.getFRRconfig('bfd', stop_section='^exit',
235+
start_subsection=f' peer {peer}', stop_subsection='^ exit')
235236
if 'profile' in peer_config:
236237
self.assertIn(f' profile {peer_config["profile"]}', peerconfig)
237238

0 commit comments

Comments
 (0)