blob: 68db58111aa4725e275967ecef66583da24a9de5 [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:
George Keishing89537a82020-06-17 00:37:25 -050069 redfish = BuiltIn().get_library_instance('redfish')
Michael Walshe58df1c2019-08-07 09:57:43 -050070 default_power_on = "Redfish Power On"
71 default_power_off = "Redfish Power Off"
Michael Walsh409ad352020-02-06 11:46:35 -060072 delete_errlogs_cmd = "Delete Error Logs"
73 # TODO: delete_errlogs_cmd="Redfish Purge Event Log"
George Keishing763902a2020-06-16 12:13:05 -050074 # TODO: default_set_power_policy = "Redfish Set Power Restore Policy AlwaysOff"
75 default_set_power_policy = "Set BMC Power Policy ALWAYS_POWER_OFF"
Michael Walshe58df1c2019-08-07 09:57:43 -050076else:
77 default_power_on = "REST Power On"
78 default_power_off = "REST Power Off"
Michael Walsh409ad352020-02-06 11:46:35 -060079 delete_errlogs_cmd = "Delete Error Logs"
George Keishinga54e06f2020-06-12 10:42:41 -050080 default_set_power_policy = "Set BMC Power Policy ALWAYS_POWER_OFF"
Michael Walsh6741f742017-02-20 16:16:38 -060081boot_count = 0
Michael Walsh0bbd8602016-11-22 11:31:49 -060082
Michael Walsh85678942017-03-27 14:34:22 -050083LOG_LEVEL = BuiltIn().get_variable_value("${LOG_LEVEL}")
Michael Walsh986d8ae2019-07-17 10:02:23 -050084AUTOBOOT_FFDC_PREFIX = os.environ.get('AUTOBOOT_FFDC_PREFIX', '')
85ffdc_prefix = AUTOBOOT_FFDC_PREFIX
Sunil M325eb542017-08-10 07:09:43 -050086boot_start_time = ""
87boot_end_time = ""
Michael Walshff340002017-08-29 11:18:27 -050088save_stack = vs.var_stack('save_stack')
89main_func_parm_list = ['boot_stack', 'stack_mode', 'quiet']
Michael Walsh85678942017-03-27 14:34:22 -050090
91
Michael Walsh89de14a2018-10-01 16:51:37 -050092def dump_ffdc_rc():
93 r"""
94 Return the constant dump ffdc test return code value.
95
96 When a plug-in call point program returns this value, it indicates that
97 this program should collect FFDC.
98 """
99
100 return 0x00000200
101
102
103def stop_test_rc():
104 r"""
105 Return the constant stop test return code value.
106
107 When a plug-in call point program returns this value, it indicates that
108 this program should stop running.
109 """
110
111 return 0x00000200
112
113
Michael Walsh0ad0f7f2017-05-04 14:39:58 -0500114def process_host(host,
115 host_var_name=""):
Michael Walsh0ad0f7f2017-05-04 14:39:58 -0500116 r"""
117 Process a host by getting the associated host name and IP address and
118 setting them in global variables.
119
120 If the caller does not pass the host_var_name, this function will try to
121 figure out the name of the variable used by the caller for the host parm.
122 Callers are advised to explicitly specify the host_var_name when calling
123 with an exec command. In such cases, the get_arg_name cannot figure out
124 the host variable name.
125
126 This function will then create similar global variable names by
127 removing "_host" and appending "_host_name" or "_ip" to the host variable
128 name.
129
130 Example:
131
132 If a call is made like this:
133 process_host(openbmc_host)
134
135 Global variables openbmc_host_name and openbmc_ip will be set.
136
137 Description of argument(s):
138 host A host name or IP. The name of the variable used should
139 have a suffix of "_host".
140 host_var_name The name of the variable being used as the host parm.
141 """
142
143 if host_var_name == "":
144 host_var_name = gp.get_arg_name(0, 1, stack_frame_ix=2)
145
146 host_name_var_name = re.sub("host", "host_name", host_var_name)
147 ip_var_name = re.sub("host", "ip", host_var_name)
148 cmd_buf = "global " + host_name_var_name + ", " + ip_var_name + " ; " +\
149 host_name_var_name + ", " + ip_var_name + " = gm.get_host_name_ip('" +\
150 host + "')"
151 exec(cmd_buf)
152
Michael Walsh0ad0f7f2017-05-04 14:39:58 -0500153
Michael Walshb5839d02017-04-12 16:11:20 -0500154def process_pgm_parms():
Michael Walshb5839d02017-04-12 16:11:20 -0500155 r"""
156 Process the program parameters by assigning them all to corresponding
157 globals. Also, set some global values that depend on program parameters.
158 """
159
160 # Program parameter processing.
161 # Assign all program parms to python variables which are global to this
162 # module.
163
164 global parm_list
165 parm_list = BuiltIn().get_variable_value("${parm_list}")
166 # The following subset of parms should be processed as integers.
167 int_list = ['max_num_tests', 'boot_pass', 'boot_fail', 'ffdc_only',
Michael Walsh89de14a2018-10-01 16:51:37 -0500168 'boot_fail_threshold', 'delete_errlogs',
Michael Walsh986d8ae2019-07-17 10:02:23 -0500169 'call_post_stack_plug', 'do_pre_boot_plug_in_setup', 'quiet',
170 'test_mode', 'debug']
Michael Walshb5839d02017-04-12 16:11:20 -0500171 for parm in parm_list:
172 if parm in int_list:
173 sub_cmd = "int(BuiltIn().get_variable_value(\"${" + parm +\
174 "}\", \"0\"))"
175 else:
176 sub_cmd = "BuiltIn().get_variable_value(\"${" + parm + "}\")"
177 cmd_buf = "global " + parm + " ; " + parm + " = " + sub_cmd
Michael Walshff340002017-08-29 11:18:27 -0500178 gp.dpissuing(cmd_buf)
Michael Walshb5839d02017-04-12 16:11:20 -0500179 exec(cmd_buf)
Michael Walsh0ad0f7f2017-05-04 14:39:58 -0500180 if re.match(r".*_host$", parm):
181 cmd_buf = "process_host(" + parm + ", '" + parm + "')"
182 exec(cmd_buf)
183 if re.match(r".*_password$", parm):
184 # Register the value of any parm whose name ends in _password.
185 # This will cause the print functions to replace passwords with
186 # asterisks in the output.
187 cmd_buf = "gp.register_passwords(" + parm + ")"
188 exec(cmd_buf)
Michael Walshb5839d02017-04-12 16:11:20 -0500189
190 global ffdc_dir_path_style
191 global boot_list
192 global boot_stack
193 global boot_results_file_path
194 global boot_results
Michael Walsh986d8ae2019-07-17 10:02:23 -0500195 global boot_history
Michael Walshb5839d02017-04-12 16:11:20 -0500196 global ffdc_list_file_path
Michael Walshe0cf8d72017-05-17 13:20:46 -0500197 global ffdc_report_list_path
Michael Walsh600876d2017-05-30 17:58:58 -0500198 global ffdc_summary_list_path
Michael Walsha3e7b222020-02-03 15:32:16 -0600199 global boot_table
200 global valid_boot_types
Michael Walshb5839d02017-04-12 16:11:20 -0500201
202 if ffdc_dir_path_style == "":
203 ffdc_dir_path_style = int(os.environ.get('FFDC_DIR_PATH_STYLE', '0'))
204
205 # Convert these program parms to lists for easier processing..
George Keishing36efbc02018-12-12 10:18:23 -0600206 boot_list = list(filter(None, boot_list.split(":")))
207 boot_stack = list(filter(None, boot_stack.split(":")))
Michael Walshb5839d02017-04-12 16:11:20 -0500208
Michael Walsha3e7b222020-02-03 15:32:16 -0600209 boot_table = create_boot_table(boot_table_path, os_host=os_host)
210 valid_boot_types = create_valid_boot_list(boot_table)
211
Michael Walsh903e0b22017-09-19 17:00:33 -0500212 cleanup_boot_results_file()
213 boot_results_file_path = create_boot_results_file_path(pgm_name,
214 openbmc_nickname,
215 master_pid)
Michael Walshb5839d02017-04-12 16:11:20 -0500216
217 if os.path.isfile(boot_results_file_path):
218 # We've been called before in this run so we'll load the saved
Michael Walsh986d8ae2019-07-17 10:02:23 -0500219 # boot_results and boot_history objects.
220 boot_results, boot_history =\
Michael Walsh6c645742018-08-17 15:02:17 -0500221 pickle.load(open(boot_results_file_path, 'rb'))
Michael Walshb5839d02017-04-12 16:11:20 -0500222 else:
223 boot_results = boot_results(boot_table, boot_pass, boot_fail)
224
225 ffdc_list_file_path = base_tool_dir_path + openbmc_nickname +\
226 "/FFDC_FILE_LIST"
Michael Walshe0cf8d72017-05-17 13:20:46 -0500227 ffdc_report_list_path = base_tool_dir_path + openbmc_nickname +\
228 "/FFDC_REPORT_FILE_LIST"
Michael Walshb5839d02017-04-12 16:11:20 -0500229
Michael Walsh600876d2017-05-30 17:58:58 -0500230 ffdc_summary_list_path = base_tool_dir_path + openbmc_nickname +\
231 "/FFDC_SUMMARY_FILE_LIST"
232
Michael Walshb5839d02017-04-12 16:11:20 -0500233
Michael Walsh85678942017-03-27 14:34:22 -0500234def initial_plug_in_setup():
Michael Walsh85678942017-03-27 14:34:22 -0500235 r"""
236 Initialize all plug-in environment variables which do not change for the
237 duration of the program.
238
239 """
240
241 global LOG_LEVEL
242 BuiltIn().set_log_level("NONE")
243
244 BuiltIn().set_global_variable("${master_pid}", master_pid)
245 BuiltIn().set_global_variable("${FFDC_DIR_PATH}", ffdc_dir_path)
246 BuiltIn().set_global_variable("${STATUS_DIR_PATH}", status_dir_path)
247 BuiltIn().set_global_variable("${BASE_TOOL_DIR_PATH}", base_tool_dir_path)
248 BuiltIn().set_global_variable("${FFDC_LIST_FILE_PATH}",
249 ffdc_list_file_path)
Michael Walshe0cf8d72017-05-17 13:20:46 -0500250 BuiltIn().set_global_variable("${FFDC_REPORT_LIST_PATH}",
251 ffdc_report_list_path)
Michael Walsh600876d2017-05-30 17:58:58 -0500252 BuiltIn().set_global_variable("${FFDC_SUMMARY_LIST_PATH}",
253 ffdc_summary_list_path)
Michael Walsh85678942017-03-27 14:34:22 -0500254
255 BuiltIn().set_global_variable("${FFDC_DIR_PATH_STYLE}",
256 ffdc_dir_path_style)
257 BuiltIn().set_global_variable("${FFDC_CHECK}",
258 ffdc_check)
259
260 # For each program parameter, set the corresponding AUTOBOOT_ environment
261 # variable value. Also, set an AUTOBOOT_ environment variable for every
262 # element in additional_values.
263 additional_values = ["program_pid", "master_pid", "ffdc_dir_path",
264 "status_dir_path", "base_tool_dir_path",
Michael Walsh600876d2017-05-30 17:58:58 -0500265 "ffdc_list_file_path", "ffdc_report_list_path",
George Keishinga54e06f2020-06-12 10:42:41 -0500266 "ffdc_summary_list_path", "execdir", "redfish_supported"]
Michael Walsh85678942017-03-27 14:34:22 -0500267
268 plug_in_vars = parm_list + additional_values
269
270 for var_name in plug_in_vars:
271 var_value = BuiltIn().get_variable_value("${" + var_name + "}")
272 var_name = var_name.upper()
273 if var_value is None:
274 var_value = ""
275 os.environ["AUTOBOOT_" + var_name] = str(var_value)
276
277 BuiltIn().set_log_level(LOG_LEVEL)
278
Michael Walsh68a61162017-04-25 11:54:06 -0500279 # Make sure the ffdc list directory exists.
280 ffdc_list_dir_path = os.path.dirname(ffdc_list_file_path) + os.sep
281 if not os.path.exists(ffdc_list_dir_path):
282 os.makedirs(ffdc_list_dir_path)
Michael Walsh85678942017-03-27 14:34:22 -0500283
Michael Walsh85678942017-03-27 14:34:22 -0500284
Michael Walsh0bbd8602016-11-22 11:31:49 -0600285def plug_in_setup():
Michael Walsh0bbd8602016-11-22 11:31:49 -0600286 r"""
Michael Walsh85678942017-03-27 14:34:22 -0500287 Initialize all changing plug-in environment variables for use by the
288 plug-in programs.
Michael Walsh0bbd8602016-11-22 11:31:49 -0600289 """
290
Michael Walsh85678942017-03-27 14:34:22 -0500291 global LOG_LEVEL
292 global test_really_running
293
294 BuiltIn().set_log_level("NONE")
295
Michael Walsh6741f742017-02-20 16:16:38 -0600296 boot_pass, boot_fail = boot_results.return_total_pass_fail()
Michael Walsh0bbd8602016-11-22 11:31:49 -0600297 if boot_pass > 1:
298 test_really_running = 1
299 else:
300 test_really_running = 0
301
Michael Walsh6741f742017-02-20 16:16:38 -0600302 BuiltIn().set_global_variable("${test_really_running}",
303 test_really_running)
304 BuiltIn().set_global_variable("${boot_type_desc}", next_boot)
Michael Walsh6741f742017-02-20 16:16:38 -0600305 BuiltIn().set_global_variable("${boot_pass}", boot_pass)
306 BuiltIn().set_global_variable("${boot_fail}", boot_fail)
307 BuiltIn().set_global_variable("${boot_success}", boot_success)
308 BuiltIn().set_global_variable("${ffdc_prefix}", ffdc_prefix)
Sunil M325eb542017-08-10 07:09:43 -0500309 BuiltIn().set_global_variable("${boot_start_time}", boot_start_time)
310 BuiltIn().set_global_variable("${boot_end_time}", boot_end_time)
Michael Walsh4c9a6452016-12-13 16:03:11 -0600311
Michael Walsh0bbd8602016-11-22 11:31:49 -0600312 # For each program parameter, set the corresponding AUTOBOOT_ environment
313 # variable value. Also, set an AUTOBOOT_ environment variable for every
314 # element in additional_values.
315 additional_values = ["boot_type_desc", "boot_success", "boot_pass",
Sunil M325eb542017-08-10 07:09:43 -0500316 "boot_fail", "test_really_running", "ffdc_prefix",
317 "boot_start_time", "boot_end_time"]
Michael Walsh0bbd8602016-11-22 11:31:49 -0600318
Michael Walsh85678942017-03-27 14:34:22 -0500319 plug_in_vars = additional_values
Michael Walsh0bbd8602016-11-22 11:31:49 -0600320
321 for var_name in plug_in_vars:
322 var_value = BuiltIn().get_variable_value("${" + var_name + "}")
323 var_name = var_name.upper()
324 if var_value is None:
325 var_value = ""
Michael Walsh6741f742017-02-20 16:16:38 -0600326 os.environ["AUTOBOOT_" + var_name] = str(var_value)
Michael Walsh0bbd8602016-11-22 11:31:49 -0600327
Michael Walsh0bbd8602016-11-22 11:31:49 -0600328 if debug:
Michael Walsh6741f742017-02-20 16:16:38 -0600329 shell_rc, out_buf = \
330 gc.cmd_fnc_u("printenv | egrep AUTOBOOT_ | sort -u")
Michael Walsh0bbd8602016-11-22 11:31:49 -0600331
Michael Walsh85678942017-03-27 14:34:22 -0500332 BuiltIn().set_log_level(LOG_LEVEL)
333
Michael Walsh0bbd8602016-11-22 11:31:49 -0600334
Michael Walshe0cf8d72017-05-17 13:20:46 -0500335def pre_boot_plug_in_setup():
336
337 # Clear the ffdc_list_file_path file. Plug-ins may now write to it.
338 try:
339 os.remove(ffdc_list_file_path)
340 except OSError:
341 pass
342
343 # Clear the ffdc_report_list_path file. Plug-ins may now write to it.
344 try:
345 os.remove(ffdc_report_list_path)
346 except OSError:
347 pass
348
Michael Walsh600876d2017-05-30 17:58:58 -0500349 # Clear the ffdc_summary_list_path file. Plug-ins may now write to it.
350 try:
351 os.remove(ffdc_summary_list_path)
352 except OSError:
353 pass
354
Michael Walshe1974b92017-08-03 13:39:51 -0500355 global ffdc_prefix
356
357 seconds = time.time()
358 loc_time = time.localtime(seconds)
359 time_string = time.strftime("%y%m%d.%H%M%S.", loc_time)
360
361 ffdc_prefix = openbmc_nickname + "." + time_string
362
Michael Walshe0cf8d72017-05-17 13:20:46 -0500363
Michael Walshf566fb12019-02-01 14:35:09 -0600364def default_sigusr1(signal_number=0,
365 frame=None):
366 r"""
367 Handle SIGUSR1 by doing nothing.
368
369 This function assists in debugging SIGUSR1 processing by printing messages
370 to stdout and to the log.html file.
371
372 Description of argument(s):
373 signal_number The signal number (should always be 10 for SIGUSR1).
374 frame The frame data.
375 """
376
Michael Walsh80dddde2019-10-22 13:54:38 -0500377 gp.qprintn()
378 gp.qprint_executing()
Michael Walshf566fb12019-02-01 14:35:09 -0600379 gp.lprint_executing()
380
381
382def set_default_siguser1():
383 r"""
384 Set the default_sigusr1 function to be the SIGUSR1 handler.
385 """
386
Michael Walsh80dddde2019-10-22 13:54:38 -0500387 gp.qprintn()
388 gp.qprint_executing()
Michael Walshf566fb12019-02-01 14:35:09 -0600389 gp.lprint_executing()
390 signal.signal(signal.SIGUSR1, default_sigusr1)
391
392
Michael Walsh6741f742017-02-20 16:16:38 -0600393def setup():
Michael Walsh0bbd8602016-11-22 11:31:49 -0600394 r"""
Michael Walsh6741f742017-02-20 16:16:38 -0600395 Do general program setup tasks.
Michael Walsh0bbd8602016-11-22 11:31:49 -0600396 """
397
Michael Walsh6741f742017-02-20 16:16:38 -0600398 global cp_setup_called
Michael Walsh81816742017-09-27 11:02:29 -0500399 global transitional_boot_selected
Michael Walsh0bbd8602016-11-22 11:31:49 -0600400
Michael Walshb5839d02017-04-12 16:11:20 -0500401 gp.qprintn()
402
George Keishinga54e06f2020-06-12 10:42:41 -0500403 if redfish_supported:
404 redfish.login()
405
Michael Walshf566fb12019-02-01 14:35:09 -0600406 set_default_siguser1()
Michael Walsh81816742017-09-27 11:02:29 -0500407 transitional_boot_selected = False
408
Michael Walsh83f4bc72017-04-20 16:49:43 -0500409 robot_pgm_dir_path = os.path.dirname(__file__) + os.sep
410 repo_bin_path = robot_pgm_dir_path.replace("/lib/", "/bin/")
Michael Walshd061c042017-05-23 14:46:57 -0500411 # If we can't find process_plug_in_packages.py, ssh_pw or
412 # validate_plug_ins.py, then we don't have our repo bin in PATH.
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -0500413 shell_rc, out_buf = gc.cmd_fnc_u("which process_plug_in_packages.py"
414 + " ssh_pw validate_plug_ins.py", quiet=1,
Michael Walshd061c042017-05-23 14:46:57 -0500415 print_output=0, show_err=0)
Michael Walshb5839d02017-04-12 16:11:20 -0500416 if shell_rc != 0:
Michael Walsh83f4bc72017-04-20 16:49:43 -0500417 os.environ['PATH'] = repo_bin_path + ":" + os.environ.get('PATH', "")
418 # Likewise, our repo lib subdir needs to be in sys.path and PYTHONPATH.
419 if robot_pgm_dir_path not in sys.path:
420 sys.path.append(robot_pgm_dir_path)
421 PYTHONPATH = os.environ.get("PYTHONPATH", "")
422 if PYTHONPATH == "":
423 os.environ['PYTHONPATH'] = robot_pgm_dir_path
424 else:
425 os.environ['PYTHONPATH'] = robot_pgm_dir_path + ":" + PYTHONPATH
Michael Walsh6741f742017-02-20 16:16:38 -0600426
427 validate_parms()
428
Michael Walshc108e422019-03-28 12:27:18 -0500429 gp.qprint_pgm_header()
Michael Walsh6741f742017-02-20 16:16:38 -0600430
George Keishinga54e06f2020-06-12 10:42:41 -0500431 grk.run_key_u(default_set_power_policy)
Michael Walsh11cfc8c2017-03-31 09:40:55 -0500432
Michael Walsh85678942017-03-27 14:34:22 -0500433 initial_plug_in_setup()
434
Michael Walsh6741f742017-02-20 16:16:38 -0600435 plug_in_setup()
436 rc, shell_rc, failed_plug_in_name = grpi.rprocess_plug_in_packages(
437 call_point='setup')
438 if rc != 0:
439 error_message = "Plug-in setup failed.\n"
Michael Walshc108e422019-03-28 12:27:18 -0500440 gp.print_error_report(error_message)
Michael Walsh6741f742017-02-20 16:16:38 -0600441 BuiltIn().fail(error_message)
442 # Setting cp_setup_called lets our Teardown know that it needs to call
443 # the cleanup plug-in call point.
444 cp_setup_called = 1
445
446 # Keyword "FFDC" will fail if TEST_MESSAGE is not set.
447 BuiltIn().set_global_variable("${TEST_MESSAGE}", "${EMPTY}")
Michael Walsh85678942017-03-27 14:34:22 -0500448 # FFDC_LOG_PATH is used by "FFDC" keyword.
449 BuiltIn().set_global_variable("${FFDC_LOG_PATH}", ffdc_dir_path)
Michael Walsh6741f742017-02-20 16:16:38 -0600450
Michael Walshdc80d672017-05-09 12:58:32 -0500451 # Also printed by FFDC.
452 global host_name
453 global host_ip
454 host = socket.gethostname()
455 host_name, host_ip = gm.get_host_name_ip(host)
456
Michael Walsh986d8ae2019-07-17 10:02:23 -0500457 gp.dprint_var(boot_table)
Michael Walshb5839d02017-04-12 16:11:20 -0500458 gp.dprint_var(boot_lists)
Michael Walsh0bbd8602016-11-22 11:31:49 -0600459
Michael Walsh0bbd8602016-11-22 11:31:49 -0600460
Michael Walsh6741f742017-02-20 16:16:38 -0600461def validate_parms():
Michael Walsh0bbd8602016-11-22 11:31:49 -0600462 r"""
Michael Walsh6741f742017-02-20 16:16:38 -0600463 Validate all program parameters.
Michael Walsh0bbd8602016-11-22 11:31:49 -0600464 """
465
Michael Walshb5839d02017-04-12 16:11:20 -0500466 process_pgm_parms()
Michael Walsh0bbd8602016-11-22 11:31:49 -0600467
Michael Walshb5839d02017-04-12 16:11:20 -0500468 gp.qprintn()
469
470 global openbmc_model
Michael Walshf5ce38c2020-02-27 12:46:20 -0600471 if openbmc_model == "":
472 status, ret_values =\
473 grk.run_key_u("Get BMC System Model")
474 openbmc_model = ret_values
475 BuiltIn().set_global_variable("${openbmc_model}", openbmc_model)
476 gv.set_exit_on_error(True)
Michael Walsh44cef252019-08-01 12:38:56 -0500477 gv.valid_value(openbmc_host)
478 gv.valid_value(openbmc_username)
479 gv.valid_value(openbmc_password)
480 gv.valid_value(rest_username)
481 gv.valid_value(rest_password)
482 gv.valid_value(ipmi_username)
483 gv.valid_value(ipmi_password)
Michael Walsh6741f742017-02-20 16:16:38 -0600484 if os_host != "":
Michael Walsh44cef252019-08-01 12:38:56 -0500485 gv.valid_value(os_username)
486 gv.valid_value(os_password)
Michael Walsh6741f742017-02-20 16:16:38 -0600487 if pdu_host != "":
Michael Walsh44cef252019-08-01 12:38:56 -0500488 gv.valid_value(pdu_username)
489 gv.valid_value(pdu_password)
490 gv.valid_integer(pdu_slot_no)
Michael Walsh6741f742017-02-20 16:16:38 -0600491 if openbmc_serial_host != "":
Michael Walsh44cef252019-08-01 12:38:56 -0500492 gv.valid_integer(openbmc_serial_port)
Michael Walsh44cef252019-08-01 12:38:56 -0500493 gv.valid_value(openbmc_model)
494 gv.valid_integer(max_num_tests)
495 gv.valid_integer(boot_pass)
496 gv.valid_integer(boot_fail)
Michael Walsh6741f742017-02-20 16:16:38 -0600497 plug_in_packages_list = grpi.rvalidate_plug_ins(plug_in_dir_paths)
498 BuiltIn().set_global_variable("${plug_in_packages_list}",
499 plug_in_packages_list)
Michael Walsh44cef252019-08-01 12:38:56 -0500500 gv.valid_value(stack_mode, valid_values=['normal', 'skip'])
Michael Walshf5ce38c2020-02-27 12:46:20 -0600501 gv.set_exit_on_error(False)
Michael Walsha20da402017-03-31 16:27:45 -0500502 if len(boot_list) == 0 and len(boot_stack) == 0 and not ffdc_only:
Michael Walsh6741f742017-02-20 16:16:38 -0600503 error_message = "You must provide either a value for either the" +\
504 " boot_list or the boot_stack parm.\n"
505 BuiltIn().fail(gp.sprint_error(error_message))
Michael Walsh6741f742017-02-20 16:16:38 -0600506 valid_boot_list(boot_list, valid_boot_types)
507 valid_boot_list(boot_stack, valid_boot_types)
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -0500508 selected_PDU_boots = list(set(boot_list + boot_stack)
509 & set(boot_lists['PDU_reboot']))
Michael Walsh11cfc8c2017-03-31 09:40:55 -0500510 if len(selected_PDU_boots) > 0 and pdu_host == "":
511 error_message = "You have selected the following boots which" +\
512 " require a PDU host but no value for pdu_host:\n"
513 error_message += gp.sprint_var(selected_PDU_boots)
Michael Walsh986d8ae2019-07-17 10:02:23 -0500514 error_message += gp.sprint_var(pdu_host, fmt=gp.blank())
Michael Walsh11cfc8c2017-03-31 09:40:55 -0500515 BuiltIn().fail(gp.sprint_error(error_message))
516
Michael Walsh6741f742017-02-20 16:16:38 -0600517 return
Michael Walsh0bbd8602016-11-22 11:31:49 -0600518
Michael Walsh0bbd8602016-11-22 11:31:49 -0600519
Michael Walsh6741f742017-02-20 16:16:38 -0600520def my_get_state():
Michael Walsh0bbd8602016-11-22 11:31:49 -0600521 r"""
Michael Walsh6741f742017-02-20 16:16:38 -0600522 Get the system state plus a little bit of wrapping.
Michael Walsh0bbd8602016-11-22 11:31:49 -0600523 """
524
Michael Walsh6741f742017-02-20 16:16:38 -0600525 global state
526
527 req_states = ['epoch_seconds'] + st.default_req_states
528
Michael Walshb5839d02017-04-12 16:11:20 -0500529 gp.qprint_timen("Getting system state.")
Michael Walsh6741f742017-02-20 16:16:38 -0600530 if test_mode:
531 state['epoch_seconds'] = int(time.time())
532 else:
Michael Walshb5839d02017-04-12 16:11:20 -0500533 state = st.get_state(req_states=req_states, quiet=quiet)
534 gp.qprint_var(state)
Michael Walsh341c21e2017-01-17 16:25:20 -0600535
Michael Walsh341c21e2017-01-17 16:25:20 -0600536
Michael Walsh45ca6e42017-09-14 17:29:12 -0500537def valid_state():
Michael Walsh45ca6e42017-09-14 17:29:12 -0500538 r"""
539 Verify that our state dictionary contains no blank values. If we don't get
540 valid state data, we cannot continue to work.
541 """
542
543 if st.compare_states(state, st.invalid_state_match, 'or'):
544 error_message = "The state dictionary contains blank fields which" +\
545 " is illegal.\n" + gp.sprint_var(state)
546 BuiltIn().fail(gp.sprint_error(error_message))
547
Michael Walsh45ca6e42017-09-14 17:29:12 -0500548
Michael Walsh6741f742017-02-20 16:16:38 -0600549def select_boot():
Michael Walsh341c21e2017-01-17 16:25:20 -0600550 r"""
551 Select a boot test to be run based on our current state and return the
552 chosen boot type.
553
554 Description of arguments:
Michael Walsh6741f742017-02-20 16:16:38 -0600555 state The state of the machine.
Michael Walsh341c21e2017-01-17 16:25:20 -0600556 """
557
Michael Walsh81816742017-09-27 11:02:29 -0500558 global transitional_boot_selected
Michael Walsh30dadae2017-02-27 14:25:52 -0600559 global boot_stack
560
Michael Walshb5839d02017-04-12 16:11:20 -0500561 gp.qprint_timen("Selecting a boot test.")
Michael Walsh6741f742017-02-20 16:16:38 -0600562
Michael Walsh81816742017-09-27 11:02:29 -0500563 if transitional_boot_selected and not boot_success:
564 prior_boot = next_boot
565 boot_candidate = boot_stack.pop()
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -0500566 gp.qprint_timen("The prior '" + next_boot + "' was chosen to"
567 + " transition to a valid state for '" + boot_candidate
568 + "' which was at the top of the boot_stack. Since"
569 + " the '" + next_boot + "' failed, the '"
570 + boot_candidate + "' has been removed from the stack"
571 + " to avoid and endless failure loop.")
Michael Walsh81816742017-09-27 11:02:29 -0500572 if len(boot_stack) == 0:
573 return ""
574
Michael Walsh6741f742017-02-20 16:16:38 -0600575 my_get_state()
Michael Walsh45ca6e42017-09-14 17:29:12 -0500576 valid_state()
Michael Walsh6741f742017-02-20 16:16:38 -0600577
Michael Walsh81816742017-09-27 11:02:29 -0500578 transitional_boot_selected = False
Michael Walsh6741f742017-02-20 16:16:38 -0600579 stack_popped = 0
580 if len(boot_stack) > 0:
581 stack_popped = 1
Michael Walshb5839d02017-04-12 16:11:20 -0500582 gp.qprint_dashes()
583 gp.qprint_var(boot_stack)
584 gp.qprint_dashes()
585 skip_boot_printed = 0
586 while len(boot_stack) > 0:
587 boot_candidate = boot_stack.pop()
588 if stack_mode == 'normal':
589 break
590 else:
591 if st.compare_states(state, boot_table[boot_candidate]['end']):
592 if not skip_boot_printed:
Michael Walshff340002017-08-29 11:18:27 -0500593 gp.qprint_var(stack_mode)
594 gp.qprintn()
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -0500595 gp.qprint_timen("Skipping the following boot tests"
596 + " which are unnecessary since their"
597 + " required end states match the"
598 + " current machine state:")
Michael Walshb5839d02017-04-12 16:11:20 -0500599 skip_boot_printed = 1
Michael Walshff340002017-08-29 11:18:27 -0500600 gp.qprint_var(boot_candidate)
Michael Walshb5839d02017-04-12 16:11:20 -0500601 boot_candidate = ""
602 if boot_candidate == "":
603 gp.qprint_dashes()
604 gp.qprint_var(boot_stack)
605 gp.qprint_dashes()
606 return boot_candidate
Michael Walsh6741f742017-02-20 16:16:38 -0600607 if st.compare_states(state, boot_table[boot_candidate]['start']):
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -0500608 gp.qprint_timen("The machine state is valid for a '"
609 + boot_candidate + "' boot test.")
Michael Walshb5839d02017-04-12 16:11:20 -0500610 gp.qprint_dashes()
611 gp.qprint_var(boot_stack)
612 gp.qprint_dashes()
Michael Walsh6741f742017-02-20 16:16:38 -0600613 return boot_candidate
Michael Walsh341c21e2017-01-17 16:25:20 -0600614 else:
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -0500615 gp.qprint_timen("The machine state does not match the required"
616 + " starting state for a '" + boot_candidate
617 + "' boot test:")
Michael Walsh986d8ae2019-07-17 10:02:23 -0500618 gp.qprint_varx("boot_table_start_entry",
619 boot_table[boot_candidate]['start'])
Michael Walsh6741f742017-02-20 16:16:38 -0600620 boot_stack.append(boot_candidate)
Michael Walsh81816742017-09-27 11:02:29 -0500621 transitional_boot_selected = True
Michael Walsh6741f742017-02-20 16:16:38 -0600622 popped_boot = boot_candidate
623
624 # Loop through your list selecting a boot_candidates
625 boot_candidates = []
626 for boot_candidate in boot_list:
627 if st.compare_states(state, boot_table[boot_candidate]['start']):
628 if stack_popped:
629 if st.compare_states(boot_table[boot_candidate]['end'],
Gunnar Mills096cd562018-03-26 10:19:12 -0500630 boot_table[popped_boot]['start']):
Michael Walsh6741f742017-02-20 16:16:38 -0600631 boot_candidates.append(boot_candidate)
632 else:
633 boot_candidates.append(boot_candidate)
634
635 if len(boot_candidates) == 0:
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -0500636 gp.qprint_timen("The user's boot list contained no boot tests"
637 + " which are valid for the current machine state.")
Michael Walsh6741f742017-02-20 16:16:38 -0600638 boot_candidate = default_power_on
639 if not st.compare_states(state, boot_table[default_power_on]['start']):
640 boot_candidate = default_power_off
641 boot_candidates.append(boot_candidate)
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -0500642 gp.qprint_timen("Using default '" + boot_candidate
643 + "' boot type to transition to valid state.")
Michael Walsh6741f742017-02-20 16:16:38 -0600644
Michael Walshb5839d02017-04-12 16:11:20 -0500645 gp.dprint_var(boot_candidates)
Michael Walsh6741f742017-02-20 16:16:38 -0600646
647 # Randomly select a boot from the candidate list.
648 boot = random.choice(boot_candidates)
Michael Walsh341c21e2017-01-17 16:25:20 -0600649
650 return boot
Michael Walsh0bbd8602016-11-22 11:31:49 -0600651
Michael Walsh55302292017-01-10 11:43:02 -0600652
Michael Walshb2e53ec2017-10-30 15:04:36 -0500653def print_defect_report(ffdc_file_list):
Michael Walsh341c21e2017-01-17 16:25:20 -0600654 r"""
655 Print a defect report.
Michael Walshb2e53ec2017-10-30 15:04:36 -0500656
657 Description of argument(s):
658 ffdc_file_list A list of files which were collected by our ffdc functions.
Michael Walsh341c21e2017-01-17 16:25:20 -0600659 """
660
Michael Walsh600876d2017-05-30 17:58:58 -0500661 # Making deliberate choice to NOT run plug_in_setup(). We don't want
662 # ffdc_prefix updated.
663 rc, shell_rc, failed_plug_in_name = grpi.rprocess_plug_in_packages(
664 call_point='ffdc_report', stop_on_plug_in_failure=0)
665
Michael Walshe0cf8d72017-05-17 13:20:46 -0500666 # Get additional header data which may have been created by ffdc plug-ins.
667 # Also, delete the individual header files to cleanup.
668 cmd_buf = "file_list=$(cat " + ffdc_report_list_path + " 2>/dev/null)" +\
669 " ; [ ! -z \"${file_list}\" ] && cat ${file_list}" +\
670 " 2>/dev/null ; rm -rf ${file_list} 2>/dev/null || :"
671 shell_rc, more_header_info = gc.cmd_fnc_u(cmd_buf, print_output=0,
672 show_err=0)
673
Michael Walshb2e53ec2017-10-30 15:04:36 -0500674 # Get additional summary data which may have been created by ffdc plug-ins.
Michael Walsh600876d2017-05-30 17:58:58 -0500675 # Also, delete the individual header files to cleanup.
676 cmd_buf = "file_list=$(cat " + ffdc_summary_list_path + " 2>/dev/null)" +\
677 " ; [ ! -z \"${file_list}\" ] && cat ${file_list}" +\
678 " 2>/dev/null ; rm -rf ${file_list} 2>/dev/null || :"
679 shell_rc, ffdc_summary_info = gc.cmd_fnc_u(cmd_buf, print_output=0,
680 show_err=0)
681
Michael Walshb2e53ec2017-10-30 15:04:36 -0500682 # ffdc_list_file_path contains a list of any ffdc files created by plug-
683 # ins, etc. Read that data into a list.
Michael Walsh341c21e2017-01-17 16:25:20 -0600684 try:
Michael Walshb2e53ec2017-10-30 15:04:36 -0500685 plug_in_ffdc_list = \
686 open(ffdc_list_file_path, 'r').read().rstrip("\n").split("\n")
George Keishing36efbc02018-12-12 10:18:23 -0600687 plug_in_ffdc_list = list(filter(None, plug_in_ffdc_list))
Michael Walsh341c21e2017-01-17 16:25:20 -0600688 except IOError:
Michael Walshb2e53ec2017-10-30 15:04:36 -0500689 plug_in_ffdc_list = []
690
691 # Combine the files from plug_in_ffdc_list with the ffdc_file_list passed
692 # in. Eliminate duplicates and sort the list.
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -0500693 ffdc_file_list = sorted(set(ffdc_file_list + plug_in_ffdc_list))
Michael Walshb2e53ec2017-10-30 15:04:36 -0500694
695 if status_file_path != "":
696 ffdc_file_list.insert(0, status_file_path)
697
698 # Convert the list to a printable list.
699 printable_ffdc_file_list = "\n".join(ffdc_file_list)
Michael Walsh341c21e2017-01-17 16:25:20 -0600700
Michael Walsh68a61162017-04-25 11:54:06 -0500701 # Open ffdc_file_list for writing. We will write a complete list of
702 # FFDC files to it for possible use by plug-ins like cp_stop_check.
703 ffdc_list_file = open(ffdc_list_file_path, 'w')
Michael Walshb2e53ec2017-10-30 15:04:36 -0500704 ffdc_list_file.write(printable_ffdc_file_list + "\n")
705 ffdc_list_file.close()
706
707 indent = 0
708 width = 90
709 linefeed = 1
710 char = "="
Michael Walsh68a61162017-04-25 11:54:06 -0500711
712 gp.qprintn()
Michael Walshb2e53ec2017-10-30 15:04:36 -0500713 gp.qprint_dashes(indent, width, linefeed, char)
Michael Walsh68a61162017-04-25 11:54:06 -0500714 gp.qprintn("Copy this data to the defect:\n")
715
Michael Walshe0cf8d72017-05-17 13:20:46 -0500716 if len(more_header_info) > 0:
Michael Walshff340002017-08-29 11:18:27 -0500717 gp.qprintn(more_header_info)
Michael Walshdc80d672017-05-09 12:58:32 -0500718 gp.qpvars(host_name, host_ip, openbmc_nickname, openbmc_host,
719 openbmc_host_name, openbmc_ip, openbmc_username,
Michael Walsh0a3bdb42019-01-31 16:21:44 +0000720 openbmc_password, rest_username, rest_password, ipmi_username,
721 ipmi_password, os_host, os_host_name, os_ip, os_username,
Michael Walshdc80d672017-05-09 12:58:32 -0500722 os_password, pdu_host, pdu_host_name, pdu_ip, pdu_username,
723 pdu_password, pdu_slot_no, openbmc_serial_host,
724 openbmc_serial_host_name, openbmc_serial_ip, openbmc_serial_port)
Michael Walsh68a61162017-04-25 11:54:06 -0500725
726 gp.qprintn()
Michael Walsh986d8ae2019-07-17 10:02:23 -0500727 print_boot_history(boot_history)
Michael Walsh68a61162017-04-25 11:54:06 -0500728 gp.qprintn()
729 gp.qprint_var(state)
Michael Walshb5839d02017-04-12 16:11:20 -0500730 gp.qprintn()
731 gp.qprintn("FFDC data files:")
Michael Walshb2e53ec2017-10-30 15:04:36 -0500732 gp.qprintn(printable_ffdc_file_list)
Michael Walshb5839d02017-04-12 16:11:20 -0500733 gp.qprintn()
Michael Walsh341c21e2017-01-17 16:25:20 -0600734
Michael Walsh600876d2017-05-30 17:58:58 -0500735 if len(ffdc_summary_info) > 0:
Michael Walshff340002017-08-29 11:18:27 -0500736 gp.qprintn(ffdc_summary_info)
Michael Walsh600876d2017-05-30 17:58:58 -0500737
Michael Walshb2e53ec2017-10-30 15:04:36 -0500738 gp.qprint_dashes(indent, width, linefeed, char)
Michael Walsh68a61162017-04-25 11:54:06 -0500739
Michael Walsh6741f742017-02-20 16:16:38 -0600740
Michael Walsh6741f742017-02-20 16:16:38 -0600741def my_ffdc():
Michael Walsh6741f742017-02-20 16:16:38 -0600742 r"""
743 Collect FFDC data.
744 """
745
746 global state
747
748 plug_in_setup()
749 rc, shell_rc, failed_plug_in_name = grpi.rprocess_plug_in_packages(
Michael Walsh600876d2017-05-30 17:58:58 -0500750 call_point='ffdc', stop_on_plug_in_failure=0)
Michael Walsh6741f742017-02-20 16:16:38 -0600751
752 AUTOBOOT_FFDC_PREFIX = os.environ['AUTOBOOT_FFDC_PREFIX']
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -0500753 status, ffdc_file_list = grk.run_key_u("FFDC ffdc_prefix="
754 + AUTOBOOT_FFDC_PREFIX
755 + " ffdc_function_list="
756 + ffdc_function_list, ignore=1)
Michael Walsh83f4bc72017-04-20 16:49:43 -0500757 if status != 'PASS':
Michael Walshff340002017-08-29 11:18:27 -0500758 gp.qprint_error("Call to ffdc failed.\n")
Michael Walshc9bd2e82019-04-18 11:06:52 -0500759 if type(ffdc_file_list) is not list:
760 ffdc_file_list = []
761 # Leave a record for caller that "soft" errors occurred.
762 soft_errors = 1
763 gpu.save_plug_in_value(soft_errors, pgm_name)
Michael Walsh6741f742017-02-20 16:16:38 -0600764
765 my_get_state()
766
Michael Walshb2e53ec2017-10-30 15:04:36 -0500767 print_defect_report(ffdc_file_list)
Michael Walsh6741f742017-02-20 16:16:38 -0600768
Michael Walsh6741f742017-02-20 16:16:38 -0600769
Michael Walsh6741f742017-02-20 16:16:38 -0600770def print_test_start_message(boot_keyword):
Michael Walsh6741f742017-02-20 16:16:38 -0600771 r"""
772 Print a message indicating what boot test is about to run.
773
774 Description of arguments:
775 boot_keyword The name of the boot which is to be run
776 (e.g. "BMC Power On").
777 """
778
Michael Walsh986d8ae2019-07-17 10:02:23 -0500779 global boot_history
Sunil M325eb542017-08-10 07:09:43 -0500780 global boot_start_time
Michael Walsh6741f742017-02-20 16:16:38 -0600781
782 doing_msg = gp.sprint_timen("Doing \"" + boot_keyword + "\".")
Sunil M325eb542017-08-10 07:09:43 -0500783
784 # Set boot_start_time for use by plug-ins.
785 boot_start_time = doing_msg[1:33]
786 gp.qprint_var(boot_start_time)
787
Michael Walshb5839d02017-04-12 16:11:20 -0500788 gp.qprint(doing_msg)
Michael Walsh6741f742017-02-20 16:16:38 -0600789
Michael Walsh986d8ae2019-07-17 10:02:23 -0500790 update_boot_history(boot_history, doing_msg, max_boot_history)
Michael Walsh6741f742017-02-20 16:16:38 -0600791
Michael Walsh6741f742017-02-20 16:16:38 -0600792
Michael Walshf566fb12019-02-01 14:35:09 -0600793def stop_boot_test(signal_number=0,
794 frame=None):
795 r"""
796 Handle SIGUSR1 by aborting the boot test that is running.
797
798 Description of argument(s):
799 signal_number The signal number (should always be 10 for SIGUSR1).
800 frame The frame data.
801 """
802
Michael Walsh80dddde2019-10-22 13:54:38 -0500803 gp.qprintn()
804 gp.qprint_executing()
Michael Walshf566fb12019-02-01 14:35:09 -0600805 gp.lprint_executing()
806
807 # Restore original sigusr1 handler.
808 set_default_siguser1()
809
810 message = "The caller has asked that the boot test be stopped and marked"
811 message += " as a failure."
812
813 function_stack = gm.get_function_stack()
814 if "wait_state" in function_stack:
Michael Walshc44aa532019-06-14 13:33:29 -0500815 st.set_exit_wait_early_message(message)
Michael Walshf566fb12019-02-01 14:35:09 -0600816 else:
817 BuiltIn().fail(gp.sprint_error(message))
818
819
Michael Walsh6741f742017-02-20 16:16:38 -0600820def run_boot(boot):
Michael Walsh6741f742017-02-20 16:16:38 -0600821 r"""
822 Run the specified boot.
823
824 Description of arguments:
825 boot The name of the boot test to be performed.
826 """
827
828 global state
829
Michael Walshf566fb12019-02-01 14:35:09 -0600830 signal.signal(signal.SIGUSR1, stop_boot_test)
831 gp.qprint_timen("stop_boot_test is armed.")
832
Michael Walsh6741f742017-02-20 16:16:38 -0600833 print_test_start_message(boot)
834
835 plug_in_setup()
836 rc, shell_rc, failed_plug_in_name = \
837 grpi.rprocess_plug_in_packages(call_point="pre_boot")
838 if rc != 0:
839 error_message = "Plug-in failed with non-zero return code.\n" +\
Michael Walsh986d8ae2019-07-17 10:02:23 -0500840 gp.sprint_var(rc, fmt=gp.hexa())
Michael Walshf566fb12019-02-01 14:35:09 -0600841 set_default_siguser1()
Michael Walsh6741f742017-02-20 16:16:38 -0600842 BuiltIn().fail(gp.sprint_error(error_message))
843
844 if test_mode:
845 # In test mode, we'll pretend the boot worked by assigning its
846 # required end state to the default state value.
Michael Walsh30dadae2017-02-27 14:25:52 -0600847 state = st.strip_anchor_state(boot_table[boot]['end'])
Michael Walsh6741f742017-02-20 16:16:38 -0600848 else:
849 # Assertion: We trust that the state data was made fresh by the
850 # caller.
851
Michael Walshb5839d02017-04-12 16:11:20 -0500852 gp.qprintn()
Michael Walsh6741f742017-02-20 16:16:38 -0600853
854 if boot_table[boot]['method_type'] == "keyword":
Michael Walsh0b93fbf2017-03-02 14:42:41 -0600855 rk.my_run_keywords(boot_table[boot].get('lib_file_path', ''),
Michael Walshb5839d02017-04-12 16:11:20 -0500856 boot_table[boot]['method'],
857 quiet=quiet)
Michael Walsh6741f742017-02-20 16:16:38 -0600858
859 if boot_table[boot]['bmc_reboot']:
860 st.wait_for_comm_cycle(int(state['epoch_seconds']))
Michael Walsh30dadae2017-02-27 14:25:52 -0600861 plug_in_setup()
862 rc, shell_rc, failed_plug_in_name = \
863 grpi.rprocess_plug_in_packages(call_point="post_reboot")
864 if rc != 0:
Michael Walsh0b93fbf2017-03-02 14:42:41 -0600865 error_message = "Plug-in failed with non-zero return code.\n"
Michael Walsh986d8ae2019-07-17 10:02:23 -0500866 error_message += gp.sprint_var(rc, fmt=gp.hexa())
Michael Walshf566fb12019-02-01 14:35:09 -0600867 set_default_siguser1()
Michael Walsh30dadae2017-02-27 14:25:52 -0600868 BuiltIn().fail(gp.sprint_error(error_message))
Michael Walsh6741f742017-02-20 16:16:38 -0600869 else:
870 match_state = st.anchor_state(state)
871 del match_state['epoch_seconds']
872 # Wait for the state to change in any way.
873 st.wait_state(match_state, wait_time=state_change_timeout,
Michael Walsh600876d2017-05-30 17:58:58 -0500874 interval="10 seconds", invert=1)
Michael Walsh6741f742017-02-20 16:16:38 -0600875
Michael Walshb5839d02017-04-12 16:11:20 -0500876 gp.qprintn()
Michael Walsh6741f742017-02-20 16:16:38 -0600877 if boot_table[boot]['end']['chassis'] == "Off":
878 boot_timeout = power_off_timeout
879 else:
880 boot_timeout = power_on_timeout
881 st.wait_state(boot_table[boot]['end'], wait_time=boot_timeout,
Michael Walsh600876d2017-05-30 17:58:58 -0500882 interval="10 seconds")
Michael Walsh6741f742017-02-20 16:16:38 -0600883
884 plug_in_setup()
885 rc, shell_rc, failed_plug_in_name = \
886 grpi.rprocess_plug_in_packages(call_point="post_boot")
887 if rc != 0:
888 error_message = "Plug-in failed with non-zero return code.\n" +\
Michael Walsh986d8ae2019-07-17 10:02:23 -0500889 gp.sprint_var(rc, fmt=gp.hexa())
Michael Walshf566fb12019-02-01 14:35:09 -0600890 set_default_siguser1()
Michael Walsh6741f742017-02-20 16:16:38 -0600891 BuiltIn().fail(gp.sprint_error(error_message))
892
Michael Walshf566fb12019-02-01 14:35:09 -0600893 # Restore original sigusr1 handler.
894 set_default_siguser1()
895
Michael Walsh6741f742017-02-20 16:16:38 -0600896
Michael Walsh6741f742017-02-20 16:16:38 -0600897def test_loop_body():
Michael Walsh6741f742017-02-20 16:16:38 -0600898 r"""
899 The main loop body for the loop in main_py.
900
901 Description of arguments:
902 boot_count The iteration number (starts at 1).
903 """
904
905 global boot_count
906 global state
907 global next_boot
908 global boot_success
Sunil M325eb542017-08-10 07:09:43 -0500909 global boot_end_time
Michael Walsh6741f742017-02-20 16:16:38 -0600910
Michael Walshb5839d02017-04-12 16:11:20 -0500911 gp.qprintn()
Michael Walsh6741f742017-02-20 16:16:38 -0600912
913 next_boot = select_boot()
Michael Walshb5839d02017-04-12 16:11:20 -0500914 if next_boot == "":
915 return True
Michael Walsh6741f742017-02-20 16:16:38 -0600916
Michael Walshb5839d02017-04-12 16:11:20 -0500917 boot_count += 1
918 gp.qprint_timen("Starting boot " + str(boot_count) + ".")
Michael Walsh6741f742017-02-20 16:16:38 -0600919
Michael Walshe0cf8d72017-05-17 13:20:46 -0500920 pre_boot_plug_in_setup()
Michael Walsh6741f742017-02-20 16:16:38 -0600921
922 cmd_buf = ["run_boot", next_boot]
923 boot_status, msg = BuiltIn().run_keyword_and_ignore_error(*cmd_buf)
924 if boot_status == "FAIL":
Michael Walshb5839d02017-04-12 16:11:20 -0500925 gp.qprint(msg)
Michael Walsh6741f742017-02-20 16:16:38 -0600926
Michael Walshb5839d02017-04-12 16:11:20 -0500927 gp.qprintn()
Michael Walsh6741f742017-02-20 16:16:38 -0600928 if boot_status == "PASS":
929 boot_success = 1
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -0500930 completion_msg = gp.sprint_timen("BOOT_SUCCESS: \"" + next_boot
931 + "\" succeeded.")
Michael Walsh6741f742017-02-20 16:16:38 -0600932 else:
933 boot_success = 0
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -0500934 completion_msg = gp.sprint_timen("BOOT_FAILED: \"" + next_boot
935 + "\" failed.")
Sunil M325eb542017-08-10 07:09:43 -0500936
937 # Set boot_end_time for use by plug-ins.
938 boot_end_time = completion_msg[1:33]
939 gp.qprint_var(boot_end_time)
940
941 gp.qprint(completion_msg)
Michael Walsh6741f742017-02-20 16:16:38 -0600942
943 boot_results.update(next_boot, boot_status)
944
945 plug_in_setup()
946 # NOTE: A post_test_case call point failure is NOT counted as a boot
947 # failure.
948 rc, shell_rc, failed_plug_in_name = grpi.rprocess_plug_in_packages(
Michael Walsh600876d2017-05-30 17:58:58 -0500949 call_point='post_test_case', stop_on_plug_in_failure=0)
Michael Walsh6741f742017-02-20 16:16:38 -0600950
951 plug_in_setup()
952 rc, shell_rc, failed_plug_in_name = grpi.rprocess_plug_in_packages(
Michael Walsh89de14a2018-10-01 16:51:37 -0500953 call_point='ffdc_check', shell_rc=dump_ffdc_rc(),
Michael Walsh6741f742017-02-20 16:16:38 -0600954 stop_on_plug_in_failure=1, stop_on_non_zero_rc=1)
Michael Walsh12059e22019-03-21 11:03:45 -0500955 if ffdc_check == "All" or\
Michael Walsh89de14a2018-10-01 16:51:37 -0500956 shell_rc == dump_ffdc_rc():
Michael Walsh83f4bc72017-04-20 16:49:43 -0500957 status, ret_values = grk.run_key_u("my_ffdc", ignore=1)
958 if status != 'PASS':
Michael Walshff340002017-08-29 11:18:27 -0500959 gp.qprint_error("Call to my_ffdc failed.\n")
Michael Walshc9bd2e82019-04-18 11:06:52 -0500960 # Leave a record for caller that "soft" errors occurred.
961 soft_errors = 1
962 gpu.save_plug_in_value(soft_errors, pgm_name)
Michael Walsh6741f742017-02-20 16:16:38 -0600963
Michael Walshaabef1e2017-09-20 15:16:17 -0500964 if delete_errlogs:
965 # We need to purge error logs between boots or they build up.
Michael Walsh409ad352020-02-06 11:46:35 -0600966 grk.run_key(delete_errlogs_cmd, ignore=1)
Michael Walshd139f282017-04-04 18:00:23 -0500967
Michael Walsh952f9b02017-03-09 13:11:14 -0600968 boot_results.print_report()
Michael Walshb5839d02017-04-12 16:11:20 -0500969 gp.qprint_timen("Finished boot " + str(boot_count) + ".")
Michael Walsh952f9b02017-03-09 13:11:14 -0600970
Michael Walsh6741f742017-02-20 16:16:38 -0600971 plug_in_setup()
972 rc, shell_rc, failed_plug_in_name = grpi.rprocess_plug_in_packages(
Michael Walsh89de14a2018-10-01 16:51:37 -0500973 call_point='stop_check', shell_rc=stop_test_rc(),
974 stop_on_non_zero_rc=1)
975 if shell_rc == stop_test_rc():
Michael Walsh3ba8ecd2018-04-24 11:33:25 -0500976 message = "Stopping as requested by user.\n"
Michael Walsh80dddde2019-10-22 13:54:38 -0500977 gp.qprint_time(message)
Michael Walsh3ba8ecd2018-04-24 11:33:25 -0500978 BuiltIn().fail(message)
Michael Walsh6741f742017-02-20 16:16:38 -0600979
Michael Walshd139f282017-04-04 18:00:23 -0500980 # This should help prevent ConnectionErrors.
Michael Walsh0960b382017-06-22 16:23:37 -0500981 grk.run_key_u("Close All Connections")
Michael Walshd139f282017-04-04 18:00:23 -0500982
Michael Walsh6741f742017-02-20 16:16:38 -0600983 return True
984
Michael Walsh6741f742017-02-20 16:16:38 -0600985
Michael Walsh83f4bc72017-04-20 16:49:43 -0500986def obmc_boot_test_teardown():
Michael Walsh6741f742017-02-20 16:16:38 -0600987 r"""
Michael Walshf75d4352019-12-05 17:01:20 -0600988 Clean up after the main keyword.
Michael Walsh6741f742017-02-20 16:16:38 -0600989 """
Michael Walshf75d4352019-12-05 17:01:20 -0600990 gp.qprint_executing()
991
992 if ga.psutil_imported:
993 ga.terminate_descendants()
Michael Walsh6741f742017-02-20 16:16:38 -0600994
995 if cp_setup_called:
996 plug_in_setup()
997 rc, shell_rc, failed_plug_in_name = grpi.rprocess_plug_in_packages(
Michael Walsh600876d2017-05-30 17:58:58 -0500998 call_point='cleanup', stop_on_plug_in_failure=0)
Michael Walsh6741f742017-02-20 16:16:38 -0600999
Michael Walsh600876d2017-05-30 17:58:58 -05001000 if 'boot_results_file_path' in globals():
Michael Walsh986d8ae2019-07-17 10:02:23 -05001001 # Save boot_results and boot_history objects to a file in case they are
Michael Walsh6c645742018-08-17 15:02:17 -05001002 # needed again.
Michael Walsh600876d2017-05-30 17:58:58 -05001003 gp.qprint_timen("Saving boot_results to the following path.")
1004 gp.qprint_var(boot_results_file_path)
Michael Walsh986d8ae2019-07-17 10:02:23 -05001005 pickle.dump((boot_results, boot_history),
Michael Walsh6c645742018-08-17 15:02:17 -05001006 open(boot_results_file_path, 'wb'),
Michael Walsh600876d2017-05-30 17:58:58 -05001007 pickle.HIGHEST_PROTOCOL)
Michael Walsh0b93fbf2017-03-02 14:42:41 -06001008
Michael Walshff340002017-08-29 11:18:27 -05001009 global save_stack
1010 # Restore any global values saved on the save_stack.
1011 for parm_name in main_func_parm_list:
1012 # Get the parm_value if it was saved on the stack.
1013 try:
1014 parm_value = save_stack.pop(parm_name)
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -05001015 except BaseException:
Michael Walshff340002017-08-29 11:18:27 -05001016 # If it was not saved, no further action is required.
1017 continue
1018
1019 # Restore the saved value.
1020 cmd_buf = "BuiltIn().set_global_variable(\"${" + parm_name +\
1021 "}\", parm_value)"
1022 gp.dpissuing(cmd_buf)
1023 exec(cmd_buf)
1024
1025 gp.dprintn(save_stack.sprint_obj())
1026
Michael Walsh6741f742017-02-20 16:16:38 -06001027
Michael Walshc9116812017-03-10 14:23:06 -06001028def test_teardown():
Michael Walshc9116812017-03-10 14:23:06 -06001029 r"""
1030 Clean up after this test case.
1031 """
1032
1033 gp.qprintn()
Michael Walshf75d4352019-12-05 17:01:20 -06001034 gp.qprint_executing()
1035
1036 if ga.psutil_imported:
1037 ga.terminate_descendants()
1038
Michael Walshc9116812017-03-10 14:23:06 -06001039 cmd_buf = ["Print Error",
1040 "A keyword timeout occurred ending this program.\n"]
1041 BuiltIn().run_keyword_if_timeout_occurred(*cmd_buf)
1042
George Keishinga54e06f2020-06-12 10:42:41 -05001043 if redfish_supported:
1044 redfish.logout()
1045
Michael Walshc108e422019-03-28 12:27:18 -05001046 gp.qprint_pgm_footer()
Michael Walshb5839d02017-04-12 16:11:20 -05001047
Michael Walshc9116812017-03-10 14:23:06 -06001048
Michael Walsh89de14a2018-10-01 16:51:37 -05001049def post_stack():
1050 r"""
1051 Process post_stack plug-in programs.
1052 """
1053
1054 if not call_post_stack_plug:
1055 # The caller does not wish to have post_stack plug-in processing done.
1056 return
1057
1058 global boot_success
1059
1060 # NOTE: A post_stack call-point failure is NOT counted as a boot failure.
1061 pre_boot_plug_in_setup()
1062 # For the purposes of the following plug-ins, mark the "boot" as a success.
1063 boot_success = 1
1064 plug_in_setup()
Michael Walsh815b1d52018-10-30 13:32:26 -05001065 rc, shell_rc, failed_plug_in_name, history =\
1066 grpi.rprocess_plug_in_packages(call_point='post_stack',
1067 stop_on_plug_in_failure=0,
1068 return_history=True)
Michael Walsh986d8ae2019-07-17 10:02:23 -05001069 for doing_msg in history:
1070 update_boot_history(boot_history, doing_msg, max_boot_history)
Michael Walsh815b1d52018-10-30 13:32:26 -05001071 if rc != 0:
1072 boot_success = 0
Michael Walsh89de14a2018-10-01 16:51:37 -05001073
1074 plug_in_setup()
Michael Walsh815b1d52018-10-30 13:32:26 -05001075 rc, shell_rc, failed_plug_in_name =\
1076 grpi.rprocess_plug_in_packages(call_point='ffdc_check',
1077 shell_rc=dump_ffdc_rc(),
1078 stop_on_plug_in_failure=1,
1079 stop_on_non_zero_rc=1)
1080 if shell_rc == dump_ffdc_rc():
Michael Walsh89de14a2018-10-01 16:51:37 -05001081 status, ret_values = grk.run_key_u("my_ffdc", ignore=1)
1082 if status != 'PASS':
1083 gp.qprint_error("Call to my_ffdc failed.\n")
Michael Walshc9bd2e82019-04-18 11:06:52 -05001084 # Leave a record for caller that "soft" errors occurred.
1085 soft_errors = 1
1086 gpu.save_plug_in_value(soft_errors, pgm_name)
Michael Walsh89de14a2018-10-01 16:51:37 -05001087
1088 plug_in_setup()
1089 rc, shell_rc, failed_plug_in_name = grpi.rprocess_plug_in_packages(
1090 call_point='stop_check', shell_rc=stop_test_rc(),
1091 stop_on_non_zero_rc=1)
1092 if shell_rc == stop_test_rc():
1093 message = "Stopping as requested by user.\n"
Michael Walsh80dddde2019-10-22 13:54:38 -05001094 gp.qprint_time(message)
Michael Walsh89de14a2018-10-01 16:51:37 -05001095 BuiltIn().fail(message)
1096
1097
Michael Walshff340002017-08-29 11:18:27 -05001098def obmc_boot_test_py(loc_boot_stack=None,
1099 loc_stack_mode=None,
1100 loc_quiet=None):
Michael Walsh6741f742017-02-20 16:16:38 -06001101 r"""
1102 Do main program processing.
1103 """
1104
Michael Walshff340002017-08-29 11:18:27 -05001105 global save_stack
1106
Michael Walshf75d4352019-12-05 17:01:20 -06001107 ga.set_term_options(term_requests={'pgm_names': ['process_plug_in_packages.py']})
1108
George Keishing36efbc02018-12-12 10:18:23 -06001109 gp.dprintn()
Michael Walshff340002017-08-29 11:18:27 -05001110 # Process function parms.
1111 for parm_name in main_func_parm_list:
1112 # Get parm's value.
George Keishing36efbc02018-12-12 10:18:23 -06001113 parm_value = eval("loc_" + parm_name)
1114 gp.dpvars(parm_name, parm_value)
Michael Walshff340002017-08-29 11:18:27 -05001115
George Keishing36efbc02018-12-12 10:18:23 -06001116 if parm_value is not None:
Michael Walshff340002017-08-29 11:18:27 -05001117 # Save the global value on a stack.
1118 cmd_buf = "save_stack.push(BuiltIn().get_variable_value(\"${" +\
1119 parm_name + "}\"), \"" + parm_name + "\")"
1120 gp.dpissuing(cmd_buf)
1121 exec(cmd_buf)
1122
1123 # Set the global value to the passed value.
1124 cmd_buf = "BuiltIn().set_global_variable(\"${" + parm_name +\
1125 "}\", loc_" + parm_name + ")"
1126 gp.dpissuing(cmd_buf)
1127 exec(cmd_buf)
1128
1129 gp.dprintn(save_stack.sprint_obj())
Michael Walshb5839d02017-04-12 16:11:20 -05001130
Michael Walsh6741f742017-02-20 16:16:38 -06001131 setup()
1132
Michael Walshcd9fbfd2017-09-19 12:00:08 -05001133 init_boot_pass, init_boot_fail = boot_results.return_total_pass_fail()
1134
Michael Walsha20da402017-03-31 16:27:45 -05001135 if ffdc_only:
1136 gp.qprint_timen("Caller requested ffdc_only.")
Michael Walsh986d8ae2019-07-17 10:02:23 -05001137 if do_pre_boot_plug_in_setup:
1138 pre_boot_plug_in_setup()
Michael Walsh83f4bc72017-04-20 16:49:43 -05001139 grk.run_key_u("my_ffdc")
Michael Walsh764d2f82017-04-27 16:01:08 -05001140 return
Michael Walsha20da402017-03-31 16:27:45 -05001141
Michael Walsh409ad352020-02-06 11:46:35 -06001142 if delete_errlogs:
1143 # Delete errlogs prior to doing any boot tests.
1144 grk.run_key(delete_errlogs_cmd, ignore=1)
1145
Michael Walsh6741f742017-02-20 16:16:38 -06001146 # Process caller's boot_stack.
1147 while (len(boot_stack) > 0):
1148 test_loop_body()
1149
Michael Walshb5839d02017-04-12 16:11:20 -05001150 gp.qprint_timen("Finished processing stack.")
Michael Walsh30dadae2017-02-27 14:25:52 -06001151
Michael Walsh89de14a2018-10-01 16:51:37 -05001152 post_stack()
1153
Michael Walsh6741f742017-02-20 16:16:38 -06001154 # Process caller's boot_list.
1155 if len(boot_list) > 0:
1156 for ix in range(1, max_num_tests + 1):
1157 test_loop_body()
1158
Michael Walshb5839d02017-04-12 16:11:20 -05001159 gp.qprint_timen("Completed all requested boot tests.")
1160
1161 boot_pass, boot_fail = boot_results.return_total_pass_fail()
Michael Walshcd9fbfd2017-09-19 12:00:08 -05001162 new_fail = boot_fail - init_boot_fail
1163 if new_fail > boot_fail_threshold:
Michael Walshb5839d02017-04-12 16:11:20 -05001164 error_message = "Boot failures exceed the boot failure" +\
1165 " threshold:\n" +\
Michael Walshcd9fbfd2017-09-19 12:00:08 -05001166 gp.sprint_var(new_fail) +\
Michael Walshb5839d02017-04-12 16:11:20 -05001167 gp.sprint_var(boot_fail_threshold)
1168 BuiltIn().fail(gp.sprint_error(error_message))