blob: a5a4efbb8ccf81f792406fe2db578693beab8409 [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 Walshf53d9102020-02-26 13:22:17 -060035gv.set_exit_on_error(True)
36
Michael Walsh0b93fbf2017-03-02 14:42:41 -060037base_path = os.path.dirname(os.path.dirname(
38 imp.find_module("gen_robot_print")[1])) +\
Michael Walshc9116812017-03-10 14:23:06 -060039 os.sep
Michael Walsh0b93fbf2017-03-02 14:42:41 -060040sys.path.append(base_path + "extended/")
41import run_keyword as rk
Michael Walsh0bbd8602016-11-22 11:31:49 -060042
Michael Walshe1e26442017-03-06 17:50:07 -060043# Setting master_pid correctly influences the behavior of plug-ins like
44# DB_Logging
45program_pid = os.getpid()
46master_pid = os.environ.get('AUTOBOOT_MASTER_PID', program_pid)
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -050047pgm_name = re.sub('\\.py$', '', os.path.basename(__file__))
Michael Walshe1e26442017-03-06 17:50:07 -060048
Michael Walshb5839d02017-04-12 16:11:20 -050049# Set up boot data structures.
Michael Walsh986d8ae2019-07-17 10:02:23 -050050os_host = BuiltIn().get_variable_value("${OS_HOST}", default="")
Michael Walsh0b93fbf2017-03-02 14:42:41 -060051
Michael Walsh6741f742017-02-20 16:16:38 -060052boot_lists = read_boot_lists()
Michael Walsh986d8ae2019-07-17 10:02:23 -050053
54# The maximum number of entries that can be in the boot_history global variable.
Michael Walsh815b1d52018-10-30 13:32:26 -050055max_boot_history = 10
Michael Walsh986d8ae2019-07-17 10:02:23 -050056boot_history = []
Michael Walsh6741f742017-02-20 16:16:38 -060057
Michael Walsh7dc885b2018-03-14 17:51:59 -050058state = st.return_state_constant('default_state')
Michael Walsh6741f742017-02-20 16:16:38 -060059cp_setup_called = 0
60next_boot = ""
61base_tool_dir_path = os.path.normpath(os.environ.get(
62 'AUTOBOOT_BASE_TOOL_DIR_PATH', "/tmp")) + os.sep
Michael Walshb5839d02017-04-12 16:11:20 -050063
Michael Walsh6741f742017-02-20 16:16:38 -060064ffdc_dir_path = os.path.normpath(os.environ.get('FFDC_DIR_PATH', '')) + os.sep
Michael Walsh6741f742017-02-20 16:16:38 -060065boot_success = 0
Michael Walsh6741f742017-02-20 16:16:38 -060066status_dir_path = os.environ.get('STATUS_DIR_PATH', "")
67if status_dir_path != "":
68 status_dir_path = os.path.normpath(status_dir_path) + os.sep
Michael Walshe58df1c2019-08-07 09:57:43 -050069redfish_supported = BuiltIn().get_variable_value("${REDFISH_SUPPORTED}", default=False)
70if redfish_supported:
71 default_power_on = "Redfish Power On"
72 default_power_off = "Redfish Power Off"
Michael Walsh409ad352020-02-06 11:46:35 -060073 delete_errlogs_cmd = "Delete Error Logs"
74 # TODO: delete_errlogs_cmd="Redfish Purge Event Log"
Michael Walshe58df1c2019-08-07 09:57:43 -050075else:
76 default_power_on = "REST Power On"
77 default_power_off = "REST Power Off"
Michael Walsh409ad352020-02-06 11:46:35 -060078 delete_errlogs_cmd = "Delete Error Logs"
Michael Walsh6741f742017-02-20 16:16:38 -060079boot_count = 0
Michael Walsh0bbd8602016-11-22 11:31:49 -060080
Michael Walsh85678942017-03-27 14:34:22 -050081LOG_LEVEL = BuiltIn().get_variable_value("${LOG_LEVEL}")
Michael Walsh986d8ae2019-07-17 10:02:23 -050082AUTOBOOT_FFDC_PREFIX = os.environ.get('AUTOBOOT_FFDC_PREFIX', '')
83ffdc_prefix = AUTOBOOT_FFDC_PREFIX
Sunil M325eb542017-08-10 07:09:43 -050084boot_start_time = ""
85boot_end_time = ""
Michael Walshff340002017-08-29 11:18:27 -050086save_stack = vs.var_stack('save_stack')
87main_func_parm_list = ['boot_stack', 'stack_mode', 'quiet']
Michael Walsh85678942017-03-27 14:34:22 -050088
89
Michael Walsh89de14a2018-10-01 16:51:37 -050090def dump_ffdc_rc():
91 r"""
92 Return the constant dump ffdc test return code value.
93
94 When a plug-in call point program returns this value, it indicates that
95 this program should collect FFDC.
96 """
97
98 return 0x00000200
99
100
101def stop_test_rc():
102 r"""
103 Return the constant stop test return code value.
104
105 When a plug-in call point program returns this value, it indicates that
106 this program should stop running.
107 """
108
109 return 0x00000200
110
111
Michael Walsh0ad0f7f2017-05-04 14:39:58 -0500112def process_host(host,
113 host_var_name=""):
Michael Walsh0ad0f7f2017-05-04 14:39:58 -0500114 r"""
115 Process a host by getting the associated host name and IP address and
116 setting them in global variables.
117
118 If the caller does not pass the host_var_name, this function will try to
119 figure out the name of the variable used by the caller for the host parm.
120 Callers are advised to explicitly specify the host_var_name when calling
121 with an exec command. In such cases, the get_arg_name cannot figure out
122 the host variable name.
123
124 This function will then create similar global variable names by
125 removing "_host" and appending "_host_name" or "_ip" to the host variable
126 name.
127
128 Example:
129
130 If a call is made like this:
131 process_host(openbmc_host)
132
133 Global variables openbmc_host_name and openbmc_ip will be set.
134
135 Description of argument(s):
136 host A host name or IP. The name of the variable used should
137 have a suffix of "_host".
138 host_var_name The name of the variable being used as the host parm.
139 """
140
141 if host_var_name == "":
142 host_var_name = gp.get_arg_name(0, 1, stack_frame_ix=2)
143
144 host_name_var_name = re.sub("host", "host_name", host_var_name)
145 ip_var_name = re.sub("host", "ip", host_var_name)
146 cmd_buf = "global " + host_name_var_name + ", " + ip_var_name + " ; " +\
147 host_name_var_name + ", " + ip_var_name + " = gm.get_host_name_ip('" +\
148 host + "')"
149 exec(cmd_buf)
150
Michael Walsh0ad0f7f2017-05-04 14:39:58 -0500151
Michael Walshb5839d02017-04-12 16:11:20 -0500152def process_pgm_parms():
Michael Walshb5839d02017-04-12 16:11:20 -0500153 r"""
154 Process the program parameters by assigning them all to corresponding
155 globals. Also, set some global values that depend on program parameters.
156 """
157
158 # Program parameter processing.
159 # Assign all program parms to python variables which are global to this
160 # module.
161
162 global parm_list
163 parm_list = BuiltIn().get_variable_value("${parm_list}")
164 # The following subset of parms should be processed as integers.
165 int_list = ['max_num_tests', 'boot_pass', 'boot_fail', 'ffdc_only',
Michael Walsh89de14a2018-10-01 16:51:37 -0500166 'boot_fail_threshold', 'delete_errlogs',
Michael Walsh986d8ae2019-07-17 10:02:23 -0500167 'call_post_stack_plug', 'do_pre_boot_plug_in_setup', 'quiet',
168 'test_mode', 'debug']
Michael Walshb5839d02017-04-12 16:11:20 -0500169 for parm in parm_list:
170 if parm in int_list:
171 sub_cmd = "int(BuiltIn().get_variable_value(\"${" + parm +\
172 "}\", \"0\"))"
173 else:
174 sub_cmd = "BuiltIn().get_variable_value(\"${" + parm + "}\")"
175 cmd_buf = "global " + parm + " ; " + parm + " = " + sub_cmd
Michael Walshff340002017-08-29 11:18:27 -0500176 gp.dpissuing(cmd_buf)
Michael Walshb5839d02017-04-12 16:11:20 -0500177 exec(cmd_buf)
Michael Walsh0ad0f7f2017-05-04 14:39:58 -0500178 if re.match(r".*_host$", parm):
179 cmd_buf = "process_host(" + parm + ", '" + parm + "')"
180 exec(cmd_buf)
181 if re.match(r".*_password$", parm):
182 # Register the value of any parm whose name ends in _password.
183 # This will cause the print functions to replace passwords with
184 # asterisks in the output.
185 cmd_buf = "gp.register_passwords(" + parm + ")"
186 exec(cmd_buf)
Michael Walshb5839d02017-04-12 16:11:20 -0500187
188 global ffdc_dir_path_style
189 global boot_list
190 global boot_stack
191 global boot_results_file_path
192 global boot_results
Michael Walsh986d8ae2019-07-17 10:02:23 -0500193 global boot_history
Michael Walshb5839d02017-04-12 16:11:20 -0500194 global ffdc_list_file_path
Michael Walshe0cf8d72017-05-17 13:20:46 -0500195 global ffdc_report_list_path
Michael Walsh600876d2017-05-30 17:58:58 -0500196 global ffdc_summary_list_path
Michael Walsha3e7b222020-02-03 15:32:16 -0600197 global boot_table
198 global valid_boot_types
Michael Walshb5839d02017-04-12 16:11:20 -0500199
200 if ffdc_dir_path_style == "":
201 ffdc_dir_path_style = int(os.environ.get('FFDC_DIR_PATH_STYLE', '0'))
202
203 # Convert these program parms to lists for easier processing..
George Keishing36efbc02018-12-12 10:18:23 -0600204 boot_list = list(filter(None, boot_list.split(":")))
205 boot_stack = list(filter(None, boot_stack.split(":")))
Michael Walshb5839d02017-04-12 16:11:20 -0500206
Michael Walsha3e7b222020-02-03 15:32:16 -0600207 boot_table = create_boot_table(boot_table_path, os_host=os_host)
208 valid_boot_types = create_valid_boot_list(boot_table)
209
Michael Walsh903e0b22017-09-19 17:00:33 -0500210 cleanup_boot_results_file()
211 boot_results_file_path = create_boot_results_file_path(pgm_name,
212 openbmc_nickname,
213 master_pid)
Michael Walshb5839d02017-04-12 16:11:20 -0500214
215 if os.path.isfile(boot_results_file_path):
216 # We've been called before in this run so we'll load the saved
Michael Walsh986d8ae2019-07-17 10:02:23 -0500217 # boot_results and boot_history objects.
218 boot_results, boot_history =\
Michael Walsh6c645742018-08-17 15:02:17 -0500219 pickle.load(open(boot_results_file_path, 'rb'))
Michael Walshb5839d02017-04-12 16:11:20 -0500220 else:
221 boot_results = boot_results(boot_table, boot_pass, boot_fail)
222
223 ffdc_list_file_path = base_tool_dir_path + openbmc_nickname +\
224 "/FFDC_FILE_LIST"
Michael Walshe0cf8d72017-05-17 13:20:46 -0500225 ffdc_report_list_path = base_tool_dir_path + openbmc_nickname +\
226 "/FFDC_REPORT_FILE_LIST"
Michael Walshb5839d02017-04-12 16:11:20 -0500227
Michael Walsh600876d2017-05-30 17:58:58 -0500228 ffdc_summary_list_path = base_tool_dir_path + openbmc_nickname +\
229 "/FFDC_SUMMARY_FILE_LIST"
230
Michael Walshb5839d02017-04-12 16:11:20 -0500231
Michael Walsh85678942017-03-27 14:34:22 -0500232def initial_plug_in_setup():
Michael Walsh85678942017-03-27 14:34:22 -0500233 r"""
234 Initialize all plug-in environment variables which do not change for the
235 duration of the program.
236
237 """
238
239 global LOG_LEVEL
240 BuiltIn().set_log_level("NONE")
241
242 BuiltIn().set_global_variable("${master_pid}", master_pid)
243 BuiltIn().set_global_variable("${FFDC_DIR_PATH}", ffdc_dir_path)
244 BuiltIn().set_global_variable("${STATUS_DIR_PATH}", status_dir_path)
245 BuiltIn().set_global_variable("${BASE_TOOL_DIR_PATH}", base_tool_dir_path)
246 BuiltIn().set_global_variable("${FFDC_LIST_FILE_PATH}",
247 ffdc_list_file_path)
Michael Walshe0cf8d72017-05-17 13:20:46 -0500248 BuiltIn().set_global_variable("${FFDC_REPORT_LIST_PATH}",
249 ffdc_report_list_path)
Michael Walsh600876d2017-05-30 17:58:58 -0500250 BuiltIn().set_global_variable("${FFDC_SUMMARY_LIST_PATH}",
251 ffdc_summary_list_path)
Michael Walsh85678942017-03-27 14:34:22 -0500252
253 BuiltIn().set_global_variable("${FFDC_DIR_PATH_STYLE}",
254 ffdc_dir_path_style)
255 BuiltIn().set_global_variable("${FFDC_CHECK}",
256 ffdc_check)
257
258 # For each program parameter, set the corresponding AUTOBOOT_ environment
259 # variable value. Also, set an AUTOBOOT_ environment variable for every
260 # element in additional_values.
261 additional_values = ["program_pid", "master_pid", "ffdc_dir_path",
262 "status_dir_path", "base_tool_dir_path",
Michael Walsh600876d2017-05-30 17:58:58 -0500263 "ffdc_list_file_path", "ffdc_report_list_path",
Michael Walsh0a3bdb42019-01-31 16:21:44 +0000264 "ffdc_summary_list_path", "execdir"]
Michael Walsh85678942017-03-27 14:34:22 -0500265
266 plug_in_vars = parm_list + additional_values
267
268 for var_name in plug_in_vars:
269 var_value = BuiltIn().get_variable_value("${" + var_name + "}")
270 var_name = var_name.upper()
271 if var_value is None:
272 var_value = ""
273 os.environ["AUTOBOOT_" + var_name] = str(var_value)
274
275 BuiltIn().set_log_level(LOG_LEVEL)
276
Michael Walsh68a61162017-04-25 11:54:06 -0500277 # Make sure the ffdc list directory exists.
278 ffdc_list_dir_path = os.path.dirname(ffdc_list_file_path) + os.sep
279 if not os.path.exists(ffdc_list_dir_path):
280 os.makedirs(ffdc_list_dir_path)
Michael Walsh85678942017-03-27 14:34:22 -0500281
Michael Walsh85678942017-03-27 14:34:22 -0500282
Michael Walsh0bbd8602016-11-22 11:31:49 -0600283def plug_in_setup():
Michael Walsh0bbd8602016-11-22 11:31:49 -0600284 r"""
Michael Walsh85678942017-03-27 14:34:22 -0500285 Initialize all changing plug-in environment variables for use by the
286 plug-in programs.
Michael Walsh0bbd8602016-11-22 11:31:49 -0600287 """
288
Michael Walsh85678942017-03-27 14:34:22 -0500289 global LOG_LEVEL
290 global test_really_running
291
292 BuiltIn().set_log_level("NONE")
293
Michael Walsh6741f742017-02-20 16:16:38 -0600294 boot_pass, boot_fail = boot_results.return_total_pass_fail()
Michael Walsh0bbd8602016-11-22 11:31:49 -0600295 if boot_pass > 1:
296 test_really_running = 1
297 else:
298 test_really_running = 0
299
Michael Walsh6741f742017-02-20 16:16:38 -0600300 BuiltIn().set_global_variable("${test_really_running}",
301 test_really_running)
302 BuiltIn().set_global_variable("${boot_type_desc}", next_boot)
Michael Walsh6741f742017-02-20 16:16:38 -0600303 BuiltIn().set_global_variable("${boot_pass}", boot_pass)
304 BuiltIn().set_global_variable("${boot_fail}", boot_fail)
305 BuiltIn().set_global_variable("${boot_success}", boot_success)
306 BuiltIn().set_global_variable("${ffdc_prefix}", ffdc_prefix)
Sunil M325eb542017-08-10 07:09:43 -0500307 BuiltIn().set_global_variable("${boot_start_time}", boot_start_time)
308 BuiltIn().set_global_variable("${boot_end_time}", boot_end_time)
Michael Walsh4c9a6452016-12-13 16:03:11 -0600309
Michael Walsh0bbd8602016-11-22 11:31:49 -0600310 # For each program parameter, set the corresponding AUTOBOOT_ environment
311 # variable value. Also, set an AUTOBOOT_ environment variable for every
312 # element in additional_values.
313 additional_values = ["boot_type_desc", "boot_success", "boot_pass",
Sunil M325eb542017-08-10 07:09:43 -0500314 "boot_fail", "test_really_running", "ffdc_prefix",
315 "boot_start_time", "boot_end_time"]
Michael Walsh0bbd8602016-11-22 11:31:49 -0600316
Michael Walsh85678942017-03-27 14:34:22 -0500317 plug_in_vars = additional_values
Michael Walsh0bbd8602016-11-22 11:31:49 -0600318
319 for var_name in plug_in_vars:
320 var_value = BuiltIn().get_variable_value("${" + var_name + "}")
321 var_name = var_name.upper()
322 if var_value is None:
323 var_value = ""
Michael Walsh6741f742017-02-20 16:16:38 -0600324 os.environ["AUTOBOOT_" + var_name] = str(var_value)
Michael Walsh0bbd8602016-11-22 11:31:49 -0600325
Michael Walsh0bbd8602016-11-22 11:31:49 -0600326 if debug:
Michael Walsh6741f742017-02-20 16:16:38 -0600327 shell_rc, out_buf = \
328 gc.cmd_fnc_u("printenv | egrep AUTOBOOT_ | sort -u")
Michael Walsh0bbd8602016-11-22 11:31:49 -0600329
Michael Walsh85678942017-03-27 14:34:22 -0500330 BuiltIn().set_log_level(LOG_LEVEL)
331
Michael Walsh0bbd8602016-11-22 11:31:49 -0600332
Michael Walshe0cf8d72017-05-17 13:20:46 -0500333def pre_boot_plug_in_setup():
334
335 # Clear the ffdc_list_file_path file. Plug-ins may now write to it.
336 try:
337 os.remove(ffdc_list_file_path)
338 except OSError:
339 pass
340
341 # Clear the ffdc_report_list_path file. Plug-ins may now write to it.
342 try:
343 os.remove(ffdc_report_list_path)
344 except OSError:
345 pass
346
Michael Walsh600876d2017-05-30 17:58:58 -0500347 # Clear the ffdc_summary_list_path file. Plug-ins may now write to it.
348 try:
349 os.remove(ffdc_summary_list_path)
350 except OSError:
351 pass
352
Michael Walshe1974b92017-08-03 13:39:51 -0500353 global ffdc_prefix
354
355 seconds = time.time()
356 loc_time = time.localtime(seconds)
357 time_string = time.strftime("%y%m%d.%H%M%S.", loc_time)
358
359 ffdc_prefix = openbmc_nickname + "." + time_string
360
Michael Walshe0cf8d72017-05-17 13:20:46 -0500361
Michael Walshf566fb12019-02-01 14:35:09 -0600362def default_sigusr1(signal_number=0,
363 frame=None):
364 r"""
365 Handle SIGUSR1 by doing nothing.
366
367 This function assists in debugging SIGUSR1 processing by printing messages
368 to stdout and to the log.html file.
369
370 Description of argument(s):
371 signal_number The signal number (should always be 10 for SIGUSR1).
372 frame The frame data.
373 """
374
Michael Walsh80dddde2019-10-22 13:54:38 -0500375 gp.qprintn()
376 gp.qprint_executing()
Michael Walshf566fb12019-02-01 14:35:09 -0600377 gp.lprint_executing()
378
379
380def set_default_siguser1():
381 r"""
382 Set the default_sigusr1 function to be the SIGUSR1 handler.
383 """
384
Michael Walsh80dddde2019-10-22 13:54:38 -0500385 gp.qprintn()
386 gp.qprint_executing()
Michael Walshf566fb12019-02-01 14:35:09 -0600387 gp.lprint_executing()
388 signal.signal(signal.SIGUSR1, default_sigusr1)
389
390
Michael Walsh6741f742017-02-20 16:16:38 -0600391def setup():
Michael Walsh0bbd8602016-11-22 11:31:49 -0600392 r"""
Michael Walsh6741f742017-02-20 16:16:38 -0600393 Do general program setup tasks.
Michael Walsh0bbd8602016-11-22 11:31:49 -0600394 """
395
Michael Walsh6741f742017-02-20 16:16:38 -0600396 global cp_setup_called
Michael Walsh81816742017-09-27 11:02:29 -0500397 global transitional_boot_selected
Michael Walsh0bbd8602016-11-22 11:31:49 -0600398
Michael Walshb5839d02017-04-12 16:11:20 -0500399 gp.qprintn()
400
Michael Walshf566fb12019-02-01 14:35:09 -0600401 set_default_siguser1()
Michael Walsh81816742017-09-27 11:02:29 -0500402 transitional_boot_selected = False
403
Michael Walsh83f4bc72017-04-20 16:49:43 -0500404 robot_pgm_dir_path = os.path.dirname(__file__) + os.sep
405 repo_bin_path = robot_pgm_dir_path.replace("/lib/", "/bin/")
Michael Walshd061c042017-05-23 14:46:57 -0500406 # If we can't find process_plug_in_packages.py, ssh_pw or
407 # validate_plug_ins.py, then we don't have our repo bin in PATH.
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -0500408 shell_rc, out_buf = gc.cmd_fnc_u("which process_plug_in_packages.py"
409 + " ssh_pw validate_plug_ins.py", quiet=1,
Michael Walshd061c042017-05-23 14:46:57 -0500410 print_output=0, show_err=0)
Michael Walshb5839d02017-04-12 16:11:20 -0500411 if shell_rc != 0:
Michael Walsh83f4bc72017-04-20 16:49:43 -0500412 os.environ['PATH'] = repo_bin_path + ":" + os.environ.get('PATH', "")
413 # Likewise, our repo lib subdir needs to be in sys.path and PYTHONPATH.
414 if robot_pgm_dir_path not in sys.path:
415 sys.path.append(robot_pgm_dir_path)
416 PYTHONPATH = os.environ.get("PYTHONPATH", "")
417 if PYTHONPATH == "":
418 os.environ['PYTHONPATH'] = robot_pgm_dir_path
419 else:
420 os.environ['PYTHONPATH'] = robot_pgm_dir_path + ":" + PYTHONPATH
Michael Walsh6741f742017-02-20 16:16:38 -0600421
422 validate_parms()
423
Michael Walshc108e422019-03-28 12:27:18 -0500424 gp.qprint_pgm_header()
Michael Walsh6741f742017-02-20 16:16:38 -0600425
George Keishingefc3ff22017-12-12 11:49:25 -0600426 grk.run_key("Set BMC Power Policy ALWAYS_POWER_OFF")
Michael Walsh11cfc8c2017-03-31 09:40:55 -0500427
Michael Walsh85678942017-03-27 14:34:22 -0500428 initial_plug_in_setup()
429
Michael Walsh6741f742017-02-20 16:16:38 -0600430 plug_in_setup()
431 rc, shell_rc, failed_plug_in_name = grpi.rprocess_plug_in_packages(
432 call_point='setup')
433 if rc != 0:
434 error_message = "Plug-in setup failed.\n"
Michael Walshc108e422019-03-28 12:27:18 -0500435 gp.print_error_report(error_message)
Michael Walsh6741f742017-02-20 16:16:38 -0600436 BuiltIn().fail(error_message)
437 # Setting cp_setup_called lets our Teardown know that it needs to call
438 # the cleanup plug-in call point.
439 cp_setup_called = 1
440
441 # Keyword "FFDC" will fail if TEST_MESSAGE is not set.
442 BuiltIn().set_global_variable("${TEST_MESSAGE}", "${EMPTY}")
Michael Walsh85678942017-03-27 14:34:22 -0500443 # FFDC_LOG_PATH is used by "FFDC" keyword.
444 BuiltIn().set_global_variable("${FFDC_LOG_PATH}", ffdc_dir_path)
Michael Walsh6741f742017-02-20 16:16:38 -0600445
Michael Walshdc80d672017-05-09 12:58:32 -0500446 # Also printed by FFDC.
447 global host_name
448 global host_ip
449 host = socket.gethostname()
450 host_name, host_ip = gm.get_host_name_ip(host)
451
Michael Walsh986d8ae2019-07-17 10:02:23 -0500452 gp.dprint_var(boot_table)
Michael Walshb5839d02017-04-12 16:11:20 -0500453 gp.dprint_var(boot_lists)
Michael Walsh0bbd8602016-11-22 11:31:49 -0600454
Michael Walsh0bbd8602016-11-22 11:31:49 -0600455
Michael Walsh6741f742017-02-20 16:16:38 -0600456def validate_parms():
Michael Walsh0bbd8602016-11-22 11:31:49 -0600457 r"""
Michael Walsh6741f742017-02-20 16:16:38 -0600458 Validate all program parameters.
Michael Walsh0bbd8602016-11-22 11:31:49 -0600459 """
460
Michael Walshb5839d02017-04-12 16:11:20 -0500461 process_pgm_parms()
Michael Walsh0bbd8602016-11-22 11:31:49 -0600462
Michael Walshb5839d02017-04-12 16:11:20 -0500463 gp.qprintn()
464
465 global openbmc_model
Michael Walsh44cef252019-08-01 12:38:56 -0500466 gv.valid_value(openbmc_host)
467 gv.valid_value(openbmc_username)
468 gv.valid_value(openbmc_password)
469 gv.valid_value(rest_username)
470 gv.valid_value(rest_password)
471 gv.valid_value(ipmi_username)
472 gv.valid_value(ipmi_password)
Michael Walsh6741f742017-02-20 16:16:38 -0600473 if os_host != "":
Michael Walsh44cef252019-08-01 12:38:56 -0500474 gv.valid_value(os_username)
475 gv.valid_value(os_password)
Michael Walsh0bbd8602016-11-22 11:31:49 -0600476
Michael Walsh6741f742017-02-20 16:16:38 -0600477 if pdu_host != "":
Michael Walsh44cef252019-08-01 12:38:56 -0500478 gv.valid_value(pdu_username)
479 gv.valid_value(pdu_password)
480 gv.valid_integer(pdu_slot_no)
Michael Walsh6741f742017-02-20 16:16:38 -0600481 if openbmc_serial_host != "":
Michael Walsh44cef252019-08-01 12:38:56 -0500482 gv.valid_integer(openbmc_serial_port)
Michael Walshb5839d02017-04-12 16:11:20 -0500483 if openbmc_model == "":
484 status, ret_values =\
485 grk.run_key_u("Get BMC System Model")
486 openbmc_model = ret_values
487 BuiltIn().set_global_variable("${openbmc_model}", openbmc_model)
Michael Walsh44cef252019-08-01 12:38:56 -0500488 gv.valid_value(openbmc_model)
489 gv.valid_integer(max_num_tests)
490 gv.valid_integer(boot_pass)
491 gv.valid_integer(boot_fail)
Michael Walsh6741f742017-02-20 16:16:38 -0600492
493 plug_in_packages_list = grpi.rvalidate_plug_ins(plug_in_dir_paths)
494 BuiltIn().set_global_variable("${plug_in_packages_list}",
495 plug_in_packages_list)
496
Michael Walsh44cef252019-08-01 12:38:56 -0500497 gv.valid_value(stack_mode, valid_values=['normal', 'skip'])
Michael Walsha20da402017-03-31 16:27:45 -0500498 if len(boot_list) == 0 and len(boot_stack) == 0 and not ffdc_only:
Michael Walsh6741f742017-02-20 16:16:38 -0600499 error_message = "You must provide either a value for either the" +\
500 " boot_list or the boot_stack parm.\n"
501 BuiltIn().fail(gp.sprint_error(error_message))
502
503 valid_boot_list(boot_list, valid_boot_types)
504 valid_boot_list(boot_stack, valid_boot_types)
505
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -0500506 selected_PDU_boots = list(set(boot_list + boot_stack)
507 & set(boot_lists['PDU_reboot']))
Michael Walsh11cfc8c2017-03-31 09:40:55 -0500508
509 if len(selected_PDU_boots) > 0 and pdu_host == "":
510 error_message = "You have selected the following boots which" +\
511 " require a PDU host but no value for pdu_host:\n"
512 error_message += gp.sprint_var(selected_PDU_boots)
Michael Walsh986d8ae2019-07-17 10:02:23 -0500513 error_message += gp.sprint_var(pdu_host, fmt=gp.blank())
Michael Walsh11cfc8c2017-03-31 09:40:55 -0500514 BuiltIn().fail(gp.sprint_error(error_message))
515
Michael Walsh6741f742017-02-20 16:16:38 -0600516 return
Michael Walsh0bbd8602016-11-22 11:31:49 -0600517
Michael Walsh0bbd8602016-11-22 11:31:49 -0600518
Michael Walsh6741f742017-02-20 16:16:38 -0600519def my_get_state():
Michael Walsh0bbd8602016-11-22 11:31:49 -0600520 r"""
Michael Walsh6741f742017-02-20 16:16:38 -0600521 Get the system state plus a little bit of wrapping.
Michael Walsh0bbd8602016-11-22 11:31:49 -0600522 """
523
Michael Walsh6741f742017-02-20 16:16:38 -0600524 global state
525
526 req_states = ['epoch_seconds'] + st.default_req_states
527
Michael Walshb5839d02017-04-12 16:11:20 -0500528 gp.qprint_timen("Getting system state.")
Michael Walsh6741f742017-02-20 16:16:38 -0600529 if test_mode:
530 state['epoch_seconds'] = int(time.time())
531 else:
Michael Walshb5839d02017-04-12 16:11:20 -0500532 state = st.get_state(req_states=req_states, quiet=quiet)
533 gp.qprint_var(state)
Michael Walsh341c21e2017-01-17 16:25:20 -0600534
Michael Walsh341c21e2017-01-17 16:25:20 -0600535
Michael Walsh45ca6e42017-09-14 17:29:12 -0500536def valid_state():
Michael Walsh45ca6e42017-09-14 17:29:12 -0500537 r"""
538 Verify that our state dictionary contains no blank values. If we don't get
539 valid state data, we cannot continue to work.
540 """
541
542 if st.compare_states(state, st.invalid_state_match, 'or'):
543 error_message = "The state dictionary contains blank fields which" +\
544 " is illegal.\n" + gp.sprint_var(state)
545 BuiltIn().fail(gp.sprint_error(error_message))
546
Michael Walsh45ca6e42017-09-14 17:29:12 -0500547
Michael Walsh6741f742017-02-20 16:16:38 -0600548def select_boot():
Michael Walsh341c21e2017-01-17 16:25:20 -0600549 r"""
550 Select a boot test to be run based on our current state and return the
551 chosen boot type.
552
553 Description of arguments:
Michael Walsh6741f742017-02-20 16:16:38 -0600554 state The state of the machine.
Michael Walsh341c21e2017-01-17 16:25:20 -0600555 """
556
Michael Walsh81816742017-09-27 11:02:29 -0500557 global transitional_boot_selected
Michael Walsh30dadae2017-02-27 14:25:52 -0600558 global boot_stack
559
Michael Walshb5839d02017-04-12 16:11:20 -0500560 gp.qprint_timen("Selecting a boot test.")
Michael Walsh6741f742017-02-20 16:16:38 -0600561
Michael Walsh81816742017-09-27 11:02:29 -0500562 if transitional_boot_selected and not boot_success:
563 prior_boot = next_boot
564 boot_candidate = boot_stack.pop()
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -0500565 gp.qprint_timen("The prior '" + next_boot + "' was chosen to"
566 + " transition to a valid state for '" + boot_candidate
567 + "' which was at the top of the boot_stack. Since"
568 + " the '" + next_boot + "' failed, the '"
569 + boot_candidate + "' has been removed from the stack"
570 + " to avoid and endless failure loop.")
Michael Walsh81816742017-09-27 11:02:29 -0500571 if len(boot_stack) == 0:
572 return ""
573
Michael Walsh6741f742017-02-20 16:16:38 -0600574 my_get_state()
Michael Walsh45ca6e42017-09-14 17:29:12 -0500575 valid_state()
Michael Walsh6741f742017-02-20 16:16:38 -0600576
Michael Walsh81816742017-09-27 11:02:29 -0500577 transitional_boot_selected = False
Michael Walsh6741f742017-02-20 16:16:38 -0600578 stack_popped = 0
579 if len(boot_stack) > 0:
580 stack_popped = 1
Michael Walshb5839d02017-04-12 16:11:20 -0500581 gp.qprint_dashes()
582 gp.qprint_var(boot_stack)
583 gp.qprint_dashes()
584 skip_boot_printed = 0
585 while len(boot_stack) > 0:
586 boot_candidate = boot_stack.pop()
587 if stack_mode == 'normal':
588 break
589 else:
590 if st.compare_states(state, boot_table[boot_candidate]['end']):
591 if not skip_boot_printed:
Michael Walshff340002017-08-29 11:18:27 -0500592 gp.qprint_var(stack_mode)
593 gp.qprintn()
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -0500594 gp.qprint_timen("Skipping the following boot tests"
595 + " which are unnecessary since their"
596 + " required end states match the"
597 + " current machine state:")
Michael Walshb5839d02017-04-12 16:11:20 -0500598 skip_boot_printed = 1
Michael Walshff340002017-08-29 11:18:27 -0500599 gp.qprint_var(boot_candidate)
Michael Walshb5839d02017-04-12 16:11:20 -0500600 boot_candidate = ""
601 if boot_candidate == "":
602 gp.qprint_dashes()
603 gp.qprint_var(boot_stack)
604 gp.qprint_dashes()
605 return boot_candidate
Michael Walsh6741f742017-02-20 16:16:38 -0600606 if st.compare_states(state, boot_table[boot_candidate]['start']):
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -0500607 gp.qprint_timen("The machine state is valid for a '"
608 + boot_candidate + "' boot test.")
Michael Walshb5839d02017-04-12 16:11:20 -0500609 gp.qprint_dashes()
610 gp.qprint_var(boot_stack)
611 gp.qprint_dashes()
Michael Walsh6741f742017-02-20 16:16:38 -0600612 return boot_candidate
Michael Walsh341c21e2017-01-17 16:25:20 -0600613 else:
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -0500614 gp.qprint_timen("The machine state does not match the required"
615 + " starting state for a '" + boot_candidate
616 + "' boot test:")
Michael Walsh986d8ae2019-07-17 10:02:23 -0500617 gp.qprint_varx("boot_table_start_entry",
618 boot_table[boot_candidate]['start'])
Michael Walsh6741f742017-02-20 16:16:38 -0600619 boot_stack.append(boot_candidate)
Michael Walsh81816742017-09-27 11:02:29 -0500620 transitional_boot_selected = True
Michael Walsh6741f742017-02-20 16:16:38 -0600621 popped_boot = boot_candidate
622
623 # Loop through your list selecting a boot_candidates
624 boot_candidates = []
625 for boot_candidate in boot_list:
626 if st.compare_states(state, boot_table[boot_candidate]['start']):
627 if stack_popped:
628 if st.compare_states(boot_table[boot_candidate]['end'],
Gunnar Mills096cd562018-03-26 10:19:12 -0500629 boot_table[popped_boot]['start']):
Michael Walsh6741f742017-02-20 16:16:38 -0600630 boot_candidates.append(boot_candidate)
631 else:
632 boot_candidates.append(boot_candidate)
633
634 if len(boot_candidates) == 0:
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -0500635 gp.qprint_timen("The user's boot list contained no boot tests"
636 + " which are valid for the current machine state.")
Michael Walsh6741f742017-02-20 16:16:38 -0600637 boot_candidate = default_power_on
638 if not st.compare_states(state, boot_table[default_power_on]['start']):
639 boot_candidate = default_power_off
640 boot_candidates.append(boot_candidate)
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -0500641 gp.qprint_timen("Using default '" + boot_candidate
642 + "' boot type to transition to valid state.")
Michael Walsh6741f742017-02-20 16:16:38 -0600643
Michael Walshb5839d02017-04-12 16:11:20 -0500644 gp.dprint_var(boot_candidates)
Michael Walsh6741f742017-02-20 16:16:38 -0600645
646 # Randomly select a boot from the candidate list.
647 boot = random.choice(boot_candidates)
Michael Walsh341c21e2017-01-17 16:25:20 -0600648
649 return boot
Michael Walsh0bbd8602016-11-22 11:31:49 -0600650
Michael Walsh55302292017-01-10 11:43:02 -0600651
Michael Walshb2e53ec2017-10-30 15:04:36 -0500652def print_defect_report(ffdc_file_list):
Michael Walsh341c21e2017-01-17 16:25:20 -0600653 r"""
654 Print a defect report.
Michael Walshb2e53ec2017-10-30 15:04:36 -0500655
656 Description of argument(s):
657 ffdc_file_list A list of files which were collected by our ffdc functions.
Michael Walsh341c21e2017-01-17 16:25:20 -0600658 """
659
Michael Walsh600876d2017-05-30 17:58:58 -0500660 # Making deliberate choice to NOT run plug_in_setup(). We don't want
661 # ffdc_prefix updated.
662 rc, shell_rc, failed_plug_in_name = grpi.rprocess_plug_in_packages(
663 call_point='ffdc_report', stop_on_plug_in_failure=0)
664
Michael Walshe0cf8d72017-05-17 13:20:46 -0500665 # Get additional header data which may have been created by ffdc plug-ins.
666 # Also, delete the individual header files to cleanup.
667 cmd_buf = "file_list=$(cat " + ffdc_report_list_path + " 2>/dev/null)" +\
668 " ; [ ! -z \"${file_list}\" ] && cat ${file_list}" +\
669 " 2>/dev/null ; rm -rf ${file_list} 2>/dev/null || :"
670 shell_rc, more_header_info = gc.cmd_fnc_u(cmd_buf, print_output=0,
671 show_err=0)
672
Michael Walshb2e53ec2017-10-30 15:04:36 -0500673 # Get additional summary data which may have been created by ffdc plug-ins.
Michael Walsh600876d2017-05-30 17:58:58 -0500674 # Also, delete the individual header files to cleanup.
675 cmd_buf = "file_list=$(cat " + ffdc_summary_list_path + " 2>/dev/null)" +\
676 " ; [ ! -z \"${file_list}\" ] && cat ${file_list}" +\
677 " 2>/dev/null ; rm -rf ${file_list} 2>/dev/null || :"
678 shell_rc, ffdc_summary_info = gc.cmd_fnc_u(cmd_buf, print_output=0,
679 show_err=0)
680
Michael Walshb2e53ec2017-10-30 15:04:36 -0500681 # ffdc_list_file_path contains a list of any ffdc files created by plug-
682 # ins, etc. Read that data into a list.
Michael Walsh341c21e2017-01-17 16:25:20 -0600683 try:
Michael Walshb2e53ec2017-10-30 15:04:36 -0500684 plug_in_ffdc_list = \
685 open(ffdc_list_file_path, 'r').read().rstrip("\n").split("\n")
George Keishing36efbc02018-12-12 10:18:23 -0600686 plug_in_ffdc_list = list(filter(None, plug_in_ffdc_list))
Michael Walsh341c21e2017-01-17 16:25:20 -0600687 except IOError:
Michael Walshb2e53ec2017-10-30 15:04:36 -0500688 plug_in_ffdc_list = []
689
690 # Combine the files from plug_in_ffdc_list with the ffdc_file_list passed
691 # in. Eliminate duplicates and sort the list.
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -0500692 ffdc_file_list = sorted(set(ffdc_file_list + plug_in_ffdc_list))
Michael Walshb2e53ec2017-10-30 15:04:36 -0500693
694 if status_file_path != "":
695 ffdc_file_list.insert(0, status_file_path)
696
697 # Convert the list to a printable list.
698 printable_ffdc_file_list = "\n".join(ffdc_file_list)
Michael Walsh341c21e2017-01-17 16:25:20 -0600699
Michael Walsh68a61162017-04-25 11:54:06 -0500700 # Open ffdc_file_list for writing. We will write a complete list of
701 # FFDC files to it for possible use by plug-ins like cp_stop_check.
702 ffdc_list_file = open(ffdc_list_file_path, 'w')
Michael Walshb2e53ec2017-10-30 15:04:36 -0500703 ffdc_list_file.write(printable_ffdc_file_list + "\n")
704 ffdc_list_file.close()
705
706 indent = 0
707 width = 90
708 linefeed = 1
709 char = "="
Michael Walsh68a61162017-04-25 11:54:06 -0500710
711 gp.qprintn()
Michael Walshb2e53ec2017-10-30 15:04:36 -0500712 gp.qprint_dashes(indent, width, linefeed, char)
Michael Walsh68a61162017-04-25 11:54:06 -0500713 gp.qprintn("Copy this data to the defect:\n")
714
Michael Walshe0cf8d72017-05-17 13:20:46 -0500715 if len(more_header_info) > 0:
Michael Walshff340002017-08-29 11:18:27 -0500716 gp.qprintn(more_header_info)
Michael Walshdc80d672017-05-09 12:58:32 -0500717 gp.qpvars(host_name, host_ip, openbmc_nickname, openbmc_host,
718 openbmc_host_name, openbmc_ip, openbmc_username,
Michael Walsh0a3bdb42019-01-31 16:21:44 +0000719 openbmc_password, rest_username, rest_password, ipmi_username,
720 ipmi_password, os_host, os_host_name, os_ip, os_username,
Michael Walshdc80d672017-05-09 12:58:32 -0500721 os_password, pdu_host, pdu_host_name, pdu_ip, pdu_username,
722 pdu_password, pdu_slot_no, openbmc_serial_host,
723 openbmc_serial_host_name, openbmc_serial_ip, openbmc_serial_port)
Michael Walsh68a61162017-04-25 11:54:06 -0500724
725 gp.qprintn()
Michael Walsh986d8ae2019-07-17 10:02:23 -0500726 print_boot_history(boot_history)
Michael Walsh68a61162017-04-25 11:54:06 -0500727 gp.qprintn()
728 gp.qprint_var(state)
Michael Walshb5839d02017-04-12 16:11:20 -0500729 gp.qprintn()
730 gp.qprintn("FFDC data files:")
Michael Walshb2e53ec2017-10-30 15:04:36 -0500731 gp.qprintn(printable_ffdc_file_list)
Michael Walshb5839d02017-04-12 16:11:20 -0500732 gp.qprintn()
Michael Walsh341c21e2017-01-17 16:25:20 -0600733
Michael Walsh600876d2017-05-30 17:58:58 -0500734 if len(ffdc_summary_info) > 0:
Michael Walshff340002017-08-29 11:18:27 -0500735 gp.qprintn(ffdc_summary_info)
Michael Walsh600876d2017-05-30 17:58:58 -0500736
Michael Walshb2e53ec2017-10-30 15:04:36 -0500737 gp.qprint_dashes(indent, width, linefeed, char)
Michael Walsh68a61162017-04-25 11:54:06 -0500738
Michael Walsh6741f742017-02-20 16:16:38 -0600739
Michael Walsh6741f742017-02-20 16:16:38 -0600740def my_ffdc():
Michael Walsh6741f742017-02-20 16:16:38 -0600741 r"""
742 Collect FFDC data.
743 """
744
745 global state
746
747 plug_in_setup()
748 rc, shell_rc, failed_plug_in_name = grpi.rprocess_plug_in_packages(
Michael Walsh600876d2017-05-30 17:58:58 -0500749 call_point='ffdc', stop_on_plug_in_failure=0)
Michael Walsh6741f742017-02-20 16:16:38 -0600750
751 AUTOBOOT_FFDC_PREFIX = os.environ['AUTOBOOT_FFDC_PREFIX']
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -0500752 status, ffdc_file_list = grk.run_key_u("FFDC ffdc_prefix="
753 + AUTOBOOT_FFDC_PREFIX
754 + " ffdc_function_list="
755 + ffdc_function_list, ignore=1)
Michael Walsh83f4bc72017-04-20 16:49:43 -0500756 if status != 'PASS':
Michael Walshff340002017-08-29 11:18:27 -0500757 gp.qprint_error("Call to ffdc failed.\n")
Michael Walshc9bd2e82019-04-18 11:06:52 -0500758 if type(ffdc_file_list) is not list:
759 ffdc_file_list = []
760 # Leave a record for caller that "soft" errors occurred.
761 soft_errors = 1
762 gpu.save_plug_in_value(soft_errors, pgm_name)
Michael Walsh6741f742017-02-20 16:16:38 -0600763
764 my_get_state()
765
Michael Walshb2e53ec2017-10-30 15:04:36 -0500766 print_defect_report(ffdc_file_list)
Michael Walsh6741f742017-02-20 16:16:38 -0600767
Michael Walsh6741f742017-02-20 16:16:38 -0600768
Michael Walsh6741f742017-02-20 16:16:38 -0600769def print_test_start_message(boot_keyword):
Michael Walsh6741f742017-02-20 16:16:38 -0600770 r"""
771 Print a message indicating what boot test is about to run.
772
773 Description of arguments:
774 boot_keyword The name of the boot which is to be run
775 (e.g. "BMC Power On").
776 """
777
Michael Walsh986d8ae2019-07-17 10:02:23 -0500778 global boot_history
Sunil M325eb542017-08-10 07:09:43 -0500779 global boot_start_time
Michael Walsh6741f742017-02-20 16:16:38 -0600780
781 doing_msg = gp.sprint_timen("Doing \"" + boot_keyword + "\".")
Sunil M325eb542017-08-10 07:09:43 -0500782
783 # Set boot_start_time for use by plug-ins.
784 boot_start_time = doing_msg[1:33]
785 gp.qprint_var(boot_start_time)
786
Michael Walshb5839d02017-04-12 16:11:20 -0500787 gp.qprint(doing_msg)
Michael Walsh6741f742017-02-20 16:16:38 -0600788
Michael Walsh986d8ae2019-07-17 10:02:23 -0500789 update_boot_history(boot_history, doing_msg, max_boot_history)
Michael Walsh6741f742017-02-20 16:16:38 -0600790
Michael Walsh6741f742017-02-20 16:16:38 -0600791
Michael Walshf566fb12019-02-01 14:35:09 -0600792def stop_boot_test(signal_number=0,
793 frame=None):
794 r"""
795 Handle SIGUSR1 by aborting the boot test that is running.
796
797 Description of argument(s):
798 signal_number The signal number (should always be 10 for SIGUSR1).
799 frame The frame data.
800 """
801
Michael Walsh80dddde2019-10-22 13:54:38 -0500802 gp.qprintn()
803 gp.qprint_executing()
Michael Walshf566fb12019-02-01 14:35:09 -0600804 gp.lprint_executing()
805
806 # Restore original sigusr1 handler.
807 set_default_siguser1()
808
809 message = "The caller has asked that the boot test be stopped and marked"
810 message += " as a failure."
811
812 function_stack = gm.get_function_stack()
813 if "wait_state" in function_stack:
Michael Walshc44aa532019-06-14 13:33:29 -0500814 st.set_exit_wait_early_message(message)
Michael Walshf566fb12019-02-01 14:35:09 -0600815 else:
816 BuiltIn().fail(gp.sprint_error(message))
817
818
Michael Walsh6741f742017-02-20 16:16:38 -0600819def run_boot(boot):
Michael Walsh6741f742017-02-20 16:16:38 -0600820 r"""
821 Run the specified boot.
822
823 Description of arguments:
824 boot The name of the boot test to be performed.
825 """
826
827 global state
828
Michael Walshf566fb12019-02-01 14:35:09 -0600829 signal.signal(signal.SIGUSR1, stop_boot_test)
830 gp.qprint_timen("stop_boot_test is armed.")
831
Michael Walsh6741f742017-02-20 16:16:38 -0600832 print_test_start_message(boot)
833
834 plug_in_setup()
835 rc, shell_rc, failed_plug_in_name = \
836 grpi.rprocess_plug_in_packages(call_point="pre_boot")
837 if rc != 0:
838 error_message = "Plug-in failed with non-zero return code.\n" +\
Michael Walsh986d8ae2019-07-17 10:02:23 -0500839 gp.sprint_var(rc, fmt=gp.hexa())
Michael Walshf566fb12019-02-01 14:35:09 -0600840 set_default_siguser1()
Michael Walsh6741f742017-02-20 16:16:38 -0600841 BuiltIn().fail(gp.sprint_error(error_message))
842
843 if test_mode:
844 # In test mode, we'll pretend the boot worked by assigning its
845 # required end state to the default state value.
Michael Walsh30dadae2017-02-27 14:25:52 -0600846 state = st.strip_anchor_state(boot_table[boot]['end'])
Michael Walsh6741f742017-02-20 16:16:38 -0600847 else:
848 # Assertion: We trust that the state data was made fresh by the
849 # caller.
850
Michael Walshb5839d02017-04-12 16:11:20 -0500851 gp.qprintn()
Michael Walsh6741f742017-02-20 16:16:38 -0600852
853 if boot_table[boot]['method_type'] == "keyword":
Michael Walsh0b93fbf2017-03-02 14:42:41 -0600854 rk.my_run_keywords(boot_table[boot].get('lib_file_path', ''),
Michael Walshb5839d02017-04-12 16:11:20 -0500855 boot_table[boot]['method'],
856 quiet=quiet)
Michael Walsh6741f742017-02-20 16:16:38 -0600857
858 if boot_table[boot]['bmc_reboot']:
859 st.wait_for_comm_cycle(int(state['epoch_seconds']))
Michael Walsh30dadae2017-02-27 14:25:52 -0600860 plug_in_setup()
861 rc, shell_rc, failed_plug_in_name = \
862 grpi.rprocess_plug_in_packages(call_point="post_reboot")
863 if rc != 0:
Michael Walsh0b93fbf2017-03-02 14:42:41 -0600864 error_message = "Plug-in failed with non-zero return code.\n"
Michael Walsh986d8ae2019-07-17 10:02:23 -0500865 error_message += gp.sprint_var(rc, fmt=gp.hexa())
Michael Walshf566fb12019-02-01 14:35:09 -0600866 set_default_siguser1()
Michael Walsh30dadae2017-02-27 14:25:52 -0600867 BuiltIn().fail(gp.sprint_error(error_message))
Michael Walsh6741f742017-02-20 16:16:38 -0600868 else:
869 match_state = st.anchor_state(state)
870 del match_state['epoch_seconds']
871 # Wait for the state to change in any way.
872 st.wait_state(match_state, wait_time=state_change_timeout,
Michael Walsh600876d2017-05-30 17:58:58 -0500873 interval="10 seconds", invert=1)
Michael Walsh6741f742017-02-20 16:16:38 -0600874
Michael Walshb5839d02017-04-12 16:11:20 -0500875 gp.qprintn()
Michael Walsh6741f742017-02-20 16:16:38 -0600876 if boot_table[boot]['end']['chassis'] == "Off":
877 boot_timeout = power_off_timeout
878 else:
879 boot_timeout = power_on_timeout
880 st.wait_state(boot_table[boot]['end'], wait_time=boot_timeout,
Michael Walsh600876d2017-05-30 17:58:58 -0500881 interval="10 seconds")
Michael Walsh6741f742017-02-20 16:16:38 -0600882
883 plug_in_setup()
884 rc, shell_rc, failed_plug_in_name = \
885 grpi.rprocess_plug_in_packages(call_point="post_boot")
886 if rc != 0:
887 error_message = "Plug-in failed with non-zero return code.\n" +\
Michael Walsh986d8ae2019-07-17 10:02:23 -0500888 gp.sprint_var(rc, fmt=gp.hexa())
Michael Walshf566fb12019-02-01 14:35:09 -0600889 set_default_siguser1()
Michael Walsh6741f742017-02-20 16:16:38 -0600890 BuiltIn().fail(gp.sprint_error(error_message))
891
Michael Walshf566fb12019-02-01 14:35:09 -0600892 # Restore original sigusr1 handler.
893 set_default_siguser1()
894
Michael Walsh6741f742017-02-20 16:16:38 -0600895
Michael Walsh6741f742017-02-20 16:16:38 -0600896def test_loop_body():
Michael Walsh6741f742017-02-20 16:16:38 -0600897 r"""
898 The main loop body for the loop in main_py.
899
900 Description of arguments:
901 boot_count The iteration number (starts at 1).
902 """
903
904 global boot_count
905 global state
906 global next_boot
907 global boot_success
Sunil M325eb542017-08-10 07:09:43 -0500908 global boot_end_time
Michael Walsh6741f742017-02-20 16:16:38 -0600909
Michael Walshb5839d02017-04-12 16:11:20 -0500910 gp.qprintn()
Michael Walsh6741f742017-02-20 16:16:38 -0600911
912 next_boot = select_boot()
Michael Walshb5839d02017-04-12 16:11:20 -0500913 if next_boot == "":
914 return True
Michael Walsh6741f742017-02-20 16:16:38 -0600915
Michael Walshb5839d02017-04-12 16:11:20 -0500916 boot_count += 1
917 gp.qprint_timen("Starting boot " + str(boot_count) + ".")
Michael Walsh6741f742017-02-20 16:16:38 -0600918
Michael Walshe0cf8d72017-05-17 13:20:46 -0500919 pre_boot_plug_in_setup()
Michael Walsh6741f742017-02-20 16:16:38 -0600920
921 cmd_buf = ["run_boot", next_boot]
922 boot_status, msg = BuiltIn().run_keyword_and_ignore_error(*cmd_buf)
923 if boot_status == "FAIL":
Michael Walshb5839d02017-04-12 16:11:20 -0500924 gp.qprint(msg)
Michael Walsh6741f742017-02-20 16:16:38 -0600925
Michael Walshb5839d02017-04-12 16:11:20 -0500926 gp.qprintn()
Michael Walsh6741f742017-02-20 16:16:38 -0600927 if boot_status == "PASS":
928 boot_success = 1
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -0500929 completion_msg = gp.sprint_timen("BOOT_SUCCESS: \"" + next_boot
930 + "\" succeeded.")
Michael Walsh6741f742017-02-20 16:16:38 -0600931 else:
932 boot_success = 0
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -0500933 completion_msg = gp.sprint_timen("BOOT_FAILED: \"" + next_boot
934 + "\" failed.")
Sunil M325eb542017-08-10 07:09:43 -0500935
936 # Set boot_end_time for use by plug-ins.
937 boot_end_time = completion_msg[1:33]
938 gp.qprint_var(boot_end_time)
939
940 gp.qprint(completion_msg)
Michael Walsh6741f742017-02-20 16:16:38 -0600941
942 boot_results.update(next_boot, boot_status)
943
944 plug_in_setup()
945 # NOTE: A post_test_case call point failure is NOT counted as a boot
946 # failure.
947 rc, shell_rc, failed_plug_in_name = grpi.rprocess_plug_in_packages(
Michael Walsh600876d2017-05-30 17:58:58 -0500948 call_point='post_test_case', stop_on_plug_in_failure=0)
Michael Walsh6741f742017-02-20 16:16:38 -0600949
950 plug_in_setup()
951 rc, shell_rc, failed_plug_in_name = grpi.rprocess_plug_in_packages(
Michael Walsh89de14a2018-10-01 16:51:37 -0500952 call_point='ffdc_check', shell_rc=dump_ffdc_rc(),
Michael Walsh6741f742017-02-20 16:16:38 -0600953 stop_on_plug_in_failure=1, stop_on_non_zero_rc=1)
Michael Walsh12059e22019-03-21 11:03:45 -0500954 if ffdc_check == "All" or\
Michael Walsh89de14a2018-10-01 16:51:37 -0500955 shell_rc == dump_ffdc_rc():
Michael Walsh83f4bc72017-04-20 16:49:43 -0500956 status, ret_values = grk.run_key_u("my_ffdc", ignore=1)
957 if status != 'PASS':
Michael Walshff340002017-08-29 11:18:27 -0500958 gp.qprint_error("Call to my_ffdc failed.\n")
Michael Walshc9bd2e82019-04-18 11:06:52 -0500959 # Leave a record for caller that "soft" errors occurred.
960 soft_errors = 1
961 gpu.save_plug_in_value(soft_errors, pgm_name)
Michael Walsh6741f742017-02-20 16:16:38 -0600962
Michael Walshaabef1e2017-09-20 15:16:17 -0500963 if delete_errlogs:
964 # We need to purge error logs between boots or they build up.
Michael Walsh409ad352020-02-06 11:46:35 -0600965 grk.run_key(delete_errlogs_cmd, ignore=1)
Michael Walshd139f282017-04-04 18:00:23 -0500966
Michael Walsh952f9b02017-03-09 13:11:14 -0600967 boot_results.print_report()
Michael Walshb5839d02017-04-12 16:11:20 -0500968 gp.qprint_timen("Finished boot " + str(boot_count) + ".")
Michael Walsh952f9b02017-03-09 13:11:14 -0600969
Michael Walsh6741f742017-02-20 16:16:38 -0600970 plug_in_setup()
971 rc, shell_rc, failed_plug_in_name = grpi.rprocess_plug_in_packages(
Michael Walsh89de14a2018-10-01 16:51:37 -0500972 call_point='stop_check', shell_rc=stop_test_rc(),
973 stop_on_non_zero_rc=1)
974 if shell_rc == stop_test_rc():
Michael Walsh3ba8ecd2018-04-24 11:33:25 -0500975 message = "Stopping as requested by user.\n"
Michael Walsh80dddde2019-10-22 13:54:38 -0500976 gp.qprint_time(message)
Michael Walsh3ba8ecd2018-04-24 11:33:25 -0500977 BuiltIn().fail(message)
Michael Walsh6741f742017-02-20 16:16:38 -0600978
Michael Walshd139f282017-04-04 18:00:23 -0500979 # This should help prevent ConnectionErrors.
Michael Walsh0960b382017-06-22 16:23:37 -0500980 grk.run_key_u("Close All Connections")
Michael Walshd139f282017-04-04 18:00:23 -0500981
Michael Walsh6741f742017-02-20 16:16:38 -0600982 return True
983
Michael Walsh6741f742017-02-20 16:16:38 -0600984
Michael Walsh83f4bc72017-04-20 16:49:43 -0500985def obmc_boot_test_teardown():
Michael Walsh6741f742017-02-20 16:16:38 -0600986 r"""
Michael Walshf75d4352019-12-05 17:01:20 -0600987 Clean up after the main keyword.
Michael Walsh6741f742017-02-20 16:16:38 -0600988 """
Michael Walshf75d4352019-12-05 17:01:20 -0600989 gp.qprint_executing()
990
991 if ga.psutil_imported:
992 ga.terminate_descendants()
Michael Walsh6741f742017-02-20 16:16:38 -0600993
994 if cp_setup_called:
995 plug_in_setup()
996 rc, shell_rc, failed_plug_in_name = grpi.rprocess_plug_in_packages(
Michael Walsh600876d2017-05-30 17:58:58 -0500997 call_point='cleanup', stop_on_plug_in_failure=0)
Michael Walsh6741f742017-02-20 16:16:38 -0600998
Michael Walsh600876d2017-05-30 17:58:58 -0500999 if 'boot_results_file_path' in globals():
Michael Walsh986d8ae2019-07-17 10:02:23 -05001000 # Save boot_results and boot_history objects to a file in case they are
Michael Walsh6c645742018-08-17 15:02:17 -05001001 # needed again.
Michael Walsh600876d2017-05-30 17:58:58 -05001002 gp.qprint_timen("Saving boot_results to the following path.")
1003 gp.qprint_var(boot_results_file_path)
Michael Walsh986d8ae2019-07-17 10:02:23 -05001004 pickle.dump((boot_results, boot_history),
Michael Walsh6c645742018-08-17 15:02:17 -05001005 open(boot_results_file_path, 'wb'),
Michael Walsh600876d2017-05-30 17:58:58 -05001006 pickle.HIGHEST_PROTOCOL)
Michael Walsh0b93fbf2017-03-02 14:42:41 -06001007
Michael Walshff340002017-08-29 11:18:27 -05001008 global save_stack
1009 # Restore any global values saved on the save_stack.
1010 for parm_name in main_func_parm_list:
1011 # Get the parm_value if it was saved on the stack.
1012 try:
1013 parm_value = save_stack.pop(parm_name)
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -05001014 except BaseException:
Michael Walshff340002017-08-29 11:18:27 -05001015 # If it was not saved, no further action is required.
1016 continue
1017
1018 # Restore the saved value.
1019 cmd_buf = "BuiltIn().set_global_variable(\"${" + parm_name +\
1020 "}\", parm_value)"
1021 gp.dpissuing(cmd_buf)
1022 exec(cmd_buf)
1023
1024 gp.dprintn(save_stack.sprint_obj())
1025
Michael Walsh6741f742017-02-20 16:16:38 -06001026
Michael Walshc9116812017-03-10 14:23:06 -06001027def test_teardown():
Michael Walshc9116812017-03-10 14:23:06 -06001028 r"""
1029 Clean up after this test case.
1030 """
1031
1032 gp.qprintn()
Michael Walshf75d4352019-12-05 17:01:20 -06001033 gp.qprint_executing()
1034
1035 if ga.psutil_imported:
1036 ga.terminate_descendants()
1037
Michael Walshc9116812017-03-10 14:23:06 -06001038 cmd_buf = ["Print Error",
1039 "A keyword timeout occurred ending this program.\n"]
1040 BuiltIn().run_keyword_if_timeout_occurred(*cmd_buf)
1041
Michael Walshc108e422019-03-28 12:27:18 -05001042 gp.qprint_pgm_footer()
Michael Walshb5839d02017-04-12 16:11:20 -05001043
Michael Walshc9116812017-03-10 14:23:06 -06001044
Michael Walsh89de14a2018-10-01 16:51:37 -05001045def post_stack():
1046 r"""
1047 Process post_stack plug-in programs.
1048 """
1049
1050 if not call_post_stack_plug:
1051 # The caller does not wish to have post_stack plug-in processing done.
1052 return
1053
1054 global boot_success
1055
1056 # NOTE: A post_stack call-point failure is NOT counted as a boot failure.
1057 pre_boot_plug_in_setup()
1058 # For the purposes of the following plug-ins, mark the "boot" as a success.
1059 boot_success = 1
1060 plug_in_setup()
Michael Walsh815b1d52018-10-30 13:32:26 -05001061 rc, shell_rc, failed_plug_in_name, history =\
1062 grpi.rprocess_plug_in_packages(call_point='post_stack',
1063 stop_on_plug_in_failure=0,
1064 return_history=True)
Michael Walsh986d8ae2019-07-17 10:02:23 -05001065 for doing_msg in history:
1066 update_boot_history(boot_history, doing_msg, max_boot_history)
Michael Walsh815b1d52018-10-30 13:32:26 -05001067 if rc != 0:
1068 boot_success = 0
Michael Walsh89de14a2018-10-01 16:51:37 -05001069
1070 plug_in_setup()
Michael Walsh815b1d52018-10-30 13:32:26 -05001071 rc, shell_rc, failed_plug_in_name =\
1072 grpi.rprocess_plug_in_packages(call_point='ffdc_check',
1073 shell_rc=dump_ffdc_rc(),
1074 stop_on_plug_in_failure=1,
1075 stop_on_non_zero_rc=1)
1076 if shell_rc == dump_ffdc_rc():
Michael Walsh89de14a2018-10-01 16:51:37 -05001077 status, ret_values = grk.run_key_u("my_ffdc", ignore=1)
1078 if status != 'PASS':
1079 gp.qprint_error("Call to my_ffdc failed.\n")
Michael Walshc9bd2e82019-04-18 11:06:52 -05001080 # Leave a record for caller that "soft" errors occurred.
1081 soft_errors = 1
1082 gpu.save_plug_in_value(soft_errors, pgm_name)
Michael Walsh89de14a2018-10-01 16:51:37 -05001083
1084 plug_in_setup()
1085 rc, shell_rc, failed_plug_in_name = grpi.rprocess_plug_in_packages(
1086 call_point='stop_check', shell_rc=stop_test_rc(),
1087 stop_on_non_zero_rc=1)
1088 if shell_rc == stop_test_rc():
1089 message = "Stopping as requested by user.\n"
Michael Walsh80dddde2019-10-22 13:54:38 -05001090 gp.qprint_time(message)
Michael Walsh89de14a2018-10-01 16:51:37 -05001091 BuiltIn().fail(message)
1092
1093
Michael Walshff340002017-08-29 11:18:27 -05001094def obmc_boot_test_py(loc_boot_stack=None,
1095 loc_stack_mode=None,
1096 loc_quiet=None):
Michael Walsh6741f742017-02-20 16:16:38 -06001097 r"""
1098 Do main program processing.
1099 """
1100
Michael Walshff340002017-08-29 11:18:27 -05001101 global save_stack
1102
Michael Walshf75d4352019-12-05 17:01:20 -06001103 ga.set_term_options(term_requests={'pgm_names': ['process_plug_in_packages.py']})
1104
George Keishing36efbc02018-12-12 10:18:23 -06001105 gp.dprintn()
Michael Walshff340002017-08-29 11:18:27 -05001106 # Process function parms.
1107 for parm_name in main_func_parm_list:
1108 # Get parm's value.
George Keishing36efbc02018-12-12 10:18:23 -06001109 parm_value = eval("loc_" + parm_name)
1110 gp.dpvars(parm_name, parm_value)
Michael Walshff340002017-08-29 11:18:27 -05001111
George Keishing36efbc02018-12-12 10:18:23 -06001112 if parm_value is not None:
Michael Walshff340002017-08-29 11:18:27 -05001113 # Save the global value on a stack.
1114 cmd_buf = "save_stack.push(BuiltIn().get_variable_value(\"${" +\
1115 parm_name + "}\"), \"" + parm_name + "\")"
1116 gp.dpissuing(cmd_buf)
1117 exec(cmd_buf)
1118
1119 # Set the global value to the passed value.
1120 cmd_buf = "BuiltIn().set_global_variable(\"${" + parm_name +\
1121 "}\", loc_" + parm_name + ")"
1122 gp.dpissuing(cmd_buf)
1123 exec(cmd_buf)
1124
1125 gp.dprintn(save_stack.sprint_obj())
Michael Walshb5839d02017-04-12 16:11:20 -05001126
Michael Walsh6741f742017-02-20 16:16:38 -06001127 setup()
1128
Michael Walshcd9fbfd2017-09-19 12:00:08 -05001129 init_boot_pass, init_boot_fail = boot_results.return_total_pass_fail()
1130
Michael Walsha20da402017-03-31 16:27:45 -05001131 if ffdc_only:
1132 gp.qprint_timen("Caller requested ffdc_only.")
Michael Walsh986d8ae2019-07-17 10:02:23 -05001133 if do_pre_boot_plug_in_setup:
1134 pre_boot_plug_in_setup()
Michael Walsh83f4bc72017-04-20 16:49:43 -05001135 grk.run_key_u("my_ffdc")
Michael Walsh764d2f82017-04-27 16:01:08 -05001136 return
Michael Walsha20da402017-03-31 16:27:45 -05001137
Michael Walsh409ad352020-02-06 11:46:35 -06001138 if delete_errlogs:
1139 # Delete errlogs prior to doing any boot tests.
1140 grk.run_key(delete_errlogs_cmd, ignore=1)
1141
Michael Walsh6741f742017-02-20 16:16:38 -06001142 # Process caller's boot_stack.
1143 while (len(boot_stack) > 0):
1144 test_loop_body()
1145
Michael Walshb5839d02017-04-12 16:11:20 -05001146 gp.qprint_timen("Finished processing stack.")
Michael Walsh30dadae2017-02-27 14:25:52 -06001147
Michael Walsh89de14a2018-10-01 16:51:37 -05001148 post_stack()
1149
Michael Walsh6741f742017-02-20 16:16:38 -06001150 # Process caller's boot_list.
1151 if len(boot_list) > 0:
1152 for ix in range(1, max_num_tests + 1):
1153 test_loop_body()
1154
Michael Walshb5839d02017-04-12 16:11:20 -05001155 gp.qprint_timen("Completed all requested boot tests.")
1156
1157 boot_pass, boot_fail = boot_results.return_total_pass_fail()
Michael Walshcd9fbfd2017-09-19 12:00:08 -05001158 new_fail = boot_fail - init_boot_fail
1159 if new_fail > boot_fail_threshold:
Michael Walshb5839d02017-04-12 16:11:20 -05001160 error_message = "Boot failures exceed the boot failure" +\
1161 " threshold:\n" +\
Michael Walshcd9fbfd2017-09-19 12:00:08 -05001162 gp.sprint_var(new_fail) +\
Michael Walshb5839d02017-04-12 16:11:20 -05001163 gp.sprint_var(boot_fail_threshold)
1164 BuiltIn().fail(gp.sprint_error(error_message))