blob: 000a4972278bd019ad8c725677b6b6e88eeaeca4 [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"
Michael Walsh409ad352020-02-06 11:46:35 -060071 delete_errlogs_cmd = "Delete Error Logs"
72 # TODO: delete_errlogs_cmd="Redfish Purge Event Log"
Michael Walshe58df1c2019-08-07 09:57:43 -050073else:
74 default_power_on = "REST Power On"
75 default_power_off = "REST Power Off"
Michael Walsh409ad352020-02-06 11:46:35 -060076 delete_errlogs_cmd = "Delete Error Logs"
Michael Walsh6741f742017-02-20 16:16:38 -060077boot_count = 0
Michael Walsh0bbd8602016-11-22 11:31:49 -060078
Michael Walsh85678942017-03-27 14:34:22 -050079LOG_LEVEL = BuiltIn().get_variable_value("${LOG_LEVEL}")
Michael Walsh986d8ae2019-07-17 10:02:23 -050080AUTOBOOT_FFDC_PREFIX = os.environ.get('AUTOBOOT_FFDC_PREFIX', '')
81ffdc_prefix = AUTOBOOT_FFDC_PREFIX
Sunil M325eb542017-08-10 07:09:43 -050082boot_start_time = ""
83boot_end_time = ""
Michael Walshff340002017-08-29 11:18:27 -050084save_stack = vs.var_stack('save_stack')
85main_func_parm_list = ['boot_stack', 'stack_mode', 'quiet']
Michael Walsh85678942017-03-27 14:34:22 -050086
87
Michael Walsh89de14a2018-10-01 16:51:37 -050088def dump_ffdc_rc():
89 r"""
90 Return the constant dump ffdc test return code value.
91
92 When a plug-in call point program returns this value, it indicates that
93 this program should collect FFDC.
94 """
95
96 return 0x00000200
97
98
99def stop_test_rc():
100 r"""
101 Return the constant stop test return code value.
102
103 When a plug-in call point program returns this value, it indicates that
104 this program should stop running.
105 """
106
107 return 0x00000200
108
109
Michael Walsh0ad0f7f2017-05-04 14:39:58 -0500110def process_host(host,
111 host_var_name=""):
Michael Walsh0ad0f7f2017-05-04 14:39:58 -0500112 r"""
113 Process a host by getting the associated host name and IP address and
114 setting them in global variables.
115
116 If the caller does not pass the host_var_name, this function will try to
117 figure out the name of the variable used by the caller for the host parm.
118 Callers are advised to explicitly specify the host_var_name when calling
119 with an exec command. In such cases, the get_arg_name cannot figure out
120 the host variable name.
121
122 This function will then create similar global variable names by
123 removing "_host" and appending "_host_name" or "_ip" to the host variable
124 name.
125
126 Example:
127
128 If a call is made like this:
129 process_host(openbmc_host)
130
131 Global variables openbmc_host_name and openbmc_ip will be set.
132
133 Description of argument(s):
134 host A host name or IP. The name of the variable used should
135 have a suffix of "_host".
136 host_var_name The name of the variable being used as the host parm.
137 """
138
139 if host_var_name == "":
140 host_var_name = gp.get_arg_name(0, 1, stack_frame_ix=2)
141
142 host_name_var_name = re.sub("host", "host_name", host_var_name)
143 ip_var_name = re.sub("host", "ip", host_var_name)
144 cmd_buf = "global " + host_name_var_name + ", " + ip_var_name + " ; " +\
145 host_name_var_name + ", " + ip_var_name + " = gm.get_host_name_ip('" +\
146 host + "')"
147 exec(cmd_buf)
148
Michael Walsh0ad0f7f2017-05-04 14:39:58 -0500149
Michael Walshb5839d02017-04-12 16:11:20 -0500150def process_pgm_parms():
Michael Walshb5839d02017-04-12 16:11:20 -0500151 r"""
152 Process the program parameters by assigning them all to corresponding
153 globals. Also, set some global values that depend on program parameters.
154 """
155
156 # Program parameter processing.
157 # Assign all program parms to python variables which are global to this
158 # module.
159
160 global parm_list
161 parm_list = BuiltIn().get_variable_value("${parm_list}")
162 # The following subset of parms should be processed as integers.
163 int_list = ['max_num_tests', 'boot_pass', 'boot_fail', 'ffdc_only',
Michael Walsh89de14a2018-10-01 16:51:37 -0500164 'boot_fail_threshold', 'delete_errlogs',
Michael Walsh986d8ae2019-07-17 10:02:23 -0500165 'call_post_stack_plug', 'do_pre_boot_plug_in_setup', 'quiet',
166 'test_mode', 'debug']
Michael Walshb5839d02017-04-12 16:11:20 -0500167 for parm in parm_list:
168 if parm in int_list:
169 sub_cmd = "int(BuiltIn().get_variable_value(\"${" + parm +\
170 "}\", \"0\"))"
171 else:
172 sub_cmd = "BuiltIn().get_variable_value(\"${" + parm + "}\")"
173 cmd_buf = "global " + parm + " ; " + parm + " = " + sub_cmd
Michael Walshff340002017-08-29 11:18:27 -0500174 gp.dpissuing(cmd_buf)
Michael Walshb5839d02017-04-12 16:11:20 -0500175 exec(cmd_buf)
Michael Walsh0ad0f7f2017-05-04 14:39:58 -0500176 if re.match(r".*_host$", parm):
177 cmd_buf = "process_host(" + parm + ", '" + parm + "')"
178 exec(cmd_buf)
179 if re.match(r".*_password$", parm):
180 # Register the value of any parm whose name ends in _password.
181 # This will cause the print functions to replace passwords with
182 # asterisks in the output.
183 cmd_buf = "gp.register_passwords(" + parm + ")"
184 exec(cmd_buf)
Michael Walshb5839d02017-04-12 16:11:20 -0500185
186 global ffdc_dir_path_style
187 global boot_list
188 global boot_stack
189 global boot_results_file_path
190 global boot_results
Michael Walsh986d8ae2019-07-17 10:02:23 -0500191 global boot_history
Michael Walshb5839d02017-04-12 16:11:20 -0500192 global ffdc_list_file_path
Michael Walshe0cf8d72017-05-17 13:20:46 -0500193 global ffdc_report_list_path
Michael Walsh600876d2017-05-30 17:58:58 -0500194 global ffdc_summary_list_path
Michael Walsha3e7b222020-02-03 15:32:16 -0600195 global boot_table
196 global valid_boot_types
Michael Walshb5839d02017-04-12 16:11:20 -0500197
198 if ffdc_dir_path_style == "":
199 ffdc_dir_path_style = int(os.environ.get('FFDC_DIR_PATH_STYLE', '0'))
200
201 # Convert these program parms to lists for easier processing..
George Keishing36efbc02018-12-12 10:18:23 -0600202 boot_list = list(filter(None, boot_list.split(":")))
203 boot_stack = list(filter(None, boot_stack.split(":")))
Michael Walshb5839d02017-04-12 16:11:20 -0500204
Michael Walsha3e7b222020-02-03 15:32:16 -0600205 boot_table = create_boot_table(boot_table_path, os_host=os_host)
206 valid_boot_types = create_valid_boot_list(boot_table)
207
Michael Walsh903e0b22017-09-19 17:00:33 -0500208 cleanup_boot_results_file()
209 boot_results_file_path = create_boot_results_file_path(pgm_name,
210 openbmc_nickname,
211 master_pid)
Michael Walshb5839d02017-04-12 16:11:20 -0500212
213 if os.path.isfile(boot_results_file_path):
214 # We've been called before in this run so we'll load the saved
Michael Walsh986d8ae2019-07-17 10:02:23 -0500215 # boot_results and boot_history objects.
216 boot_results, boot_history =\
Michael Walsh6c645742018-08-17 15:02:17 -0500217 pickle.load(open(boot_results_file_path, 'rb'))
Michael Walshb5839d02017-04-12 16:11:20 -0500218 else:
219 boot_results = boot_results(boot_table, boot_pass, boot_fail)
220
221 ffdc_list_file_path = base_tool_dir_path + openbmc_nickname +\
222 "/FFDC_FILE_LIST"
Michael Walshe0cf8d72017-05-17 13:20:46 -0500223 ffdc_report_list_path = base_tool_dir_path + openbmc_nickname +\
224 "/FFDC_REPORT_FILE_LIST"
Michael Walshb5839d02017-04-12 16:11:20 -0500225
Michael Walsh600876d2017-05-30 17:58:58 -0500226 ffdc_summary_list_path = base_tool_dir_path + openbmc_nickname +\
227 "/FFDC_SUMMARY_FILE_LIST"
228
Michael Walshb5839d02017-04-12 16:11:20 -0500229
Michael Walsh85678942017-03-27 14:34:22 -0500230def initial_plug_in_setup():
Michael Walsh85678942017-03-27 14:34:22 -0500231 r"""
232 Initialize all plug-in environment variables which do not change for the
233 duration of the program.
234
235 """
236
237 global LOG_LEVEL
238 BuiltIn().set_log_level("NONE")
239
240 BuiltIn().set_global_variable("${master_pid}", master_pid)
241 BuiltIn().set_global_variable("${FFDC_DIR_PATH}", ffdc_dir_path)
242 BuiltIn().set_global_variable("${STATUS_DIR_PATH}", status_dir_path)
243 BuiltIn().set_global_variable("${BASE_TOOL_DIR_PATH}", base_tool_dir_path)
244 BuiltIn().set_global_variable("${FFDC_LIST_FILE_PATH}",
245 ffdc_list_file_path)
Michael Walshe0cf8d72017-05-17 13:20:46 -0500246 BuiltIn().set_global_variable("${FFDC_REPORT_LIST_PATH}",
247 ffdc_report_list_path)
Michael Walsh600876d2017-05-30 17:58:58 -0500248 BuiltIn().set_global_variable("${FFDC_SUMMARY_LIST_PATH}",
249 ffdc_summary_list_path)
Michael Walsh85678942017-03-27 14:34:22 -0500250
251 BuiltIn().set_global_variable("${FFDC_DIR_PATH_STYLE}",
252 ffdc_dir_path_style)
253 BuiltIn().set_global_variable("${FFDC_CHECK}",
254 ffdc_check)
255
256 # For each program parameter, set the corresponding AUTOBOOT_ environment
257 # variable value. Also, set an AUTOBOOT_ environment variable for every
258 # element in additional_values.
259 additional_values = ["program_pid", "master_pid", "ffdc_dir_path",
260 "status_dir_path", "base_tool_dir_path",
Michael Walsh600876d2017-05-30 17:58:58 -0500261 "ffdc_list_file_path", "ffdc_report_list_path",
Michael Walsh0a3bdb42019-01-31 16:21:44 +0000262 "ffdc_summary_list_path", "execdir"]
Michael Walsh85678942017-03-27 14:34:22 -0500263
264 plug_in_vars = parm_list + additional_values
265
266 for var_name in plug_in_vars:
267 var_value = BuiltIn().get_variable_value("${" + var_name + "}")
268 var_name = var_name.upper()
269 if var_value is None:
270 var_value = ""
271 os.environ["AUTOBOOT_" + var_name] = str(var_value)
272
273 BuiltIn().set_log_level(LOG_LEVEL)
274
Michael Walsh68a61162017-04-25 11:54:06 -0500275 # Make sure the ffdc list directory exists.
276 ffdc_list_dir_path = os.path.dirname(ffdc_list_file_path) + os.sep
277 if not os.path.exists(ffdc_list_dir_path):
278 os.makedirs(ffdc_list_dir_path)
Michael Walsh85678942017-03-27 14:34:22 -0500279
Michael Walsh85678942017-03-27 14:34:22 -0500280
Michael Walsh0bbd8602016-11-22 11:31:49 -0600281def plug_in_setup():
Michael Walsh0bbd8602016-11-22 11:31:49 -0600282 r"""
Michael Walsh85678942017-03-27 14:34:22 -0500283 Initialize all changing plug-in environment variables for use by the
284 plug-in programs.
Michael Walsh0bbd8602016-11-22 11:31:49 -0600285 """
286
Michael Walsh85678942017-03-27 14:34:22 -0500287 global LOG_LEVEL
288 global test_really_running
289
290 BuiltIn().set_log_level("NONE")
291
Michael Walsh6741f742017-02-20 16:16:38 -0600292 boot_pass, boot_fail = boot_results.return_total_pass_fail()
Michael Walsh0bbd8602016-11-22 11:31:49 -0600293 if boot_pass > 1:
294 test_really_running = 1
295 else:
296 test_really_running = 0
297
Michael Walsh6741f742017-02-20 16:16:38 -0600298 BuiltIn().set_global_variable("${test_really_running}",
299 test_really_running)
300 BuiltIn().set_global_variable("${boot_type_desc}", next_boot)
Michael Walsh6741f742017-02-20 16:16:38 -0600301 BuiltIn().set_global_variable("${boot_pass}", boot_pass)
302 BuiltIn().set_global_variable("${boot_fail}", boot_fail)
303 BuiltIn().set_global_variable("${boot_success}", boot_success)
304 BuiltIn().set_global_variable("${ffdc_prefix}", ffdc_prefix)
Sunil M325eb542017-08-10 07:09:43 -0500305 BuiltIn().set_global_variable("${boot_start_time}", boot_start_time)
306 BuiltIn().set_global_variable("${boot_end_time}", boot_end_time)
Michael Walsh4c9a6452016-12-13 16:03:11 -0600307
Michael Walsh0bbd8602016-11-22 11:31:49 -0600308 # For each program parameter, set the corresponding AUTOBOOT_ environment
309 # variable value. Also, set an AUTOBOOT_ environment variable for every
310 # element in additional_values.
311 additional_values = ["boot_type_desc", "boot_success", "boot_pass",
Sunil M325eb542017-08-10 07:09:43 -0500312 "boot_fail", "test_really_running", "ffdc_prefix",
313 "boot_start_time", "boot_end_time"]
Michael Walsh0bbd8602016-11-22 11:31:49 -0600314
Michael Walsh85678942017-03-27 14:34:22 -0500315 plug_in_vars = additional_values
Michael Walsh0bbd8602016-11-22 11:31:49 -0600316
317 for var_name in plug_in_vars:
318 var_value = BuiltIn().get_variable_value("${" + var_name + "}")
319 var_name = var_name.upper()
320 if var_value is None:
321 var_value = ""
Michael Walsh6741f742017-02-20 16:16:38 -0600322 os.environ["AUTOBOOT_" + var_name] = str(var_value)
Michael Walsh0bbd8602016-11-22 11:31:49 -0600323
Michael Walsh0bbd8602016-11-22 11:31:49 -0600324 if debug:
Michael Walsh6741f742017-02-20 16:16:38 -0600325 shell_rc, out_buf = \
326 gc.cmd_fnc_u("printenv | egrep AUTOBOOT_ | sort -u")
Michael Walsh0bbd8602016-11-22 11:31:49 -0600327
Michael Walsh85678942017-03-27 14:34:22 -0500328 BuiltIn().set_log_level(LOG_LEVEL)
329
Michael Walsh0bbd8602016-11-22 11:31:49 -0600330
Michael Walshe0cf8d72017-05-17 13:20:46 -0500331def pre_boot_plug_in_setup():
332
333 # Clear the ffdc_list_file_path file. Plug-ins may now write to it.
334 try:
335 os.remove(ffdc_list_file_path)
336 except OSError:
337 pass
338
339 # Clear the ffdc_report_list_path file. Plug-ins may now write to it.
340 try:
341 os.remove(ffdc_report_list_path)
342 except OSError:
343 pass
344
Michael Walsh600876d2017-05-30 17:58:58 -0500345 # Clear the ffdc_summary_list_path file. Plug-ins may now write to it.
346 try:
347 os.remove(ffdc_summary_list_path)
348 except OSError:
349 pass
350
Michael Walshe1974b92017-08-03 13:39:51 -0500351 global ffdc_prefix
352
353 seconds = time.time()
354 loc_time = time.localtime(seconds)
355 time_string = time.strftime("%y%m%d.%H%M%S.", loc_time)
356
357 ffdc_prefix = openbmc_nickname + "." + time_string
358
Michael Walshe0cf8d72017-05-17 13:20:46 -0500359
Michael Walshf566fb12019-02-01 14:35:09 -0600360def default_sigusr1(signal_number=0,
361 frame=None):
362 r"""
363 Handle SIGUSR1 by doing nothing.
364
365 This function assists in debugging SIGUSR1 processing by printing messages
366 to stdout and to the log.html file.
367
368 Description of argument(s):
369 signal_number The signal number (should always be 10 for SIGUSR1).
370 frame The frame data.
371 """
372
Michael Walsh80dddde2019-10-22 13:54:38 -0500373 gp.qprintn()
374 gp.qprint_executing()
Michael Walshf566fb12019-02-01 14:35:09 -0600375 gp.lprint_executing()
376
377
378def set_default_siguser1():
379 r"""
380 Set the default_sigusr1 function to be the SIGUSR1 handler.
381 """
382
Michael Walsh80dddde2019-10-22 13:54:38 -0500383 gp.qprintn()
384 gp.qprint_executing()
Michael Walshf566fb12019-02-01 14:35:09 -0600385 gp.lprint_executing()
386 signal.signal(signal.SIGUSR1, default_sigusr1)
387
388
Michael Walsh6741f742017-02-20 16:16:38 -0600389def setup():
Michael Walsh0bbd8602016-11-22 11:31:49 -0600390 r"""
Michael Walsh6741f742017-02-20 16:16:38 -0600391 Do general program setup tasks.
Michael Walsh0bbd8602016-11-22 11:31:49 -0600392 """
393
Michael Walsh6741f742017-02-20 16:16:38 -0600394 global cp_setup_called
Michael Walsh81816742017-09-27 11:02:29 -0500395 global transitional_boot_selected
Michael Walsh0bbd8602016-11-22 11:31:49 -0600396
Michael Walshb5839d02017-04-12 16:11:20 -0500397 gp.qprintn()
398
Michael Walshf566fb12019-02-01 14:35:09 -0600399 set_default_siguser1()
Michael Walsh81816742017-09-27 11:02:29 -0500400 transitional_boot_selected = False
401
Michael Walsh83f4bc72017-04-20 16:49:43 -0500402 robot_pgm_dir_path = os.path.dirname(__file__) + os.sep
403 repo_bin_path = robot_pgm_dir_path.replace("/lib/", "/bin/")
Michael Walshd061c042017-05-23 14:46:57 -0500404 # If we can't find process_plug_in_packages.py, ssh_pw or
405 # validate_plug_ins.py, then we don't have our repo bin in PATH.
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -0500406 shell_rc, out_buf = gc.cmd_fnc_u("which process_plug_in_packages.py"
407 + " ssh_pw validate_plug_ins.py", quiet=1,
Michael Walshd061c042017-05-23 14:46:57 -0500408 print_output=0, show_err=0)
Michael Walshb5839d02017-04-12 16:11:20 -0500409 if shell_rc != 0:
Michael Walsh83f4bc72017-04-20 16:49:43 -0500410 os.environ['PATH'] = repo_bin_path + ":" + os.environ.get('PATH', "")
411 # Likewise, our repo lib subdir needs to be in sys.path and PYTHONPATH.
412 if robot_pgm_dir_path not in sys.path:
413 sys.path.append(robot_pgm_dir_path)
414 PYTHONPATH = os.environ.get("PYTHONPATH", "")
415 if PYTHONPATH == "":
416 os.environ['PYTHONPATH'] = robot_pgm_dir_path
417 else:
418 os.environ['PYTHONPATH'] = robot_pgm_dir_path + ":" + PYTHONPATH
Michael Walsh6741f742017-02-20 16:16:38 -0600419
420 validate_parms()
421
Michael Walshc108e422019-03-28 12:27:18 -0500422 gp.qprint_pgm_header()
Michael Walsh6741f742017-02-20 16:16:38 -0600423
George Keishingefc3ff22017-12-12 11:49:25 -0600424 grk.run_key("Set BMC Power Policy ALWAYS_POWER_OFF")
Michael Walsh11cfc8c2017-03-31 09:40:55 -0500425
Michael Walsh85678942017-03-27 14:34:22 -0500426 initial_plug_in_setup()
427
Michael Walsh6741f742017-02-20 16:16:38 -0600428 plug_in_setup()
429 rc, shell_rc, failed_plug_in_name = grpi.rprocess_plug_in_packages(
430 call_point='setup')
431 if rc != 0:
432 error_message = "Plug-in setup failed.\n"
Michael Walshc108e422019-03-28 12:27:18 -0500433 gp.print_error_report(error_message)
Michael Walsh6741f742017-02-20 16:16:38 -0600434 BuiltIn().fail(error_message)
435 # Setting cp_setup_called lets our Teardown know that it needs to call
436 # the cleanup plug-in call point.
437 cp_setup_called = 1
438
439 # Keyword "FFDC" will fail if TEST_MESSAGE is not set.
440 BuiltIn().set_global_variable("${TEST_MESSAGE}", "${EMPTY}")
Michael Walsh85678942017-03-27 14:34:22 -0500441 # FFDC_LOG_PATH is used by "FFDC" keyword.
442 BuiltIn().set_global_variable("${FFDC_LOG_PATH}", ffdc_dir_path)
Michael Walsh6741f742017-02-20 16:16:38 -0600443
Michael Walshdc80d672017-05-09 12:58:32 -0500444 # Also printed by FFDC.
445 global host_name
446 global host_ip
447 host = socket.gethostname()
448 host_name, host_ip = gm.get_host_name_ip(host)
449
Michael Walsh986d8ae2019-07-17 10:02:23 -0500450 gp.dprint_var(boot_table)
Michael Walshb5839d02017-04-12 16:11:20 -0500451 gp.dprint_var(boot_lists)
Michael Walsh0bbd8602016-11-22 11:31:49 -0600452
Michael Walsh0bbd8602016-11-22 11:31:49 -0600453
Michael Walsh6741f742017-02-20 16:16:38 -0600454def validate_parms():
Michael Walsh0bbd8602016-11-22 11:31:49 -0600455 r"""
Michael Walsh6741f742017-02-20 16:16:38 -0600456 Validate all program parameters.
Michael Walsh0bbd8602016-11-22 11:31:49 -0600457 """
458
Michael Walshb5839d02017-04-12 16:11:20 -0500459 process_pgm_parms()
Michael Walsh0bbd8602016-11-22 11:31:49 -0600460
Michael Walshb5839d02017-04-12 16:11:20 -0500461 gp.qprintn()
462
463 global openbmc_model
Michael Walshf5ce38c2020-02-27 12:46:20 -0600464 if openbmc_model == "":
465 status, ret_values =\
466 grk.run_key_u("Get BMC System Model")
467 openbmc_model = ret_values
468 BuiltIn().set_global_variable("${openbmc_model}", openbmc_model)
469 gv.set_exit_on_error(True)
Michael Walsh44cef252019-08-01 12:38:56 -0500470 gv.valid_value(openbmc_host)
471 gv.valid_value(openbmc_username)
472 gv.valid_value(openbmc_password)
473 gv.valid_value(rest_username)
474 gv.valid_value(rest_password)
475 gv.valid_value(ipmi_username)
476 gv.valid_value(ipmi_password)
Michael Walsh6741f742017-02-20 16:16:38 -0600477 if os_host != "":
Michael Walsh44cef252019-08-01 12:38:56 -0500478 gv.valid_value(os_username)
479 gv.valid_value(os_password)
Michael Walsh6741f742017-02-20 16:16:38 -0600480 if pdu_host != "":
Michael Walsh44cef252019-08-01 12:38:56 -0500481 gv.valid_value(pdu_username)
482 gv.valid_value(pdu_password)
483 gv.valid_integer(pdu_slot_no)
Michael Walsh6741f742017-02-20 16:16:38 -0600484 if openbmc_serial_host != "":
Michael Walsh44cef252019-08-01 12:38:56 -0500485 gv.valid_integer(openbmc_serial_port)
Michael Walsh44cef252019-08-01 12:38:56 -0500486 gv.valid_value(openbmc_model)
487 gv.valid_integer(max_num_tests)
488 gv.valid_integer(boot_pass)
489 gv.valid_integer(boot_fail)
Michael Walsh6741f742017-02-20 16:16:38 -0600490 plug_in_packages_list = grpi.rvalidate_plug_ins(plug_in_dir_paths)
491 BuiltIn().set_global_variable("${plug_in_packages_list}",
492 plug_in_packages_list)
Michael Walsh44cef252019-08-01 12:38:56 -0500493 gv.valid_value(stack_mode, valid_values=['normal', 'skip'])
Michael Walshf5ce38c2020-02-27 12:46:20 -0600494 gv.set_exit_on_error(False)
Michael Walsha20da402017-03-31 16:27:45 -0500495 if len(boot_list) == 0 and len(boot_stack) == 0 and not ffdc_only:
Michael Walsh6741f742017-02-20 16:16:38 -0600496 error_message = "You must provide either a value for either the" +\
497 " boot_list or the boot_stack parm.\n"
498 BuiltIn().fail(gp.sprint_error(error_message))
Michael Walsh6741f742017-02-20 16:16:38 -0600499 valid_boot_list(boot_list, valid_boot_types)
500 valid_boot_list(boot_stack, valid_boot_types)
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 if len(selected_PDU_boots) > 0 and pdu_host == "":
504 error_message = "You have selected the following boots which" +\
505 " require a PDU host but no value for pdu_host:\n"
506 error_message += gp.sprint_var(selected_PDU_boots)
Michael Walsh986d8ae2019-07-17 10:02:23 -0500507 error_message += gp.sprint_var(pdu_host, fmt=gp.blank())
Michael Walsh11cfc8c2017-03-31 09:40:55 -0500508 BuiltIn().fail(gp.sprint_error(error_message))
509
Michael Walsh6741f742017-02-20 16:16:38 -0600510 return
Michael Walsh0bbd8602016-11-22 11:31:49 -0600511
Michael Walsh0bbd8602016-11-22 11:31:49 -0600512
Michael Walsh6741f742017-02-20 16:16:38 -0600513def my_get_state():
Michael Walsh0bbd8602016-11-22 11:31:49 -0600514 r"""
Michael Walsh6741f742017-02-20 16:16:38 -0600515 Get the system state plus a little bit of wrapping.
Michael Walsh0bbd8602016-11-22 11:31:49 -0600516 """
517
Michael Walsh6741f742017-02-20 16:16:38 -0600518 global state
519
520 req_states = ['epoch_seconds'] + st.default_req_states
521
Michael Walshb5839d02017-04-12 16:11:20 -0500522 gp.qprint_timen("Getting system state.")
Michael Walsh6741f742017-02-20 16:16:38 -0600523 if test_mode:
524 state['epoch_seconds'] = int(time.time())
525 else:
Michael Walshb5839d02017-04-12 16:11:20 -0500526 state = st.get_state(req_states=req_states, quiet=quiet)
527 gp.qprint_var(state)
Michael Walsh341c21e2017-01-17 16:25:20 -0600528
Michael Walsh341c21e2017-01-17 16:25:20 -0600529
Michael Walsh45ca6e42017-09-14 17:29:12 -0500530def valid_state():
Michael Walsh45ca6e42017-09-14 17:29:12 -0500531 r"""
532 Verify that our state dictionary contains no blank values. If we don't get
533 valid state data, we cannot continue to work.
534 """
535
536 if st.compare_states(state, st.invalid_state_match, 'or'):
537 error_message = "The state dictionary contains blank fields which" +\
538 " is illegal.\n" + gp.sprint_var(state)
539 BuiltIn().fail(gp.sprint_error(error_message))
540
Michael Walsh45ca6e42017-09-14 17:29:12 -0500541
Michael Walsh6741f742017-02-20 16:16:38 -0600542def select_boot():
Michael Walsh341c21e2017-01-17 16:25:20 -0600543 r"""
544 Select a boot test to be run based on our current state and return the
545 chosen boot type.
546
547 Description of arguments:
Michael Walsh6741f742017-02-20 16:16:38 -0600548 state The state of the machine.
Michael Walsh341c21e2017-01-17 16:25:20 -0600549 """
550
Michael Walsh81816742017-09-27 11:02:29 -0500551 global transitional_boot_selected
Michael Walsh30dadae2017-02-27 14:25:52 -0600552 global boot_stack
553
Michael Walshb5839d02017-04-12 16:11:20 -0500554 gp.qprint_timen("Selecting a boot test.")
Michael Walsh6741f742017-02-20 16:16:38 -0600555
Michael Walsh81816742017-09-27 11:02:29 -0500556 if transitional_boot_selected and not boot_success:
557 prior_boot = next_boot
558 boot_candidate = boot_stack.pop()
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -0500559 gp.qprint_timen("The prior '" + next_boot + "' was chosen to"
560 + " transition to a valid state for '" + boot_candidate
561 + "' which was at the top of the boot_stack. Since"
562 + " the '" + next_boot + "' failed, the '"
563 + boot_candidate + "' has been removed from the stack"
564 + " to avoid and endless failure loop.")
Michael Walsh81816742017-09-27 11:02:29 -0500565 if len(boot_stack) == 0:
566 return ""
567
Michael Walsh6741f742017-02-20 16:16:38 -0600568 my_get_state()
Michael Walsh45ca6e42017-09-14 17:29:12 -0500569 valid_state()
Michael Walsh6741f742017-02-20 16:16:38 -0600570
Michael Walsh81816742017-09-27 11:02:29 -0500571 transitional_boot_selected = False
Michael Walsh6741f742017-02-20 16:16:38 -0600572 stack_popped = 0
573 if len(boot_stack) > 0:
574 stack_popped = 1
Michael Walshb5839d02017-04-12 16:11:20 -0500575 gp.qprint_dashes()
576 gp.qprint_var(boot_stack)
577 gp.qprint_dashes()
578 skip_boot_printed = 0
579 while len(boot_stack) > 0:
580 boot_candidate = boot_stack.pop()
581 if stack_mode == 'normal':
582 break
583 else:
584 if st.compare_states(state, boot_table[boot_candidate]['end']):
585 if not skip_boot_printed:
Michael Walshff340002017-08-29 11:18:27 -0500586 gp.qprint_var(stack_mode)
587 gp.qprintn()
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -0500588 gp.qprint_timen("Skipping the following boot tests"
589 + " which are unnecessary since their"
590 + " required end states match the"
591 + " current machine state:")
Michael Walshb5839d02017-04-12 16:11:20 -0500592 skip_boot_printed = 1
Michael Walshff340002017-08-29 11:18:27 -0500593 gp.qprint_var(boot_candidate)
Michael Walshb5839d02017-04-12 16:11:20 -0500594 boot_candidate = ""
595 if boot_candidate == "":
596 gp.qprint_dashes()
597 gp.qprint_var(boot_stack)
598 gp.qprint_dashes()
599 return boot_candidate
Michael Walsh6741f742017-02-20 16:16:38 -0600600 if st.compare_states(state, boot_table[boot_candidate]['start']):
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -0500601 gp.qprint_timen("The machine state is valid for a '"
602 + boot_candidate + "' boot test.")
Michael Walshb5839d02017-04-12 16:11:20 -0500603 gp.qprint_dashes()
604 gp.qprint_var(boot_stack)
605 gp.qprint_dashes()
Michael Walsh6741f742017-02-20 16:16:38 -0600606 return boot_candidate
Michael Walsh341c21e2017-01-17 16:25:20 -0600607 else:
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -0500608 gp.qprint_timen("The machine state does not match the required"
609 + " starting state for a '" + boot_candidate
610 + "' boot test:")
Michael Walsh986d8ae2019-07-17 10:02:23 -0500611 gp.qprint_varx("boot_table_start_entry",
612 boot_table[boot_candidate]['start'])
Michael Walsh6741f742017-02-20 16:16:38 -0600613 boot_stack.append(boot_candidate)
Michael Walsh81816742017-09-27 11:02:29 -0500614 transitional_boot_selected = True
Michael Walsh6741f742017-02-20 16:16:38 -0600615 popped_boot = boot_candidate
616
617 # Loop through your list selecting a boot_candidates
618 boot_candidates = []
619 for boot_candidate in boot_list:
620 if st.compare_states(state, boot_table[boot_candidate]['start']):
621 if stack_popped:
622 if st.compare_states(boot_table[boot_candidate]['end'],
Gunnar Mills096cd562018-03-26 10:19:12 -0500623 boot_table[popped_boot]['start']):
Michael Walsh6741f742017-02-20 16:16:38 -0600624 boot_candidates.append(boot_candidate)
625 else:
626 boot_candidates.append(boot_candidate)
627
628 if len(boot_candidates) == 0:
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -0500629 gp.qprint_timen("The user's boot list contained no boot tests"
630 + " which are valid for the current machine state.")
Michael Walsh6741f742017-02-20 16:16:38 -0600631 boot_candidate = default_power_on
632 if not st.compare_states(state, boot_table[default_power_on]['start']):
633 boot_candidate = default_power_off
634 boot_candidates.append(boot_candidate)
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -0500635 gp.qprint_timen("Using default '" + boot_candidate
636 + "' boot type to transition to valid state.")
Michael Walsh6741f742017-02-20 16:16:38 -0600637
Michael Walshb5839d02017-04-12 16:11:20 -0500638 gp.dprint_var(boot_candidates)
Michael Walsh6741f742017-02-20 16:16:38 -0600639
640 # Randomly select a boot from the candidate list.
641 boot = random.choice(boot_candidates)
Michael Walsh341c21e2017-01-17 16:25:20 -0600642
643 return boot
Michael Walsh0bbd8602016-11-22 11:31:49 -0600644
Michael Walsh55302292017-01-10 11:43:02 -0600645
Michael Walshb2e53ec2017-10-30 15:04:36 -0500646def print_defect_report(ffdc_file_list):
Michael Walsh341c21e2017-01-17 16:25:20 -0600647 r"""
648 Print a defect report.
Michael Walshb2e53ec2017-10-30 15:04:36 -0500649
650 Description of argument(s):
651 ffdc_file_list A list of files which were collected by our ffdc functions.
Michael Walsh341c21e2017-01-17 16:25:20 -0600652 """
653
Michael Walsh600876d2017-05-30 17:58:58 -0500654 # Making deliberate choice to NOT run plug_in_setup(). We don't want
655 # ffdc_prefix updated.
656 rc, shell_rc, failed_plug_in_name = grpi.rprocess_plug_in_packages(
657 call_point='ffdc_report', stop_on_plug_in_failure=0)
658
Michael Walshe0cf8d72017-05-17 13:20:46 -0500659 # Get additional header data which may have been created by ffdc plug-ins.
660 # Also, delete the individual header files to cleanup.
661 cmd_buf = "file_list=$(cat " + ffdc_report_list_path + " 2>/dev/null)" +\
662 " ; [ ! -z \"${file_list}\" ] && cat ${file_list}" +\
663 " 2>/dev/null ; rm -rf ${file_list} 2>/dev/null || :"
664 shell_rc, more_header_info = gc.cmd_fnc_u(cmd_buf, print_output=0,
665 show_err=0)
666
Michael Walshb2e53ec2017-10-30 15:04:36 -0500667 # Get additional summary data which may have been created by ffdc plug-ins.
Michael Walsh600876d2017-05-30 17:58:58 -0500668 # Also, delete the individual header files to cleanup.
669 cmd_buf = "file_list=$(cat " + ffdc_summary_list_path + " 2>/dev/null)" +\
670 " ; [ ! -z \"${file_list}\" ] && cat ${file_list}" +\
671 " 2>/dev/null ; rm -rf ${file_list} 2>/dev/null || :"
672 shell_rc, ffdc_summary_info = gc.cmd_fnc_u(cmd_buf, print_output=0,
673 show_err=0)
674
Michael Walshb2e53ec2017-10-30 15:04:36 -0500675 # ffdc_list_file_path contains a list of any ffdc files created by plug-
676 # ins, etc. Read that data into a list.
Michael Walsh341c21e2017-01-17 16:25:20 -0600677 try:
Michael Walshb2e53ec2017-10-30 15:04:36 -0500678 plug_in_ffdc_list = \
679 open(ffdc_list_file_path, 'r').read().rstrip("\n").split("\n")
George Keishing36efbc02018-12-12 10:18:23 -0600680 plug_in_ffdc_list = list(filter(None, plug_in_ffdc_list))
Michael Walsh341c21e2017-01-17 16:25:20 -0600681 except IOError:
Michael Walshb2e53ec2017-10-30 15:04:36 -0500682 plug_in_ffdc_list = []
683
684 # Combine the files from plug_in_ffdc_list with the ffdc_file_list passed
685 # in. Eliminate duplicates and sort the list.
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -0500686 ffdc_file_list = sorted(set(ffdc_file_list + plug_in_ffdc_list))
Michael Walshb2e53ec2017-10-30 15:04:36 -0500687
688 if status_file_path != "":
689 ffdc_file_list.insert(0, status_file_path)
690
691 # Convert the list to a printable list.
692 printable_ffdc_file_list = "\n".join(ffdc_file_list)
Michael Walsh341c21e2017-01-17 16:25:20 -0600693
Michael Walsh68a61162017-04-25 11:54:06 -0500694 # Open ffdc_file_list for writing. We will write a complete list of
695 # FFDC files to it for possible use by plug-ins like cp_stop_check.
696 ffdc_list_file = open(ffdc_list_file_path, 'w')
Michael Walshb2e53ec2017-10-30 15:04:36 -0500697 ffdc_list_file.write(printable_ffdc_file_list + "\n")
698 ffdc_list_file.close()
699
700 indent = 0
701 width = 90
702 linefeed = 1
703 char = "="
Michael Walsh68a61162017-04-25 11:54:06 -0500704
705 gp.qprintn()
Michael Walshb2e53ec2017-10-30 15:04:36 -0500706 gp.qprint_dashes(indent, width, linefeed, char)
Michael Walsh68a61162017-04-25 11:54:06 -0500707 gp.qprintn("Copy this data to the defect:\n")
708
Michael Walshe0cf8d72017-05-17 13:20:46 -0500709 if len(more_header_info) > 0:
Michael Walshff340002017-08-29 11:18:27 -0500710 gp.qprintn(more_header_info)
Michael Walshdc80d672017-05-09 12:58:32 -0500711 gp.qpvars(host_name, host_ip, openbmc_nickname, openbmc_host,
712 openbmc_host_name, openbmc_ip, openbmc_username,
Michael Walsh0a3bdb42019-01-31 16:21:44 +0000713 openbmc_password, rest_username, rest_password, ipmi_username,
714 ipmi_password, os_host, os_host_name, os_ip, os_username,
Michael Walshdc80d672017-05-09 12:58:32 -0500715 os_password, pdu_host, pdu_host_name, pdu_ip, pdu_username,
716 pdu_password, pdu_slot_no, openbmc_serial_host,
717 openbmc_serial_host_name, openbmc_serial_ip, openbmc_serial_port)
Michael Walsh68a61162017-04-25 11:54:06 -0500718
719 gp.qprintn()
Michael Walsh986d8ae2019-07-17 10:02:23 -0500720 print_boot_history(boot_history)
Michael Walsh68a61162017-04-25 11:54:06 -0500721 gp.qprintn()
722 gp.qprint_var(state)
Michael Walshb5839d02017-04-12 16:11:20 -0500723 gp.qprintn()
724 gp.qprintn("FFDC data files:")
Michael Walshb2e53ec2017-10-30 15:04:36 -0500725 gp.qprintn(printable_ffdc_file_list)
Michael Walshb5839d02017-04-12 16:11:20 -0500726 gp.qprintn()
Michael Walsh341c21e2017-01-17 16:25:20 -0600727
Michael Walsh600876d2017-05-30 17:58:58 -0500728 if len(ffdc_summary_info) > 0:
Michael Walshff340002017-08-29 11:18:27 -0500729 gp.qprintn(ffdc_summary_info)
Michael Walsh600876d2017-05-30 17:58:58 -0500730
Michael Walshb2e53ec2017-10-30 15:04:36 -0500731 gp.qprint_dashes(indent, width, linefeed, char)
Michael Walsh68a61162017-04-25 11:54:06 -0500732
Michael Walsh6741f742017-02-20 16:16:38 -0600733
Michael Walsh6741f742017-02-20 16:16:38 -0600734def my_ffdc():
Michael Walsh6741f742017-02-20 16:16:38 -0600735 r"""
736 Collect FFDC data.
737 """
738
739 global state
740
741 plug_in_setup()
742 rc, shell_rc, failed_plug_in_name = grpi.rprocess_plug_in_packages(
Michael Walsh600876d2017-05-30 17:58:58 -0500743 call_point='ffdc', stop_on_plug_in_failure=0)
Michael Walsh6741f742017-02-20 16:16:38 -0600744
745 AUTOBOOT_FFDC_PREFIX = os.environ['AUTOBOOT_FFDC_PREFIX']
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -0500746 status, ffdc_file_list = grk.run_key_u("FFDC ffdc_prefix="
747 + AUTOBOOT_FFDC_PREFIX
748 + " ffdc_function_list="
749 + ffdc_function_list, ignore=1)
Michael Walsh83f4bc72017-04-20 16:49:43 -0500750 if status != 'PASS':
Michael Walshff340002017-08-29 11:18:27 -0500751 gp.qprint_error("Call to ffdc failed.\n")
Michael Walshc9bd2e82019-04-18 11:06:52 -0500752 if type(ffdc_file_list) is not list:
753 ffdc_file_list = []
754 # Leave a record for caller that "soft" errors occurred.
755 soft_errors = 1
756 gpu.save_plug_in_value(soft_errors, pgm_name)
Michael Walsh6741f742017-02-20 16:16:38 -0600757
758 my_get_state()
759
Michael Walshb2e53ec2017-10-30 15:04:36 -0500760 print_defect_report(ffdc_file_list)
Michael Walsh6741f742017-02-20 16:16:38 -0600761
Michael Walsh6741f742017-02-20 16:16:38 -0600762
Michael Walsh6741f742017-02-20 16:16:38 -0600763def print_test_start_message(boot_keyword):
Michael Walsh6741f742017-02-20 16:16:38 -0600764 r"""
765 Print a message indicating what boot test is about to run.
766
767 Description of arguments:
768 boot_keyword The name of the boot which is to be run
769 (e.g. "BMC Power On").
770 """
771
Michael Walsh986d8ae2019-07-17 10:02:23 -0500772 global boot_history
Sunil M325eb542017-08-10 07:09:43 -0500773 global boot_start_time
Michael Walsh6741f742017-02-20 16:16:38 -0600774
775 doing_msg = gp.sprint_timen("Doing \"" + boot_keyword + "\".")
Sunil M325eb542017-08-10 07:09:43 -0500776
777 # Set boot_start_time for use by plug-ins.
778 boot_start_time = doing_msg[1:33]
779 gp.qprint_var(boot_start_time)
780
Michael Walshb5839d02017-04-12 16:11:20 -0500781 gp.qprint(doing_msg)
Michael Walsh6741f742017-02-20 16:16:38 -0600782
Michael Walsh986d8ae2019-07-17 10:02:23 -0500783 update_boot_history(boot_history, doing_msg, max_boot_history)
Michael Walsh6741f742017-02-20 16:16:38 -0600784
Michael Walsh6741f742017-02-20 16:16:38 -0600785
Michael Walshf566fb12019-02-01 14:35:09 -0600786def stop_boot_test(signal_number=0,
787 frame=None):
788 r"""
789 Handle SIGUSR1 by aborting the boot test that is running.
790
791 Description of argument(s):
792 signal_number The signal number (should always be 10 for SIGUSR1).
793 frame The frame data.
794 """
795
Michael Walsh80dddde2019-10-22 13:54:38 -0500796 gp.qprintn()
797 gp.qprint_executing()
Michael Walshf566fb12019-02-01 14:35:09 -0600798 gp.lprint_executing()
799
800 # Restore original sigusr1 handler.
801 set_default_siguser1()
802
803 message = "The caller has asked that the boot test be stopped and marked"
804 message += " as a failure."
805
806 function_stack = gm.get_function_stack()
807 if "wait_state" in function_stack:
Michael Walshc44aa532019-06-14 13:33:29 -0500808 st.set_exit_wait_early_message(message)
Michael Walshf566fb12019-02-01 14:35:09 -0600809 else:
810 BuiltIn().fail(gp.sprint_error(message))
811
812
Michael Walsh6741f742017-02-20 16:16:38 -0600813def run_boot(boot):
Michael Walsh6741f742017-02-20 16:16:38 -0600814 r"""
815 Run the specified boot.
816
817 Description of arguments:
818 boot The name of the boot test to be performed.
819 """
820
821 global state
822
Michael Walshf566fb12019-02-01 14:35:09 -0600823 signal.signal(signal.SIGUSR1, stop_boot_test)
824 gp.qprint_timen("stop_boot_test is armed.")
825
Michael Walsh6741f742017-02-20 16:16:38 -0600826 print_test_start_message(boot)
827
828 plug_in_setup()
829 rc, shell_rc, failed_plug_in_name = \
830 grpi.rprocess_plug_in_packages(call_point="pre_boot")
831 if rc != 0:
832 error_message = "Plug-in failed with non-zero return code.\n" +\
Michael Walsh986d8ae2019-07-17 10:02:23 -0500833 gp.sprint_var(rc, fmt=gp.hexa())
Michael Walshf566fb12019-02-01 14:35:09 -0600834 set_default_siguser1()
Michael Walsh6741f742017-02-20 16:16:38 -0600835 BuiltIn().fail(gp.sprint_error(error_message))
836
837 if test_mode:
838 # In test mode, we'll pretend the boot worked by assigning its
839 # required end state to the default state value.
Michael Walsh30dadae2017-02-27 14:25:52 -0600840 state = st.strip_anchor_state(boot_table[boot]['end'])
Michael Walsh6741f742017-02-20 16:16:38 -0600841 else:
842 # Assertion: We trust that the state data was made fresh by the
843 # caller.
844
Michael Walshb5839d02017-04-12 16:11:20 -0500845 gp.qprintn()
Michael Walsh6741f742017-02-20 16:16:38 -0600846
847 if boot_table[boot]['method_type'] == "keyword":
Michael Walsh0b93fbf2017-03-02 14:42:41 -0600848 rk.my_run_keywords(boot_table[boot].get('lib_file_path', ''),
Michael Walshb5839d02017-04-12 16:11:20 -0500849 boot_table[boot]['method'],
850 quiet=quiet)
Michael Walsh6741f742017-02-20 16:16:38 -0600851
852 if boot_table[boot]['bmc_reboot']:
853 st.wait_for_comm_cycle(int(state['epoch_seconds']))
Michael Walsh30dadae2017-02-27 14:25:52 -0600854 plug_in_setup()
855 rc, shell_rc, failed_plug_in_name = \
856 grpi.rprocess_plug_in_packages(call_point="post_reboot")
857 if rc != 0:
Michael Walsh0b93fbf2017-03-02 14:42:41 -0600858 error_message = "Plug-in failed with non-zero return code.\n"
Michael Walsh986d8ae2019-07-17 10:02:23 -0500859 error_message += gp.sprint_var(rc, fmt=gp.hexa())
Michael Walshf566fb12019-02-01 14:35:09 -0600860 set_default_siguser1()
Michael Walsh30dadae2017-02-27 14:25:52 -0600861 BuiltIn().fail(gp.sprint_error(error_message))
Michael Walsh6741f742017-02-20 16:16:38 -0600862 else:
863 match_state = st.anchor_state(state)
864 del match_state['epoch_seconds']
865 # Wait for the state to change in any way.
866 st.wait_state(match_state, wait_time=state_change_timeout,
Michael Walsh600876d2017-05-30 17:58:58 -0500867 interval="10 seconds", invert=1)
Michael Walsh6741f742017-02-20 16:16:38 -0600868
Michael Walshb5839d02017-04-12 16:11:20 -0500869 gp.qprintn()
Michael Walsh6741f742017-02-20 16:16:38 -0600870 if boot_table[boot]['end']['chassis'] == "Off":
871 boot_timeout = power_off_timeout
872 else:
873 boot_timeout = power_on_timeout
874 st.wait_state(boot_table[boot]['end'], wait_time=boot_timeout,
Michael Walsh600876d2017-05-30 17:58:58 -0500875 interval="10 seconds")
Michael Walsh6741f742017-02-20 16:16:38 -0600876
877 plug_in_setup()
878 rc, shell_rc, failed_plug_in_name = \
879 grpi.rprocess_plug_in_packages(call_point="post_boot")
880 if rc != 0:
881 error_message = "Plug-in failed with non-zero return code.\n" +\
Michael Walsh986d8ae2019-07-17 10:02:23 -0500882 gp.sprint_var(rc, fmt=gp.hexa())
Michael Walshf566fb12019-02-01 14:35:09 -0600883 set_default_siguser1()
Michael Walsh6741f742017-02-20 16:16:38 -0600884 BuiltIn().fail(gp.sprint_error(error_message))
885
Michael Walshf566fb12019-02-01 14:35:09 -0600886 # Restore original sigusr1 handler.
887 set_default_siguser1()
888
Michael Walsh6741f742017-02-20 16:16:38 -0600889
Michael Walsh6741f742017-02-20 16:16:38 -0600890def test_loop_body():
Michael Walsh6741f742017-02-20 16:16:38 -0600891 r"""
892 The main loop body for the loop in main_py.
893
894 Description of arguments:
895 boot_count The iteration number (starts at 1).
896 """
897
898 global boot_count
899 global state
900 global next_boot
901 global boot_success
Sunil M325eb542017-08-10 07:09:43 -0500902 global boot_end_time
Michael Walsh6741f742017-02-20 16:16:38 -0600903
Michael Walshb5839d02017-04-12 16:11:20 -0500904 gp.qprintn()
Michael Walsh6741f742017-02-20 16:16:38 -0600905
906 next_boot = select_boot()
Michael Walshb5839d02017-04-12 16:11:20 -0500907 if next_boot == "":
908 return True
Michael Walsh6741f742017-02-20 16:16:38 -0600909
Michael Walshb5839d02017-04-12 16:11:20 -0500910 boot_count += 1
911 gp.qprint_timen("Starting boot " + str(boot_count) + ".")
Michael Walsh6741f742017-02-20 16:16:38 -0600912
Michael Walshe0cf8d72017-05-17 13:20:46 -0500913 pre_boot_plug_in_setup()
Michael Walsh6741f742017-02-20 16:16:38 -0600914
915 cmd_buf = ["run_boot", next_boot]
916 boot_status, msg = BuiltIn().run_keyword_and_ignore_error(*cmd_buf)
917 if boot_status == "FAIL":
Michael Walshb5839d02017-04-12 16:11:20 -0500918 gp.qprint(msg)
Michael Walsh6741f742017-02-20 16:16:38 -0600919
Michael Walshb5839d02017-04-12 16:11:20 -0500920 gp.qprintn()
Michael Walsh6741f742017-02-20 16:16:38 -0600921 if boot_status == "PASS":
922 boot_success = 1
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -0500923 completion_msg = gp.sprint_timen("BOOT_SUCCESS: \"" + next_boot
924 + "\" succeeded.")
Michael Walsh6741f742017-02-20 16:16:38 -0600925 else:
926 boot_success = 0
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -0500927 completion_msg = gp.sprint_timen("BOOT_FAILED: \"" + next_boot
928 + "\" failed.")
Sunil M325eb542017-08-10 07:09:43 -0500929
930 # Set boot_end_time for use by plug-ins.
931 boot_end_time = completion_msg[1:33]
932 gp.qprint_var(boot_end_time)
933
934 gp.qprint(completion_msg)
Michael Walsh6741f742017-02-20 16:16:38 -0600935
936 boot_results.update(next_boot, boot_status)
937
938 plug_in_setup()
939 # NOTE: A post_test_case call point failure is NOT counted as a boot
940 # failure.
941 rc, shell_rc, failed_plug_in_name = grpi.rprocess_plug_in_packages(
Michael Walsh600876d2017-05-30 17:58:58 -0500942 call_point='post_test_case', stop_on_plug_in_failure=0)
Michael Walsh6741f742017-02-20 16:16:38 -0600943
944 plug_in_setup()
945 rc, shell_rc, failed_plug_in_name = grpi.rprocess_plug_in_packages(
Michael Walsh89de14a2018-10-01 16:51:37 -0500946 call_point='ffdc_check', shell_rc=dump_ffdc_rc(),
Michael Walsh6741f742017-02-20 16:16:38 -0600947 stop_on_plug_in_failure=1, stop_on_non_zero_rc=1)
Michael Walsh12059e22019-03-21 11:03:45 -0500948 if ffdc_check == "All" or\
Michael Walsh89de14a2018-10-01 16:51:37 -0500949 shell_rc == dump_ffdc_rc():
Michael Walsh83f4bc72017-04-20 16:49:43 -0500950 status, ret_values = grk.run_key_u("my_ffdc", ignore=1)
951 if status != 'PASS':
Michael Walshff340002017-08-29 11:18:27 -0500952 gp.qprint_error("Call to my_ffdc failed.\n")
Michael Walshc9bd2e82019-04-18 11:06:52 -0500953 # Leave a record for caller that "soft" errors occurred.
954 soft_errors = 1
955 gpu.save_plug_in_value(soft_errors, pgm_name)
Michael Walsh6741f742017-02-20 16:16:38 -0600956
Michael Walshaabef1e2017-09-20 15:16:17 -0500957 if delete_errlogs:
958 # We need to purge error logs between boots or they build up.
Michael Walsh409ad352020-02-06 11:46:35 -0600959 grk.run_key(delete_errlogs_cmd, ignore=1)
Michael Walshd139f282017-04-04 18:00:23 -0500960
Michael Walsh952f9b02017-03-09 13:11:14 -0600961 boot_results.print_report()
Michael Walshb5839d02017-04-12 16:11:20 -0500962 gp.qprint_timen("Finished boot " + str(boot_count) + ".")
Michael Walsh952f9b02017-03-09 13:11:14 -0600963
Michael Walsh6741f742017-02-20 16:16:38 -0600964 plug_in_setup()
965 rc, shell_rc, failed_plug_in_name = grpi.rprocess_plug_in_packages(
Michael Walsh89de14a2018-10-01 16:51:37 -0500966 call_point='stop_check', shell_rc=stop_test_rc(),
967 stop_on_non_zero_rc=1)
968 if shell_rc == stop_test_rc():
Michael Walsh3ba8ecd2018-04-24 11:33:25 -0500969 message = "Stopping as requested by user.\n"
Michael Walsh80dddde2019-10-22 13:54:38 -0500970 gp.qprint_time(message)
Michael Walsh3ba8ecd2018-04-24 11:33:25 -0500971 BuiltIn().fail(message)
Michael Walsh6741f742017-02-20 16:16:38 -0600972
Michael Walshd139f282017-04-04 18:00:23 -0500973 # This should help prevent ConnectionErrors.
Michael Walsh0960b382017-06-22 16:23:37 -0500974 grk.run_key_u("Close All Connections")
Michael Walshd139f282017-04-04 18:00:23 -0500975
Michael Walsh6741f742017-02-20 16:16:38 -0600976 return True
977
Michael Walsh6741f742017-02-20 16:16:38 -0600978
Michael Walsh83f4bc72017-04-20 16:49:43 -0500979def obmc_boot_test_teardown():
Michael Walsh6741f742017-02-20 16:16:38 -0600980 r"""
Michael Walshf75d4352019-12-05 17:01:20 -0600981 Clean up after the main keyword.
Michael Walsh6741f742017-02-20 16:16:38 -0600982 """
Michael Walshf75d4352019-12-05 17:01:20 -0600983 gp.qprint_executing()
984
985 if ga.psutil_imported:
986 ga.terminate_descendants()
Michael Walsh6741f742017-02-20 16:16:38 -0600987
988 if cp_setup_called:
989 plug_in_setup()
990 rc, shell_rc, failed_plug_in_name = grpi.rprocess_plug_in_packages(
Michael Walsh600876d2017-05-30 17:58:58 -0500991 call_point='cleanup', stop_on_plug_in_failure=0)
Michael Walsh6741f742017-02-20 16:16:38 -0600992
Michael Walsh600876d2017-05-30 17:58:58 -0500993 if 'boot_results_file_path' in globals():
Michael Walsh986d8ae2019-07-17 10:02:23 -0500994 # Save boot_results and boot_history objects to a file in case they are
Michael Walsh6c645742018-08-17 15:02:17 -0500995 # needed again.
Michael Walsh600876d2017-05-30 17:58:58 -0500996 gp.qprint_timen("Saving boot_results to the following path.")
997 gp.qprint_var(boot_results_file_path)
Michael Walsh986d8ae2019-07-17 10:02:23 -0500998 pickle.dump((boot_results, boot_history),
Michael Walsh6c645742018-08-17 15:02:17 -0500999 open(boot_results_file_path, 'wb'),
Michael Walsh600876d2017-05-30 17:58:58 -05001000 pickle.HIGHEST_PROTOCOL)
Michael Walsh0b93fbf2017-03-02 14:42:41 -06001001
Michael Walshff340002017-08-29 11:18:27 -05001002 global save_stack
1003 # Restore any global values saved on the save_stack.
1004 for parm_name in main_func_parm_list:
1005 # Get the parm_value if it was saved on the stack.
1006 try:
1007 parm_value = save_stack.pop(parm_name)
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -05001008 except BaseException:
Michael Walshff340002017-08-29 11:18:27 -05001009 # If it was not saved, no further action is required.
1010 continue
1011
1012 # Restore the saved value.
1013 cmd_buf = "BuiltIn().set_global_variable(\"${" + parm_name +\
1014 "}\", parm_value)"
1015 gp.dpissuing(cmd_buf)
1016 exec(cmd_buf)
1017
1018 gp.dprintn(save_stack.sprint_obj())
1019
Michael Walsh6741f742017-02-20 16:16:38 -06001020
Michael Walshc9116812017-03-10 14:23:06 -06001021def test_teardown():
Michael Walshc9116812017-03-10 14:23:06 -06001022 r"""
1023 Clean up after this test case.
1024 """
1025
1026 gp.qprintn()
Michael Walshf75d4352019-12-05 17:01:20 -06001027 gp.qprint_executing()
1028
1029 if ga.psutil_imported:
1030 ga.terminate_descendants()
1031
Michael Walshc9116812017-03-10 14:23:06 -06001032 cmd_buf = ["Print Error",
1033 "A keyword timeout occurred ending this program.\n"]
1034 BuiltIn().run_keyword_if_timeout_occurred(*cmd_buf)
1035
Michael Walshc108e422019-03-28 12:27:18 -05001036 gp.qprint_pgm_footer()
Michael Walshb5839d02017-04-12 16:11:20 -05001037
Michael Walshc9116812017-03-10 14:23:06 -06001038
Michael Walsh89de14a2018-10-01 16:51:37 -05001039def post_stack():
1040 r"""
1041 Process post_stack plug-in programs.
1042 """
1043
1044 if not call_post_stack_plug:
1045 # The caller does not wish to have post_stack plug-in processing done.
1046 return
1047
1048 global boot_success
1049
1050 # NOTE: A post_stack call-point failure is NOT counted as a boot failure.
1051 pre_boot_plug_in_setup()
1052 # For the purposes of the following plug-ins, mark the "boot" as a success.
1053 boot_success = 1
1054 plug_in_setup()
Michael Walsh815b1d52018-10-30 13:32:26 -05001055 rc, shell_rc, failed_plug_in_name, history =\
1056 grpi.rprocess_plug_in_packages(call_point='post_stack',
1057 stop_on_plug_in_failure=0,
1058 return_history=True)
Michael Walsh986d8ae2019-07-17 10:02:23 -05001059 for doing_msg in history:
1060 update_boot_history(boot_history, doing_msg, max_boot_history)
Michael Walsh815b1d52018-10-30 13:32:26 -05001061 if rc != 0:
1062 boot_success = 0
Michael Walsh89de14a2018-10-01 16:51:37 -05001063
1064 plug_in_setup()
Michael Walsh815b1d52018-10-30 13:32:26 -05001065 rc, shell_rc, failed_plug_in_name =\
1066 grpi.rprocess_plug_in_packages(call_point='ffdc_check',
1067 shell_rc=dump_ffdc_rc(),
1068 stop_on_plug_in_failure=1,
1069 stop_on_non_zero_rc=1)
1070 if shell_rc == dump_ffdc_rc():
Michael Walsh89de14a2018-10-01 16:51:37 -05001071 status, ret_values = grk.run_key_u("my_ffdc", ignore=1)
1072 if status != 'PASS':
1073 gp.qprint_error("Call to my_ffdc failed.\n")
Michael Walshc9bd2e82019-04-18 11:06:52 -05001074 # Leave a record for caller that "soft" errors occurred.
1075 soft_errors = 1
1076 gpu.save_plug_in_value(soft_errors, pgm_name)
Michael Walsh89de14a2018-10-01 16:51:37 -05001077
1078 plug_in_setup()
1079 rc, shell_rc, failed_plug_in_name = grpi.rprocess_plug_in_packages(
1080 call_point='stop_check', shell_rc=stop_test_rc(),
1081 stop_on_non_zero_rc=1)
1082 if shell_rc == stop_test_rc():
1083 message = "Stopping as requested by user.\n"
Michael Walsh80dddde2019-10-22 13:54:38 -05001084 gp.qprint_time(message)
Michael Walsh89de14a2018-10-01 16:51:37 -05001085 BuiltIn().fail(message)
1086
1087
Michael Walshff340002017-08-29 11:18:27 -05001088def obmc_boot_test_py(loc_boot_stack=None,
1089 loc_stack_mode=None,
1090 loc_quiet=None):
Michael Walsh6741f742017-02-20 16:16:38 -06001091 r"""
1092 Do main program processing.
1093 """
1094
Michael Walshff340002017-08-29 11:18:27 -05001095 global save_stack
1096
Michael Walshf75d4352019-12-05 17:01:20 -06001097 ga.set_term_options(term_requests={'pgm_names': ['process_plug_in_packages.py']})
1098
George Keishing36efbc02018-12-12 10:18:23 -06001099 gp.dprintn()
Michael Walshff340002017-08-29 11:18:27 -05001100 # Process function parms.
1101 for parm_name in main_func_parm_list:
1102 # Get parm's value.
George Keishing36efbc02018-12-12 10:18:23 -06001103 parm_value = eval("loc_" + parm_name)
1104 gp.dpvars(parm_name, parm_value)
Michael Walshff340002017-08-29 11:18:27 -05001105
George Keishing36efbc02018-12-12 10:18:23 -06001106 if parm_value is not None:
Michael Walshff340002017-08-29 11:18:27 -05001107 # Save the global value on a stack.
1108 cmd_buf = "save_stack.push(BuiltIn().get_variable_value(\"${" +\
1109 parm_name + "}\"), \"" + parm_name + "\")"
1110 gp.dpissuing(cmd_buf)
1111 exec(cmd_buf)
1112
1113 # Set the global value to the passed value.
1114 cmd_buf = "BuiltIn().set_global_variable(\"${" + parm_name +\
1115 "}\", loc_" + parm_name + ")"
1116 gp.dpissuing(cmd_buf)
1117 exec(cmd_buf)
1118
1119 gp.dprintn(save_stack.sprint_obj())
Michael Walshb5839d02017-04-12 16:11:20 -05001120
Michael Walsh6741f742017-02-20 16:16:38 -06001121 setup()
1122
Michael Walshcd9fbfd2017-09-19 12:00:08 -05001123 init_boot_pass, init_boot_fail = boot_results.return_total_pass_fail()
1124
Michael Walsha20da402017-03-31 16:27:45 -05001125 if ffdc_only:
1126 gp.qprint_timen("Caller requested ffdc_only.")
Michael Walsh986d8ae2019-07-17 10:02:23 -05001127 if do_pre_boot_plug_in_setup:
1128 pre_boot_plug_in_setup()
Michael Walsh83f4bc72017-04-20 16:49:43 -05001129 grk.run_key_u("my_ffdc")
Michael Walsh764d2f82017-04-27 16:01:08 -05001130 return
Michael Walsha20da402017-03-31 16:27:45 -05001131
Michael Walsh409ad352020-02-06 11:46:35 -06001132 if delete_errlogs:
1133 # Delete errlogs prior to doing any boot tests.
1134 grk.run_key(delete_errlogs_cmd, ignore=1)
1135
Michael Walsh6741f742017-02-20 16:16:38 -06001136 # Process caller's boot_stack.
1137 while (len(boot_stack) > 0):
1138 test_loop_body()
1139
Michael Walshb5839d02017-04-12 16:11:20 -05001140 gp.qprint_timen("Finished processing stack.")
Michael Walsh30dadae2017-02-27 14:25:52 -06001141
Michael Walsh89de14a2018-10-01 16:51:37 -05001142 post_stack()
1143
Michael Walsh6741f742017-02-20 16:16:38 -06001144 # Process caller's boot_list.
1145 if len(boot_list) > 0:
1146 for ix in range(1, max_num_tests + 1):
1147 test_loop_body()
1148
Michael Walshb5839d02017-04-12 16:11:20 -05001149 gp.qprint_timen("Completed all requested boot tests.")
1150
1151 boot_pass, boot_fail = boot_results.return_total_pass_fail()
Michael Walshcd9fbfd2017-09-19 12:00:08 -05001152 new_fail = boot_fail - init_boot_fail
1153 if new_fail > boot_fail_threshold:
Michael Walshb5839d02017-04-12 16:11:20 -05001154 error_message = "Boot failures exceed the boot failure" +\
1155 " threshold:\n" +\
Michael Walshcd9fbfd2017-09-19 12:00:08 -05001156 gp.sprint_var(new_fail) +\
Michael Walshb5839d02017-04-12 16:11:20 -05001157 gp.sprint_var(boot_fail_threshold)
1158 BuiltIn().fail(gp.sprint_error(error_message))