blob: c31b0530ec694e9894567c246baedc6a8cdb1dcf [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 Walsh0bbd8602016-11-22 11:31:49 -060034
Michael Walsh0b93fbf2017-03-02 14:42:41 -060035base_path = os.path.dirname(os.path.dirname(
36 imp.find_module("gen_robot_print")[1])) +\
Michael Walshc9116812017-03-10 14:23:06 -060037 os.sep
Michael Walsh0b93fbf2017-03-02 14:42:41 -060038sys.path.append(base_path + "extended/")
39import run_keyword as rk
Michael Walsh0bbd8602016-11-22 11:31:49 -060040
Michael Walshe1e26442017-03-06 17:50:07 -060041# Setting master_pid correctly influences the behavior of plug-ins like
42# DB_Logging
43program_pid = os.getpid()
44master_pid = os.environ.get('AUTOBOOT_MASTER_PID', program_pid)
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -050045pgm_name = re.sub('\\.py$', '', os.path.basename(__file__))
Michael Walshe1e26442017-03-06 17:50:07 -060046
Michael Walshb5839d02017-04-12 16:11:20 -050047# Set up boot data structures.
Michael Walsh986d8ae2019-07-17 10:02:23 -050048os_host = BuiltIn().get_variable_value("${OS_HOST}", default="")
49boot_table = create_boot_table(os_host=os_host)
Michael Walshb5839d02017-04-12 16:11:20 -050050valid_boot_types = create_valid_boot_list(boot_table)
Michael Walsh0b93fbf2017-03-02 14:42:41 -060051
Michael Walsh6741f742017-02-20 16:16:38 -060052boot_lists = read_boot_lists()
Michael Walsh986d8ae2019-07-17 10:02:23 -050053
54# The maximum number of entries that can be in the boot_history global variable.
Michael Walsh815b1d52018-10-30 13:32:26 -050055max_boot_history = 10
Michael Walsh986d8ae2019-07-17 10:02:23 -050056boot_history = []
Michael Walsh6741f742017-02-20 16:16:38 -060057
Michael Walsh7dc885b2018-03-14 17:51:59 -050058state = st.return_state_constant('default_state')
Michael Walsh6741f742017-02-20 16:16:38 -060059cp_setup_called = 0
60next_boot = ""
61base_tool_dir_path = os.path.normpath(os.environ.get(
62 'AUTOBOOT_BASE_TOOL_DIR_PATH', "/tmp")) + os.sep
Michael Walshb5839d02017-04-12 16:11:20 -050063
Michael Walsh6741f742017-02-20 16:16:38 -060064ffdc_dir_path = os.path.normpath(os.environ.get('FFDC_DIR_PATH', '')) + os.sep
Michael Walsh6741f742017-02-20 16:16:38 -060065boot_success = 0
Michael Walsh6741f742017-02-20 16:16:38 -060066status_dir_path = os.environ.get('STATUS_DIR_PATH', "")
67if status_dir_path != "":
68 status_dir_path = os.path.normpath(status_dir_path) + os.sep
Michael Walshe58df1c2019-08-07 09:57:43 -050069redfish_supported = BuiltIn().get_variable_value("${REDFISH_SUPPORTED}", default=False)
70if redfish_supported:
71 default_power_on = "Redfish Power On"
72 default_power_off = "Redfish Power Off"
73else:
74 default_power_on = "REST Power On"
75 default_power_off = "REST Power Off"
Michael Walsh6741f742017-02-20 16:16:38 -060076boot_count = 0
Michael Walsh0bbd8602016-11-22 11:31:49 -060077
Michael Walsh85678942017-03-27 14:34:22 -050078LOG_LEVEL = BuiltIn().get_variable_value("${LOG_LEVEL}")
Michael Walsh986d8ae2019-07-17 10:02:23 -050079AUTOBOOT_FFDC_PREFIX = os.environ.get('AUTOBOOT_FFDC_PREFIX', '')
80ffdc_prefix = AUTOBOOT_FFDC_PREFIX
Sunil M325eb542017-08-10 07:09:43 -050081boot_start_time = ""
82boot_end_time = ""
Michael Walshff340002017-08-29 11:18:27 -050083save_stack = vs.var_stack('save_stack')
84main_func_parm_list = ['boot_stack', 'stack_mode', 'quiet']
Michael Walsh85678942017-03-27 14:34:22 -050085
86
Michael Walsh89de14a2018-10-01 16:51:37 -050087def dump_ffdc_rc():
88 r"""
89 Return the constant dump ffdc test return code value.
90
91 When a plug-in call point program returns this value, it indicates that
92 this program should collect FFDC.
93 """
94
95 return 0x00000200
96
97
98def stop_test_rc():
99 r"""
100 Return the constant stop test return code value.
101
102 When a plug-in call point program returns this value, it indicates that
103 this program should stop running.
104 """
105
106 return 0x00000200
107
108
Michael Walsh0ad0f7f2017-05-04 14:39:58 -0500109def process_host(host,
110 host_var_name=""):
Michael Walsh0ad0f7f2017-05-04 14:39:58 -0500111 r"""
112 Process a host by getting the associated host name and IP address and
113 setting them in global variables.
114
115 If the caller does not pass the host_var_name, this function will try to
116 figure out the name of the variable used by the caller for the host parm.
117 Callers are advised to explicitly specify the host_var_name when calling
118 with an exec command. In such cases, the get_arg_name cannot figure out
119 the host variable name.
120
121 This function will then create similar global variable names by
122 removing "_host" and appending "_host_name" or "_ip" to the host variable
123 name.
124
125 Example:
126
127 If a call is made like this:
128 process_host(openbmc_host)
129
130 Global variables openbmc_host_name and openbmc_ip will be set.
131
132 Description of argument(s):
133 host A host name or IP. The name of the variable used should
134 have a suffix of "_host".
135 host_var_name The name of the variable being used as the host parm.
136 """
137
138 if host_var_name == "":
139 host_var_name = gp.get_arg_name(0, 1, stack_frame_ix=2)
140
141 host_name_var_name = re.sub("host", "host_name", host_var_name)
142 ip_var_name = re.sub("host", "ip", host_var_name)
143 cmd_buf = "global " + host_name_var_name + ", " + ip_var_name + " ; " +\
144 host_name_var_name + ", " + ip_var_name + " = gm.get_host_name_ip('" +\
145 host + "')"
146 exec(cmd_buf)
147
Michael Walsh0ad0f7f2017-05-04 14:39:58 -0500148
Michael Walshb5839d02017-04-12 16:11:20 -0500149def process_pgm_parms():
Michael Walshb5839d02017-04-12 16:11:20 -0500150 r"""
151 Process the program parameters by assigning them all to corresponding
152 globals. Also, set some global values that depend on program parameters.
153 """
154
155 # Program parameter processing.
156 # Assign all program parms to python variables which are global to this
157 # module.
158
159 global parm_list
160 parm_list = BuiltIn().get_variable_value("${parm_list}")
161 # The following subset of parms should be processed as integers.
162 int_list = ['max_num_tests', 'boot_pass', 'boot_fail', 'ffdc_only',
Michael Walsh89de14a2018-10-01 16:51:37 -0500163 'boot_fail_threshold', 'delete_errlogs',
Michael Walsh986d8ae2019-07-17 10:02:23 -0500164 'call_post_stack_plug', 'do_pre_boot_plug_in_setup', 'quiet',
165 'test_mode', 'debug']
Michael Walshb5839d02017-04-12 16:11:20 -0500166 for parm in parm_list:
167 if parm in int_list:
168 sub_cmd = "int(BuiltIn().get_variable_value(\"${" + parm +\
169 "}\", \"0\"))"
170 else:
171 sub_cmd = "BuiltIn().get_variable_value(\"${" + parm + "}\")"
172 cmd_buf = "global " + parm + " ; " + parm + " = " + sub_cmd
Michael Walshff340002017-08-29 11:18:27 -0500173 gp.dpissuing(cmd_buf)
Michael Walshb5839d02017-04-12 16:11:20 -0500174 exec(cmd_buf)
Michael Walsh0ad0f7f2017-05-04 14:39:58 -0500175 if re.match(r".*_host$", parm):
176 cmd_buf = "process_host(" + parm + ", '" + parm + "')"
177 exec(cmd_buf)
178 if re.match(r".*_password$", parm):
179 # Register the value of any parm whose name ends in _password.
180 # This will cause the print functions to replace passwords with
181 # asterisks in the output.
182 cmd_buf = "gp.register_passwords(" + parm + ")"
183 exec(cmd_buf)
Michael Walshb5839d02017-04-12 16:11:20 -0500184
185 global ffdc_dir_path_style
186 global boot_list
187 global boot_stack
188 global boot_results_file_path
189 global boot_results
Michael Walsh986d8ae2019-07-17 10:02:23 -0500190 global boot_history
Michael Walshb5839d02017-04-12 16:11:20 -0500191 global ffdc_list_file_path
Michael Walshe0cf8d72017-05-17 13:20:46 -0500192 global ffdc_report_list_path
Michael Walsh600876d2017-05-30 17:58:58 -0500193 global ffdc_summary_list_path
Michael Walshb5839d02017-04-12 16:11:20 -0500194
195 if ffdc_dir_path_style == "":
196 ffdc_dir_path_style = int(os.environ.get('FFDC_DIR_PATH_STYLE', '0'))
197
198 # Convert these program parms to lists for easier processing..
George Keishing36efbc02018-12-12 10:18:23 -0600199 boot_list = list(filter(None, boot_list.split(":")))
200 boot_stack = list(filter(None, boot_stack.split(":")))
Michael Walshb5839d02017-04-12 16:11:20 -0500201
Michael Walsh903e0b22017-09-19 17:00:33 -0500202 cleanup_boot_results_file()
203 boot_results_file_path = create_boot_results_file_path(pgm_name,
204 openbmc_nickname,
205 master_pid)
Michael Walshb5839d02017-04-12 16:11:20 -0500206
207 if os.path.isfile(boot_results_file_path):
208 # We've been called before in this run so we'll load the saved
Michael Walsh986d8ae2019-07-17 10:02:23 -0500209 # boot_results and boot_history objects.
210 boot_results, boot_history =\
Michael Walsh6c645742018-08-17 15:02:17 -0500211 pickle.load(open(boot_results_file_path, 'rb'))
Michael Walshb5839d02017-04-12 16:11:20 -0500212 else:
213 boot_results = boot_results(boot_table, boot_pass, boot_fail)
214
215 ffdc_list_file_path = base_tool_dir_path + openbmc_nickname +\
216 "/FFDC_FILE_LIST"
Michael Walshe0cf8d72017-05-17 13:20:46 -0500217 ffdc_report_list_path = base_tool_dir_path + openbmc_nickname +\
218 "/FFDC_REPORT_FILE_LIST"
Michael Walshb5839d02017-04-12 16:11:20 -0500219
Michael Walsh600876d2017-05-30 17:58:58 -0500220 ffdc_summary_list_path = base_tool_dir_path + openbmc_nickname +\
221 "/FFDC_SUMMARY_FILE_LIST"
222
Michael Walshb5839d02017-04-12 16:11:20 -0500223
Michael Walsh85678942017-03-27 14:34:22 -0500224def initial_plug_in_setup():
Michael Walsh85678942017-03-27 14:34:22 -0500225 r"""
226 Initialize all plug-in environment variables which do not change for the
227 duration of the program.
228
229 """
230
231 global LOG_LEVEL
232 BuiltIn().set_log_level("NONE")
233
234 BuiltIn().set_global_variable("${master_pid}", master_pid)
235 BuiltIn().set_global_variable("${FFDC_DIR_PATH}", ffdc_dir_path)
236 BuiltIn().set_global_variable("${STATUS_DIR_PATH}", status_dir_path)
237 BuiltIn().set_global_variable("${BASE_TOOL_DIR_PATH}", base_tool_dir_path)
238 BuiltIn().set_global_variable("${FFDC_LIST_FILE_PATH}",
239 ffdc_list_file_path)
Michael Walshe0cf8d72017-05-17 13:20:46 -0500240 BuiltIn().set_global_variable("${FFDC_REPORT_LIST_PATH}",
241 ffdc_report_list_path)
Michael Walsh600876d2017-05-30 17:58:58 -0500242 BuiltIn().set_global_variable("${FFDC_SUMMARY_LIST_PATH}",
243 ffdc_summary_list_path)
Michael Walsh85678942017-03-27 14:34:22 -0500244
245 BuiltIn().set_global_variable("${FFDC_DIR_PATH_STYLE}",
246 ffdc_dir_path_style)
247 BuiltIn().set_global_variable("${FFDC_CHECK}",
248 ffdc_check)
249
250 # For each program parameter, set the corresponding AUTOBOOT_ environment
251 # variable value. Also, set an AUTOBOOT_ environment variable for every
252 # element in additional_values.
253 additional_values = ["program_pid", "master_pid", "ffdc_dir_path",
254 "status_dir_path", "base_tool_dir_path",
Michael Walsh600876d2017-05-30 17:58:58 -0500255 "ffdc_list_file_path", "ffdc_report_list_path",
Michael Walsh0a3bdb42019-01-31 16:21:44 +0000256 "ffdc_summary_list_path", "execdir"]
Michael Walsh85678942017-03-27 14:34:22 -0500257
258 plug_in_vars = parm_list + additional_values
259
260 for var_name in plug_in_vars:
261 var_value = BuiltIn().get_variable_value("${" + var_name + "}")
262 var_name = var_name.upper()
263 if var_value is None:
264 var_value = ""
265 os.environ["AUTOBOOT_" + var_name] = str(var_value)
266
267 BuiltIn().set_log_level(LOG_LEVEL)
268
Michael Walsh68a61162017-04-25 11:54:06 -0500269 # Make sure the ffdc list directory exists.
270 ffdc_list_dir_path = os.path.dirname(ffdc_list_file_path) + os.sep
271 if not os.path.exists(ffdc_list_dir_path):
272 os.makedirs(ffdc_list_dir_path)
Michael Walsh85678942017-03-27 14:34:22 -0500273
Michael Walsh85678942017-03-27 14:34:22 -0500274
Michael Walsh0bbd8602016-11-22 11:31:49 -0600275def plug_in_setup():
Michael Walsh0bbd8602016-11-22 11:31:49 -0600276 r"""
Michael Walsh85678942017-03-27 14:34:22 -0500277 Initialize all changing plug-in environment variables for use by the
278 plug-in programs.
Michael Walsh0bbd8602016-11-22 11:31:49 -0600279 """
280
Michael Walsh85678942017-03-27 14:34:22 -0500281 global LOG_LEVEL
282 global test_really_running
283
284 BuiltIn().set_log_level("NONE")
285
Michael Walsh6741f742017-02-20 16:16:38 -0600286 boot_pass, boot_fail = boot_results.return_total_pass_fail()
Michael Walsh0bbd8602016-11-22 11:31:49 -0600287 if boot_pass > 1:
288 test_really_running = 1
289 else:
290 test_really_running = 0
291
Michael Walsh6741f742017-02-20 16:16:38 -0600292 BuiltIn().set_global_variable("${test_really_running}",
293 test_really_running)
294 BuiltIn().set_global_variable("${boot_type_desc}", next_boot)
Michael Walsh6741f742017-02-20 16:16:38 -0600295 BuiltIn().set_global_variable("${boot_pass}", boot_pass)
296 BuiltIn().set_global_variable("${boot_fail}", boot_fail)
297 BuiltIn().set_global_variable("${boot_success}", boot_success)
298 BuiltIn().set_global_variable("${ffdc_prefix}", ffdc_prefix)
Sunil M325eb542017-08-10 07:09:43 -0500299 BuiltIn().set_global_variable("${boot_start_time}", boot_start_time)
300 BuiltIn().set_global_variable("${boot_end_time}", boot_end_time)
Michael Walsh4c9a6452016-12-13 16:03:11 -0600301
Michael Walsh0bbd8602016-11-22 11:31:49 -0600302 # For each program parameter, set the corresponding AUTOBOOT_ environment
303 # variable value. Also, set an AUTOBOOT_ environment variable for every
304 # element in additional_values.
305 additional_values = ["boot_type_desc", "boot_success", "boot_pass",
Sunil M325eb542017-08-10 07:09:43 -0500306 "boot_fail", "test_really_running", "ffdc_prefix",
307 "boot_start_time", "boot_end_time"]
Michael Walsh0bbd8602016-11-22 11:31:49 -0600308
Michael Walsh85678942017-03-27 14:34:22 -0500309 plug_in_vars = additional_values
Michael Walsh0bbd8602016-11-22 11:31:49 -0600310
311 for var_name in plug_in_vars:
312 var_value = BuiltIn().get_variable_value("${" + var_name + "}")
313 var_name = var_name.upper()
314 if var_value is None:
315 var_value = ""
Michael Walsh6741f742017-02-20 16:16:38 -0600316 os.environ["AUTOBOOT_" + var_name] = str(var_value)
Michael Walsh0bbd8602016-11-22 11:31:49 -0600317
Michael Walsh0bbd8602016-11-22 11:31:49 -0600318 if debug:
Michael Walsh6741f742017-02-20 16:16:38 -0600319 shell_rc, out_buf = \
320 gc.cmd_fnc_u("printenv | egrep AUTOBOOT_ | sort -u")
Michael Walsh0bbd8602016-11-22 11:31:49 -0600321
Michael Walsh85678942017-03-27 14:34:22 -0500322 BuiltIn().set_log_level(LOG_LEVEL)
323
Michael Walsh0bbd8602016-11-22 11:31:49 -0600324
Michael Walshe0cf8d72017-05-17 13:20:46 -0500325def pre_boot_plug_in_setup():
326
327 # Clear the ffdc_list_file_path file. Plug-ins may now write to it.
328 try:
329 os.remove(ffdc_list_file_path)
330 except OSError:
331 pass
332
333 # Clear the ffdc_report_list_path file. Plug-ins may now write to it.
334 try:
335 os.remove(ffdc_report_list_path)
336 except OSError:
337 pass
338
Michael Walsh600876d2017-05-30 17:58:58 -0500339 # Clear the ffdc_summary_list_path file. Plug-ins may now write to it.
340 try:
341 os.remove(ffdc_summary_list_path)
342 except OSError:
343 pass
344
Michael Walshe1974b92017-08-03 13:39:51 -0500345 global ffdc_prefix
346
347 seconds = time.time()
348 loc_time = time.localtime(seconds)
349 time_string = time.strftime("%y%m%d.%H%M%S.", loc_time)
350
351 ffdc_prefix = openbmc_nickname + "." + time_string
352
Michael Walshe0cf8d72017-05-17 13:20:46 -0500353
Michael Walshf566fb12019-02-01 14:35:09 -0600354def default_sigusr1(signal_number=0,
355 frame=None):
356 r"""
357 Handle SIGUSR1 by doing nothing.
358
359 This function assists in debugging SIGUSR1 processing by printing messages
360 to stdout and to the log.html file.
361
362 Description of argument(s):
363 signal_number The signal number (should always be 10 for SIGUSR1).
364 frame The frame data.
365 """
366
Michael Walsh80dddde2019-10-22 13:54:38 -0500367 gp.qprintn()
368 gp.qprint_executing()
Michael Walshf566fb12019-02-01 14:35:09 -0600369 gp.lprint_executing()
370
371
372def set_default_siguser1():
373 r"""
374 Set the default_sigusr1 function to be the SIGUSR1 handler.
375 """
376
Michael Walsh80dddde2019-10-22 13:54:38 -0500377 gp.qprintn()
378 gp.qprint_executing()
Michael Walshf566fb12019-02-01 14:35:09 -0600379 gp.lprint_executing()
380 signal.signal(signal.SIGUSR1, default_sigusr1)
381
382
Michael Walsh6741f742017-02-20 16:16:38 -0600383def setup():
Michael Walsh0bbd8602016-11-22 11:31:49 -0600384 r"""
Michael Walsh6741f742017-02-20 16:16:38 -0600385 Do general program setup tasks.
Michael Walsh0bbd8602016-11-22 11:31:49 -0600386 """
387
Michael Walsh6741f742017-02-20 16:16:38 -0600388 global cp_setup_called
Michael Walsh81816742017-09-27 11:02:29 -0500389 global transitional_boot_selected
Michael Walsh0bbd8602016-11-22 11:31:49 -0600390
Michael Walshb5839d02017-04-12 16:11:20 -0500391 gp.qprintn()
392
Michael Walshf566fb12019-02-01 14:35:09 -0600393 set_default_siguser1()
Michael Walsh81816742017-09-27 11:02:29 -0500394 transitional_boot_selected = False
395
Michael Walsh83f4bc72017-04-20 16:49:43 -0500396 robot_pgm_dir_path = os.path.dirname(__file__) + os.sep
397 repo_bin_path = robot_pgm_dir_path.replace("/lib/", "/bin/")
Michael Walshd061c042017-05-23 14:46:57 -0500398 # If we can't find process_plug_in_packages.py, ssh_pw or
399 # validate_plug_ins.py, then we don't have our repo bin in PATH.
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -0500400 shell_rc, out_buf = gc.cmd_fnc_u("which process_plug_in_packages.py"
401 + " ssh_pw validate_plug_ins.py", quiet=1,
Michael Walshd061c042017-05-23 14:46:57 -0500402 print_output=0, show_err=0)
Michael Walshb5839d02017-04-12 16:11:20 -0500403 if shell_rc != 0:
Michael Walsh83f4bc72017-04-20 16:49:43 -0500404 os.environ['PATH'] = repo_bin_path + ":" + os.environ.get('PATH', "")
405 # Likewise, our repo lib subdir needs to be in sys.path and PYTHONPATH.
406 if robot_pgm_dir_path not in sys.path:
407 sys.path.append(robot_pgm_dir_path)
408 PYTHONPATH = os.environ.get("PYTHONPATH", "")
409 if PYTHONPATH == "":
410 os.environ['PYTHONPATH'] = robot_pgm_dir_path
411 else:
412 os.environ['PYTHONPATH'] = robot_pgm_dir_path + ":" + PYTHONPATH
Michael Walsh6741f742017-02-20 16:16:38 -0600413
414 validate_parms()
415
Michael Walshc108e422019-03-28 12:27:18 -0500416 gp.qprint_pgm_header()
Michael Walsh6741f742017-02-20 16:16:38 -0600417
George Keishingefc3ff22017-12-12 11:49:25 -0600418 grk.run_key("Set BMC Power Policy ALWAYS_POWER_OFF")
Michael Walsh11cfc8c2017-03-31 09:40:55 -0500419
Michael Walsh85678942017-03-27 14:34:22 -0500420 initial_plug_in_setup()
421
Michael Walsh6741f742017-02-20 16:16:38 -0600422 plug_in_setup()
423 rc, shell_rc, failed_plug_in_name = grpi.rprocess_plug_in_packages(
424 call_point='setup')
425 if rc != 0:
426 error_message = "Plug-in setup failed.\n"
Michael Walshc108e422019-03-28 12:27:18 -0500427 gp.print_error_report(error_message)
Michael Walsh6741f742017-02-20 16:16:38 -0600428 BuiltIn().fail(error_message)
429 # Setting cp_setup_called lets our Teardown know that it needs to call
430 # the cleanup plug-in call point.
431 cp_setup_called = 1
432
433 # Keyword "FFDC" will fail if TEST_MESSAGE is not set.
434 BuiltIn().set_global_variable("${TEST_MESSAGE}", "${EMPTY}")
Michael Walsh85678942017-03-27 14:34:22 -0500435 # FFDC_LOG_PATH is used by "FFDC" keyword.
436 BuiltIn().set_global_variable("${FFDC_LOG_PATH}", ffdc_dir_path)
Michael Walsh6741f742017-02-20 16:16:38 -0600437
Michael Walshdc80d672017-05-09 12:58:32 -0500438 # Also printed by FFDC.
439 global host_name
440 global host_ip
441 host = socket.gethostname()
442 host_name, host_ip = gm.get_host_name_ip(host)
443
Michael Walsh986d8ae2019-07-17 10:02:23 -0500444 gp.dprint_var(boot_table)
Michael Walshb5839d02017-04-12 16:11:20 -0500445 gp.dprint_var(boot_lists)
Michael Walsh0bbd8602016-11-22 11:31:49 -0600446
Michael Walsh0bbd8602016-11-22 11:31:49 -0600447
Michael Walsh6741f742017-02-20 16:16:38 -0600448def validate_parms():
Michael Walsh0bbd8602016-11-22 11:31:49 -0600449 r"""
Michael Walsh6741f742017-02-20 16:16:38 -0600450 Validate all program parameters.
Michael Walsh0bbd8602016-11-22 11:31:49 -0600451 """
452
Michael Walshb5839d02017-04-12 16:11:20 -0500453 process_pgm_parms()
Michael Walsh0bbd8602016-11-22 11:31:49 -0600454
Michael Walshb5839d02017-04-12 16:11:20 -0500455 gp.qprintn()
456
457 global openbmc_model
Michael Walsh44cef252019-08-01 12:38:56 -0500458 gv.valid_value(openbmc_host)
459 gv.valid_value(openbmc_username)
460 gv.valid_value(openbmc_password)
461 gv.valid_value(rest_username)
462 gv.valid_value(rest_password)
463 gv.valid_value(ipmi_username)
464 gv.valid_value(ipmi_password)
Michael Walsh6741f742017-02-20 16:16:38 -0600465 if os_host != "":
Michael Walsh44cef252019-08-01 12:38:56 -0500466 gv.valid_value(os_username)
467 gv.valid_value(os_password)
Michael Walsh0bbd8602016-11-22 11:31:49 -0600468
Michael Walsh6741f742017-02-20 16:16:38 -0600469 if pdu_host != "":
Michael Walsh44cef252019-08-01 12:38:56 -0500470 gv.valid_value(pdu_username)
471 gv.valid_value(pdu_password)
472 gv.valid_integer(pdu_slot_no)
Michael Walsh6741f742017-02-20 16:16:38 -0600473 if openbmc_serial_host != "":
Michael Walsh44cef252019-08-01 12:38:56 -0500474 gv.valid_integer(openbmc_serial_port)
Michael Walshb5839d02017-04-12 16:11:20 -0500475 if openbmc_model == "":
476 status, ret_values =\
477 grk.run_key_u("Get BMC System Model")
478 openbmc_model = ret_values
479 BuiltIn().set_global_variable("${openbmc_model}", openbmc_model)
Michael Walsh44cef252019-08-01 12:38:56 -0500480 gv.valid_value(openbmc_model)
481 gv.valid_integer(max_num_tests)
482 gv.valid_integer(boot_pass)
483 gv.valid_integer(boot_fail)
Michael Walsh6741f742017-02-20 16:16:38 -0600484
485 plug_in_packages_list = grpi.rvalidate_plug_ins(plug_in_dir_paths)
486 BuiltIn().set_global_variable("${plug_in_packages_list}",
487 plug_in_packages_list)
488
Michael Walsh44cef252019-08-01 12:38:56 -0500489 gv.valid_value(stack_mode, valid_values=['normal', 'skip'])
Michael Walsha20da402017-03-31 16:27:45 -0500490 if len(boot_list) == 0 and len(boot_stack) == 0 and not ffdc_only:
Michael Walsh6741f742017-02-20 16:16:38 -0600491 error_message = "You must provide either a value for either the" +\
492 " boot_list or the boot_stack parm.\n"
493 BuiltIn().fail(gp.sprint_error(error_message))
494
495 valid_boot_list(boot_list, valid_boot_types)
496 valid_boot_list(boot_stack, valid_boot_types)
497
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -0500498 selected_PDU_boots = list(set(boot_list + boot_stack)
499 & set(boot_lists['PDU_reboot']))
Michael Walsh11cfc8c2017-03-31 09:40:55 -0500500
501 if len(selected_PDU_boots) > 0 and pdu_host == "":
502 error_message = "You have selected the following boots which" +\
503 " require a PDU host but no value for pdu_host:\n"
504 error_message += gp.sprint_var(selected_PDU_boots)
Michael Walsh986d8ae2019-07-17 10:02:23 -0500505 error_message += gp.sprint_var(pdu_host, fmt=gp.blank())
Michael Walsh11cfc8c2017-03-31 09:40:55 -0500506 BuiltIn().fail(gp.sprint_error(error_message))
507
Michael Walsh6741f742017-02-20 16:16:38 -0600508 return
Michael Walsh0bbd8602016-11-22 11:31:49 -0600509
Michael Walsh0bbd8602016-11-22 11:31:49 -0600510
Michael Walsh6741f742017-02-20 16:16:38 -0600511def my_get_state():
Michael Walsh0bbd8602016-11-22 11:31:49 -0600512 r"""
Michael Walsh6741f742017-02-20 16:16:38 -0600513 Get the system state plus a little bit of wrapping.
Michael Walsh0bbd8602016-11-22 11:31:49 -0600514 """
515
Michael Walsh6741f742017-02-20 16:16:38 -0600516 global state
517
518 req_states = ['epoch_seconds'] + st.default_req_states
519
Michael Walshb5839d02017-04-12 16:11:20 -0500520 gp.qprint_timen("Getting system state.")
Michael Walsh6741f742017-02-20 16:16:38 -0600521 if test_mode:
522 state['epoch_seconds'] = int(time.time())
523 else:
Michael Walshb5839d02017-04-12 16:11:20 -0500524 state = st.get_state(req_states=req_states, quiet=quiet)
525 gp.qprint_var(state)
Michael Walsh341c21e2017-01-17 16:25:20 -0600526
Michael Walsh341c21e2017-01-17 16:25:20 -0600527
Michael Walsh45ca6e42017-09-14 17:29:12 -0500528def valid_state():
Michael Walsh45ca6e42017-09-14 17:29:12 -0500529 r"""
530 Verify that our state dictionary contains no blank values. If we don't get
531 valid state data, we cannot continue to work.
532 """
533
534 if st.compare_states(state, st.invalid_state_match, 'or'):
535 error_message = "The state dictionary contains blank fields which" +\
536 " is illegal.\n" + gp.sprint_var(state)
537 BuiltIn().fail(gp.sprint_error(error_message))
538
Michael Walsh45ca6e42017-09-14 17:29:12 -0500539
Michael Walsh6741f742017-02-20 16:16:38 -0600540def select_boot():
Michael Walsh341c21e2017-01-17 16:25:20 -0600541 r"""
542 Select a boot test to be run based on our current state and return the
543 chosen boot type.
544
545 Description of arguments:
Michael Walsh6741f742017-02-20 16:16:38 -0600546 state The state of the machine.
Michael Walsh341c21e2017-01-17 16:25:20 -0600547 """
548
Michael Walsh81816742017-09-27 11:02:29 -0500549 global transitional_boot_selected
Michael Walsh30dadae2017-02-27 14:25:52 -0600550 global boot_stack
551
Michael Walshb5839d02017-04-12 16:11:20 -0500552 gp.qprint_timen("Selecting a boot test.")
Michael Walsh6741f742017-02-20 16:16:38 -0600553
Michael Walsh81816742017-09-27 11:02:29 -0500554 if transitional_boot_selected and not boot_success:
555 prior_boot = next_boot
556 boot_candidate = boot_stack.pop()
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -0500557 gp.qprint_timen("The prior '" + next_boot + "' was chosen to"
558 + " transition to a valid state for '" + boot_candidate
559 + "' which was at the top of the boot_stack. Since"
560 + " the '" + next_boot + "' failed, the '"
561 + boot_candidate + "' has been removed from the stack"
562 + " to avoid and endless failure loop.")
Michael Walsh81816742017-09-27 11:02:29 -0500563 if len(boot_stack) == 0:
564 return ""
565
Michael Walsh6741f742017-02-20 16:16:38 -0600566 my_get_state()
Michael Walsh45ca6e42017-09-14 17:29:12 -0500567 valid_state()
Michael Walsh6741f742017-02-20 16:16:38 -0600568
Michael Walsh81816742017-09-27 11:02:29 -0500569 transitional_boot_selected = False
Michael Walsh6741f742017-02-20 16:16:38 -0600570 stack_popped = 0
571 if len(boot_stack) > 0:
572 stack_popped = 1
Michael Walshb5839d02017-04-12 16:11:20 -0500573 gp.qprint_dashes()
574 gp.qprint_var(boot_stack)
575 gp.qprint_dashes()
576 skip_boot_printed = 0
577 while len(boot_stack) > 0:
578 boot_candidate = boot_stack.pop()
579 if stack_mode == 'normal':
580 break
581 else:
582 if st.compare_states(state, boot_table[boot_candidate]['end']):
583 if not skip_boot_printed:
Michael Walshff340002017-08-29 11:18:27 -0500584 gp.qprint_var(stack_mode)
585 gp.qprintn()
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -0500586 gp.qprint_timen("Skipping the following boot tests"
587 + " which are unnecessary since their"
588 + " required end states match the"
589 + " current machine state:")
Michael Walshb5839d02017-04-12 16:11:20 -0500590 skip_boot_printed = 1
Michael Walshff340002017-08-29 11:18:27 -0500591 gp.qprint_var(boot_candidate)
Michael Walshb5839d02017-04-12 16:11:20 -0500592 boot_candidate = ""
593 if boot_candidate == "":
594 gp.qprint_dashes()
595 gp.qprint_var(boot_stack)
596 gp.qprint_dashes()
597 return boot_candidate
Michael Walsh6741f742017-02-20 16:16:38 -0600598 if st.compare_states(state, boot_table[boot_candidate]['start']):
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -0500599 gp.qprint_timen("The machine state is valid for a '"
600 + boot_candidate + "' boot test.")
Michael Walshb5839d02017-04-12 16:11:20 -0500601 gp.qprint_dashes()
602 gp.qprint_var(boot_stack)
603 gp.qprint_dashes()
Michael Walsh6741f742017-02-20 16:16:38 -0600604 return boot_candidate
Michael Walsh341c21e2017-01-17 16:25:20 -0600605 else:
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -0500606 gp.qprint_timen("The machine state does not match the required"
607 + " starting state for a '" + boot_candidate
608 + "' boot test:")
Michael Walsh986d8ae2019-07-17 10:02:23 -0500609 gp.qprint_varx("boot_table_start_entry",
610 boot_table[boot_candidate]['start'])
Michael Walsh6741f742017-02-20 16:16:38 -0600611 boot_stack.append(boot_candidate)
Michael Walsh81816742017-09-27 11:02:29 -0500612 transitional_boot_selected = True
Michael Walsh6741f742017-02-20 16:16:38 -0600613 popped_boot = boot_candidate
614
615 # Loop through your list selecting a boot_candidates
616 boot_candidates = []
617 for boot_candidate in boot_list:
618 if st.compare_states(state, boot_table[boot_candidate]['start']):
619 if stack_popped:
620 if st.compare_states(boot_table[boot_candidate]['end'],
Gunnar Mills096cd562018-03-26 10:19:12 -0500621 boot_table[popped_boot]['start']):
Michael Walsh6741f742017-02-20 16:16:38 -0600622 boot_candidates.append(boot_candidate)
623 else:
624 boot_candidates.append(boot_candidate)
625
626 if len(boot_candidates) == 0:
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -0500627 gp.qprint_timen("The user's boot list contained no boot tests"
628 + " which are valid for the current machine state.")
Michael Walsh6741f742017-02-20 16:16:38 -0600629 boot_candidate = default_power_on
630 if not st.compare_states(state, boot_table[default_power_on]['start']):
631 boot_candidate = default_power_off
632 boot_candidates.append(boot_candidate)
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -0500633 gp.qprint_timen("Using default '" + boot_candidate
634 + "' boot type to transition to valid state.")
Michael Walsh6741f742017-02-20 16:16:38 -0600635
Michael Walshb5839d02017-04-12 16:11:20 -0500636 gp.dprint_var(boot_candidates)
Michael Walsh6741f742017-02-20 16:16:38 -0600637
638 # Randomly select a boot from the candidate list.
639 boot = random.choice(boot_candidates)
Michael Walsh341c21e2017-01-17 16:25:20 -0600640
641 return boot
Michael Walsh0bbd8602016-11-22 11:31:49 -0600642
Michael Walsh55302292017-01-10 11:43:02 -0600643
Michael Walshb2e53ec2017-10-30 15:04:36 -0500644def print_defect_report(ffdc_file_list):
Michael Walsh341c21e2017-01-17 16:25:20 -0600645 r"""
646 Print a defect report.
Michael Walshb2e53ec2017-10-30 15:04:36 -0500647
648 Description of argument(s):
649 ffdc_file_list A list of files which were collected by our ffdc functions.
Michael Walsh341c21e2017-01-17 16:25:20 -0600650 """
651
Michael Walsh600876d2017-05-30 17:58:58 -0500652 # Making deliberate choice to NOT run plug_in_setup(). We don't want
653 # ffdc_prefix updated.
654 rc, shell_rc, failed_plug_in_name = grpi.rprocess_plug_in_packages(
655 call_point='ffdc_report', stop_on_plug_in_failure=0)
656
Michael Walshe0cf8d72017-05-17 13:20:46 -0500657 # Get additional header data which may have been created by ffdc plug-ins.
658 # Also, delete the individual header files to cleanup.
659 cmd_buf = "file_list=$(cat " + ffdc_report_list_path + " 2>/dev/null)" +\
660 " ; [ ! -z \"${file_list}\" ] && cat ${file_list}" +\
661 " 2>/dev/null ; rm -rf ${file_list} 2>/dev/null || :"
662 shell_rc, more_header_info = gc.cmd_fnc_u(cmd_buf, print_output=0,
663 show_err=0)
664
Michael Walshb2e53ec2017-10-30 15:04:36 -0500665 # Get additional summary data which may have been created by ffdc plug-ins.
Michael Walsh600876d2017-05-30 17:58:58 -0500666 # Also, delete the individual header files to cleanup.
667 cmd_buf = "file_list=$(cat " + ffdc_summary_list_path + " 2>/dev/null)" +\
668 " ; [ ! -z \"${file_list}\" ] && cat ${file_list}" +\
669 " 2>/dev/null ; rm -rf ${file_list} 2>/dev/null || :"
670 shell_rc, ffdc_summary_info = gc.cmd_fnc_u(cmd_buf, print_output=0,
671 show_err=0)
672
Michael Walshb2e53ec2017-10-30 15:04:36 -0500673 # ffdc_list_file_path contains a list of any ffdc files created by plug-
674 # ins, etc. Read that data into a list.
Michael Walsh341c21e2017-01-17 16:25:20 -0600675 try:
Michael Walshb2e53ec2017-10-30 15:04:36 -0500676 plug_in_ffdc_list = \
677 open(ffdc_list_file_path, 'r').read().rstrip("\n").split("\n")
George Keishing36efbc02018-12-12 10:18:23 -0600678 plug_in_ffdc_list = list(filter(None, plug_in_ffdc_list))
Michael Walsh341c21e2017-01-17 16:25:20 -0600679 except IOError:
Michael Walshb2e53ec2017-10-30 15:04:36 -0500680 plug_in_ffdc_list = []
681
682 # Combine the files from plug_in_ffdc_list with the ffdc_file_list passed
683 # in. Eliminate duplicates and sort the list.
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -0500684 ffdc_file_list = sorted(set(ffdc_file_list + plug_in_ffdc_list))
Michael Walshb2e53ec2017-10-30 15:04:36 -0500685
686 if status_file_path != "":
687 ffdc_file_list.insert(0, status_file_path)
688
689 # Convert the list to a printable list.
690 printable_ffdc_file_list = "\n".join(ffdc_file_list)
Michael Walsh341c21e2017-01-17 16:25:20 -0600691
Michael Walsh68a61162017-04-25 11:54:06 -0500692 # Open ffdc_file_list for writing. We will write a complete list of
693 # FFDC files to it for possible use by plug-ins like cp_stop_check.
694 ffdc_list_file = open(ffdc_list_file_path, 'w')
Michael Walshb2e53ec2017-10-30 15:04:36 -0500695 ffdc_list_file.write(printable_ffdc_file_list + "\n")
696 ffdc_list_file.close()
697
698 indent = 0
699 width = 90
700 linefeed = 1
701 char = "="
Michael Walsh68a61162017-04-25 11:54:06 -0500702
703 gp.qprintn()
Michael Walshb2e53ec2017-10-30 15:04:36 -0500704 gp.qprint_dashes(indent, width, linefeed, char)
Michael Walsh68a61162017-04-25 11:54:06 -0500705 gp.qprintn("Copy this data to the defect:\n")
706
Michael Walshe0cf8d72017-05-17 13:20:46 -0500707 if len(more_header_info) > 0:
Michael Walshff340002017-08-29 11:18:27 -0500708 gp.qprintn(more_header_info)
Michael Walshdc80d672017-05-09 12:58:32 -0500709 gp.qpvars(host_name, host_ip, openbmc_nickname, openbmc_host,
710 openbmc_host_name, openbmc_ip, openbmc_username,
Michael Walsh0a3bdb42019-01-31 16:21:44 +0000711 openbmc_password, rest_username, rest_password, ipmi_username,
712 ipmi_password, os_host, os_host_name, os_ip, os_username,
Michael Walshdc80d672017-05-09 12:58:32 -0500713 os_password, pdu_host, pdu_host_name, pdu_ip, pdu_username,
714 pdu_password, pdu_slot_no, openbmc_serial_host,
715 openbmc_serial_host_name, openbmc_serial_ip, openbmc_serial_port)
Michael Walsh68a61162017-04-25 11:54:06 -0500716
717 gp.qprintn()
Michael Walsh986d8ae2019-07-17 10:02:23 -0500718 print_boot_history(boot_history)
Michael Walsh68a61162017-04-25 11:54:06 -0500719 gp.qprintn()
720 gp.qprint_var(state)
Michael Walshb5839d02017-04-12 16:11:20 -0500721 gp.qprintn()
722 gp.qprintn("FFDC data files:")
Michael Walshb2e53ec2017-10-30 15:04:36 -0500723 gp.qprintn(printable_ffdc_file_list)
Michael Walshb5839d02017-04-12 16:11:20 -0500724 gp.qprintn()
Michael Walsh341c21e2017-01-17 16:25:20 -0600725
Michael Walsh600876d2017-05-30 17:58:58 -0500726 if len(ffdc_summary_info) > 0:
Michael Walshff340002017-08-29 11:18:27 -0500727 gp.qprintn(ffdc_summary_info)
Michael Walsh600876d2017-05-30 17:58:58 -0500728
Michael Walshb2e53ec2017-10-30 15:04:36 -0500729 gp.qprint_dashes(indent, width, linefeed, char)
Michael Walsh68a61162017-04-25 11:54:06 -0500730
Michael Walsh6741f742017-02-20 16:16:38 -0600731
Michael Walsh6741f742017-02-20 16:16:38 -0600732def my_ffdc():
Michael Walsh6741f742017-02-20 16:16:38 -0600733 r"""
734 Collect FFDC data.
735 """
736
737 global state
738
739 plug_in_setup()
740 rc, shell_rc, failed_plug_in_name = grpi.rprocess_plug_in_packages(
Michael Walsh600876d2017-05-30 17:58:58 -0500741 call_point='ffdc', stop_on_plug_in_failure=0)
Michael Walsh6741f742017-02-20 16:16:38 -0600742
743 AUTOBOOT_FFDC_PREFIX = os.environ['AUTOBOOT_FFDC_PREFIX']
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -0500744 status, ffdc_file_list = grk.run_key_u("FFDC ffdc_prefix="
745 + AUTOBOOT_FFDC_PREFIX
746 + " ffdc_function_list="
747 + ffdc_function_list, ignore=1)
Michael Walsh83f4bc72017-04-20 16:49:43 -0500748 if status != 'PASS':
Michael Walshff340002017-08-29 11:18:27 -0500749 gp.qprint_error("Call to ffdc failed.\n")
Michael Walshc9bd2e82019-04-18 11:06:52 -0500750 if type(ffdc_file_list) is not list:
751 ffdc_file_list = []
752 # Leave a record for caller that "soft" errors occurred.
753 soft_errors = 1
754 gpu.save_plug_in_value(soft_errors, pgm_name)
Michael Walsh6741f742017-02-20 16:16:38 -0600755
756 my_get_state()
757
Michael Walshb2e53ec2017-10-30 15:04:36 -0500758 print_defect_report(ffdc_file_list)
Michael Walsh6741f742017-02-20 16:16:38 -0600759
Michael Walsh6741f742017-02-20 16:16:38 -0600760
Michael Walsh6741f742017-02-20 16:16:38 -0600761def print_test_start_message(boot_keyword):
Michael Walsh6741f742017-02-20 16:16:38 -0600762 r"""
763 Print a message indicating what boot test is about to run.
764
765 Description of arguments:
766 boot_keyword The name of the boot which is to be run
767 (e.g. "BMC Power On").
768 """
769
Michael Walsh986d8ae2019-07-17 10:02:23 -0500770 global boot_history
Sunil M325eb542017-08-10 07:09:43 -0500771 global boot_start_time
Michael Walsh6741f742017-02-20 16:16:38 -0600772
773 doing_msg = gp.sprint_timen("Doing \"" + boot_keyword + "\".")
Sunil M325eb542017-08-10 07:09:43 -0500774
775 # Set boot_start_time for use by plug-ins.
776 boot_start_time = doing_msg[1:33]
777 gp.qprint_var(boot_start_time)
778
Michael Walshb5839d02017-04-12 16:11:20 -0500779 gp.qprint(doing_msg)
Michael Walsh6741f742017-02-20 16:16:38 -0600780
Michael Walsh986d8ae2019-07-17 10:02:23 -0500781 update_boot_history(boot_history, doing_msg, max_boot_history)
Michael Walsh6741f742017-02-20 16:16:38 -0600782
Michael Walsh6741f742017-02-20 16:16:38 -0600783
Michael Walshf566fb12019-02-01 14:35:09 -0600784def stop_boot_test(signal_number=0,
785 frame=None):
786 r"""
787 Handle SIGUSR1 by aborting the boot test that is running.
788
789 Description of argument(s):
790 signal_number The signal number (should always be 10 for SIGUSR1).
791 frame The frame data.
792 """
793
Michael Walsh80dddde2019-10-22 13:54:38 -0500794 gp.qprintn()
795 gp.qprint_executing()
Michael Walshf566fb12019-02-01 14:35:09 -0600796 gp.lprint_executing()
797
798 # Restore original sigusr1 handler.
799 set_default_siguser1()
800
801 message = "The caller has asked that the boot test be stopped and marked"
802 message += " as a failure."
803
804 function_stack = gm.get_function_stack()
805 if "wait_state" in function_stack:
Michael Walshc44aa532019-06-14 13:33:29 -0500806 st.set_exit_wait_early_message(message)
Michael Walshf566fb12019-02-01 14:35:09 -0600807 else:
808 BuiltIn().fail(gp.sprint_error(message))
809
810
Michael Walsh6741f742017-02-20 16:16:38 -0600811def run_boot(boot):
Michael Walsh6741f742017-02-20 16:16:38 -0600812 r"""
813 Run the specified boot.
814
815 Description of arguments:
816 boot The name of the boot test to be performed.
817 """
818
819 global state
820
Michael Walshf566fb12019-02-01 14:35:09 -0600821 signal.signal(signal.SIGUSR1, stop_boot_test)
822 gp.qprint_timen("stop_boot_test is armed.")
823
Michael Walsh6741f742017-02-20 16:16:38 -0600824 print_test_start_message(boot)
825
826 plug_in_setup()
827 rc, shell_rc, failed_plug_in_name = \
828 grpi.rprocess_plug_in_packages(call_point="pre_boot")
829 if rc != 0:
830 error_message = "Plug-in failed with non-zero return code.\n" +\
Michael Walsh986d8ae2019-07-17 10:02:23 -0500831 gp.sprint_var(rc, fmt=gp.hexa())
Michael Walshf566fb12019-02-01 14:35:09 -0600832 set_default_siguser1()
Michael Walsh6741f742017-02-20 16:16:38 -0600833 BuiltIn().fail(gp.sprint_error(error_message))
834
835 if test_mode:
836 # In test mode, we'll pretend the boot worked by assigning its
837 # required end state to the default state value.
Michael Walsh30dadae2017-02-27 14:25:52 -0600838 state = st.strip_anchor_state(boot_table[boot]['end'])
Michael Walsh6741f742017-02-20 16:16:38 -0600839 else:
840 # Assertion: We trust that the state data was made fresh by the
841 # caller.
842
Michael Walshb5839d02017-04-12 16:11:20 -0500843 gp.qprintn()
Michael Walsh6741f742017-02-20 16:16:38 -0600844
845 if boot_table[boot]['method_type'] == "keyword":
Michael Walsh0b93fbf2017-03-02 14:42:41 -0600846 rk.my_run_keywords(boot_table[boot].get('lib_file_path', ''),
Michael Walshb5839d02017-04-12 16:11:20 -0500847 boot_table[boot]['method'],
848 quiet=quiet)
Michael Walsh6741f742017-02-20 16:16:38 -0600849
850 if boot_table[boot]['bmc_reboot']:
851 st.wait_for_comm_cycle(int(state['epoch_seconds']))
Michael Walsh30dadae2017-02-27 14:25:52 -0600852 plug_in_setup()
853 rc, shell_rc, failed_plug_in_name = \
854 grpi.rprocess_plug_in_packages(call_point="post_reboot")
855 if rc != 0:
Michael Walsh0b93fbf2017-03-02 14:42:41 -0600856 error_message = "Plug-in failed with non-zero return code.\n"
Michael Walsh986d8ae2019-07-17 10:02:23 -0500857 error_message += gp.sprint_var(rc, fmt=gp.hexa())
Michael Walshf566fb12019-02-01 14:35:09 -0600858 set_default_siguser1()
Michael Walsh30dadae2017-02-27 14:25:52 -0600859 BuiltIn().fail(gp.sprint_error(error_message))
Michael Walsh6741f742017-02-20 16:16:38 -0600860 else:
861 match_state = st.anchor_state(state)
862 del match_state['epoch_seconds']
863 # Wait for the state to change in any way.
864 st.wait_state(match_state, wait_time=state_change_timeout,
Michael Walsh600876d2017-05-30 17:58:58 -0500865 interval="10 seconds", invert=1)
Michael Walsh6741f742017-02-20 16:16:38 -0600866
Michael Walshb5839d02017-04-12 16:11:20 -0500867 gp.qprintn()
Michael Walsh6741f742017-02-20 16:16:38 -0600868 if boot_table[boot]['end']['chassis'] == "Off":
869 boot_timeout = power_off_timeout
870 else:
871 boot_timeout = power_on_timeout
872 st.wait_state(boot_table[boot]['end'], wait_time=boot_timeout,
Michael Walsh600876d2017-05-30 17:58:58 -0500873 interval="10 seconds")
Michael Walsh6741f742017-02-20 16:16:38 -0600874
875 plug_in_setup()
876 rc, shell_rc, failed_plug_in_name = \
877 grpi.rprocess_plug_in_packages(call_point="post_boot")
878 if rc != 0:
879 error_message = "Plug-in failed with non-zero return code.\n" +\
Michael Walsh986d8ae2019-07-17 10:02:23 -0500880 gp.sprint_var(rc, fmt=gp.hexa())
Michael Walshf566fb12019-02-01 14:35:09 -0600881 set_default_siguser1()
Michael Walsh6741f742017-02-20 16:16:38 -0600882 BuiltIn().fail(gp.sprint_error(error_message))
883
Michael Walshf566fb12019-02-01 14:35:09 -0600884 # Restore original sigusr1 handler.
885 set_default_siguser1()
886
Michael Walsh6741f742017-02-20 16:16:38 -0600887
Michael Walsh6741f742017-02-20 16:16:38 -0600888def test_loop_body():
Michael Walsh6741f742017-02-20 16:16:38 -0600889 r"""
890 The main loop body for the loop in main_py.
891
892 Description of arguments:
893 boot_count The iteration number (starts at 1).
894 """
895
896 global boot_count
897 global state
898 global next_boot
899 global boot_success
Sunil M325eb542017-08-10 07:09:43 -0500900 global boot_end_time
Michael Walsh6741f742017-02-20 16:16:38 -0600901
Michael Walshb5839d02017-04-12 16:11:20 -0500902 gp.qprintn()
Michael Walsh6741f742017-02-20 16:16:38 -0600903
904 next_boot = select_boot()
Michael Walshb5839d02017-04-12 16:11:20 -0500905 if next_boot == "":
906 return True
Michael Walsh6741f742017-02-20 16:16:38 -0600907
Michael Walshb5839d02017-04-12 16:11:20 -0500908 boot_count += 1
909 gp.qprint_timen("Starting boot " + str(boot_count) + ".")
Michael Walsh6741f742017-02-20 16:16:38 -0600910
Michael Walshe0cf8d72017-05-17 13:20:46 -0500911 pre_boot_plug_in_setup()
Michael Walsh6741f742017-02-20 16:16:38 -0600912
913 cmd_buf = ["run_boot", next_boot]
914 boot_status, msg = BuiltIn().run_keyword_and_ignore_error(*cmd_buf)
915 if boot_status == "FAIL":
Michael Walshb5839d02017-04-12 16:11:20 -0500916 gp.qprint(msg)
Michael Walsh6741f742017-02-20 16:16:38 -0600917
Michael Walshb5839d02017-04-12 16:11:20 -0500918 gp.qprintn()
Michael Walsh6741f742017-02-20 16:16:38 -0600919 if boot_status == "PASS":
920 boot_success = 1
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -0500921 completion_msg = gp.sprint_timen("BOOT_SUCCESS: \"" + next_boot
922 + "\" succeeded.")
Michael Walsh6741f742017-02-20 16:16:38 -0600923 else:
924 boot_success = 0
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -0500925 completion_msg = gp.sprint_timen("BOOT_FAILED: \"" + next_boot
926 + "\" failed.")
Sunil M325eb542017-08-10 07:09:43 -0500927
928 # Set boot_end_time for use by plug-ins.
929 boot_end_time = completion_msg[1:33]
930 gp.qprint_var(boot_end_time)
931
932 gp.qprint(completion_msg)
Michael Walsh6741f742017-02-20 16:16:38 -0600933
934 boot_results.update(next_boot, boot_status)
935
936 plug_in_setup()
937 # NOTE: A post_test_case call point failure is NOT counted as a boot
938 # failure.
939 rc, shell_rc, failed_plug_in_name = grpi.rprocess_plug_in_packages(
Michael Walsh600876d2017-05-30 17:58:58 -0500940 call_point='post_test_case', stop_on_plug_in_failure=0)
Michael Walsh6741f742017-02-20 16:16:38 -0600941
942 plug_in_setup()
943 rc, shell_rc, failed_plug_in_name = grpi.rprocess_plug_in_packages(
Michael Walsh89de14a2018-10-01 16:51:37 -0500944 call_point='ffdc_check', shell_rc=dump_ffdc_rc(),
Michael Walsh6741f742017-02-20 16:16:38 -0600945 stop_on_plug_in_failure=1, stop_on_non_zero_rc=1)
Michael Walsh12059e22019-03-21 11:03:45 -0500946 if ffdc_check == "All" or\
Michael Walsh89de14a2018-10-01 16:51:37 -0500947 shell_rc == dump_ffdc_rc():
Michael Walsh83f4bc72017-04-20 16:49:43 -0500948 status, ret_values = grk.run_key_u("my_ffdc", ignore=1)
949 if status != 'PASS':
Michael Walshff340002017-08-29 11:18:27 -0500950 gp.qprint_error("Call to my_ffdc failed.\n")
Michael Walshc9bd2e82019-04-18 11:06:52 -0500951 # Leave a record for caller that "soft" errors occurred.
952 soft_errors = 1
953 gpu.save_plug_in_value(soft_errors, pgm_name)
Michael Walsh6741f742017-02-20 16:16:38 -0600954
Michael Walshaabef1e2017-09-20 15:16:17 -0500955 if delete_errlogs:
956 # We need to purge error logs between boots or they build up.
957 grk.run_key("Delete Error logs", ignore=1)
Michael Walshd139f282017-04-04 18:00:23 -0500958
Michael Walsh952f9b02017-03-09 13:11:14 -0600959 boot_results.print_report()
Michael Walshb5839d02017-04-12 16:11:20 -0500960 gp.qprint_timen("Finished boot " + str(boot_count) + ".")
Michael Walsh952f9b02017-03-09 13:11:14 -0600961
Michael Walsh6741f742017-02-20 16:16:38 -0600962 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='stop_check', shell_rc=stop_test_rc(),
965 stop_on_non_zero_rc=1)
966 if shell_rc == stop_test_rc():
Michael Walsh3ba8ecd2018-04-24 11:33:25 -0500967 message = "Stopping as requested by user.\n"
Michael Walsh80dddde2019-10-22 13:54:38 -0500968 gp.qprint_time(message)
Michael Walsh3ba8ecd2018-04-24 11:33:25 -0500969 BuiltIn().fail(message)
Michael Walsh6741f742017-02-20 16:16:38 -0600970
Michael Walshd139f282017-04-04 18:00:23 -0500971 # This should help prevent ConnectionErrors.
Michael Walsh0960b382017-06-22 16:23:37 -0500972 grk.run_key_u("Close All Connections")
Michael Walshd139f282017-04-04 18:00:23 -0500973
Michael Walsh6741f742017-02-20 16:16:38 -0600974 return True
975
Michael Walsh6741f742017-02-20 16:16:38 -0600976
Michael Walsh83f4bc72017-04-20 16:49:43 -0500977def obmc_boot_test_teardown():
Michael Walsh6741f742017-02-20 16:16:38 -0600978 r"""
Michael Walshf75d4352019-12-05 17:01:20 -0600979 Clean up after the main keyword.
Michael Walsh6741f742017-02-20 16:16:38 -0600980 """
Michael Walshf75d4352019-12-05 17:01:20 -0600981 gp.qprint_executing()
982
983 if ga.psutil_imported:
984 ga.terminate_descendants()
Michael Walsh6741f742017-02-20 16:16:38 -0600985
986 if cp_setup_called:
987 plug_in_setup()
988 rc, shell_rc, failed_plug_in_name = grpi.rprocess_plug_in_packages(
Michael Walsh600876d2017-05-30 17:58:58 -0500989 call_point='cleanup', stop_on_plug_in_failure=0)
Michael Walsh6741f742017-02-20 16:16:38 -0600990
Michael Walsh600876d2017-05-30 17:58:58 -0500991 if 'boot_results_file_path' in globals():
Michael Walsh986d8ae2019-07-17 10:02:23 -0500992 # Save boot_results and boot_history objects to a file in case they are
Michael Walsh6c645742018-08-17 15:02:17 -0500993 # needed again.
Michael Walsh600876d2017-05-30 17:58:58 -0500994 gp.qprint_timen("Saving boot_results to the following path.")
995 gp.qprint_var(boot_results_file_path)
Michael Walsh986d8ae2019-07-17 10:02:23 -0500996 pickle.dump((boot_results, boot_history),
Michael Walsh6c645742018-08-17 15:02:17 -0500997 open(boot_results_file_path, 'wb'),
Michael Walsh600876d2017-05-30 17:58:58 -0500998 pickle.HIGHEST_PROTOCOL)
Michael Walsh0b93fbf2017-03-02 14:42:41 -0600999
Michael Walshff340002017-08-29 11:18:27 -05001000 global save_stack
1001 # Restore any global values saved on the save_stack.
1002 for parm_name in main_func_parm_list:
1003 # Get the parm_value if it was saved on the stack.
1004 try:
1005 parm_value = save_stack.pop(parm_name)
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -05001006 except BaseException:
Michael Walshff340002017-08-29 11:18:27 -05001007 # If it was not saved, no further action is required.
1008 continue
1009
1010 # Restore the saved value.
1011 cmd_buf = "BuiltIn().set_global_variable(\"${" + parm_name +\
1012 "}\", parm_value)"
1013 gp.dpissuing(cmd_buf)
1014 exec(cmd_buf)
1015
1016 gp.dprintn(save_stack.sprint_obj())
1017
Michael Walsh6741f742017-02-20 16:16:38 -06001018
Michael Walshc9116812017-03-10 14:23:06 -06001019def test_teardown():
Michael Walshc9116812017-03-10 14:23:06 -06001020 r"""
1021 Clean up after this test case.
1022 """
1023
1024 gp.qprintn()
Michael Walshf75d4352019-12-05 17:01:20 -06001025 gp.qprint_executing()
1026
1027 if ga.psutil_imported:
1028 ga.terminate_descendants()
1029
Michael Walshc9116812017-03-10 14:23:06 -06001030 cmd_buf = ["Print Error",
1031 "A keyword timeout occurred ending this program.\n"]
1032 BuiltIn().run_keyword_if_timeout_occurred(*cmd_buf)
1033
Michael Walshc108e422019-03-28 12:27:18 -05001034 gp.qprint_pgm_footer()
Michael Walshb5839d02017-04-12 16:11:20 -05001035
Michael Walshc9116812017-03-10 14:23:06 -06001036
Michael Walsh89de14a2018-10-01 16:51:37 -05001037def post_stack():
1038 r"""
1039 Process post_stack plug-in programs.
1040 """
1041
1042 if not call_post_stack_plug:
1043 # The caller does not wish to have post_stack plug-in processing done.
1044 return
1045
1046 global boot_success
1047
1048 # NOTE: A post_stack call-point failure is NOT counted as a boot failure.
1049 pre_boot_plug_in_setup()
1050 # For the purposes of the following plug-ins, mark the "boot" as a success.
1051 boot_success = 1
1052 plug_in_setup()
Michael Walsh815b1d52018-10-30 13:32:26 -05001053 rc, shell_rc, failed_plug_in_name, history =\
1054 grpi.rprocess_plug_in_packages(call_point='post_stack',
1055 stop_on_plug_in_failure=0,
1056 return_history=True)
Michael Walsh986d8ae2019-07-17 10:02:23 -05001057 for doing_msg in history:
1058 update_boot_history(boot_history, doing_msg, max_boot_history)
Michael Walsh815b1d52018-10-30 13:32:26 -05001059 if rc != 0:
1060 boot_success = 0
Michael Walsh89de14a2018-10-01 16:51:37 -05001061
1062 plug_in_setup()
Michael Walsh815b1d52018-10-30 13:32:26 -05001063 rc, shell_rc, failed_plug_in_name =\
1064 grpi.rprocess_plug_in_packages(call_point='ffdc_check',
1065 shell_rc=dump_ffdc_rc(),
1066 stop_on_plug_in_failure=1,
1067 stop_on_non_zero_rc=1)
1068 if shell_rc == dump_ffdc_rc():
Michael Walsh89de14a2018-10-01 16:51:37 -05001069 status, ret_values = grk.run_key_u("my_ffdc", ignore=1)
1070 if status != 'PASS':
1071 gp.qprint_error("Call to my_ffdc failed.\n")
Michael Walshc9bd2e82019-04-18 11:06:52 -05001072 # Leave a record for caller that "soft" errors occurred.
1073 soft_errors = 1
1074 gpu.save_plug_in_value(soft_errors, pgm_name)
Michael Walsh89de14a2018-10-01 16:51:37 -05001075
1076 plug_in_setup()
1077 rc, shell_rc, failed_plug_in_name = grpi.rprocess_plug_in_packages(
1078 call_point='stop_check', shell_rc=stop_test_rc(),
1079 stop_on_non_zero_rc=1)
1080 if shell_rc == stop_test_rc():
1081 message = "Stopping as requested by user.\n"
Michael Walsh80dddde2019-10-22 13:54:38 -05001082 gp.qprint_time(message)
Michael Walsh89de14a2018-10-01 16:51:37 -05001083 BuiltIn().fail(message)
1084
1085
Michael Walshff340002017-08-29 11:18:27 -05001086def obmc_boot_test_py(loc_boot_stack=None,
1087 loc_stack_mode=None,
1088 loc_quiet=None):
Michael Walsh6741f742017-02-20 16:16:38 -06001089 r"""
1090 Do main program processing.
1091 """
1092
Michael Walshff340002017-08-29 11:18:27 -05001093 global save_stack
1094
Michael Walshf75d4352019-12-05 17:01:20 -06001095 ga.set_term_options(term_requests={'pgm_names': ['process_plug_in_packages.py']})
1096
George Keishing36efbc02018-12-12 10:18:23 -06001097 gp.dprintn()
Michael Walshff340002017-08-29 11:18:27 -05001098 # Process function parms.
1099 for parm_name in main_func_parm_list:
1100 # Get parm's value.
George Keishing36efbc02018-12-12 10:18:23 -06001101 parm_value = eval("loc_" + parm_name)
1102 gp.dpvars(parm_name, parm_value)
Michael Walshff340002017-08-29 11:18:27 -05001103
George Keishing36efbc02018-12-12 10:18:23 -06001104 if parm_value is not None:
Michael Walshff340002017-08-29 11:18:27 -05001105 # Save the global value on a stack.
1106 cmd_buf = "save_stack.push(BuiltIn().get_variable_value(\"${" +\
1107 parm_name + "}\"), \"" + parm_name + "\")"
1108 gp.dpissuing(cmd_buf)
1109 exec(cmd_buf)
1110
1111 # Set the global value to the passed value.
1112 cmd_buf = "BuiltIn().set_global_variable(\"${" + parm_name +\
1113 "}\", loc_" + parm_name + ")"
1114 gp.dpissuing(cmd_buf)
1115 exec(cmd_buf)
1116
1117 gp.dprintn(save_stack.sprint_obj())
Michael Walshb5839d02017-04-12 16:11:20 -05001118
Michael Walsh6741f742017-02-20 16:16:38 -06001119 setup()
1120
Michael Walshcd9fbfd2017-09-19 12:00:08 -05001121 init_boot_pass, init_boot_fail = boot_results.return_total_pass_fail()
1122
Michael Walsha20da402017-03-31 16:27:45 -05001123 if ffdc_only:
1124 gp.qprint_timen("Caller requested ffdc_only.")
Michael Walsh986d8ae2019-07-17 10:02:23 -05001125 if do_pre_boot_plug_in_setup:
1126 pre_boot_plug_in_setup()
Michael Walsh83f4bc72017-04-20 16:49:43 -05001127 grk.run_key_u("my_ffdc")
Michael Walsh764d2f82017-04-27 16:01:08 -05001128 return
Michael Walsha20da402017-03-31 16:27:45 -05001129
Michael Walsh6741f742017-02-20 16:16:38 -06001130 # Process caller's boot_stack.
1131 while (len(boot_stack) > 0):
1132 test_loop_body()
1133
Michael Walshb5839d02017-04-12 16:11:20 -05001134 gp.qprint_timen("Finished processing stack.")
Michael Walsh30dadae2017-02-27 14:25:52 -06001135
Michael Walsh89de14a2018-10-01 16:51:37 -05001136 post_stack()
1137
Michael Walsh6741f742017-02-20 16:16:38 -06001138 # Process caller's boot_list.
1139 if len(boot_list) > 0:
1140 for ix in range(1, max_num_tests + 1):
1141 test_loop_body()
1142
Michael Walshb5839d02017-04-12 16:11:20 -05001143 gp.qprint_timen("Completed all requested boot tests.")
1144
1145 boot_pass, boot_fail = boot_results.return_total_pass_fail()
Michael Walshcd9fbfd2017-09-19 12:00:08 -05001146 new_fail = boot_fail - init_boot_fail
1147 if new_fail > boot_fail_threshold:
Michael Walshb5839d02017-04-12 16:11:20 -05001148 error_message = "Boot failures exceed the boot failure" +\
1149 " threshold:\n" +\
Michael Walshcd9fbfd2017-09-19 12:00:08 -05001150 gp.sprint_var(new_fail) +\
Michael Walshb5839d02017-04-12 16:11:20 -05001151 gp.sprint_var(boot_fail_threshold)
1152 BuiltIn().fail(gp.sprint_error(error_message))