blob: 5ba505a534e06f50c20a79a0820cc307fbbbaef3 [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 Sheposcb6b53b2021-03-15 23:23:10 -050069redfish_support_trans_state = int(os.environ.get('REDFISH_SUPPORT_TRANS_STATE', 0)) or \
70 int(BuiltIn().get_variable_value("${REDFISH_SUPPORT_TRANS_STATE}", default=0))
Michael Walshe58df1c2019-08-07 09:57:43 -050071redfish_supported = BuiltIn().get_variable_value("${REDFISH_SUPPORTED}", default=False)
George Keishingeb1fe352020-06-19 03:02:22 -050072redfish_rest_supported = BuiltIn().get_variable_value("${REDFISH_REST_SUPPORTED}", default=False)
Michael Walshe58df1c2019-08-07 09:57:43 -050073if redfish_supported:
George Keishing89537a82020-06-17 00:37:25 -050074 redfish = BuiltIn().get_library_instance('redfish')
Michael Walshe58df1c2019-08-07 09:57:43 -050075 default_power_on = "Redfish Power On"
76 default_power_off = "Redfish Power Off"
George Keishingeb1fe352020-06-19 03:02:22 -050077 if redfish_rest_supported:
Michael Sheposcc490b42020-08-26 12:53:01 -050078 delete_errlogs_cmd = "Delete Error Logs ${quiet}=${1}"
Michael Shepos92a54bf2020-11-11 11:48:55 -060079 delete_bmcdump_cmd = "Delete All BMC Dump"
George Keishingeb1fe352020-06-19 03:02:22 -050080 default_set_power_policy = "Set BMC Power Policy ALWAYS_POWER_OFF"
81 else:
82 delete_errlogs_cmd = "Redfish Purge Event Log"
Michael Shepos92a54bf2020-11-11 11:48:55 -060083 delete_bmcdump_cmd = "Redfish Delete All BMC Dumps"
George Keishingeb1fe352020-06-19 03:02:22 -050084 default_set_power_policy = "Redfish Set Power Restore Policy AlwaysOff"
Michael Walshe58df1c2019-08-07 09:57:43 -050085else:
86 default_power_on = "REST Power On"
87 default_power_off = "REST Power Off"
Michael Sheposcc490b42020-08-26 12:53:01 -050088 delete_errlogs_cmd = "Delete Error Logs ${quiet}=${1}"
Michael Shepos92a54bf2020-11-11 11:48:55 -060089 delete_bmcdump_cmd = "Delete All BMC Dump"
George Keishinga54e06f2020-06-12 10:42:41 -050090 default_set_power_policy = "Set BMC Power Policy ALWAYS_POWER_OFF"
Michael Walsh6741f742017-02-20 16:16:38 -060091boot_count = 0
Michael Walsh0bbd8602016-11-22 11:31:49 -060092
Michael Walsh85678942017-03-27 14:34:22 -050093LOG_LEVEL = BuiltIn().get_variable_value("${LOG_LEVEL}")
Michael Walsh986d8ae2019-07-17 10:02:23 -050094AUTOBOOT_FFDC_PREFIX = os.environ.get('AUTOBOOT_FFDC_PREFIX', '')
95ffdc_prefix = AUTOBOOT_FFDC_PREFIX
Sunil M325eb542017-08-10 07:09:43 -050096boot_start_time = ""
97boot_end_time = ""
Michael Walshff340002017-08-29 11:18:27 -050098save_stack = vs.var_stack('save_stack')
99main_func_parm_list = ['boot_stack', 'stack_mode', 'quiet']
Michael Walsh85678942017-03-27 14:34:22 -0500100
101
Michael Walsh89de14a2018-10-01 16:51:37 -0500102def dump_ffdc_rc():
103 r"""
104 Return the constant dump ffdc test return code value.
105
106 When a plug-in call point program returns this value, it indicates that
107 this program should collect FFDC.
108 """
109
110 return 0x00000200
111
112
113def stop_test_rc():
114 r"""
115 Return the constant stop test return code value.
116
117 When a plug-in call point program returns this value, it indicates that
118 this program should stop running.
119 """
120
121 return 0x00000200
122
123
Michael Walsh0ad0f7f2017-05-04 14:39:58 -0500124def process_host(host,
125 host_var_name=""):
Michael Walsh0ad0f7f2017-05-04 14:39:58 -0500126 r"""
127 Process a host by getting the associated host name and IP address and
128 setting them in global variables.
129
130 If the caller does not pass the host_var_name, this function will try to
131 figure out the name of the variable used by the caller for the host parm.
132 Callers are advised to explicitly specify the host_var_name when calling
133 with an exec command. In such cases, the get_arg_name cannot figure out
134 the host variable name.
135
136 This function will then create similar global variable names by
137 removing "_host" and appending "_host_name" or "_ip" to the host variable
138 name.
139
140 Example:
141
142 If a call is made like this:
143 process_host(openbmc_host)
144
145 Global variables openbmc_host_name and openbmc_ip will be set.
146
147 Description of argument(s):
148 host A host name or IP. The name of the variable used should
149 have a suffix of "_host".
150 host_var_name The name of the variable being used as the host parm.
151 """
152
153 if host_var_name == "":
154 host_var_name = gp.get_arg_name(0, 1, stack_frame_ix=2)
155
156 host_name_var_name = re.sub("host", "host_name", host_var_name)
157 ip_var_name = re.sub("host", "ip", host_var_name)
158 cmd_buf = "global " + host_name_var_name + ", " + ip_var_name + " ; " +\
159 host_name_var_name + ", " + ip_var_name + " = gm.get_host_name_ip('" +\
160 host + "')"
161 exec(cmd_buf)
162
Michael Walsh0ad0f7f2017-05-04 14:39:58 -0500163
Michael Walshb5839d02017-04-12 16:11:20 -0500164def process_pgm_parms():
Michael Walshb5839d02017-04-12 16:11:20 -0500165 r"""
166 Process the program parameters by assigning them all to corresponding
167 globals. Also, set some global values that depend on program parameters.
168 """
169
170 # Program parameter processing.
171 # Assign all program parms to python variables which are global to this
172 # module.
173
174 global parm_list
175 parm_list = BuiltIn().get_variable_value("${parm_list}")
176 # The following subset of parms should be processed as integers.
177 int_list = ['max_num_tests', 'boot_pass', 'boot_fail', 'ffdc_only',
Michael Walsh89de14a2018-10-01 16:51:37 -0500178 'boot_fail_threshold', 'delete_errlogs',
Michael Walsh986d8ae2019-07-17 10:02:23 -0500179 'call_post_stack_plug', 'do_pre_boot_plug_in_setup', 'quiet',
180 'test_mode', 'debug']
Michael Walshb5839d02017-04-12 16:11:20 -0500181 for parm in parm_list:
182 if parm in int_list:
183 sub_cmd = "int(BuiltIn().get_variable_value(\"${" + parm +\
184 "}\", \"0\"))"
185 else:
186 sub_cmd = "BuiltIn().get_variable_value(\"${" + parm + "}\")"
187 cmd_buf = "global " + parm + " ; " + parm + " = " + sub_cmd
Michael Walshff340002017-08-29 11:18:27 -0500188 gp.dpissuing(cmd_buf)
Michael Walshb5839d02017-04-12 16:11:20 -0500189 exec(cmd_buf)
Michael Walsh0ad0f7f2017-05-04 14:39:58 -0500190 if re.match(r".*_host$", parm):
191 cmd_buf = "process_host(" + parm + ", '" + parm + "')"
192 exec(cmd_buf)
193 if re.match(r".*_password$", parm):
194 # Register the value of any parm whose name ends in _password.
195 # This will cause the print functions to replace passwords with
196 # asterisks in the output.
197 cmd_buf = "gp.register_passwords(" + parm + ")"
198 exec(cmd_buf)
Michael Walshb5839d02017-04-12 16:11:20 -0500199
200 global ffdc_dir_path_style
201 global boot_list
202 global boot_stack
203 global boot_results_file_path
204 global boot_results
Michael Walsh986d8ae2019-07-17 10:02:23 -0500205 global boot_history
Michael Walshb5839d02017-04-12 16:11:20 -0500206 global ffdc_list_file_path
Michael Walshe0cf8d72017-05-17 13:20:46 -0500207 global ffdc_report_list_path
Michael Walsh600876d2017-05-30 17:58:58 -0500208 global ffdc_summary_list_path
Michael Walsha3e7b222020-02-03 15:32:16 -0600209 global boot_table
210 global valid_boot_types
Michael Walshb5839d02017-04-12 16:11:20 -0500211
212 if ffdc_dir_path_style == "":
213 ffdc_dir_path_style = int(os.environ.get('FFDC_DIR_PATH_STYLE', '0'))
214
215 # Convert these program parms to lists for easier processing..
George Keishing36efbc02018-12-12 10:18:23 -0600216 boot_list = list(filter(None, boot_list.split(":")))
217 boot_stack = list(filter(None, boot_stack.split(":")))
Michael Walshb5839d02017-04-12 16:11:20 -0500218
Michael Walsha3e7b222020-02-03 15:32:16 -0600219 boot_table = create_boot_table(boot_table_path, os_host=os_host)
220 valid_boot_types = create_valid_boot_list(boot_table)
221
Michael Walsh903e0b22017-09-19 17:00:33 -0500222 cleanup_boot_results_file()
223 boot_results_file_path = create_boot_results_file_path(pgm_name,
224 openbmc_nickname,
225 master_pid)
Michael Walshb5839d02017-04-12 16:11:20 -0500226
227 if os.path.isfile(boot_results_file_path):
228 # We've been called before in this run so we'll load the saved
Michael Walsh986d8ae2019-07-17 10:02:23 -0500229 # boot_results and boot_history objects.
230 boot_results, boot_history =\
Michael Walsh6c645742018-08-17 15:02:17 -0500231 pickle.load(open(boot_results_file_path, 'rb'))
Michael Walshb5839d02017-04-12 16:11:20 -0500232 else:
233 boot_results = boot_results(boot_table, boot_pass, boot_fail)
234
235 ffdc_list_file_path = base_tool_dir_path + openbmc_nickname +\
236 "/FFDC_FILE_LIST"
Michael Walshe0cf8d72017-05-17 13:20:46 -0500237 ffdc_report_list_path = base_tool_dir_path + openbmc_nickname +\
238 "/FFDC_REPORT_FILE_LIST"
Michael Walshb5839d02017-04-12 16:11:20 -0500239
Michael Walsh600876d2017-05-30 17:58:58 -0500240 ffdc_summary_list_path = base_tool_dir_path + openbmc_nickname +\
241 "/FFDC_SUMMARY_FILE_LIST"
242
Michael Walshb5839d02017-04-12 16:11:20 -0500243
Michael Walsh85678942017-03-27 14:34:22 -0500244def initial_plug_in_setup():
Michael Walsh85678942017-03-27 14:34:22 -0500245 r"""
246 Initialize all plug-in environment variables which do not change for the
247 duration of the program.
248
249 """
250
251 global LOG_LEVEL
252 BuiltIn().set_log_level("NONE")
253
254 BuiltIn().set_global_variable("${master_pid}", master_pid)
255 BuiltIn().set_global_variable("${FFDC_DIR_PATH}", ffdc_dir_path)
256 BuiltIn().set_global_variable("${STATUS_DIR_PATH}", status_dir_path)
257 BuiltIn().set_global_variable("${BASE_TOOL_DIR_PATH}", base_tool_dir_path)
258 BuiltIn().set_global_variable("${FFDC_LIST_FILE_PATH}",
259 ffdc_list_file_path)
Michael Walshe0cf8d72017-05-17 13:20:46 -0500260 BuiltIn().set_global_variable("${FFDC_REPORT_LIST_PATH}",
261 ffdc_report_list_path)
Michael Walsh600876d2017-05-30 17:58:58 -0500262 BuiltIn().set_global_variable("${FFDC_SUMMARY_LIST_PATH}",
263 ffdc_summary_list_path)
Michael Walsh85678942017-03-27 14:34:22 -0500264
265 BuiltIn().set_global_variable("${FFDC_DIR_PATH_STYLE}",
266 ffdc_dir_path_style)
267 BuiltIn().set_global_variable("${FFDC_CHECK}",
268 ffdc_check)
269
270 # For each program parameter, set the corresponding AUTOBOOT_ environment
271 # variable value. Also, set an AUTOBOOT_ environment variable for every
272 # element in additional_values.
273 additional_values = ["program_pid", "master_pid", "ffdc_dir_path",
274 "status_dir_path", "base_tool_dir_path",
Michael Walsh600876d2017-05-30 17:58:58 -0500275 "ffdc_list_file_path", "ffdc_report_list_path",
Michael Shepos7fe83b32020-09-21 15:46:01 -0500276 "ffdc_summary_list_path", "execdir", "redfish_supported",
Michael Sheposcb6b53b2021-03-15 23:23:10 -0500277 "redfish_rest_supported", "redfish_support_trans_state"]
Michael Walsh85678942017-03-27 14:34:22 -0500278
279 plug_in_vars = parm_list + additional_values
280
281 for var_name in plug_in_vars:
282 var_value = BuiltIn().get_variable_value("${" + var_name + "}")
283 var_name = var_name.upper()
284 if var_value is None:
285 var_value = ""
286 os.environ["AUTOBOOT_" + var_name] = str(var_value)
287
288 BuiltIn().set_log_level(LOG_LEVEL)
289
Michael Walsh68a61162017-04-25 11:54:06 -0500290 # Make sure the ffdc list directory exists.
291 ffdc_list_dir_path = os.path.dirname(ffdc_list_file_path) + os.sep
292 if not os.path.exists(ffdc_list_dir_path):
293 os.makedirs(ffdc_list_dir_path)
Michael Walsh85678942017-03-27 14:34:22 -0500294
Michael Walsh85678942017-03-27 14:34:22 -0500295
Michael Walsh0bbd8602016-11-22 11:31:49 -0600296def plug_in_setup():
Michael Walsh0bbd8602016-11-22 11:31:49 -0600297 r"""
Michael Walsh85678942017-03-27 14:34:22 -0500298 Initialize all changing plug-in environment variables for use by the
299 plug-in programs.
Michael Walsh0bbd8602016-11-22 11:31:49 -0600300 """
301
Michael Walsh85678942017-03-27 14:34:22 -0500302 global LOG_LEVEL
303 global test_really_running
304
305 BuiltIn().set_log_level("NONE")
306
Michael Walsh6741f742017-02-20 16:16:38 -0600307 boot_pass, boot_fail = boot_results.return_total_pass_fail()
Michael Walsh0bbd8602016-11-22 11:31:49 -0600308 if boot_pass > 1:
309 test_really_running = 1
310 else:
311 test_really_running = 0
312
Michael Walsh6741f742017-02-20 16:16:38 -0600313 BuiltIn().set_global_variable("${test_really_running}",
314 test_really_running)
315 BuiltIn().set_global_variable("${boot_type_desc}", next_boot)
Michael Walsh6741f742017-02-20 16:16:38 -0600316 BuiltIn().set_global_variable("${boot_pass}", boot_pass)
317 BuiltIn().set_global_variable("${boot_fail}", boot_fail)
318 BuiltIn().set_global_variable("${boot_success}", boot_success)
319 BuiltIn().set_global_variable("${ffdc_prefix}", ffdc_prefix)
Sunil M325eb542017-08-10 07:09:43 -0500320 BuiltIn().set_global_variable("${boot_start_time}", boot_start_time)
321 BuiltIn().set_global_variable("${boot_end_time}", boot_end_time)
Michael Walsh4c9a6452016-12-13 16:03:11 -0600322
Michael Walsh0bbd8602016-11-22 11:31:49 -0600323 # For each program parameter, set the corresponding AUTOBOOT_ environment
324 # variable value. Also, set an AUTOBOOT_ environment variable for every
325 # element in additional_values.
326 additional_values = ["boot_type_desc", "boot_success", "boot_pass",
Sunil M325eb542017-08-10 07:09:43 -0500327 "boot_fail", "test_really_running", "ffdc_prefix",
328 "boot_start_time", "boot_end_time"]
Michael Walsh0bbd8602016-11-22 11:31:49 -0600329
Michael Walsh85678942017-03-27 14:34:22 -0500330 plug_in_vars = additional_values
Michael Walsh0bbd8602016-11-22 11:31:49 -0600331
332 for var_name in plug_in_vars:
333 var_value = BuiltIn().get_variable_value("${" + var_name + "}")
334 var_name = var_name.upper()
335 if var_value is None:
336 var_value = ""
Michael Walsh6741f742017-02-20 16:16:38 -0600337 os.environ["AUTOBOOT_" + var_name] = str(var_value)
Michael Walsh0bbd8602016-11-22 11:31:49 -0600338
Michael Walsh0bbd8602016-11-22 11:31:49 -0600339 if debug:
Michael Walsh6741f742017-02-20 16:16:38 -0600340 shell_rc, out_buf = \
341 gc.cmd_fnc_u("printenv | egrep AUTOBOOT_ | sort -u")
Michael Walsh0bbd8602016-11-22 11:31:49 -0600342
Michael Walsh85678942017-03-27 14:34:22 -0500343 BuiltIn().set_log_level(LOG_LEVEL)
344
Michael Walsh0bbd8602016-11-22 11:31:49 -0600345
Michael Walshe0cf8d72017-05-17 13:20:46 -0500346def pre_boot_plug_in_setup():
347
348 # Clear the ffdc_list_file_path file. Plug-ins may now write to it.
349 try:
350 os.remove(ffdc_list_file_path)
351 except OSError:
352 pass
353
354 # Clear the ffdc_report_list_path file. Plug-ins may now write to it.
355 try:
356 os.remove(ffdc_report_list_path)
357 except OSError:
358 pass
359
Michael Walsh600876d2017-05-30 17:58:58 -0500360 # Clear the ffdc_summary_list_path file. Plug-ins may now write to it.
361 try:
362 os.remove(ffdc_summary_list_path)
363 except OSError:
364 pass
365
Michael Walshe1974b92017-08-03 13:39:51 -0500366 global ffdc_prefix
367
368 seconds = time.time()
369 loc_time = time.localtime(seconds)
370 time_string = time.strftime("%y%m%d.%H%M%S.", loc_time)
371
372 ffdc_prefix = openbmc_nickname + "." + time_string
373
Michael Walshe0cf8d72017-05-17 13:20:46 -0500374
Michael Walshf566fb12019-02-01 14:35:09 -0600375def default_sigusr1(signal_number=0,
376 frame=None):
377 r"""
378 Handle SIGUSR1 by doing nothing.
379
380 This function assists in debugging SIGUSR1 processing by printing messages
381 to stdout and to the log.html file.
382
383 Description of argument(s):
384 signal_number The signal number (should always be 10 for SIGUSR1).
385 frame The frame data.
386 """
387
Michael Walsh80dddde2019-10-22 13:54:38 -0500388 gp.qprintn()
389 gp.qprint_executing()
Michael Walshf566fb12019-02-01 14:35:09 -0600390 gp.lprint_executing()
391
392
393def set_default_siguser1():
394 r"""
395 Set the default_sigusr1 function to be the SIGUSR1 handler.
396 """
397
Michael Walsh80dddde2019-10-22 13:54:38 -0500398 gp.qprintn()
399 gp.qprint_executing()
Michael Walshf566fb12019-02-01 14:35:09 -0600400 gp.lprint_executing()
401 signal.signal(signal.SIGUSR1, default_sigusr1)
402
403
Michael Walsh6741f742017-02-20 16:16:38 -0600404def setup():
Michael Walsh0bbd8602016-11-22 11:31:49 -0600405 r"""
Michael Walsh6741f742017-02-20 16:16:38 -0600406 Do general program setup tasks.
Michael Walsh0bbd8602016-11-22 11:31:49 -0600407 """
408
Michael Walsh6741f742017-02-20 16:16:38 -0600409 global cp_setup_called
Michael Walsh81816742017-09-27 11:02:29 -0500410 global transitional_boot_selected
Michael Walsh0bbd8602016-11-22 11:31:49 -0600411
Michael Walshb5839d02017-04-12 16:11:20 -0500412 gp.qprintn()
413
George Keishinga54e06f2020-06-12 10:42:41 -0500414 if redfish_supported:
415 redfish.login()
416
Michael Walshf566fb12019-02-01 14:35:09 -0600417 set_default_siguser1()
Michael Walsh81816742017-09-27 11:02:29 -0500418 transitional_boot_selected = False
419
Michael Walsh83f4bc72017-04-20 16:49:43 -0500420 robot_pgm_dir_path = os.path.dirname(__file__) + os.sep
421 repo_bin_path = robot_pgm_dir_path.replace("/lib/", "/bin/")
Michael Walshd061c042017-05-23 14:46:57 -0500422 # If we can't find process_plug_in_packages.py, ssh_pw or
423 # validate_plug_ins.py, then we don't have our repo bin in PATH.
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -0500424 shell_rc, out_buf = gc.cmd_fnc_u("which process_plug_in_packages.py"
425 + " ssh_pw validate_plug_ins.py", quiet=1,
Michael Walshd061c042017-05-23 14:46:57 -0500426 print_output=0, show_err=0)
Michael Walshb5839d02017-04-12 16:11:20 -0500427 if shell_rc != 0:
Michael Walsh83f4bc72017-04-20 16:49:43 -0500428 os.environ['PATH'] = repo_bin_path + ":" + os.environ.get('PATH', "")
429 # Likewise, our repo lib subdir needs to be in sys.path and PYTHONPATH.
430 if robot_pgm_dir_path not in sys.path:
431 sys.path.append(robot_pgm_dir_path)
432 PYTHONPATH = os.environ.get("PYTHONPATH", "")
433 if PYTHONPATH == "":
434 os.environ['PYTHONPATH'] = robot_pgm_dir_path
435 else:
436 os.environ['PYTHONPATH'] = robot_pgm_dir_path + ":" + PYTHONPATH
Michael Walsh6741f742017-02-20 16:16:38 -0600437
438 validate_parms()
439
Michael Walshc108e422019-03-28 12:27:18 -0500440 gp.qprint_pgm_header()
Michael Walsh6741f742017-02-20 16:16:38 -0600441
George Keishinga54e06f2020-06-12 10:42:41 -0500442 grk.run_key_u(default_set_power_policy)
Michael Walsh11cfc8c2017-03-31 09:40:55 -0500443
Michael Walsh85678942017-03-27 14:34:22 -0500444 initial_plug_in_setup()
445
Michael Walsh6741f742017-02-20 16:16:38 -0600446 plug_in_setup()
447 rc, shell_rc, failed_plug_in_name = grpi.rprocess_plug_in_packages(
448 call_point='setup')
449 if rc != 0:
450 error_message = "Plug-in setup failed.\n"
Michael Walshc108e422019-03-28 12:27:18 -0500451 gp.print_error_report(error_message)
Michael Walsh6741f742017-02-20 16:16:38 -0600452 BuiltIn().fail(error_message)
453 # Setting cp_setup_called lets our Teardown know that it needs to call
454 # the cleanup plug-in call point.
455 cp_setup_called = 1
456
457 # Keyword "FFDC" will fail if TEST_MESSAGE is not set.
458 BuiltIn().set_global_variable("${TEST_MESSAGE}", "${EMPTY}")
Michael Walsh85678942017-03-27 14:34:22 -0500459 # FFDC_LOG_PATH is used by "FFDC" keyword.
460 BuiltIn().set_global_variable("${FFDC_LOG_PATH}", ffdc_dir_path)
Michael Walsh6741f742017-02-20 16:16:38 -0600461
Michael Walshdc80d672017-05-09 12:58:32 -0500462 # Also printed by FFDC.
463 global host_name
464 global host_ip
465 host = socket.gethostname()
466 host_name, host_ip = gm.get_host_name_ip(host)
467
Michael Walsh986d8ae2019-07-17 10:02:23 -0500468 gp.dprint_var(boot_table)
Michael Walshb5839d02017-04-12 16:11:20 -0500469 gp.dprint_var(boot_lists)
Michael Walsh0bbd8602016-11-22 11:31:49 -0600470
Michael Walsh0bbd8602016-11-22 11:31:49 -0600471
Michael Walsh6741f742017-02-20 16:16:38 -0600472def validate_parms():
Michael Walsh0bbd8602016-11-22 11:31:49 -0600473 r"""
Michael Walsh6741f742017-02-20 16:16:38 -0600474 Validate all program parameters.
Michael Walsh0bbd8602016-11-22 11:31:49 -0600475 """
476
Michael Walshb5839d02017-04-12 16:11:20 -0500477 process_pgm_parms()
Michael Walsh0bbd8602016-11-22 11:31:49 -0600478
Michael Walshb5839d02017-04-12 16:11:20 -0500479 gp.qprintn()
480
481 global openbmc_model
Michael Walshf5ce38c2020-02-27 12:46:20 -0600482 if openbmc_model == "":
483 status, ret_values =\
484 grk.run_key_u("Get BMC System Model")
485 openbmc_model = ret_values
486 BuiltIn().set_global_variable("${openbmc_model}", openbmc_model)
487 gv.set_exit_on_error(True)
Michael Walsh44cef252019-08-01 12:38:56 -0500488 gv.valid_value(openbmc_host)
489 gv.valid_value(openbmc_username)
490 gv.valid_value(openbmc_password)
491 gv.valid_value(rest_username)
492 gv.valid_value(rest_password)
493 gv.valid_value(ipmi_username)
494 gv.valid_value(ipmi_password)
Michael Walsh6741f742017-02-20 16:16:38 -0600495 if os_host != "":
Michael Walsh44cef252019-08-01 12:38:56 -0500496 gv.valid_value(os_username)
497 gv.valid_value(os_password)
Michael Walsh6741f742017-02-20 16:16:38 -0600498 if pdu_host != "":
Michael Walsh44cef252019-08-01 12:38:56 -0500499 gv.valid_value(pdu_username)
500 gv.valid_value(pdu_password)
501 gv.valid_integer(pdu_slot_no)
Michael Walsh6741f742017-02-20 16:16:38 -0600502 if openbmc_serial_host != "":
Michael Walsh44cef252019-08-01 12:38:56 -0500503 gv.valid_integer(openbmc_serial_port)
Michael Walsh44cef252019-08-01 12:38:56 -0500504 gv.valid_value(openbmc_model)
505 gv.valid_integer(max_num_tests)
506 gv.valid_integer(boot_pass)
507 gv.valid_integer(boot_fail)
Michael Walsh6741f742017-02-20 16:16:38 -0600508 plug_in_packages_list = grpi.rvalidate_plug_ins(plug_in_dir_paths)
509 BuiltIn().set_global_variable("${plug_in_packages_list}",
510 plug_in_packages_list)
Michael Walsh44cef252019-08-01 12:38:56 -0500511 gv.valid_value(stack_mode, valid_values=['normal', 'skip'])
Michael Walshf5ce38c2020-02-27 12:46:20 -0600512 gv.set_exit_on_error(False)
Michael Walsha20da402017-03-31 16:27:45 -0500513 if len(boot_list) == 0 and len(boot_stack) == 0 and not ffdc_only:
Michael Walsh6741f742017-02-20 16:16:38 -0600514 error_message = "You must provide either a value for either the" +\
515 " boot_list or the boot_stack parm.\n"
516 BuiltIn().fail(gp.sprint_error(error_message))
Michael Walsh6741f742017-02-20 16:16:38 -0600517 valid_boot_list(boot_list, valid_boot_types)
518 valid_boot_list(boot_stack, valid_boot_types)
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -0500519 selected_PDU_boots = list(set(boot_list + boot_stack)
520 & set(boot_lists['PDU_reboot']))
Michael Walsh11cfc8c2017-03-31 09:40:55 -0500521 if len(selected_PDU_boots) > 0 and pdu_host == "":
522 error_message = "You have selected the following boots which" +\
523 " require a PDU host but no value for pdu_host:\n"
524 error_message += gp.sprint_var(selected_PDU_boots)
Michael Walsh986d8ae2019-07-17 10:02:23 -0500525 error_message += gp.sprint_var(pdu_host, fmt=gp.blank())
Michael Walsh11cfc8c2017-03-31 09:40:55 -0500526 BuiltIn().fail(gp.sprint_error(error_message))
527
Michael Walsh6741f742017-02-20 16:16:38 -0600528 return
Michael Walsh0bbd8602016-11-22 11:31:49 -0600529
Michael Walsh0bbd8602016-11-22 11:31:49 -0600530
Michael Walsh6741f742017-02-20 16:16:38 -0600531def my_get_state():
Michael Walsh0bbd8602016-11-22 11:31:49 -0600532 r"""
Michael Walsh6741f742017-02-20 16:16:38 -0600533 Get the system state plus a little bit of wrapping.
Michael Walsh0bbd8602016-11-22 11:31:49 -0600534 """
535
Michael Walsh6741f742017-02-20 16:16:38 -0600536 global state
537
538 req_states = ['epoch_seconds'] + st.default_req_states
539
Michael Walshb5839d02017-04-12 16:11:20 -0500540 gp.qprint_timen("Getting system state.")
Michael Walsh6741f742017-02-20 16:16:38 -0600541 if test_mode:
542 state['epoch_seconds'] = int(time.time())
543 else:
Michael Walshb5839d02017-04-12 16:11:20 -0500544 state = st.get_state(req_states=req_states, quiet=quiet)
545 gp.qprint_var(state)
Michael Walsh341c21e2017-01-17 16:25:20 -0600546
Michael Walsh341c21e2017-01-17 16:25:20 -0600547
Michael Walsh45ca6e42017-09-14 17:29:12 -0500548def valid_state():
Michael Walsh45ca6e42017-09-14 17:29:12 -0500549 r"""
550 Verify that our state dictionary contains no blank values. If we don't get
551 valid state data, we cannot continue to work.
552 """
553
554 if st.compare_states(state, st.invalid_state_match, 'or'):
555 error_message = "The state dictionary contains blank fields which" +\
556 " is illegal.\n" + gp.sprint_var(state)
557 BuiltIn().fail(gp.sprint_error(error_message))
558
Michael Walsh45ca6e42017-09-14 17:29:12 -0500559
Michael Walsh6741f742017-02-20 16:16:38 -0600560def select_boot():
Michael Walsh341c21e2017-01-17 16:25:20 -0600561 r"""
562 Select a boot test to be run based on our current state and return the
563 chosen boot type.
564
565 Description of arguments:
Michael Walsh6741f742017-02-20 16:16:38 -0600566 state The state of the machine.
Michael Walsh341c21e2017-01-17 16:25:20 -0600567 """
568
Michael Walsh81816742017-09-27 11:02:29 -0500569 global transitional_boot_selected
Michael Walsh30dadae2017-02-27 14:25:52 -0600570 global boot_stack
571
Michael Walshb5839d02017-04-12 16:11:20 -0500572 gp.qprint_timen("Selecting a boot test.")
Michael Walsh6741f742017-02-20 16:16:38 -0600573
Michael Walsh81816742017-09-27 11:02:29 -0500574 if transitional_boot_selected and not boot_success:
575 prior_boot = next_boot
576 boot_candidate = boot_stack.pop()
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -0500577 gp.qprint_timen("The prior '" + next_boot + "' was chosen to"
578 + " transition to a valid state for '" + boot_candidate
579 + "' which was at the top of the boot_stack. Since"
580 + " the '" + next_boot + "' failed, the '"
581 + boot_candidate + "' has been removed from the stack"
582 + " to avoid and endless failure loop.")
Michael Walsh81816742017-09-27 11:02:29 -0500583 if len(boot_stack) == 0:
584 return ""
585
Michael Walsh6741f742017-02-20 16:16:38 -0600586 my_get_state()
Michael Walsh45ca6e42017-09-14 17:29:12 -0500587 valid_state()
Michael Walsh6741f742017-02-20 16:16:38 -0600588
Michael Walsh81816742017-09-27 11:02:29 -0500589 transitional_boot_selected = False
Michael Walsh6741f742017-02-20 16:16:38 -0600590 stack_popped = 0
591 if len(boot_stack) > 0:
592 stack_popped = 1
Michael Walshb5839d02017-04-12 16:11:20 -0500593 gp.qprint_dashes()
594 gp.qprint_var(boot_stack)
595 gp.qprint_dashes()
596 skip_boot_printed = 0
597 while len(boot_stack) > 0:
598 boot_candidate = boot_stack.pop()
599 if stack_mode == 'normal':
600 break
601 else:
602 if st.compare_states(state, boot_table[boot_candidate]['end']):
603 if not skip_boot_printed:
Michael Walshff340002017-08-29 11:18:27 -0500604 gp.qprint_var(stack_mode)
605 gp.qprintn()
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -0500606 gp.qprint_timen("Skipping the following boot tests"
607 + " which are unnecessary since their"
608 + " required end states match the"
609 + " current machine state:")
Michael Walshb5839d02017-04-12 16:11:20 -0500610 skip_boot_printed = 1
Michael Walshff340002017-08-29 11:18:27 -0500611 gp.qprint_var(boot_candidate)
Michael Walshb5839d02017-04-12 16:11:20 -0500612 boot_candidate = ""
613 if boot_candidate == "":
614 gp.qprint_dashes()
615 gp.qprint_var(boot_stack)
616 gp.qprint_dashes()
617 return boot_candidate
Michael Walsh6741f742017-02-20 16:16:38 -0600618 if st.compare_states(state, boot_table[boot_candidate]['start']):
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -0500619 gp.qprint_timen("The machine state is valid for a '"
620 + boot_candidate + "' boot test.")
Michael Walshb5839d02017-04-12 16:11:20 -0500621 gp.qprint_dashes()
622 gp.qprint_var(boot_stack)
623 gp.qprint_dashes()
Michael Walsh6741f742017-02-20 16:16:38 -0600624 return boot_candidate
Michael Walsh341c21e2017-01-17 16:25:20 -0600625 else:
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -0500626 gp.qprint_timen("The machine state does not match the required"
627 + " starting state for a '" + boot_candidate
628 + "' boot test:")
Michael Walsh986d8ae2019-07-17 10:02:23 -0500629 gp.qprint_varx("boot_table_start_entry",
630 boot_table[boot_candidate]['start'])
Michael Walsh6741f742017-02-20 16:16:38 -0600631 boot_stack.append(boot_candidate)
Michael Walsh81816742017-09-27 11:02:29 -0500632 transitional_boot_selected = True
Michael Walsh6741f742017-02-20 16:16:38 -0600633 popped_boot = boot_candidate
634
635 # Loop through your list selecting a boot_candidates
636 boot_candidates = []
637 for boot_candidate in boot_list:
638 if st.compare_states(state, boot_table[boot_candidate]['start']):
639 if stack_popped:
640 if st.compare_states(boot_table[boot_candidate]['end'],
Gunnar Mills096cd562018-03-26 10:19:12 -0500641 boot_table[popped_boot]['start']):
Michael Walsh6741f742017-02-20 16:16:38 -0600642 boot_candidates.append(boot_candidate)
643 else:
644 boot_candidates.append(boot_candidate)
645
646 if len(boot_candidates) == 0:
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -0500647 gp.qprint_timen("The user's boot list contained no boot tests"
648 + " which are valid for the current machine state.")
Michael Walsh6741f742017-02-20 16:16:38 -0600649 boot_candidate = default_power_on
650 if not st.compare_states(state, boot_table[default_power_on]['start']):
651 boot_candidate = default_power_off
652 boot_candidates.append(boot_candidate)
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -0500653 gp.qprint_timen("Using default '" + boot_candidate
654 + "' boot type to transition to valid state.")
Michael Walsh6741f742017-02-20 16:16:38 -0600655
Michael Walshb5839d02017-04-12 16:11:20 -0500656 gp.dprint_var(boot_candidates)
Michael Walsh6741f742017-02-20 16:16:38 -0600657
658 # Randomly select a boot from the candidate list.
659 boot = random.choice(boot_candidates)
Michael Walsh341c21e2017-01-17 16:25:20 -0600660
661 return boot
Michael Walsh0bbd8602016-11-22 11:31:49 -0600662
Michael Walsh55302292017-01-10 11:43:02 -0600663
Michael Walshb2e53ec2017-10-30 15:04:36 -0500664def print_defect_report(ffdc_file_list):
Michael Walsh341c21e2017-01-17 16:25:20 -0600665 r"""
666 Print a defect report.
Michael Walshb2e53ec2017-10-30 15:04:36 -0500667
668 Description of argument(s):
669 ffdc_file_list A list of files which were collected by our ffdc functions.
Michael Walsh341c21e2017-01-17 16:25:20 -0600670 """
671
Michael Walsh600876d2017-05-30 17:58:58 -0500672 # Making deliberate choice to NOT run plug_in_setup(). We don't want
673 # ffdc_prefix updated.
674 rc, shell_rc, failed_plug_in_name = grpi.rprocess_plug_in_packages(
675 call_point='ffdc_report', stop_on_plug_in_failure=0)
676
Michael Walshe0cf8d72017-05-17 13:20:46 -0500677 # Get additional header data which may have been created by ffdc plug-ins.
678 # Also, delete the individual header files to cleanup.
679 cmd_buf = "file_list=$(cat " + ffdc_report_list_path + " 2>/dev/null)" +\
680 " ; [ ! -z \"${file_list}\" ] && cat ${file_list}" +\
681 " 2>/dev/null ; rm -rf ${file_list} 2>/dev/null || :"
682 shell_rc, more_header_info = gc.cmd_fnc_u(cmd_buf, print_output=0,
683 show_err=0)
684
Michael Walshb2e53ec2017-10-30 15:04:36 -0500685 # Get additional summary data which may have been created by ffdc plug-ins.
Michael Walsh600876d2017-05-30 17:58:58 -0500686 # Also, delete the individual header files to cleanup.
687 cmd_buf = "file_list=$(cat " + ffdc_summary_list_path + " 2>/dev/null)" +\
688 " ; [ ! -z \"${file_list}\" ] && cat ${file_list}" +\
689 " 2>/dev/null ; rm -rf ${file_list} 2>/dev/null || :"
690 shell_rc, ffdc_summary_info = gc.cmd_fnc_u(cmd_buf, print_output=0,
691 show_err=0)
692
Michael Walshb2e53ec2017-10-30 15:04:36 -0500693 # ffdc_list_file_path contains a list of any ffdc files created by plug-
694 # ins, etc. Read that data into a list.
Michael Walsh341c21e2017-01-17 16:25:20 -0600695 try:
Michael Walshb2e53ec2017-10-30 15:04:36 -0500696 plug_in_ffdc_list = \
697 open(ffdc_list_file_path, 'r').read().rstrip("\n").split("\n")
George Keishing36efbc02018-12-12 10:18:23 -0600698 plug_in_ffdc_list = list(filter(None, plug_in_ffdc_list))
Michael Walsh341c21e2017-01-17 16:25:20 -0600699 except IOError:
Michael Walshb2e53ec2017-10-30 15:04:36 -0500700 plug_in_ffdc_list = []
701
702 # Combine the files from plug_in_ffdc_list with the ffdc_file_list passed
703 # in. Eliminate duplicates and sort the list.
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -0500704 ffdc_file_list = sorted(set(ffdc_file_list + plug_in_ffdc_list))
Michael Walshb2e53ec2017-10-30 15:04:36 -0500705
706 if status_file_path != "":
707 ffdc_file_list.insert(0, status_file_path)
708
709 # Convert the list to a printable list.
710 printable_ffdc_file_list = "\n".join(ffdc_file_list)
Michael Walsh341c21e2017-01-17 16:25:20 -0600711
Michael Walsh68a61162017-04-25 11:54:06 -0500712 # Open ffdc_file_list for writing. We will write a complete list of
713 # FFDC files to it for possible use by plug-ins like cp_stop_check.
714 ffdc_list_file = open(ffdc_list_file_path, 'w')
Michael Walshb2e53ec2017-10-30 15:04:36 -0500715 ffdc_list_file.write(printable_ffdc_file_list + "\n")
716 ffdc_list_file.close()
717
718 indent = 0
719 width = 90
720 linefeed = 1
721 char = "="
Michael Walsh68a61162017-04-25 11:54:06 -0500722
723 gp.qprintn()
Michael Walshb2e53ec2017-10-30 15:04:36 -0500724 gp.qprint_dashes(indent, width, linefeed, char)
Michael Walsh68a61162017-04-25 11:54:06 -0500725 gp.qprintn("Copy this data to the defect:\n")
726
Michael Walshe0cf8d72017-05-17 13:20:46 -0500727 if len(more_header_info) > 0:
Michael Walshff340002017-08-29 11:18:27 -0500728 gp.qprintn(more_header_info)
Michael Walshdc80d672017-05-09 12:58:32 -0500729 gp.qpvars(host_name, host_ip, openbmc_nickname, openbmc_host,
730 openbmc_host_name, openbmc_ip, openbmc_username,
Michael Walsh0a3bdb42019-01-31 16:21:44 +0000731 openbmc_password, rest_username, rest_password, ipmi_username,
732 ipmi_password, os_host, os_host_name, os_ip, os_username,
Michael Walshdc80d672017-05-09 12:58:32 -0500733 os_password, pdu_host, pdu_host_name, pdu_ip, pdu_username,
734 pdu_password, pdu_slot_no, openbmc_serial_host,
735 openbmc_serial_host_name, openbmc_serial_ip, openbmc_serial_port)
Michael Walsh68a61162017-04-25 11:54:06 -0500736
737 gp.qprintn()
Michael Walsh986d8ae2019-07-17 10:02:23 -0500738 print_boot_history(boot_history)
Michael Walsh68a61162017-04-25 11:54:06 -0500739 gp.qprintn()
740 gp.qprint_var(state)
Michael Walshb5839d02017-04-12 16:11:20 -0500741 gp.qprintn()
742 gp.qprintn("FFDC data files:")
Michael Walshb2e53ec2017-10-30 15:04:36 -0500743 gp.qprintn(printable_ffdc_file_list)
Michael Walshb5839d02017-04-12 16:11:20 -0500744 gp.qprintn()
Michael Walsh341c21e2017-01-17 16:25:20 -0600745
Michael Walsh600876d2017-05-30 17:58:58 -0500746 if len(ffdc_summary_info) > 0:
Michael Walshff340002017-08-29 11:18:27 -0500747 gp.qprintn(ffdc_summary_info)
Michael Walsh600876d2017-05-30 17:58:58 -0500748
Michael Walshb2e53ec2017-10-30 15:04:36 -0500749 gp.qprint_dashes(indent, width, linefeed, char)
Michael Walsh68a61162017-04-25 11:54:06 -0500750
Michael Walsh6741f742017-02-20 16:16:38 -0600751
Michael Walsh6741f742017-02-20 16:16:38 -0600752def my_ffdc():
Michael Walsh6741f742017-02-20 16:16:38 -0600753 r"""
754 Collect FFDC data.
755 """
756
757 global state
758
759 plug_in_setup()
760 rc, shell_rc, failed_plug_in_name = grpi.rprocess_plug_in_packages(
Michael Walsh600876d2017-05-30 17:58:58 -0500761 call_point='ffdc', stop_on_plug_in_failure=0)
Michael Walsh6741f742017-02-20 16:16:38 -0600762
763 AUTOBOOT_FFDC_PREFIX = os.environ['AUTOBOOT_FFDC_PREFIX']
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -0500764 status, ffdc_file_list = grk.run_key_u("FFDC ffdc_prefix="
765 + AUTOBOOT_FFDC_PREFIX
766 + " ffdc_function_list="
767 + ffdc_function_list, ignore=1)
Michael Walsh83f4bc72017-04-20 16:49:43 -0500768 if status != 'PASS':
Michael Walshff340002017-08-29 11:18:27 -0500769 gp.qprint_error("Call to ffdc failed.\n")
Michael Walshc9bd2e82019-04-18 11:06:52 -0500770 if type(ffdc_file_list) is not list:
771 ffdc_file_list = []
772 # Leave a record for caller that "soft" errors occurred.
773 soft_errors = 1
774 gpu.save_plug_in_value(soft_errors, pgm_name)
Michael Walsh6741f742017-02-20 16:16:38 -0600775
776 my_get_state()
777
Michael Walshb2e53ec2017-10-30 15:04:36 -0500778 print_defect_report(ffdc_file_list)
Michael Walsh6741f742017-02-20 16:16:38 -0600779
Michael Walsh6741f742017-02-20 16:16:38 -0600780
Michael Walsh6741f742017-02-20 16:16:38 -0600781def print_test_start_message(boot_keyword):
Michael Walsh6741f742017-02-20 16:16:38 -0600782 r"""
783 Print a message indicating what boot test is about to run.
784
785 Description of arguments:
786 boot_keyword The name of the boot which is to be run
787 (e.g. "BMC Power On").
788 """
789
Michael Walsh986d8ae2019-07-17 10:02:23 -0500790 global boot_history
Sunil M325eb542017-08-10 07:09:43 -0500791 global boot_start_time
Michael Walsh6741f742017-02-20 16:16:38 -0600792
793 doing_msg = gp.sprint_timen("Doing \"" + boot_keyword + "\".")
Sunil M325eb542017-08-10 07:09:43 -0500794
795 # Set boot_start_time for use by plug-ins.
796 boot_start_time = doing_msg[1:33]
797 gp.qprint_var(boot_start_time)
798
Michael Walshb5839d02017-04-12 16:11:20 -0500799 gp.qprint(doing_msg)
Michael Walsh6741f742017-02-20 16:16:38 -0600800
Michael Walsh986d8ae2019-07-17 10:02:23 -0500801 update_boot_history(boot_history, doing_msg, max_boot_history)
Michael Walsh6741f742017-02-20 16:16:38 -0600802
Michael Walsh6741f742017-02-20 16:16:38 -0600803
Michael Walshf566fb12019-02-01 14:35:09 -0600804def stop_boot_test(signal_number=0,
805 frame=None):
806 r"""
807 Handle SIGUSR1 by aborting the boot test that is running.
808
809 Description of argument(s):
810 signal_number The signal number (should always be 10 for SIGUSR1).
811 frame The frame data.
812 """
813
Michael Walsh80dddde2019-10-22 13:54:38 -0500814 gp.qprintn()
815 gp.qprint_executing()
Michael Walshf566fb12019-02-01 14:35:09 -0600816 gp.lprint_executing()
817
818 # Restore original sigusr1 handler.
819 set_default_siguser1()
820
821 message = "The caller has asked that the boot test be stopped and marked"
822 message += " as a failure."
823
824 function_stack = gm.get_function_stack()
825 if "wait_state" in function_stack:
Michael Walshc44aa532019-06-14 13:33:29 -0500826 st.set_exit_wait_early_message(message)
Michael Walshf566fb12019-02-01 14:35:09 -0600827 else:
828 BuiltIn().fail(gp.sprint_error(message))
829
830
Michael Walsh6741f742017-02-20 16:16:38 -0600831def run_boot(boot):
Michael Walsh6741f742017-02-20 16:16:38 -0600832 r"""
833 Run the specified boot.
834
835 Description of arguments:
836 boot The name of the boot test to be performed.
837 """
838
839 global state
840
Michael Walshf566fb12019-02-01 14:35:09 -0600841 signal.signal(signal.SIGUSR1, stop_boot_test)
842 gp.qprint_timen("stop_boot_test is armed.")
843
Michael Walsh6741f742017-02-20 16:16:38 -0600844 print_test_start_message(boot)
845
846 plug_in_setup()
847 rc, shell_rc, failed_plug_in_name = \
848 grpi.rprocess_plug_in_packages(call_point="pre_boot")
849 if rc != 0:
850 error_message = "Plug-in failed with non-zero return code.\n" +\
Michael Walsh986d8ae2019-07-17 10:02:23 -0500851 gp.sprint_var(rc, fmt=gp.hexa())
Michael Walshf566fb12019-02-01 14:35:09 -0600852 set_default_siguser1()
Michael Walsh6741f742017-02-20 16:16:38 -0600853 BuiltIn().fail(gp.sprint_error(error_message))
854
855 if test_mode:
856 # In test mode, we'll pretend the boot worked by assigning its
857 # required end state to the default state value.
Michael Walsh30dadae2017-02-27 14:25:52 -0600858 state = st.strip_anchor_state(boot_table[boot]['end'])
Michael Walsh6741f742017-02-20 16:16:38 -0600859 else:
860 # Assertion: We trust that the state data was made fresh by the
861 # caller.
862
Michael Walshb5839d02017-04-12 16:11:20 -0500863 gp.qprintn()
Michael Walsh6741f742017-02-20 16:16:38 -0600864
865 if boot_table[boot]['method_type'] == "keyword":
Michael Walsh0b93fbf2017-03-02 14:42:41 -0600866 rk.my_run_keywords(boot_table[boot].get('lib_file_path', ''),
Michael Walshb5839d02017-04-12 16:11:20 -0500867 boot_table[boot]['method'],
868 quiet=quiet)
Michael Walsh6741f742017-02-20 16:16:38 -0600869
870 if boot_table[boot]['bmc_reboot']:
871 st.wait_for_comm_cycle(int(state['epoch_seconds']))
Michael Walsh30dadae2017-02-27 14:25:52 -0600872 plug_in_setup()
873 rc, shell_rc, failed_plug_in_name = \
874 grpi.rprocess_plug_in_packages(call_point="post_reboot")
875 if rc != 0:
Michael Walsh0b93fbf2017-03-02 14:42:41 -0600876 error_message = "Plug-in failed with non-zero return code.\n"
Michael Walsh986d8ae2019-07-17 10:02:23 -0500877 error_message += gp.sprint_var(rc, fmt=gp.hexa())
Michael Walshf566fb12019-02-01 14:35:09 -0600878 set_default_siguser1()
Michael Walsh30dadae2017-02-27 14:25:52 -0600879 BuiltIn().fail(gp.sprint_error(error_message))
Michael Walsh6741f742017-02-20 16:16:38 -0600880 else:
881 match_state = st.anchor_state(state)
882 del match_state['epoch_seconds']
883 # Wait for the state to change in any way.
884 st.wait_state(match_state, wait_time=state_change_timeout,
Michael Walsh600876d2017-05-30 17:58:58 -0500885 interval="10 seconds", invert=1)
Michael Walsh6741f742017-02-20 16:16:38 -0600886
Michael Walshb5839d02017-04-12 16:11:20 -0500887 gp.qprintn()
Michael Walsh6741f742017-02-20 16:16:38 -0600888 if boot_table[boot]['end']['chassis'] == "Off":
889 boot_timeout = power_off_timeout
890 else:
891 boot_timeout = power_on_timeout
892 st.wait_state(boot_table[boot]['end'], wait_time=boot_timeout,
Michael Walsh600876d2017-05-30 17:58:58 -0500893 interval="10 seconds")
Michael Walsh6741f742017-02-20 16:16:38 -0600894
895 plug_in_setup()
896 rc, shell_rc, failed_plug_in_name = \
897 grpi.rprocess_plug_in_packages(call_point="post_boot")
898 if rc != 0:
899 error_message = "Plug-in failed with non-zero return code.\n" +\
Michael Walsh986d8ae2019-07-17 10:02:23 -0500900 gp.sprint_var(rc, fmt=gp.hexa())
Michael Walshf566fb12019-02-01 14:35:09 -0600901 set_default_siguser1()
Michael Walsh6741f742017-02-20 16:16:38 -0600902 BuiltIn().fail(gp.sprint_error(error_message))
903
Michael Walshf566fb12019-02-01 14:35:09 -0600904 # Restore original sigusr1 handler.
905 set_default_siguser1()
906
Michael Walsh6741f742017-02-20 16:16:38 -0600907
Michael Walsh6741f742017-02-20 16:16:38 -0600908def test_loop_body():
Michael Walsh6741f742017-02-20 16:16:38 -0600909 r"""
910 The main loop body for the loop in main_py.
911
912 Description of arguments:
913 boot_count The iteration number (starts at 1).
914 """
915
916 global boot_count
917 global state
918 global next_boot
919 global boot_success
Sunil M325eb542017-08-10 07:09:43 -0500920 global boot_end_time
Michael Walsh6741f742017-02-20 16:16:38 -0600921
Michael Walshb5839d02017-04-12 16:11:20 -0500922 gp.qprintn()
Michael Walsh6741f742017-02-20 16:16:38 -0600923
924 next_boot = select_boot()
Michael Walshb5839d02017-04-12 16:11:20 -0500925 if next_boot == "":
926 return True
Michael Walsh6741f742017-02-20 16:16:38 -0600927
Michael Walshb5839d02017-04-12 16:11:20 -0500928 boot_count += 1
929 gp.qprint_timen("Starting boot " + str(boot_count) + ".")
Michael Walsh6741f742017-02-20 16:16:38 -0600930
Michael Walshe0cf8d72017-05-17 13:20:46 -0500931 pre_boot_plug_in_setup()
Michael Walsh6741f742017-02-20 16:16:38 -0600932
933 cmd_buf = ["run_boot", next_boot]
934 boot_status, msg = BuiltIn().run_keyword_and_ignore_error(*cmd_buf)
935 if boot_status == "FAIL":
Michael Walshb5839d02017-04-12 16:11:20 -0500936 gp.qprint(msg)
Michael Walsh6741f742017-02-20 16:16:38 -0600937
Michael Walshb5839d02017-04-12 16:11:20 -0500938 gp.qprintn()
Michael Walsh6741f742017-02-20 16:16:38 -0600939 if boot_status == "PASS":
940 boot_success = 1
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -0500941 completion_msg = gp.sprint_timen("BOOT_SUCCESS: \"" + next_boot
942 + "\" succeeded.")
Michael Walsh6741f742017-02-20 16:16:38 -0600943 else:
944 boot_success = 0
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -0500945 completion_msg = gp.sprint_timen("BOOT_FAILED: \"" + next_boot
946 + "\" failed.")
Sunil M325eb542017-08-10 07:09:43 -0500947
948 # Set boot_end_time for use by plug-ins.
949 boot_end_time = completion_msg[1:33]
950 gp.qprint_var(boot_end_time)
951
952 gp.qprint(completion_msg)
Michael Walsh6741f742017-02-20 16:16:38 -0600953
954 boot_results.update(next_boot, boot_status)
955
956 plug_in_setup()
957 # NOTE: A post_test_case call point failure is NOT counted as a boot
958 # failure.
959 rc, shell_rc, failed_plug_in_name = grpi.rprocess_plug_in_packages(
Michael Walsh600876d2017-05-30 17:58:58 -0500960 call_point='post_test_case', stop_on_plug_in_failure=0)
Michael Walsh6741f742017-02-20 16:16:38 -0600961
962 plug_in_setup()
963 rc, shell_rc, failed_plug_in_name = grpi.rprocess_plug_in_packages(
Michael Walsh89de14a2018-10-01 16:51:37 -0500964 call_point='ffdc_check', shell_rc=dump_ffdc_rc(),
Michael Walsh6741f742017-02-20 16:16:38 -0600965 stop_on_plug_in_failure=1, stop_on_non_zero_rc=1)
Michael Walsh12059e22019-03-21 11:03:45 -0500966 if ffdc_check == "All" or\
Michael Walsh89de14a2018-10-01 16:51:37 -0500967 shell_rc == dump_ffdc_rc():
Michael Walsh83f4bc72017-04-20 16:49:43 -0500968 status, ret_values = grk.run_key_u("my_ffdc", ignore=1)
969 if status != 'PASS':
Michael Walshff340002017-08-29 11:18:27 -0500970 gp.qprint_error("Call to my_ffdc failed.\n")
Michael Walshc9bd2e82019-04-18 11:06:52 -0500971 # Leave a record for caller that "soft" errors occurred.
972 soft_errors = 1
973 gpu.save_plug_in_value(soft_errors, pgm_name)
Michael Walsh6741f742017-02-20 16:16:38 -0600974
Michael Walshaabef1e2017-09-20 15:16:17 -0500975 if delete_errlogs:
Michael Shepos1a67b082020-08-28 16:01:58 -0500976 # print error logs before delete
977 status, error_logs = grk.run_key_u("Get Error Logs")
978 pels = pel.peltool("-l", ignore_err=1)
Michael Shepos0e5f1132020-09-30 16:24:25 -0500979 log.print_error_logs(error_logs, "AdditionalData Message Severity")
980 gp.qprint_var(pels)
Michael Shepos1a67b082020-08-28 16:01:58 -0500981
Michael Walshaabef1e2017-09-20 15:16:17 -0500982 # We need to purge error logs between boots or they build up.
Michael Walsh409ad352020-02-06 11:46:35 -0600983 grk.run_key(delete_errlogs_cmd, ignore=1)
Michael Shepos92a54bf2020-11-11 11:48:55 -0600984 grk.run_key(delete_bmcdump_cmd, ignore=1)
Michael Walshd139f282017-04-04 18:00:23 -0500985
Michael Walsh952f9b02017-03-09 13:11:14 -0600986 boot_results.print_report()
Michael Walshb5839d02017-04-12 16:11:20 -0500987 gp.qprint_timen("Finished boot " + str(boot_count) + ".")
Michael Walsh952f9b02017-03-09 13:11:14 -0600988
Michael Walsh6741f742017-02-20 16:16:38 -0600989 plug_in_setup()
990 rc, shell_rc, failed_plug_in_name = grpi.rprocess_plug_in_packages(
Michael Walsh89de14a2018-10-01 16:51:37 -0500991 call_point='stop_check', shell_rc=stop_test_rc(),
992 stop_on_non_zero_rc=1)
993 if shell_rc == stop_test_rc():
Michael Walsh3ba8ecd2018-04-24 11:33:25 -0500994 message = "Stopping as requested by user.\n"
Michael Walsh80dddde2019-10-22 13:54:38 -0500995 gp.qprint_time(message)
Michael Walsh3ba8ecd2018-04-24 11:33:25 -0500996 BuiltIn().fail(message)
Michael Walsh6741f742017-02-20 16:16:38 -0600997
Michael Walshd139f282017-04-04 18:00:23 -0500998 # This should help prevent ConnectionErrors.
George Keishing4d65c862020-12-03 06:52:11 -0600999 # Purge all redfish and REST connection 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))