blob: 780b8a07dee14857c96202eaa6456b78e51df4d4 [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="")
Michael Walsh0b93fbf2017-03-02 14:42:41 -060049
Michael Walsh6741f742017-02-20 16:16:38 -060050boot_lists = read_boot_lists()
Michael Walsh986d8ae2019-07-17 10:02:23 -050051
52# The maximum number of entries that can be in the boot_history global variable.
Michael Walsh815b1d52018-10-30 13:32:26 -050053max_boot_history = 10
Michael Walsh986d8ae2019-07-17 10:02:23 -050054boot_history = []
Michael Walsh6741f742017-02-20 16:16:38 -060055
Michael Walsh7dc885b2018-03-14 17:51:59 -050056state = st.return_state_constant('default_state')
Michael Walsh6741f742017-02-20 16:16:38 -060057cp_setup_called = 0
58next_boot = ""
59base_tool_dir_path = os.path.normpath(os.environ.get(
60 'AUTOBOOT_BASE_TOOL_DIR_PATH', "/tmp")) + os.sep
Michael Walshb5839d02017-04-12 16:11:20 -050061
Michael Walsh6741f742017-02-20 16:16:38 -060062ffdc_dir_path = os.path.normpath(os.environ.get('FFDC_DIR_PATH', '')) + os.sep
Michael Walsh6741f742017-02-20 16:16:38 -060063boot_success = 0
Michael Walsh6741f742017-02-20 16:16:38 -060064status_dir_path = os.environ.get('STATUS_DIR_PATH', "")
65if status_dir_path != "":
66 status_dir_path = os.path.normpath(status_dir_path) + os.sep
Michael Walshe58df1c2019-08-07 09:57:43 -050067redfish_supported = BuiltIn().get_variable_value("${REDFISH_SUPPORTED}", default=False)
68if redfish_supported:
69 default_power_on = "Redfish Power On"
70 default_power_off = "Redfish Power Off"
71else:
72 default_power_on = "REST Power On"
73 default_power_off = "REST Power Off"
Michael Walsh6741f742017-02-20 16:16:38 -060074boot_count = 0
Michael Walsh0bbd8602016-11-22 11:31:49 -060075
Michael Walsh85678942017-03-27 14:34:22 -050076LOG_LEVEL = BuiltIn().get_variable_value("${LOG_LEVEL}")
Michael Walsh986d8ae2019-07-17 10:02:23 -050077AUTOBOOT_FFDC_PREFIX = os.environ.get('AUTOBOOT_FFDC_PREFIX', '')
78ffdc_prefix = AUTOBOOT_FFDC_PREFIX
Sunil M325eb542017-08-10 07:09:43 -050079boot_start_time = ""
80boot_end_time = ""
Michael Walshff340002017-08-29 11:18:27 -050081save_stack = vs.var_stack('save_stack')
82main_func_parm_list = ['boot_stack', 'stack_mode', 'quiet']
Michael Walsh85678942017-03-27 14:34:22 -050083
84
Michael Walsh89de14a2018-10-01 16:51:37 -050085def dump_ffdc_rc():
86 r"""
87 Return the constant dump ffdc test return code value.
88
89 When a plug-in call point program returns this value, it indicates that
90 this program should collect FFDC.
91 """
92
93 return 0x00000200
94
95
96def stop_test_rc():
97 r"""
98 Return the constant stop test return code value.
99
100 When a plug-in call point program returns this value, it indicates that
101 this program should stop running.
102 """
103
104 return 0x00000200
105
106
Michael Walsh0ad0f7f2017-05-04 14:39:58 -0500107def process_host(host,
108 host_var_name=""):
Michael Walsh0ad0f7f2017-05-04 14:39:58 -0500109 r"""
110 Process a host by getting the associated host name and IP address and
111 setting them in global variables.
112
113 If the caller does not pass the host_var_name, this function will try to
114 figure out the name of the variable used by the caller for the host parm.
115 Callers are advised to explicitly specify the host_var_name when calling
116 with an exec command. In such cases, the get_arg_name cannot figure out
117 the host variable name.
118
119 This function will then create similar global variable names by
120 removing "_host" and appending "_host_name" or "_ip" to the host variable
121 name.
122
123 Example:
124
125 If a call is made like this:
126 process_host(openbmc_host)
127
128 Global variables openbmc_host_name and openbmc_ip will be set.
129
130 Description of argument(s):
131 host A host name or IP. The name of the variable used should
132 have a suffix of "_host".
133 host_var_name The name of the variable being used as the host parm.
134 """
135
136 if host_var_name == "":
137 host_var_name = gp.get_arg_name(0, 1, stack_frame_ix=2)
138
139 host_name_var_name = re.sub("host", "host_name", host_var_name)
140 ip_var_name = re.sub("host", "ip", host_var_name)
141 cmd_buf = "global " + host_name_var_name + ", " + ip_var_name + " ; " +\
142 host_name_var_name + ", " + ip_var_name + " = gm.get_host_name_ip('" +\
143 host + "')"
144 exec(cmd_buf)
145
Michael Walsh0ad0f7f2017-05-04 14:39:58 -0500146
Michael Walshb5839d02017-04-12 16:11:20 -0500147def process_pgm_parms():
Michael Walshb5839d02017-04-12 16:11:20 -0500148 r"""
149 Process the program parameters by assigning them all to corresponding
150 globals. Also, set some global values that depend on program parameters.
151 """
152
153 # Program parameter processing.
154 # Assign all program parms to python variables which are global to this
155 # module.
156
157 global parm_list
158 parm_list = BuiltIn().get_variable_value("${parm_list}")
159 # The following subset of parms should be processed as integers.
160 int_list = ['max_num_tests', 'boot_pass', 'boot_fail', 'ffdc_only',
Michael Walsh89de14a2018-10-01 16:51:37 -0500161 'boot_fail_threshold', 'delete_errlogs',
Michael Walsh986d8ae2019-07-17 10:02:23 -0500162 'call_post_stack_plug', 'do_pre_boot_plug_in_setup', 'quiet',
163 'test_mode', 'debug']
Michael Walshb5839d02017-04-12 16:11:20 -0500164 for parm in parm_list:
165 if parm in int_list:
166 sub_cmd = "int(BuiltIn().get_variable_value(\"${" + parm +\
167 "}\", \"0\"))"
168 else:
169 sub_cmd = "BuiltIn().get_variable_value(\"${" + parm + "}\")"
170 cmd_buf = "global " + parm + " ; " + parm + " = " + sub_cmd
Michael Walshff340002017-08-29 11:18:27 -0500171 gp.dpissuing(cmd_buf)
Michael Walshb5839d02017-04-12 16:11:20 -0500172 exec(cmd_buf)
Michael Walsh0ad0f7f2017-05-04 14:39:58 -0500173 if re.match(r".*_host$", parm):
174 cmd_buf = "process_host(" + parm + ", '" + parm + "')"
175 exec(cmd_buf)
176 if re.match(r".*_password$", parm):
177 # Register the value of any parm whose name ends in _password.
178 # This will cause the print functions to replace passwords with
179 # asterisks in the output.
180 cmd_buf = "gp.register_passwords(" + parm + ")"
181 exec(cmd_buf)
Michael Walshb5839d02017-04-12 16:11:20 -0500182
183 global ffdc_dir_path_style
184 global boot_list
185 global boot_stack
186 global boot_results_file_path
187 global boot_results
Michael Walsh986d8ae2019-07-17 10:02:23 -0500188 global boot_history
Michael Walshb5839d02017-04-12 16:11:20 -0500189 global ffdc_list_file_path
Michael Walshe0cf8d72017-05-17 13:20:46 -0500190 global ffdc_report_list_path
Michael Walsh600876d2017-05-30 17:58:58 -0500191 global ffdc_summary_list_path
Michael Walsha3e7b222020-02-03 15:32:16 -0600192 global boot_table
193 global valid_boot_types
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 Walsha3e7b222020-02-03 15:32:16 -0600202 boot_table = create_boot_table(boot_table_path, os_host=os_host)
203 valid_boot_types = create_valid_boot_list(boot_table)
204
Michael Walsh903e0b22017-09-19 17:00:33 -0500205 cleanup_boot_results_file()
206 boot_results_file_path = create_boot_results_file_path(pgm_name,
207 openbmc_nickname,
208 master_pid)
Michael Walshb5839d02017-04-12 16:11:20 -0500209
210 if os.path.isfile(boot_results_file_path):
211 # We've been called before in this run so we'll load the saved
Michael Walsh986d8ae2019-07-17 10:02:23 -0500212 # boot_results and boot_history objects.
213 boot_results, boot_history =\
Michael Walsh6c645742018-08-17 15:02:17 -0500214 pickle.load(open(boot_results_file_path, 'rb'))
Michael Walshb5839d02017-04-12 16:11:20 -0500215 else:
216 boot_results = boot_results(boot_table, boot_pass, boot_fail)
217
218 ffdc_list_file_path = base_tool_dir_path + openbmc_nickname +\
219 "/FFDC_FILE_LIST"
Michael Walshe0cf8d72017-05-17 13:20:46 -0500220 ffdc_report_list_path = base_tool_dir_path + openbmc_nickname +\
221 "/FFDC_REPORT_FILE_LIST"
Michael Walshb5839d02017-04-12 16:11:20 -0500222
Michael Walsh600876d2017-05-30 17:58:58 -0500223 ffdc_summary_list_path = base_tool_dir_path + openbmc_nickname +\
224 "/FFDC_SUMMARY_FILE_LIST"
225
Michael Walshb5839d02017-04-12 16:11:20 -0500226
Michael Walsh85678942017-03-27 14:34:22 -0500227def initial_plug_in_setup():
Michael Walsh85678942017-03-27 14:34:22 -0500228 r"""
229 Initialize all plug-in environment variables which do not change for the
230 duration of the program.
231
232 """
233
234 global LOG_LEVEL
235 BuiltIn().set_log_level("NONE")
236
237 BuiltIn().set_global_variable("${master_pid}", master_pid)
238 BuiltIn().set_global_variable("${FFDC_DIR_PATH}", ffdc_dir_path)
239 BuiltIn().set_global_variable("${STATUS_DIR_PATH}", status_dir_path)
240 BuiltIn().set_global_variable("${BASE_TOOL_DIR_PATH}", base_tool_dir_path)
241 BuiltIn().set_global_variable("${FFDC_LIST_FILE_PATH}",
242 ffdc_list_file_path)
Michael Walshe0cf8d72017-05-17 13:20:46 -0500243 BuiltIn().set_global_variable("${FFDC_REPORT_LIST_PATH}",
244 ffdc_report_list_path)
Michael Walsh600876d2017-05-30 17:58:58 -0500245 BuiltIn().set_global_variable("${FFDC_SUMMARY_LIST_PATH}",
246 ffdc_summary_list_path)
Michael Walsh85678942017-03-27 14:34:22 -0500247
248 BuiltIn().set_global_variable("${FFDC_DIR_PATH_STYLE}",
249 ffdc_dir_path_style)
250 BuiltIn().set_global_variable("${FFDC_CHECK}",
251 ffdc_check)
252
253 # For each program parameter, set the corresponding AUTOBOOT_ environment
254 # variable value. Also, set an AUTOBOOT_ environment variable for every
255 # element in additional_values.
256 additional_values = ["program_pid", "master_pid", "ffdc_dir_path",
257 "status_dir_path", "base_tool_dir_path",
Michael Walsh600876d2017-05-30 17:58:58 -0500258 "ffdc_list_file_path", "ffdc_report_list_path",
Michael Walsh0a3bdb42019-01-31 16:21:44 +0000259 "ffdc_summary_list_path", "execdir"]
Michael Walsh85678942017-03-27 14:34:22 -0500260
261 plug_in_vars = parm_list + additional_values
262
263 for var_name in plug_in_vars:
264 var_value = BuiltIn().get_variable_value("${" + var_name + "}")
265 var_name = var_name.upper()
266 if var_value is None:
267 var_value = ""
268 os.environ["AUTOBOOT_" + var_name] = str(var_value)
269
270 BuiltIn().set_log_level(LOG_LEVEL)
271
Michael Walsh68a61162017-04-25 11:54:06 -0500272 # Make sure the ffdc list directory exists.
273 ffdc_list_dir_path = os.path.dirname(ffdc_list_file_path) + os.sep
274 if not os.path.exists(ffdc_list_dir_path):
275 os.makedirs(ffdc_list_dir_path)
Michael Walsh85678942017-03-27 14:34:22 -0500276
Michael Walsh85678942017-03-27 14:34:22 -0500277
Michael Walsh0bbd8602016-11-22 11:31:49 -0600278def plug_in_setup():
Michael Walsh0bbd8602016-11-22 11:31:49 -0600279 r"""
Michael Walsh85678942017-03-27 14:34:22 -0500280 Initialize all changing plug-in environment variables for use by the
281 plug-in programs.
Michael Walsh0bbd8602016-11-22 11:31:49 -0600282 """
283
Michael Walsh85678942017-03-27 14:34:22 -0500284 global LOG_LEVEL
285 global test_really_running
286
287 BuiltIn().set_log_level("NONE")
288
Michael Walsh6741f742017-02-20 16:16:38 -0600289 boot_pass, boot_fail = boot_results.return_total_pass_fail()
Michael Walsh0bbd8602016-11-22 11:31:49 -0600290 if boot_pass > 1:
291 test_really_running = 1
292 else:
293 test_really_running = 0
294
Michael Walsh6741f742017-02-20 16:16:38 -0600295 BuiltIn().set_global_variable("${test_really_running}",
296 test_really_running)
297 BuiltIn().set_global_variable("${boot_type_desc}", next_boot)
Michael Walsh6741f742017-02-20 16:16:38 -0600298 BuiltIn().set_global_variable("${boot_pass}", boot_pass)
299 BuiltIn().set_global_variable("${boot_fail}", boot_fail)
300 BuiltIn().set_global_variable("${boot_success}", boot_success)
301 BuiltIn().set_global_variable("${ffdc_prefix}", ffdc_prefix)
Sunil M325eb542017-08-10 07:09:43 -0500302 BuiltIn().set_global_variable("${boot_start_time}", boot_start_time)
303 BuiltIn().set_global_variable("${boot_end_time}", boot_end_time)
Michael Walsh4c9a6452016-12-13 16:03:11 -0600304
Michael Walsh0bbd8602016-11-22 11:31:49 -0600305 # For each program parameter, set the corresponding AUTOBOOT_ environment
306 # variable value. Also, set an AUTOBOOT_ environment variable for every
307 # element in additional_values.
308 additional_values = ["boot_type_desc", "boot_success", "boot_pass",
Sunil M325eb542017-08-10 07:09:43 -0500309 "boot_fail", "test_really_running", "ffdc_prefix",
310 "boot_start_time", "boot_end_time"]
Michael Walsh0bbd8602016-11-22 11:31:49 -0600311
Michael Walsh85678942017-03-27 14:34:22 -0500312 plug_in_vars = additional_values
Michael Walsh0bbd8602016-11-22 11:31:49 -0600313
314 for var_name in plug_in_vars:
315 var_value = BuiltIn().get_variable_value("${" + var_name + "}")
316 var_name = var_name.upper()
317 if var_value is None:
318 var_value = ""
Michael Walsh6741f742017-02-20 16:16:38 -0600319 os.environ["AUTOBOOT_" + var_name] = str(var_value)
Michael Walsh0bbd8602016-11-22 11:31:49 -0600320
Michael Walsh0bbd8602016-11-22 11:31:49 -0600321 if debug:
Michael Walsh6741f742017-02-20 16:16:38 -0600322 shell_rc, out_buf = \
323 gc.cmd_fnc_u("printenv | egrep AUTOBOOT_ | sort -u")
Michael Walsh0bbd8602016-11-22 11:31:49 -0600324
Michael Walsh85678942017-03-27 14:34:22 -0500325 BuiltIn().set_log_level(LOG_LEVEL)
326
Michael Walsh0bbd8602016-11-22 11:31:49 -0600327
Michael Walshe0cf8d72017-05-17 13:20:46 -0500328def pre_boot_plug_in_setup():
329
330 # Clear the ffdc_list_file_path file. Plug-ins may now write to it.
331 try:
332 os.remove(ffdc_list_file_path)
333 except OSError:
334 pass
335
336 # Clear the ffdc_report_list_path file. Plug-ins may now write to it.
337 try:
338 os.remove(ffdc_report_list_path)
339 except OSError:
340 pass
341
Michael Walsh600876d2017-05-30 17:58:58 -0500342 # Clear the ffdc_summary_list_path file. Plug-ins may now write to it.
343 try:
344 os.remove(ffdc_summary_list_path)
345 except OSError:
346 pass
347
Michael Walshe1974b92017-08-03 13:39:51 -0500348 global ffdc_prefix
349
350 seconds = time.time()
351 loc_time = time.localtime(seconds)
352 time_string = time.strftime("%y%m%d.%H%M%S.", loc_time)
353
354 ffdc_prefix = openbmc_nickname + "." + time_string
355
Michael Walshe0cf8d72017-05-17 13:20:46 -0500356
Michael Walshf566fb12019-02-01 14:35:09 -0600357def default_sigusr1(signal_number=0,
358 frame=None):
359 r"""
360 Handle SIGUSR1 by doing nothing.
361
362 This function assists in debugging SIGUSR1 processing by printing messages
363 to stdout and to the log.html file.
364
365 Description of argument(s):
366 signal_number The signal number (should always be 10 for SIGUSR1).
367 frame The frame data.
368 """
369
Michael Walsh80dddde2019-10-22 13:54:38 -0500370 gp.qprintn()
371 gp.qprint_executing()
Michael Walshf566fb12019-02-01 14:35:09 -0600372 gp.lprint_executing()
373
374
375def set_default_siguser1():
376 r"""
377 Set the default_sigusr1 function to be the SIGUSR1 handler.
378 """
379
Michael Walsh80dddde2019-10-22 13:54:38 -0500380 gp.qprintn()
381 gp.qprint_executing()
Michael Walshf566fb12019-02-01 14:35:09 -0600382 gp.lprint_executing()
383 signal.signal(signal.SIGUSR1, default_sigusr1)
384
385
Michael Walsh6741f742017-02-20 16:16:38 -0600386def setup():
Michael Walsh0bbd8602016-11-22 11:31:49 -0600387 r"""
Michael Walsh6741f742017-02-20 16:16:38 -0600388 Do general program setup tasks.
Michael Walsh0bbd8602016-11-22 11:31:49 -0600389 """
390
Michael Walsh6741f742017-02-20 16:16:38 -0600391 global cp_setup_called
Michael Walsh81816742017-09-27 11:02:29 -0500392 global transitional_boot_selected
Michael Walsh0bbd8602016-11-22 11:31:49 -0600393
Michael Walshb5839d02017-04-12 16:11:20 -0500394 gp.qprintn()
395
Michael Walshf566fb12019-02-01 14:35:09 -0600396 set_default_siguser1()
Michael Walsh81816742017-09-27 11:02:29 -0500397 transitional_boot_selected = False
398
Michael Walsh83f4bc72017-04-20 16:49:43 -0500399 robot_pgm_dir_path = os.path.dirname(__file__) + os.sep
400 repo_bin_path = robot_pgm_dir_path.replace("/lib/", "/bin/")
Michael Walshd061c042017-05-23 14:46:57 -0500401 # If we can't find process_plug_in_packages.py, ssh_pw or
402 # validate_plug_ins.py, then we don't have our repo bin in PATH.
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -0500403 shell_rc, out_buf = gc.cmd_fnc_u("which process_plug_in_packages.py"
404 + " ssh_pw validate_plug_ins.py", quiet=1,
Michael Walshd061c042017-05-23 14:46:57 -0500405 print_output=0, show_err=0)
Michael Walshb5839d02017-04-12 16:11:20 -0500406 if shell_rc != 0:
Michael Walsh83f4bc72017-04-20 16:49:43 -0500407 os.environ['PATH'] = repo_bin_path + ":" + os.environ.get('PATH', "")
408 # Likewise, our repo lib subdir needs to be in sys.path and PYTHONPATH.
409 if robot_pgm_dir_path not in sys.path:
410 sys.path.append(robot_pgm_dir_path)
411 PYTHONPATH = os.environ.get("PYTHONPATH", "")
412 if PYTHONPATH == "":
413 os.environ['PYTHONPATH'] = robot_pgm_dir_path
414 else:
415 os.environ['PYTHONPATH'] = robot_pgm_dir_path + ":" + PYTHONPATH
Michael Walsh6741f742017-02-20 16:16:38 -0600416
417 validate_parms()
418
Michael Walshc108e422019-03-28 12:27:18 -0500419 gp.qprint_pgm_header()
Michael Walsh6741f742017-02-20 16:16:38 -0600420
George Keishingefc3ff22017-12-12 11:49:25 -0600421 grk.run_key("Set BMC Power Policy ALWAYS_POWER_OFF")
Michael Walsh11cfc8c2017-03-31 09:40:55 -0500422
Michael Walsh85678942017-03-27 14:34:22 -0500423 initial_plug_in_setup()
424
Michael Walsh6741f742017-02-20 16:16:38 -0600425 plug_in_setup()
426 rc, shell_rc, failed_plug_in_name = grpi.rprocess_plug_in_packages(
427 call_point='setup')
428 if rc != 0:
429 error_message = "Plug-in setup failed.\n"
Michael Walshc108e422019-03-28 12:27:18 -0500430 gp.print_error_report(error_message)
Michael Walsh6741f742017-02-20 16:16:38 -0600431 BuiltIn().fail(error_message)
432 # Setting cp_setup_called lets our Teardown know that it needs to call
433 # the cleanup plug-in call point.
434 cp_setup_called = 1
435
436 # Keyword "FFDC" will fail if TEST_MESSAGE is not set.
437 BuiltIn().set_global_variable("${TEST_MESSAGE}", "${EMPTY}")
Michael Walsh85678942017-03-27 14:34:22 -0500438 # FFDC_LOG_PATH is used by "FFDC" keyword.
439 BuiltIn().set_global_variable("${FFDC_LOG_PATH}", ffdc_dir_path)
Michael Walsh6741f742017-02-20 16:16:38 -0600440
Michael Walshdc80d672017-05-09 12:58:32 -0500441 # Also printed by FFDC.
442 global host_name
443 global host_ip
444 host = socket.gethostname()
445 host_name, host_ip = gm.get_host_name_ip(host)
446
Michael Walsh986d8ae2019-07-17 10:02:23 -0500447 gp.dprint_var(boot_table)
Michael Walshb5839d02017-04-12 16:11:20 -0500448 gp.dprint_var(boot_lists)
Michael Walsh0bbd8602016-11-22 11:31:49 -0600449
Michael Walsh0bbd8602016-11-22 11:31:49 -0600450
Michael Walsh6741f742017-02-20 16:16:38 -0600451def validate_parms():
Michael Walsh0bbd8602016-11-22 11:31:49 -0600452 r"""
Michael Walsh6741f742017-02-20 16:16:38 -0600453 Validate all program parameters.
Michael Walsh0bbd8602016-11-22 11:31:49 -0600454 """
455
Michael Walshb5839d02017-04-12 16:11:20 -0500456 process_pgm_parms()
Michael Walsh0bbd8602016-11-22 11:31:49 -0600457
Michael Walshb5839d02017-04-12 16:11:20 -0500458 gp.qprintn()
459
460 global openbmc_model
Michael Walsh44cef252019-08-01 12:38:56 -0500461 gv.valid_value(openbmc_host)
462 gv.valid_value(openbmc_username)
463 gv.valid_value(openbmc_password)
464 gv.valid_value(rest_username)
465 gv.valid_value(rest_password)
466 gv.valid_value(ipmi_username)
467 gv.valid_value(ipmi_password)
Michael Walsh6741f742017-02-20 16:16:38 -0600468 if os_host != "":
Michael Walsh44cef252019-08-01 12:38:56 -0500469 gv.valid_value(os_username)
470 gv.valid_value(os_password)
Michael Walsh0bbd8602016-11-22 11:31:49 -0600471
Michael Walsh6741f742017-02-20 16:16:38 -0600472 if pdu_host != "":
Michael Walsh44cef252019-08-01 12:38:56 -0500473 gv.valid_value(pdu_username)
474 gv.valid_value(pdu_password)
475 gv.valid_integer(pdu_slot_no)
Michael Walsh6741f742017-02-20 16:16:38 -0600476 if openbmc_serial_host != "":
Michael Walsh44cef252019-08-01 12:38:56 -0500477 gv.valid_integer(openbmc_serial_port)
Michael Walshb5839d02017-04-12 16:11:20 -0500478 if openbmc_model == "":
479 status, ret_values =\
480 grk.run_key_u("Get BMC System Model")
481 openbmc_model = ret_values
482 BuiltIn().set_global_variable("${openbmc_model}", openbmc_model)
Michael Walsh44cef252019-08-01 12:38:56 -0500483 gv.valid_value(openbmc_model)
484 gv.valid_integer(max_num_tests)
485 gv.valid_integer(boot_pass)
486 gv.valid_integer(boot_fail)
Michael Walsh6741f742017-02-20 16:16:38 -0600487
488 plug_in_packages_list = grpi.rvalidate_plug_ins(plug_in_dir_paths)
489 BuiltIn().set_global_variable("${plug_in_packages_list}",
490 plug_in_packages_list)
491
Michael Walsh44cef252019-08-01 12:38:56 -0500492 gv.valid_value(stack_mode, valid_values=['normal', 'skip'])
Michael Walsha20da402017-03-31 16:27:45 -0500493 if len(boot_list) == 0 and len(boot_stack) == 0 and not ffdc_only:
Michael Walsh6741f742017-02-20 16:16:38 -0600494 error_message = "You must provide either a value for either the" +\
495 " boot_list or the boot_stack parm.\n"
496 BuiltIn().fail(gp.sprint_error(error_message))
497
498 valid_boot_list(boot_list, valid_boot_types)
499 valid_boot_list(boot_stack, valid_boot_types)
500
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -0500501 selected_PDU_boots = list(set(boot_list + boot_stack)
502 & set(boot_lists['PDU_reboot']))
Michael Walsh11cfc8c2017-03-31 09:40:55 -0500503
504 if len(selected_PDU_boots) > 0 and pdu_host == "":
505 error_message = "You have selected the following boots which" +\
506 " require a PDU host but no value for pdu_host:\n"
507 error_message += gp.sprint_var(selected_PDU_boots)
Michael Walsh986d8ae2019-07-17 10:02:23 -0500508 error_message += gp.sprint_var(pdu_host, fmt=gp.blank())
Michael Walsh11cfc8c2017-03-31 09:40:55 -0500509 BuiltIn().fail(gp.sprint_error(error_message))
510
Michael Walsh6741f742017-02-20 16:16:38 -0600511 return
Michael Walsh0bbd8602016-11-22 11:31:49 -0600512
Michael Walsh0bbd8602016-11-22 11:31:49 -0600513
Michael Walsh6741f742017-02-20 16:16:38 -0600514def my_get_state():
Michael Walsh0bbd8602016-11-22 11:31:49 -0600515 r"""
Michael Walsh6741f742017-02-20 16:16:38 -0600516 Get the system state plus a little bit of wrapping.
Michael Walsh0bbd8602016-11-22 11:31:49 -0600517 """
518
Michael Walsh6741f742017-02-20 16:16:38 -0600519 global state
520
521 req_states = ['epoch_seconds'] + st.default_req_states
522
Michael Walshb5839d02017-04-12 16:11:20 -0500523 gp.qprint_timen("Getting system state.")
Michael Walsh6741f742017-02-20 16:16:38 -0600524 if test_mode:
525 state['epoch_seconds'] = int(time.time())
526 else:
Michael Walshb5839d02017-04-12 16:11:20 -0500527 state = st.get_state(req_states=req_states, quiet=quiet)
528 gp.qprint_var(state)
Michael Walsh341c21e2017-01-17 16:25:20 -0600529
Michael Walsh341c21e2017-01-17 16:25:20 -0600530
Michael Walsh45ca6e42017-09-14 17:29:12 -0500531def valid_state():
Michael Walsh45ca6e42017-09-14 17:29:12 -0500532 r"""
533 Verify that our state dictionary contains no blank values. If we don't get
534 valid state data, we cannot continue to work.
535 """
536
537 if st.compare_states(state, st.invalid_state_match, 'or'):
538 error_message = "The state dictionary contains blank fields which" +\
539 " is illegal.\n" + gp.sprint_var(state)
540 BuiltIn().fail(gp.sprint_error(error_message))
541
Michael Walsh45ca6e42017-09-14 17:29:12 -0500542
Michael Walsh6741f742017-02-20 16:16:38 -0600543def select_boot():
Michael Walsh341c21e2017-01-17 16:25:20 -0600544 r"""
545 Select a boot test to be run based on our current state and return the
546 chosen boot type.
547
548 Description of arguments:
Michael Walsh6741f742017-02-20 16:16:38 -0600549 state The state of the machine.
Michael Walsh341c21e2017-01-17 16:25:20 -0600550 """
551
Michael Walsh81816742017-09-27 11:02:29 -0500552 global transitional_boot_selected
Michael Walsh30dadae2017-02-27 14:25:52 -0600553 global boot_stack
554
Michael Walshb5839d02017-04-12 16:11:20 -0500555 gp.qprint_timen("Selecting a boot test.")
Michael Walsh6741f742017-02-20 16:16:38 -0600556
Michael Walsh81816742017-09-27 11:02:29 -0500557 if transitional_boot_selected and not boot_success:
558 prior_boot = next_boot
559 boot_candidate = boot_stack.pop()
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -0500560 gp.qprint_timen("The prior '" + next_boot + "' was chosen to"
561 + " transition to a valid state for '" + boot_candidate
562 + "' which was at the top of the boot_stack. Since"
563 + " the '" + next_boot + "' failed, the '"
564 + boot_candidate + "' has been removed from the stack"
565 + " to avoid and endless failure loop.")
Michael Walsh81816742017-09-27 11:02:29 -0500566 if len(boot_stack) == 0:
567 return ""
568
Michael Walsh6741f742017-02-20 16:16:38 -0600569 my_get_state()
Michael Walsh45ca6e42017-09-14 17:29:12 -0500570 valid_state()
Michael Walsh6741f742017-02-20 16:16:38 -0600571
Michael Walsh81816742017-09-27 11:02:29 -0500572 transitional_boot_selected = False
Michael Walsh6741f742017-02-20 16:16:38 -0600573 stack_popped = 0
574 if len(boot_stack) > 0:
575 stack_popped = 1
Michael Walshb5839d02017-04-12 16:11:20 -0500576 gp.qprint_dashes()
577 gp.qprint_var(boot_stack)
578 gp.qprint_dashes()
579 skip_boot_printed = 0
580 while len(boot_stack) > 0:
581 boot_candidate = boot_stack.pop()
582 if stack_mode == 'normal':
583 break
584 else:
585 if st.compare_states(state, boot_table[boot_candidate]['end']):
586 if not skip_boot_printed:
Michael Walshff340002017-08-29 11:18:27 -0500587 gp.qprint_var(stack_mode)
588 gp.qprintn()
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -0500589 gp.qprint_timen("Skipping the following boot tests"
590 + " which are unnecessary since their"
591 + " required end states match the"
592 + " current machine state:")
Michael Walshb5839d02017-04-12 16:11:20 -0500593 skip_boot_printed = 1
Michael Walshff340002017-08-29 11:18:27 -0500594 gp.qprint_var(boot_candidate)
Michael Walshb5839d02017-04-12 16:11:20 -0500595 boot_candidate = ""
596 if boot_candidate == "":
597 gp.qprint_dashes()
598 gp.qprint_var(boot_stack)
599 gp.qprint_dashes()
600 return boot_candidate
Michael Walsh6741f742017-02-20 16:16:38 -0600601 if st.compare_states(state, boot_table[boot_candidate]['start']):
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -0500602 gp.qprint_timen("The machine state is valid for a '"
603 + boot_candidate + "' boot test.")
Michael Walshb5839d02017-04-12 16:11:20 -0500604 gp.qprint_dashes()
605 gp.qprint_var(boot_stack)
606 gp.qprint_dashes()
Michael Walsh6741f742017-02-20 16:16:38 -0600607 return boot_candidate
Michael Walsh341c21e2017-01-17 16:25:20 -0600608 else:
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -0500609 gp.qprint_timen("The machine state does not match the required"
610 + " starting state for a '" + boot_candidate
611 + "' boot test:")
Michael Walsh986d8ae2019-07-17 10:02:23 -0500612 gp.qprint_varx("boot_table_start_entry",
613 boot_table[boot_candidate]['start'])
Michael Walsh6741f742017-02-20 16:16:38 -0600614 boot_stack.append(boot_candidate)
Michael Walsh81816742017-09-27 11:02:29 -0500615 transitional_boot_selected = True
Michael Walsh6741f742017-02-20 16:16:38 -0600616 popped_boot = boot_candidate
617
618 # Loop through your list selecting a boot_candidates
619 boot_candidates = []
620 for boot_candidate in boot_list:
621 if st.compare_states(state, boot_table[boot_candidate]['start']):
622 if stack_popped:
623 if st.compare_states(boot_table[boot_candidate]['end'],
Gunnar Mills096cd562018-03-26 10:19:12 -0500624 boot_table[popped_boot]['start']):
Michael Walsh6741f742017-02-20 16:16:38 -0600625 boot_candidates.append(boot_candidate)
626 else:
627 boot_candidates.append(boot_candidate)
628
629 if len(boot_candidates) == 0:
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -0500630 gp.qprint_timen("The user's boot list contained no boot tests"
631 + " which are valid for the current machine state.")
Michael Walsh6741f742017-02-20 16:16:38 -0600632 boot_candidate = default_power_on
633 if not st.compare_states(state, boot_table[default_power_on]['start']):
634 boot_candidate = default_power_off
635 boot_candidates.append(boot_candidate)
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -0500636 gp.qprint_timen("Using default '" + boot_candidate
637 + "' boot type to transition to valid state.")
Michael Walsh6741f742017-02-20 16:16:38 -0600638
Michael Walshb5839d02017-04-12 16:11:20 -0500639 gp.dprint_var(boot_candidates)
Michael Walsh6741f742017-02-20 16:16:38 -0600640
641 # Randomly select a boot from the candidate list.
642 boot = random.choice(boot_candidates)
Michael Walsh341c21e2017-01-17 16:25:20 -0600643
644 return boot
Michael Walsh0bbd8602016-11-22 11:31:49 -0600645
Michael Walsh55302292017-01-10 11:43:02 -0600646
Michael Walshb2e53ec2017-10-30 15:04:36 -0500647def print_defect_report(ffdc_file_list):
Michael Walsh341c21e2017-01-17 16:25:20 -0600648 r"""
649 Print a defect report.
Michael Walshb2e53ec2017-10-30 15:04:36 -0500650
651 Description of argument(s):
652 ffdc_file_list A list of files which were collected by our ffdc functions.
Michael Walsh341c21e2017-01-17 16:25:20 -0600653 """
654
Michael Walsh600876d2017-05-30 17:58:58 -0500655 # Making deliberate choice to NOT run plug_in_setup(). We don't want
656 # ffdc_prefix updated.
657 rc, shell_rc, failed_plug_in_name = grpi.rprocess_plug_in_packages(
658 call_point='ffdc_report', stop_on_plug_in_failure=0)
659
Michael Walshe0cf8d72017-05-17 13:20:46 -0500660 # Get additional header data which may have been created by ffdc plug-ins.
661 # Also, delete the individual header files to cleanup.
662 cmd_buf = "file_list=$(cat " + ffdc_report_list_path + " 2>/dev/null)" +\
663 " ; [ ! -z \"${file_list}\" ] && cat ${file_list}" +\
664 " 2>/dev/null ; rm -rf ${file_list} 2>/dev/null || :"
665 shell_rc, more_header_info = gc.cmd_fnc_u(cmd_buf, print_output=0,
666 show_err=0)
667
Michael Walshb2e53ec2017-10-30 15:04:36 -0500668 # Get additional summary data which may have been created by ffdc plug-ins.
Michael Walsh600876d2017-05-30 17:58:58 -0500669 # Also, delete the individual header files to cleanup.
670 cmd_buf = "file_list=$(cat " + ffdc_summary_list_path + " 2>/dev/null)" +\
671 " ; [ ! -z \"${file_list}\" ] && cat ${file_list}" +\
672 " 2>/dev/null ; rm -rf ${file_list} 2>/dev/null || :"
673 shell_rc, ffdc_summary_info = gc.cmd_fnc_u(cmd_buf, print_output=0,
674 show_err=0)
675
Michael Walshb2e53ec2017-10-30 15:04:36 -0500676 # ffdc_list_file_path contains a list of any ffdc files created by plug-
677 # ins, etc. Read that data into a list.
Michael Walsh341c21e2017-01-17 16:25:20 -0600678 try:
Michael Walshb2e53ec2017-10-30 15:04:36 -0500679 plug_in_ffdc_list = \
680 open(ffdc_list_file_path, 'r').read().rstrip("\n").split("\n")
George Keishing36efbc02018-12-12 10:18:23 -0600681 plug_in_ffdc_list = list(filter(None, plug_in_ffdc_list))
Michael Walsh341c21e2017-01-17 16:25:20 -0600682 except IOError:
Michael Walshb2e53ec2017-10-30 15:04:36 -0500683 plug_in_ffdc_list = []
684
685 # Combine the files from plug_in_ffdc_list with the ffdc_file_list passed
686 # in. Eliminate duplicates and sort the list.
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -0500687 ffdc_file_list = sorted(set(ffdc_file_list + plug_in_ffdc_list))
Michael Walshb2e53ec2017-10-30 15:04:36 -0500688
689 if status_file_path != "":
690 ffdc_file_list.insert(0, status_file_path)
691
692 # Convert the list to a printable list.
693 printable_ffdc_file_list = "\n".join(ffdc_file_list)
Michael Walsh341c21e2017-01-17 16:25:20 -0600694
Michael Walsh68a61162017-04-25 11:54:06 -0500695 # Open ffdc_file_list for writing. We will write a complete list of
696 # FFDC files to it for possible use by plug-ins like cp_stop_check.
697 ffdc_list_file = open(ffdc_list_file_path, 'w')
Michael Walshb2e53ec2017-10-30 15:04:36 -0500698 ffdc_list_file.write(printable_ffdc_file_list + "\n")
699 ffdc_list_file.close()
700
701 indent = 0
702 width = 90
703 linefeed = 1
704 char = "="
Michael Walsh68a61162017-04-25 11:54:06 -0500705
706 gp.qprintn()
Michael Walshb2e53ec2017-10-30 15:04:36 -0500707 gp.qprint_dashes(indent, width, linefeed, char)
Michael Walsh68a61162017-04-25 11:54:06 -0500708 gp.qprintn("Copy this data to the defect:\n")
709
Michael Walshe0cf8d72017-05-17 13:20:46 -0500710 if len(more_header_info) > 0:
Michael Walshff340002017-08-29 11:18:27 -0500711 gp.qprintn(more_header_info)
Michael Walshdc80d672017-05-09 12:58:32 -0500712 gp.qpvars(host_name, host_ip, openbmc_nickname, openbmc_host,
713 openbmc_host_name, openbmc_ip, openbmc_username,
Michael Walsh0a3bdb42019-01-31 16:21:44 +0000714 openbmc_password, rest_username, rest_password, ipmi_username,
715 ipmi_password, os_host, os_host_name, os_ip, os_username,
Michael Walshdc80d672017-05-09 12:58:32 -0500716 os_password, pdu_host, pdu_host_name, pdu_ip, pdu_username,
717 pdu_password, pdu_slot_no, openbmc_serial_host,
718 openbmc_serial_host_name, openbmc_serial_ip, openbmc_serial_port)
Michael Walsh68a61162017-04-25 11:54:06 -0500719
720 gp.qprintn()
Michael Walsh986d8ae2019-07-17 10:02:23 -0500721 print_boot_history(boot_history)
Michael Walsh68a61162017-04-25 11:54:06 -0500722 gp.qprintn()
723 gp.qprint_var(state)
Michael Walshb5839d02017-04-12 16:11:20 -0500724 gp.qprintn()
725 gp.qprintn("FFDC data files:")
Michael Walshb2e53ec2017-10-30 15:04:36 -0500726 gp.qprintn(printable_ffdc_file_list)
Michael Walshb5839d02017-04-12 16:11:20 -0500727 gp.qprintn()
Michael Walsh341c21e2017-01-17 16:25:20 -0600728
Michael Walsh600876d2017-05-30 17:58:58 -0500729 if len(ffdc_summary_info) > 0:
Michael Walshff340002017-08-29 11:18:27 -0500730 gp.qprintn(ffdc_summary_info)
Michael Walsh600876d2017-05-30 17:58:58 -0500731
Michael Walshb2e53ec2017-10-30 15:04:36 -0500732 gp.qprint_dashes(indent, width, linefeed, char)
Michael Walsh68a61162017-04-25 11:54:06 -0500733
Michael Walsh6741f742017-02-20 16:16:38 -0600734
Michael Walsh6741f742017-02-20 16:16:38 -0600735def my_ffdc():
Michael Walsh6741f742017-02-20 16:16:38 -0600736 r"""
737 Collect FFDC data.
738 """
739
740 global state
741
742 plug_in_setup()
743 rc, shell_rc, failed_plug_in_name = grpi.rprocess_plug_in_packages(
Michael Walsh600876d2017-05-30 17:58:58 -0500744 call_point='ffdc', stop_on_plug_in_failure=0)
Michael Walsh6741f742017-02-20 16:16:38 -0600745
746 AUTOBOOT_FFDC_PREFIX = os.environ['AUTOBOOT_FFDC_PREFIX']
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -0500747 status, ffdc_file_list = grk.run_key_u("FFDC ffdc_prefix="
748 + AUTOBOOT_FFDC_PREFIX
749 + " ffdc_function_list="
750 + ffdc_function_list, ignore=1)
Michael Walsh83f4bc72017-04-20 16:49:43 -0500751 if status != 'PASS':
Michael Walshff340002017-08-29 11:18:27 -0500752 gp.qprint_error("Call to ffdc failed.\n")
Michael Walshc9bd2e82019-04-18 11:06:52 -0500753 if type(ffdc_file_list) is not list:
754 ffdc_file_list = []
755 # Leave a record for caller that "soft" errors occurred.
756 soft_errors = 1
757 gpu.save_plug_in_value(soft_errors, pgm_name)
Michael Walsh6741f742017-02-20 16:16:38 -0600758
759 my_get_state()
760
Michael Walshb2e53ec2017-10-30 15:04:36 -0500761 print_defect_report(ffdc_file_list)
Michael Walsh6741f742017-02-20 16:16:38 -0600762
Michael Walsh6741f742017-02-20 16:16:38 -0600763
Michael Walsh6741f742017-02-20 16:16:38 -0600764def print_test_start_message(boot_keyword):
Michael Walsh6741f742017-02-20 16:16:38 -0600765 r"""
766 Print a message indicating what boot test is about to run.
767
768 Description of arguments:
769 boot_keyword The name of the boot which is to be run
770 (e.g. "BMC Power On").
771 """
772
Michael Walsh986d8ae2019-07-17 10:02:23 -0500773 global boot_history
Sunil M325eb542017-08-10 07:09:43 -0500774 global boot_start_time
Michael Walsh6741f742017-02-20 16:16:38 -0600775
776 doing_msg = gp.sprint_timen("Doing \"" + boot_keyword + "\".")
Sunil M325eb542017-08-10 07:09:43 -0500777
778 # Set boot_start_time for use by plug-ins.
779 boot_start_time = doing_msg[1:33]
780 gp.qprint_var(boot_start_time)
781
Michael Walshb5839d02017-04-12 16:11:20 -0500782 gp.qprint(doing_msg)
Michael Walsh6741f742017-02-20 16:16:38 -0600783
Michael Walsh986d8ae2019-07-17 10:02:23 -0500784 update_boot_history(boot_history, doing_msg, max_boot_history)
Michael Walsh6741f742017-02-20 16:16:38 -0600785
Michael Walsh6741f742017-02-20 16:16:38 -0600786
Michael Walshf566fb12019-02-01 14:35:09 -0600787def stop_boot_test(signal_number=0,
788 frame=None):
789 r"""
790 Handle SIGUSR1 by aborting the boot test that is running.
791
792 Description of argument(s):
793 signal_number The signal number (should always be 10 for SIGUSR1).
794 frame The frame data.
795 """
796
Michael Walsh80dddde2019-10-22 13:54:38 -0500797 gp.qprintn()
798 gp.qprint_executing()
Michael Walshf566fb12019-02-01 14:35:09 -0600799 gp.lprint_executing()
800
801 # Restore original sigusr1 handler.
802 set_default_siguser1()
803
804 message = "The caller has asked that the boot test be stopped and marked"
805 message += " as a failure."
806
807 function_stack = gm.get_function_stack()
808 if "wait_state" in function_stack:
Michael Walshc44aa532019-06-14 13:33:29 -0500809 st.set_exit_wait_early_message(message)
Michael Walshf566fb12019-02-01 14:35:09 -0600810 else:
811 BuiltIn().fail(gp.sprint_error(message))
812
813
Michael Walsh6741f742017-02-20 16:16:38 -0600814def run_boot(boot):
Michael Walsh6741f742017-02-20 16:16:38 -0600815 r"""
816 Run the specified boot.
817
818 Description of arguments:
819 boot The name of the boot test to be performed.
820 """
821
822 global state
823
Michael Walshf566fb12019-02-01 14:35:09 -0600824 signal.signal(signal.SIGUSR1, stop_boot_test)
825 gp.qprint_timen("stop_boot_test is armed.")
826
Michael Walsh6741f742017-02-20 16:16:38 -0600827 print_test_start_message(boot)
828
829 plug_in_setup()
830 rc, shell_rc, failed_plug_in_name = \
831 grpi.rprocess_plug_in_packages(call_point="pre_boot")
832 if rc != 0:
833 error_message = "Plug-in failed with non-zero return code.\n" +\
Michael Walsh986d8ae2019-07-17 10:02:23 -0500834 gp.sprint_var(rc, fmt=gp.hexa())
Michael Walshf566fb12019-02-01 14:35:09 -0600835 set_default_siguser1()
Michael Walsh6741f742017-02-20 16:16:38 -0600836 BuiltIn().fail(gp.sprint_error(error_message))
837
838 if test_mode:
839 # In test mode, we'll pretend the boot worked by assigning its
840 # required end state to the default state value.
Michael Walsh30dadae2017-02-27 14:25:52 -0600841 state = st.strip_anchor_state(boot_table[boot]['end'])
Michael Walsh6741f742017-02-20 16:16:38 -0600842 else:
843 # Assertion: We trust that the state data was made fresh by the
844 # caller.
845
Michael Walshb5839d02017-04-12 16:11:20 -0500846 gp.qprintn()
Michael Walsh6741f742017-02-20 16:16:38 -0600847
848 if boot_table[boot]['method_type'] == "keyword":
Michael Walsh0b93fbf2017-03-02 14:42:41 -0600849 rk.my_run_keywords(boot_table[boot].get('lib_file_path', ''),
Michael Walshb5839d02017-04-12 16:11:20 -0500850 boot_table[boot]['method'],
851 quiet=quiet)
Michael Walsh6741f742017-02-20 16:16:38 -0600852
853 if boot_table[boot]['bmc_reboot']:
854 st.wait_for_comm_cycle(int(state['epoch_seconds']))
Michael Walsh30dadae2017-02-27 14:25:52 -0600855 plug_in_setup()
856 rc, shell_rc, failed_plug_in_name = \
857 grpi.rprocess_plug_in_packages(call_point="post_reboot")
858 if rc != 0:
Michael Walsh0b93fbf2017-03-02 14:42:41 -0600859 error_message = "Plug-in failed with non-zero return code.\n"
Michael Walsh986d8ae2019-07-17 10:02:23 -0500860 error_message += gp.sprint_var(rc, fmt=gp.hexa())
Michael Walshf566fb12019-02-01 14:35:09 -0600861 set_default_siguser1()
Michael Walsh30dadae2017-02-27 14:25:52 -0600862 BuiltIn().fail(gp.sprint_error(error_message))
Michael Walsh6741f742017-02-20 16:16:38 -0600863 else:
864 match_state = st.anchor_state(state)
865 del match_state['epoch_seconds']
866 # Wait for the state to change in any way.
867 st.wait_state(match_state, wait_time=state_change_timeout,
Michael Walsh600876d2017-05-30 17:58:58 -0500868 interval="10 seconds", invert=1)
Michael Walsh6741f742017-02-20 16:16:38 -0600869
Michael Walshb5839d02017-04-12 16:11:20 -0500870 gp.qprintn()
Michael Walsh6741f742017-02-20 16:16:38 -0600871 if boot_table[boot]['end']['chassis'] == "Off":
872 boot_timeout = power_off_timeout
873 else:
874 boot_timeout = power_on_timeout
875 st.wait_state(boot_table[boot]['end'], wait_time=boot_timeout,
Michael Walsh600876d2017-05-30 17:58:58 -0500876 interval="10 seconds")
Michael Walsh6741f742017-02-20 16:16:38 -0600877
878 plug_in_setup()
879 rc, shell_rc, failed_plug_in_name = \
880 grpi.rprocess_plug_in_packages(call_point="post_boot")
881 if rc != 0:
882 error_message = "Plug-in failed with non-zero return code.\n" +\
Michael Walsh986d8ae2019-07-17 10:02:23 -0500883 gp.sprint_var(rc, fmt=gp.hexa())
Michael Walshf566fb12019-02-01 14:35:09 -0600884 set_default_siguser1()
Michael Walsh6741f742017-02-20 16:16:38 -0600885 BuiltIn().fail(gp.sprint_error(error_message))
886
Michael Walshf566fb12019-02-01 14:35:09 -0600887 # Restore original sigusr1 handler.
888 set_default_siguser1()
889
Michael Walsh6741f742017-02-20 16:16:38 -0600890
Michael Walsh6741f742017-02-20 16:16:38 -0600891def test_loop_body():
Michael Walsh6741f742017-02-20 16:16:38 -0600892 r"""
893 The main loop body for the loop in main_py.
894
895 Description of arguments:
896 boot_count The iteration number (starts at 1).
897 """
898
899 global boot_count
900 global state
901 global next_boot
902 global boot_success
Sunil M325eb542017-08-10 07:09:43 -0500903 global boot_end_time
Michael Walsh6741f742017-02-20 16:16:38 -0600904
Michael Walshb5839d02017-04-12 16:11:20 -0500905 gp.qprintn()
Michael Walsh6741f742017-02-20 16:16:38 -0600906
907 next_boot = select_boot()
Michael Walshb5839d02017-04-12 16:11:20 -0500908 if next_boot == "":
909 return True
Michael Walsh6741f742017-02-20 16:16:38 -0600910
Michael Walshb5839d02017-04-12 16:11:20 -0500911 boot_count += 1
912 gp.qprint_timen("Starting boot " + str(boot_count) + ".")
Michael Walsh6741f742017-02-20 16:16:38 -0600913
Michael Walshe0cf8d72017-05-17 13:20:46 -0500914 pre_boot_plug_in_setup()
Michael Walsh6741f742017-02-20 16:16:38 -0600915
916 cmd_buf = ["run_boot", next_boot]
917 boot_status, msg = BuiltIn().run_keyword_and_ignore_error(*cmd_buf)
918 if boot_status == "FAIL":
Michael Walshb5839d02017-04-12 16:11:20 -0500919 gp.qprint(msg)
Michael Walsh6741f742017-02-20 16:16:38 -0600920
Michael Walshb5839d02017-04-12 16:11:20 -0500921 gp.qprintn()
Michael Walsh6741f742017-02-20 16:16:38 -0600922 if boot_status == "PASS":
923 boot_success = 1
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -0500924 completion_msg = gp.sprint_timen("BOOT_SUCCESS: \"" + next_boot
925 + "\" succeeded.")
Michael Walsh6741f742017-02-20 16:16:38 -0600926 else:
927 boot_success = 0
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -0500928 completion_msg = gp.sprint_timen("BOOT_FAILED: \"" + next_boot
929 + "\" failed.")
Sunil M325eb542017-08-10 07:09:43 -0500930
931 # Set boot_end_time for use by plug-ins.
932 boot_end_time = completion_msg[1:33]
933 gp.qprint_var(boot_end_time)
934
935 gp.qprint(completion_msg)
Michael Walsh6741f742017-02-20 16:16:38 -0600936
937 boot_results.update(next_boot, boot_status)
938
939 plug_in_setup()
940 # NOTE: A post_test_case call point failure is NOT counted as a boot
941 # failure.
942 rc, shell_rc, failed_plug_in_name = grpi.rprocess_plug_in_packages(
Michael Walsh600876d2017-05-30 17:58:58 -0500943 call_point='post_test_case', stop_on_plug_in_failure=0)
Michael Walsh6741f742017-02-20 16:16:38 -0600944
945 plug_in_setup()
946 rc, shell_rc, failed_plug_in_name = grpi.rprocess_plug_in_packages(
Michael Walsh89de14a2018-10-01 16:51:37 -0500947 call_point='ffdc_check', shell_rc=dump_ffdc_rc(),
Michael Walsh6741f742017-02-20 16:16:38 -0600948 stop_on_plug_in_failure=1, stop_on_non_zero_rc=1)
Michael Walsh12059e22019-03-21 11:03:45 -0500949 if ffdc_check == "All" or\
Michael Walsh89de14a2018-10-01 16:51:37 -0500950 shell_rc == dump_ffdc_rc():
Michael Walsh83f4bc72017-04-20 16:49:43 -0500951 status, ret_values = grk.run_key_u("my_ffdc", ignore=1)
952 if status != 'PASS':
Michael Walshff340002017-08-29 11:18:27 -0500953 gp.qprint_error("Call to my_ffdc failed.\n")
Michael Walshc9bd2e82019-04-18 11:06:52 -0500954 # Leave a record for caller that "soft" errors occurred.
955 soft_errors = 1
956 gpu.save_plug_in_value(soft_errors, pgm_name)
Michael Walsh6741f742017-02-20 16:16:38 -0600957
Michael Walshaabef1e2017-09-20 15:16:17 -0500958 if delete_errlogs:
959 # We need to purge error logs between boots or they build up.
960 grk.run_key("Delete Error logs", ignore=1)
Michael Walshd139f282017-04-04 18:00:23 -0500961
Michael Walsh952f9b02017-03-09 13:11:14 -0600962 boot_results.print_report()
Michael Walshb5839d02017-04-12 16:11:20 -0500963 gp.qprint_timen("Finished boot " + str(boot_count) + ".")
Michael Walsh952f9b02017-03-09 13:11:14 -0600964
Michael Walsh6741f742017-02-20 16:16:38 -0600965 plug_in_setup()
966 rc, shell_rc, failed_plug_in_name = grpi.rprocess_plug_in_packages(
Michael Walsh89de14a2018-10-01 16:51:37 -0500967 call_point='stop_check', shell_rc=stop_test_rc(),
968 stop_on_non_zero_rc=1)
969 if shell_rc == stop_test_rc():
Michael Walsh3ba8ecd2018-04-24 11:33:25 -0500970 message = "Stopping as requested by user.\n"
Michael Walsh80dddde2019-10-22 13:54:38 -0500971 gp.qprint_time(message)
Michael Walsh3ba8ecd2018-04-24 11:33:25 -0500972 BuiltIn().fail(message)
Michael Walsh6741f742017-02-20 16:16:38 -0600973
Michael Walshd139f282017-04-04 18:00:23 -0500974 # This should help prevent ConnectionErrors.
Michael Walsh0960b382017-06-22 16:23:37 -0500975 grk.run_key_u("Close All Connections")
Michael Walshd139f282017-04-04 18:00:23 -0500976
Michael Walsh6741f742017-02-20 16:16:38 -0600977 return True
978
Michael Walsh6741f742017-02-20 16:16:38 -0600979
Michael Walsh83f4bc72017-04-20 16:49:43 -0500980def obmc_boot_test_teardown():
Michael Walsh6741f742017-02-20 16:16:38 -0600981 r"""
Michael Walshf75d4352019-12-05 17:01:20 -0600982 Clean up after the main keyword.
Michael Walsh6741f742017-02-20 16:16:38 -0600983 """
Michael Walshf75d4352019-12-05 17:01:20 -0600984 gp.qprint_executing()
985
986 if ga.psutil_imported:
987 ga.terminate_descendants()
Michael Walsh6741f742017-02-20 16:16:38 -0600988
989 if cp_setup_called:
990 plug_in_setup()
991 rc, shell_rc, failed_plug_in_name = grpi.rprocess_plug_in_packages(
Michael Walsh600876d2017-05-30 17:58:58 -0500992 call_point='cleanup', stop_on_plug_in_failure=0)
Michael Walsh6741f742017-02-20 16:16:38 -0600993
Michael Walsh600876d2017-05-30 17:58:58 -0500994 if 'boot_results_file_path' in globals():
Michael Walsh986d8ae2019-07-17 10:02:23 -0500995 # Save boot_results and boot_history objects to a file in case they are
Michael Walsh6c645742018-08-17 15:02:17 -0500996 # needed again.
Michael Walsh600876d2017-05-30 17:58:58 -0500997 gp.qprint_timen("Saving boot_results to the following path.")
998 gp.qprint_var(boot_results_file_path)
Michael Walsh986d8ae2019-07-17 10:02:23 -0500999 pickle.dump((boot_results, boot_history),
Michael Walsh6c645742018-08-17 15:02:17 -05001000 open(boot_results_file_path, 'wb'),
Michael Walsh600876d2017-05-30 17:58:58 -05001001 pickle.HIGHEST_PROTOCOL)
Michael Walsh0b93fbf2017-03-02 14:42:41 -06001002
Michael Walshff340002017-08-29 11:18:27 -05001003 global save_stack
1004 # Restore any global values saved on the save_stack.
1005 for parm_name in main_func_parm_list:
1006 # Get the parm_value if it was saved on the stack.
1007 try:
1008 parm_value = save_stack.pop(parm_name)
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -05001009 except BaseException:
Michael Walshff340002017-08-29 11:18:27 -05001010 # If it was not saved, no further action is required.
1011 continue
1012
1013 # Restore the saved value.
1014 cmd_buf = "BuiltIn().set_global_variable(\"${" + parm_name +\
1015 "}\", parm_value)"
1016 gp.dpissuing(cmd_buf)
1017 exec(cmd_buf)
1018
1019 gp.dprintn(save_stack.sprint_obj())
1020
Michael Walsh6741f742017-02-20 16:16:38 -06001021
Michael Walshc9116812017-03-10 14:23:06 -06001022def test_teardown():
Michael Walshc9116812017-03-10 14:23:06 -06001023 r"""
1024 Clean up after this test case.
1025 """
1026
1027 gp.qprintn()
Michael Walshf75d4352019-12-05 17:01:20 -06001028 gp.qprint_executing()
1029
1030 if ga.psutil_imported:
1031 ga.terminate_descendants()
1032
Michael Walshc9116812017-03-10 14:23:06 -06001033 cmd_buf = ["Print Error",
1034 "A keyword timeout occurred ending this program.\n"]
1035 BuiltIn().run_keyword_if_timeout_occurred(*cmd_buf)
1036
Michael Walshc108e422019-03-28 12:27:18 -05001037 gp.qprint_pgm_footer()
Michael Walshb5839d02017-04-12 16:11:20 -05001038
Michael Walshc9116812017-03-10 14:23:06 -06001039
Michael Walsh89de14a2018-10-01 16:51:37 -05001040def post_stack():
1041 r"""
1042 Process post_stack plug-in programs.
1043 """
1044
1045 if not call_post_stack_plug:
1046 # The caller does not wish to have post_stack plug-in processing done.
1047 return
1048
1049 global boot_success
1050
1051 # NOTE: A post_stack call-point failure is NOT counted as a boot failure.
1052 pre_boot_plug_in_setup()
1053 # For the purposes of the following plug-ins, mark the "boot" as a success.
1054 boot_success = 1
1055 plug_in_setup()
Michael Walsh815b1d52018-10-30 13:32:26 -05001056 rc, shell_rc, failed_plug_in_name, history =\
1057 grpi.rprocess_plug_in_packages(call_point='post_stack',
1058 stop_on_plug_in_failure=0,
1059 return_history=True)
Michael Walsh986d8ae2019-07-17 10:02:23 -05001060 for doing_msg in history:
1061 update_boot_history(boot_history, doing_msg, max_boot_history)
Michael Walsh815b1d52018-10-30 13:32:26 -05001062 if rc != 0:
1063 boot_success = 0
Michael Walsh89de14a2018-10-01 16:51:37 -05001064
1065 plug_in_setup()
Michael Walsh815b1d52018-10-30 13:32:26 -05001066 rc, shell_rc, failed_plug_in_name =\
1067 grpi.rprocess_plug_in_packages(call_point='ffdc_check',
1068 shell_rc=dump_ffdc_rc(),
1069 stop_on_plug_in_failure=1,
1070 stop_on_non_zero_rc=1)
1071 if shell_rc == dump_ffdc_rc():
Michael Walsh89de14a2018-10-01 16:51:37 -05001072 status, ret_values = grk.run_key_u("my_ffdc", ignore=1)
1073 if status != 'PASS':
1074 gp.qprint_error("Call to my_ffdc failed.\n")
Michael Walshc9bd2e82019-04-18 11:06:52 -05001075 # Leave a record for caller that "soft" errors occurred.
1076 soft_errors = 1
1077 gpu.save_plug_in_value(soft_errors, pgm_name)
Michael Walsh89de14a2018-10-01 16:51:37 -05001078
1079 plug_in_setup()
1080 rc, shell_rc, failed_plug_in_name = grpi.rprocess_plug_in_packages(
1081 call_point='stop_check', shell_rc=stop_test_rc(),
1082 stop_on_non_zero_rc=1)
1083 if shell_rc == stop_test_rc():
1084 message = "Stopping as requested by user.\n"
Michael Walsh80dddde2019-10-22 13:54:38 -05001085 gp.qprint_time(message)
Michael Walsh89de14a2018-10-01 16:51:37 -05001086 BuiltIn().fail(message)
1087
1088
Michael Walshff340002017-08-29 11:18:27 -05001089def obmc_boot_test_py(loc_boot_stack=None,
1090 loc_stack_mode=None,
1091 loc_quiet=None):
Michael Walsh6741f742017-02-20 16:16:38 -06001092 r"""
1093 Do main program processing.
1094 """
1095
Michael Walshff340002017-08-29 11:18:27 -05001096 global save_stack
1097
Michael Walshf75d4352019-12-05 17:01:20 -06001098 ga.set_term_options(term_requests={'pgm_names': ['process_plug_in_packages.py']})
1099
George Keishing36efbc02018-12-12 10:18:23 -06001100 gp.dprintn()
Michael Walshff340002017-08-29 11:18:27 -05001101 # Process function parms.
1102 for parm_name in main_func_parm_list:
1103 # Get parm's value.
George Keishing36efbc02018-12-12 10:18:23 -06001104 parm_value = eval("loc_" + parm_name)
1105 gp.dpvars(parm_name, parm_value)
Michael Walshff340002017-08-29 11:18:27 -05001106
George Keishing36efbc02018-12-12 10:18:23 -06001107 if parm_value is not None:
Michael Walshff340002017-08-29 11:18:27 -05001108 # Save the global value on a stack.
1109 cmd_buf = "save_stack.push(BuiltIn().get_variable_value(\"${" +\
1110 parm_name + "}\"), \"" + parm_name + "\")"
1111 gp.dpissuing(cmd_buf)
1112 exec(cmd_buf)
1113
1114 # Set the global value to the passed value.
1115 cmd_buf = "BuiltIn().set_global_variable(\"${" + parm_name +\
1116 "}\", loc_" + parm_name + ")"
1117 gp.dpissuing(cmd_buf)
1118 exec(cmd_buf)
1119
1120 gp.dprintn(save_stack.sprint_obj())
Michael Walshb5839d02017-04-12 16:11:20 -05001121
Michael Walsh6741f742017-02-20 16:16:38 -06001122 setup()
1123
Michael Walshcd9fbfd2017-09-19 12:00:08 -05001124 init_boot_pass, init_boot_fail = boot_results.return_total_pass_fail()
1125
Michael Walsha20da402017-03-31 16:27:45 -05001126 if ffdc_only:
1127 gp.qprint_timen("Caller requested ffdc_only.")
Michael Walsh986d8ae2019-07-17 10:02:23 -05001128 if do_pre_boot_plug_in_setup:
1129 pre_boot_plug_in_setup()
Michael Walsh83f4bc72017-04-20 16:49:43 -05001130 grk.run_key_u("my_ffdc")
Michael Walsh764d2f82017-04-27 16:01:08 -05001131 return
Michael Walsha20da402017-03-31 16:27:45 -05001132
Michael Walsh6741f742017-02-20 16:16:38 -06001133 # Process caller's boot_stack.
1134 while (len(boot_stack) > 0):
1135 test_loop_body()
1136
Michael Walshb5839d02017-04-12 16:11:20 -05001137 gp.qprint_timen("Finished processing stack.")
Michael Walsh30dadae2017-02-27 14:25:52 -06001138
Michael Walsh89de14a2018-10-01 16:51:37 -05001139 post_stack()
1140
Michael Walsh6741f742017-02-20 16:16:38 -06001141 # Process caller's boot_list.
1142 if len(boot_list) > 0:
1143 for ix in range(1, max_num_tests + 1):
1144 test_loop_body()
1145
Michael Walshb5839d02017-04-12 16:11:20 -05001146 gp.qprint_timen("Completed all requested boot tests.")
1147
1148 boot_pass, boot_fail = boot_results.return_total_pass_fail()
Michael Walshcd9fbfd2017-09-19 12:00:08 -05001149 new_fail = boot_fail - init_boot_fail
1150 if new_fail > boot_fail_threshold:
Michael Walshb5839d02017-04-12 16:11:20 -05001151 error_message = "Boot failures exceed the boot failure" +\
1152 " threshold:\n" +\
Michael Walshcd9fbfd2017-09-19 12:00:08 -05001153 gp.sprint_var(new_fail) +\
Michael Walshb5839d02017-04-12 16:11:20 -05001154 gp.sprint_var(boot_fail_threshold)
1155 BuiltIn().fail(gp.sprint_error(error_message))