blob: a0f3e777c407f3f07209357d2aa5f53ff4625e8a [file] [log] [blame]
Michael Walsh0bbd8602016-11-22 11:31:49 -06001#!/usr/bin/env python
2
3r"""
4This module is the python counterpart to obmc_boot_test.
5"""
6
Michael Walsh0b93fbf2017-03-02 14:42:41 -06007import os
8import imp
9import time
10import glob
11import random
Michael Walsh0ad0f7f2017-05-04 14:39:58 -050012import re
Michael Walshf566fb12019-02-01 14:35:09 -060013import signal
George Keishingd54bbc22018-08-03 08:24:58 -050014try:
15 import cPickle as pickle
16except ImportError:
17 import pickle
Michael Walshdc80d672017-05-09 12:58:32 -050018import socket
Michael Walsh0b93fbf2017-03-02 14:42:41 -060019
20from robot.utils import DotDict
21from robot.libraries.BuiltIn import BuiltIn
22
Michael Walsh6741f742017-02-20 16:16:38 -060023from boot_data import *
Michael Walshc9116812017-03-10 14:23:06 -060024import gen_print as gp
Michael Walsh55302292017-01-10 11:43:02 -060025import gen_robot_plug_in as grpi
Michael Walshf75d4352019-12-05 17:01:20 -060026import gen_arg as ga
Michael Walsh44cef252019-08-01 12:38:56 -050027import gen_valid as gv
Michael Walsh6741f742017-02-20 16:16:38 -060028import gen_misc as gm
29import gen_cmd as gc
Michael Walshb5839d02017-04-12 16:11:20 -050030import gen_robot_keyword as grk
Michael Walsh55302292017-01-10 11:43:02 -060031import state as st
Michael Walshff340002017-08-29 11:18:27 -050032import var_stack as vs
Michael Walshc9bd2e82019-04-18 11:06:52 -050033import gen_plug_in_utils as gpu
Michael Shepos1a67b082020-08-28 16:01:58 -050034import pel_utils as pel
Michael Shepos0e5f1132020-09-30 16:24:25 -050035import logging_utils as log
Michael Walsh0bbd8602016-11-22 11:31:49 -060036
Michael Walsh0b93fbf2017-03-02 14:42:41 -060037base_path = os.path.dirname(os.path.dirname(
38 imp.find_module("gen_robot_print")[1])) +\
Michael Walshc9116812017-03-10 14:23:06 -060039 os.sep
Michael Walsh0b93fbf2017-03-02 14:42:41 -060040sys.path.append(base_path + "extended/")
41import run_keyword as rk
Michael Walsh0bbd8602016-11-22 11:31:49 -060042
Michael Walshe1e26442017-03-06 17:50:07 -060043# Setting master_pid correctly influences the behavior of plug-ins like
44# DB_Logging
45program_pid = os.getpid()
46master_pid = os.environ.get('AUTOBOOT_MASTER_PID', program_pid)
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -050047pgm_name = re.sub('\\.py$', '', os.path.basename(__file__))
Michael Walshe1e26442017-03-06 17:50:07 -060048
Michael Walshb5839d02017-04-12 16:11:20 -050049# Set up boot data structures.
Michael Walsh986d8ae2019-07-17 10:02:23 -050050os_host = BuiltIn().get_variable_value("${OS_HOST}", default="")
Michael Walsh0b93fbf2017-03-02 14:42:41 -060051
Michael Walsh6741f742017-02-20 16:16:38 -060052boot_lists = read_boot_lists()
Michael Walsh986d8ae2019-07-17 10:02:23 -050053
54# The maximum number of entries that can be in the boot_history global variable.
Michael Walsh815b1d52018-10-30 13:32:26 -050055max_boot_history = 10
Michael Walsh986d8ae2019-07-17 10:02:23 -050056boot_history = []
Michael Walsh6741f742017-02-20 16:16:38 -060057
Michael Walsh7dc885b2018-03-14 17:51:59 -050058state = st.return_state_constant('default_state')
Michael Walsh6741f742017-02-20 16:16:38 -060059cp_setup_called = 0
60next_boot = ""
61base_tool_dir_path = os.path.normpath(os.environ.get(
62 'AUTOBOOT_BASE_TOOL_DIR_PATH', "/tmp")) + os.sep
Michael Walshb5839d02017-04-12 16:11:20 -050063
Michael Walsh6741f742017-02-20 16:16:38 -060064ffdc_dir_path = os.path.normpath(os.environ.get('FFDC_DIR_PATH', '')) + os.sep
Michael Walsh6741f742017-02-20 16:16:38 -060065boot_success = 0
Michael Walsh6741f742017-02-20 16:16:38 -060066status_dir_path = os.environ.get('STATUS_DIR_PATH', "")
67if status_dir_path != "":
68 status_dir_path = os.path.normpath(status_dir_path) + os.sep
Michael Walshe58df1c2019-08-07 09:57:43 -050069redfish_supported = BuiltIn().get_variable_value("${REDFISH_SUPPORTED}", default=False)
George Keishingeb1fe352020-06-19 03:02:22 -050070redfish_rest_supported = BuiltIn().get_variable_value("${REDFISH_REST_SUPPORTED}", default=False)
George Keishingd86e45c2021-03-19 07:38:14 -050071redfish_delete_sessions = int(BuiltIn().get_variable_value("${REDFISH_DELETE_SESSIONS}", default=1))
Michael Walshe58df1c2019-08-07 09:57:43 -050072if redfish_supported:
George Keishing89537a82020-06-17 00:37:25 -050073 redfish = BuiltIn().get_library_instance('redfish')
Michael Walshe58df1c2019-08-07 09:57:43 -050074 default_power_on = "Redfish Power On"
75 default_power_off = "Redfish Power Off"
George Keishingeb1fe352020-06-19 03:02:22 -050076 if redfish_rest_supported:
Michael Sheposcc490b42020-08-26 12:53:01 -050077 delete_errlogs_cmd = "Delete Error Logs ${quiet}=${1}"
Michael Shepos92a54bf2020-11-11 11:48:55 -060078 delete_bmcdump_cmd = "Delete All BMC Dump"
George Keishingeb1fe352020-06-19 03:02:22 -050079 default_set_power_policy = "Set BMC Power Policy ALWAYS_POWER_OFF"
80 else:
81 delete_errlogs_cmd = "Redfish Purge Event Log"
Michael Shepos92a54bf2020-11-11 11:48:55 -060082 delete_bmcdump_cmd = "Redfish Delete All BMC Dumps"
George Keishingeb1fe352020-06-19 03:02:22 -050083 default_set_power_policy = "Redfish Set Power Restore Policy AlwaysOff"
Michael Walshe58df1c2019-08-07 09:57:43 -050084else:
85 default_power_on = "REST Power On"
86 default_power_off = "REST Power Off"
Michael Sheposcc490b42020-08-26 12:53:01 -050087 delete_errlogs_cmd = "Delete Error Logs ${quiet}=${1}"
Michael Shepos92a54bf2020-11-11 11:48:55 -060088 delete_bmcdump_cmd = "Delete All BMC Dump"
George Keishinga54e06f2020-06-12 10:42:41 -050089 default_set_power_policy = "Set BMC Power Policy ALWAYS_POWER_OFF"
Michael Walsh6741f742017-02-20 16:16:38 -060090boot_count = 0
Michael Walsh0bbd8602016-11-22 11:31:49 -060091
Michael Walsh85678942017-03-27 14:34:22 -050092LOG_LEVEL = BuiltIn().get_variable_value("${LOG_LEVEL}")
Michael Walsh986d8ae2019-07-17 10:02:23 -050093AUTOBOOT_FFDC_PREFIX = os.environ.get('AUTOBOOT_FFDC_PREFIX', '')
94ffdc_prefix = AUTOBOOT_FFDC_PREFIX
Sunil M325eb542017-08-10 07:09:43 -050095boot_start_time = ""
96boot_end_time = ""
Michael Walshff340002017-08-29 11:18:27 -050097save_stack = vs.var_stack('save_stack')
98main_func_parm_list = ['boot_stack', 'stack_mode', 'quiet']
Michael Walsh85678942017-03-27 14:34:22 -050099
100
Michael Walsh89de14a2018-10-01 16:51:37 -0500101def dump_ffdc_rc():
102 r"""
103 Return the constant dump ffdc test return code value.
104
105 When a plug-in call point program returns this value, it indicates that
106 this program should collect FFDC.
107 """
108
109 return 0x00000200
110
111
112def stop_test_rc():
113 r"""
114 Return the constant stop test return code value.
115
116 When a plug-in call point program returns this value, it indicates that
117 this program should stop running.
118 """
119
120 return 0x00000200
121
122
Michael Walsh0ad0f7f2017-05-04 14:39:58 -0500123def process_host(host,
124 host_var_name=""):
Michael Walsh0ad0f7f2017-05-04 14:39:58 -0500125 r"""
126 Process a host by getting the associated host name and IP address and
127 setting them in global variables.
128
129 If the caller does not pass the host_var_name, this function will try to
130 figure out the name of the variable used by the caller for the host parm.
131 Callers are advised to explicitly specify the host_var_name when calling
132 with an exec command. In such cases, the get_arg_name cannot figure out
133 the host variable name.
134
135 This function will then create similar global variable names by
136 removing "_host" and appending "_host_name" or "_ip" to the host variable
137 name.
138
139 Example:
140
141 If a call is made like this:
142 process_host(openbmc_host)
143
144 Global variables openbmc_host_name and openbmc_ip will be set.
145
146 Description of argument(s):
147 host A host name or IP. The name of the variable used should
148 have a suffix of "_host".
149 host_var_name The name of the variable being used as the host parm.
150 """
151
152 if host_var_name == "":
153 host_var_name = gp.get_arg_name(0, 1, stack_frame_ix=2)
154
155 host_name_var_name = re.sub("host", "host_name", host_var_name)
156 ip_var_name = re.sub("host", "ip", host_var_name)
157 cmd_buf = "global " + host_name_var_name + ", " + ip_var_name + " ; " +\
158 host_name_var_name + ", " + ip_var_name + " = gm.get_host_name_ip('" +\
159 host + "')"
160 exec(cmd_buf)
161
Michael Walsh0ad0f7f2017-05-04 14:39:58 -0500162
Michael Walshb5839d02017-04-12 16:11:20 -0500163def process_pgm_parms():
Michael Walshb5839d02017-04-12 16:11:20 -0500164 r"""
165 Process the program parameters by assigning them all to corresponding
166 globals. Also, set some global values that depend on program parameters.
167 """
168
169 # Program parameter processing.
170 # Assign all program parms to python variables which are global to this
171 # module.
172
173 global parm_list
174 parm_list = BuiltIn().get_variable_value("${parm_list}")
175 # The following subset of parms should be processed as integers.
176 int_list = ['max_num_tests', 'boot_pass', 'boot_fail', 'ffdc_only',
Michael Walsh89de14a2018-10-01 16:51:37 -0500177 'boot_fail_threshold', 'delete_errlogs',
Michael Walsh986d8ae2019-07-17 10:02:23 -0500178 'call_post_stack_plug', 'do_pre_boot_plug_in_setup', 'quiet',
179 'test_mode', 'debug']
Michael Walshb5839d02017-04-12 16:11:20 -0500180 for parm in parm_list:
181 if parm in int_list:
182 sub_cmd = "int(BuiltIn().get_variable_value(\"${" + parm +\
183 "}\", \"0\"))"
184 else:
185 sub_cmd = "BuiltIn().get_variable_value(\"${" + parm + "}\")"
186 cmd_buf = "global " + parm + " ; " + parm + " = " + sub_cmd
Michael Walshff340002017-08-29 11:18:27 -0500187 gp.dpissuing(cmd_buf)
Michael Walshb5839d02017-04-12 16:11:20 -0500188 exec(cmd_buf)
Michael Walsh0ad0f7f2017-05-04 14:39:58 -0500189 if re.match(r".*_host$", parm):
190 cmd_buf = "process_host(" + parm + ", '" + parm + "')"
191 exec(cmd_buf)
192 if re.match(r".*_password$", parm):
193 # Register the value of any parm whose name ends in _password.
194 # This will cause the print functions to replace passwords with
195 # asterisks in the output.
196 cmd_buf = "gp.register_passwords(" + parm + ")"
197 exec(cmd_buf)
Michael Walshb5839d02017-04-12 16:11:20 -0500198
199 global ffdc_dir_path_style
200 global boot_list
201 global boot_stack
202 global boot_results_file_path
203 global boot_results
Michael Walsh986d8ae2019-07-17 10:02:23 -0500204 global boot_history
Michael Walshb5839d02017-04-12 16:11:20 -0500205 global ffdc_list_file_path
Michael Walshe0cf8d72017-05-17 13:20:46 -0500206 global ffdc_report_list_path
Michael Walsh600876d2017-05-30 17:58:58 -0500207 global ffdc_summary_list_path
Michael Walsha3e7b222020-02-03 15:32:16 -0600208 global boot_table
209 global valid_boot_types
Michael Walshb5839d02017-04-12 16:11:20 -0500210
211 if ffdc_dir_path_style == "":
212 ffdc_dir_path_style = int(os.environ.get('FFDC_DIR_PATH_STYLE', '0'))
213
214 # Convert these program parms to lists for easier processing..
George Keishing36efbc02018-12-12 10:18:23 -0600215 boot_list = list(filter(None, boot_list.split(":")))
216 boot_stack = list(filter(None, boot_stack.split(":")))
Michael Walshb5839d02017-04-12 16:11:20 -0500217
Michael Walsha3e7b222020-02-03 15:32:16 -0600218 boot_table = create_boot_table(boot_table_path, os_host=os_host)
219 valid_boot_types = create_valid_boot_list(boot_table)
220
Michael Walsh903e0b22017-09-19 17:00:33 -0500221 cleanup_boot_results_file()
222 boot_results_file_path = create_boot_results_file_path(pgm_name,
223 openbmc_nickname,
224 master_pid)
Michael Walshb5839d02017-04-12 16:11:20 -0500225
226 if os.path.isfile(boot_results_file_path):
227 # We've been called before in this run so we'll load the saved
Michael Walsh986d8ae2019-07-17 10:02:23 -0500228 # boot_results and boot_history objects.
229 boot_results, boot_history =\
Michael Walsh6c645742018-08-17 15:02:17 -0500230 pickle.load(open(boot_results_file_path, 'rb'))
Michael Walshb5839d02017-04-12 16:11:20 -0500231 else:
232 boot_results = boot_results(boot_table, boot_pass, boot_fail)
233
234 ffdc_list_file_path = base_tool_dir_path + openbmc_nickname +\
235 "/FFDC_FILE_LIST"
Michael Walshe0cf8d72017-05-17 13:20:46 -0500236 ffdc_report_list_path = base_tool_dir_path + openbmc_nickname +\
237 "/FFDC_REPORT_FILE_LIST"
Michael Walshb5839d02017-04-12 16:11:20 -0500238
Michael Walsh600876d2017-05-30 17:58:58 -0500239 ffdc_summary_list_path = base_tool_dir_path + openbmc_nickname +\
240 "/FFDC_SUMMARY_FILE_LIST"
241
Michael Walshb5839d02017-04-12 16:11:20 -0500242
Michael Walsh85678942017-03-27 14:34:22 -0500243def initial_plug_in_setup():
Michael Walsh85678942017-03-27 14:34:22 -0500244 r"""
245 Initialize all plug-in environment variables which do not change for the
246 duration of the program.
247
248 """
249
250 global LOG_LEVEL
251 BuiltIn().set_log_level("NONE")
252
253 BuiltIn().set_global_variable("${master_pid}", master_pid)
254 BuiltIn().set_global_variable("${FFDC_DIR_PATH}", ffdc_dir_path)
255 BuiltIn().set_global_variable("${STATUS_DIR_PATH}", status_dir_path)
256 BuiltIn().set_global_variable("${BASE_TOOL_DIR_PATH}", base_tool_dir_path)
257 BuiltIn().set_global_variable("${FFDC_LIST_FILE_PATH}",
258 ffdc_list_file_path)
Michael Walshe0cf8d72017-05-17 13:20:46 -0500259 BuiltIn().set_global_variable("${FFDC_REPORT_LIST_PATH}",
260 ffdc_report_list_path)
Michael Walsh600876d2017-05-30 17:58:58 -0500261 BuiltIn().set_global_variable("${FFDC_SUMMARY_LIST_PATH}",
262 ffdc_summary_list_path)
Michael Walsh85678942017-03-27 14:34:22 -0500263
264 BuiltIn().set_global_variable("${FFDC_DIR_PATH_STYLE}",
265 ffdc_dir_path_style)
266 BuiltIn().set_global_variable("${FFDC_CHECK}",
267 ffdc_check)
268
269 # For each program parameter, set the corresponding AUTOBOOT_ environment
270 # variable value. Also, set an AUTOBOOT_ environment variable for every
271 # element in additional_values.
272 additional_values = ["program_pid", "master_pid", "ffdc_dir_path",
273 "status_dir_path", "base_tool_dir_path",
Michael Walsh600876d2017-05-30 17:58:58 -0500274 "ffdc_list_file_path", "ffdc_report_list_path",
Michael Shepos7fe83b32020-09-21 15:46:01 -0500275 "ffdc_summary_list_path", "execdir", "redfish_supported",
George Keishing343cc782021-03-18 15:51:45 +0000276 "redfish_rest_supported"]
Michael Walsh85678942017-03-27 14:34:22 -0500277
278 plug_in_vars = parm_list + additional_values
279
280 for var_name in plug_in_vars:
281 var_value = BuiltIn().get_variable_value("${" + var_name + "}")
282 var_name = var_name.upper()
283 if var_value is None:
284 var_value = ""
285 os.environ["AUTOBOOT_" + var_name] = str(var_value)
286
287 BuiltIn().set_log_level(LOG_LEVEL)
288
Michael Walsh68a61162017-04-25 11:54:06 -0500289 # Make sure the ffdc list directory exists.
290 ffdc_list_dir_path = os.path.dirname(ffdc_list_file_path) + os.sep
291 if not os.path.exists(ffdc_list_dir_path):
292 os.makedirs(ffdc_list_dir_path)
Michael Walsh85678942017-03-27 14:34:22 -0500293
Michael Walsh85678942017-03-27 14:34:22 -0500294
Michael Walsh0bbd8602016-11-22 11:31:49 -0600295def plug_in_setup():
Michael Walsh0bbd8602016-11-22 11:31:49 -0600296 r"""
Michael Walsh85678942017-03-27 14:34:22 -0500297 Initialize all changing plug-in environment variables for use by the
298 plug-in programs.
Michael Walsh0bbd8602016-11-22 11:31:49 -0600299 """
300
Michael Walsh85678942017-03-27 14:34:22 -0500301 global LOG_LEVEL
302 global test_really_running
303
304 BuiltIn().set_log_level("NONE")
305
Michael Walsh6741f742017-02-20 16:16:38 -0600306 boot_pass, boot_fail = boot_results.return_total_pass_fail()
Michael Walsh0bbd8602016-11-22 11:31:49 -0600307 if boot_pass > 1:
308 test_really_running = 1
309 else:
310 test_really_running = 0
311
Michael Walsh6741f742017-02-20 16:16:38 -0600312 BuiltIn().set_global_variable("${test_really_running}",
313 test_really_running)
314 BuiltIn().set_global_variable("${boot_type_desc}", next_boot)
Michael Walsh6741f742017-02-20 16:16:38 -0600315 BuiltIn().set_global_variable("${boot_pass}", boot_pass)
316 BuiltIn().set_global_variable("${boot_fail}", boot_fail)
317 BuiltIn().set_global_variable("${boot_success}", boot_success)
318 BuiltIn().set_global_variable("${ffdc_prefix}", ffdc_prefix)
Sunil M325eb542017-08-10 07:09:43 -0500319 BuiltIn().set_global_variable("${boot_start_time}", boot_start_time)
320 BuiltIn().set_global_variable("${boot_end_time}", boot_end_time)
Michael Walsh4c9a6452016-12-13 16:03:11 -0600321
Michael Walsh0bbd8602016-11-22 11:31:49 -0600322 # For each program parameter, set the corresponding AUTOBOOT_ environment
323 # variable value. Also, set an AUTOBOOT_ environment variable for every
324 # element in additional_values.
325 additional_values = ["boot_type_desc", "boot_success", "boot_pass",
Sunil M325eb542017-08-10 07:09:43 -0500326 "boot_fail", "test_really_running", "ffdc_prefix",
327 "boot_start_time", "boot_end_time"]
Michael Walsh0bbd8602016-11-22 11:31:49 -0600328
Michael Walsh85678942017-03-27 14:34:22 -0500329 plug_in_vars = additional_values
Michael Walsh0bbd8602016-11-22 11:31:49 -0600330
331 for var_name in plug_in_vars:
332 var_value = BuiltIn().get_variable_value("${" + var_name + "}")
333 var_name = var_name.upper()
334 if var_value is None:
335 var_value = ""
Michael Walsh6741f742017-02-20 16:16:38 -0600336 os.environ["AUTOBOOT_" + var_name] = str(var_value)
Michael Walsh0bbd8602016-11-22 11:31:49 -0600337
Michael Walsh0bbd8602016-11-22 11:31:49 -0600338 if debug:
Michael Walsh6741f742017-02-20 16:16:38 -0600339 shell_rc, out_buf = \
340 gc.cmd_fnc_u("printenv | egrep AUTOBOOT_ | sort -u")
Michael Walsh0bbd8602016-11-22 11:31:49 -0600341
Michael Walsh85678942017-03-27 14:34:22 -0500342 BuiltIn().set_log_level(LOG_LEVEL)
343
Michael Walsh0bbd8602016-11-22 11:31:49 -0600344
Michael Walshe0cf8d72017-05-17 13:20:46 -0500345def pre_boot_plug_in_setup():
346
347 # Clear the ffdc_list_file_path file. Plug-ins may now write to it.
348 try:
349 os.remove(ffdc_list_file_path)
350 except OSError:
351 pass
352
353 # Clear the ffdc_report_list_path file. Plug-ins may now write to it.
354 try:
355 os.remove(ffdc_report_list_path)
356 except OSError:
357 pass
358
Michael Walsh600876d2017-05-30 17:58:58 -0500359 # Clear the ffdc_summary_list_path file. Plug-ins may now write to it.
360 try:
361 os.remove(ffdc_summary_list_path)
362 except OSError:
363 pass
364
Michael Walshe1974b92017-08-03 13:39:51 -0500365 global ffdc_prefix
366
367 seconds = time.time()
368 loc_time = time.localtime(seconds)
369 time_string = time.strftime("%y%m%d.%H%M%S.", loc_time)
370
371 ffdc_prefix = openbmc_nickname + "." + time_string
372
Michael Walshe0cf8d72017-05-17 13:20:46 -0500373
Michael Walshf566fb12019-02-01 14:35:09 -0600374def default_sigusr1(signal_number=0,
375 frame=None):
376 r"""
377 Handle SIGUSR1 by doing nothing.
378
379 This function assists in debugging SIGUSR1 processing by printing messages
380 to stdout and to the log.html file.
381
382 Description of argument(s):
383 signal_number The signal number (should always be 10 for SIGUSR1).
384 frame The frame data.
385 """
386
Michael Walsh80dddde2019-10-22 13:54:38 -0500387 gp.qprintn()
388 gp.qprint_executing()
Michael Walshf566fb12019-02-01 14:35:09 -0600389 gp.lprint_executing()
390
391
392def set_default_siguser1():
393 r"""
394 Set the default_sigusr1 function to be the SIGUSR1 handler.
395 """
396
Michael Walsh80dddde2019-10-22 13:54:38 -0500397 gp.qprintn()
398 gp.qprint_executing()
Michael Walshf566fb12019-02-01 14:35:09 -0600399 gp.lprint_executing()
400 signal.signal(signal.SIGUSR1, default_sigusr1)
401
402
Michael Walsh6741f742017-02-20 16:16:38 -0600403def setup():
Michael Walsh0bbd8602016-11-22 11:31:49 -0600404 r"""
Michael Walsh6741f742017-02-20 16:16:38 -0600405 Do general program setup tasks.
Michael Walsh0bbd8602016-11-22 11:31:49 -0600406 """
407
Michael Walsh6741f742017-02-20 16:16:38 -0600408 global cp_setup_called
Michael Walsh81816742017-09-27 11:02:29 -0500409 global transitional_boot_selected
Michael Walsh0bbd8602016-11-22 11:31:49 -0600410
Michael Walshb5839d02017-04-12 16:11:20 -0500411 gp.qprintn()
412
George Keishinga54e06f2020-06-12 10:42:41 -0500413 if redfish_supported:
414 redfish.login()
415
Michael Walshf566fb12019-02-01 14:35:09 -0600416 set_default_siguser1()
Michael Walsh81816742017-09-27 11:02:29 -0500417 transitional_boot_selected = False
418
Michael Walsh83f4bc72017-04-20 16:49:43 -0500419 robot_pgm_dir_path = os.path.dirname(__file__) + os.sep
420 repo_bin_path = robot_pgm_dir_path.replace("/lib/", "/bin/")
Michael Walshd061c042017-05-23 14:46:57 -0500421 # If we can't find process_plug_in_packages.py, ssh_pw or
422 # validate_plug_ins.py, then we don't have our repo bin in PATH.
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -0500423 shell_rc, out_buf = gc.cmd_fnc_u("which process_plug_in_packages.py"
424 + " ssh_pw validate_plug_ins.py", quiet=1,
Michael Walshd061c042017-05-23 14:46:57 -0500425 print_output=0, show_err=0)
Michael Walshb5839d02017-04-12 16:11:20 -0500426 if shell_rc != 0:
Michael Walsh83f4bc72017-04-20 16:49:43 -0500427 os.environ['PATH'] = repo_bin_path + ":" + os.environ.get('PATH', "")
428 # Likewise, our repo lib subdir needs to be in sys.path and PYTHONPATH.
429 if robot_pgm_dir_path not in sys.path:
430 sys.path.append(robot_pgm_dir_path)
431 PYTHONPATH = os.environ.get("PYTHONPATH", "")
432 if PYTHONPATH == "":
433 os.environ['PYTHONPATH'] = robot_pgm_dir_path
434 else:
435 os.environ['PYTHONPATH'] = robot_pgm_dir_path + ":" + PYTHONPATH
Michael Walsh6741f742017-02-20 16:16:38 -0600436
437 validate_parms()
438
Michael Walshc108e422019-03-28 12:27:18 -0500439 gp.qprint_pgm_header()
Michael Walsh6741f742017-02-20 16:16:38 -0600440
George Keishinga54e06f2020-06-12 10:42:41 -0500441 grk.run_key_u(default_set_power_policy)
Michael Walsh11cfc8c2017-03-31 09:40:55 -0500442
Michael Walsh85678942017-03-27 14:34:22 -0500443 initial_plug_in_setup()
444
Michael Walsh6741f742017-02-20 16:16:38 -0600445 plug_in_setup()
446 rc, shell_rc, failed_plug_in_name = grpi.rprocess_plug_in_packages(
447 call_point='setup')
448 if rc != 0:
449 error_message = "Plug-in setup failed.\n"
Michael Walshc108e422019-03-28 12:27:18 -0500450 gp.print_error_report(error_message)
Michael Walsh6741f742017-02-20 16:16:38 -0600451 BuiltIn().fail(error_message)
452 # Setting cp_setup_called lets our Teardown know that it needs to call
453 # the cleanup plug-in call point.
454 cp_setup_called = 1
455
456 # Keyword "FFDC" will fail if TEST_MESSAGE is not set.
457 BuiltIn().set_global_variable("${TEST_MESSAGE}", "${EMPTY}")
Michael Walsh85678942017-03-27 14:34:22 -0500458 # FFDC_LOG_PATH is used by "FFDC" keyword.
459 BuiltIn().set_global_variable("${FFDC_LOG_PATH}", ffdc_dir_path)
Michael Walsh6741f742017-02-20 16:16:38 -0600460
Michael Walshdc80d672017-05-09 12:58:32 -0500461 # Also printed by FFDC.
462 global host_name
463 global host_ip
464 host = socket.gethostname()
465 host_name, host_ip = gm.get_host_name_ip(host)
466
Michael Walsh986d8ae2019-07-17 10:02:23 -0500467 gp.dprint_var(boot_table)
Michael Walshb5839d02017-04-12 16:11:20 -0500468 gp.dprint_var(boot_lists)
Michael Walsh0bbd8602016-11-22 11:31:49 -0600469
Michael Walsh0bbd8602016-11-22 11:31:49 -0600470
Michael Walsh6741f742017-02-20 16:16:38 -0600471def validate_parms():
Michael Walsh0bbd8602016-11-22 11:31:49 -0600472 r"""
Michael Walsh6741f742017-02-20 16:16:38 -0600473 Validate all program parameters.
Michael Walsh0bbd8602016-11-22 11:31:49 -0600474 """
475
Michael Walshb5839d02017-04-12 16:11:20 -0500476 process_pgm_parms()
Michael Walsh0bbd8602016-11-22 11:31:49 -0600477
Michael Walshb5839d02017-04-12 16:11:20 -0500478 gp.qprintn()
479
480 global openbmc_model
Michael Walshf5ce38c2020-02-27 12:46:20 -0600481 if openbmc_model == "":
482 status, ret_values =\
483 grk.run_key_u("Get BMC System Model")
484 openbmc_model = ret_values
485 BuiltIn().set_global_variable("${openbmc_model}", openbmc_model)
486 gv.set_exit_on_error(True)
Michael Walsh44cef252019-08-01 12:38:56 -0500487 gv.valid_value(openbmc_host)
488 gv.valid_value(openbmc_username)
489 gv.valid_value(openbmc_password)
490 gv.valid_value(rest_username)
491 gv.valid_value(rest_password)
492 gv.valid_value(ipmi_username)
493 gv.valid_value(ipmi_password)
Michael Walsh6741f742017-02-20 16:16:38 -0600494 if os_host != "":
Michael Walsh44cef252019-08-01 12:38:56 -0500495 gv.valid_value(os_username)
496 gv.valid_value(os_password)
Michael Walsh6741f742017-02-20 16:16:38 -0600497 if pdu_host != "":
Michael Walsh44cef252019-08-01 12:38:56 -0500498 gv.valid_value(pdu_username)
499 gv.valid_value(pdu_password)
500 gv.valid_integer(pdu_slot_no)
Michael Walsh6741f742017-02-20 16:16:38 -0600501 if openbmc_serial_host != "":
Michael Walsh44cef252019-08-01 12:38:56 -0500502 gv.valid_integer(openbmc_serial_port)
Michael Walsh44cef252019-08-01 12:38:56 -0500503 gv.valid_value(openbmc_model)
504 gv.valid_integer(max_num_tests)
505 gv.valid_integer(boot_pass)
506 gv.valid_integer(boot_fail)
Michael Walsh6741f742017-02-20 16:16:38 -0600507 plug_in_packages_list = grpi.rvalidate_plug_ins(plug_in_dir_paths)
508 BuiltIn().set_global_variable("${plug_in_packages_list}",
509 plug_in_packages_list)
Michael Walsh44cef252019-08-01 12:38:56 -0500510 gv.valid_value(stack_mode, valid_values=['normal', 'skip'])
Michael Walshf5ce38c2020-02-27 12:46:20 -0600511 gv.set_exit_on_error(False)
Michael Walsha20da402017-03-31 16:27:45 -0500512 if len(boot_list) == 0 and len(boot_stack) == 0 and not ffdc_only:
Michael Walsh6741f742017-02-20 16:16:38 -0600513 error_message = "You must provide either a value for either the" +\
514 " boot_list or the boot_stack parm.\n"
515 BuiltIn().fail(gp.sprint_error(error_message))
Michael Walsh6741f742017-02-20 16:16:38 -0600516 valid_boot_list(boot_list, valid_boot_types)
517 valid_boot_list(boot_stack, valid_boot_types)
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -0500518 selected_PDU_boots = list(set(boot_list + boot_stack)
519 & set(boot_lists['PDU_reboot']))
Michael Walsh11cfc8c2017-03-31 09:40:55 -0500520 if len(selected_PDU_boots) > 0 and pdu_host == "":
521 error_message = "You have selected the following boots which" +\
522 " require a PDU host but no value for pdu_host:\n"
523 error_message += gp.sprint_var(selected_PDU_boots)
Michael Walsh986d8ae2019-07-17 10:02:23 -0500524 error_message += gp.sprint_var(pdu_host, fmt=gp.blank())
Michael Walsh11cfc8c2017-03-31 09:40:55 -0500525 BuiltIn().fail(gp.sprint_error(error_message))
526
Michael Walsh6741f742017-02-20 16:16:38 -0600527 return
Michael Walsh0bbd8602016-11-22 11:31:49 -0600528
Michael Walsh0bbd8602016-11-22 11:31:49 -0600529
Michael Walsh6741f742017-02-20 16:16:38 -0600530def my_get_state():
Michael Walsh0bbd8602016-11-22 11:31:49 -0600531 r"""
Michael Walsh6741f742017-02-20 16:16:38 -0600532 Get the system state plus a little bit of wrapping.
Michael Walsh0bbd8602016-11-22 11:31:49 -0600533 """
534
Michael Walsh6741f742017-02-20 16:16:38 -0600535 global state
536
537 req_states = ['epoch_seconds'] + st.default_req_states
538
Michael Walshb5839d02017-04-12 16:11:20 -0500539 gp.qprint_timen("Getting system state.")
Michael Walsh6741f742017-02-20 16:16:38 -0600540 if test_mode:
541 state['epoch_seconds'] = int(time.time())
542 else:
Michael Walshb5839d02017-04-12 16:11:20 -0500543 state = st.get_state(req_states=req_states, quiet=quiet)
544 gp.qprint_var(state)
Michael Walsh341c21e2017-01-17 16:25:20 -0600545
Michael Walsh341c21e2017-01-17 16:25:20 -0600546
Michael Walsh45ca6e42017-09-14 17:29:12 -0500547def valid_state():
Michael Walsh45ca6e42017-09-14 17:29:12 -0500548 r"""
549 Verify that our state dictionary contains no blank values. If we don't get
550 valid state data, we cannot continue to work.
551 """
552
553 if st.compare_states(state, st.invalid_state_match, 'or'):
554 error_message = "The state dictionary contains blank fields which" +\
555 " is illegal.\n" + gp.sprint_var(state)
556 BuiltIn().fail(gp.sprint_error(error_message))
557
Michael Walsh45ca6e42017-09-14 17:29:12 -0500558
Michael Walsh6741f742017-02-20 16:16:38 -0600559def select_boot():
Michael Walsh341c21e2017-01-17 16:25:20 -0600560 r"""
561 Select a boot test to be run based on our current state and return the
562 chosen boot type.
563
564 Description of arguments:
Michael Walsh6741f742017-02-20 16:16:38 -0600565 state The state of the machine.
Michael Walsh341c21e2017-01-17 16:25:20 -0600566 """
567
Michael Walsh81816742017-09-27 11:02:29 -0500568 global transitional_boot_selected
Michael Walsh30dadae2017-02-27 14:25:52 -0600569 global boot_stack
570
Michael Walshb5839d02017-04-12 16:11:20 -0500571 gp.qprint_timen("Selecting a boot test.")
Michael Walsh6741f742017-02-20 16:16:38 -0600572
Michael Walsh81816742017-09-27 11:02:29 -0500573 if transitional_boot_selected and not boot_success:
574 prior_boot = next_boot
575 boot_candidate = boot_stack.pop()
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -0500576 gp.qprint_timen("The prior '" + next_boot + "' was chosen to"
577 + " transition to a valid state for '" + boot_candidate
578 + "' which was at the top of the boot_stack. Since"
579 + " the '" + next_boot + "' failed, the '"
580 + boot_candidate + "' has been removed from the stack"
581 + " to avoid and endless failure loop.")
Michael Walsh81816742017-09-27 11:02:29 -0500582 if len(boot_stack) == 0:
583 return ""
584
Michael Walsh6741f742017-02-20 16:16:38 -0600585 my_get_state()
Michael Walsh45ca6e42017-09-14 17:29:12 -0500586 valid_state()
Michael Walsh6741f742017-02-20 16:16:38 -0600587
Michael Walsh81816742017-09-27 11:02:29 -0500588 transitional_boot_selected = False
Michael Walsh6741f742017-02-20 16:16:38 -0600589 stack_popped = 0
590 if len(boot_stack) > 0:
591 stack_popped = 1
Michael Walshb5839d02017-04-12 16:11:20 -0500592 gp.qprint_dashes()
593 gp.qprint_var(boot_stack)
594 gp.qprint_dashes()
595 skip_boot_printed = 0
596 while len(boot_stack) > 0:
597 boot_candidate = boot_stack.pop()
598 if stack_mode == 'normal':
599 break
600 else:
601 if st.compare_states(state, boot_table[boot_candidate]['end']):
602 if not skip_boot_printed:
Michael Walshff340002017-08-29 11:18:27 -0500603 gp.qprint_var(stack_mode)
604 gp.qprintn()
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -0500605 gp.qprint_timen("Skipping the following boot tests"
606 + " which are unnecessary since their"
607 + " required end states match the"
608 + " current machine state:")
Michael Walshb5839d02017-04-12 16:11:20 -0500609 skip_boot_printed = 1
Michael Walshff340002017-08-29 11:18:27 -0500610 gp.qprint_var(boot_candidate)
Michael Walshb5839d02017-04-12 16:11:20 -0500611 boot_candidate = ""
612 if boot_candidate == "":
613 gp.qprint_dashes()
614 gp.qprint_var(boot_stack)
615 gp.qprint_dashes()
616 return boot_candidate
Michael Walsh6741f742017-02-20 16:16:38 -0600617 if st.compare_states(state, boot_table[boot_candidate]['start']):
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -0500618 gp.qprint_timen("The machine state is valid for a '"
619 + boot_candidate + "' boot test.")
Michael Walshb5839d02017-04-12 16:11:20 -0500620 gp.qprint_dashes()
621 gp.qprint_var(boot_stack)
622 gp.qprint_dashes()
Michael Walsh6741f742017-02-20 16:16:38 -0600623 return boot_candidate
Michael Walsh341c21e2017-01-17 16:25:20 -0600624 else:
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -0500625 gp.qprint_timen("The machine state does not match the required"
626 + " starting state for a '" + boot_candidate
627 + "' boot test:")
Michael Walsh986d8ae2019-07-17 10:02:23 -0500628 gp.qprint_varx("boot_table_start_entry",
629 boot_table[boot_candidate]['start'])
Michael Walsh6741f742017-02-20 16:16:38 -0600630 boot_stack.append(boot_candidate)
Michael Walsh81816742017-09-27 11:02:29 -0500631 transitional_boot_selected = True
Michael Walsh6741f742017-02-20 16:16:38 -0600632 popped_boot = boot_candidate
633
634 # Loop through your list selecting a boot_candidates
635 boot_candidates = []
636 for boot_candidate in boot_list:
637 if st.compare_states(state, boot_table[boot_candidate]['start']):
638 if stack_popped:
639 if st.compare_states(boot_table[boot_candidate]['end'],
Gunnar Mills096cd562018-03-26 10:19:12 -0500640 boot_table[popped_boot]['start']):
Michael Walsh6741f742017-02-20 16:16:38 -0600641 boot_candidates.append(boot_candidate)
642 else:
643 boot_candidates.append(boot_candidate)
644
645 if len(boot_candidates) == 0:
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -0500646 gp.qprint_timen("The user's boot list contained no boot tests"
647 + " which are valid for the current machine state.")
Michael Walsh6741f742017-02-20 16:16:38 -0600648 boot_candidate = default_power_on
649 if not st.compare_states(state, boot_table[default_power_on]['start']):
650 boot_candidate = default_power_off
651 boot_candidates.append(boot_candidate)
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -0500652 gp.qprint_timen("Using default '" + boot_candidate
653 + "' boot type to transition to valid state.")
Michael Walsh6741f742017-02-20 16:16:38 -0600654
Michael Walshb5839d02017-04-12 16:11:20 -0500655 gp.dprint_var(boot_candidates)
Michael Walsh6741f742017-02-20 16:16:38 -0600656
657 # Randomly select a boot from the candidate list.
658 boot = random.choice(boot_candidates)
Michael Walsh341c21e2017-01-17 16:25:20 -0600659
660 return boot
Michael Walsh0bbd8602016-11-22 11:31:49 -0600661
Michael Walsh55302292017-01-10 11:43:02 -0600662
Michael Walshb2e53ec2017-10-30 15:04:36 -0500663def print_defect_report(ffdc_file_list):
Michael Walsh341c21e2017-01-17 16:25:20 -0600664 r"""
665 Print a defect report.
Michael Walshb2e53ec2017-10-30 15:04:36 -0500666
667 Description of argument(s):
668 ffdc_file_list A list of files which were collected by our ffdc functions.
Michael Walsh341c21e2017-01-17 16:25:20 -0600669 """
670
Michael Walsh600876d2017-05-30 17:58:58 -0500671 # Making deliberate choice to NOT run plug_in_setup(). We don't want
672 # ffdc_prefix updated.
673 rc, shell_rc, failed_plug_in_name = grpi.rprocess_plug_in_packages(
674 call_point='ffdc_report', stop_on_plug_in_failure=0)
675
Michael Walshe0cf8d72017-05-17 13:20:46 -0500676 # Get additional header data which may have been created by ffdc plug-ins.
677 # Also, delete the individual header files to cleanup.
678 cmd_buf = "file_list=$(cat " + ffdc_report_list_path + " 2>/dev/null)" +\
679 " ; [ ! -z \"${file_list}\" ] && cat ${file_list}" +\
680 " 2>/dev/null ; rm -rf ${file_list} 2>/dev/null || :"
681 shell_rc, more_header_info = gc.cmd_fnc_u(cmd_buf, print_output=0,
682 show_err=0)
683
Michael Walshb2e53ec2017-10-30 15:04:36 -0500684 # Get additional summary data which may have been created by ffdc plug-ins.
Michael Walsh600876d2017-05-30 17:58:58 -0500685 # Also, delete the individual header files to cleanup.
686 cmd_buf = "file_list=$(cat " + ffdc_summary_list_path + " 2>/dev/null)" +\
687 " ; [ ! -z \"${file_list}\" ] && cat ${file_list}" +\
688 " 2>/dev/null ; rm -rf ${file_list} 2>/dev/null || :"
689 shell_rc, ffdc_summary_info = gc.cmd_fnc_u(cmd_buf, print_output=0,
690 show_err=0)
691
Michael Walshb2e53ec2017-10-30 15:04:36 -0500692 # ffdc_list_file_path contains a list of any ffdc files created by plug-
693 # ins, etc. Read that data into a list.
Michael Walsh341c21e2017-01-17 16:25:20 -0600694 try:
Michael Walshb2e53ec2017-10-30 15:04:36 -0500695 plug_in_ffdc_list = \
696 open(ffdc_list_file_path, 'r').read().rstrip("\n").split("\n")
George Keishing36efbc02018-12-12 10:18:23 -0600697 plug_in_ffdc_list = list(filter(None, plug_in_ffdc_list))
Michael Walsh341c21e2017-01-17 16:25:20 -0600698 except IOError:
Michael Walshb2e53ec2017-10-30 15:04:36 -0500699 plug_in_ffdc_list = []
700
701 # Combine the files from plug_in_ffdc_list with the ffdc_file_list passed
702 # in. Eliminate duplicates and sort the list.
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -0500703 ffdc_file_list = sorted(set(ffdc_file_list + plug_in_ffdc_list))
Michael Walshb2e53ec2017-10-30 15:04:36 -0500704
705 if status_file_path != "":
706 ffdc_file_list.insert(0, status_file_path)
707
708 # Convert the list to a printable list.
709 printable_ffdc_file_list = "\n".join(ffdc_file_list)
Michael Walsh341c21e2017-01-17 16:25:20 -0600710
Michael Walsh68a61162017-04-25 11:54:06 -0500711 # Open ffdc_file_list for writing. We will write a complete list of
712 # FFDC files to it for possible use by plug-ins like cp_stop_check.
713 ffdc_list_file = open(ffdc_list_file_path, 'w')
Michael Walshb2e53ec2017-10-30 15:04:36 -0500714 ffdc_list_file.write(printable_ffdc_file_list + "\n")
715 ffdc_list_file.close()
716
717 indent = 0
718 width = 90
719 linefeed = 1
720 char = "="
Michael Walsh68a61162017-04-25 11:54:06 -0500721
722 gp.qprintn()
Michael Walshb2e53ec2017-10-30 15:04:36 -0500723 gp.qprint_dashes(indent, width, linefeed, char)
Michael Walsh68a61162017-04-25 11:54:06 -0500724 gp.qprintn("Copy this data to the defect:\n")
725
Michael Walshe0cf8d72017-05-17 13:20:46 -0500726 if len(more_header_info) > 0:
Michael Walshff340002017-08-29 11:18:27 -0500727 gp.qprintn(more_header_info)
Michael Walshdc80d672017-05-09 12:58:32 -0500728 gp.qpvars(host_name, host_ip, openbmc_nickname, openbmc_host,
729 openbmc_host_name, openbmc_ip, openbmc_username,
Michael Walsh0a3bdb42019-01-31 16:21:44 +0000730 openbmc_password, rest_username, rest_password, ipmi_username,
731 ipmi_password, os_host, os_host_name, os_ip, os_username,
Michael Walshdc80d672017-05-09 12:58:32 -0500732 os_password, pdu_host, pdu_host_name, pdu_ip, pdu_username,
733 pdu_password, pdu_slot_no, openbmc_serial_host,
734 openbmc_serial_host_name, openbmc_serial_ip, openbmc_serial_port)
Michael Walsh68a61162017-04-25 11:54:06 -0500735
736 gp.qprintn()
Michael Walsh986d8ae2019-07-17 10:02:23 -0500737 print_boot_history(boot_history)
Michael Walsh68a61162017-04-25 11:54:06 -0500738 gp.qprintn()
739 gp.qprint_var(state)
Michael Walshb5839d02017-04-12 16:11:20 -0500740 gp.qprintn()
741 gp.qprintn("FFDC data files:")
Michael Walshb2e53ec2017-10-30 15:04:36 -0500742 gp.qprintn(printable_ffdc_file_list)
Michael Walshb5839d02017-04-12 16:11:20 -0500743 gp.qprintn()
Michael Walsh341c21e2017-01-17 16:25:20 -0600744
Michael Walsh600876d2017-05-30 17:58:58 -0500745 if len(ffdc_summary_info) > 0:
Michael Walshff340002017-08-29 11:18:27 -0500746 gp.qprintn(ffdc_summary_info)
Michael Walsh600876d2017-05-30 17:58:58 -0500747
Michael Walshb2e53ec2017-10-30 15:04:36 -0500748 gp.qprint_dashes(indent, width, linefeed, char)
Michael Walsh68a61162017-04-25 11:54:06 -0500749
Michael Walsh6741f742017-02-20 16:16:38 -0600750
Michael Walsh6741f742017-02-20 16:16:38 -0600751def my_ffdc():
Michael Walsh6741f742017-02-20 16:16:38 -0600752 r"""
753 Collect FFDC data.
754 """
755
756 global state
757
758 plug_in_setup()
759 rc, shell_rc, failed_plug_in_name = grpi.rprocess_plug_in_packages(
Michael Walsh600876d2017-05-30 17:58:58 -0500760 call_point='ffdc', stop_on_plug_in_failure=0)
Michael Walsh6741f742017-02-20 16:16:38 -0600761
762 AUTOBOOT_FFDC_PREFIX = os.environ['AUTOBOOT_FFDC_PREFIX']
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -0500763 status, ffdc_file_list = grk.run_key_u("FFDC ffdc_prefix="
764 + AUTOBOOT_FFDC_PREFIX
765 + " ffdc_function_list="
766 + ffdc_function_list, ignore=1)
Michael Walsh83f4bc72017-04-20 16:49:43 -0500767 if status != 'PASS':
Michael Walshff340002017-08-29 11:18:27 -0500768 gp.qprint_error("Call to ffdc failed.\n")
Michael Walshc9bd2e82019-04-18 11:06:52 -0500769 if type(ffdc_file_list) is not list:
770 ffdc_file_list = []
771 # Leave a record for caller that "soft" errors occurred.
772 soft_errors = 1
773 gpu.save_plug_in_value(soft_errors, pgm_name)
Michael Walsh6741f742017-02-20 16:16:38 -0600774
775 my_get_state()
776
Michael Walshb2e53ec2017-10-30 15:04:36 -0500777 print_defect_report(ffdc_file_list)
Michael Walsh6741f742017-02-20 16:16:38 -0600778
Michael Walsh6741f742017-02-20 16:16:38 -0600779
Michael Walsh6741f742017-02-20 16:16:38 -0600780def print_test_start_message(boot_keyword):
Michael Walsh6741f742017-02-20 16:16:38 -0600781 r"""
782 Print a message indicating what boot test is about to run.
783
784 Description of arguments:
785 boot_keyword The name of the boot which is to be run
786 (e.g. "BMC Power On").
787 """
788
Michael Walsh986d8ae2019-07-17 10:02:23 -0500789 global boot_history
Sunil M325eb542017-08-10 07:09:43 -0500790 global boot_start_time
Michael Walsh6741f742017-02-20 16:16:38 -0600791
792 doing_msg = gp.sprint_timen("Doing \"" + boot_keyword + "\".")
Sunil M325eb542017-08-10 07:09:43 -0500793
794 # Set boot_start_time for use by plug-ins.
795 boot_start_time = doing_msg[1:33]
796 gp.qprint_var(boot_start_time)
797
Michael Walshb5839d02017-04-12 16:11:20 -0500798 gp.qprint(doing_msg)
Michael Walsh6741f742017-02-20 16:16:38 -0600799
Michael Walsh986d8ae2019-07-17 10:02:23 -0500800 update_boot_history(boot_history, doing_msg, max_boot_history)
Michael Walsh6741f742017-02-20 16:16:38 -0600801
Michael Walsh6741f742017-02-20 16:16:38 -0600802
Michael Walshf566fb12019-02-01 14:35:09 -0600803def stop_boot_test(signal_number=0,
804 frame=None):
805 r"""
806 Handle SIGUSR1 by aborting the boot test that is running.
807
808 Description of argument(s):
809 signal_number The signal number (should always be 10 for SIGUSR1).
810 frame The frame data.
811 """
812
Michael Walsh80dddde2019-10-22 13:54:38 -0500813 gp.qprintn()
814 gp.qprint_executing()
Michael Walshf566fb12019-02-01 14:35:09 -0600815 gp.lprint_executing()
816
817 # Restore original sigusr1 handler.
818 set_default_siguser1()
819
820 message = "The caller has asked that the boot test be stopped and marked"
821 message += " as a failure."
822
823 function_stack = gm.get_function_stack()
824 if "wait_state" in function_stack:
Michael Walshc44aa532019-06-14 13:33:29 -0500825 st.set_exit_wait_early_message(message)
Michael Walshf566fb12019-02-01 14:35:09 -0600826 else:
827 BuiltIn().fail(gp.sprint_error(message))
828
829
Michael Walsh6741f742017-02-20 16:16:38 -0600830def run_boot(boot):
Michael Walsh6741f742017-02-20 16:16:38 -0600831 r"""
832 Run the specified boot.
833
834 Description of arguments:
835 boot The name of the boot test to be performed.
836 """
837
838 global state
839
Michael Walshf566fb12019-02-01 14:35:09 -0600840 signal.signal(signal.SIGUSR1, stop_boot_test)
841 gp.qprint_timen("stop_boot_test is armed.")
842
Michael Walsh6741f742017-02-20 16:16:38 -0600843 print_test_start_message(boot)
844
845 plug_in_setup()
846 rc, shell_rc, failed_plug_in_name = \
847 grpi.rprocess_plug_in_packages(call_point="pre_boot")
848 if rc != 0:
849 error_message = "Plug-in failed with non-zero return code.\n" +\
Michael Walsh986d8ae2019-07-17 10:02:23 -0500850 gp.sprint_var(rc, fmt=gp.hexa())
Michael Walshf566fb12019-02-01 14:35:09 -0600851 set_default_siguser1()
Michael Walsh6741f742017-02-20 16:16:38 -0600852 BuiltIn().fail(gp.sprint_error(error_message))
853
854 if test_mode:
855 # In test mode, we'll pretend the boot worked by assigning its
856 # required end state to the default state value.
Michael Walsh30dadae2017-02-27 14:25:52 -0600857 state = st.strip_anchor_state(boot_table[boot]['end'])
Michael Walsh6741f742017-02-20 16:16:38 -0600858 else:
859 # Assertion: We trust that the state data was made fresh by the
860 # caller.
861
Michael Walshb5839d02017-04-12 16:11:20 -0500862 gp.qprintn()
Michael Walsh6741f742017-02-20 16:16:38 -0600863
864 if boot_table[boot]['method_type'] == "keyword":
Michael Walsh0b93fbf2017-03-02 14:42:41 -0600865 rk.my_run_keywords(boot_table[boot].get('lib_file_path', ''),
Michael Walshb5839d02017-04-12 16:11:20 -0500866 boot_table[boot]['method'],
867 quiet=quiet)
Michael Walsh6741f742017-02-20 16:16:38 -0600868
869 if boot_table[boot]['bmc_reboot']:
870 st.wait_for_comm_cycle(int(state['epoch_seconds']))
Michael Walsh30dadae2017-02-27 14:25:52 -0600871 plug_in_setup()
872 rc, shell_rc, failed_plug_in_name = \
873 grpi.rprocess_plug_in_packages(call_point="post_reboot")
874 if rc != 0:
Michael Walsh0b93fbf2017-03-02 14:42:41 -0600875 error_message = "Plug-in failed with non-zero return code.\n"
Michael Walsh986d8ae2019-07-17 10:02:23 -0500876 error_message += gp.sprint_var(rc, fmt=gp.hexa())
Michael Walshf566fb12019-02-01 14:35:09 -0600877 set_default_siguser1()
Michael Walsh30dadae2017-02-27 14:25:52 -0600878 BuiltIn().fail(gp.sprint_error(error_message))
Michael Walsh6741f742017-02-20 16:16:38 -0600879 else:
880 match_state = st.anchor_state(state)
881 del match_state['epoch_seconds']
882 # Wait for the state to change in any way.
883 st.wait_state(match_state, wait_time=state_change_timeout,
Michael Walsh600876d2017-05-30 17:58:58 -0500884 interval="10 seconds", invert=1)
Michael Walsh6741f742017-02-20 16:16:38 -0600885
Michael Walshb5839d02017-04-12 16:11:20 -0500886 gp.qprintn()
Michael Walsh6741f742017-02-20 16:16:38 -0600887 if boot_table[boot]['end']['chassis'] == "Off":
888 boot_timeout = power_off_timeout
889 else:
890 boot_timeout = power_on_timeout
891 st.wait_state(boot_table[boot]['end'], wait_time=boot_timeout,
Michael Walsh600876d2017-05-30 17:58:58 -0500892 interval="10 seconds")
Michael Walsh6741f742017-02-20 16:16:38 -0600893
894 plug_in_setup()
895 rc, shell_rc, failed_plug_in_name = \
896 grpi.rprocess_plug_in_packages(call_point="post_boot")
897 if rc != 0:
898 error_message = "Plug-in failed with non-zero return code.\n" +\
Michael Walsh986d8ae2019-07-17 10:02:23 -0500899 gp.sprint_var(rc, fmt=gp.hexa())
Michael Walshf566fb12019-02-01 14:35:09 -0600900 set_default_siguser1()
Michael Walsh6741f742017-02-20 16:16:38 -0600901 BuiltIn().fail(gp.sprint_error(error_message))
902
Michael Walshf566fb12019-02-01 14:35:09 -0600903 # Restore original sigusr1 handler.
904 set_default_siguser1()
905
Michael Walsh6741f742017-02-20 16:16:38 -0600906
Michael Walsh6741f742017-02-20 16:16:38 -0600907def test_loop_body():
Michael Walsh6741f742017-02-20 16:16:38 -0600908 r"""
909 The main loop body for the loop in main_py.
910
911 Description of arguments:
912 boot_count The iteration number (starts at 1).
913 """
914
915 global boot_count
916 global state
917 global next_boot
918 global boot_success
Sunil M325eb542017-08-10 07:09:43 -0500919 global boot_end_time
Michael Walsh6741f742017-02-20 16:16:38 -0600920
Michael Walshb5839d02017-04-12 16:11:20 -0500921 gp.qprintn()
Michael Walsh6741f742017-02-20 16:16:38 -0600922
923 next_boot = select_boot()
Michael Walshb5839d02017-04-12 16:11:20 -0500924 if next_boot == "":
925 return True
Michael Walsh6741f742017-02-20 16:16:38 -0600926
Michael Walshb5839d02017-04-12 16:11:20 -0500927 boot_count += 1
928 gp.qprint_timen("Starting boot " + str(boot_count) + ".")
Michael Walsh6741f742017-02-20 16:16:38 -0600929
Michael Walshe0cf8d72017-05-17 13:20:46 -0500930 pre_boot_plug_in_setup()
Michael Walsh6741f742017-02-20 16:16:38 -0600931
932 cmd_buf = ["run_boot", next_boot]
933 boot_status, msg = BuiltIn().run_keyword_and_ignore_error(*cmd_buf)
934 if boot_status == "FAIL":
Michael Walshb5839d02017-04-12 16:11:20 -0500935 gp.qprint(msg)
Michael Walsh6741f742017-02-20 16:16:38 -0600936
Michael Walshb5839d02017-04-12 16:11:20 -0500937 gp.qprintn()
Michael Walsh6741f742017-02-20 16:16:38 -0600938 if boot_status == "PASS":
939 boot_success = 1
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -0500940 completion_msg = gp.sprint_timen("BOOT_SUCCESS: \"" + next_boot
941 + "\" succeeded.")
Michael Walsh6741f742017-02-20 16:16:38 -0600942 else:
943 boot_success = 0
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -0500944 completion_msg = gp.sprint_timen("BOOT_FAILED: \"" + next_boot
945 + "\" failed.")
Sunil M325eb542017-08-10 07:09:43 -0500946
947 # Set boot_end_time for use by plug-ins.
948 boot_end_time = completion_msg[1:33]
949 gp.qprint_var(boot_end_time)
950
951 gp.qprint(completion_msg)
Michael Walsh6741f742017-02-20 16:16:38 -0600952
953 boot_results.update(next_boot, boot_status)
954
955 plug_in_setup()
956 # NOTE: A post_test_case call point failure is NOT counted as a boot
957 # failure.
958 rc, shell_rc, failed_plug_in_name = grpi.rprocess_plug_in_packages(
Michael Walsh600876d2017-05-30 17:58:58 -0500959 call_point='post_test_case', stop_on_plug_in_failure=0)
Michael Walsh6741f742017-02-20 16:16:38 -0600960
961 plug_in_setup()
962 rc, shell_rc, failed_plug_in_name = grpi.rprocess_plug_in_packages(
Michael Walsh89de14a2018-10-01 16:51:37 -0500963 call_point='ffdc_check', shell_rc=dump_ffdc_rc(),
Michael Walsh6741f742017-02-20 16:16:38 -0600964 stop_on_plug_in_failure=1, stop_on_non_zero_rc=1)
Michael Walsh12059e22019-03-21 11:03:45 -0500965 if ffdc_check == "All" or\
Michael Walsh89de14a2018-10-01 16:51:37 -0500966 shell_rc == dump_ffdc_rc():
Michael Walsh83f4bc72017-04-20 16:49:43 -0500967 status, ret_values = grk.run_key_u("my_ffdc", ignore=1)
968 if status != 'PASS':
Michael Walshff340002017-08-29 11:18:27 -0500969 gp.qprint_error("Call to my_ffdc failed.\n")
Michael Walshc9bd2e82019-04-18 11:06:52 -0500970 # Leave a record for caller that "soft" errors occurred.
971 soft_errors = 1
972 gpu.save_plug_in_value(soft_errors, pgm_name)
Michael Walsh6741f742017-02-20 16:16:38 -0600973
Michael Walshaabef1e2017-09-20 15:16:17 -0500974 if delete_errlogs:
Michael Shepos1a67b082020-08-28 16:01:58 -0500975 # print error logs before delete
976 status, error_logs = grk.run_key_u("Get Error Logs")
977 pels = pel.peltool("-l", ignore_err=1)
Michael Shepos0e5f1132020-09-30 16:24:25 -0500978 log.print_error_logs(error_logs, "AdditionalData Message Severity")
979 gp.qprint_var(pels)
Michael Shepos1a67b082020-08-28 16:01:58 -0500980
Michael Walshaabef1e2017-09-20 15:16:17 -0500981 # We need to purge error logs between boots or they build up.
Michael Walsh409ad352020-02-06 11:46:35 -0600982 grk.run_key(delete_errlogs_cmd, ignore=1)
Michael Shepos92a54bf2020-11-11 11:48:55 -0600983 grk.run_key(delete_bmcdump_cmd, ignore=1)
Michael Walshd139f282017-04-04 18:00:23 -0500984
Michael Walsh952f9b02017-03-09 13:11:14 -0600985 boot_results.print_report()
Michael Walshb5839d02017-04-12 16:11:20 -0500986 gp.qprint_timen("Finished boot " + str(boot_count) + ".")
Michael Walsh952f9b02017-03-09 13:11:14 -0600987
Michael Walsh6741f742017-02-20 16:16:38 -0600988 plug_in_setup()
989 rc, shell_rc, failed_plug_in_name = grpi.rprocess_plug_in_packages(
Michael Walsh89de14a2018-10-01 16:51:37 -0500990 call_point='stop_check', shell_rc=stop_test_rc(),
991 stop_on_non_zero_rc=1)
992 if shell_rc == stop_test_rc():
Michael Walsh3ba8ecd2018-04-24 11:33:25 -0500993 message = "Stopping as requested by user.\n"
Michael Walsh80dddde2019-10-22 13:54:38 -0500994 gp.qprint_time(message)
Michael Walsh3ba8ecd2018-04-24 11:33:25 -0500995 BuiltIn().fail(message)
Michael Walsh6741f742017-02-20 16:16:38 -0600996
Michael Walshd139f282017-04-04 18:00:23 -0500997 # This should help prevent ConnectionErrors.
George Keishing4d65c862020-12-03 06:52:11 -0600998 # Purge all redfish and REST connection sessions.
George Keishingd86e45c2021-03-19 07:38:14 -0500999 if redfish_delete_sessions:
1000 grk.run_key_u("Close All Connections", ignore=1)
1001 grk.run_key_u("Delete All Redfish Sessions", ignore=1)
Michael Walshd139f282017-04-04 18:00:23 -05001002
Michael Walsh6741f742017-02-20 16:16:38 -06001003 return True
1004
Michael Walsh6741f742017-02-20 16:16:38 -06001005
Michael Walsh83f4bc72017-04-20 16:49:43 -05001006def obmc_boot_test_teardown():
Michael Walsh6741f742017-02-20 16:16:38 -06001007 r"""
Michael Walshf75d4352019-12-05 17:01:20 -06001008 Clean up after the main keyword.
Michael Walsh6741f742017-02-20 16:16:38 -06001009 """
Michael Walshf75d4352019-12-05 17:01:20 -06001010 gp.qprint_executing()
1011
1012 if ga.psutil_imported:
1013 ga.terminate_descendants()
Michael Walsh6741f742017-02-20 16:16:38 -06001014
1015 if cp_setup_called:
1016 plug_in_setup()
1017 rc, shell_rc, failed_plug_in_name = grpi.rprocess_plug_in_packages(
Michael Walsh600876d2017-05-30 17:58:58 -05001018 call_point='cleanup', stop_on_plug_in_failure=0)
Michael Walsh6741f742017-02-20 16:16:38 -06001019
Michael Walsh600876d2017-05-30 17:58:58 -05001020 if 'boot_results_file_path' in globals():
Michael Walsh986d8ae2019-07-17 10:02:23 -05001021 # Save boot_results and boot_history objects to a file in case they are
Michael Walsh6c645742018-08-17 15:02:17 -05001022 # needed again.
Michael Walsh600876d2017-05-30 17:58:58 -05001023 gp.qprint_timen("Saving boot_results to the following path.")
1024 gp.qprint_var(boot_results_file_path)
Michael Walsh986d8ae2019-07-17 10:02:23 -05001025 pickle.dump((boot_results, boot_history),
Michael Walsh6c645742018-08-17 15:02:17 -05001026 open(boot_results_file_path, 'wb'),
Michael Walsh600876d2017-05-30 17:58:58 -05001027 pickle.HIGHEST_PROTOCOL)
Michael Walsh0b93fbf2017-03-02 14:42:41 -06001028
Michael Walshff340002017-08-29 11:18:27 -05001029 global save_stack
1030 # Restore any global values saved on the save_stack.
1031 for parm_name in main_func_parm_list:
1032 # Get the parm_value if it was saved on the stack.
1033 try:
1034 parm_value = save_stack.pop(parm_name)
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -05001035 except BaseException:
Michael Walshff340002017-08-29 11:18:27 -05001036 # If it was not saved, no further action is required.
1037 continue
1038
1039 # Restore the saved value.
1040 cmd_buf = "BuiltIn().set_global_variable(\"${" + parm_name +\
1041 "}\", parm_value)"
1042 gp.dpissuing(cmd_buf)
1043 exec(cmd_buf)
1044
1045 gp.dprintn(save_stack.sprint_obj())
1046
Michael Walsh6741f742017-02-20 16:16:38 -06001047
Michael Walshc9116812017-03-10 14:23:06 -06001048def test_teardown():
Michael Walshc9116812017-03-10 14:23:06 -06001049 r"""
1050 Clean up after this test case.
1051 """
1052
1053 gp.qprintn()
Michael Walshf75d4352019-12-05 17:01:20 -06001054 gp.qprint_executing()
1055
1056 if ga.psutil_imported:
1057 ga.terminate_descendants()
1058
Michael Walshc9116812017-03-10 14:23:06 -06001059 cmd_buf = ["Print Error",
1060 "A keyword timeout occurred ending this program.\n"]
1061 BuiltIn().run_keyword_if_timeout_occurred(*cmd_buf)
1062
George Keishinga54e06f2020-06-12 10:42:41 -05001063 if redfish_supported:
1064 redfish.logout()
1065
Michael Walshc108e422019-03-28 12:27:18 -05001066 gp.qprint_pgm_footer()
Michael Walshb5839d02017-04-12 16:11:20 -05001067
Michael Walshc9116812017-03-10 14:23:06 -06001068
Michael Walsh89de14a2018-10-01 16:51:37 -05001069def post_stack():
1070 r"""
1071 Process post_stack plug-in programs.
1072 """
1073
1074 if not call_post_stack_plug:
1075 # The caller does not wish to have post_stack plug-in processing done.
1076 return
1077
1078 global boot_success
1079
1080 # NOTE: A post_stack call-point failure is NOT counted as a boot failure.
1081 pre_boot_plug_in_setup()
1082 # For the purposes of the following plug-ins, mark the "boot" as a success.
1083 boot_success = 1
1084 plug_in_setup()
Michael Walsh815b1d52018-10-30 13:32:26 -05001085 rc, shell_rc, failed_plug_in_name, history =\
1086 grpi.rprocess_plug_in_packages(call_point='post_stack',
1087 stop_on_plug_in_failure=0,
1088 return_history=True)
Michael Walsh986d8ae2019-07-17 10:02:23 -05001089 for doing_msg in history:
1090 update_boot_history(boot_history, doing_msg, max_boot_history)
Michael Walsh815b1d52018-10-30 13:32:26 -05001091 if rc != 0:
1092 boot_success = 0
Michael Walsh89de14a2018-10-01 16:51:37 -05001093
1094 plug_in_setup()
Michael Walsh815b1d52018-10-30 13:32:26 -05001095 rc, shell_rc, failed_plug_in_name =\
1096 grpi.rprocess_plug_in_packages(call_point='ffdc_check',
1097 shell_rc=dump_ffdc_rc(),
1098 stop_on_plug_in_failure=1,
1099 stop_on_non_zero_rc=1)
1100 if shell_rc == dump_ffdc_rc():
Michael Walsh89de14a2018-10-01 16:51:37 -05001101 status, ret_values = grk.run_key_u("my_ffdc", ignore=1)
1102 if status != 'PASS':
1103 gp.qprint_error("Call to my_ffdc failed.\n")
Michael Walshc9bd2e82019-04-18 11:06:52 -05001104 # Leave a record for caller that "soft" errors occurred.
1105 soft_errors = 1
1106 gpu.save_plug_in_value(soft_errors, pgm_name)
Michael Walsh89de14a2018-10-01 16:51:37 -05001107
1108 plug_in_setup()
1109 rc, shell_rc, failed_plug_in_name = grpi.rprocess_plug_in_packages(
1110 call_point='stop_check', shell_rc=stop_test_rc(),
1111 stop_on_non_zero_rc=1)
1112 if shell_rc == stop_test_rc():
1113 message = "Stopping as requested by user.\n"
Michael Walsh80dddde2019-10-22 13:54:38 -05001114 gp.qprint_time(message)
Michael Walsh89de14a2018-10-01 16:51:37 -05001115 BuiltIn().fail(message)
1116
1117
Michael Walshff340002017-08-29 11:18:27 -05001118def obmc_boot_test_py(loc_boot_stack=None,
1119 loc_stack_mode=None,
1120 loc_quiet=None):
Michael Walsh6741f742017-02-20 16:16:38 -06001121 r"""
1122 Do main program processing.
1123 """
1124
Michael Walshff340002017-08-29 11:18:27 -05001125 global save_stack
1126
Michael Walshf75d4352019-12-05 17:01:20 -06001127 ga.set_term_options(term_requests={'pgm_names': ['process_plug_in_packages.py']})
1128
George Keishing36efbc02018-12-12 10:18:23 -06001129 gp.dprintn()
Michael Walshff340002017-08-29 11:18:27 -05001130 # Process function parms.
1131 for parm_name in main_func_parm_list:
1132 # Get parm's value.
George Keishing36efbc02018-12-12 10:18:23 -06001133 parm_value = eval("loc_" + parm_name)
1134 gp.dpvars(parm_name, parm_value)
Michael Walshff340002017-08-29 11:18:27 -05001135
George Keishing36efbc02018-12-12 10:18:23 -06001136 if parm_value is not None:
Michael Walshff340002017-08-29 11:18:27 -05001137 # Save the global value on a stack.
1138 cmd_buf = "save_stack.push(BuiltIn().get_variable_value(\"${" +\
1139 parm_name + "}\"), \"" + parm_name + "\")"
1140 gp.dpissuing(cmd_buf)
1141 exec(cmd_buf)
1142
1143 # Set the global value to the passed value.
1144 cmd_buf = "BuiltIn().set_global_variable(\"${" + parm_name +\
1145 "}\", loc_" + parm_name + ")"
1146 gp.dpissuing(cmd_buf)
1147 exec(cmd_buf)
1148
1149 gp.dprintn(save_stack.sprint_obj())
Michael Walshb5839d02017-04-12 16:11:20 -05001150
Michael Walsh6741f742017-02-20 16:16:38 -06001151 setup()
1152
Michael Walshcd9fbfd2017-09-19 12:00:08 -05001153 init_boot_pass, init_boot_fail = boot_results.return_total_pass_fail()
1154
Michael Walsha20da402017-03-31 16:27:45 -05001155 if ffdc_only:
1156 gp.qprint_timen("Caller requested ffdc_only.")
Michael Walsh986d8ae2019-07-17 10:02:23 -05001157 if do_pre_boot_plug_in_setup:
1158 pre_boot_plug_in_setup()
Michael Walsh83f4bc72017-04-20 16:49:43 -05001159 grk.run_key_u("my_ffdc")
Michael Walsh764d2f82017-04-27 16:01:08 -05001160 return
Michael Walsha20da402017-03-31 16:27:45 -05001161
Michael Walsh409ad352020-02-06 11:46:35 -06001162 if delete_errlogs:
Michael Shepos1a67b082020-08-28 16:01:58 -05001163 # print error logs before delete
1164 status, error_logs = grk.run_key_u("Get Error Logs")
1165 pels = pel.peltool("-l", ignore_err=1)
Michael Shepos0e5f1132020-09-30 16:24:25 -05001166 log.print_error_logs(error_logs, "AdditionalData Message Severity")
1167 gp.qprint_var(pels)
Michael Shepos1a67b082020-08-28 16:01:58 -05001168
Michael Walsh409ad352020-02-06 11:46:35 -06001169 # Delete errlogs prior to doing any boot tests.
1170 grk.run_key(delete_errlogs_cmd, ignore=1)
Michael Shepos92a54bf2020-11-11 11:48:55 -06001171 grk.run_key(delete_bmcdump_cmd, ignore=1)
Michael Walsh409ad352020-02-06 11:46:35 -06001172
Michael Walsh6741f742017-02-20 16:16:38 -06001173 # Process caller's boot_stack.
1174 while (len(boot_stack) > 0):
1175 test_loop_body()
1176
Michael Walshb5839d02017-04-12 16:11:20 -05001177 gp.qprint_timen("Finished processing stack.")
Michael Walsh30dadae2017-02-27 14:25:52 -06001178
Michael Walsh89de14a2018-10-01 16:51:37 -05001179 post_stack()
1180
Michael Walsh6741f742017-02-20 16:16:38 -06001181 # Process caller's boot_list.
1182 if len(boot_list) > 0:
1183 for ix in range(1, max_num_tests + 1):
1184 test_loop_body()
1185
Michael Walshb5839d02017-04-12 16:11:20 -05001186 gp.qprint_timen("Completed all requested boot tests.")
1187
1188 boot_pass, boot_fail = boot_results.return_total_pass_fail()
Michael Walshcd9fbfd2017-09-19 12:00:08 -05001189 new_fail = boot_fail - init_boot_fail
1190 if new_fail > boot_fail_threshold:
Michael Walshb5839d02017-04-12 16:11:20 -05001191 error_message = "Boot failures exceed the boot failure" +\
1192 " threshold:\n" +\
Michael Walshcd9fbfd2017-09-19 12:00:08 -05001193 gp.sprint_var(new_fail) +\
Michael Walshb5839d02017-04-12 16:11:20 -05001194 gp.sprint_var(boot_fail_threshold)
1195 BuiltIn().fail(gp.sprint_error(error_message))