blob: 93d89abbb355d34f82290d884a92ccd7d0f98bc3 [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
George Keishinga54e06f2020-06-12 10:42:41 -050041redfish = BuiltIn().get_library_instance('redfish')
42
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"
George Keishing763902a2020-06-16 12:13:05 -050075 # TODO: default_set_power_policy = "Redfish Set Power Restore Policy AlwaysOff"
76 default_set_power_policy = "Set BMC Power Policy ALWAYS_POWER_OFF"
Michael Walshe58df1c2019-08-07 09:57:43 -050077else:
78 default_power_on = "REST Power On"
79 default_power_off = "REST Power Off"
Michael Walsh409ad352020-02-06 11:46:35 -060080 delete_errlogs_cmd = "Delete Error Logs"
George Keishinga54e06f2020-06-12 10:42:41 -050081 default_set_power_policy = "Set BMC Power Policy ALWAYS_POWER_OFF"
Michael Walsh6741f742017-02-20 16:16:38 -060082boot_count = 0
Michael Walsh0bbd8602016-11-22 11:31:49 -060083
Michael Walsh85678942017-03-27 14:34:22 -050084LOG_LEVEL = BuiltIn().get_variable_value("${LOG_LEVEL}")
Michael Walsh986d8ae2019-07-17 10:02:23 -050085AUTOBOOT_FFDC_PREFIX = os.environ.get('AUTOBOOT_FFDC_PREFIX', '')
86ffdc_prefix = AUTOBOOT_FFDC_PREFIX
Sunil M325eb542017-08-10 07:09:43 -050087boot_start_time = ""
88boot_end_time = ""
Michael Walshff340002017-08-29 11:18:27 -050089save_stack = vs.var_stack('save_stack')
90main_func_parm_list = ['boot_stack', 'stack_mode', 'quiet']
Michael Walsh85678942017-03-27 14:34:22 -050091
92
Michael Walsh89de14a2018-10-01 16:51:37 -050093def dump_ffdc_rc():
94 r"""
95 Return the constant dump ffdc test return code value.
96
97 When a plug-in call point program returns this value, it indicates that
98 this program should collect FFDC.
99 """
100
101 return 0x00000200
102
103
104def stop_test_rc():
105 r"""
106 Return the constant stop test return code value.
107
108 When a plug-in call point program returns this value, it indicates that
109 this program should stop running.
110 """
111
112 return 0x00000200
113
114
Michael Walsh0ad0f7f2017-05-04 14:39:58 -0500115def process_host(host,
116 host_var_name=""):
Michael Walsh0ad0f7f2017-05-04 14:39:58 -0500117 r"""
118 Process a host by getting the associated host name and IP address and
119 setting them in global variables.
120
121 If the caller does not pass the host_var_name, this function will try to
122 figure out the name of the variable used by the caller for the host parm.
123 Callers are advised to explicitly specify the host_var_name when calling
124 with an exec command. In such cases, the get_arg_name cannot figure out
125 the host variable name.
126
127 This function will then create similar global variable names by
128 removing "_host" and appending "_host_name" or "_ip" to the host variable
129 name.
130
131 Example:
132
133 If a call is made like this:
134 process_host(openbmc_host)
135
136 Global variables openbmc_host_name and openbmc_ip will be set.
137
138 Description of argument(s):
139 host A host name or IP. The name of the variable used should
140 have a suffix of "_host".
141 host_var_name The name of the variable being used as the host parm.
142 """
143
144 if host_var_name == "":
145 host_var_name = gp.get_arg_name(0, 1, stack_frame_ix=2)
146
147 host_name_var_name = re.sub("host", "host_name", host_var_name)
148 ip_var_name = re.sub("host", "ip", host_var_name)
149 cmd_buf = "global " + host_name_var_name + ", " + ip_var_name + " ; " +\
150 host_name_var_name + ", " + ip_var_name + " = gm.get_host_name_ip('" +\
151 host + "')"
152 exec(cmd_buf)
153
Michael Walsh0ad0f7f2017-05-04 14:39:58 -0500154
Michael Walshb5839d02017-04-12 16:11:20 -0500155def process_pgm_parms():
Michael Walshb5839d02017-04-12 16:11:20 -0500156 r"""
157 Process the program parameters by assigning them all to corresponding
158 globals. Also, set some global values that depend on program parameters.
159 """
160
161 # Program parameter processing.
162 # Assign all program parms to python variables which are global to this
163 # module.
164
165 global parm_list
166 parm_list = BuiltIn().get_variable_value("${parm_list}")
167 # The following subset of parms should be processed as integers.
168 int_list = ['max_num_tests', 'boot_pass', 'boot_fail', 'ffdc_only',
Michael Walsh89de14a2018-10-01 16:51:37 -0500169 'boot_fail_threshold', 'delete_errlogs',
Michael Walsh986d8ae2019-07-17 10:02:23 -0500170 'call_post_stack_plug', 'do_pre_boot_plug_in_setup', 'quiet',
171 'test_mode', 'debug']
Michael Walshb5839d02017-04-12 16:11:20 -0500172 for parm in parm_list:
173 if parm in int_list:
174 sub_cmd = "int(BuiltIn().get_variable_value(\"${" + parm +\
175 "}\", \"0\"))"
176 else:
177 sub_cmd = "BuiltIn().get_variable_value(\"${" + parm + "}\")"
178 cmd_buf = "global " + parm + " ; " + parm + " = " + sub_cmd
Michael Walshff340002017-08-29 11:18:27 -0500179 gp.dpissuing(cmd_buf)
Michael Walshb5839d02017-04-12 16:11:20 -0500180 exec(cmd_buf)
Michael Walsh0ad0f7f2017-05-04 14:39:58 -0500181 if re.match(r".*_host$", parm):
182 cmd_buf = "process_host(" + parm + ", '" + parm + "')"
183 exec(cmd_buf)
184 if re.match(r".*_password$", parm):
185 # Register the value of any parm whose name ends in _password.
186 # This will cause the print functions to replace passwords with
187 # asterisks in the output.
188 cmd_buf = "gp.register_passwords(" + parm + ")"
189 exec(cmd_buf)
Michael Walshb5839d02017-04-12 16:11:20 -0500190
191 global ffdc_dir_path_style
192 global boot_list
193 global boot_stack
194 global boot_results_file_path
195 global boot_results
Michael Walsh986d8ae2019-07-17 10:02:23 -0500196 global boot_history
Michael Walshb5839d02017-04-12 16:11:20 -0500197 global ffdc_list_file_path
Michael Walshe0cf8d72017-05-17 13:20:46 -0500198 global ffdc_report_list_path
Michael Walsh600876d2017-05-30 17:58:58 -0500199 global ffdc_summary_list_path
Michael Walsha3e7b222020-02-03 15:32:16 -0600200 global boot_table
201 global valid_boot_types
Michael Walshb5839d02017-04-12 16:11:20 -0500202
203 if ffdc_dir_path_style == "":
204 ffdc_dir_path_style = int(os.environ.get('FFDC_DIR_PATH_STYLE', '0'))
205
206 # Convert these program parms to lists for easier processing..
George Keishing36efbc02018-12-12 10:18:23 -0600207 boot_list = list(filter(None, boot_list.split(":")))
208 boot_stack = list(filter(None, boot_stack.split(":")))
Michael Walshb5839d02017-04-12 16:11:20 -0500209
Michael Walsha3e7b222020-02-03 15:32:16 -0600210 boot_table = create_boot_table(boot_table_path, os_host=os_host)
211 valid_boot_types = create_valid_boot_list(boot_table)
212
Michael Walsh903e0b22017-09-19 17:00:33 -0500213 cleanup_boot_results_file()
214 boot_results_file_path = create_boot_results_file_path(pgm_name,
215 openbmc_nickname,
216 master_pid)
Michael Walshb5839d02017-04-12 16:11:20 -0500217
218 if os.path.isfile(boot_results_file_path):
219 # We've been called before in this run so we'll load the saved
Michael Walsh986d8ae2019-07-17 10:02:23 -0500220 # boot_results and boot_history objects.
221 boot_results, boot_history =\
Michael Walsh6c645742018-08-17 15:02:17 -0500222 pickle.load(open(boot_results_file_path, 'rb'))
Michael Walshb5839d02017-04-12 16:11:20 -0500223 else:
224 boot_results = boot_results(boot_table, boot_pass, boot_fail)
225
226 ffdc_list_file_path = base_tool_dir_path + openbmc_nickname +\
227 "/FFDC_FILE_LIST"
Michael Walshe0cf8d72017-05-17 13:20:46 -0500228 ffdc_report_list_path = base_tool_dir_path + openbmc_nickname +\
229 "/FFDC_REPORT_FILE_LIST"
Michael Walshb5839d02017-04-12 16:11:20 -0500230
Michael Walsh600876d2017-05-30 17:58:58 -0500231 ffdc_summary_list_path = base_tool_dir_path + openbmc_nickname +\
232 "/FFDC_SUMMARY_FILE_LIST"
233
Michael Walshb5839d02017-04-12 16:11:20 -0500234
Michael Walsh85678942017-03-27 14:34:22 -0500235def initial_plug_in_setup():
Michael Walsh85678942017-03-27 14:34:22 -0500236 r"""
237 Initialize all plug-in environment variables which do not change for the
238 duration of the program.
239
240 """
241
242 global LOG_LEVEL
243 BuiltIn().set_log_level("NONE")
244
245 BuiltIn().set_global_variable("${master_pid}", master_pid)
246 BuiltIn().set_global_variable("${FFDC_DIR_PATH}", ffdc_dir_path)
247 BuiltIn().set_global_variable("${STATUS_DIR_PATH}", status_dir_path)
248 BuiltIn().set_global_variable("${BASE_TOOL_DIR_PATH}", base_tool_dir_path)
249 BuiltIn().set_global_variable("${FFDC_LIST_FILE_PATH}",
250 ffdc_list_file_path)
Michael Walshe0cf8d72017-05-17 13:20:46 -0500251 BuiltIn().set_global_variable("${FFDC_REPORT_LIST_PATH}",
252 ffdc_report_list_path)
Michael Walsh600876d2017-05-30 17:58:58 -0500253 BuiltIn().set_global_variable("${FFDC_SUMMARY_LIST_PATH}",
254 ffdc_summary_list_path)
Michael Walsh85678942017-03-27 14:34:22 -0500255
256 BuiltIn().set_global_variable("${FFDC_DIR_PATH_STYLE}",
257 ffdc_dir_path_style)
258 BuiltIn().set_global_variable("${FFDC_CHECK}",
259 ffdc_check)
260
261 # For each program parameter, set the corresponding AUTOBOOT_ environment
262 # variable value. Also, set an AUTOBOOT_ environment variable for every
263 # element in additional_values.
264 additional_values = ["program_pid", "master_pid", "ffdc_dir_path",
265 "status_dir_path", "base_tool_dir_path",
Michael Walsh600876d2017-05-30 17:58:58 -0500266 "ffdc_list_file_path", "ffdc_report_list_path",
George Keishinga54e06f2020-06-12 10:42:41 -0500267 "ffdc_summary_list_path", "execdir", "redfish_supported"]
Michael Walsh85678942017-03-27 14:34:22 -0500268
269 plug_in_vars = parm_list + additional_values
270
271 for var_name in plug_in_vars:
272 var_value = BuiltIn().get_variable_value("${" + var_name + "}")
273 var_name = var_name.upper()
274 if var_value is None:
275 var_value = ""
276 os.environ["AUTOBOOT_" + var_name] = str(var_value)
277
278 BuiltIn().set_log_level(LOG_LEVEL)
279
Michael Walsh68a61162017-04-25 11:54:06 -0500280 # Make sure the ffdc list directory exists.
281 ffdc_list_dir_path = os.path.dirname(ffdc_list_file_path) + os.sep
282 if not os.path.exists(ffdc_list_dir_path):
283 os.makedirs(ffdc_list_dir_path)
Michael Walsh85678942017-03-27 14:34:22 -0500284
Michael Walsh85678942017-03-27 14:34:22 -0500285
Michael Walsh0bbd8602016-11-22 11:31:49 -0600286def plug_in_setup():
Michael Walsh0bbd8602016-11-22 11:31:49 -0600287 r"""
Michael Walsh85678942017-03-27 14:34:22 -0500288 Initialize all changing plug-in environment variables for use by the
289 plug-in programs.
Michael Walsh0bbd8602016-11-22 11:31:49 -0600290 """
291
Michael Walsh85678942017-03-27 14:34:22 -0500292 global LOG_LEVEL
293 global test_really_running
294
295 BuiltIn().set_log_level("NONE")
296
Michael Walsh6741f742017-02-20 16:16:38 -0600297 boot_pass, boot_fail = boot_results.return_total_pass_fail()
Michael Walsh0bbd8602016-11-22 11:31:49 -0600298 if boot_pass > 1:
299 test_really_running = 1
300 else:
301 test_really_running = 0
302
Michael Walsh6741f742017-02-20 16:16:38 -0600303 BuiltIn().set_global_variable("${test_really_running}",
304 test_really_running)
305 BuiltIn().set_global_variable("${boot_type_desc}", next_boot)
Michael Walsh6741f742017-02-20 16:16:38 -0600306 BuiltIn().set_global_variable("${boot_pass}", boot_pass)
307 BuiltIn().set_global_variable("${boot_fail}", boot_fail)
308 BuiltIn().set_global_variable("${boot_success}", boot_success)
309 BuiltIn().set_global_variable("${ffdc_prefix}", ffdc_prefix)
Sunil M325eb542017-08-10 07:09:43 -0500310 BuiltIn().set_global_variable("${boot_start_time}", boot_start_time)
311 BuiltIn().set_global_variable("${boot_end_time}", boot_end_time)
Michael Walsh4c9a6452016-12-13 16:03:11 -0600312
Michael Walsh0bbd8602016-11-22 11:31:49 -0600313 # For each program parameter, set the corresponding AUTOBOOT_ environment
314 # variable value. Also, set an AUTOBOOT_ environment variable for every
315 # element in additional_values.
316 additional_values = ["boot_type_desc", "boot_success", "boot_pass",
Sunil M325eb542017-08-10 07:09:43 -0500317 "boot_fail", "test_really_running", "ffdc_prefix",
318 "boot_start_time", "boot_end_time"]
Michael Walsh0bbd8602016-11-22 11:31:49 -0600319
Michael Walsh85678942017-03-27 14:34:22 -0500320 plug_in_vars = additional_values
Michael Walsh0bbd8602016-11-22 11:31:49 -0600321
322 for var_name in plug_in_vars:
323 var_value = BuiltIn().get_variable_value("${" + var_name + "}")
324 var_name = var_name.upper()
325 if var_value is None:
326 var_value = ""
Michael Walsh6741f742017-02-20 16:16:38 -0600327 os.environ["AUTOBOOT_" + var_name] = str(var_value)
Michael Walsh0bbd8602016-11-22 11:31:49 -0600328
Michael Walsh0bbd8602016-11-22 11:31:49 -0600329 if debug:
Michael Walsh6741f742017-02-20 16:16:38 -0600330 shell_rc, out_buf = \
331 gc.cmd_fnc_u("printenv | egrep AUTOBOOT_ | sort -u")
Michael Walsh0bbd8602016-11-22 11:31:49 -0600332
Michael Walsh85678942017-03-27 14:34:22 -0500333 BuiltIn().set_log_level(LOG_LEVEL)
334
Michael Walsh0bbd8602016-11-22 11:31:49 -0600335
Michael Walshe0cf8d72017-05-17 13:20:46 -0500336def pre_boot_plug_in_setup():
337
338 # Clear the ffdc_list_file_path file. Plug-ins may now write to it.
339 try:
340 os.remove(ffdc_list_file_path)
341 except OSError:
342 pass
343
344 # Clear the ffdc_report_list_path file. Plug-ins may now write to it.
345 try:
346 os.remove(ffdc_report_list_path)
347 except OSError:
348 pass
349
Michael Walsh600876d2017-05-30 17:58:58 -0500350 # Clear the ffdc_summary_list_path file. Plug-ins may now write to it.
351 try:
352 os.remove(ffdc_summary_list_path)
353 except OSError:
354 pass
355
Michael Walshe1974b92017-08-03 13:39:51 -0500356 global ffdc_prefix
357
358 seconds = time.time()
359 loc_time = time.localtime(seconds)
360 time_string = time.strftime("%y%m%d.%H%M%S.", loc_time)
361
362 ffdc_prefix = openbmc_nickname + "." + time_string
363
Michael Walshe0cf8d72017-05-17 13:20:46 -0500364
Michael Walshf566fb12019-02-01 14:35:09 -0600365def default_sigusr1(signal_number=0,
366 frame=None):
367 r"""
368 Handle SIGUSR1 by doing nothing.
369
370 This function assists in debugging SIGUSR1 processing by printing messages
371 to stdout and to the log.html file.
372
373 Description of argument(s):
374 signal_number The signal number (should always be 10 for SIGUSR1).
375 frame The frame data.
376 """
377
Michael Walsh80dddde2019-10-22 13:54:38 -0500378 gp.qprintn()
379 gp.qprint_executing()
Michael Walshf566fb12019-02-01 14:35:09 -0600380 gp.lprint_executing()
381
382
383def set_default_siguser1():
384 r"""
385 Set the default_sigusr1 function to be the SIGUSR1 handler.
386 """
387
Michael Walsh80dddde2019-10-22 13:54:38 -0500388 gp.qprintn()
389 gp.qprint_executing()
Michael Walshf566fb12019-02-01 14:35:09 -0600390 gp.lprint_executing()
391 signal.signal(signal.SIGUSR1, default_sigusr1)
392
393
Michael Walsh6741f742017-02-20 16:16:38 -0600394def setup():
Michael Walsh0bbd8602016-11-22 11:31:49 -0600395 r"""
Michael Walsh6741f742017-02-20 16:16:38 -0600396 Do general program setup tasks.
Michael Walsh0bbd8602016-11-22 11:31:49 -0600397 """
398
Michael Walsh6741f742017-02-20 16:16:38 -0600399 global cp_setup_called
Michael Walsh81816742017-09-27 11:02:29 -0500400 global transitional_boot_selected
Michael Walsh0bbd8602016-11-22 11:31:49 -0600401
Michael Walshb5839d02017-04-12 16:11:20 -0500402 gp.qprintn()
403
George Keishinga54e06f2020-06-12 10:42:41 -0500404 if redfish_supported:
405 redfish.login()
406
Michael Walshf566fb12019-02-01 14:35:09 -0600407 set_default_siguser1()
Michael Walsh81816742017-09-27 11:02:29 -0500408 transitional_boot_selected = False
409
Michael Walsh83f4bc72017-04-20 16:49:43 -0500410 robot_pgm_dir_path = os.path.dirname(__file__) + os.sep
411 repo_bin_path = robot_pgm_dir_path.replace("/lib/", "/bin/")
Michael Walshd061c042017-05-23 14:46:57 -0500412 # If we can't find process_plug_in_packages.py, ssh_pw or
413 # validate_plug_ins.py, then we don't have our repo bin in PATH.
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -0500414 shell_rc, out_buf = gc.cmd_fnc_u("which process_plug_in_packages.py"
415 + " ssh_pw validate_plug_ins.py", quiet=1,
Michael Walshd061c042017-05-23 14:46:57 -0500416 print_output=0, show_err=0)
Michael Walshb5839d02017-04-12 16:11:20 -0500417 if shell_rc != 0:
Michael Walsh83f4bc72017-04-20 16:49:43 -0500418 os.environ['PATH'] = repo_bin_path + ":" + os.environ.get('PATH', "")
419 # Likewise, our repo lib subdir needs to be in sys.path and PYTHONPATH.
420 if robot_pgm_dir_path not in sys.path:
421 sys.path.append(robot_pgm_dir_path)
422 PYTHONPATH = os.environ.get("PYTHONPATH", "")
423 if PYTHONPATH == "":
424 os.environ['PYTHONPATH'] = robot_pgm_dir_path
425 else:
426 os.environ['PYTHONPATH'] = robot_pgm_dir_path + ":" + PYTHONPATH
Michael Walsh6741f742017-02-20 16:16:38 -0600427
428 validate_parms()
429
Michael Walshc108e422019-03-28 12:27:18 -0500430 gp.qprint_pgm_header()
Michael Walsh6741f742017-02-20 16:16:38 -0600431
George Keishinga54e06f2020-06-12 10:42:41 -0500432 grk.run_key_u(default_set_power_policy)
Michael Walsh11cfc8c2017-03-31 09:40:55 -0500433
Michael Walsh85678942017-03-27 14:34:22 -0500434 initial_plug_in_setup()
435
Michael Walsh6741f742017-02-20 16:16:38 -0600436 plug_in_setup()
437 rc, shell_rc, failed_plug_in_name = grpi.rprocess_plug_in_packages(
438 call_point='setup')
439 if rc != 0:
440 error_message = "Plug-in setup failed.\n"
Michael Walshc108e422019-03-28 12:27:18 -0500441 gp.print_error_report(error_message)
Michael Walsh6741f742017-02-20 16:16:38 -0600442 BuiltIn().fail(error_message)
443 # Setting cp_setup_called lets our Teardown know that it needs to call
444 # the cleanup plug-in call point.
445 cp_setup_called = 1
446
447 # Keyword "FFDC" will fail if TEST_MESSAGE is not set.
448 BuiltIn().set_global_variable("${TEST_MESSAGE}", "${EMPTY}")
Michael Walsh85678942017-03-27 14:34:22 -0500449 # FFDC_LOG_PATH is used by "FFDC" keyword.
450 BuiltIn().set_global_variable("${FFDC_LOG_PATH}", ffdc_dir_path)
Michael Walsh6741f742017-02-20 16:16:38 -0600451
Michael Walshdc80d672017-05-09 12:58:32 -0500452 # Also printed by FFDC.
453 global host_name
454 global host_ip
455 host = socket.gethostname()
456 host_name, host_ip = gm.get_host_name_ip(host)
457
Michael Walsh986d8ae2019-07-17 10:02:23 -0500458 gp.dprint_var(boot_table)
Michael Walshb5839d02017-04-12 16:11:20 -0500459 gp.dprint_var(boot_lists)
Michael Walsh0bbd8602016-11-22 11:31:49 -0600460
Michael Walsh0bbd8602016-11-22 11:31:49 -0600461
Michael Walsh6741f742017-02-20 16:16:38 -0600462def validate_parms():
Michael Walsh0bbd8602016-11-22 11:31:49 -0600463 r"""
Michael Walsh6741f742017-02-20 16:16:38 -0600464 Validate all program parameters.
Michael Walsh0bbd8602016-11-22 11:31:49 -0600465 """
466
Michael Walshb5839d02017-04-12 16:11:20 -0500467 process_pgm_parms()
Michael Walsh0bbd8602016-11-22 11:31:49 -0600468
Michael Walshb5839d02017-04-12 16:11:20 -0500469 gp.qprintn()
470
471 global openbmc_model
Michael Walshf5ce38c2020-02-27 12:46:20 -0600472 if openbmc_model == "":
473 status, ret_values =\
474 grk.run_key_u("Get BMC System Model")
475 openbmc_model = ret_values
476 BuiltIn().set_global_variable("${openbmc_model}", openbmc_model)
477 gv.set_exit_on_error(True)
Michael Walsh44cef252019-08-01 12:38:56 -0500478 gv.valid_value(openbmc_host)
479 gv.valid_value(openbmc_username)
480 gv.valid_value(openbmc_password)
481 gv.valid_value(rest_username)
482 gv.valid_value(rest_password)
483 gv.valid_value(ipmi_username)
484 gv.valid_value(ipmi_password)
Michael Walsh6741f742017-02-20 16:16:38 -0600485 if os_host != "":
Michael Walsh44cef252019-08-01 12:38:56 -0500486 gv.valid_value(os_username)
487 gv.valid_value(os_password)
Michael Walsh6741f742017-02-20 16:16:38 -0600488 if pdu_host != "":
Michael Walsh44cef252019-08-01 12:38:56 -0500489 gv.valid_value(pdu_username)
490 gv.valid_value(pdu_password)
491 gv.valid_integer(pdu_slot_no)
Michael Walsh6741f742017-02-20 16:16:38 -0600492 if openbmc_serial_host != "":
Michael Walsh44cef252019-08-01 12:38:56 -0500493 gv.valid_integer(openbmc_serial_port)
Michael Walsh44cef252019-08-01 12:38:56 -0500494 gv.valid_value(openbmc_model)
495 gv.valid_integer(max_num_tests)
496 gv.valid_integer(boot_pass)
497 gv.valid_integer(boot_fail)
Michael Walsh6741f742017-02-20 16:16:38 -0600498 plug_in_packages_list = grpi.rvalidate_plug_ins(plug_in_dir_paths)
499 BuiltIn().set_global_variable("${plug_in_packages_list}",
500 plug_in_packages_list)
Michael Walsh44cef252019-08-01 12:38:56 -0500501 gv.valid_value(stack_mode, valid_values=['normal', 'skip'])
Michael Walshf5ce38c2020-02-27 12:46:20 -0600502 gv.set_exit_on_error(False)
Michael Walsha20da402017-03-31 16:27:45 -0500503 if len(boot_list) == 0 and len(boot_stack) == 0 and not ffdc_only:
Michael Walsh6741f742017-02-20 16:16:38 -0600504 error_message = "You must provide either a value for either the" +\
505 " boot_list or the boot_stack parm.\n"
506 BuiltIn().fail(gp.sprint_error(error_message))
Michael Walsh6741f742017-02-20 16:16:38 -0600507 valid_boot_list(boot_list, valid_boot_types)
508 valid_boot_list(boot_stack, valid_boot_types)
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -0500509 selected_PDU_boots = list(set(boot_list + boot_stack)
510 & set(boot_lists['PDU_reboot']))
Michael Walsh11cfc8c2017-03-31 09:40:55 -0500511 if len(selected_PDU_boots) > 0 and pdu_host == "":
512 error_message = "You have selected the following boots which" +\
513 " require a PDU host but no value for pdu_host:\n"
514 error_message += gp.sprint_var(selected_PDU_boots)
Michael Walsh986d8ae2019-07-17 10:02:23 -0500515 error_message += gp.sprint_var(pdu_host, fmt=gp.blank())
Michael Walsh11cfc8c2017-03-31 09:40:55 -0500516 BuiltIn().fail(gp.sprint_error(error_message))
517
Michael Walsh6741f742017-02-20 16:16:38 -0600518 return
Michael Walsh0bbd8602016-11-22 11:31:49 -0600519
Michael Walsh0bbd8602016-11-22 11:31:49 -0600520
Michael Walsh6741f742017-02-20 16:16:38 -0600521def my_get_state():
Michael Walsh0bbd8602016-11-22 11:31:49 -0600522 r"""
Michael Walsh6741f742017-02-20 16:16:38 -0600523 Get the system state plus a little bit of wrapping.
Michael Walsh0bbd8602016-11-22 11:31:49 -0600524 """
525
Michael Walsh6741f742017-02-20 16:16:38 -0600526 global state
527
528 req_states = ['epoch_seconds'] + st.default_req_states
529
Michael Walshb5839d02017-04-12 16:11:20 -0500530 gp.qprint_timen("Getting system state.")
Michael Walsh6741f742017-02-20 16:16:38 -0600531 if test_mode:
532 state['epoch_seconds'] = int(time.time())
533 else:
Michael Walshb5839d02017-04-12 16:11:20 -0500534 state = st.get_state(req_states=req_states, quiet=quiet)
535 gp.qprint_var(state)
Michael Walsh341c21e2017-01-17 16:25:20 -0600536
Michael Walsh341c21e2017-01-17 16:25:20 -0600537
Michael Walsh45ca6e42017-09-14 17:29:12 -0500538def valid_state():
Michael Walsh45ca6e42017-09-14 17:29:12 -0500539 r"""
540 Verify that our state dictionary contains no blank values. If we don't get
541 valid state data, we cannot continue to work.
542 """
543
544 if st.compare_states(state, st.invalid_state_match, 'or'):
545 error_message = "The state dictionary contains blank fields which" +\
546 " is illegal.\n" + gp.sprint_var(state)
547 BuiltIn().fail(gp.sprint_error(error_message))
548
Michael Walsh45ca6e42017-09-14 17:29:12 -0500549
Michael Walsh6741f742017-02-20 16:16:38 -0600550def select_boot():
Michael Walsh341c21e2017-01-17 16:25:20 -0600551 r"""
552 Select a boot test to be run based on our current state and return the
553 chosen boot type.
554
555 Description of arguments:
Michael Walsh6741f742017-02-20 16:16:38 -0600556 state The state of the machine.
Michael Walsh341c21e2017-01-17 16:25:20 -0600557 """
558
Michael Walsh81816742017-09-27 11:02:29 -0500559 global transitional_boot_selected
Michael Walsh30dadae2017-02-27 14:25:52 -0600560 global boot_stack
561
Michael Walshb5839d02017-04-12 16:11:20 -0500562 gp.qprint_timen("Selecting a boot test.")
Michael Walsh6741f742017-02-20 16:16:38 -0600563
Michael Walsh81816742017-09-27 11:02:29 -0500564 if transitional_boot_selected and not boot_success:
565 prior_boot = next_boot
566 boot_candidate = boot_stack.pop()
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -0500567 gp.qprint_timen("The prior '" + next_boot + "' was chosen to"
568 + " transition to a valid state for '" + boot_candidate
569 + "' which was at the top of the boot_stack. Since"
570 + " the '" + next_boot + "' failed, the '"
571 + boot_candidate + "' has been removed from the stack"
572 + " to avoid and endless failure loop.")
Michael Walsh81816742017-09-27 11:02:29 -0500573 if len(boot_stack) == 0:
574 return ""
575
Michael Walsh6741f742017-02-20 16:16:38 -0600576 my_get_state()
Michael Walsh45ca6e42017-09-14 17:29:12 -0500577 valid_state()
Michael Walsh6741f742017-02-20 16:16:38 -0600578
Michael Walsh81816742017-09-27 11:02:29 -0500579 transitional_boot_selected = False
Michael Walsh6741f742017-02-20 16:16:38 -0600580 stack_popped = 0
581 if len(boot_stack) > 0:
582 stack_popped = 1
Michael Walshb5839d02017-04-12 16:11:20 -0500583 gp.qprint_dashes()
584 gp.qprint_var(boot_stack)
585 gp.qprint_dashes()
586 skip_boot_printed = 0
587 while len(boot_stack) > 0:
588 boot_candidate = boot_stack.pop()
589 if stack_mode == 'normal':
590 break
591 else:
592 if st.compare_states(state, boot_table[boot_candidate]['end']):
593 if not skip_boot_printed:
Michael Walshff340002017-08-29 11:18:27 -0500594 gp.qprint_var(stack_mode)
595 gp.qprintn()
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -0500596 gp.qprint_timen("Skipping the following boot tests"
597 + " which are unnecessary since their"
598 + " required end states match the"
599 + " current machine state:")
Michael Walshb5839d02017-04-12 16:11:20 -0500600 skip_boot_printed = 1
Michael Walshff340002017-08-29 11:18:27 -0500601 gp.qprint_var(boot_candidate)
Michael Walshb5839d02017-04-12 16:11:20 -0500602 boot_candidate = ""
603 if boot_candidate == "":
604 gp.qprint_dashes()
605 gp.qprint_var(boot_stack)
606 gp.qprint_dashes()
607 return boot_candidate
Michael Walsh6741f742017-02-20 16:16:38 -0600608 if st.compare_states(state, boot_table[boot_candidate]['start']):
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -0500609 gp.qprint_timen("The machine state is valid for a '"
610 + boot_candidate + "' boot test.")
Michael Walshb5839d02017-04-12 16:11:20 -0500611 gp.qprint_dashes()
612 gp.qprint_var(boot_stack)
613 gp.qprint_dashes()
Michael Walsh6741f742017-02-20 16:16:38 -0600614 return boot_candidate
Michael Walsh341c21e2017-01-17 16:25:20 -0600615 else:
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -0500616 gp.qprint_timen("The machine state does not match the required"
617 + " starting state for a '" + boot_candidate
618 + "' boot test:")
Michael Walsh986d8ae2019-07-17 10:02:23 -0500619 gp.qprint_varx("boot_table_start_entry",
620 boot_table[boot_candidate]['start'])
Michael Walsh6741f742017-02-20 16:16:38 -0600621 boot_stack.append(boot_candidate)
Michael Walsh81816742017-09-27 11:02:29 -0500622 transitional_boot_selected = True
Michael Walsh6741f742017-02-20 16:16:38 -0600623 popped_boot = boot_candidate
624
625 # Loop through your list selecting a boot_candidates
626 boot_candidates = []
627 for boot_candidate in boot_list:
628 if st.compare_states(state, boot_table[boot_candidate]['start']):
629 if stack_popped:
630 if st.compare_states(boot_table[boot_candidate]['end'],
Gunnar Mills096cd562018-03-26 10:19:12 -0500631 boot_table[popped_boot]['start']):
Michael Walsh6741f742017-02-20 16:16:38 -0600632 boot_candidates.append(boot_candidate)
633 else:
634 boot_candidates.append(boot_candidate)
635
636 if len(boot_candidates) == 0:
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -0500637 gp.qprint_timen("The user's boot list contained no boot tests"
638 + " which are valid for the current machine state.")
Michael Walsh6741f742017-02-20 16:16:38 -0600639 boot_candidate = default_power_on
640 if not st.compare_states(state, boot_table[default_power_on]['start']):
641 boot_candidate = default_power_off
642 boot_candidates.append(boot_candidate)
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -0500643 gp.qprint_timen("Using default '" + boot_candidate
644 + "' boot type to transition to valid state.")
Michael Walsh6741f742017-02-20 16:16:38 -0600645
Michael Walshb5839d02017-04-12 16:11:20 -0500646 gp.dprint_var(boot_candidates)
Michael Walsh6741f742017-02-20 16:16:38 -0600647
648 # Randomly select a boot from the candidate list.
649 boot = random.choice(boot_candidates)
Michael Walsh341c21e2017-01-17 16:25:20 -0600650
651 return boot
Michael Walsh0bbd8602016-11-22 11:31:49 -0600652
Michael Walsh55302292017-01-10 11:43:02 -0600653
Michael Walshb2e53ec2017-10-30 15:04:36 -0500654def print_defect_report(ffdc_file_list):
Michael Walsh341c21e2017-01-17 16:25:20 -0600655 r"""
656 Print a defect report.
Michael Walshb2e53ec2017-10-30 15:04:36 -0500657
658 Description of argument(s):
659 ffdc_file_list A list of files which were collected by our ffdc functions.
Michael Walsh341c21e2017-01-17 16:25:20 -0600660 """
661
Michael Walsh600876d2017-05-30 17:58:58 -0500662 # Making deliberate choice to NOT run plug_in_setup(). We don't want
663 # ffdc_prefix updated.
664 rc, shell_rc, failed_plug_in_name = grpi.rprocess_plug_in_packages(
665 call_point='ffdc_report', stop_on_plug_in_failure=0)
666
Michael Walshe0cf8d72017-05-17 13:20:46 -0500667 # Get additional header data which may have been created by ffdc plug-ins.
668 # Also, delete the individual header files to cleanup.
669 cmd_buf = "file_list=$(cat " + ffdc_report_list_path + " 2>/dev/null)" +\
670 " ; [ ! -z \"${file_list}\" ] && cat ${file_list}" +\
671 " 2>/dev/null ; rm -rf ${file_list} 2>/dev/null || :"
672 shell_rc, more_header_info = gc.cmd_fnc_u(cmd_buf, print_output=0,
673 show_err=0)
674
Michael Walshb2e53ec2017-10-30 15:04:36 -0500675 # Get additional summary data which may have been created by ffdc plug-ins.
Michael Walsh600876d2017-05-30 17:58:58 -0500676 # Also, delete the individual header files to cleanup.
677 cmd_buf = "file_list=$(cat " + ffdc_summary_list_path + " 2>/dev/null)" +\
678 " ; [ ! -z \"${file_list}\" ] && cat ${file_list}" +\
679 " 2>/dev/null ; rm -rf ${file_list} 2>/dev/null || :"
680 shell_rc, ffdc_summary_info = gc.cmd_fnc_u(cmd_buf, print_output=0,
681 show_err=0)
682
Michael Walshb2e53ec2017-10-30 15:04:36 -0500683 # ffdc_list_file_path contains a list of any ffdc files created by plug-
684 # ins, etc. Read that data into a list.
Michael Walsh341c21e2017-01-17 16:25:20 -0600685 try:
Michael Walshb2e53ec2017-10-30 15:04:36 -0500686 plug_in_ffdc_list = \
687 open(ffdc_list_file_path, 'r').read().rstrip("\n").split("\n")
George Keishing36efbc02018-12-12 10:18:23 -0600688 plug_in_ffdc_list = list(filter(None, plug_in_ffdc_list))
Michael Walsh341c21e2017-01-17 16:25:20 -0600689 except IOError:
Michael Walshb2e53ec2017-10-30 15:04:36 -0500690 plug_in_ffdc_list = []
691
692 # Combine the files from plug_in_ffdc_list with the ffdc_file_list passed
693 # in. Eliminate duplicates and sort the list.
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -0500694 ffdc_file_list = sorted(set(ffdc_file_list + plug_in_ffdc_list))
Michael Walshb2e53ec2017-10-30 15:04:36 -0500695
696 if status_file_path != "":
697 ffdc_file_list.insert(0, status_file_path)
698
699 # Convert the list to a printable list.
700 printable_ffdc_file_list = "\n".join(ffdc_file_list)
Michael Walsh341c21e2017-01-17 16:25:20 -0600701
Michael Walsh68a61162017-04-25 11:54:06 -0500702 # Open ffdc_file_list for writing. We will write a complete list of
703 # FFDC files to it for possible use by plug-ins like cp_stop_check.
704 ffdc_list_file = open(ffdc_list_file_path, 'w')
Michael Walshb2e53ec2017-10-30 15:04:36 -0500705 ffdc_list_file.write(printable_ffdc_file_list + "\n")
706 ffdc_list_file.close()
707
708 indent = 0
709 width = 90
710 linefeed = 1
711 char = "="
Michael Walsh68a61162017-04-25 11:54:06 -0500712
713 gp.qprintn()
Michael Walshb2e53ec2017-10-30 15:04:36 -0500714 gp.qprint_dashes(indent, width, linefeed, char)
Michael Walsh68a61162017-04-25 11:54:06 -0500715 gp.qprintn("Copy this data to the defect:\n")
716
Michael Walshe0cf8d72017-05-17 13:20:46 -0500717 if len(more_header_info) > 0:
Michael Walshff340002017-08-29 11:18:27 -0500718 gp.qprintn(more_header_info)
Michael Walshdc80d672017-05-09 12:58:32 -0500719 gp.qpvars(host_name, host_ip, openbmc_nickname, openbmc_host,
720 openbmc_host_name, openbmc_ip, openbmc_username,
Michael Walsh0a3bdb42019-01-31 16:21:44 +0000721 openbmc_password, rest_username, rest_password, ipmi_username,
722 ipmi_password, os_host, os_host_name, os_ip, os_username,
Michael Walshdc80d672017-05-09 12:58:32 -0500723 os_password, pdu_host, pdu_host_name, pdu_ip, pdu_username,
724 pdu_password, pdu_slot_no, openbmc_serial_host,
725 openbmc_serial_host_name, openbmc_serial_ip, openbmc_serial_port)
Michael Walsh68a61162017-04-25 11:54:06 -0500726
727 gp.qprintn()
Michael Walsh986d8ae2019-07-17 10:02:23 -0500728 print_boot_history(boot_history)
Michael Walsh68a61162017-04-25 11:54:06 -0500729 gp.qprintn()
730 gp.qprint_var(state)
Michael Walshb5839d02017-04-12 16:11:20 -0500731 gp.qprintn()
732 gp.qprintn("FFDC data files:")
Michael Walshb2e53ec2017-10-30 15:04:36 -0500733 gp.qprintn(printable_ffdc_file_list)
Michael Walshb5839d02017-04-12 16:11:20 -0500734 gp.qprintn()
Michael Walsh341c21e2017-01-17 16:25:20 -0600735
Michael Walsh600876d2017-05-30 17:58:58 -0500736 if len(ffdc_summary_info) > 0:
Michael Walshff340002017-08-29 11:18:27 -0500737 gp.qprintn(ffdc_summary_info)
Michael Walsh600876d2017-05-30 17:58:58 -0500738
Michael Walshb2e53ec2017-10-30 15:04:36 -0500739 gp.qprint_dashes(indent, width, linefeed, char)
Michael Walsh68a61162017-04-25 11:54:06 -0500740
Michael Walsh6741f742017-02-20 16:16:38 -0600741
Michael Walsh6741f742017-02-20 16:16:38 -0600742def my_ffdc():
Michael Walsh6741f742017-02-20 16:16:38 -0600743 r"""
744 Collect FFDC data.
745 """
746
747 global state
748
749 plug_in_setup()
750 rc, shell_rc, failed_plug_in_name = grpi.rprocess_plug_in_packages(
Michael Walsh600876d2017-05-30 17:58:58 -0500751 call_point='ffdc', stop_on_plug_in_failure=0)
Michael Walsh6741f742017-02-20 16:16:38 -0600752
753 AUTOBOOT_FFDC_PREFIX = os.environ['AUTOBOOT_FFDC_PREFIX']
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -0500754 status, ffdc_file_list = grk.run_key_u("FFDC ffdc_prefix="
755 + AUTOBOOT_FFDC_PREFIX
756 + " ffdc_function_list="
757 + ffdc_function_list, ignore=1)
Michael Walsh83f4bc72017-04-20 16:49:43 -0500758 if status != 'PASS':
Michael Walshff340002017-08-29 11:18:27 -0500759 gp.qprint_error("Call to ffdc failed.\n")
Michael Walshc9bd2e82019-04-18 11:06:52 -0500760 if type(ffdc_file_list) is not list:
761 ffdc_file_list = []
762 # Leave a record for caller that "soft" errors occurred.
763 soft_errors = 1
764 gpu.save_plug_in_value(soft_errors, pgm_name)
Michael Walsh6741f742017-02-20 16:16:38 -0600765
766 my_get_state()
767
Michael Walshb2e53ec2017-10-30 15:04:36 -0500768 print_defect_report(ffdc_file_list)
Michael Walsh6741f742017-02-20 16:16:38 -0600769
Michael Walsh6741f742017-02-20 16:16:38 -0600770
Michael Walsh6741f742017-02-20 16:16:38 -0600771def print_test_start_message(boot_keyword):
Michael Walsh6741f742017-02-20 16:16:38 -0600772 r"""
773 Print a message indicating what boot test is about to run.
774
775 Description of arguments:
776 boot_keyword The name of the boot which is to be run
777 (e.g. "BMC Power On").
778 """
779
Michael Walsh986d8ae2019-07-17 10:02:23 -0500780 global boot_history
Sunil M325eb542017-08-10 07:09:43 -0500781 global boot_start_time
Michael Walsh6741f742017-02-20 16:16:38 -0600782
783 doing_msg = gp.sprint_timen("Doing \"" + boot_keyword + "\".")
Sunil M325eb542017-08-10 07:09:43 -0500784
785 # Set boot_start_time for use by plug-ins.
786 boot_start_time = doing_msg[1:33]
787 gp.qprint_var(boot_start_time)
788
Michael Walshb5839d02017-04-12 16:11:20 -0500789 gp.qprint(doing_msg)
Michael Walsh6741f742017-02-20 16:16:38 -0600790
Michael Walsh986d8ae2019-07-17 10:02:23 -0500791 update_boot_history(boot_history, doing_msg, max_boot_history)
Michael Walsh6741f742017-02-20 16:16:38 -0600792
Michael Walsh6741f742017-02-20 16:16:38 -0600793
Michael Walshf566fb12019-02-01 14:35:09 -0600794def stop_boot_test(signal_number=0,
795 frame=None):
796 r"""
797 Handle SIGUSR1 by aborting the boot test that is running.
798
799 Description of argument(s):
800 signal_number The signal number (should always be 10 for SIGUSR1).
801 frame The frame data.
802 """
803
Michael Walsh80dddde2019-10-22 13:54:38 -0500804 gp.qprintn()
805 gp.qprint_executing()
Michael Walshf566fb12019-02-01 14:35:09 -0600806 gp.lprint_executing()
807
808 # Restore original sigusr1 handler.
809 set_default_siguser1()
810
811 message = "The caller has asked that the boot test be stopped and marked"
812 message += " as a failure."
813
814 function_stack = gm.get_function_stack()
815 if "wait_state" in function_stack:
Michael Walshc44aa532019-06-14 13:33:29 -0500816 st.set_exit_wait_early_message(message)
Michael Walshf566fb12019-02-01 14:35:09 -0600817 else:
818 BuiltIn().fail(gp.sprint_error(message))
819
820
Michael Walsh6741f742017-02-20 16:16:38 -0600821def run_boot(boot):
Michael Walsh6741f742017-02-20 16:16:38 -0600822 r"""
823 Run the specified boot.
824
825 Description of arguments:
826 boot The name of the boot test to be performed.
827 """
828
829 global state
830
Michael Walshf566fb12019-02-01 14:35:09 -0600831 signal.signal(signal.SIGUSR1, stop_boot_test)
832 gp.qprint_timen("stop_boot_test is armed.")
833
Michael Walsh6741f742017-02-20 16:16:38 -0600834 print_test_start_message(boot)
835
836 plug_in_setup()
837 rc, shell_rc, failed_plug_in_name = \
838 grpi.rprocess_plug_in_packages(call_point="pre_boot")
839 if rc != 0:
840 error_message = "Plug-in failed with non-zero return code.\n" +\
Michael Walsh986d8ae2019-07-17 10:02:23 -0500841 gp.sprint_var(rc, fmt=gp.hexa())
Michael Walshf566fb12019-02-01 14:35:09 -0600842 set_default_siguser1()
Michael Walsh6741f742017-02-20 16:16:38 -0600843 BuiltIn().fail(gp.sprint_error(error_message))
844
845 if test_mode:
846 # In test mode, we'll pretend the boot worked by assigning its
847 # required end state to the default state value.
Michael Walsh30dadae2017-02-27 14:25:52 -0600848 state = st.strip_anchor_state(boot_table[boot]['end'])
Michael Walsh6741f742017-02-20 16:16:38 -0600849 else:
850 # Assertion: We trust that the state data was made fresh by the
851 # caller.
852
Michael Walshb5839d02017-04-12 16:11:20 -0500853 gp.qprintn()
Michael Walsh6741f742017-02-20 16:16:38 -0600854
855 if boot_table[boot]['method_type'] == "keyword":
Michael Walsh0b93fbf2017-03-02 14:42:41 -0600856 rk.my_run_keywords(boot_table[boot].get('lib_file_path', ''),
Michael Walshb5839d02017-04-12 16:11:20 -0500857 boot_table[boot]['method'],
858 quiet=quiet)
Michael Walsh6741f742017-02-20 16:16:38 -0600859
860 if boot_table[boot]['bmc_reboot']:
861 st.wait_for_comm_cycle(int(state['epoch_seconds']))
Michael Walsh30dadae2017-02-27 14:25:52 -0600862 plug_in_setup()
863 rc, shell_rc, failed_plug_in_name = \
864 grpi.rprocess_plug_in_packages(call_point="post_reboot")
865 if rc != 0:
Michael Walsh0b93fbf2017-03-02 14:42:41 -0600866 error_message = "Plug-in failed with non-zero return code.\n"
Michael Walsh986d8ae2019-07-17 10:02:23 -0500867 error_message += gp.sprint_var(rc, fmt=gp.hexa())
Michael Walshf566fb12019-02-01 14:35:09 -0600868 set_default_siguser1()
Michael Walsh30dadae2017-02-27 14:25:52 -0600869 BuiltIn().fail(gp.sprint_error(error_message))
Michael Walsh6741f742017-02-20 16:16:38 -0600870 else:
871 match_state = st.anchor_state(state)
872 del match_state['epoch_seconds']
873 # Wait for the state to change in any way.
874 st.wait_state(match_state, wait_time=state_change_timeout,
Michael Walsh600876d2017-05-30 17:58:58 -0500875 interval="10 seconds", invert=1)
Michael Walsh6741f742017-02-20 16:16:38 -0600876
Michael Walshb5839d02017-04-12 16:11:20 -0500877 gp.qprintn()
Michael Walsh6741f742017-02-20 16:16:38 -0600878 if boot_table[boot]['end']['chassis'] == "Off":
879 boot_timeout = power_off_timeout
880 else:
881 boot_timeout = power_on_timeout
882 st.wait_state(boot_table[boot]['end'], wait_time=boot_timeout,
Michael Walsh600876d2017-05-30 17:58:58 -0500883 interval="10 seconds")
Michael Walsh6741f742017-02-20 16:16:38 -0600884
885 plug_in_setup()
886 rc, shell_rc, failed_plug_in_name = \
887 grpi.rprocess_plug_in_packages(call_point="post_boot")
888 if rc != 0:
889 error_message = "Plug-in failed with non-zero return code.\n" +\
Michael Walsh986d8ae2019-07-17 10:02:23 -0500890 gp.sprint_var(rc, fmt=gp.hexa())
Michael Walshf566fb12019-02-01 14:35:09 -0600891 set_default_siguser1()
Michael Walsh6741f742017-02-20 16:16:38 -0600892 BuiltIn().fail(gp.sprint_error(error_message))
893
Michael Walshf566fb12019-02-01 14:35:09 -0600894 # Restore original sigusr1 handler.
895 set_default_siguser1()
896
Michael Walsh6741f742017-02-20 16:16:38 -0600897
Michael Walsh6741f742017-02-20 16:16:38 -0600898def test_loop_body():
Michael Walsh6741f742017-02-20 16:16:38 -0600899 r"""
900 The main loop body for the loop in main_py.
901
902 Description of arguments:
903 boot_count The iteration number (starts at 1).
904 """
905
906 global boot_count
907 global state
908 global next_boot
909 global boot_success
Sunil M325eb542017-08-10 07:09:43 -0500910 global boot_end_time
Michael Walsh6741f742017-02-20 16:16:38 -0600911
Michael Walshb5839d02017-04-12 16:11:20 -0500912 gp.qprintn()
Michael Walsh6741f742017-02-20 16:16:38 -0600913
914 next_boot = select_boot()
Michael Walshb5839d02017-04-12 16:11:20 -0500915 if next_boot == "":
916 return True
Michael Walsh6741f742017-02-20 16:16:38 -0600917
Michael Walshb5839d02017-04-12 16:11:20 -0500918 boot_count += 1
919 gp.qprint_timen("Starting boot " + str(boot_count) + ".")
Michael Walsh6741f742017-02-20 16:16:38 -0600920
Michael Walshe0cf8d72017-05-17 13:20:46 -0500921 pre_boot_plug_in_setup()
Michael Walsh6741f742017-02-20 16:16:38 -0600922
923 cmd_buf = ["run_boot", next_boot]
924 boot_status, msg = BuiltIn().run_keyword_and_ignore_error(*cmd_buf)
925 if boot_status == "FAIL":
Michael Walshb5839d02017-04-12 16:11:20 -0500926 gp.qprint(msg)
Michael Walsh6741f742017-02-20 16:16:38 -0600927
Michael Walshb5839d02017-04-12 16:11:20 -0500928 gp.qprintn()
Michael Walsh6741f742017-02-20 16:16:38 -0600929 if boot_status == "PASS":
930 boot_success = 1
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -0500931 completion_msg = gp.sprint_timen("BOOT_SUCCESS: \"" + next_boot
932 + "\" succeeded.")
Michael Walsh6741f742017-02-20 16:16:38 -0600933 else:
934 boot_success = 0
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -0500935 completion_msg = gp.sprint_timen("BOOT_FAILED: \"" + next_boot
936 + "\" failed.")
Sunil M325eb542017-08-10 07:09:43 -0500937
938 # Set boot_end_time for use by plug-ins.
939 boot_end_time = completion_msg[1:33]
940 gp.qprint_var(boot_end_time)
941
942 gp.qprint(completion_msg)
Michael Walsh6741f742017-02-20 16:16:38 -0600943
944 boot_results.update(next_boot, boot_status)
945
946 plug_in_setup()
947 # NOTE: A post_test_case call point failure is NOT counted as a boot
948 # failure.
949 rc, shell_rc, failed_plug_in_name = grpi.rprocess_plug_in_packages(
Michael Walsh600876d2017-05-30 17:58:58 -0500950 call_point='post_test_case', stop_on_plug_in_failure=0)
Michael Walsh6741f742017-02-20 16:16:38 -0600951
952 plug_in_setup()
953 rc, shell_rc, failed_plug_in_name = grpi.rprocess_plug_in_packages(
Michael Walsh89de14a2018-10-01 16:51:37 -0500954 call_point='ffdc_check', shell_rc=dump_ffdc_rc(),
Michael Walsh6741f742017-02-20 16:16:38 -0600955 stop_on_plug_in_failure=1, stop_on_non_zero_rc=1)
Michael Walsh12059e22019-03-21 11:03:45 -0500956 if ffdc_check == "All" or\
Michael Walsh89de14a2018-10-01 16:51:37 -0500957 shell_rc == dump_ffdc_rc():
Michael Walsh83f4bc72017-04-20 16:49:43 -0500958 status, ret_values = grk.run_key_u("my_ffdc", ignore=1)
959 if status != 'PASS':
Michael Walshff340002017-08-29 11:18:27 -0500960 gp.qprint_error("Call to my_ffdc failed.\n")
Michael Walshc9bd2e82019-04-18 11:06:52 -0500961 # Leave a record for caller that "soft" errors occurred.
962 soft_errors = 1
963 gpu.save_plug_in_value(soft_errors, pgm_name)
Michael Walsh6741f742017-02-20 16:16:38 -0600964
Michael Walshaabef1e2017-09-20 15:16:17 -0500965 if delete_errlogs:
966 # We need to purge error logs between boots or they build up.
Michael Walsh409ad352020-02-06 11:46:35 -0600967 grk.run_key(delete_errlogs_cmd, ignore=1)
Michael Walshd139f282017-04-04 18:00:23 -0500968
Michael Walsh952f9b02017-03-09 13:11:14 -0600969 boot_results.print_report()
Michael Walshb5839d02017-04-12 16:11:20 -0500970 gp.qprint_timen("Finished boot " + str(boot_count) + ".")
Michael Walsh952f9b02017-03-09 13:11:14 -0600971
Michael Walsh6741f742017-02-20 16:16:38 -0600972 plug_in_setup()
973 rc, shell_rc, failed_plug_in_name = grpi.rprocess_plug_in_packages(
Michael Walsh89de14a2018-10-01 16:51:37 -0500974 call_point='stop_check', shell_rc=stop_test_rc(),
975 stop_on_non_zero_rc=1)
976 if shell_rc == stop_test_rc():
Michael Walsh3ba8ecd2018-04-24 11:33:25 -0500977 message = "Stopping as requested by user.\n"
Michael Walsh80dddde2019-10-22 13:54:38 -0500978 gp.qprint_time(message)
Michael Walsh3ba8ecd2018-04-24 11:33:25 -0500979 BuiltIn().fail(message)
Michael Walsh6741f742017-02-20 16:16:38 -0600980
Michael Walshd139f282017-04-04 18:00:23 -0500981 # This should help prevent ConnectionErrors.
Michael Walsh0960b382017-06-22 16:23:37 -0500982 grk.run_key_u("Close All Connections")
Michael Walshd139f282017-04-04 18:00:23 -0500983
Michael Walsh6741f742017-02-20 16:16:38 -0600984 return True
985
Michael Walsh6741f742017-02-20 16:16:38 -0600986
Michael Walsh83f4bc72017-04-20 16:49:43 -0500987def obmc_boot_test_teardown():
Michael Walsh6741f742017-02-20 16:16:38 -0600988 r"""
Michael Walshf75d4352019-12-05 17:01:20 -0600989 Clean up after the main keyword.
Michael Walsh6741f742017-02-20 16:16:38 -0600990 """
Michael Walshf75d4352019-12-05 17:01:20 -0600991 gp.qprint_executing()
992
993 if ga.psutil_imported:
994 ga.terminate_descendants()
Michael Walsh6741f742017-02-20 16:16:38 -0600995
996 if cp_setup_called:
997 plug_in_setup()
998 rc, shell_rc, failed_plug_in_name = grpi.rprocess_plug_in_packages(
Michael Walsh600876d2017-05-30 17:58:58 -0500999 call_point='cleanup', stop_on_plug_in_failure=0)
Michael Walsh6741f742017-02-20 16:16:38 -06001000
Michael Walsh600876d2017-05-30 17:58:58 -05001001 if 'boot_results_file_path' in globals():
Michael Walsh986d8ae2019-07-17 10:02:23 -05001002 # Save boot_results and boot_history objects to a file in case they are
Michael Walsh6c645742018-08-17 15:02:17 -05001003 # needed again.
Michael Walsh600876d2017-05-30 17:58:58 -05001004 gp.qprint_timen("Saving boot_results to the following path.")
1005 gp.qprint_var(boot_results_file_path)
Michael Walsh986d8ae2019-07-17 10:02:23 -05001006 pickle.dump((boot_results, boot_history),
Michael Walsh6c645742018-08-17 15:02:17 -05001007 open(boot_results_file_path, 'wb'),
Michael Walsh600876d2017-05-30 17:58:58 -05001008 pickle.HIGHEST_PROTOCOL)
Michael Walsh0b93fbf2017-03-02 14:42:41 -06001009
Michael Walshff340002017-08-29 11:18:27 -05001010 global save_stack
1011 # Restore any global values saved on the save_stack.
1012 for parm_name in main_func_parm_list:
1013 # Get the parm_value if it was saved on the stack.
1014 try:
1015 parm_value = save_stack.pop(parm_name)
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -05001016 except BaseException:
Michael Walshff340002017-08-29 11:18:27 -05001017 # If it was not saved, no further action is required.
1018 continue
1019
1020 # Restore the saved value.
1021 cmd_buf = "BuiltIn().set_global_variable(\"${" + parm_name +\
1022 "}\", parm_value)"
1023 gp.dpissuing(cmd_buf)
1024 exec(cmd_buf)
1025
1026 gp.dprintn(save_stack.sprint_obj())
1027
Michael Walsh6741f742017-02-20 16:16:38 -06001028
Michael Walshc9116812017-03-10 14:23:06 -06001029def test_teardown():
Michael Walshc9116812017-03-10 14:23:06 -06001030 r"""
1031 Clean up after this test case.
1032 """
1033
1034 gp.qprintn()
Michael Walshf75d4352019-12-05 17:01:20 -06001035 gp.qprint_executing()
1036
1037 if ga.psutil_imported:
1038 ga.terminate_descendants()
1039
Michael Walshc9116812017-03-10 14:23:06 -06001040 cmd_buf = ["Print Error",
1041 "A keyword timeout occurred ending this program.\n"]
1042 BuiltIn().run_keyword_if_timeout_occurred(*cmd_buf)
1043
George Keishinga54e06f2020-06-12 10:42:41 -05001044 if redfish_supported:
1045 redfish.logout()
1046
Michael Walshc108e422019-03-28 12:27:18 -05001047 gp.qprint_pgm_footer()
Michael Walshb5839d02017-04-12 16:11:20 -05001048
Michael Walshc9116812017-03-10 14:23:06 -06001049
Michael Walsh89de14a2018-10-01 16:51:37 -05001050def post_stack():
1051 r"""
1052 Process post_stack plug-in programs.
1053 """
1054
1055 if not call_post_stack_plug:
1056 # The caller does not wish to have post_stack plug-in processing done.
1057 return
1058
1059 global boot_success
1060
1061 # NOTE: A post_stack call-point failure is NOT counted as a boot failure.
1062 pre_boot_plug_in_setup()
1063 # For the purposes of the following plug-ins, mark the "boot" as a success.
1064 boot_success = 1
1065 plug_in_setup()
Michael Walsh815b1d52018-10-30 13:32:26 -05001066 rc, shell_rc, failed_plug_in_name, history =\
1067 grpi.rprocess_plug_in_packages(call_point='post_stack',
1068 stop_on_plug_in_failure=0,
1069 return_history=True)
Michael Walsh986d8ae2019-07-17 10:02:23 -05001070 for doing_msg in history:
1071 update_boot_history(boot_history, doing_msg, max_boot_history)
Michael Walsh815b1d52018-10-30 13:32:26 -05001072 if rc != 0:
1073 boot_success = 0
Michael Walsh89de14a2018-10-01 16:51:37 -05001074
1075 plug_in_setup()
Michael Walsh815b1d52018-10-30 13:32:26 -05001076 rc, shell_rc, failed_plug_in_name =\
1077 grpi.rprocess_plug_in_packages(call_point='ffdc_check',
1078 shell_rc=dump_ffdc_rc(),
1079 stop_on_plug_in_failure=1,
1080 stop_on_non_zero_rc=1)
1081 if shell_rc == dump_ffdc_rc():
Michael Walsh89de14a2018-10-01 16:51:37 -05001082 status, ret_values = grk.run_key_u("my_ffdc", ignore=1)
1083 if status != 'PASS':
1084 gp.qprint_error("Call to my_ffdc failed.\n")
Michael Walshc9bd2e82019-04-18 11:06:52 -05001085 # Leave a record for caller that "soft" errors occurred.
1086 soft_errors = 1
1087 gpu.save_plug_in_value(soft_errors, pgm_name)
Michael Walsh89de14a2018-10-01 16:51:37 -05001088
1089 plug_in_setup()
1090 rc, shell_rc, failed_plug_in_name = grpi.rprocess_plug_in_packages(
1091 call_point='stop_check', shell_rc=stop_test_rc(),
1092 stop_on_non_zero_rc=1)
1093 if shell_rc == stop_test_rc():
1094 message = "Stopping as requested by user.\n"
Michael Walsh80dddde2019-10-22 13:54:38 -05001095 gp.qprint_time(message)
Michael Walsh89de14a2018-10-01 16:51:37 -05001096 BuiltIn().fail(message)
1097
1098
Michael Walshff340002017-08-29 11:18:27 -05001099def obmc_boot_test_py(loc_boot_stack=None,
1100 loc_stack_mode=None,
1101 loc_quiet=None):
Michael Walsh6741f742017-02-20 16:16:38 -06001102 r"""
1103 Do main program processing.
1104 """
1105
Michael Walshff340002017-08-29 11:18:27 -05001106 global save_stack
1107
Michael Walshf75d4352019-12-05 17:01:20 -06001108 ga.set_term_options(term_requests={'pgm_names': ['process_plug_in_packages.py']})
1109
George Keishing36efbc02018-12-12 10:18:23 -06001110 gp.dprintn()
Michael Walshff340002017-08-29 11:18:27 -05001111 # Process function parms.
1112 for parm_name in main_func_parm_list:
1113 # Get parm's value.
George Keishing36efbc02018-12-12 10:18:23 -06001114 parm_value = eval("loc_" + parm_name)
1115 gp.dpvars(parm_name, parm_value)
Michael Walshff340002017-08-29 11:18:27 -05001116
George Keishing36efbc02018-12-12 10:18:23 -06001117 if parm_value is not None:
Michael Walshff340002017-08-29 11:18:27 -05001118 # Save the global value on a stack.
1119 cmd_buf = "save_stack.push(BuiltIn().get_variable_value(\"${" +\
1120 parm_name + "}\"), \"" + parm_name + "\")"
1121 gp.dpissuing(cmd_buf)
1122 exec(cmd_buf)
1123
1124 # Set the global value to the passed value.
1125 cmd_buf = "BuiltIn().set_global_variable(\"${" + parm_name +\
1126 "}\", loc_" + parm_name + ")"
1127 gp.dpissuing(cmd_buf)
1128 exec(cmd_buf)
1129
1130 gp.dprintn(save_stack.sprint_obj())
Michael Walshb5839d02017-04-12 16:11:20 -05001131
Michael Walsh6741f742017-02-20 16:16:38 -06001132 setup()
1133
Michael Walshcd9fbfd2017-09-19 12:00:08 -05001134 init_boot_pass, init_boot_fail = boot_results.return_total_pass_fail()
1135
Michael Walsha20da402017-03-31 16:27:45 -05001136 if ffdc_only:
1137 gp.qprint_timen("Caller requested ffdc_only.")
Michael Walsh986d8ae2019-07-17 10:02:23 -05001138 if do_pre_boot_plug_in_setup:
1139 pre_boot_plug_in_setup()
Michael Walsh83f4bc72017-04-20 16:49:43 -05001140 grk.run_key_u("my_ffdc")
Michael Walsh764d2f82017-04-27 16:01:08 -05001141 return
Michael Walsha20da402017-03-31 16:27:45 -05001142
Michael Walsh409ad352020-02-06 11:46:35 -06001143 if delete_errlogs:
1144 # Delete errlogs prior to doing any boot tests.
1145 grk.run_key(delete_errlogs_cmd, ignore=1)
1146
Michael Walsh6741f742017-02-20 16:16:38 -06001147 # Process caller's boot_stack.
1148 while (len(boot_stack) > 0):
1149 test_loop_body()
1150
Michael Walshb5839d02017-04-12 16:11:20 -05001151 gp.qprint_timen("Finished processing stack.")
Michael Walsh30dadae2017-02-27 14:25:52 -06001152
Michael Walsh89de14a2018-10-01 16:51:37 -05001153 post_stack()
1154
Michael Walsh6741f742017-02-20 16:16:38 -06001155 # Process caller's boot_list.
1156 if len(boot_list) > 0:
1157 for ix in range(1, max_num_tests + 1):
1158 test_loop_body()
1159
Michael Walshb5839d02017-04-12 16:11:20 -05001160 gp.qprint_timen("Completed all requested boot tests.")
1161
1162 boot_pass, boot_fail = boot_results.return_total_pass_fail()
Michael Walshcd9fbfd2017-09-19 12:00:08 -05001163 new_fail = boot_fail - init_boot_fail
1164 if new_fail > boot_fail_threshold:
Michael Walshb5839d02017-04-12 16:11:20 -05001165 error_message = "Boot failures exceed the boot failure" +\
1166 " threshold:\n" +\
Michael Walshcd9fbfd2017-09-19 12:00:08 -05001167 gp.sprint_var(new_fail) +\
Michael Walshb5839d02017-04-12 16:11:20 -05001168 gp.sprint_var(boot_fail_threshold)
1169 BuiltIn().fail(gp.sprint_error(error_message))