blob: 6c6b7bb50861f41718860ef5ea1fdf9ccb64cd5b [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 Shepos1a67b082020-08-28 16:01:58 -050034import pel_utils as pel
Michael Walsh0bbd8602016-11-22 11:31:49 -060035
Michael Walsh0b93fbf2017-03-02 14:42:41 -060036base_path = os.path.dirname(os.path.dirname(
37 imp.find_module("gen_robot_print")[1])) +\
Michael Walshc9116812017-03-10 14:23:06 -060038 os.sep
Michael Walsh0b93fbf2017-03-02 14:42:41 -060039sys.path.append(base_path + "extended/")
40import run_keyword as rk
Michael Walsh0bbd8602016-11-22 11:31:49 -060041
Michael Walshe1e26442017-03-06 17:50:07 -060042# Setting master_pid correctly influences the behavior of plug-ins like
43# DB_Logging
44program_pid = os.getpid()
45master_pid = os.environ.get('AUTOBOOT_MASTER_PID', program_pid)
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -050046pgm_name = re.sub('\\.py$', '', os.path.basename(__file__))
Michael Walshe1e26442017-03-06 17:50:07 -060047
Michael Walshb5839d02017-04-12 16:11:20 -050048# Set up boot data structures.
Michael Walsh986d8ae2019-07-17 10:02:23 -050049os_host = BuiltIn().get_variable_value("${OS_HOST}", default="")
Michael Walsh0b93fbf2017-03-02 14:42:41 -060050
Michael Walsh6741f742017-02-20 16:16:38 -060051boot_lists = read_boot_lists()
Michael Walsh986d8ae2019-07-17 10:02:23 -050052
53# The maximum number of entries that can be in the boot_history global variable.
Michael Walsh815b1d52018-10-30 13:32:26 -050054max_boot_history = 10
Michael Walsh986d8ae2019-07-17 10:02:23 -050055boot_history = []
Michael Walsh6741f742017-02-20 16:16:38 -060056
Michael Walsh7dc885b2018-03-14 17:51:59 -050057state = st.return_state_constant('default_state')
Michael Walsh6741f742017-02-20 16:16:38 -060058cp_setup_called = 0
59next_boot = ""
60base_tool_dir_path = os.path.normpath(os.environ.get(
61 'AUTOBOOT_BASE_TOOL_DIR_PATH', "/tmp")) + os.sep
Michael Walshb5839d02017-04-12 16:11:20 -050062
Michael Walsh6741f742017-02-20 16:16:38 -060063ffdc_dir_path = os.path.normpath(os.environ.get('FFDC_DIR_PATH', '')) + os.sep
Michael Walsh6741f742017-02-20 16:16:38 -060064boot_success = 0
Michael Walsh6741f742017-02-20 16:16:38 -060065status_dir_path = os.environ.get('STATUS_DIR_PATH', "")
66if status_dir_path != "":
67 status_dir_path = os.path.normpath(status_dir_path) + os.sep
Michael Walshe58df1c2019-08-07 09:57:43 -050068redfish_supported = BuiltIn().get_variable_value("${REDFISH_SUPPORTED}", default=False)
George Keishingeb1fe352020-06-19 03:02:22 -050069redfish_rest_supported = BuiltIn().get_variable_value("${REDFISH_REST_SUPPORTED}", default=False)
Michael Walshe58df1c2019-08-07 09:57:43 -050070if redfish_supported:
George Keishing89537a82020-06-17 00:37:25 -050071 redfish = BuiltIn().get_library_instance('redfish')
Michael Walshe58df1c2019-08-07 09:57:43 -050072 default_power_on = "Redfish Power On"
73 default_power_off = "Redfish Power Off"
George Keishingeb1fe352020-06-19 03:02:22 -050074 if redfish_rest_supported:
Michael Sheposcc490b42020-08-26 12:53:01 -050075 delete_errlogs_cmd = "Delete Error Logs ${quiet}=${1}"
George Keishingeb1fe352020-06-19 03:02:22 -050076 default_set_power_policy = "Set BMC Power Policy ALWAYS_POWER_OFF"
77 else:
78 delete_errlogs_cmd = "Redfish Purge Event Log"
79 default_set_power_policy = "Redfish Set Power Restore Policy AlwaysOff"
Michael Walshe58df1c2019-08-07 09:57:43 -050080else:
81 default_power_on = "REST Power On"
82 default_power_off = "REST Power Off"
Michael Sheposcc490b42020-08-26 12:53:01 -050083 delete_errlogs_cmd = "Delete Error Logs ${quiet}=${1}"
George Keishinga54e06f2020-06-12 10:42:41 -050084 default_set_power_policy = "Set BMC Power Policy ALWAYS_POWER_OFF"
Michael Walsh6741f742017-02-20 16:16:38 -060085boot_count = 0
Michael Walsh0bbd8602016-11-22 11:31:49 -060086
Michael Walsh85678942017-03-27 14:34:22 -050087LOG_LEVEL = BuiltIn().get_variable_value("${LOG_LEVEL}")
Michael Walsh986d8ae2019-07-17 10:02:23 -050088AUTOBOOT_FFDC_PREFIX = os.environ.get('AUTOBOOT_FFDC_PREFIX', '')
89ffdc_prefix = AUTOBOOT_FFDC_PREFIX
Sunil M325eb542017-08-10 07:09:43 -050090boot_start_time = ""
91boot_end_time = ""
Michael Walshff340002017-08-29 11:18:27 -050092save_stack = vs.var_stack('save_stack')
93main_func_parm_list = ['boot_stack', 'stack_mode', 'quiet']
Michael Walsh85678942017-03-27 14:34:22 -050094
95
Michael Walsh89de14a2018-10-01 16:51:37 -050096def dump_ffdc_rc():
97 r"""
98 Return the constant dump ffdc test return code value.
99
100 When a plug-in call point program returns this value, it indicates that
101 this program should collect FFDC.
102 """
103
104 return 0x00000200
105
106
107def stop_test_rc():
108 r"""
109 Return the constant stop test return code value.
110
111 When a plug-in call point program returns this value, it indicates that
112 this program should stop running.
113 """
114
115 return 0x00000200
116
117
Michael Walsh0ad0f7f2017-05-04 14:39:58 -0500118def process_host(host,
119 host_var_name=""):
Michael Walsh0ad0f7f2017-05-04 14:39:58 -0500120 r"""
121 Process a host by getting the associated host name and IP address and
122 setting them in global variables.
123
124 If the caller does not pass the host_var_name, this function will try to
125 figure out the name of the variable used by the caller for the host parm.
126 Callers are advised to explicitly specify the host_var_name when calling
127 with an exec command. In such cases, the get_arg_name cannot figure out
128 the host variable name.
129
130 This function will then create similar global variable names by
131 removing "_host" and appending "_host_name" or "_ip" to the host variable
132 name.
133
134 Example:
135
136 If a call is made like this:
137 process_host(openbmc_host)
138
139 Global variables openbmc_host_name and openbmc_ip will be set.
140
141 Description of argument(s):
142 host A host name or IP. The name of the variable used should
143 have a suffix of "_host".
144 host_var_name The name of the variable being used as the host parm.
145 """
146
147 if host_var_name == "":
148 host_var_name = gp.get_arg_name(0, 1, stack_frame_ix=2)
149
150 host_name_var_name = re.sub("host", "host_name", host_var_name)
151 ip_var_name = re.sub("host", "ip", host_var_name)
152 cmd_buf = "global " + host_name_var_name + ", " + ip_var_name + " ; " +\
153 host_name_var_name + ", " + ip_var_name + " = gm.get_host_name_ip('" +\
154 host + "')"
155 exec(cmd_buf)
156
Michael Walsh0ad0f7f2017-05-04 14:39:58 -0500157
Michael Walshb5839d02017-04-12 16:11:20 -0500158def process_pgm_parms():
Michael Walshb5839d02017-04-12 16:11:20 -0500159 r"""
160 Process the program parameters by assigning them all to corresponding
161 globals. Also, set some global values that depend on program parameters.
162 """
163
164 # Program parameter processing.
165 # Assign all program parms to python variables which are global to this
166 # module.
167
168 global parm_list
169 parm_list = BuiltIn().get_variable_value("${parm_list}")
170 # The following subset of parms should be processed as integers.
171 int_list = ['max_num_tests', 'boot_pass', 'boot_fail', 'ffdc_only',
Michael Walsh89de14a2018-10-01 16:51:37 -0500172 'boot_fail_threshold', 'delete_errlogs',
Michael Walsh986d8ae2019-07-17 10:02:23 -0500173 'call_post_stack_plug', 'do_pre_boot_plug_in_setup', 'quiet',
174 'test_mode', 'debug']
Michael Walshb5839d02017-04-12 16:11:20 -0500175 for parm in parm_list:
176 if parm in int_list:
177 sub_cmd = "int(BuiltIn().get_variable_value(\"${" + parm +\
178 "}\", \"0\"))"
179 else:
180 sub_cmd = "BuiltIn().get_variable_value(\"${" + parm + "}\")"
181 cmd_buf = "global " + parm + " ; " + parm + " = " + sub_cmd
Michael Walshff340002017-08-29 11:18:27 -0500182 gp.dpissuing(cmd_buf)
Michael Walshb5839d02017-04-12 16:11:20 -0500183 exec(cmd_buf)
Michael Walsh0ad0f7f2017-05-04 14:39:58 -0500184 if re.match(r".*_host$", parm):
185 cmd_buf = "process_host(" + parm + ", '" + parm + "')"
186 exec(cmd_buf)
187 if re.match(r".*_password$", parm):
188 # Register the value of any parm whose name ends in _password.
189 # This will cause the print functions to replace passwords with
190 # asterisks in the output.
191 cmd_buf = "gp.register_passwords(" + parm + ")"
192 exec(cmd_buf)
Michael Walshb5839d02017-04-12 16:11:20 -0500193
194 global ffdc_dir_path_style
195 global boot_list
196 global boot_stack
197 global boot_results_file_path
198 global boot_results
Michael Walsh986d8ae2019-07-17 10:02:23 -0500199 global boot_history
Michael Walshb5839d02017-04-12 16:11:20 -0500200 global ffdc_list_file_path
Michael Walshe0cf8d72017-05-17 13:20:46 -0500201 global ffdc_report_list_path
Michael Walsh600876d2017-05-30 17:58:58 -0500202 global ffdc_summary_list_path
Michael Walsha3e7b222020-02-03 15:32:16 -0600203 global boot_table
204 global valid_boot_types
Michael Walshb5839d02017-04-12 16:11:20 -0500205
206 if ffdc_dir_path_style == "":
207 ffdc_dir_path_style = int(os.environ.get('FFDC_DIR_PATH_STYLE', '0'))
208
209 # Convert these program parms to lists for easier processing..
George Keishing36efbc02018-12-12 10:18:23 -0600210 boot_list = list(filter(None, boot_list.split(":")))
211 boot_stack = list(filter(None, boot_stack.split(":")))
Michael Walshb5839d02017-04-12 16:11:20 -0500212
Michael Walsha3e7b222020-02-03 15:32:16 -0600213 boot_table = create_boot_table(boot_table_path, os_host=os_host)
214 valid_boot_types = create_valid_boot_list(boot_table)
215
Michael Walsh903e0b22017-09-19 17:00:33 -0500216 cleanup_boot_results_file()
217 boot_results_file_path = create_boot_results_file_path(pgm_name,
218 openbmc_nickname,
219 master_pid)
Michael Walshb5839d02017-04-12 16:11:20 -0500220
221 if os.path.isfile(boot_results_file_path):
222 # We've been called before in this run so we'll load the saved
Michael Walsh986d8ae2019-07-17 10:02:23 -0500223 # boot_results and boot_history objects.
224 boot_results, boot_history =\
Michael Walsh6c645742018-08-17 15:02:17 -0500225 pickle.load(open(boot_results_file_path, 'rb'))
Michael Walshb5839d02017-04-12 16:11:20 -0500226 else:
227 boot_results = boot_results(boot_table, boot_pass, boot_fail)
228
229 ffdc_list_file_path = base_tool_dir_path + openbmc_nickname +\
230 "/FFDC_FILE_LIST"
Michael Walshe0cf8d72017-05-17 13:20:46 -0500231 ffdc_report_list_path = base_tool_dir_path + openbmc_nickname +\
232 "/FFDC_REPORT_FILE_LIST"
Michael Walshb5839d02017-04-12 16:11:20 -0500233
Michael Walsh600876d2017-05-30 17:58:58 -0500234 ffdc_summary_list_path = base_tool_dir_path + openbmc_nickname +\
235 "/FFDC_SUMMARY_FILE_LIST"
236
Michael Walshb5839d02017-04-12 16:11:20 -0500237
Michael Walsh85678942017-03-27 14:34:22 -0500238def initial_plug_in_setup():
Michael Walsh85678942017-03-27 14:34:22 -0500239 r"""
240 Initialize all plug-in environment variables which do not change for the
241 duration of the program.
242
243 """
244
245 global LOG_LEVEL
246 BuiltIn().set_log_level("NONE")
247
248 BuiltIn().set_global_variable("${master_pid}", master_pid)
249 BuiltIn().set_global_variable("${FFDC_DIR_PATH}", ffdc_dir_path)
250 BuiltIn().set_global_variable("${STATUS_DIR_PATH}", status_dir_path)
251 BuiltIn().set_global_variable("${BASE_TOOL_DIR_PATH}", base_tool_dir_path)
252 BuiltIn().set_global_variable("${FFDC_LIST_FILE_PATH}",
253 ffdc_list_file_path)
Michael Walshe0cf8d72017-05-17 13:20:46 -0500254 BuiltIn().set_global_variable("${FFDC_REPORT_LIST_PATH}",
255 ffdc_report_list_path)
Michael Walsh600876d2017-05-30 17:58:58 -0500256 BuiltIn().set_global_variable("${FFDC_SUMMARY_LIST_PATH}",
257 ffdc_summary_list_path)
Michael Walsh85678942017-03-27 14:34:22 -0500258
259 BuiltIn().set_global_variable("${FFDC_DIR_PATH_STYLE}",
260 ffdc_dir_path_style)
261 BuiltIn().set_global_variable("${FFDC_CHECK}",
262 ffdc_check)
263
264 # For each program parameter, set the corresponding AUTOBOOT_ environment
265 # variable value. Also, set an AUTOBOOT_ environment variable for every
266 # element in additional_values.
267 additional_values = ["program_pid", "master_pid", "ffdc_dir_path",
268 "status_dir_path", "base_tool_dir_path",
Michael Walsh600876d2017-05-30 17:58:58 -0500269 "ffdc_list_file_path", "ffdc_report_list_path",
Michael Shepos7fe83b32020-09-21 15:46:01 -0500270 "ffdc_summary_list_path", "execdir", "redfish_supported",
271 "redfish_rest_supported"]
Michael Walsh85678942017-03-27 14:34:22 -0500272
273 plug_in_vars = parm_list + additional_values
274
275 for var_name in plug_in_vars:
276 var_value = BuiltIn().get_variable_value("${" + var_name + "}")
277 var_name = var_name.upper()
278 if var_value is None:
279 var_value = ""
280 os.environ["AUTOBOOT_" + var_name] = str(var_value)
281
282 BuiltIn().set_log_level(LOG_LEVEL)
283
Michael Walsh68a61162017-04-25 11:54:06 -0500284 # Make sure the ffdc list directory exists.
285 ffdc_list_dir_path = os.path.dirname(ffdc_list_file_path) + os.sep
286 if not os.path.exists(ffdc_list_dir_path):
287 os.makedirs(ffdc_list_dir_path)
Michael Walsh85678942017-03-27 14:34:22 -0500288
Michael Walsh85678942017-03-27 14:34:22 -0500289
Michael Walsh0bbd8602016-11-22 11:31:49 -0600290def plug_in_setup():
Michael Walsh0bbd8602016-11-22 11:31:49 -0600291 r"""
Michael Walsh85678942017-03-27 14:34:22 -0500292 Initialize all changing plug-in environment variables for use by the
293 plug-in programs.
Michael Walsh0bbd8602016-11-22 11:31:49 -0600294 """
295
Michael Walsh85678942017-03-27 14:34:22 -0500296 global LOG_LEVEL
297 global test_really_running
298
299 BuiltIn().set_log_level("NONE")
300
Michael Walsh6741f742017-02-20 16:16:38 -0600301 boot_pass, boot_fail = boot_results.return_total_pass_fail()
Michael Walsh0bbd8602016-11-22 11:31:49 -0600302 if boot_pass > 1:
303 test_really_running = 1
304 else:
305 test_really_running = 0
306
Michael Walsh6741f742017-02-20 16:16:38 -0600307 BuiltIn().set_global_variable("${test_really_running}",
308 test_really_running)
309 BuiltIn().set_global_variable("${boot_type_desc}", next_boot)
Michael Walsh6741f742017-02-20 16:16:38 -0600310 BuiltIn().set_global_variable("${boot_pass}", boot_pass)
311 BuiltIn().set_global_variable("${boot_fail}", boot_fail)
312 BuiltIn().set_global_variable("${boot_success}", boot_success)
313 BuiltIn().set_global_variable("${ffdc_prefix}", ffdc_prefix)
Sunil M325eb542017-08-10 07:09:43 -0500314 BuiltIn().set_global_variable("${boot_start_time}", boot_start_time)
315 BuiltIn().set_global_variable("${boot_end_time}", boot_end_time)
Michael Walsh4c9a6452016-12-13 16:03:11 -0600316
Michael Walsh0bbd8602016-11-22 11:31:49 -0600317 # For each program parameter, set the corresponding AUTOBOOT_ environment
318 # variable value. Also, set an AUTOBOOT_ environment variable for every
319 # element in additional_values.
320 additional_values = ["boot_type_desc", "boot_success", "boot_pass",
Sunil M325eb542017-08-10 07:09:43 -0500321 "boot_fail", "test_really_running", "ffdc_prefix",
322 "boot_start_time", "boot_end_time"]
Michael Walsh0bbd8602016-11-22 11:31:49 -0600323
Michael Walsh85678942017-03-27 14:34:22 -0500324 plug_in_vars = additional_values
Michael Walsh0bbd8602016-11-22 11:31:49 -0600325
326 for var_name in plug_in_vars:
327 var_value = BuiltIn().get_variable_value("${" + var_name + "}")
328 var_name = var_name.upper()
329 if var_value is None:
330 var_value = ""
Michael Walsh6741f742017-02-20 16:16:38 -0600331 os.environ["AUTOBOOT_" + var_name] = str(var_value)
Michael Walsh0bbd8602016-11-22 11:31:49 -0600332
Michael Walsh0bbd8602016-11-22 11:31:49 -0600333 if debug:
Michael Walsh6741f742017-02-20 16:16:38 -0600334 shell_rc, out_buf = \
335 gc.cmd_fnc_u("printenv | egrep AUTOBOOT_ | sort -u")
Michael Walsh0bbd8602016-11-22 11:31:49 -0600336
Michael Walsh85678942017-03-27 14:34:22 -0500337 BuiltIn().set_log_level(LOG_LEVEL)
338
Michael Walsh0bbd8602016-11-22 11:31:49 -0600339
Michael Walshe0cf8d72017-05-17 13:20:46 -0500340def pre_boot_plug_in_setup():
341
342 # Clear the ffdc_list_file_path file. Plug-ins may now write to it.
343 try:
344 os.remove(ffdc_list_file_path)
345 except OSError:
346 pass
347
348 # Clear the ffdc_report_list_path file. Plug-ins may now write to it.
349 try:
350 os.remove(ffdc_report_list_path)
351 except OSError:
352 pass
353
Michael Walsh600876d2017-05-30 17:58:58 -0500354 # Clear the ffdc_summary_list_path file. Plug-ins may now write to it.
355 try:
356 os.remove(ffdc_summary_list_path)
357 except OSError:
358 pass
359
Michael Walshe1974b92017-08-03 13:39:51 -0500360 global ffdc_prefix
361
362 seconds = time.time()
363 loc_time = time.localtime(seconds)
364 time_string = time.strftime("%y%m%d.%H%M%S.", loc_time)
365
366 ffdc_prefix = openbmc_nickname + "." + time_string
367
Michael Walshe0cf8d72017-05-17 13:20:46 -0500368
Michael Walshf566fb12019-02-01 14:35:09 -0600369def default_sigusr1(signal_number=0,
370 frame=None):
371 r"""
372 Handle SIGUSR1 by doing nothing.
373
374 This function assists in debugging SIGUSR1 processing by printing messages
375 to stdout and to the log.html file.
376
377 Description of argument(s):
378 signal_number The signal number (should always be 10 for SIGUSR1).
379 frame The frame data.
380 """
381
Michael Walsh80dddde2019-10-22 13:54:38 -0500382 gp.qprintn()
383 gp.qprint_executing()
Michael Walshf566fb12019-02-01 14:35:09 -0600384 gp.lprint_executing()
385
386
387def set_default_siguser1():
388 r"""
389 Set the default_sigusr1 function to be the SIGUSR1 handler.
390 """
391
Michael Walsh80dddde2019-10-22 13:54:38 -0500392 gp.qprintn()
393 gp.qprint_executing()
Michael Walshf566fb12019-02-01 14:35:09 -0600394 gp.lprint_executing()
395 signal.signal(signal.SIGUSR1, default_sigusr1)
396
397
Michael Walsh6741f742017-02-20 16:16:38 -0600398def setup():
Michael Walsh0bbd8602016-11-22 11:31:49 -0600399 r"""
Michael Walsh6741f742017-02-20 16:16:38 -0600400 Do general program setup tasks.
Michael Walsh0bbd8602016-11-22 11:31:49 -0600401 """
402
Michael Walsh6741f742017-02-20 16:16:38 -0600403 global cp_setup_called
Michael Walsh81816742017-09-27 11:02:29 -0500404 global transitional_boot_selected
Michael Walsh0bbd8602016-11-22 11:31:49 -0600405
Michael Walshb5839d02017-04-12 16:11:20 -0500406 gp.qprintn()
407
George Keishinga54e06f2020-06-12 10:42:41 -0500408 if redfish_supported:
409 redfish.login()
410
Michael Walshf566fb12019-02-01 14:35:09 -0600411 set_default_siguser1()
Michael Walsh81816742017-09-27 11:02:29 -0500412 transitional_boot_selected = False
413
Michael Walsh83f4bc72017-04-20 16:49:43 -0500414 robot_pgm_dir_path = os.path.dirname(__file__) + os.sep
415 repo_bin_path = robot_pgm_dir_path.replace("/lib/", "/bin/")
Michael Walshd061c042017-05-23 14:46:57 -0500416 # If we can't find process_plug_in_packages.py, ssh_pw or
417 # validate_plug_ins.py, then we don't have our repo bin in PATH.
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -0500418 shell_rc, out_buf = gc.cmd_fnc_u("which process_plug_in_packages.py"
419 + " ssh_pw validate_plug_ins.py", quiet=1,
Michael Walshd061c042017-05-23 14:46:57 -0500420 print_output=0, show_err=0)
Michael Walshb5839d02017-04-12 16:11:20 -0500421 if shell_rc != 0:
Michael Walsh83f4bc72017-04-20 16:49:43 -0500422 os.environ['PATH'] = repo_bin_path + ":" + os.environ.get('PATH', "")
423 # Likewise, our repo lib subdir needs to be in sys.path and PYTHONPATH.
424 if robot_pgm_dir_path not in sys.path:
425 sys.path.append(robot_pgm_dir_path)
426 PYTHONPATH = os.environ.get("PYTHONPATH", "")
427 if PYTHONPATH == "":
428 os.environ['PYTHONPATH'] = robot_pgm_dir_path
429 else:
430 os.environ['PYTHONPATH'] = robot_pgm_dir_path + ":" + PYTHONPATH
Michael Walsh6741f742017-02-20 16:16:38 -0600431
432 validate_parms()
433
Michael Walshc108e422019-03-28 12:27:18 -0500434 gp.qprint_pgm_header()
Michael Walsh6741f742017-02-20 16:16:38 -0600435
George Keishinga54e06f2020-06-12 10:42:41 -0500436 grk.run_key_u(default_set_power_policy)
Michael Walsh11cfc8c2017-03-31 09:40:55 -0500437
Michael Walsh85678942017-03-27 14:34:22 -0500438 initial_plug_in_setup()
439
Michael Walsh6741f742017-02-20 16:16:38 -0600440 plug_in_setup()
441 rc, shell_rc, failed_plug_in_name = grpi.rprocess_plug_in_packages(
442 call_point='setup')
443 if rc != 0:
444 error_message = "Plug-in setup failed.\n"
Michael Walshc108e422019-03-28 12:27:18 -0500445 gp.print_error_report(error_message)
Michael Walsh6741f742017-02-20 16:16:38 -0600446 BuiltIn().fail(error_message)
447 # Setting cp_setup_called lets our Teardown know that it needs to call
448 # the cleanup plug-in call point.
449 cp_setup_called = 1
450
451 # Keyword "FFDC" will fail if TEST_MESSAGE is not set.
452 BuiltIn().set_global_variable("${TEST_MESSAGE}", "${EMPTY}")
Michael Walsh85678942017-03-27 14:34:22 -0500453 # FFDC_LOG_PATH is used by "FFDC" keyword.
454 BuiltIn().set_global_variable("${FFDC_LOG_PATH}", ffdc_dir_path)
Michael Walsh6741f742017-02-20 16:16:38 -0600455
Michael Walshdc80d672017-05-09 12:58:32 -0500456 # Also printed by FFDC.
457 global host_name
458 global host_ip
459 host = socket.gethostname()
460 host_name, host_ip = gm.get_host_name_ip(host)
461
Michael Walsh986d8ae2019-07-17 10:02:23 -0500462 gp.dprint_var(boot_table)
Michael Walshb5839d02017-04-12 16:11:20 -0500463 gp.dprint_var(boot_lists)
Michael Walsh0bbd8602016-11-22 11:31:49 -0600464
Michael Walsh0bbd8602016-11-22 11:31:49 -0600465
Michael Walsh6741f742017-02-20 16:16:38 -0600466def validate_parms():
Michael Walsh0bbd8602016-11-22 11:31:49 -0600467 r"""
Michael Walsh6741f742017-02-20 16:16:38 -0600468 Validate all program parameters.
Michael Walsh0bbd8602016-11-22 11:31:49 -0600469 """
470
Michael Walshb5839d02017-04-12 16:11:20 -0500471 process_pgm_parms()
Michael Walsh0bbd8602016-11-22 11:31:49 -0600472
Michael Walshb5839d02017-04-12 16:11:20 -0500473 gp.qprintn()
474
475 global openbmc_model
Michael Walshf5ce38c2020-02-27 12:46:20 -0600476 if openbmc_model == "":
477 status, ret_values =\
478 grk.run_key_u("Get BMC System Model")
479 openbmc_model = ret_values
480 BuiltIn().set_global_variable("${openbmc_model}", openbmc_model)
481 gv.set_exit_on_error(True)
Michael Walsh44cef252019-08-01 12:38:56 -0500482 gv.valid_value(openbmc_host)
483 gv.valid_value(openbmc_username)
484 gv.valid_value(openbmc_password)
485 gv.valid_value(rest_username)
486 gv.valid_value(rest_password)
487 gv.valid_value(ipmi_username)
488 gv.valid_value(ipmi_password)
Michael Walsh6741f742017-02-20 16:16:38 -0600489 if os_host != "":
Michael Walsh44cef252019-08-01 12:38:56 -0500490 gv.valid_value(os_username)
491 gv.valid_value(os_password)
Michael Walsh6741f742017-02-20 16:16:38 -0600492 if pdu_host != "":
Michael Walsh44cef252019-08-01 12:38:56 -0500493 gv.valid_value(pdu_username)
494 gv.valid_value(pdu_password)
495 gv.valid_integer(pdu_slot_no)
Michael Walsh6741f742017-02-20 16:16:38 -0600496 if openbmc_serial_host != "":
Michael Walsh44cef252019-08-01 12:38:56 -0500497 gv.valid_integer(openbmc_serial_port)
Michael Walsh44cef252019-08-01 12:38:56 -0500498 gv.valid_value(openbmc_model)
499 gv.valid_integer(max_num_tests)
500 gv.valid_integer(boot_pass)
501 gv.valid_integer(boot_fail)
Michael Walsh6741f742017-02-20 16:16:38 -0600502 plug_in_packages_list = grpi.rvalidate_plug_ins(plug_in_dir_paths)
503 BuiltIn().set_global_variable("${plug_in_packages_list}",
504 plug_in_packages_list)
Michael Walsh44cef252019-08-01 12:38:56 -0500505 gv.valid_value(stack_mode, valid_values=['normal', 'skip'])
Michael Walshf5ce38c2020-02-27 12:46:20 -0600506 gv.set_exit_on_error(False)
Michael Walsha20da402017-03-31 16:27:45 -0500507 if len(boot_list) == 0 and len(boot_stack) == 0 and not ffdc_only:
Michael Walsh6741f742017-02-20 16:16:38 -0600508 error_message = "You must provide either a value for either the" +\
509 " boot_list or the boot_stack parm.\n"
510 BuiltIn().fail(gp.sprint_error(error_message))
Michael Walsh6741f742017-02-20 16:16:38 -0600511 valid_boot_list(boot_list, valid_boot_types)
512 valid_boot_list(boot_stack, valid_boot_types)
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -0500513 selected_PDU_boots = list(set(boot_list + boot_stack)
514 & set(boot_lists['PDU_reboot']))
Michael Walsh11cfc8c2017-03-31 09:40:55 -0500515 if len(selected_PDU_boots) > 0 and pdu_host == "":
516 error_message = "You have selected the following boots which" +\
517 " require a PDU host but no value for pdu_host:\n"
518 error_message += gp.sprint_var(selected_PDU_boots)
Michael Walsh986d8ae2019-07-17 10:02:23 -0500519 error_message += gp.sprint_var(pdu_host, fmt=gp.blank())
Michael Walsh11cfc8c2017-03-31 09:40:55 -0500520 BuiltIn().fail(gp.sprint_error(error_message))
521
Michael Walsh6741f742017-02-20 16:16:38 -0600522 return
Michael Walsh0bbd8602016-11-22 11:31:49 -0600523
Michael Walsh0bbd8602016-11-22 11:31:49 -0600524
Michael Walsh6741f742017-02-20 16:16:38 -0600525def my_get_state():
Michael Walsh0bbd8602016-11-22 11:31:49 -0600526 r"""
Michael Walsh6741f742017-02-20 16:16:38 -0600527 Get the system state plus a little bit of wrapping.
Michael Walsh0bbd8602016-11-22 11:31:49 -0600528 """
529
Michael Walsh6741f742017-02-20 16:16:38 -0600530 global state
531
532 req_states = ['epoch_seconds'] + st.default_req_states
533
Michael Walshb5839d02017-04-12 16:11:20 -0500534 gp.qprint_timen("Getting system state.")
Michael Walsh6741f742017-02-20 16:16:38 -0600535 if test_mode:
536 state['epoch_seconds'] = int(time.time())
537 else:
Michael Walshb5839d02017-04-12 16:11:20 -0500538 state = st.get_state(req_states=req_states, quiet=quiet)
539 gp.qprint_var(state)
Michael Walsh341c21e2017-01-17 16:25:20 -0600540
Michael Walsh341c21e2017-01-17 16:25:20 -0600541
Michael Walsh45ca6e42017-09-14 17:29:12 -0500542def valid_state():
Michael Walsh45ca6e42017-09-14 17:29:12 -0500543 r"""
544 Verify that our state dictionary contains no blank values. If we don't get
545 valid state data, we cannot continue to work.
546 """
547
548 if st.compare_states(state, st.invalid_state_match, 'or'):
549 error_message = "The state dictionary contains blank fields which" +\
550 " is illegal.\n" + gp.sprint_var(state)
551 BuiltIn().fail(gp.sprint_error(error_message))
552
Michael Walsh45ca6e42017-09-14 17:29:12 -0500553
Michael Walsh6741f742017-02-20 16:16:38 -0600554def select_boot():
Michael Walsh341c21e2017-01-17 16:25:20 -0600555 r"""
556 Select a boot test to be run based on our current state and return the
557 chosen boot type.
558
559 Description of arguments:
Michael Walsh6741f742017-02-20 16:16:38 -0600560 state The state of the machine.
Michael Walsh341c21e2017-01-17 16:25:20 -0600561 """
562
Michael Walsh81816742017-09-27 11:02:29 -0500563 global transitional_boot_selected
Michael Walsh30dadae2017-02-27 14:25:52 -0600564 global boot_stack
565
Michael Walshb5839d02017-04-12 16:11:20 -0500566 gp.qprint_timen("Selecting a boot test.")
Michael Walsh6741f742017-02-20 16:16:38 -0600567
Michael Walsh81816742017-09-27 11:02:29 -0500568 if transitional_boot_selected and not boot_success:
569 prior_boot = next_boot
570 boot_candidate = boot_stack.pop()
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -0500571 gp.qprint_timen("The prior '" + next_boot + "' was chosen to"
572 + " transition to a valid state for '" + boot_candidate
573 + "' which was at the top of the boot_stack. Since"
574 + " the '" + next_boot + "' failed, the '"
575 + boot_candidate + "' has been removed from the stack"
576 + " to avoid and endless failure loop.")
Michael Walsh81816742017-09-27 11:02:29 -0500577 if len(boot_stack) == 0:
578 return ""
579
Michael Walsh6741f742017-02-20 16:16:38 -0600580 my_get_state()
Michael Walsh45ca6e42017-09-14 17:29:12 -0500581 valid_state()
Michael Walsh6741f742017-02-20 16:16:38 -0600582
Michael Walsh81816742017-09-27 11:02:29 -0500583 transitional_boot_selected = False
Michael Walsh6741f742017-02-20 16:16:38 -0600584 stack_popped = 0
585 if len(boot_stack) > 0:
586 stack_popped = 1
Michael Walshb5839d02017-04-12 16:11:20 -0500587 gp.qprint_dashes()
588 gp.qprint_var(boot_stack)
589 gp.qprint_dashes()
590 skip_boot_printed = 0
591 while len(boot_stack) > 0:
592 boot_candidate = boot_stack.pop()
593 if stack_mode == 'normal':
594 break
595 else:
596 if st.compare_states(state, boot_table[boot_candidate]['end']):
597 if not skip_boot_printed:
Michael Walshff340002017-08-29 11:18:27 -0500598 gp.qprint_var(stack_mode)
599 gp.qprintn()
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -0500600 gp.qprint_timen("Skipping the following boot tests"
601 + " which are unnecessary since their"
602 + " required end states match the"
603 + " current machine state:")
Michael Walshb5839d02017-04-12 16:11:20 -0500604 skip_boot_printed = 1
Michael Walshff340002017-08-29 11:18:27 -0500605 gp.qprint_var(boot_candidate)
Michael Walshb5839d02017-04-12 16:11:20 -0500606 boot_candidate = ""
607 if boot_candidate == "":
608 gp.qprint_dashes()
609 gp.qprint_var(boot_stack)
610 gp.qprint_dashes()
611 return boot_candidate
Michael Walsh6741f742017-02-20 16:16:38 -0600612 if st.compare_states(state, boot_table[boot_candidate]['start']):
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -0500613 gp.qprint_timen("The machine state is valid for a '"
614 + boot_candidate + "' boot test.")
Michael Walshb5839d02017-04-12 16:11:20 -0500615 gp.qprint_dashes()
616 gp.qprint_var(boot_stack)
617 gp.qprint_dashes()
Michael Walsh6741f742017-02-20 16:16:38 -0600618 return boot_candidate
Michael Walsh341c21e2017-01-17 16:25:20 -0600619 else:
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -0500620 gp.qprint_timen("The machine state does not match the required"
621 + " starting state for a '" + boot_candidate
622 + "' boot test:")
Michael Walsh986d8ae2019-07-17 10:02:23 -0500623 gp.qprint_varx("boot_table_start_entry",
624 boot_table[boot_candidate]['start'])
Michael Walsh6741f742017-02-20 16:16:38 -0600625 boot_stack.append(boot_candidate)
Michael Walsh81816742017-09-27 11:02:29 -0500626 transitional_boot_selected = True
Michael Walsh6741f742017-02-20 16:16:38 -0600627 popped_boot = boot_candidate
628
629 # Loop through your list selecting a boot_candidates
630 boot_candidates = []
631 for boot_candidate in boot_list:
632 if st.compare_states(state, boot_table[boot_candidate]['start']):
633 if stack_popped:
634 if st.compare_states(boot_table[boot_candidate]['end'],
Gunnar Mills096cd562018-03-26 10:19:12 -0500635 boot_table[popped_boot]['start']):
Michael Walsh6741f742017-02-20 16:16:38 -0600636 boot_candidates.append(boot_candidate)
637 else:
638 boot_candidates.append(boot_candidate)
639
640 if len(boot_candidates) == 0:
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -0500641 gp.qprint_timen("The user's boot list contained no boot tests"
642 + " which are valid for the current machine state.")
Michael Walsh6741f742017-02-20 16:16:38 -0600643 boot_candidate = default_power_on
644 if not st.compare_states(state, boot_table[default_power_on]['start']):
645 boot_candidate = default_power_off
646 boot_candidates.append(boot_candidate)
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -0500647 gp.qprint_timen("Using default '" + boot_candidate
648 + "' boot type to transition to valid state.")
Michael Walsh6741f742017-02-20 16:16:38 -0600649
Michael Walshb5839d02017-04-12 16:11:20 -0500650 gp.dprint_var(boot_candidates)
Michael Walsh6741f742017-02-20 16:16:38 -0600651
652 # Randomly select a boot from the candidate list.
653 boot = random.choice(boot_candidates)
Michael Walsh341c21e2017-01-17 16:25:20 -0600654
655 return boot
Michael Walsh0bbd8602016-11-22 11:31:49 -0600656
Michael Walsh55302292017-01-10 11:43:02 -0600657
Michael Walshb2e53ec2017-10-30 15:04:36 -0500658def print_defect_report(ffdc_file_list):
Michael Walsh341c21e2017-01-17 16:25:20 -0600659 r"""
660 Print a defect report.
Michael Walshb2e53ec2017-10-30 15:04:36 -0500661
662 Description of argument(s):
663 ffdc_file_list A list of files which were collected by our ffdc functions.
Michael Walsh341c21e2017-01-17 16:25:20 -0600664 """
665
Michael Walsh600876d2017-05-30 17:58:58 -0500666 # Making deliberate choice to NOT run plug_in_setup(). We don't want
667 # ffdc_prefix updated.
668 rc, shell_rc, failed_plug_in_name = grpi.rprocess_plug_in_packages(
669 call_point='ffdc_report', stop_on_plug_in_failure=0)
670
Michael Walshe0cf8d72017-05-17 13:20:46 -0500671 # Get additional header data which may have been created by ffdc plug-ins.
672 # Also, delete the individual header files to cleanup.
673 cmd_buf = "file_list=$(cat " + ffdc_report_list_path + " 2>/dev/null)" +\
674 " ; [ ! -z \"${file_list}\" ] && cat ${file_list}" +\
675 " 2>/dev/null ; rm -rf ${file_list} 2>/dev/null || :"
676 shell_rc, more_header_info = gc.cmd_fnc_u(cmd_buf, print_output=0,
677 show_err=0)
678
Michael Walshb2e53ec2017-10-30 15:04:36 -0500679 # Get additional summary data which may have been created by ffdc plug-ins.
Michael Walsh600876d2017-05-30 17:58:58 -0500680 # Also, delete the individual header files to cleanup.
681 cmd_buf = "file_list=$(cat " + ffdc_summary_list_path + " 2>/dev/null)" +\
682 " ; [ ! -z \"${file_list}\" ] && cat ${file_list}" +\
683 " 2>/dev/null ; rm -rf ${file_list} 2>/dev/null || :"
684 shell_rc, ffdc_summary_info = gc.cmd_fnc_u(cmd_buf, print_output=0,
685 show_err=0)
686
Michael Walshb2e53ec2017-10-30 15:04:36 -0500687 # ffdc_list_file_path contains a list of any ffdc files created by plug-
688 # ins, etc. Read that data into a list.
Michael Walsh341c21e2017-01-17 16:25:20 -0600689 try:
Michael Walshb2e53ec2017-10-30 15:04:36 -0500690 plug_in_ffdc_list = \
691 open(ffdc_list_file_path, 'r').read().rstrip("\n").split("\n")
George Keishing36efbc02018-12-12 10:18:23 -0600692 plug_in_ffdc_list = list(filter(None, plug_in_ffdc_list))
Michael Walsh341c21e2017-01-17 16:25:20 -0600693 except IOError:
Michael Walshb2e53ec2017-10-30 15:04:36 -0500694 plug_in_ffdc_list = []
695
696 # Combine the files from plug_in_ffdc_list with the ffdc_file_list passed
697 # in. Eliminate duplicates and sort the list.
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -0500698 ffdc_file_list = sorted(set(ffdc_file_list + plug_in_ffdc_list))
Michael Walshb2e53ec2017-10-30 15:04:36 -0500699
700 if status_file_path != "":
701 ffdc_file_list.insert(0, status_file_path)
702
703 # Convert the list to a printable list.
704 printable_ffdc_file_list = "\n".join(ffdc_file_list)
Michael Walsh341c21e2017-01-17 16:25:20 -0600705
Michael Walsh68a61162017-04-25 11:54:06 -0500706 # Open ffdc_file_list for writing. We will write a complete list of
707 # FFDC files to it for possible use by plug-ins like cp_stop_check.
708 ffdc_list_file = open(ffdc_list_file_path, 'w')
Michael Walshb2e53ec2017-10-30 15:04:36 -0500709 ffdc_list_file.write(printable_ffdc_file_list + "\n")
710 ffdc_list_file.close()
711
712 indent = 0
713 width = 90
714 linefeed = 1
715 char = "="
Michael Walsh68a61162017-04-25 11:54:06 -0500716
717 gp.qprintn()
Michael Walshb2e53ec2017-10-30 15:04:36 -0500718 gp.qprint_dashes(indent, width, linefeed, char)
Michael Walsh68a61162017-04-25 11:54:06 -0500719 gp.qprintn("Copy this data to the defect:\n")
720
Michael Walshe0cf8d72017-05-17 13:20:46 -0500721 if len(more_header_info) > 0:
Michael Walshff340002017-08-29 11:18:27 -0500722 gp.qprintn(more_header_info)
Michael Walshdc80d672017-05-09 12:58:32 -0500723 gp.qpvars(host_name, host_ip, openbmc_nickname, openbmc_host,
724 openbmc_host_name, openbmc_ip, openbmc_username,
Michael Walsh0a3bdb42019-01-31 16:21:44 +0000725 openbmc_password, rest_username, rest_password, ipmi_username,
726 ipmi_password, os_host, os_host_name, os_ip, os_username,
Michael Walshdc80d672017-05-09 12:58:32 -0500727 os_password, pdu_host, pdu_host_name, pdu_ip, pdu_username,
728 pdu_password, pdu_slot_no, openbmc_serial_host,
729 openbmc_serial_host_name, openbmc_serial_ip, openbmc_serial_port)
Michael Walsh68a61162017-04-25 11:54:06 -0500730
731 gp.qprintn()
Michael Walsh986d8ae2019-07-17 10:02:23 -0500732 print_boot_history(boot_history)
Michael Walsh68a61162017-04-25 11:54:06 -0500733 gp.qprintn()
734 gp.qprint_var(state)
Michael Walshb5839d02017-04-12 16:11:20 -0500735 gp.qprintn()
736 gp.qprintn("FFDC data files:")
Michael Walshb2e53ec2017-10-30 15:04:36 -0500737 gp.qprintn(printable_ffdc_file_list)
Michael Walshb5839d02017-04-12 16:11:20 -0500738 gp.qprintn()
Michael Walsh341c21e2017-01-17 16:25:20 -0600739
Michael Walsh600876d2017-05-30 17:58:58 -0500740 if len(ffdc_summary_info) > 0:
Michael Walshff340002017-08-29 11:18:27 -0500741 gp.qprintn(ffdc_summary_info)
Michael Walsh600876d2017-05-30 17:58:58 -0500742
Michael Walshb2e53ec2017-10-30 15:04:36 -0500743 gp.qprint_dashes(indent, width, linefeed, char)
Michael Walsh68a61162017-04-25 11:54:06 -0500744
Michael Walsh6741f742017-02-20 16:16:38 -0600745
Michael Walsh6741f742017-02-20 16:16:38 -0600746def my_ffdc():
Michael Walsh6741f742017-02-20 16:16:38 -0600747 r"""
748 Collect FFDC data.
749 """
750
751 global state
752
753 plug_in_setup()
754 rc, shell_rc, failed_plug_in_name = grpi.rprocess_plug_in_packages(
Michael Walsh600876d2017-05-30 17:58:58 -0500755 call_point='ffdc', stop_on_plug_in_failure=0)
Michael Walsh6741f742017-02-20 16:16:38 -0600756
757 AUTOBOOT_FFDC_PREFIX = os.environ['AUTOBOOT_FFDC_PREFIX']
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -0500758 status, ffdc_file_list = grk.run_key_u("FFDC ffdc_prefix="
759 + AUTOBOOT_FFDC_PREFIX
760 + " ffdc_function_list="
761 + ffdc_function_list, ignore=1)
Michael Walsh83f4bc72017-04-20 16:49:43 -0500762 if status != 'PASS':
Michael Walshff340002017-08-29 11:18:27 -0500763 gp.qprint_error("Call to ffdc failed.\n")
Michael Walshc9bd2e82019-04-18 11:06:52 -0500764 if type(ffdc_file_list) is not list:
765 ffdc_file_list = []
766 # Leave a record for caller that "soft" errors occurred.
767 soft_errors = 1
768 gpu.save_plug_in_value(soft_errors, pgm_name)
Michael Walsh6741f742017-02-20 16:16:38 -0600769
770 my_get_state()
771
Michael Walshb2e53ec2017-10-30 15:04:36 -0500772 print_defect_report(ffdc_file_list)
Michael Walsh6741f742017-02-20 16:16:38 -0600773
Michael Walsh6741f742017-02-20 16:16:38 -0600774
Michael Walsh6741f742017-02-20 16:16:38 -0600775def print_test_start_message(boot_keyword):
Michael Walsh6741f742017-02-20 16:16:38 -0600776 r"""
777 Print a message indicating what boot test is about to run.
778
779 Description of arguments:
780 boot_keyword The name of the boot which is to be run
781 (e.g. "BMC Power On").
782 """
783
Michael Walsh986d8ae2019-07-17 10:02:23 -0500784 global boot_history
Sunil M325eb542017-08-10 07:09:43 -0500785 global boot_start_time
Michael Walsh6741f742017-02-20 16:16:38 -0600786
787 doing_msg = gp.sprint_timen("Doing \"" + boot_keyword + "\".")
Sunil M325eb542017-08-10 07:09:43 -0500788
789 # Set boot_start_time for use by plug-ins.
790 boot_start_time = doing_msg[1:33]
791 gp.qprint_var(boot_start_time)
792
Michael Walshb5839d02017-04-12 16:11:20 -0500793 gp.qprint(doing_msg)
Michael Walsh6741f742017-02-20 16:16:38 -0600794
Michael Walsh986d8ae2019-07-17 10:02:23 -0500795 update_boot_history(boot_history, doing_msg, max_boot_history)
Michael Walsh6741f742017-02-20 16:16:38 -0600796
Michael Walsh6741f742017-02-20 16:16:38 -0600797
Michael Walshf566fb12019-02-01 14:35:09 -0600798def stop_boot_test(signal_number=0,
799 frame=None):
800 r"""
801 Handle SIGUSR1 by aborting the boot test that is running.
802
803 Description of argument(s):
804 signal_number The signal number (should always be 10 for SIGUSR1).
805 frame The frame data.
806 """
807
Michael Walsh80dddde2019-10-22 13:54:38 -0500808 gp.qprintn()
809 gp.qprint_executing()
Michael Walshf566fb12019-02-01 14:35:09 -0600810 gp.lprint_executing()
811
812 # Restore original sigusr1 handler.
813 set_default_siguser1()
814
815 message = "The caller has asked that the boot test be stopped and marked"
816 message += " as a failure."
817
818 function_stack = gm.get_function_stack()
819 if "wait_state" in function_stack:
Michael Walshc44aa532019-06-14 13:33:29 -0500820 st.set_exit_wait_early_message(message)
Michael Walshf566fb12019-02-01 14:35:09 -0600821 else:
822 BuiltIn().fail(gp.sprint_error(message))
823
824
Michael Walsh6741f742017-02-20 16:16:38 -0600825def run_boot(boot):
Michael Walsh6741f742017-02-20 16:16:38 -0600826 r"""
827 Run the specified boot.
828
829 Description of arguments:
830 boot The name of the boot test to be performed.
831 """
832
833 global state
834
Michael Walshf566fb12019-02-01 14:35:09 -0600835 signal.signal(signal.SIGUSR1, stop_boot_test)
836 gp.qprint_timen("stop_boot_test is armed.")
837
Michael Walsh6741f742017-02-20 16:16:38 -0600838 print_test_start_message(boot)
839
840 plug_in_setup()
841 rc, shell_rc, failed_plug_in_name = \
842 grpi.rprocess_plug_in_packages(call_point="pre_boot")
843 if rc != 0:
844 error_message = "Plug-in failed with non-zero return code.\n" +\
Michael Walsh986d8ae2019-07-17 10:02:23 -0500845 gp.sprint_var(rc, fmt=gp.hexa())
Michael Walshf566fb12019-02-01 14:35:09 -0600846 set_default_siguser1()
Michael Walsh6741f742017-02-20 16:16:38 -0600847 BuiltIn().fail(gp.sprint_error(error_message))
848
849 if test_mode:
850 # In test mode, we'll pretend the boot worked by assigning its
851 # required end state to the default state value.
Michael Walsh30dadae2017-02-27 14:25:52 -0600852 state = st.strip_anchor_state(boot_table[boot]['end'])
Michael Walsh6741f742017-02-20 16:16:38 -0600853 else:
854 # Assertion: We trust that the state data was made fresh by the
855 # caller.
856
Michael Walshb5839d02017-04-12 16:11:20 -0500857 gp.qprintn()
Michael Walsh6741f742017-02-20 16:16:38 -0600858
859 if boot_table[boot]['method_type'] == "keyword":
Michael Walsh0b93fbf2017-03-02 14:42:41 -0600860 rk.my_run_keywords(boot_table[boot].get('lib_file_path', ''),
Michael Walshb5839d02017-04-12 16:11:20 -0500861 boot_table[boot]['method'],
862 quiet=quiet)
Michael Walsh6741f742017-02-20 16:16:38 -0600863
864 if boot_table[boot]['bmc_reboot']:
865 st.wait_for_comm_cycle(int(state['epoch_seconds']))
Michael Walsh30dadae2017-02-27 14:25:52 -0600866 plug_in_setup()
867 rc, shell_rc, failed_plug_in_name = \
868 grpi.rprocess_plug_in_packages(call_point="post_reboot")
869 if rc != 0:
Michael Walsh0b93fbf2017-03-02 14:42:41 -0600870 error_message = "Plug-in failed with non-zero return code.\n"
Michael Walsh986d8ae2019-07-17 10:02:23 -0500871 error_message += gp.sprint_var(rc, fmt=gp.hexa())
Michael Walshf566fb12019-02-01 14:35:09 -0600872 set_default_siguser1()
Michael Walsh30dadae2017-02-27 14:25:52 -0600873 BuiltIn().fail(gp.sprint_error(error_message))
Michael Walsh6741f742017-02-20 16:16:38 -0600874 else:
875 match_state = st.anchor_state(state)
876 del match_state['epoch_seconds']
877 # Wait for the state to change in any way.
878 st.wait_state(match_state, wait_time=state_change_timeout,
Michael Walsh600876d2017-05-30 17:58:58 -0500879 interval="10 seconds", invert=1)
Michael Walsh6741f742017-02-20 16:16:38 -0600880
Michael Walshb5839d02017-04-12 16:11:20 -0500881 gp.qprintn()
Michael Walsh6741f742017-02-20 16:16:38 -0600882 if boot_table[boot]['end']['chassis'] == "Off":
883 boot_timeout = power_off_timeout
884 else:
885 boot_timeout = power_on_timeout
886 st.wait_state(boot_table[boot]['end'], wait_time=boot_timeout,
Michael Walsh600876d2017-05-30 17:58:58 -0500887 interval="10 seconds")
Michael Walsh6741f742017-02-20 16:16:38 -0600888
889 plug_in_setup()
890 rc, shell_rc, failed_plug_in_name = \
891 grpi.rprocess_plug_in_packages(call_point="post_boot")
892 if rc != 0:
893 error_message = "Plug-in failed with non-zero return code.\n" +\
Michael Walsh986d8ae2019-07-17 10:02:23 -0500894 gp.sprint_var(rc, fmt=gp.hexa())
Michael Walshf566fb12019-02-01 14:35:09 -0600895 set_default_siguser1()
Michael Walsh6741f742017-02-20 16:16:38 -0600896 BuiltIn().fail(gp.sprint_error(error_message))
897
Michael Walshf566fb12019-02-01 14:35:09 -0600898 # Restore original sigusr1 handler.
899 set_default_siguser1()
900
Michael Walsh6741f742017-02-20 16:16:38 -0600901
Michael Walsh6741f742017-02-20 16:16:38 -0600902def test_loop_body():
Michael Walsh6741f742017-02-20 16:16:38 -0600903 r"""
904 The main loop body for the loop in main_py.
905
906 Description of arguments:
907 boot_count The iteration number (starts at 1).
908 """
909
910 global boot_count
911 global state
912 global next_boot
913 global boot_success
Sunil M325eb542017-08-10 07:09:43 -0500914 global boot_end_time
Michael Walsh6741f742017-02-20 16:16:38 -0600915
Michael Walshb5839d02017-04-12 16:11:20 -0500916 gp.qprintn()
Michael Walsh6741f742017-02-20 16:16:38 -0600917
918 next_boot = select_boot()
Michael Walshb5839d02017-04-12 16:11:20 -0500919 if next_boot == "":
920 return True
Michael Walsh6741f742017-02-20 16:16:38 -0600921
Michael Walshb5839d02017-04-12 16:11:20 -0500922 boot_count += 1
923 gp.qprint_timen("Starting boot " + str(boot_count) + ".")
Michael Walsh6741f742017-02-20 16:16:38 -0600924
Michael Walshe0cf8d72017-05-17 13:20:46 -0500925 pre_boot_plug_in_setup()
Michael Walsh6741f742017-02-20 16:16:38 -0600926
927 cmd_buf = ["run_boot", next_boot]
928 boot_status, msg = BuiltIn().run_keyword_and_ignore_error(*cmd_buf)
929 if boot_status == "FAIL":
Michael Walshb5839d02017-04-12 16:11:20 -0500930 gp.qprint(msg)
Michael Walsh6741f742017-02-20 16:16:38 -0600931
Michael Walshb5839d02017-04-12 16:11:20 -0500932 gp.qprintn()
Michael Walsh6741f742017-02-20 16:16:38 -0600933 if boot_status == "PASS":
934 boot_success = 1
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -0500935 completion_msg = gp.sprint_timen("BOOT_SUCCESS: \"" + next_boot
936 + "\" succeeded.")
Michael Walsh6741f742017-02-20 16:16:38 -0600937 else:
938 boot_success = 0
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -0500939 completion_msg = gp.sprint_timen("BOOT_FAILED: \"" + next_boot
940 + "\" failed.")
Sunil M325eb542017-08-10 07:09:43 -0500941
942 # Set boot_end_time for use by plug-ins.
943 boot_end_time = completion_msg[1:33]
944 gp.qprint_var(boot_end_time)
945
946 gp.qprint(completion_msg)
Michael Walsh6741f742017-02-20 16:16:38 -0600947
948 boot_results.update(next_boot, boot_status)
949
950 plug_in_setup()
951 # NOTE: A post_test_case call point failure is NOT counted as a boot
952 # failure.
953 rc, shell_rc, failed_plug_in_name = grpi.rprocess_plug_in_packages(
Michael Walsh600876d2017-05-30 17:58:58 -0500954 call_point='post_test_case', stop_on_plug_in_failure=0)
Michael Walsh6741f742017-02-20 16:16:38 -0600955
956 plug_in_setup()
957 rc, shell_rc, failed_plug_in_name = grpi.rprocess_plug_in_packages(
Michael Walsh89de14a2018-10-01 16:51:37 -0500958 call_point='ffdc_check', shell_rc=dump_ffdc_rc(),
Michael Walsh6741f742017-02-20 16:16:38 -0600959 stop_on_plug_in_failure=1, stop_on_non_zero_rc=1)
Michael Walsh12059e22019-03-21 11:03:45 -0500960 if ffdc_check == "All" or\
Michael Walsh89de14a2018-10-01 16:51:37 -0500961 shell_rc == dump_ffdc_rc():
Michael Walsh83f4bc72017-04-20 16:49:43 -0500962 status, ret_values = grk.run_key_u("my_ffdc", ignore=1)
963 if status != 'PASS':
Michael Walshff340002017-08-29 11:18:27 -0500964 gp.qprint_error("Call to my_ffdc failed.\n")
Michael Walshc9bd2e82019-04-18 11:06:52 -0500965 # Leave a record for caller that "soft" errors occurred.
966 soft_errors = 1
967 gpu.save_plug_in_value(soft_errors, pgm_name)
Michael Walsh6741f742017-02-20 16:16:38 -0600968
Michael Walshaabef1e2017-09-20 15:16:17 -0500969 if delete_errlogs:
Michael Shepos1a67b082020-08-28 16:01:58 -0500970 # print error logs before delete
971 status, error_logs = grk.run_key_u("Get Error Logs")
972 pels = pel.peltool("-l", ignore_err=1)
973 gp.qprint_vars(error_logs, pels)
974
Michael Walshaabef1e2017-09-20 15:16:17 -0500975 # We need to purge error logs between boots or they build up.
Michael Walsh409ad352020-02-06 11:46:35 -0600976 grk.run_key(delete_errlogs_cmd, ignore=1)
Michael Walshd139f282017-04-04 18:00:23 -0500977
Michael Walsh952f9b02017-03-09 13:11:14 -0600978 boot_results.print_report()
Michael Walshb5839d02017-04-12 16:11:20 -0500979 gp.qprint_timen("Finished boot " + str(boot_count) + ".")
Michael Walsh952f9b02017-03-09 13:11:14 -0600980
Michael Walsh6741f742017-02-20 16:16:38 -0600981 plug_in_setup()
982 rc, shell_rc, failed_plug_in_name = grpi.rprocess_plug_in_packages(
Michael Walsh89de14a2018-10-01 16:51:37 -0500983 call_point='stop_check', shell_rc=stop_test_rc(),
984 stop_on_non_zero_rc=1)
985 if shell_rc == stop_test_rc():
Michael Walsh3ba8ecd2018-04-24 11:33:25 -0500986 message = "Stopping as requested by user.\n"
Michael Walsh80dddde2019-10-22 13:54:38 -0500987 gp.qprint_time(message)
Michael Walsh3ba8ecd2018-04-24 11:33:25 -0500988 BuiltIn().fail(message)
Michael Walsh6741f742017-02-20 16:16:38 -0600989
Michael Walshd139f282017-04-04 18:00:23 -0500990 # This should help prevent ConnectionErrors.
Michael Walsh0960b382017-06-22 16:23:37 -0500991 grk.run_key_u("Close All Connections")
Michael Walshd139f282017-04-04 18:00:23 -0500992
Michael Walsh6741f742017-02-20 16:16:38 -0600993 return True
994
Michael Walsh6741f742017-02-20 16:16:38 -0600995
Michael Walsh83f4bc72017-04-20 16:49:43 -0500996def obmc_boot_test_teardown():
Michael Walsh6741f742017-02-20 16:16:38 -0600997 r"""
Michael Walshf75d4352019-12-05 17:01:20 -0600998 Clean up after the main keyword.
Michael Walsh6741f742017-02-20 16:16:38 -0600999 """
Michael Walshf75d4352019-12-05 17:01:20 -06001000 gp.qprint_executing()
1001
1002 if ga.psutil_imported:
1003 ga.terminate_descendants()
Michael Walsh6741f742017-02-20 16:16:38 -06001004
1005 if cp_setup_called:
1006 plug_in_setup()
1007 rc, shell_rc, failed_plug_in_name = grpi.rprocess_plug_in_packages(
Michael Walsh600876d2017-05-30 17:58:58 -05001008 call_point='cleanup', stop_on_plug_in_failure=0)
Michael Walsh6741f742017-02-20 16:16:38 -06001009
Michael Walsh600876d2017-05-30 17:58:58 -05001010 if 'boot_results_file_path' in globals():
Michael Walsh986d8ae2019-07-17 10:02:23 -05001011 # Save boot_results and boot_history objects to a file in case they are
Michael Walsh6c645742018-08-17 15:02:17 -05001012 # needed again.
Michael Walsh600876d2017-05-30 17:58:58 -05001013 gp.qprint_timen("Saving boot_results to the following path.")
1014 gp.qprint_var(boot_results_file_path)
Michael Walsh986d8ae2019-07-17 10:02:23 -05001015 pickle.dump((boot_results, boot_history),
Michael Walsh6c645742018-08-17 15:02:17 -05001016 open(boot_results_file_path, 'wb'),
Michael Walsh600876d2017-05-30 17:58:58 -05001017 pickle.HIGHEST_PROTOCOL)
Michael Walsh0b93fbf2017-03-02 14:42:41 -06001018
Michael Walshff340002017-08-29 11:18:27 -05001019 global save_stack
1020 # Restore any global values saved on the save_stack.
1021 for parm_name in main_func_parm_list:
1022 # Get the parm_value if it was saved on the stack.
1023 try:
1024 parm_value = save_stack.pop(parm_name)
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -05001025 except BaseException:
Michael Walshff340002017-08-29 11:18:27 -05001026 # If it was not saved, no further action is required.
1027 continue
1028
1029 # Restore the saved value.
1030 cmd_buf = "BuiltIn().set_global_variable(\"${" + parm_name +\
1031 "}\", parm_value)"
1032 gp.dpissuing(cmd_buf)
1033 exec(cmd_buf)
1034
1035 gp.dprintn(save_stack.sprint_obj())
1036
Michael Walsh6741f742017-02-20 16:16:38 -06001037
Michael Walshc9116812017-03-10 14:23:06 -06001038def test_teardown():
Michael Walshc9116812017-03-10 14:23:06 -06001039 r"""
1040 Clean up after this test case.
1041 """
1042
1043 gp.qprintn()
Michael Walshf75d4352019-12-05 17:01:20 -06001044 gp.qprint_executing()
1045
1046 if ga.psutil_imported:
1047 ga.terminate_descendants()
1048
Michael Walshc9116812017-03-10 14:23:06 -06001049 cmd_buf = ["Print Error",
1050 "A keyword timeout occurred ending this program.\n"]
1051 BuiltIn().run_keyword_if_timeout_occurred(*cmd_buf)
1052
George Keishinga54e06f2020-06-12 10:42:41 -05001053 if redfish_supported:
1054 redfish.logout()
1055
Michael Walshc108e422019-03-28 12:27:18 -05001056 gp.qprint_pgm_footer()
Michael Walshb5839d02017-04-12 16:11:20 -05001057
Michael Walshc9116812017-03-10 14:23:06 -06001058
Michael Walsh89de14a2018-10-01 16:51:37 -05001059def post_stack():
1060 r"""
1061 Process post_stack plug-in programs.
1062 """
1063
1064 if not call_post_stack_plug:
1065 # The caller does not wish to have post_stack plug-in processing done.
1066 return
1067
1068 global boot_success
1069
1070 # NOTE: A post_stack call-point failure is NOT counted as a boot failure.
1071 pre_boot_plug_in_setup()
1072 # For the purposes of the following plug-ins, mark the "boot" as a success.
1073 boot_success = 1
1074 plug_in_setup()
Michael Walsh815b1d52018-10-30 13:32:26 -05001075 rc, shell_rc, failed_plug_in_name, history =\
1076 grpi.rprocess_plug_in_packages(call_point='post_stack',
1077 stop_on_plug_in_failure=0,
1078 return_history=True)
Michael Walsh986d8ae2019-07-17 10:02:23 -05001079 for doing_msg in history:
1080 update_boot_history(boot_history, doing_msg, max_boot_history)
Michael Walsh815b1d52018-10-30 13:32:26 -05001081 if rc != 0:
1082 boot_success = 0
Michael Walsh89de14a2018-10-01 16:51:37 -05001083
1084 plug_in_setup()
Michael Walsh815b1d52018-10-30 13:32:26 -05001085 rc, shell_rc, failed_plug_in_name =\
1086 grpi.rprocess_plug_in_packages(call_point='ffdc_check',
1087 shell_rc=dump_ffdc_rc(),
1088 stop_on_plug_in_failure=1,
1089 stop_on_non_zero_rc=1)
1090 if shell_rc == dump_ffdc_rc():
Michael Walsh89de14a2018-10-01 16:51:37 -05001091 status, ret_values = grk.run_key_u("my_ffdc", ignore=1)
1092 if status != 'PASS':
1093 gp.qprint_error("Call to my_ffdc failed.\n")
Michael Walshc9bd2e82019-04-18 11:06:52 -05001094 # Leave a record for caller that "soft" errors occurred.
1095 soft_errors = 1
1096 gpu.save_plug_in_value(soft_errors, pgm_name)
Michael Walsh89de14a2018-10-01 16:51:37 -05001097
1098 plug_in_setup()
1099 rc, shell_rc, failed_plug_in_name = grpi.rprocess_plug_in_packages(
1100 call_point='stop_check', shell_rc=stop_test_rc(),
1101 stop_on_non_zero_rc=1)
1102 if shell_rc == stop_test_rc():
1103 message = "Stopping as requested by user.\n"
Michael Walsh80dddde2019-10-22 13:54:38 -05001104 gp.qprint_time(message)
Michael Walsh89de14a2018-10-01 16:51:37 -05001105 BuiltIn().fail(message)
1106
1107
Michael Walshff340002017-08-29 11:18:27 -05001108def obmc_boot_test_py(loc_boot_stack=None,
1109 loc_stack_mode=None,
1110 loc_quiet=None):
Michael Walsh6741f742017-02-20 16:16:38 -06001111 r"""
1112 Do main program processing.
1113 """
1114
Michael Walshff340002017-08-29 11:18:27 -05001115 global save_stack
1116
Michael Walshf75d4352019-12-05 17:01:20 -06001117 ga.set_term_options(term_requests={'pgm_names': ['process_plug_in_packages.py']})
1118
George Keishing36efbc02018-12-12 10:18:23 -06001119 gp.dprintn()
Michael Walshff340002017-08-29 11:18:27 -05001120 # Process function parms.
1121 for parm_name in main_func_parm_list:
1122 # Get parm's value.
George Keishing36efbc02018-12-12 10:18:23 -06001123 parm_value = eval("loc_" + parm_name)
1124 gp.dpvars(parm_name, parm_value)
Michael Walshff340002017-08-29 11:18:27 -05001125
George Keishing36efbc02018-12-12 10:18:23 -06001126 if parm_value is not None:
Michael Walshff340002017-08-29 11:18:27 -05001127 # Save the global value on a stack.
1128 cmd_buf = "save_stack.push(BuiltIn().get_variable_value(\"${" +\
1129 parm_name + "}\"), \"" + parm_name + "\")"
1130 gp.dpissuing(cmd_buf)
1131 exec(cmd_buf)
1132
1133 # Set the global value to the passed value.
1134 cmd_buf = "BuiltIn().set_global_variable(\"${" + parm_name +\
1135 "}\", loc_" + parm_name + ")"
1136 gp.dpissuing(cmd_buf)
1137 exec(cmd_buf)
1138
1139 gp.dprintn(save_stack.sprint_obj())
Michael Walshb5839d02017-04-12 16:11:20 -05001140
Michael Walsh6741f742017-02-20 16:16:38 -06001141 setup()
1142
Michael Walshcd9fbfd2017-09-19 12:00:08 -05001143 init_boot_pass, init_boot_fail = boot_results.return_total_pass_fail()
1144
Michael Walsha20da402017-03-31 16:27:45 -05001145 if ffdc_only:
1146 gp.qprint_timen("Caller requested ffdc_only.")
Michael Walsh986d8ae2019-07-17 10:02:23 -05001147 if do_pre_boot_plug_in_setup:
1148 pre_boot_plug_in_setup()
Michael Walsh83f4bc72017-04-20 16:49:43 -05001149 grk.run_key_u("my_ffdc")
Michael Walsh764d2f82017-04-27 16:01:08 -05001150 return
Michael Walsha20da402017-03-31 16:27:45 -05001151
Michael Walsh409ad352020-02-06 11:46:35 -06001152 if delete_errlogs:
Michael Shepos1a67b082020-08-28 16:01:58 -05001153 # print error logs before delete
1154 status, error_logs = grk.run_key_u("Get Error Logs")
1155 pels = pel.peltool("-l", ignore_err=1)
1156 gp.qprint_vars(error_logs, pels)
1157
Michael Walsh409ad352020-02-06 11:46:35 -06001158 # Delete errlogs prior to doing any boot tests.
1159 grk.run_key(delete_errlogs_cmd, ignore=1)
1160
Michael Walsh6741f742017-02-20 16:16:38 -06001161 # Process caller's boot_stack.
1162 while (len(boot_stack) > 0):
1163 test_loop_body()
1164
Michael Walshb5839d02017-04-12 16:11:20 -05001165 gp.qprint_timen("Finished processing stack.")
Michael Walsh30dadae2017-02-27 14:25:52 -06001166
Michael Walsh89de14a2018-10-01 16:51:37 -05001167 post_stack()
1168
Michael Walsh6741f742017-02-20 16:16:38 -06001169 # Process caller's boot_list.
1170 if len(boot_list) > 0:
1171 for ix in range(1, max_num_tests + 1):
1172 test_loop_body()
1173
Michael Walshb5839d02017-04-12 16:11:20 -05001174 gp.qprint_timen("Completed all requested boot tests.")
1175
1176 boot_pass, boot_fail = boot_results.return_total_pass_fail()
Michael Walshcd9fbfd2017-09-19 12:00:08 -05001177 new_fail = boot_fail - init_boot_fail
1178 if new_fail > boot_fail_threshold:
Michael Walshb5839d02017-04-12 16:11:20 -05001179 error_message = "Boot failures exceed the boot failure" +\
1180 " threshold:\n" +\
Michael Walshcd9fbfd2017-09-19 12:00:08 -05001181 gp.sprint_var(new_fail) +\
Michael Walshb5839d02017-04-12 16:11:20 -05001182 gp.sprint_var(boot_fail_threshold)
1183 BuiltIn().fail(gp.sprint_error(error_message))