blob: 41cfd4e8e07317a1aec7e1192273166ed40b3f9b [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 Shepos34c79562021-03-18 18:49:44 -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)
George Keishingd86e45c2021-03-19 07:38:14 -050073redfish_delete_sessions = int(BuiltIn().get_variable_value("${REDFISH_DELETE_SESSIONS}", default=1))
Michael Walshe58df1c2019-08-07 09:57:43 -050074if redfish_supported:
George Keishing89537a82020-06-17 00:37:25 -050075 redfish = BuiltIn().get_library_instance('redfish')
Michael Walshe58df1c2019-08-07 09:57:43 -050076 default_power_on = "Redfish Power On"
77 default_power_off = "Redfish Power Off"
George Keishing870999a2021-03-31 23:43:57 -050078 if not redfish_support_trans_state:
Michael Sheposcc490b42020-08-26 12:53:01 -050079 delete_errlogs_cmd = "Delete Error Logs ${quiet}=${1}"
Michael Shepos92a54bf2020-11-11 11:48:55 -060080 delete_bmcdump_cmd = "Delete All BMC Dump"
George Keishingeb1fe352020-06-19 03:02:22 -050081 default_set_power_policy = "Set BMC Power Policy ALWAYS_POWER_OFF"
82 else:
83 delete_errlogs_cmd = "Redfish Purge Event Log"
Michael Shepos92a54bf2020-11-11 11:48:55 -060084 delete_bmcdump_cmd = "Redfish Delete All BMC Dumps"
George Keishingeb1fe352020-06-19 03:02:22 -050085 default_set_power_policy = "Redfish Set Power Restore Policy AlwaysOff"
Michael Walshe58df1c2019-08-07 09:57:43 -050086else:
87 default_power_on = "REST Power On"
88 default_power_off = "REST Power Off"
Michael Sheposcc490b42020-08-26 12:53:01 -050089 delete_errlogs_cmd = "Delete Error Logs ${quiet}=${1}"
Michael Shepos92a54bf2020-11-11 11:48:55 -060090 delete_bmcdump_cmd = "Delete All BMC Dump"
George Keishinga54e06f2020-06-12 10:42:41 -050091 default_set_power_policy = "Set BMC Power Policy ALWAYS_POWER_OFF"
Michael Walsh6741f742017-02-20 16:16:38 -060092boot_count = 0
Michael Walsh0bbd8602016-11-22 11:31:49 -060093
Michael Walsh85678942017-03-27 14:34:22 -050094LOG_LEVEL = BuiltIn().get_variable_value("${LOG_LEVEL}")
Michael Walsh986d8ae2019-07-17 10:02:23 -050095AUTOBOOT_FFDC_PREFIX = os.environ.get('AUTOBOOT_FFDC_PREFIX', '')
96ffdc_prefix = AUTOBOOT_FFDC_PREFIX
Sunil M325eb542017-08-10 07:09:43 -050097boot_start_time = ""
98boot_end_time = ""
Michael Walshff340002017-08-29 11:18:27 -050099save_stack = vs.var_stack('save_stack')
100main_func_parm_list = ['boot_stack', 'stack_mode', 'quiet']
Michael Walsh85678942017-03-27 14:34:22 -0500101
102
Michael Walsh89de14a2018-10-01 16:51:37 -0500103def dump_ffdc_rc():
104 r"""
105 Return the constant dump ffdc test return code value.
106
107 When a plug-in call point program returns this value, it indicates that
108 this program should collect FFDC.
109 """
110
111 return 0x00000200
112
113
114def stop_test_rc():
115 r"""
116 Return the constant stop test return code value.
117
118 When a plug-in call point program returns this value, it indicates that
119 this program should stop running.
120 """
121
122 return 0x00000200
123
124
Michael Walsh0ad0f7f2017-05-04 14:39:58 -0500125def process_host(host,
126 host_var_name=""):
Michael Walsh0ad0f7f2017-05-04 14:39:58 -0500127 r"""
128 Process a host by getting the associated host name and IP address and
129 setting them in global variables.
130
131 If the caller does not pass the host_var_name, this function will try to
132 figure out the name of the variable used by the caller for the host parm.
133 Callers are advised to explicitly specify the host_var_name when calling
134 with an exec command. In such cases, the get_arg_name cannot figure out
135 the host variable name.
136
137 This function will then create similar global variable names by
138 removing "_host" and appending "_host_name" or "_ip" to the host variable
139 name.
140
141 Example:
142
143 If a call is made like this:
144 process_host(openbmc_host)
145
146 Global variables openbmc_host_name and openbmc_ip will be set.
147
148 Description of argument(s):
149 host A host name or IP. The name of the variable used should
150 have a suffix of "_host".
151 host_var_name The name of the variable being used as the host parm.
152 """
153
154 if host_var_name == "":
155 host_var_name = gp.get_arg_name(0, 1, stack_frame_ix=2)
156
157 host_name_var_name = re.sub("host", "host_name", host_var_name)
158 ip_var_name = re.sub("host", "ip", host_var_name)
159 cmd_buf = "global " + host_name_var_name + ", " + ip_var_name + " ; " +\
160 host_name_var_name + ", " + ip_var_name + " = gm.get_host_name_ip('" +\
161 host + "')"
162 exec(cmd_buf)
163
Michael Walsh0ad0f7f2017-05-04 14:39:58 -0500164
Michael Walshb5839d02017-04-12 16:11:20 -0500165def process_pgm_parms():
Michael Walshb5839d02017-04-12 16:11:20 -0500166 r"""
167 Process the program parameters by assigning them all to corresponding
168 globals. Also, set some global values that depend on program parameters.
169 """
170
171 # Program parameter processing.
172 # Assign all program parms to python variables which are global to this
173 # module.
174
175 global parm_list
176 parm_list = BuiltIn().get_variable_value("${parm_list}")
177 # The following subset of parms should be processed as integers.
178 int_list = ['max_num_tests', 'boot_pass', 'boot_fail', 'ffdc_only',
Michael Walsh89de14a2018-10-01 16:51:37 -0500179 'boot_fail_threshold', 'delete_errlogs',
Michael Walsh986d8ae2019-07-17 10:02:23 -0500180 'call_post_stack_plug', 'do_pre_boot_plug_in_setup', 'quiet',
181 'test_mode', 'debug']
Michael Walshb5839d02017-04-12 16:11:20 -0500182 for parm in parm_list:
183 if parm in int_list:
184 sub_cmd = "int(BuiltIn().get_variable_value(\"${" + parm +\
185 "}\", \"0\"))"
186 else:
187 sub_cmd = "BuiltIn().get_variable_value(\"${" + parm + "}\")"
188 cmd_buf = "global " + parm + " ; " + parm + " = " + sub_cmd
Michael Walshff340002017-08-29 11:18:27 -0500189 gp.dpissuing(cmd_buf)
Michael Walshb5839d02017-04-12 16:11:20 -0500190 exec(cmd_buf)
Michael Walsh0ad0f7f2017-05-04 14:39:58 -0500191 if re.match(r".*_host$", parm):
192 cmd_buf = "process_host(" + parm + ", '" + parm + "')"
193 exec(cmd_buf)
194 if re.match(r".*_password$", parm):
195 # Register the value of any parm whose name ends in _password.
196 # This will cause the print functions to replace passwords with
197 # asterisks in the output.
198 cmd_buf = "gp.register_passwords(" + parm + ")"
199 exec(cmd_buf)
Michael Walshb5839d02017-04-12 16:11:20 -0500200
201 global ffdc_dir_path_style
202 global boot_list
203 global boot_stack
204 global boot_results_file_path
205 global boot_results
Michael Walsh986d8ae2019-07-17 10:02:23 -0500206 global boot_history
Michael Walshb5839d02017-04-12 16:11:20 -0500207 global ffdc_list_file_path
Michael Walshe0cf8d72017-05-17 13:20:46 -0500208 global ffdc_report_list_path
Michael Walsh600876d2017-05-30 17:58:58 -0500209 global ffdc_summary_list_path
Michael Walsha3e7b222020-02-03 15:32:16 -0600210 global boot_table
211 global valid_boot_types
Michael Walshb5839d02017-04-12 16:11:20 -0500212
213 if ffdc_dir_path_style == "":
214 ffdc_dir_path_style = int(os.environ.get('FFDC_DIR_PATH_STYLE', '0'))
215
216 # Convert these program parms to lists for easier processing..
George Keishing36efbc02018-12-12 10:18:23 -0600217 boot_list = list(filter(None, boot_list.split(":")))
218 boot_stack = list(filter(None, boot_stack.split(":")))
Michael Walshb5839d02017-04-12 16:11:20 -0500219
Michael Walsha3e7b222020-02-03 15:32:16 -0600220 boot_table = create_boot_table(boot_table_path, os_host=os_host)
221 valid_boot_types = create_valid_boot_list(boot_table)
222
Michael Walsh903e0b22017-09-19 17:00:33 -0500223 cleanup_boot_results_file()
224 boot_results_file_path = create_boot_results_file_path(pgm_name,
225 openbmc_nickname,
226 master_pid)
Michael Walshb5839d02017-04-12 16:11:20 -0500227
228 if os.path.isfile(boot_results_file_path):
229 # We've been called before in this run so we'll load the saved
Michael Walsh986d8ae2019-07-17 10:02:23 -0500230 # boot_results and boot_history objects.
231 boot_results, boot_history =\
Michael Walsh6c645742018-08-17 15:02:17 -0500232 pickle.load(open(boot_results_file_path, 'rb'))
Michael Walshb5839d02017-04-12 16:11:20 -0500233 else:
234 boot_results = boot_results(boot_table, boot_pass, boot_fail)
235
236 ffdc_list_file_path = base_tool_dir_path + openbmc_nickname +\
237 "/FFDC_FILE_LIST"
Michael Walshe0cf8d72017-05-17 13:20:46 -0500238 ffdc_report_list_path = base_tool_dir_path + openbmc_nickname +\
239 "/FFDC_REPORT_FILE_LIST"
Michael Walshb5839d02017-04-12 16:11:20 -0500240
Michael Walsh600876d2017-05-30 17:58:58 -0500241 ffdc_summary_list_path = base_tool_dir_path + openbmc_nickname +\
242 "/FFDC_SUMMARY_FILE_LIST"
243
Michael Walshb5839d02017-04-12 16:11:20 -0500244
Michael Walsh85678942017-03-27 14:34:22 -0500245def initial_plug_in_setup():
Michael Walsh85678942017-03-27 14:34:22 -0500246 r"""
247 Initialize all plug-in environment variables which do not change for the
248 duration of the program.
249
250 """
251
252 global LOG_LEVEL
253 BuiltIn().set_log_level("NONE")
254
255 BuiltIn().set_global_variable("${master_pid}", master_pid)
256 BuiltIn().set_global_variable("${FFDC_DIR_PATH}", ffdc_dir_path)
257 BuiltIn().set_global_variable("${STATUS_DIR_PATH}", status_dir_path)
258 BuiltIn().set_global_variable("${BASE_TOOL_DIR_PATH}", base_tool_dir_path)
259 BuiltIn().set_global_variable("${FFDC_LIST_FILE_PATH}",
260 ffdc_list_file_path)
Michael Walshe0cf8d72017-05-17 13:20:46 -0500261 BuiltIn().set_global_variable("${FFDC_REPORT_LIST_PATH}",
262 ffdc_report_list_path)
Michael Walsh600876d2017-05-30 17:58:58 -0500263 BuiltIn().set_global_variable("${FFDC_SUMMARY_LIST_PATH}",
264 ffdc_summary_list_path)
Michael Walsh85678942017-03-27 14:34:22 -0500265
266 BuiltIn().set_global_variable("${FFDC_DIR_PATH_STYLE}",
267 ffdc_dir_path_style)
268 BuiltIn().set_global_variable("${FFDC_CHECK}",
269 ffdc_check)
270
271 # For each program parameter, set the corresponding AUTOBOOT_ environment
272 # variable value. Also, set an AUTOBOOT_ environment variable for every
273 # element in additional_values.
274 additional_values = ["program_pid", "master_pid", "ffdc_dir_path",
275 "status_dir_path", "base_tool_dir_path",
Michael Walsh600876d2017-05-30 17:58:58 -0500276 "ffdc_list_file_path", "ffdc_report_list_path",
Michael Shepos7fe83b32020-09-21 15:46:01 -0500277 "ffdc_summary_list_path", "execdir", "redfish_supported",
Michael Shepos34c79562021-03-18 18:49:44 -0500278 "redfish_rest_supported", "redfish_support_trans_state"]
Michael Walsh85678942017-03-27 14:34:22 -0500279
280 plug_in_vars = parm_list + additional_values
281
282 for var_name in plug_in_vars:
283 var_value = BuiltIn().get_variable_value("${" + var_name + "}")
284 var_name = var_name.upper()
285 if var_value is None:
286 var_value = ""
287 os.environ["AUTOBOOT_" + var_name] = str(var_value)
288
289 BuiltIn().set_log_level(LOG_LEVEL)
290
Michael Walsh68a61162017-04-25 11:54:06 -0500291 # Make sure the ffdc list directory exists.
292 ffdc_list_dir_path = os.path.dirname(ffdc_list_file_path) + os.sep
293 if not os.path.exists(ffdc_list_dir_path):
294 os.makedirs(ffdc_list_dir_path)
Michael Walsh85678942017-03-27 14:34:22 -0500295
Michael Walsh85678942017-03-27 14:34:22 -0500296
Michael Walsh0bbd8602016-11-22 11:31:49 -0600297def plug_in_setup():
Michael Walsh0bbd8602016-11-22 11:31:49 -0600298 r"""
Michael Walsh85678942017-03-27 14:34:22 -0500299 Initialize all changing plug-in environment variables for use by the
300 plug-in programs.
Michael Walsh0bbd8602016-11-22 11:31:49 -0600301 """
302
Michael Walsh85678942017-03-27 14:34:22 -0500303 global LOG_LEVEL
304 global test_really_running
305
306 BuiltIn().set_log_level("NONE")
307
Michael Walsh6741f742017-02-20 16:16:38 -0600308 boot_pass, boot_fail = boot_results.return_total_pass_fail()
Michael Walsh0bbd8602016-11-22 11:31:49 -0600309 if boot_pass > 1:
310 test_really_running = 1
311 else:
312 test_really_running = 0
313
Michael Walsh6741f742017-02-20 16:16:38 -0600314 BuiltIn().set_global_variable("${test_really_running}",
315 test_really_running)
316 BuiltIn().set_global_variable("${boot_type_desc}", next_boot)
Michael Walsh6741f742017-02-20 16:16:38 -0600317 BuiltIn().set_global_variable("${boot_pass}", boot_pass)
318 BuiltIn().set_global_variable("${boot_fail}", boot_fail)
319 BuiltIn().set_global_variable("${boot_success}", boot_success)
320 BuiltIn().set_global_variable("${ffdc_prefix}", ffdc_prefix)
Sunil M325eb542017-08-10 07:09:43 -0500321 BuiltIn().set_global_variable("${boot_start_time}", boot_start_time)
322 BuiltIn().set_global_variable("${boot_end_time}", boot_end_time)
Michael Walsh4c9a6452016-12-13 16:03:11 -0600323
Michael Walsh0bbd8602016-11-22 11:31:49 -0600324 # For each program parameter, set the corresponding AUTOBOOT_ environment
325 # variable value. Also, set an AUTOBOOT_ environment variable for every
326 # element in additional_values.
327 additional_values = ["boot_type_desc", "boot_success", "boot_pass",
Sunil M325eb542017-08-10 07:09:43 -0500328 "boot_fail", "test_really_running", "ffdc_prefix",
329 "boot_start_time", "boot_end_time"]
Michael Walsh0bbd8602016-11-22 11:31:49 -0600330
Michael Walsh85678942017-03-27 14:34:22 -0500331 plug_in_vars = additional_values
Michael Walsh0bbd8602016-11-22 11:31:49 -0600332
333 for var_name in plug_in_vars:
334 var_value = BuiltIn().get_variable_value("${" + var_name + "}")
335 var_name = var_name.upper()
336 if var_value is None:
337 var_value = ""
Michael Walsh6741f742017-02-20 16:16:38 -0600338 os.environ["AUTOBOOT_" + var_name] = str(var_value)
Michael Walsh0bbd8602016-11-22 11:31:49 -0600339
Michael Walsh0bbd8602016-11-22 11:31:49 -0600340 if debug:
Michael Walsh6741f742017-02-20 16:16:38 -0600341 shell_rc, out_buf = \
342 gc.cmd_fnc_u("printenv | egrep AUTOBOOT_ | sort -u")
Michael Walsh0bbd8602016-11-22 11:31:49 -0600343
Michael Walsh85678942017-03-27 14:34:22 -0500344 BuiltIn().set_log_level(LOG_LEVEL)
345
Michael Walsh0bbd8602016-11-22 11:31:49 -0600346
Michael Walshe0cf8d72017-05-17 13:20:46 -0500347def pre_boot_plug_in_setup():
348
349 # Clear the ffdc_list_file_path file. Plug-ins may now write to it.
350 try:
351 os.remove(ffdc_list_file_path)
352 except OSError:
353 pass
354
355 # Clear the ffdc_report_list_path file. Plug-ins may now write to it.
356 try:
357 os.remove(ffdc_report_list_path)
358 except OSError:
359 pass
360
Michael Walsh600876d2017-05-30 17:58:58 -0500361 # Clear the ffdc_summary_list_path file. Plug-ins may now write to it.
362 try:
363 os.remove(ffdc_summary_list_path)
364 except OSError:
365 pass
366
Michael Walshe1974b92017-08-03 13:39:51 -0500367 global ffdc_prefix
368
369 seconds = time.time()
370 loc_time = time.localtime(seconds)
371 time_string = time.strftime("%y%m%d.%H%M%S.", loc_time)
372
373 ffdc_prefix = openbmc_nickname + "." + time_string
374
Michael Walshe0cf8d72017-05-17 13:20:46 -0500375
Michael Walshf566fb12019-02-01 14:35:09 -0600376def default_sigusr1(signal_number=0,
377 frame=None):
378 r"""
379 Handle SIGUSR1 by doing nothing.
380
381 This function assists in debugging SIGUSR1 processing by printing messages
382 to stdout and to the log.html file.
383
384 Description of argument(s):
385 signal_number The signal number (should always be 10 for SIGUSR1).
386 frame The frame data.
387 """
388
Michael Walsh80dddde2019-10-22 13:54:38 -0500389 gp.qprintn()
390 gp.qprint_executing()
Michael Walshf566fb12019-02-01 14:35:09 -0600391 gp.lprint_executing()
392
393
394def set_default_siguser1():
395 r"""
396 Set the default_sigusr1 function to be the SIGUSR1 handler.
397 """
398
Michael Walsh80dddde2019-10-22 13:54:38 -0500399 gp.qprintn()
400 gp.qprint_executing()
Michael Walshf566fb12019-02-01 14:35:09 -0600401 gp.lprint_executing()
402 signal.signal(signal.SIGUSR1, default_sigusr1)
403
404
Michael Walsh6741f742017-02-20 16:16:38 -0600405def setup():
Michael Walsh0bbd8602016-11-22 11:31:49 -0600406 r"""
Michael Walsh6741f742017-02-20 16:16:38 -0600407 Do general program setup tasks.
Michael Walsh0bbd8602016-11-22 11:31:49 -0600408 """
409
Michael Walsh6741f742017-02-20 16:16:38 -0600410 global cp_setup_called
Michael Walsh81816742017-09-27 11:02:29 -0500411 global transitional_boot_selected
Michael Walsh0bbd8602016-11-22 11:31:49 -0600412
Michael Walshb5839d02017-04-12 16:11:20 -0500413 gp.qprintn()
414
George Keishinga54e06f2020-06-12 10:42:41 -0500415 if redfish_supported:
416 redfish.login()
417
Michael Walshf566fb12019-02-01 14:35:09 -0600418 set_default_siguser1()
Michael Walsh81816742017-09-27 11:02:29 -0500419 transitional_boot_selected = False
420
Michael Walsh83f4bc72017-04-20 16:49:43 -0500421 robot_pgm_dir_path = os.path.dirname(__file__) + os.sep
422 repo_bin_path = robot_pgm_dir_path.replace("/lib/", "/bin/")
Michael Walshd061c042017-05-23 14:46:57 -0500423 # If we can't find process_plug_in_packages.py, ssh_pw or
424 # validate_plug_ins.py, then we don't have our repo bin in PATH.
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -0500425 shell_rc, out_buf = gc.cmd_fnc_u("which process_plug_in_packages.py"
426 + " ssh_pw validate_plug_ins.py", quiet=1,
Michael Walshd061c042017-05-23 14:46:57 -0500427 print_output=0, show_err=0)
Michael Walshb5839d02017-04-12 16:11:20 -0500428 if shell_rc != 0:
Michael Walsh83f4bc72017-04-20 16:49:43 -0500429 os.environ['PATH'] = repo_bin_path + ":" + os.environ.get('PATH', "")
430 # Likewise, our repo lib subdir needs to be in sys.path and PYTHONPATH.
431 if robot_pgm_dir_path not in sys.path:
432 sys.path.append(robot_pgm_dir_path)
433 PYTHONPATH = os.environ.get("PYTHONPATH", "")
434 if PYTHONPATH == "":
435 os.environ['PYTHONPATH'] = robot_pgm_dir_path
436 else:
437 os.environ['PYTHONPATH'] = robot_pgm_dir_path + ":" + PYTHONPATH
Michael Walsh6741f742017-02-20 16:16:38 -0600438
439 validate_parms()
440
Michael Walshc108e422019-03-28 12:27:18 -0500441 gp.qprint_pgm_header()
Michael Walsh6741f742017-02-20 16:16:38 -0600442
George Keishinga54e06f2020-06-12 10:42:41 -0500443 grk.run_key_u(default_set_power_policy)
Michael Walsh11cfc8c2017-03-31 09:40:55 -0500444
Michael Walsh85678942017-03-27 14:34:22 -0500445 initial_plug_in_setup()
446
Michael Walsh6741f742017-02-20 16:16:38 -0600447 plug_in_setup()
448 rc, shell_rc, failed_plug_in_name = grpi.rprocess_plug_in_packages(
449 call_point='setup')
450 if rc != 0:
451 error_message = "Plug-in setup failed.\n"
Michael Walshc108e422019-03-28 12:27:18 -0500452 gp.print_error_report(error_message)
Michael Walsh6741f742017-02-20 16:16:38 -0600453 BuiltIn().fail(error_message)
454 # Setting cp_setup_called lets our Teardown know that it needs to call
455 # the cleanup plug-in call point.
456 cp_setup_called = 1
457
458 # Keyword "FFDC" will fail if TEST_MESSAGE is not set.
459 BuiltIn().set_global_variable("${TEST_MESSAGE}", "${EMPTY}")
Michael Walsh85678942017-03-27 14:34:22 -0500460 # FFDC_LOG_PATH is used by "FFDC" keyword.
461 BuiltIn().set_global_variable("${FFDC_LOG_PATH}", ffdc_dir_path)
Michael Walsh6741f742017-02-20 16:16:38 -0600462
Michael Walshdc80d672017-05-09 12:58:32 -0500463 # Also printed by FFDC.
464 global host_name
465 global host_ip
466 host = socket.gethostname()
467 host_name, host_ip = gm.get_host_name_ip(host)
468
Michael Walsh986d8ae2019-07-17 10:02:23 -0500469 gp.dprint_var(boot_table)
Michael Walshb5839d02017-04-12 16:11:20 -0500470 gp.dprint_var(boot_lists)
Michael Walsh0bbd8602016-11-22 11:31:49 -0600471
Michael Walsh0bbd8602016-11-22 11:31:49 -0600472
Michael Walsh6741f742017-02-20 16:16:38 -0600473def validate_parms():
Michael Walsh0bbd8602016-11-22 11:31:49 -0600474 r"""
Michael Walsh6741f742017-02-20 16:16:38 -0600475 Validate all program parameters.
Michael Walsh0bbd8602016-11-22 11:31:49 -0600476 """
477
Michael Walshb5839d02017-04-12 16:11:20 -0500478 process_pgm_parms()
Michael Walsh0bbd8602016-11-22 11:31:49 -0600479
Michael Walshb5839d02017-04-12 16:11:20 -0500480 gp.qprintn()
481
482 global openbmc_model
Michael Walshf5ce38c2020-02-27 12:46:20 -0600483 if openbmc_model == "":
484 status, ret_values =\
485 grk.run_key_u("Get BMC System Model")
486 openbmc_model = ret_values
487 BuiltIn().set_global_variable("${openbmc_model}", openbmc_model)
488 gv.set_exit_on_error(True)
Michael Walsh44cef252019-08-01 12:38:56 -0500489 gv.valid_value(openbmc_host)
490 gv.valid_value(openbmc_username)
491 gv.valid_value(openbmc_password)
492 gv.valid_value(rest_username)
493 gv.valid_value(rest_password)
494 gv.valid_value(ipmi_username)
495 gv.valid_value(ipmi_password)
Michael Walsh6741f742017-02-20 16:16:38 -0600496 if os_host != "":
Michael Walsh44cef252019-08-01 12:38:56 -0500497 gv.valid_value(os_username)
498 gv.valid_value(os_password)
Michael Walsh6741f742017-02-20 16:16:38 -0600499 if pdu_host != "":
Michael Walsh44cef252019-08-01 12:38:56 -0500500 gv.valid_value(pdu_username)
501 gv.valid_value(pdu_password)
502 gv.valid_integer(pdu_slot_no)
Michael Walsh6741f742017-02-20 16:16:38 -0600503 if openbmc_serial_host != "":
Michael Walsh44cef252019-08-01 12:38:56 -0500504 gv.valid_integer(openbmc_serial_port)
Michael Walsh44cef252019-08-01 12:38:56 -0500505 gv.valid_value(openbmc_model)
506 gv.valid_integer(max_num_tests)
507 gv.valid_integer(boot_pass)
508 gv.valid_integer(boot_fail)
Michael Walsh6741f742017-02-20 16:16:38 -0600509 plug_in_packages_list = grpi.rvalidate_plug_ins(plug_in_dir_paths)
510 BuiltIn().set_global_variable("${plug_in_packages_list}",
511 plug_in_packages_list)
Michael Walsh44cef252019-08-01 12:38:56 -0500512 gv.valid_value(stack_mode, valid_values=['normal', 'skip'])
Michael Walshf5ce38c2020-02-27 12:46:20 -0600513 gv.set_exit_on_error(False)
Michael Walsha20da402017-03-31 16:27:45 -0500514 if len(boot_list) == 0 and len(boot_stack) == 0 and not ffdc_only:
Michael Walsh6741f742017-02-20 16:16:38 -0600515 error_message = "You must provide either a value for either the" +\
516 " boot_list or the boot_stack parm.\n"
517 BuiltIn().fail(gp.sprint_error(error_message))
Michael Walsh6741f742017-02-20 16:16:38 -0600518 valid_boot_list(boot_list, valid_boot_types)
519 valid_boot_list(boot_stack, valid_boot_types)
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -0500520 selected_PDU_boots = list(set(boot_list + boot_stack)
521 & set(boot_lists['PDU_reboot']))
Michael Walsh11cfc8c2017-03-31 09:40:55 -0500522 if len(selected_PDU_boots) > 0 and pdu_host == "":
523 error_message = "You have selected the following boots which" +\
524 " require a PDU host but no value for pdu_host:\n"
525 error_message += gp.sprint_var(selected_PDU_boots)
Michael Walsh986d8ae2019-07-17 10:02:23 -0500526 error_message += gp.sprint_var(pdu_host, fmt=gp.blank())
Michael Walsh11cfc8c2017-03-31 09:40:55 -0500527 BuiltIn().fail(gp.sprint_error(error_message))
528
Michael Walsh6741f742017-02-20 16:16:38 -0600529 return
Michael Walsh0bbd8602016-11-22 11:31:49 -0600530
Michael Walsh0bbd8602016-11-22 11:31:49 -0600531
Michael Walsh6741f742017-02-20 16:16:38 -0600532def my_get_state():
Michael Walsh0bbd8602016-11-22 11:31:49 -0600533 r"""
Michael Walsh6741f742017-02-20 16:16:38 -0600534 Get the system state plus a little bit of wrapping.
Michael Walsh0bbd8602016-11-22 11:31:49 -0600535 """
536
Michael Walsh6741f742017-02-20 16:16:38 -0600537 global state
538
539 req_states = ['epoch_seconds'] + st.default_req_states
540
Michael Walshb5839d02017-04-12 16:11:20 -0500541 gp.qprint_timen("Getting system state.")
Michael Walsh6741f742017-02-20 16:16:38 -0600542 if test_mode:
543 state['epoch_seconds'] = int(time.time())
544 else:
Michael Walshb5839d02017-04-12 16:11:20 -0500545 state = st.get_state(req_states=req_states, quiet=quiet)
546 gp.qprint_var(state)
Michael Walsh341c21e2017-01-17 16:25:20 -0600547
Michael Walsh341c21e2017-01-17 16:25:20 -0600548
Michael Walsh45ca6e42017-09-14 17:29:12 -0500549def valid_state():
Michael Walsh45ca6e42017-09-14 17:29:12 -0500550 r"""
551 Verify that our state dictionary contains no blank values. If we don't get
552 valid state data, we cannot continue to work.
553 """
554
555 if st.compare_states(state, st.invalid_state_match, 'or'):
556 error_message = "The state dictionary contains blank fields which" +\
557 " is illegal.\n" + gp.sprint_var(state)
558 BuiltIn().fail(gp.sprint_error(error_message))
559
Michael Walsh45ca6e42017-09-14 17:29:12 -0500560
Michael Walsh6741f742017-02-20 16:16:38 -0600561def select_boot():
Michael Walsh341c21e2017-01-17 16:25:20 -0600562 r"""
563 Select a boot test to be run based on our current state and return the
564 chosen boot type.
565
566 Description of arguments:
Michael Walsh6741f742017-02-20 16:16:38 -0600567 state The state of the machine.
Michael Walsh341c21e2017-01-17 16:25:20 -0600568 """
569
Michael Walsh81816742017-09-27 11:02:29 -0500570 global transitional_boot_selected
Michael Walsh30dadae2017-02-27 14:25:52 -0600571 global boot_stack
572
Michael Walshb5839d02017-04-12 16:11:20 -0500573 gp.qprint_timen("Selecting a boot test.")
Michael Walsh6741f742017-02-20 16:16:38 -0600574
Michael Walsh81816742017-09-27 11:02:29 -0500575 if transitional_boot_selected and not boot_success:
576 prior_boot = next_boot
577 boot_candidate = boot_stack.pop()
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -0500578 gp.qprint_timen("The prior '" + next_boot + "' was chosen to"
579 + " transition to a valid state for '" + boot_candidate
580 + "' which was at the top of the boot_stack. Since"
581 + " the '" + next_boot + "' failed, the '"
582 + boot_candidate + "' has been removed from the stack"
583 + " to avoid and endless failure loop.")
Michael Walsh81816742017-09-27 11:02:29 -0500584 if len(boot_stack) == 0:
585 return ""
586
Michael Walsh6741f742017-02-20 16:16:38 -0600587 my_get_state()
Michael Walsh45ca6e42017-09-14 17:29:12 -0500588 valid_state()
Michael Walsh6741f742017-02-20 16:16:38 -0600589
Michael Walsh81816742017-09-27 11:02:29 -0500590 transitional_boot_selected = False
Michael Walsh6741f742017-02-20 16:16:38 -0600591 stack_popped = 0
592 if len(boot_stack) > 0:
593 stack_popped = 1
Michael Walshb5839d02017-04-12 16:11:20 -0500594 gp.qprint_dashes()
595 gp.qprint_var(boot_stack)
596 gp.qprint_dashes()
597 skip_boot_printed = 0
598 while len(boot_stack) > 0:
599 boot_candidate = boot_stack.pop()
600 if stack_mode == 'normal':
601 break
602 else:
603 if st.compare_states(state, boot_table[boot_candidate]['end']):
604 if not skip_boot_printed:
Michael Walshff340002017-08-29 11:18:27 -0500605 gp.qprint_var(stack_mode)
606 gp.qprintn()
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -0500607 gp.qprint_timen("Skipping the following boot tests"
608 + " which are unnecessary since their"
609 + " required end states match the"
610 + " current machine state:")
Michael Walshb5839d02017-04-12 16:11:20 -0500611 skip_boot_printed = 1
Michael Walshff340002017-08-29 11:18:27 -0500612 gp.qprint_var(boot_candidate)
Michael Walshb5839d02017-04-12 16:11:20 -0500613 boot_candidate = ""
614 if boot_candidate == "":
615 gp.qprint_dashes()
616 gp.qprint_var(boot_stack)
617 gp.qprint_dashes()
618 return boot_candidate
Michael Walsh6741f742017-02-20 16:16:38 -0600619 if st.compare_states(state, boot_table[boot_candidate]['start']):
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -0500620 gp.qprint_timen("The machine state is valid for a '"
621 + boot_candidate + "' boot test.")
Michael Walshb5839d02017-04-12 16:11:20 -0500622 gp.qprint_dashes()
623 gp.qprint_var(boot_stack)
624 gp.qprint_dashes()
Michael Walsh6741f742017-02-20 16:16:38 -0600625 return boot_candidate
Michael Walsh341c21e2017-01-17 16:25:20 -0600626 else:
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -0500627 gp.qprint_timen("The machine state does not match the required"
628 + " starting state for a '" + boot_candidate
629 + "' boot test:")
Michael Walsh986d8ae2019-07-17 10:02:23 -0500630 gp.qprint_varx("boot_table_start_entry",
631 boot_table[boot_candidate]['start'])
Michael Walsh6741f742017-02-20 16:16:38 -0600632 boot_stack.append(boot_candidate)
Michael Walsh81816742017-09-27 11:02:29 -0500633 transitional_boot_selected = True
Michael Walsh6741f742017-02-20 16:16:38 -0600634 popped_boot = boot_candidate
635
636 # Loop through your list selecting a boot_candidates
637 boot_candidates = []
638 for boot_candidate in boot_list:
639 if st.compare_states(state, boot_table[boot_candidate]['start']):
640 if stack_popped:
641 if st.compare_states(boot_table[boot_candidate]['end'],
Gunnar Mills096cd562018-03-26 10:19:12 -0500642 boot_table[popped_boot]['start']):
Michael Walsh6741f742017-02-20 16:16:38 -0600643 boot_candidates.append(boot_candidate)
644 else:
645 boot_candidates.append(boot_candidate)
646
647 if len(boot_candidates) == 0:
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -0500648 gp.qprint_timen("The user's boot list contained no boot tests"
649 + " which are valid for the current machine state.")
Michael Walsh6741f742017-02-20 16:16:38 -0600650 boot_candidate = default_power_on
651 if not st.compare_states(state, boot_table[default_power_on]['start']):
652 boot_candidate = default_power_off
653 boot_candidates.append(boot_candidate)
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -0500654 gp.qprint_timen("Using default '" + boot_candidate
655 + "' boot type to transition to valid state.")
Michael Walsh6741f742017-02-20 16:16:38 -0600656
Michael Walshb5839d02017-04-12 16:11:20 -0500657 gp.dprint_var(boot_candidates)
Michael Walsh6741f742017-02-20 16:16:38 -0600658
659 # Randomly select a boot from the candidate list.
660 boot = random.choice(boot_candidates)
Michael Walsh341c21e2017-01-17 16:25:20 -0600661
662 return boot
Michael Walsh0bbd8602016-11-22 11:31:49 -0600663
Michael Walsh55302292017-01-10 11:43:02 -0600664
Michael Walshb2e53ec2017-10-30 15:04:36 -0500665def print_defect_report(ffdc_file_list):
Michael Walsh341c21e2017-01-17 16:25:20 -0600666 r"""
667 Print a defect report.
Michael Walshb2e53ec2017-10-30 15:04:36 -0500668
669 Description of argument(s):
670 ffdc_file_list A list of files which were collected by our ffdc functions.
Michael Walsh341c21e2017-01-17 16:25:20 -0600671 """
672
Michael Walsh600876d2017-05-30 17:58:58 -0500673 # Making deliberate choice to NOT run plug_in_setup(). We don't want
674 # ffdc_prefix updated.
675 rc, shell_rc, failed_plug_in_name = grpi.rprocess_plug_in_packages(
676 call_point='ffdc_report', stop_on_plug_in_failure=0)
677
Michael Walshe0cf8d72017-05-17 13:20:46 -0500678 # Get additional header data which may have been created by ffdc plug-ins.
679 # Also, delete the individual header files to cleanup.
680 cmd_buf = "file_list=$(cat " + ffdc_report_list_path + " 2>/dev/null)" +\
681 " ; [ ! -z \"${file_list}\" ] && cat ${file_list}" +\
682 " 2>/dev/null ; rm -rf ${file_list} 2>/dev/null || :"
683 shell_rc, more_header_info = gc.cmd_fnc_u(cmd_buf, print_output=0,
684 show_err=0)
685
Michael Walshb2e53ec2017-10-30 15:04:36 -0500686 # Get additional summary data which may have been created by ffdc plug-ins.
Michael Walsh600876d2017-05-30 17:58:58 -0500687 # Also, delete the individual header files to cleanup.
688 cmd_buf = "file_list=$(cat " + ffdc_summary_list_path + " 2>/dev/null)" +\
689 " ; [ ! -z \"${file_list}\" ] && cat ${file_list}" +\
690 " 2>/dev/null ; rm -rf ${file_list} 2>/dev/null || :"
691 shell_rc, ffdc_summary_info = gc.cmd_fnc_u(cmd_buf, print_output=0,
692 show_err=0)
693
Michael Walshb2e53ec2017-10-30 15:04:36 -0500694 # ffdc_list_file_path contains a list of any ffdc files created by plug-
695 # ins, etc. Read that data into a list.
Michael Walsh341c21e2017-01-17 16:25:20 -0600696 try:
Michael Walshb2e53ec2017-10-30 15:04:36 -0500697 plug_in_ffdc_list = \
698 open(ffdc_list_file_path, 'r').read().rstrip("\n").split("\n")
George Keishing36efbc02018-12-12 10:18:23 -0600699 plug_in_ffdc_list = list(filter(None, plug_in_ffdc_list))
Michael Walsh341c21e2017-01-17 16:25:20 -0600700 except IOError:
Michael Walshb2e53ec2017-10-30 15:04:36 -0500701 plug_in_ffdc_list = []
702
703 # Combine the files from plug_in_ffdc_list with the ffdc_file_list passed
704 # in. Eliminate duplicates and sort the list.
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -0500705 ffdc_file_list = sorted(set(ffdc_file_list + plug_in_ffdc_list))
Michael Walshb2e53ec2017-10-30 15:04:36 -0500706
707 if status_file_path != "":
708 ffdc_file_list.insert(0, status_file_path)
709
710 # Convert the list to a printable list.
711 printable_ffdc_file_list = "\n".join(ffdc_file_list)
Michael Walsh341c21e2017-01-17 16:25:20 -0600712
Michael Walsh68a61162017-04-25 11:54:06 -0500713 # Open ffdc_file_list for writing. We will write a complete list of
714 # FFDC files to it for possible use by plug-ins like cp_stop_check.
715 ffdc_list_file = open(ffdc_list_file_path, 'w')
Michael Walshb2e53ec2017-10-30 15:04:36 -0500716 ffdc_list_file.write(printable_ffdc_file_list + "\n")
717 ffdc_list_file.close()
718
719 indent = 0
720 width = 90
721 linefeed = 1
722 char = "="
Michael Walsh68a61162017-04-25 11:54:06 -0500723
724 gp.qprintn()
Michael Walshb2e53ec2017-10-30 15:04:36 -0500725 gp.qprint_dashes(indent, width, linefeed, char)
Michael Walsh68a61162017-04-25 11:54:06 -0500726 gp.qprintn("Copy this data to the defect:\n")
727
Michael Walshe0cf8d72017-05-17 13:20:46 -0500728 if len(more_header_info) > 0:
Michael Walshff340002017-08-29 11:18:27 -0500729 gp.qprintn(more_header_info)
Michael Walshdc80d672017-05-09 12:58:32 -0500730 gp.qpvars(host_name, host_ip, openbmc_nickname, openbmc_host,
731 openbmc_host_name, openbmc_ip, openbmc_username,
Michael Walsh0a3bdb42019-01-31 16:21:44 +0000732 openbmc_password, rest_username, rest_password, ipmi_username,
733 ipmi_password, os_host, os_host_name, os_ip, os_username,
Michael Walshdc80d672017-05-09 12:58:32 -0500734 os_password, pdu_host, pdu_host_name, pdu_ip, pdu_username,
735 pdu_password, pdu_slot_no, openbmc_serial_host,
736 openbmc_serial_host_name, openbmc_serial_ip, openbmc_serial_port)
Michael Walsh68a61162017-04-25 11:54:06 -0500737
738 gp.qprintn()
Michael Walsh986d8ae2019-07-17 10:02:23 -0500739 print_boot_history(boot_history)
Michael Walsh68a61162017-04-25 11:54:06 -0500740 gp.qprintn()
741 gp.qprint_var(state)
Michael Walshb5839d02017-04-12 16:11:20 -0500742 gp.qprintn()
743 gp.qprintn("FFDC data files:")
Michael Walshb2e53ec2017-10-30 15:04:36 -0500744 gp.qprintn(printable_ffdc_file_list)
Michael Walshb5839d02017-04-12 16:11:20 -0500745 gp.qprintn()
Michael Walsh341c21e2017-01-17 16:25:20 -0600746
Michael Walsh600876d2017-05-30 17:58:58 -0500747 if len(ffdc_summary_info) > 0:
Michael Walshff340002017-08-29 11:18:27 -0500748 gp.qprintn(ffdc_summary_info)
Michael Walsh600876d2017-05-30 17:58:58 -0500749
Michael Walshb2e53ec2017-10-30 15:04:36 -0500750 gp.qprint_dashes(indent, width, linefeed, char)
Michael Walsh68a61162017-04-25 11:54:06 -0500751
Michael Walsh6741f742017-02-20 16:16:38 -0600752
Michael Walsh6741f742017-02-20 16:16:38 -0600753def my_ffdc():
Michael Walsh6741f742017-02-20 16:16:38 -0600754 r"""
755 Collect FFDC data.
756 """
757
758 global state
759
760 plug_in_setup()
761 rc, shell_rc, failed_plug_in_name = grpi.rprocess_plug_in_packages(
Michael Walsh600876d2017-05-30 17:58:58 -0500762 call_point='ffdc', stop_on_plug_in_failure=0)
Michael Walsh6741f742017-02-20 16:16:38 -0600763
764 AUTOBOOT_FFDC_PREFIX = os.environ['AUTOBOOT_FFDC_PREFIX']
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -0500765 status, ffdc_file_list = grk.run_key_u("FFDC ffdc_prefix="
766 + AUTOBOOT_FFDC_PREFIX
767 + " ffdc_function_list="
768 + ffdc_function_list, ignore=1)
Michael Walsh83f4bc72017-04-20 16:49:43 -0500769 if status != 'PASS':
Michael Walshff340002017-08-29 11:18:27 -0500770 gp.qprint_error("Call to ffdc failed.\n")
Michael Walshc9bd2e82019-04-18 11:06:52 -0500771 if type(ffdc_file_list) is not list:
772 ffdc_file_list = []
773 # Leave a record for caller that "soft" errors occurred.
774 soft_errors = 1
775 gpu.save_plug_in_value(soft_errors, pgm_name)
Michael Walsh6741f742017-02-20 16:16:38 -0600776
777 my_get_state()
778
Michael Walshb2e53ec2017-10-30 15:04:36 -0500779 print_defect_report(ffdc_file_list)
Michael Walsh6741f742017-02-20 16:16:38 -0600780
Michael Walsh6741f742017-02-20 16:16:38 -0600781
Michael Walsh6741f742017-02-20 16:16:38 -0600782def print_test_start_message(boot_keyword):
Michael Walsh6741f742017-02-20 16:16:38 -0600783 r"""
784 Print a message indicating what boot test is about to run.
785
786 Description of arguments:
787 boot_keyword The name of the boot which is to be run
788 (e.g. "BMC Power On").
789 """
790
Michael Walsh986d8ae2019-07-17 10:02:23 -0500791 global boot_history
Sunil M325eb542017-08-10 07:09:43 -0500792 global boot_start_time
Michael Walsh6741f742017-02-20 16:16:38 -0600793
794 doing_msg = gp.sprint_timen("Doing \"" + boot_keyword + "\".")
Sunil M325eb542017-08-10 07:09:43 -0500795
796 # Set boot_start_time for use by plug-ins.
797 boot_start_time = doing_msg[1:33]
798 gp.qprint_var(boot_start_time)
799
Michael Walshb5839d02017-04-12 16:11:20 -0500800 gp.qprint(doing_msg)
Michael Walsh6741f742017-02-20 16:16:38 -0600801
Michael Walsh986d8ae2019-07-17 10:02:23 -0500802 update_boot_history(boot_history, doing_msg, max_boot_history)
Michael Walsh6741f742017-02-20 16:16:38 -0600803
Michael Walsh6741f742017-02-20 16:16:38 -0600804
Michael Walshf566fb12019-02-01 14:35:09 -0600805def stop_boot_test(signal_number=0,
806 frame=None):
807 r"""
808 Handle SIGUSR1 by aborting the boot test that is running.
809
810 Description of argument(s):
811 signal_number The signal number (should always be 10 for SIGUSR1).
812 frame The frame data.
813 """
814
Michael Walsh80dddde2019-10-22 13:54:38 -0500815 gp.qprintn()
816 gp.qprint_executing()
Michael Walshf566fb12019-02-01 14:35:09 -0600817 gp.lprint_executing()
818
819 # Restore original sigusr1 handler.
820 set_default_siguser1()
821
822 message = "The caller has asked that the boot test be stopped and marked"
823 message += " as a failure."
824
825 function_stack = gm.get_function_stack()
826 if "wait_state" in function_stack:
Michael Walshc44aa532019-06-14 13:33:29 -0500827 st.set_exit_wait_early_message(message)
Michael Walshf566fb12019-02-01 14:35:09 -0600828 else:
829 BuiltIn().fail(gp.sprint_error(message))
830
831
Michael Walsh6741f742017-02-20 16:16:38 -0600832def run_boot(boot):
Michael Walsh6741f742017-02-20 16:16:38 -0600833 r"""
834 Run the specified boot.
835
836 Description of arguments:
837 boot The name of the boot test to be performed.
838 """
839
840 global state
841
Michael Walshf566fb12019-02-01 14:35:09 -0600842 signal.signal(signal.SIGUSR1, stop_boot_test)
843 gp.qprint_timen("stop_boot_test is armed.")
844
Michael Walsh6741f742017-02-20 16:16:38 -0600845 print_test_start_message(boot)
846
847 plug_in_setup()
848 rc, shell_rc, failed_plug_in_name = \
849 grpi.rprocess_plug_in_packages(call_point="pre_boot")
850 if rc != 0:
851 error_message = "Plug-in failed with non-zero return code.\n" +\
Michael Walsh986d8ae2019-07-17 10:02:23 -0500852 gp.sprint_var(rc, fmt=gp.hexa())
Michael Walshf566fb12019-02-01 14:35:09 -0600853 set_default_siguser1()
Michael Walsh6741f742017-02-20 16:16:38 -0600854 BuiltIn().fail(gp.sprint_error(error_message))
855
856 if test_mode:
857 # In test mode, we'll pretend the boot worked by assigning its
858 # required end state to the default state value.
Michael Walsh30dadae2017-02-27 14:25:52 -0600859 state = st.strip_anchor_state(boot_table[boot]['end'])
Michael Walsh6741f742017-02-20 16:16:38 -0600860 else:
861 # Assertion: We trust that the state data was made fresh by the
862 # caller.
863
Michael Walshb5839d02017-04-12 16:11:20 -0500864 gp.qprintn()
Michael Walsh6741f742017-02-20 16:16:38 -0600865
866 if boot_table[boot]['method_type'] == "keyword":
Michael Walsh0b93fbf2017-03-02 14:42:41 -0600867 rk.my_run_keywords(boot_table[boot].get('lib_file_path', ''),
Michael Walshb5839d02017-04-12 16:11:20 -0500868 boot_table[boot]['method'],
869 quiet=quiet)
Michael Walsh6741f742017-02-20 16:16:38 -0600870
871 if boot_table[boot]['bmc_reboot']:
872 st.wait_for_comm_cycle(int(state['epoch_seconds']))
Michael Walsh30dadae2017-02-27 14:25:52 -0600873 plug_in_setup()
874 rc, shell_rc, failed_plug_in_name = \
875 grpi.rprocess_plug_in_packages(call_point="post_reboot")
876 if rc != 0:
Michael Walsh0b93fbf2017-03-02 14:42:41 -0600877 error_message = "Plug-in failed with non-zero return code.\n"
Michael Walsh986d8ae2019-07-17 10:02:23 -0500878 error_message += gp.sprint_var(rc, fmt=gp.hexa())
Michael Walshf566fb12019-02-01 14:35:09 -0600879 set_default_siguser1()
Michael Walsh30dadae2017-02-27 14:25:52 -0600880 BuiltIn().fail(gp.sprint_error(error_message))
Michael Walsh6741f742017-02-20 16:16:38 -0600881 else:
882 match_state = st.anchor_state(state)
883 del match_state['epoch_seconds']
884 # Wait for the state to change in any way.
885 st.wait_state(match_state, wait_time=state_change_timeout,
Michael Walsh600876d2017-05-30 17:58:58 -0500886 interval="10 seconds", invert=1)
Michael Walsh6741f742017-02-20 16:16:38 -0600887
Michael Walshb5839d02017-04-12 16:11:20 -0500888 gp.qprintn()
Michael Walsh6741f742017-02-20 16:16:38 -0600889 if boot_table[boot]['end']['chassis'] == "Off":
890 boot_timeout = power_off_timeout
891 else:
892 boot_timeout = power_on_timeout
893 st.wait_state(boot_table[boot]['end'], wait_time=boot_timeout,
Michael Walsh600876d2017-05-30 17:58:58 -0500894 interval="10 seconds")
Michael Walsh6741f742017-02-20 16:16:38 -0600895
896 plug_in_setup()
897 rc, shell_rc, failed_plug_in_name = \
898 grpi.rprocess_plug_in_packages(call_point="post_boot")
899 if rc != 0:
900 error_message = "Plug-in failed with non-zero return code.\n" +\
Michael Walsh986d8ae2019-07-17 10:02:23 -0500901 gp.sprint_var(rc, fmt=gp.hexa())
Michael Walshf566fb12019-02-01 14:35:09 -0600902 set_default_siguser1()
Michael Walsh6741f742017-02-20 16:16:38 -0600903 BuiltIn().fail(gp.sprint_error(error_message))
904
Michael Walshf566fb12019-02-01 14:35:09 -0600905 # Restore original sigusr1 handler.
906 set_default_siguser1()
907
Michael Walsh6741f742017-02-20 16:16:38 -0600908
Michael Walsh6741f742017-02-20 16:16:38 -0600909def test_loop_body():
Michael Walsh6741f742017-02-20 16:16:38 -0600910 r"""
911 The main loop body for the loop in main_py.
912
913 Description of arguments:
914 boot_count The iteration number (starts at 1).
915 """
916
917 global boot_count
918 global state
919 global next_boot
920 global boot_success
Sunil M325eb542017-08-10 07:09:43 -0500921 global boot_end_time
Michael Walsh6741f742017-02-20 16:16:38 -0600922
Michael Walshb5839d02017-04-12 16:11:20 -0500923 gp.qprintn()
Michael Walsh6741f742017-02-20 16:16:38 -0600924
925 next_boot = select_boot()
Michael Walshb5839d02017-04-12 16:11:20 -0500926 if next_boot == "":
927 return True
Michael Walsh6741f742017-02-20 16:16:38 -0600928
Michael Walshb5839d02017-04-12 16:11:20 -0500929 boot_count += 1
930 gp.qprint_timen("Starting boot " + str(boot_count) + ".")
Michael Walsh6741f742017-02-20 16:16:38 -0600931
Michael Walshe0cf8d72017-05-17 13:20:46 -0500932 pre_boot_plug_in_setup()
Michael Walsh6741f742017-02-20 16:16:38 -0600933
934 cmd_buf = ["run_boot", next_boot]
935 boot_status, msg = BuiltIn().run_keyword_and_ignore_error(*cmd_buf)
936 if boot_status == "FAIL":
Michael Walshb5839d02017-04-12 16:11:20 -0500937 gp.qprint(msg)
Michael Walsh6741f742017-02-20 16:16:38 -0600938
Michael Walshb5839d02017-04-12 16:11:20 -0500939 gp.qprintn()
Michael Walsh6741f742017-02-20 16:16:38 -0600940 if boot_status == "PASS":
941 boot_success = 1
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -0500942 completion_msg = gp.sprint_timen("BOOT_SUCCESS: \"" + next_boot
943 + "\" succeeded.")
Michael Walsh6741f742017-02-20 16:16:38 -0600944 else:
945 boot_success = 0
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -0500946 completion_msg = gp.sprint_timen("BOOT_FAILED: \"" + next_boot
947 + "\" failed.")
Sunil M325eb542017-08-10 07:09:43 -0500948
949 # Set boot_end_time for use by plug-ins.
950 boot_end_time = completion_msg[1:33]
951 gp.qprint_var(boot_end_time)
952
953 gp.qprint(completion_msg)
Michael Walsh6741f742017-02-20 16:16:38 -0600954
955 boot_results.update(next_boot, boot_status)
956
957 plug_in_setup()
958 # NOTE: A post_test_case call point failure is NOT counted as a boot
959 # failure.
960 rc, shell_rc, failed_plug_in_name = grpi.rprocess_plug_in_packages(
Michael Walsh600876d2017-05-30 17:58:58 -0500961 call_point='post_test_case', stop_on_plug_in_failure=0)
Michael Walsh6741f742017-02-20 16:16:38 -0600962
963 plug_in_setup()
964 rc, shell_rc, failed_plug_in_name = grpi.rprocess_plug_in_packages(
Michael Walsh89de14a2018-10-01 16:51:37 -0500965 call_point='ffdc_check', shell_rc=dump_ffdc_rc(),
Michael Walsh6741f742017-02-20 16:16:38 -0600966 stop_on_plug_in_failure=1, stop_on_non_zero_rc=1)
Michael Walsh12059e22019-03-21 11:03:45 -0500967 if ffdc_check == "All" or\
Michael Walsh89de14a2018-10-01 16:51:37 -0500968 shell_rc == dump_ffdc_rc():
Michael Walsh83f4bc72017-04-20 16:49:43 -0500969 status, ret_values = grk.run_key_u("my_ffdc", ignore=1)
970 if status != 'PASS':
Michael Walshff340002017-08-29 11:18:27 -0500971 gp.qprint_error("Call to my_ffdc failed.\n")
Michael Walshc9bd2e82019-04-18 11:06:52 -0500972 # Leave a record for caller that "soft" errors occurred.
973 soft_errors = 1
974 gpu.save_plug_in_value(soft_errors, pgm_name)
Michael Walsh6741f742017-02-20 16:16:38 -0600975
Michael Walshaabef1e2017-09-20 15:16:17 -0500976 if delete_errlogs:
Michael Shepos1a67b082020-08-28 16:01:58 -0500977 # print error logs before delete
978 status, error_logs = grk.run_key_u("Get Error Logs")
979 pels = pel.peltool("-l", ignore_err=1)
Michael Shepos0e5f1132020-09-30 16:24:25 -0500980 log.print_error_logs(error_logs, "AdditionalData Message Severity")
981 gp.qprint_var(pels)
Michael Shepos1a67b082020-08-28 16:01:58 -0500982
Michael Walshaabef1e2017-09-20 15:16:17 -0500983 # We need to purge error logs between boots or they build up.
Michael Walsh409ad352020-02-06 11:46:35 -0600984 grk.run_key(delete_errlogs_cmd, ignore=1)
Michael Shepos92a54bf2020-11-11 11:48:55 -0600985 grk.run_key(delete_bmcdump_cmd, ignore=1)
Michael Walshd139f282017-04-04 18:00:23 -0500986
Michael Walsh952f9b02017-03-09 13:11:14 -0600987 boot_results.print_report()
Michael Walshb5839d02017-04-12 16:11:20 -0500988 gp.qprint_timen("Finished boot " + str(boot_count) + ".")
Michael Walsh952f9b02017-03-09 13:11:14 -0600989
Michael Walsh6741f742017-02-20 16:16:38 -0600990 plug_in_setup()
991 rc, shell_rc, failed_plug_in_name = grpi.rprocess_plug_in_packages(
Michael Walsh89de14a2018-10-01 16:51:37 -0500992 call_point='stop_check', shell_rc=stop_test_rc(),
993 stop_on_non_zero_rc=1)
994 if shell_rc == stop_test_rc():
Michael Walsh3ba8ecd2018-04-24 11:33:25 -0500995 message = "Stopping as requested by user.\n"
Michael Walsh80dddde2019-10-22 13:54:38 -0500996 gp.qprint_time(message)
Michael Walsh3ba8ecd2018-04-24 11:33:25 -0500997 BuiltIn().fail(message)
Michael Walsh6741f742017-02-20 16:16:38 -0600998
Michael Walshd139f282017-04-04 18:00:23 -0500999 # This should help prevent ConnectionErrors.
George Keishing4d65c862020-12-03 06:52:11 -06001000 # Purge all redfish and REST connection sessions.
George Keishingd86e45c2021-03-19 07:38:14 -05001001 if redfish_delete_sessions:
1002 grk.run_key_u("Close All Connections", ignore=1)
1003 grk.run_key_u("Delete All Redfish Sessions", ignore=1)
Michael Walshd139f282017-04-04 18:00:23 -05001004
Michael Walsh6741f742017-02-20 16:16:38 -06001005 return True
1006
Michael Walsh6741f742017-02-20 16:16:38 -06001007
Michael Walsh83f4bc72017-04-20 16:49:43 -05001008def obmc_boot_test_teardown():
Michael Walsh6741f742017-02-20 16:16:38 -06001009 r"""
Michael Walshf75d4352019-12-05 17:01:20 -06001010 Clean up after the main keyword.
Michael Walsh6741f742017-02-20 16:16:38 -06001011 """
Michael Walshf75d4352019-12-05 17:01:20 -06001012 gp.qprint_executing()
1013
1014 if ga.psutil_imported:
1015 ga.terminate_descendants()
Michael Walsh6741f742017-02-20 16:16:38 -06001016
1017 if cp_setup_called:
1018 plug_in_setup()
1019 rc, shell_rc, failed_plug_in_name = grpi.rprocess_plug_in_packages(
Michael Walsh600876d2017-05-30 17:58:58 -05001020 call_point='cleanup', stop_on_plug_in_failure=0)
Michael Walsh6741f742017-02-20 16:16:38 -06001021
Michael Walsh600876d2017-05-30 17:58:58 -05001022 if 'boot_results_file_path' in globals():
Michael Walsh986d8ae2019-07-17 10:02:23 -05001023 # Save boot_results and boot_history objects to a file in case they are
Michael Walsh6c645742018-08-17 15:02:17 -05001024 # needed again.
Michael Walsh600876d2017-05-30 17:58:58 -05001025 gp.qprint_timen("Saving boot_results to the following path.")
1026 gp.qprint_var(boot_results_file_path)
Michael Walsh986d8ae2019-07-17 10:02:23 -05001027 pickle.dump((boot_results, boot_history),
Michael Walsh6c645742018-08-17 15:02:17 -05001028 open(boot_results_file_path, 'wb'),
Michael Walsh600876d2017-05-30 17:58:58 -05001029 pickle.HIGHEST_PROTOCOL)
Michael Walsh0b93fbf2017-03-02 14:42:41 -06001030
Michael Walshff340002017-08-29 11:18:27 -05001031 global save_stack
1032 # Restore any global values saved on the save_stack.
1033 for parm_name in main_func_parm_list:
1034 # Get the parm_value if it was saved on the stack.
1035 try:
1036 parm_value = save_stack.pop(parm_name)
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -05001037 except BaseException:
Michael Walshff340002017-08-29 11:18:27 -05001038 # If it was not saved, no further action is required.
1039 continue
1040
1041 # Restore the saved value.
1042 cmd_buf = "BuiltIn().set_global_variable(\"${" + parm_name +\
1043 "}\", parm_value)"
1044 gp.dpissuing(cmd_buf)
1045 exec(cmd_buf)
1046
1047 gp.dprintn(save_stack.sprint_obj())
1048
Michael Walsh6741f742017-02-20 16:16:38 -06001049
Michael Walshc9116812017-03-10 14:23:06 -06001050def test_teardown():
Michael Walshc9116812017-03-10 14:23:06 -06001051 r"""
1052 Clean up after this test case.
1053 """
1054
1055 gp.qprintn()
Michael Walshf75d4352019-12-05 17:01:20 -06001056 gp.qprint_executing()
1057
1058 if ga.psutil_imported:
1059 ga.terminate_descendants()
1060
Michael Walshc9116812017-03-10 14:23:06 -06001061 cmd_buf = ["Print Error",
1062 "A keyword timeout occurred ending this program.\n"]
1063 BuiltIn().run_keyword_if_timeout_occurred(*cmd_buf)
1064
George Keishinga54e06f2020-06-12 10:42:41 -05001065 if redfish_supported:
1066 redfish.logout()
1067
Michael Walshc108e422019-03-28 12:27:18 -05001068 gp.qprint_pgm_footer()
Michael Walshb5839d02017-04-12 16:11:20 -05001069
Michael Walshc9116812017-03-10 14:23:06 -06001070
Michael Walsh89de14a2018-10-01 16:51:37 -05001071def post_stack():
1072 r"""
1073 Process post_stack plug-in programs.
1074 """
1075
1076 if not call_post_stack_plug:
1077 # The caller does not wish to have post_stack plug-in processing done.
1078 return
1079
1080 global boot_success
1081
1082 # NOTE: A post_stack call-point failure is NOT counted as a boot failure.
1083 pre_boot_plug_in_setup()
1084 # For the purposes of the following plug-ins, mark the "boot" as a success.
1085 boot_success = 1
1086 plug_in_setup()
Michael Walsh815b1d52018-10-30 13:32:26 -05001087 rc, shell_rc, failed_plug_in_name, history =\
1088 grpi.rprocess_plug_in_packages(call_point='post_stack',
1089 stop_on_plug_in_failure=0,
1090 return_history=True)
Michael Walsh986d8ae2019-07-17 10:02:23 -05001091 for doing_msg in history:
1092 update_boot_history(boot_history, doing_msg, max_boot_history)
Michael Walsh815b1d52018-10-30 13:32:26 -05001093 if rc != 0:
1094 boot_success = 0
Michael Walsh89de14a2018-10-01 16:51:37 -05001095
1096 plug_in_setup()
Michael Walsh815b1d52018-10-30 13:32:26 -05001097 rc, shell_rc, failed_plug_in_name =\
1098 grpi.rprocess_plug_in_packages(call_point='ffdc_check',
1099 shell_rc=dump_ffdc_rc(),
1100 stop_on_plug_in_failure=1,
1101 stop_on_non_zero_rc=1)
1102 if shell_rc == dump_ffdc_rc():
Michael Walsh89de14a2018-10-01 16:51:37 -05001103 status, ret_values = grk.run_key_u("my_ffdc", ignore=1)
1104 if status != 'PASS':
1105 gp.qprint_error("Call to my_ffdc failed.\n")
Michael Walshc9bd2e82019-04-18 11:06:52 -05001106 # Leave a record for caller that "soft" errors occurred.
1107 soft_errors = 1
1108 gpu.save_plug_in_value(soft_errors, pgm_name)
Michael Walsh89de14a2018-10-01 16:51:37 -05001109
1110 plug_in_setup()
1111 rc, shell_rc, failed_plug_in_name = grpi.rprocess_plug_in_packages(
1112 call_point='stop_check', shell_rc=stop_test_rc(),
1113 stop_on_non_zero_rc=1)
1114 if shell_rc == stop_test_rc():
1115 message = "Stopping as requested by user.\n"
Michael Walsh80dddde2019-10-22 13:54:38 -05001116 gp.qprint_time(message)
Michael Walsh89de14a2018-10-01 16:51:37 -05001117 BuiltIn().fail(message)
1118
1119
Michael Walshff340002017-08-29 11:18:27 -05001120def obmc_boot_test_py(loc_boot_stack=None,
1121 loc_stack_mode=None,
1122 loc_quiet=None):
Michael Walsh6741f742017-02-20 16:16:38 -06001123 r"""
1124 Do main program processing.
1125 """
1126
Michael Walshff340002017-08-29 11:18:27 -05001127 global save_stack
1128
Michael Walshf75d4352019-12-05 17:01:20 -06001129 ga.set_term_options(term_requests={'pgm_names': ['process_plug_in_packages.py']})
1130
George Keishing36efbc02018-12-12 10:18:23 -06001131 gp.dprintn()
Michael Walshff340002017-08-29 11:18:27 -05001132 # Process function parms.
1133 for parm_name in main_func_parm_list:
1134 # Get parm's value.
George Keishing36efbc02018-12-12 10:18:23 -06001135 parm_value = eval("loc_" + parm_name)
1136 gp.dpvars(parm_name, parm_value)
Michael Walshff340002017-08-29 11:18:27 -05001137
George Keishing36efbc02018-12-12 10:18:23 -06001138 if parm_value is not None:
Michael Walshff340002017-08-29 11:18:27 -05001139 # Save the global value on a stack.
1140 cmd_buf = "save_stack.push(BuiltIn().get_variable_value(\"${" +\
1141 parm_name + "}\"), \"" + parm_name + "\")"
1142 gp.dpissuing(cmd_buf)
1143 exec(cmd_buf)
1144
1145 # Set the global value to the passed value.
1146 cmd_buf = "BuiltIn().set_global_variable(\"${" + parm_name +\
1147 "}\", loc_" + parm_name + ")"
1148 gp.dpissuing(cmd_buf)
1149 exec(cmd_buf)
1150
1151 gp.dprintn(save_stack.sprint_obj())
Michael Walshb5839d02017-04-12 16:11:20 -05001152
Michael Walsh6741f742017-02-20 16:16:38 -06001153 setup()
1154
Michael Walshcd9fbfd2017-09-19 12:00:08 -05001155 init_boot_pass, init_boot_fail = boot_results.return_total_pass_fail()
1156
Michael Walsha20da402017-03-31 16:27:45 -05001157 if ffdc_only:
1158 gp.qprint_timen("Caller requested ffdc_only.")
Michael Walsh986d8ae2019-07-17 10:02:23 -05001159 if do_pre_boot_plug_in_setup:
1160 pre_boot_plug_in_setup()
Michael Walsh83f4bc72017-04-20 16:49:43 -05001161 grk.run_key_u("my_ffdc")
Michael Walsh764d2f82017-04-27 16:01:08 -05001162 return
Michael Walsha20da402017-03-31 16:27:45 -05001163
Michael Walsh409ad352020-02-06 11:46:35 -06001164 if delete_errlogs:
Michael Shepos1a67b082020-08-28 16:01:58 -05001165 # print error logs before delete
1166 status, error_logs = grk.run_key_u("Get Error Logs")
1167 pels = pel.peltool("-l", ignore_err=1)
Michael Shepos0e5f1132020-09-30 16:24:25 -05001168 log.print_error_logs(error_logs, "AdditionalData Message Severity")
1169 gp.qprint_var(pels)
Michael Shepos1a67b082020-08-28 16:01:58 -05001170
Michael Walsh409ad352020-02-06 11:46:35 -06001171 # Delete errlogs prior to doing any boot tests.
1172 grk.run_key(delete_errlogs_cmd, ignore=1)
Michael Shepos92a54bf2020-11-11 11:48:55 -06001173 grk.run_key(delete_bmcdump_cmd, ignore=1)
Michael Walsh409ad352020-02-06 11:46:35 -06001174
Michael Walsh6741f742017-02-20 16:16:38 -06001175 # Process caller's boot_stack.
1176 while (len(boot_stack) > 0):
1177 test_loop_body()
1178
Michael Walshb5839d02017-04-12 16:11:20 -05001179 gp.qprint_timen("Finished processing stack.")
Michael Walsh30dadae2017-02-27 14:25:52 -06001180
Michael Walsh89de14a2018-10-01 16:51:37 -05001181 post_stack()
1182
Michael Walsh6741f742017-02-20 16:16:38 -06001183 # Process caller's boot_list.
1184 if len(boot_list) > 0:
1185 for ix in range(1, max_num_tests + 1):
1186 test_loop_body()
1187
Michael Walshb5839d02017-04-12 16:11:20 -05001188 gp.qprint_timen("Completed all requested boot tests.")
1189
1190 boot_pass, boot_fail = boot_results.return_total_pass_fail()
Michael Walshcd9fbfd2017-09-19 12:00:08 -05001191 new_fail = boot_fail - init_boot_fail
1192 if new_fail > boot_fail_threshold:
Michael Walshb5839d02017-04-12 16:11:20 -05001193 error_message = "Boot failures exceed the boot failure" +\
1194 " threshold:\n" +\
Michael Walshcd9fbfd2017-09-19 12:00:08 -05001195 gp.sprint_var(new_fail) +\
Michael Walshb5839d02017-04-12 16:11:20 -05001196 gp.sprint_var(boot_fail_threshold)
1197 BuiltIn().fail(gp.sprint_error(error_message))