Skip to content

Commit 84cd691

Browse files
neethajohnyxieca
authored andcommitted
[warm-reboot] Add preboot LAG sad path automation (#945)
* preboot LAG sad path automation for neigh_lag_down and dut_lag_down scenarios
1 parent 84f4a6f commit 84cd691

File tree

4 files changed

+139
-16
lines changed

4 files changed

+139
-16
lines changed

ansible/roles/test/files/ptftests/advanced-reboot.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -311,7 +311,7 @@ def get_portchannel_info(self):
311311
for vm_key in self.vm_dut_map.keys():
312312
if member in self.vm_dut_map[vm_key]['dut_ports']:
313313
self.vm_dut_map[vm_key]['dut_portchannel'] = key
314-
self.vm_dut_map[vm_key]['neigh_portchannel'] = 'Port-Channel 1'
314+
self.vm_dut_map[vm_key]['neigh_portchannel'] = 'Port-Channel1'
315315
break
316316

317317
def get_neigh_port_info(self):
@@ -732,7 +732,7 @@ def wait_for_ssh_threads():
732732
if self.reboot_type == 'warm-reboot' and self.preboot_oper is not None:
733733
if self.pre_handle is not None:
734734
self.log("Postboot checks:")
735-
log_info, fails_dut, fails_vm = self.pre_handle.verify()
735+
log_info, fails_dut, fails_vm = self.pre_handle.verify(pre_check=False)
736736
self.fails[self.neigh_vm] |= fails_vm
737737
self.fails['dut'] |= fails_dut
738738
for log in log_info:

ansible/roles/test/files/ptftests/arista.py

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -358,7 +358,7 @@ def verify_bgp_neigh_state(self, dut=None, state="Active"):
358358
data = '\n'.join(output.split('\r\n')[1:-1])
359359
obj = json.loads(data)
360360

361-
if state != 'Active':
361+
if state == 'down':
362362
if 'vrfs' in obj:
363363
# return True when obj['vrfs'] is empty which is the case when the bgp state is 'down'
364364
bgp_state[ver] = not obj['vrfs']
@@ -375,6 +375,36 @@ def verify_bgp_neigh_state(self, dut=None, state="Active"):
375375
self.fails.add('Verify BGP %s neighbor: Object missing in output' % ver)
376376
return self.fails, bgp_state
377377

378+
def change_neigh_lag_state(self, lag, is_up=True):
379+
state = ['shut', 'no shut']
380+
self.do_cmd('configure')
381+
is_match = re.match('(Port-Channel|Ethernet)\d+', lag)
382+
if is_match:
383+
output = self.do_cmd('interface %s' % lag)
384+
if 'Invalid' not in output:
385+
self.do_cmd(state[is_up])
386+
self.do_cmd('exit')
387+
self.do_cmd('exit')
388+
389+
def verify_neigh_lag_state(self, lag, state="connected", pre_check=True):
390+
lag_state = False
391+
msg_prefix = ['Postboot', 'Preboot']
392+
is_match = re.match('(Port-Channel|Ethernet)\d+', lag)
393+
if is_match:
394+
output = self.do_cmd('show interfaces %s | json' % lag)
395+
if 'Invalid' not in output:
396+
data = '\n'.join(output.split('\r\n')[1:-1])
397+
obj = json.loads(data)
398+
399+
if 'interfaces' in obj and lag in obj['interfaces']:
400+
lag_state = (obj['interfaces'][lag]['interfaceStatus'] == state)
401+
else:
402+
self.fails.add('%s: Verify LAG %s: Object missing in output' % (msg_prefix[pre_check], lag))
403+
return self.fails, lag_state
404+
405+
self.fails.add('%s: Invalid interface name' % msg_prefix[pre_check])
406+
return self.fails, lag_state
407+
378408
def check_gr_peer_status(self, output):
379409
# [0] True 'ipv4_gr_enabled', [1] doesn't matter 'ipv6_enabled', [2] should be >= 120
380410
if not self.ipv4_gr_enabled:

ansible/roles/test/files/ptftests/sad_path.py

Lines changed: 105 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -20,12 +20,13 @@ def __init__(self, oper_type, vm_list, portchannel_ports, vm_dut_map, test_args,
2020
self.shandle = SadOper(self.oper_type, self.vm_list, self.portchannel_ports, self.vm_dut_map, self.test_args, self.dut_ssh)
2121

2222
def setup(self):
23-
if 'bgp' in self.oper_type:
24-
self.shandle.sad_setup(is_up=False)
23+
self.shandle.sad_setup(is_up=False)
2524
return self.shandle.retreive_test_info(), self.shandle.retreive_logs()
2625

27-
def verify(self):
26+
def verify(self, pre_check=True):
2827
self.shandle.sad_bgp_verify()
28+
if 'lag' in self.oper_type:
29+
self.shandle.sad_lag_verify(pre_check=pre_check)
2930
return self.shandle.retreive_logs()
3031

3132
def revert(self):
@@ -111,6 +112,9 @@ def __init__(self, oper_type, vm_list, portchannel_ports, vm_dut_map, test_args,
111112
super(SadOper, self).__init__(oper_type, vm_list, portchannel_ports, vm_dut_map, test_args)
112113
self.dut_ssh = dut_ssh
113114
self.dut_needed = None
115+
self.lag_members_down = None
116+
self.neigh_lag_state = None
117+
self.msg_prefix = ['Postboot', 'Preboot']
114118

115119
def populate_bgp_state(self):
116120
if self.oper_type == 'neigh_bgp_down':
@@ -121,19 +125,42 @@ def populate_bgp_state(self):
121125
self.neigh_bgp['changed_state'] = 'Active'
122126
self.dut_bgp['changed_state'] = 'Idle'
123127
self.dut_needed = self.dut_bgp
128+
elif self.oper_type == 'neigh_lag_down':
129+
# on the DUT side, bgp states are different pre and post boot. hence passing multiple values
130+
self.neigh_bgp['changed_state'] = 'Idle'
131+
self.dut_bgp['changed_state'] = 'Connect,Active,Idle'
132+
self.dut_needed = self.dut_bgp
133+
elif self.oper_type == 'dut_lag_down':
134+
self.neigh_bgp['changed_state'] = 'Idle'
135+
self.dut_bgp['changed_state'] = 'Active,Connect,Idle'
136+
self.dut_needed = self.dut_bgp
124137

125138
def sad_setup(self, is_up=True):
126139
self.log = []
140+
127141
if not is_up:
128142
self.setup()
129143
self.populate_bgp_state()
130-
self.log.append('BGP state change will be for %s' % self.neigh_vm)
131-
if self.oper_type == 'neigh_bgp_down':
132-
self.log.append('Changing state of AS %s to shut' % self.neigh_bgp['asn'])
133-
self.vm_handle.change_bgp_neigh_state(self.neigh_bgp['asn'], is_up=is_up)
134-
elif self.oper_type == 'dut_bgp_down':
135-
self.change_bgp_dut_state(is_up=is_up)
136-
time.sleep(30)
144+
if 'lag' in self.oper_type:
145+
self.populate_lag_state()
146+
147+
if 'bgp' in self.oper_type:
148+
self.log.append('BGP state change will be for %s' % self.neigh_vm)
149+
if self.oper_type == 'neigh_bgp_down':
150+
self.log.append('Changing state of AS %s to shut' % self.neigh_bgp['asn'])
151+
self.vm_handle.change_bgp_neigh_state(self.neigh_bgp['asn'], is_up=is_up)
152+
elif self.oper_type == 'dut_bgp_down':
153+
self.change_bgp_dut_state(is_up=is_up)
154+
time.sleep(30)
155+
elif 'lag' in self.oper_type:
156+
self.log.append('LAG state change will be for %s' % self.neigh_vm)
157+
if self.oper_type == 'neigh_lag_down':
158+
self.log.append('Changing state of LAG %s to shut' % self.vm_dut_map[self.neigh_name]['neigh_portchannel'])
159+
self.vm_handle.change_neigh_lag_state(self.vm_dut_map[self.neigh_name]['neigh_portchannel'], is_up=is_up)
160+
elif self.oper_type == 'dut_lag_down':
161+
self.change_dut_lag_state(is_up=is_up)
162+
# wait for sometime for lag members state to sync
163+
time.sleep(120)
137164

138165
def change_bgp_dut_state(self, is_up=True):
139166
state = ['shutdown', 'startup']
@@ -149,18 +176,19 @@ def change_bgp_dut_state(self, is_up=True):
149176
self.fails['dut'].add('Stderr: %s' % stderr)
150177

151178
def verify_bgp_dut_state(self, state='Idle'):
179+
states = state.split(',')
152180
bgp_state = {}
153181
bgp_state['v4'] = bgp_state['v6'] = False
154182
for key in self.neigh_bgp.keys():
155183
if key not in ['v4', 'v6']:
156184
continue
157-
self.log.append('Verifying if the DUT side BGP peer %s is %s' % (self.neigh_bgp[key], state))
185+
self.log.append('Verifying if the DUT side BGP peer %s is %s' % (self.neigh_bgp[key], states))
158186
stdout, stderr, return_code = self.cmd(['ssh', '-oStrictHostKeyChecking=no', self.dut_ssh, 'show ip bgp neighbor %s' % self.neigh_bgp[key]])
159187
if return_code == 0:
160188
for line in stdout.split('\n'):
161189
if 'BGP state' in line:
162190
curr_state = re.findall('BGP state = (\w+)', line)[0]
163-
bgp_state[key] = (curr_state == state)
191+
bgp_state[key] = (curr_state in states)
164192
break
165193
else:
166194
self.fails['dut'].add('Retreiving BGP info for peer %s from DUT side failed' % self.neigh_bgp[key])
@@ -181,3 +209,68 @@ def sad_bgp_verify(self):
181209
self.log.append('BGP state down as expected on DUT')
182210
else:
183211
self.fails['dut'].add('BGP state not down on DUT')
212+
213+
def populate_lag_state(self):
214+
if self.oper_type == 'neigh_lag_down':
215+
self.neigh_lag_state = 'disabled'
216+
self.lag_members_down = self.vm_dut_map[self.neigh_name]['dut_ports']
217+
elif self.oper_type == 'dut_lag_down':
218+
self.lag_members_down = self.vm_dut_map[self.neigh_name]['dut_ports']
219+
self.neigh_lag_state = 'notconnect'
220+
221+
def change_dut_lag_state(self, is_up=True):
222+
state = ['shutdown', 'startup']
223+
dut_portchannel = self.vm_dut_map[self.neigh_name]['dut_portchannel']
224+
if not re.match('(PortChannel|Ethernet)\d+', dut_portchannel): return
225+
self.log.append('Changing state of %s from DUT side to %s' % (dut_portchannel, state[is_up]))
226+
stdout, stderr, return_code = self.cmd(['ssh', '-oStrictHostKeyChecking=no', self.dut_ssh, 'sudo config interface %s %s' % (state[is_up], dut_portchannel)])
227+
if return_code != 0:
228+
self.fails['dut'].add('%s: State change not successful from DUT side for %s' % (self.msg_prefix[1 - is_up], dut_portchannel))
229+
self.fails['dut'].add('%s: Return code: %d' % (self.msg_prefix[1 - is_up], return_code))
230+
self.fails['dut'].add('%s: Stderr: %s' % (self.msg_prefix[1 - is_up], stderr))
231+
else:
232+
self.log.append('State change successful on DUT')
233+
234+
def verify_dut_lag_member_state(self, lag_memb_output, pre_check=True):
235+
success = True
236+
for member in self.vm_dut_map[self.neigh_name]['dut_ports']:
237+
if self.lag_members_down is not None and member in self.lag_members_down:
238+
search_str = '%s(D)' % member
239+
else:
240+
search_str = '%s(S)' % member
241+
242+
if lag_memb_output.find(search_str) != -1:
243+
self.log.append('Lag member %s state as expected' % member)
244+
else:
245+
success = False
246+
self.fails['dut'].add('%s: Lag member %s state not as expected' % (self.msg_prefix[pre_check], member))
247+
return success
248+
249+
def verify_dut_lag_state(self, pre_check=True):
250+
pat = re.compile(".*%s\s+LACP\(A\)\(Dw\)\s+(.*)" % self.vm_dut_map[self.neigh_name]['dut_portchannel'])
251+
stdout, stderr, return_code = self.cmd(['ssh', '-oStrictHostKeyChecking=no', self.dut_ssh, 'show interfaces portchannel'])
252+
if return_code == 0:
253+
for line in stdout.split('\n'):
254+
if self.vm_dut_map[self.neigh_name]['dut_portchannel'] in line:
255+
is_match = pat.match(line)
256+
if is_match and self.verify_dut_lag_member_state(is_match.group(1), pre_check=pre_check):
257+
self.log.append('Lag state is down as expected on the DUT')
258+
self.log.append('Pattern check: %s' % line)
259+
else:
260+
self.fails['dut'].add('%s: Lag state is not down on the DUT' % self.msg_prefix[pre_check])
261+
self.fails['dut'].add('%s: Obtained: %s' % (self.msg_prefix[pre_check], line))
262+
break
263+
else:
264+
self.fails['dut'].add('%s: Retreiving LAG info from DUT side failed' % self.msg_prefix[pre_check])
265+
self.fails['dut'].add('%s: Return code: %d' % (self.msg_prefix[pre_check], return_code))
266+
self.fails['dut'].add('%s: Stderr: %s' % (self.msg_prefix[pre_check], stderr))
267+
268+
def sad_lag_verify(self, pre_check=True):
269+
fails_vm, lag_state = self.vm_handle.verify_neigh_lag_state(self.vm_dut_map[self.neigh_name]['neigh_portchannel'], state=self.neigh_lag_state, pre_check=pre_check)
270+
self.fails[self.neigh_vm] |= fails_vm
271+
if lag_state:
272+
self.log.append('LAG state down as expected for %s' % self.neigh_vm)
273+
else:
274+
self.fails[self.neigh_vm].add('%s: LAG state not down for %s' % (self.msg_prefix[pre_check], self.neigh_vm))
275+
self.log.append('Verifying LAG state on the dut end')
276+
self.verify_dut_lag_state(pre_check=pre_check)

ansible/roles/test/tasks/warm-reboot-sad.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,5 +7,5 @@
77
include: advanced-reboot.yml
88
vars:
99
reboot_type: warm-reboot
10-
preboot_list: ['neigh_bgp_down', 'dut_bgp_down']
10+
preboot_list: ['neigh_bgp_down', 'dut_bgp_down', 'dut_lag_down', 'neigh_lag_down']
1111
preboot_files: "peer_dev_info,neigh_port_info"

0 commit comments

Comments
 (0)