blob: f9e1a9276c295bb7f69315490398edd2ee64dedb [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",
George Keishinga54e06f2020-06-12 10:42:41 -0500270 "ffdc_summary_list_path", "execdir", "redfish_supported"]
Michael Walsh85678942017-03-27 14:34:22 -0500271
272 plug_in_vars = parm_list + additional_values
273
274 for var_name in plug_in_vars:
275 var_value = BuiltIn().get_variable_value("${" + var_name + "}")
276 var_name = var_name.upper()
277 if var_value is None:
278 var_value = ""
279 os.environ["AUTOBOOT_" + var_name] = str(var_value)
280
281 BuiltIn().set_log_level(LOG_LEVEL)
282
Michael Walsh68a61162017-04-25 11:54:06 -0500283 # Make sure the ffdc list directory exists.
284 ffdc_list_dir_path = os.path.dirname(ffdc_list_file_path) + os.sep
285 if not os.path.exists(ffdc_list_dir_path):
286 os.makedirs(ffdc_list_dir_path)
Michael Walsh85678942017-03-27 14:34:22 -0500287
Michael Walsh85678942017-03-27 14:34:22 -0500288
Michael Walsh0bbd8602016-11-22 11:31:49 -0600289def plug_in_setup():
Michael Walsh0bbd8602016-11-22 11:31:49 -0600290 r"""
Michael Walsh85678942017-03-27 14:34:22 -0500291 Initialize all changing plug-in environment variables for use by the
292 plug-in programs.
Michael Walsh0bbd8602016-11-22 11:31:49 -0600293 """
294
Michael Walsh85678942017-03-27 14:34:22 -0500295 global LOG_LEVEL
296 global test_really_running
297
298 BuiltIn().set_log_level("NONE")
299
Michael Walsh6741f742017-02-20 16:16:38 -0600300 boot_pass, boot_fail = boot_results.return_total_pass_fail()
Michael Walsh0bbd8602016-11-22 11:31:49 -0600301 if boot_pass > 1:
302 test_really_running = 1
303 else:
304 test_really_running = 0
305
Michael Walsh6741f742017-02-20 16:16:38 -0600306 BuiltIn().set_global_variable("${test_really_running}",
307 test_really_running)
308 BuiltIn().set_global_variable("${boot_type_desc}", next_boot)
Michael Walsh6741f742017-02-20 16:16:38 -0600309 BuiltIn().set_global_variable("${boot_pass}", boot_pass)
310 BuiltIn().set_global_variable("${boot_fail}", boot_fail)
311 BuiltIn().set_global_variable("${boot_success}", boot_success)
312 BuiltIn().set_global_variable("${ffdc_prefix}", ffdc_prefix)
Sunil M325eb542017-08-10 07:09:43 -0500313 BuiltIn().set_global_variable("${boot_start_time}", boot_start_time)
314 BuiltIn().set_global_variable("${boot_end_time}", boot_end_time)
Michael Walsh4c9a6452016-12-13 16:03:11 -0600315
Michael Walsh0bbd8602016-11-22 11:31:49 -0600316 # For each program parameter, set the corresponding AUTOBOOT_ environment
317 # variable value. Also, set an AUTOBOOT_ environment variable for every
318 # element in additional_values.
319 additional_values = ["boot_type_desc", "boot_success", "boot_pass",
Sunil M325eb542017-08-10 07:09:43 -0500320 "boot_fail", "test_really_running", "ffdc_prefix",
321 "boot_start_time", "boot_end_time"]
Michael Walsh0bbd8602016-11-22 11:31:49 -0600322
Michael Walsh85678942017-03-27 14:34:22 -0500323 plug_in_vars = additional_values
Michael Walsh0bbd8602016-11-22 11:31:49 -0600324
325 for var_name in plug_in_vars:
326 var_value = BuiltIn().get_variable_value("${" + var_name + "}")
327 var_name = var_name.upper()
328 if var_value is None:
329 var_value = ""
Michael Walsh6741f742017-02-20 16:16:38 -0600330 os.environ["AUTOBOOT_" + var_name] = str(var_value)
Michael Walsh0bbd8602016-11-22 11:31:49 -0600331
Michael Walsh0bbd8602016-11-22 11:31:49 -0600332 if debug:
Michael Walsh6741f742017-02-20 16:16:38 -0600333 shell_rc, out_buf = \
334 gc.cmd_fnc_u("printenv | egrep AUTOBOOT_ | sort -u")
Michael Walsh0bbd8602016-11-22 11:31:49 -0600335
Michael Walsh85678942017-03-27 14:34:22 -0500336 BuiltIn().set_log_level(LOG_LEVEL)
337
Michael Walsh0bbd8602016-11-22 11:31:49 -0600338
Michael Walshe0cf8d72017-05-17 13:20:46 -0500339def pre_boot_plug_in_setup():
340
341 # Clear the ffdc_list_file_path file. Plug-ins may now write to it.
342 try:
343 os.remove(ffdc_list_file_path)
344 except OSError:
345 pass
346
347 # Clear the ffdc_report_list_path file. Plug-ins may now write to it.
348 try:
349 os.remove(ffdc_report_list_path)
350 except OSError:
351 pass
352
Michael Walsh600876d2017-05-30 17:58:58 -0500353 # Clear the ffdc_summary_list_path file. Plug-ins may now write to it.
354 try:
355 os.remove(ffdc_summary_list_path)
356 except OSError:
357 pass
358
Michael Walshe1974b92017-08-03 13:39:51 -0500359 global ffdc_prefix
360
361 seconds = time.time()
362 loc_time = time.localtime(seconds)
363 time_string = time.strftime("%y%m%d.%H%M%S.", loc_time)
364
365 ffdc_prefix = openbmc_nickname + "." + time_string
366
Michael Walshe0cf8d72017-05-17 13:20:46 -0500367
Michael Walshf566fb12019-02-01 14:35:09 -0600368def default_sigusr1(signal_number=0,
369 frame=None):
370 r"""
371 Handle SIGUSR1 by doing nothing.
372
373 This function assists in debugging SIGUSR1 processing by printing messages
374 to stdout and to the log.html file.
375
376 Description of argument(s):
377 signal_number The signal number (should always be 10 for SIGUSR1).
378 frame The frame data.
379 """
380
Michael Walsh80dddde2019-10-22 13:54:38 -0500381 gp.qprintn()
382 gp.qprint_executing()
Michael Walshf566fb12019-02-01 14:35:09 -0600383 gp.lprint_executing()
384
385
386def set_default_siguser1():
387 r"""
388 Set the default_sigusr1 function to be the SIGUSR1 handler.
389 """
390
Michael Walsh80dddde2019-10-22 13:54:38 -0500391 gp.qprintn()
392 gp.qprint_executing()
Michael Walshf566fb12019-02-01 14:35:09 -0600393 gp.lprint_executing()
394 signal.signal(signal.SIGUSR1, default_sigusr1)
395
396
Michael Walsh6741f742017-02-20 16:16:38 -0600397def setup():
Michael Walsh0bbd8602016-11-22 11:31:49 -0600398 r"""
Michael Walsh6741f742017-02-20 16:16:38 -0600399 Do general program setup tasks.
Michael Walsh0bbd8602016-11-22 11:31:49 -0600400 """
401
Michael Walsh6741f742017-02-20 16:16:38 -0600402 global cp_setup_called
Michael Walsh81816742017-09-27 11:02:29 -0500403 global transitional_boot_selected
Michael Walsh0bbd8602016-11-22 11:31:49 -0600404
Michael Walshb5839d02017-04-12 16:11:20 -0500405 gp.qprintn()
406
George Keishinga54e06f2020-06-12 10:42:41 -0500407 if redfish_supported:
408 redfish.login()
409
Michael Walshf566fb12019-02-01 14:35:09 -0600410 set_default_siguser1()
Michael Walsh81816742017-09-27 11:02:29 -0500411 transitional_boot_selected = False
412
Michael Walsh83f4bc72017-04-20 16:49:43 -0500413 robot_pgm_dir_path = os.path.dirname(__file__) + os.sep
414 repo_bin_path = robot_pgm_dir_path.replace("/lib/", "/bin/")
Michael Walshd061c042017-05-23 14:46:57 -0500415 # If we can't find process_plug_in_packages.py, ssh_pw or
416 # validate_plug_ins.py, then we don't have our repo bin in PATH.
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -0500417 shell_rc, out_buf = gc.cmd_fnc_u("which process_plug_in_packages.py"
418 + " ssh_pw validate_plug_ins.py", quiet=1,
Michael Walshd061c042017-05-23 14:46:57 -0500419 print_output=0, show_err=0)
Michael Walshb5839d02017-04-12 16:11:20 -0500420 if shell_rc != 0:
Michael Walsh83f4bc72017-04-20 16:49:43 -0500421 os.environ['PATH'] = repo_bin_path + ":" + os.environ.get('PATH', "")
422 # Likewise, our repo lib subdir needs to be in sys.path and PYTHONPATH.
423 if robot_pgm_dir_path not in sys.path:
424 sys.path.append(robot_pgm_dir_path)
425 PYTHONPATH = os.environ.get("PYTHONPATH", "")
426 if PYTHONPATH == "":
427 os.environ['PYTHONPATH'] = robot_pgm_dir_path
428 else:
429 os.environ['PYTHONPATH'] = robot_pgm_dir_path + ":" + PYTHONPATH
Michael Walsh6741f742017-02-20 16:16:38 -0600430
431 validate_parms()
432
Michael Walshc108e422019-03-28 12:27:18 -0500433 gp.qprint_pgm_header()
Michael Walsh6741f742017-02-20 16:16:38 -0600434
George Keishinga54e06f2020-06-12 10:42:41 -0500435 grk.run_key_u(default_set_power_policy)
Michael Walsh11cfc8c2017-03-31 09:40:55 -0500436
Michael Walsh85678942017-03-27 14:34:22 -0500437 initial_plug_in_setup()
438
Michael Walsh6741f742017-02-20 16:16:38 -0600439 plug_in_setup()
440 rc, shell_rc, failed_plug_in_name = grpi.rprocess_plug_in_packages(
441 call_point='setup')
442 if rc != 0:
443 error_message = "Plug-in setup failed.\n"
Michael Walshc108e422019-03-28 12:27:18 -0500444 gp.print_error_report(error_message)
Michael Walsh6741f742017-02-20 16:16:38 -0600445 BuiltIn().fail(error_message)
446 # Setting cp_setup_called lets our Teardown know that it needs to call
447 # the cleanup plug-in call point.
448 cp_setup_called = 1
449
450 # Keyword "FFDC" will fail if TEST_MESSAGE is not set.
451 BuiltIn().set_global_variable("${TEST_MESSAGE}", "${EMPTY}")
Michael Walsh85678942017-03-27 14:34:22 -0500452 # FFDC_LOG_PATH is used by "FFDC" keyword.
453 BuiltIn().set_global_variable("${FFDC_LOG_PATH}", ffdc_dir_path)
Michael Walsh6741f742017-02-20 16:16:38 -0600454
Michael Walshdc80d672017-05-09 12:58:32 -0500455 # Also printed by FFDC.
456 global host_name
457 global host_ip
458 host = socket.gethostname()
459 host_name, host_ip = gm.get_host_name_ip(host)
460
Michael Walsh986d8ae2019-07-17 10:02:23 -0500461 gp.dprint_var(boot_table)
Michael Walshb5839d02017-04-12 16:11:20 -0500462 gp.dprint_var(boot_lists)
Michael Walsh0bbd8602016-11-22 11:31:49 -0600463
Michael Walsh0bbd8602016-11-22 11:31:49 -0600464
Michael Walsh6741f742017-02-20 16:16:38 -0600465def validate_parms():
Michael Walsh0bbd8602016-11-22 11:31:49 -0600466 r"""
Michael Walsh6741f742017-02-20 16:16:38 -0600467 Validate all program parameters.
Michael Walsh0bbd8602016-11-22 11:31:49 -0600468 """
469
Michael Walshb5839d02017-04-12 16:11:20 -0500470 process_pgm_parms()
Michael Walsh0bbd8602016-11-22 11:31:49 -0600471
Michael Walshb5839d02017-04-12 16:11:20 -0500472 gp.qprintn()
473
474 global openbmc_model
Michael Walshf5ce38c2020-02-27 12:46:20 -0600475 if openbmc_model == "":
476 status, ret_values =\
477 grk.run_key_u("Get BMC System Model")
478 openbmc_model = ret_values
479 BuiltIn().set_global_variable("${openbmc_model}", openbmc_model)
480 gv.set_exit_on_error(True)
Michael Walsh44cef252019-08-01 12:38:56 -0500481 gv.valid_value(openbmc_host)
482 gv.valid_value(openbmc_username)
483 gv.valid_value(openbmc_password)
484 gv.valid_value(rest_username)
485 gv.valid_value(rest_password)
486 gv.valid_value(ipmi_username)
487 gv.valid_value(ipmi_password)
Michael Walsh6741f742017-02-20 16:16:38 -0600488 if os_host != "":
Michael Walsh44cef252019-08-01 12:38:56 -0500489 gv.valid_value(os_username)
490 gv.valid_value(os_password)
Michael Walsh6741f742017-02-20 16:16:38 -0600491 if pdu_host != "":
Michael Walsh44cef252019-08-01 12:38:56 -0500492 gv.valid_value(pdu_username)
493 gv.valid_value(pdu_password)
494 gv.valid_integer(pdu_slot_no)
Michael Walsh6741f742017-02-20 16:16:38 -0600495 if openbmc_serial_host != "":
Michael Walsh44cef252019-08-01 12:38:56 -0500496 gv.valid_integer(openbmc_serial_port)
Michael Walsh44cef252019-08-01 12:38:56 -0500497 gv.valid_value(openbmc_model)
498 gv.valid_integer(max_num_tests)
499 gv.valid_integer(boot_pass)
500 gv.valid_integer(boot_fail)
Michael Walsh6741f742017-02-20 16:16:38 -0600501 plug_in_packages_list = grpi.rvalidate_plug_ins(plug_in_dir_paths)
502 BuiltIn().set_global_variable("${plug_in_packages_list}",
503 plug_in_packages_list)
Michael Walsh44cef252019-08-01 12:38:56 -0500504 gv.valid_value(stack_mode, valid_values=['normal', 'skip'])
Michael Walshf5ce38c2020-02-27 12:46:20 -0600505 gv.set_exit_on_error(False)
Michael Walsha20da402017-03-31 16:27:45 -0500506 if len(boot_list) == 0 and len(boot_stack) == 0 and not ffdc_only:
Michael Walsh6741f742017-02-20 16:16:38 -0600507 error_message = "You must provide either a value for either the" +\
508 " boot_list or the boot_stack parm.\n"
509 BuiltIn().fail(gp.sprint_error(error_message))
Michael Walsh6741f742017-02-20 16:16:38 -0600510 valid_boot_list(boot_list, valid_boot_types)
511 valid_boot_list(boot_stack, valid_boot_types)
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -0500512 selected_PDU_boots = list(set(boot_list + boot_stack)
513 & set(boot_lists['PDU_reboot']))
Michael Walsh11cfc8c2017-03-31 09:40:55 -0500514 if len(selected_PDU_boots) > 0 and pdu_host == "":
515 error_message = "You have selected the following boots which" +\
516 " require a PDU host but no value for pdu_host:\n"
517 error_message += gp.sprint_var(selected_PDU_boots)
Michael Walsh986d8ae2019-07-17 10:02:23 -0500518 error_message += gp.sprint_var(pdu_host, fmt=gp.blank())
Michael Walsh11cfc8c2017-03-31 09:40:55 -0500519 BuiltIn().fail(gp.sprint_error(error_message))
520
Michael Walsh6741f742017-02-20 16:16:38 -0600521 return
Michael Walsh0bbd8602016-11-22 11:31:49 -0600522
Michael Walsh0bbd8602016-11-22 11:31:49 -0600523
Michael Walsh6741f742017-02-20 16:16:38 -0600524def my_get_state():
Michael Walsh0bbd8602016-11-22 11:31:49 -0600525 r"""
Michael Walsh6741f742017-02-20 16:16:38 -0600526 Get the system state plus a little bit of wrapping.
Michael Walsh0bbd8602016-11-22 11:31:49 -0600527 """
528
Michael Walsh6741f742017-02-20 16:16:38 -0600529 global state
530
531 req_states = ['epoch_seconds'] + st.default_req_states
532
Michael Walshb5839d02017-04-12 16:11:20 -0500533 gp.qprint_timen("Getting system state.")
Michael Walsh6741f742017-02-20 16:16:38 -0600534 if test_mode:
535 state['epoch_seconds'] = int(time.time())
536 else:
Michael Walshb5839d02017-04-12 16:11:20 -0500537 state = st.get_state(req_states=req_states, quiet=quiet)
538 gp.qprint_var(state)
Michael Walsh341c21e2017-01-17 16:25:20 -0600539
Michael Walsh341c21e2017-01-17 16:25:20 -0600540
Michael Walsh45ca6e42017-09-14 17:29:12 -0500541def valid_state():
Michael Walsh45ca6e42017-09-14 17:29:12 -0500542 r"""
543 Verify that our state dictionary contains no blank values. If we don't get
544 valid state data, we cannot continue to work.
545 """
546
547 if st.compare_states(state, st.invalid_state_match, 'or'):
548 error_message = "The state dictionary contains blank fields which" +\
549 " is illegal.\n" + gp.sprint_var(state)
550 BuiltIn().fail(gp.sprint_error(error_message))
551
Michael Walsh45ca6e42017-09-14 17:29:12 -0500552
Michael Walsh6741f742017-02-20 16:16:38 -0600553def select_boot():
Michael Walsh341c21e2017-01-17 16:25:20 -0600554 r"""
555 Select a boot test to be run based on our current state and return the
556 chosen boot type.
557
558 Description of arguments:
Michael Walsh6741f742017-02-20 16:16:38 -0600559 state The state of the machine.
Michael Walsh341c21e2017-01-17 16:25:20 -0600560 """
561
Michael Walsh81816742017-09-27 11:02:29 -0500562 global transitional_boot_selected
Michael Walsh30dadae2017-02-27 14:25:52 -0600563 global boot_stack
564
Michael Walshb5839d02017-04-12 16:11:20 -0500565 gp.qprint_timen("Selecting a boot test.")
Michael Walsh6741f742017-02-20 16:16:38 -0600566
Michael Walsh81816742017-09-27 11:02:29 -0500567 if transitional_boot_selected and not boot_success:
568 prior_boot = next_boot
569 boot_candidate = boot_stack.pop()
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -0500570 gp.qprint_timen("The prior '" + next_boot + "' was chosen to"
571 + " transition to a valid state for '" + boot_candidate
572 + "' which was at the top of the boot_stack. Since"
573 + " the '" + next_boot + "' failed, the '"
574 + boot_candidate + "' has been removed from the stack"
575 + " to avoid and endless failure loop.")
Michael Walsh81816742017-09-27 11:02:29 -0500576 if len(boot_stack) == 0:
577 return ""
578
Michael Walsh6741f742017-02-20 16:16:38 -0600579 my_get_state()
Michael Walsh45ca6e42017-09-14 17:29:12 -0500580 valid_state()
Michael Walsh6741f742017-02-20 16:16:38 -0600581
Michael Walsh81816742017-09-27 11:02:29 -0500582 transitional_boot_selected = False
Michael Walsh6741f742017-02-20 16:16:38 -0600583 stack_popped = 0
584 if len(boot_stack) > 0:
585 stack_popped = 1
Michael Walshb5839d02017-04-12 16:11:20 -0500586 gp.qprint_dashes()
587 gp.qprint_var(boot_stack)
588 gp.qprint_dashes()
589 skip_boot_printed = 0
590 while len(boot_stack) > 0:
591 boot_candidate = boot_stack.pop()
592 if stack_mode == 'normal':
593 break
594 else:
595 if st.compare_states(state, boot_table[boot_candidate]['end']):
596 if not skip_boot_printed:
Michael Walshff340002017-08-29 11:18:27 -0500597 gp.qprint_var(stack_mode)
598 gp.qprintn()
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -0500599 gp.qprint_timen("Skipping the following boot tests"
600 + " which are unnecessary since their"
601 + " required end states match the"
602 + " current machine state:")
Michael Walshb5839d02017-04-12 16:11:20 -0500603 skip_boot_printed = 1
Michael Walshff340002017-08-29 11:18:27 -0500604 gp.qprint_var(boot_candidate)
Michael Walshb5839d02017-04-12 16:11:20 -0500605 boot_candidate = ""
606 if boot_candidate == "":
607 gp.qprint_dashes()
608 gp.qprint_var(boot_stack)
609 gp.qprint_dashes()
610 return boot_candidate
Michael Walsh6741f742017-02-20 16:16:38 -0600611 if st.compare_states(state, boot_table[boot_candidate]['start']):
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -0500612 gp.qprint_timen("The machine state is valid for a '"
613 + boot_candidate + "' boot test.")
Michael Walshb5839d02017-04-12 16:11:20 -0500614 gp.qprint_dashes()
615 gp.qprint_var(boot_stack)
616 gp.qprint_dashes()
Michael Walsh6741f742017-02-20 16:16:38 -0600617 return boot_candidate
Michael Walsh341c21e2017-01-17 16:25:20 -0600618 else:
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -0500619 gp.qprint_timen("The machine state does not match the required"
620 + " starting state for a '" + boot_candidate
621 + "' boot test:")
Michael Walsh986d8ae2019-07-17 10:02:23 -0500622 gp.qprint_varx("boot_table_start_entry",
623 boot_table[boot_candidate]['start'])
Michael Walsh6741f742017-02-20 16:16:38 -0600624 boot_stack.append(boot_candidate)
Michael Walsh81816742017-09-27 11:02:29 -0500625 transitional_boot_selected = True
Michael Walsh6741f742017-02-20 16:16:38 -0600626 popped_boot = boot_candidate
627
628 # Loop through your list selecting a boot_candidates
629 boot_candidates = []
630 for boot_candidate in boot_list:
631 if st.compare_states(state, boot_table[boot_candidate]['start']):
632 if stack_popped:
633 if st.compare_states(boot_table[boot_candidate]['end'],
Gunnar Mills096cd562018-03-26 10:19:12 -0500634 boot_table[popped_boot]['start']):
Michael Walsh6741f742017-02-20 16:16:38 -0600635 boot_candidates.append(boot_candidate)
636 else:
637 boot_candidates.append(boot_candidate)
638
639 if len(boot_candidates) == 0:
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -0500640 gp.qprint_timen("The user's boot list contained no boot tests"
641 + " which are valid for the current machine state.")
Michael Walsh6741f742017-02-20 16:16:38 -0600642 boot_candidate = default_power_on
643 if not st.compare_states(state, boot_table[default_power_on]['start']):
644 boot_candidate = default_power_off
645 boot_candidates.append(boot_candidate)
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -0500646 gp.qprint_timen("Using default '" + boot_candidate
647 + "' boot type to transition to valid state.")
Michael Walsh6741f742017-02-20 16:16:38 -0600648
Michael Walshb5839d02017-04-12 16:11:20 -0500649 gp.dprint_var(boot_candidates)
Michael Walsh6741f742017-02-20 16:16:38 -0600650
651 # Randomly select a boot from the candidate list.
652 boot = random.choice(boot_candidates)
Michael Walsh341c21e2017-01-17 16:25:20 -0600653
654 return boot
Michael Walsh0bbd8602016-11-22 11:31:49 -0600655
Michael Walsh55302292017-01-10 11:43:02 -0600656
Michael Walshb2e53ec2017-10-30 15:04:36 -0500657def print_defect_report(ffdc_file_list):
Michael Walsh341c21e2017-01-17 16:25:20 -0600658 r"""
659 Print a defect report.
Michael Walshb2e53ec2017-10-30 15:04:36 -0500660
661 Description of argument(s):
662 ffdc_file_list A list of files which were collected by our ffdc functions.
Michael Walsh341c21e2017-01-17 16:25:20 -0600663 """
664
Michael Walsh600876d2017-05-30 17:58:58 -0500665 # Making deliberate choice to NOT run plug_in_setup(). We don't want
666 # ffdc_prefix updated.
667 rc, shell_rc, failed_plug_in_name = grpi.rprocess_plug_in_packages(
668 call_point='ffdc_report', stop_on_plug_in_failure=0)
669
Michael Walshe0cf8d72017-05-17 13:20:46 -0500670 # Get additional header data which may have been created by ffdc plug-ins.
671 # Also, delete the individual header files to cleanup.
672 cmd_buf = "file_list=$(cat " + ffdc_report_list_path + " 2>/dev/null)" +\
673 " ; [ ! -z \"${file_list}\" ] && cat ${file_list}" +\
674 " 2>/dev/null ; rm -rf ${file_list} 2>/dev/null || :"
675 shell_rc, more_header_info = gc.cmd_fnc_u(cmd_buf, print_output=0,
676 show_err=0)
677
Michael Walshb2e53ec2017-10-30 15:04:36 -0500678 # Get additional summary data which may have been created by ffdc plug-ins.
Michael Walsh600876d2017-05-30 17:58:58 -0500679 # Also, delete the individual header files to cleanup.
680 cmd_buf = "file_list=$(cat " + ffdc_summary_list_path + " 2>/dev/null)" +\
681 " ; [ ! -z \"${file_list}\" ] && cat ${file_list}" +\
682 " 2>/dev/null ; rm -rf ${file_list} 2>/dev/null || :"
683 shell_rc, ffdc_summary_info = gc.cmd_fnc_u(cmd_buf, print_output=0,
684 show_err=0)
685
Michael Walshb2e53ec2017-10-30 15:04:36 -0500686 # ffdc_list_file_path contains a list of any ffdc files created by plug-
687 # ins, etc. Read that data into a list.
Michael Walsh341c21e2017-01-17 16:25:20 -0600688 try:
Michael Walshb2e53ec2017-10-30 15:04:36 -0500689 plug_in_ffdc_list = \
690 open(ffdc_list_file_path, 'r').read().rstrip("\n").split("\n")
George Keishing36efbc02018-12-12 10:18:23 -0600691 plug_in_ffdc_list = list(filter(None, plug_in_ffdc_list))
Michael Walsh341c21e2017-01-17 16:25:20 -0600692 except IOError:
Michael Walshb2e53ec2017-10-30 15:04:36 -0500693 plug_in_ffdc_list = []
694
695 # Combine the files from plug_in_ffdc_list with the ffdc_file_list passed
696 # in. Eliminate duplicates and sort the list.
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -0500697 ffdc_file_list = sorted(set(ffdc_file_list + plug_in_ffdc_list))
Michael Walshb2e53ec2017-10-30 15:04:36 -0500698
699 if status_file_path != "":
700 ffdc_file_list.insert(0, status_file_path)
701
702 # Convert the list to a printable list.
703 printable_ffdc_file_list = "\n".join(ffdc_file_list)
Michael Walsh341c21e2017-01-17 16:25:20 -0600704
Michael Walsh68a61162017-04-25 11:54:06 -0500705 # Open ffdc_file_list for writing. We will write a complete list of
706 # FFDC files to it for possible use by plug-ins like cp_stop_check.
707 ffdc_list_file = open(ffdc_list_file_path, 'w')
Michael Walshb2e53ec2017-10-30 15:04:36 -0500708 ffdc_list_file.write(printable_ffdc_file_list + "\n")
709 ffdc_list_file.close()
710
711 indent = 0
712 width = 90
713 linefeed = 1
714 char = "="
Michael Walsh68a61162017-04-25 11:54:06 -0500715
716 gp.qprintn()
Michael Walshb2e53ec2017-10-30 15:04:36 -0500717 gp.qprint_dashes(indent, width, linefeed, char)
Michael Walsh68a61162017-04-25 11:54:06 -0500718 gp.qprintn("Copy this data to the defect:\n")
719
Michael Walshe0cf8d72017-05-17 13:20:46 -0500720 if len(more_header_info) > 0:
Michael Walshff340002017-08-29 11:18:27 -0500721 gp.qprintn(more_header_info)
Michael Walshdc80d672017-05-09 12:58:32 -0500722 gp.qpvars(host_name, host_ip, openbmc_nickname, openbmc_host,
723 openbmc_host_name, openbmc_ip, openbmc_username,
Michael Walsh0a3bdb42019-01-31 16:21:44 +0000724 openbmc_password, rest_username, rest_password, ipmi_username,
725 ipmi_password, os_host, os_host_name, os_ip, os_username,
Michael Walshdc80d672017-05-09 12:58:32 -0500726 os_password, pdu_host, pdu_host_name, pdu_ip, pdu_username,
727 pdu_password, pdu_slot_no, openbmc_serial_host,
728 openbmc_serial_host_name, openbmc_serial_ip, openbmc_serial_port)
Michael Walsh68a61162017-04-25 11:54:06 -0500729
730 gp.qprintn()
Michael Walsh986d8ae2019-07-17 10:02:23 -0500731 print_boot_history(boot_history)
Michael Walsh68a61162017-04-25 11:54:06 -0500732 gp.qprintn()
733 gp.qprint_var(state)
Michael Walshb5839d02017-04-12 16:11:20 -0500734 gp.qprintn()
735 gp.qprintn("FFDC data files:")
Michael Walshb2e53ec2017-10-30 15:04:36 -0500736 gp.qprintn(printable_ffdc_file_list)
Michael Walshb5839d02017-04-12 16:11:20 -0500737 gp.qprintn()
Michael Walsh341c21e2017-01-17 16:25:20 -0600738
Michael Walsh600876d2017-05-30 17:58:58 -0500739 if len(ffdc_summary_info) > 0:
Michael Walshff340002017-08-29 11:18:27 -0500740 gp.qprintn(ffdc_summary_info)
Michael Walsh600876d2017-05-30 17:58:58 -0500741
Michael Walshb2e53ec2017-10-30 15:04:36 -0500742 gp.qprint_dashes(indent, width, linefeed, char)
Michael Walsh68a61162017-04-25 11:54:06 -0500743
Michael Walsh6741f742017-02-20 16:16:38 -0600744
Michael Walsh6741f742017-02-20 16:16:38 -0600745def my_ffdc():
Michael Walsh6741f742017-02-20 16:16:38 -0600746 r"""
747 Collect FFDC data.
748 """
749
750 global state
751
752 plug_in_setup()
753 rc, shell_rc, failed_plug_in_name = grpi.rprocess_plug_in_packages(
Michael Walsh600876d2017-05-30 17:58:58 -0500754 call_point='ffdc', stop_on_plug_in_failure=0)
Michael Walsh6741f742017-02-20 16:16:38 -0600755
756 AUTOBOOT_FFDC_PREFIX = os.environ['AUTOBOOT_FFDC_PREFIX']
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -0500757 status, ffdc_file_list = grk.run_key_u("FFDC ffdc_prefix="
758 + AUTOBOOT_FFDC_PREFIX
759 + " ffdc_function_list="
760 + ffdc_function_list, ignore=1)
Michael Walsh83f4bc72017-04-20 16:49:43 -0500761 if status != 'PASS':
Michael Walshff340002017-08-29 11:18:27 -0500762 gp.qprint_error("Call to ffdc failed.\n")
Michael Walshc9bd2e82019-04-18 11:06:52 -0500763 if type(ffdc_file_list) is not list:
764 ffdc_file_list = []
765 # Leave a record for caller that "soft" errors occurred.
766 soft_errors = 1
767 gpu.save_plug_in_value(soft_errors, pgm_name)
Michael Walsh6741f742017-02-20 16:16:38 -0600768
769 my_get_state()
770
Michael Walshb2e53ec2017-10-30 15:04:36 -0500771 print_defect_report(ffdc_file_list)
Michael Walsh6741f742017-02-20 16:16:38 -0600772
Michael Walsh6741f742017-02-20 16:16:38 -0600773
Michael Walsh6741f742017-02-20 16:16:38 -0600774def print_test_start_message(boot_keyword):
Michael Walsh6741f742017-02-20 16:16:38 -0600775 r"""
776 Print a message indicating what boot test is about to run.
777
778 Description of arguments:
779 boot_keyword The name of the boot which is to be run
780 (e.g. "BMC Power On").
781 """
782
Michael Walsh986d8ae2019-07-17 10:02:23 -0500783 global boot_history
Sunil M325eb542017-08-10 07:09:43 -0500784 global boot_start_time
Michael Walsh6741f742017-02-20 16:16:38 -0600785
786 doing_msg = gp.sprint_timen("Doing \"" + boot_keyword + "\".")
Sunil M325eb542017-08-10 07:09:43 -0500787
788 # Set boot_start_time for use by plug-ins.
789 boot_start_time = doing_msg[1:33]
790 gp.qprint_var(boot_start_time)
791
Michael Walshb5839d02017-04-12 16:11:20 -0500792 gp.qprint(doing_msg)
Michael Walsh6741f742017-02-20 16:16:38 -0600793
Michael Walsh986d8ae2019-07-17 10:02:23 -0500794 update_boot_history(boot_history, doing_msg, max_boot_history)
Michael Walsh6741f742017-02-20 16:16:38 -0600795
Michael Walsh6741f742017-02-20 16:16:38 -0600796
Michael Walshf566fb12019-02-01 14:35:09 -0600797def stop_boot_test(signal_number=0,
798 frame=None):
799 r"""
800 Handle SIGUSR1 by aborting the boot test that is running.
801
802 Description of argument(s):
803 signal_number The signal number (should always be 10 for SIGUSR1).
804 frame The frame data.
805 """
806
Michael Walsh80dddde2019-10-22 13:54:38 -0500807 gp.qprintn()
808 gp.qprint_executing()
Michael Walshf566fb12019-02-01 14:35:09 -0600809 gp.lprint_executing()
810
811 # Restore original sigusr1 handler.
812 set_default_siguser1()
813
814 message = "The caller has asked that the boot test be stopped and marked"
815 message += " as a failure."
816
817 function_stack = gm.get_function_stack()
818 if "wait_state" in function_stack:
Michael Walshc44aa532019-06-14 13:33:29 -0500819 st.set_exit_wait_early_message(message)
Michael Walshf566fb12019-02-01 14:35:09 -0600820 else:
821 BuiltIn().fail(gp.sprint_error(message))
822
823
Michael Walsh6741f742017-02-20 16:16:38 -0600824def run_boot(boot):
Michael Walsh6741f742017-02-20 16:16:38 -0600825 r"""
826 Run the specified boot.
827
828 Description of arguments:
829 boot The name of the boot test to be performed.
830 """
831
832 global state
833
Michael Walshf566fb12019-02-01 14:35:09 -0600834 signal.signal(signal.SIGUSR1, stop_boot_test)
835 gp.qprint_timen("stop_boot_test is armed.")
836
Michael Walsh6741f742017-02-20 16:16:38 -0600837 print_test_start_message(boot)
838
839 plug_in_setup()
840 rc, shell_rc, failed_plug_in_name = \
841 grpi.rprocess_plug_in_packages(call_point="pre_boot")
842 if rc != 0:
843 error_message = "Plug-in failed with non-zero return code.\n" +\
Michael Walsh986d8ae2019-07-17 10:02:23 -0500844 gp.sprint_var(rc, fmt=gp.hexa())
Michael Walshf566fb12019-02-01 14:35:09 -0600845 set_default_siguser1()
Michael Walsh6741f742017-02-20 16:16:38 -0600846 BuiltIn().fail(gp.sprint_error(error_message))
847
848 if test_mode:
849 # In test mode, we'll pretend the boot worked by assigning its
850 # required end state to the default state value.
Michael Walsh30dadae2017-02-27 14:25:52 -0600851 state = st.strip_anchor_state(boot_table[boot]['end'])
Michael Walsh6741f742017-02-20 16:16:38 -0600852 else:
853 # Assertion: We trust that the state data was made fresh by the
854 # caller.
855
Michael Walshb5839d02017-04-12 16:11:20 -0500856 gp.qprintn()
Michael Walsh6741f742017-02-20 16:16:38 -0600857
858 if boot_table[boot]['method_type'] == "keyword":
Michael Walsh0b93fbf2017-03-02 14:42:41 -0600859 rk.my_run_keywords(boot_table[boot].get('lib_file_path', ''),
Michael Walshb5839d02017-04-12 16:11:20 -0500860 boot_table[boot]['method'],
861 quiet=quiet)
Michael Walsh6741f742017-02-20 16:16:38 -0600862
863 if boot_table[boot]['bmc_reboot']:
864 st.wait_for_comm_cycle(int(state['epoch_seconds']))
Michael Walsh30dadae2017-02-27 14:25:52 -0600865 plug_in_setup()
866 rc, shell_rc, failed_plug_in_name = \
867 grpi.rprocess_plug_in_packages(call_point="post_reboot")
868 if rc != 0:
Michael Walsh0b93fbf2017-03-02 14:42:41 -0600869 error_message = "Plug-in failed with non-zero return code.\n"
Michael Walsh986d8ae2019-07-17 10:02:23 -0500870 error_message += gp.sprint_var(rc, fmt=gp.hexa())
Michael Walshf566fb12019-02-01 14:35:09 -0600871 set_default_siguser1()
Michael Walsh30dadae2017-02-27 14:25:52 -0600872 BuiltIn().fail(gp.sprint_error(error_message))
Michael Walsh6741f742017-02-20 16:16:38 -0600873 else:
874 match_state = st.anchor_state(state)
875 del match_state['epoch_seconds']
876 # Wait for the state to change in any way.
877 st.wait_state(match_state, wait_time=state_change_timeout,
Michael Walsh600876d2017-05-30 17:58:58 -0500878 interval="10 seconds", invert=1)
Michael Walsh6741f742017-02-20 16:16:38 -0600879
Michael Walshb5839d02017-04-12 16:11:20 -0500880 gp.qprintn()
Michael Walsh6741f742017-02-20 16:16:38 -0600881 if boot_table[boot]['end']['chassis'] == "Off":
882 boot_timeout = power_off_timeout
883 else:
884 boot_timeout = power_on_timeout
885 st.wait_state(boot_table[boot]['end'], wait_time=boot_timeout,
Michael Walsh600876d2017-05-30 17:58:58 -0500886 interval="10 seconds")
Michael Walsh6741f742017-02-20 16:16:38 -0600887
888 plug_in_setup()
889 rc, shell_rc, failed_plug_in_name = \
890 grpi.rprocess_plug_in_packages(call_point="post_boot")
891 if rc != 0:
892 error_message = "Plug-in failed with non-zero return code.\n" +\
Michael Walsh986d8ae2019-07-17 10:02:23 -0500893 gp.sprint_var(rc, fmt=gp.hexa())
Michael Walshf566fb12019-02-01 14:35:09 -0600894 set_default_siguser1()
Michael Walsh6741f742017-02-20 16:16:38 -0600895 BuiltIn().fail(gp.sprint_error(error_message))
896
Michael Walshf566fb12019-02-01 14:35:09 -0600897 # Restore original sigusr1 handler.
898 set_default_siguser1()
899
Michael Walsh6741f742017-02-20 16:16:38 -0600900
Michael Walsh6741f742017-02-20 16:16:38 -0600901def test_loop_body():
Michael Walsh6741f742017-02-20 16:16:38 -0600902 r"""
903 The main loop body for the loop in main_py.
904
905 Description of arguments:
906 boot_count The iteration number (starts at 1).
907 """
908
909 global boot_count
910 global state
911 global next_boot
912 global boot_success
Sunil M325eb542017-08-10 07:09:43 -0500913 global boot_end_time
Michael Walsh6741f742017-02-20 16:16:38 -0600914
Michael Walshb5839d02017-04-12 16:11:20 -0500915 gp.qprintn()
Michael Walsh6741f742017-02-20 16:16:38 -0600916
917 next_boot = select_boot()
Michael Walshb5839d02017-04-12 16:11:20 -0500918 if next_boot == "":
919 return True
Michael Walsh6741f742017-02-20 16:16:38 -0600920
Michael Walshb5839d02017-04-12 16:11:20 -0500921 boot_count += 1
922 gp.qprint_timen("Starting boot " + str(boot_count) + ".")
Michael Walsh6741f742017-02-20 16:16:38 -0600923
Michael Walshe0cf8d72017-05-17 13:20:46 -0500924 pre_boot_plug_in_setup()
Michael Walsh6741f742017-02-20 16:16:38 -0600925
926 cmd_buf = ["run_boot", next_boot]
927 boot_status, msg = BuiltIn().run_keyword_and_ignore_error(*cmd_buf)
928 if boot_status == "FAIL":
Michael Walshb5839d02017-04-12 16:11:20 -0500929 gp.qprint(msg)
Michael Walsh6741f742017-02-20 16:16:38 -0600930
Michael Walshb5839d02017-04-12 16:11:20 -0500931 gp.qprintn()
Michael Walsh6741f742017-02-20 16:16:38 -0600932 if boot_status == "PASS":
933 boot_success = 1
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -0500934 completion_msg = gp.sprint_timen("BOOT_SUCCESS: \"" + next_boot
935 + "\" succeeded.")
Michael Walsh6741f742017-02-20 16:16:38 -0600936 else:
937 boot_success = 0
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -0500938 completion_msg = gp.sprint_timen("BOOT_FAILED: \"" + next_boot
939 + "\" failed.")
Sunil M325eb542017-08-10 07:09:43 -0500940
941 # Set boot_end_time for use by plug-ins.
942 boot_end_time = completion_msg[1:33]
943 gp.qprint_var(boot_end_time)
944
945 gp.qprint(completion_msg)
Michael Walsh6741f742017-02-20 16:16:38 -0600946
947 boot_results.update(next_boot, boot_status)
948
949 plug_in_setup()
950 # NOTE: A post_test_case call point failure is NOT counted as a boot
951 # failure.
952 rc, shell_rc, failed_plug_in_name = grpi.rprocess_plug_in_packages(
Michael Walsh600876d2017-05-30 17:58:58 -0500953 call_point='post_test_case', stop_on_plug_in_failure=0)
Michael Walsh6741f742017-02-20 16:16:38 -0600954
955 plug_in_setup()
956 rc, shell_rc, failed_plug_in_name = grpi.rprocess_plug_in_packages(
Michael Walsh89de14a2018-10-01 16:51:37 -0500957 call_point='ffdc_check', shell_rc=dump_ffdc_rc(),
Michael Walsh6741f742017-02-20 16:16:38 -0600958 stop_on_plug_in_failure=1, stop_on_non_zero_rc=1)
Michael Walsh12059e22019-03-21 11:03:45 -0500959 if ffdc_check == "All" or\
Michael Walsh89de14a2018-10-01 16:51:37 -0500960 shell_rc == dump_ffdc_rc():
Michael Walsh83f4bc72017-04-20 16:49:43 -0500961 status, ret_values = grk.run_key_u("my_ffdc", ignore=1)
962 if status != 'PASS':
Michael Walshff340002017-08-29 11:18:27 -0500963 gp.qprint_error("Call to my_ffdc failed.\n")
Michael Walshc9bd2e82019-04-18 11:06:52 -0500964 # Leave a record for caller that "soft" errors occurred.
965 soft_errors = 1
966 gpu.save_plug_in_value(soft_errors, pgm_name)
Michael Walsh6741f742017-02-20 16:16:38 -0600967
Michael Walshaabef1e2017-09-20 15:16:17 -0500968 if delete_errlogs:
Michael Shepos1a67b082020-08-28 16:01:58 -0500969 # print error logs before delete
970 status, error_logs = grk.run_key_u("Get Error Logs")
971 pels = pel.peltool("-l", ignore_err=1)
972 gp.qprint_vars(error_logs, pels)
973
Michael Walshaabef1e2017-09-20 15:16:17 -0500974 # We need to purge error logs between boots or they build up.
Michael Walsh409ad352020-02-06 11:46:35 -0600975 grk.run_key(delete_errlogs_cmd, ignore=1)
Michael Walshd139f282017-04-04 18:00:23 -0500976
Michael Walsh952f9b02017-03-09 13:11:14 -0600977 boot_results.print_report()
Michael Walshb5839d02017-04-12 16:11:20 -0500978 gp.qprint_timen("Finished boot " + str(boot_count) + ".")
Michael Walsh952f9b02017-03-09 13:11:14 -0600979
Michael Walsh6741f742017-02-20 16:16:38 -0600980 plug_in_setup()
981 rc, shell_rc, failed_plug_in_name = grpi.rprocess_plug_in_packages(
Michael Walsh89de14a2018-10-01 16:51:37 -0500982 call_point='stop_check', shell_rc=stop_test_rc(),
983 stop_on_non_zero_rc=1)
984 if shell_rc == stop_test_rc():
Michael Walsh3ba8ecd2018-04-24 11:33:25 -0500985 message = "Stopping as requested by user.\n"
Michael Walsh80dddde2019-10-22 13:54:38 -0500986 gp.qprint_time(message)
Michael Walsh3ba8ecd2018-04-24 11:33:25 -0500987 BuiltIn().fail(message)
Michael Walsh6741f742017-02-20 16:16:38 -0600988
Michael Walshd139f282017-04-04 18:00:23 -0500989 # This should help prevent ConnectionErrors.
Michael Walsh0960b382017-06-22 16:23:37 -0500990 grk.run_key_u("Close All Connections")
Michael Walshd139f282017-04-04 18:00:23 -0500991
Michael Walsh6741f742017-02-20 16:16:38 -0600992 return True
993
Michael Walsh6741f742017-02-20 16:16:38 -0600994
Michael Walsh83f4bc72017-04-20 16:49:43 -0500995def obmc_boot_test_teardown():
Michael Walsh6741f742017-02-20 16:16:38 -0600996 r"""
Michael Walshf75d4352019-12-05 17:01:20 -0600997 Clean up after the main keyword.
Michael Walsh6741f742017-02-20 16:16:38 -0600998 """
Michael Walshf75d4352019-12-05 17:01:20 -0600999 gp.qprint_executing()
1000
1001 if ga.psutil_imported:
1002 ga.terminate_descendants()
Michael Walsh6741f742017-02-20 16:16:38 -06001003
1004 if cp_setup_called:
1005 plug_in_setup()
1006 rc, shell_rc, failed_plug_in_name = grpi.rprocess_plug_in_packages(
Michael Walsh600876d2017-05-30 17:58:58 -05001007 call_point='cleanup', stop_on_plug_in_failure=0)
Michael Walsh6741f742017-02-20 16:16:38 -06001008
Michael Walsh600876d2017-05-30 17:58:58 -05001009 if 'boot_results_file_path' in globals():
Michael Walsh986d8ae2019-07-17 10:02:23 -05001010 # Save boot_results and boot_history objects to a file in case they are
Michael Walsh6c645742018-08-17 15:02:17 -05001011 # needed again.
Michael Walsh600876d2017-05-30 17:58:58 -05001012 gp.qprint_timen("Saving boot_results to the following path.")
1013 gp.qprint_var(boot_results_file_path)
Michael Walsh986d8ae2019-07-17 10:02:23 -05001014 pickle.dump((boot_results, boot_history),
Michael Walsh6c645742018-08-17 15:02:17 -05001015 open(boot_results_file_path, 'wb'),
Michael Walsh600876d2017-05-30 17:58:58 -05001016 pickle.HIGHEST_PROTOCOL)
Michael Walsh0b93fbf2017-03-02 14:42:41 -06001017
Michael Walshff340002017-08-29 11:18:27 -05001018 global save_stack
1019 # Restore any global values saved on the save_stack.
1020 for parm_name in main_func_parm_list:
1021 # Get the parm_value if it was saved on the stack.
1022 try:
1023 parm_value = save_stack.pop(parm_name)
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -05001024 except BaseException:
Michael Walshff340002017-08-29 11:18:27 -05001025 # If it was not saved, no further action is required.
1026 continue
1027
1028 # Restore the saved value.
1029 cmd_buf = "BuiltIn().set_global_variable(\"${" + parm_name +\
1030 "}\", parm_value)"
1031 gp.dpissuing(cmd_buf)
1032 exec(cmd_buf)
1033
1034 gp.dprintn(save_stack.sprint_obj())
1035
Michael Walsh6741f742017-02-20 16:16:38 -06001036
Michael Walshc9116812017-03-10 14:23:06 -06001037def test_teardown():
Michael Walshc9116812017-03-10 14:23:06 -06001038 r"""
1039 Clean up after this test case.
1040 """
1041
1042 gp.qprintn()
Michael Walshf75d4352019-12-05 17:01:20 -06001043 gp.qprint_executing()
1044
1045 if ga.psutil_imported:
1046 ga.terminate_descendants()
1047
Michael Walshc9116812017-03-10 14:23:06 -06001048 cmd_buf = ["Print Error",
1049 "A keyword timeout occurred ending this program.\n"]
1050 BuiltIn().run_keyword_if_timeout_occurred(*cmd_buf)
1051
George Keishinga54e06f2020-06-12 10:42:41 -05001052 if redfish_supported:
1053 redfish.logout()
1054
Michael Walshc108e422019-03-28 12:27:18 -05001055 gp.qprint_pgm_footer()
Michael Walshb5839d02017-04-12 16:11:20 -05001056
Michael Walshc9116812017-03-10 14:23:06 -06001057
Michael Walsh89de14a2018-10-01 16:51:37 -05001058def post_stack():
1059 r"""
1060 Process post_stack plug-in programs.
1061 """
1062
1063 if not call_post_stack_plug:
1064 # The caller does not wish to have post_stack plug-in processing done.
1065 return
1066
1067 global boot_success
1068
1069 # NOTE: A post_stack call-point failure is NOT counted as a boot failure.
1070 pre_boot_plug_in_setup()
1071 # For the purposes of the following plug-ins, mark the "boot" as a success.
1072 boot_success = 1
1073 plug_in_setup()
Michael Walsh815b1d52018-10-30 13:32:26 -05001074 rc, shell_rc, failed_plug_in_name, history =\
1075 grpi.rprocess_plug_in_packages(call_point='post_stack',
1076 stop_on_plug_in_failure=0,
1077 return_history=True)
Michael Walsh986d8ae2019-07-17 10:02:23 -05001078 for doing_msg in history:
1079 update_boot_history(boot_history, doing_msg, max_boot_history)
Michael Walsh815b1d52018-10-30 13:32:26 -05001080 if rc != 0:
1081 boot_success = 0
Michael Walsh89de14a2018-10-01 16:51:37 -05001082
1083 plug_in_setup()
Michael Walsh815b1d52018-10-30 13:32:26 -05001084 rc, shell_rc, failed_plug_in_name =\
1085 grpi.rprocess_plug_in_packages(call_point='ffdc_check',
1086 shell_rc=dump_ffdc_rc(),
1087 stop_on_plug_in_failure=1,
1088 stop_on_non_zero_rc=1)
1089 if shell_rc == dump_ffdc_rc():
Michael Walsh89de14a2018-10-01 16:51:37 -05001090 status, ret_values = grk.run_key_u("my_ffdc", ignore=1)
1091 if status != 'PASS':
1092 gp.qprint_error("Call to my_ffdc failed.\n")
Michael Walshc9bd2e82019-04-18 11:06:52 -05001093 # Leave a record for caller that "soft" errors occurred.
1094 soft_errors = 1
1095 gpu.save_plug_in_value(soft_errors, pgm_name)
Michael Walsh89de14a2018-10-01 16:51:37 -05001096
1097 plug_in_setup()
1098 rc, shell_rc, failed_plug_in_name = grpi.rprocess_plug_in_packages(
1099 call_point='stop_check', shell_rc=stop_test_rc(),
1100 stop_on_non_zero_rc=1)
1101 if shell_rc == stop_test_rc():
1102 message = "Stopping as requested by user.\n"
Michael Walsh80dddde2019-10-22 13:54:38 -05001103 gp.qprint_time(message)
Michael Walsh89de14a2018-10-01 16:51:37 -05001104 BuiltIn().fail(message)
1105
1106
Michael Walshff340002017-08-29 11:18:27 -05001107def obmc_boot_test_py(loc_boot_stack=None,
1108 loc_stack_mode=None,
1109 loc_quiet=None):
Michael Walsh6741f742017-02-20 16:16:38 -06001110 r"""
1111 Do main program processing.
1112 """
1113
Michael Walshff340002017-08-29 11:18:27 -05001114 global save_stack
1115
Michael Walshf75d4352019-12-05 17:01:20 -06001116 ga.set_term_options(term_requests={'pgm_names': ['process_plug_in_packages.py']})
1117
George Keishing36efbc02018-12-12 10:18:23 -06001118 gp.dprintn()
Michael Walshff340002017-08-29 11:18:27 -05001119 # Process function parms.
1120 for parm_name in main_func_parm_list:
1121 # Get parm's value.
George Keishing36efbc02018-12-12 10:18:23 -06001122 parm_value = eval("loc_" + parm_name)
1123 gp.dpvars(parm_name, parm_value)
Michael Walshff340002017-08-29 11:18:27 -05001124
George Keishing36efbc02018-12-12 10:18:23 -06001125 if parm_value is not None:
Michael Walshff340002017-08-29 11:18:27 -05001126 # Save the global value on a stack.
1127 cmd_buf = "save_stack.push(BuiltIn().get_variable_value(\"${" +\
1128 parm_name + "}\"), \"" + parm_name + "\")"
1129 gp.dpissuing(cmd_buf)
1130 exec(cmd_buf)
1131
1132 # Set the global value to the passed value.
1133 cmd_buf = "BuiltIn().set_global_variable(\"${" + parm_name +\
1134 "}\", loc_" + parm_name + ")"
1135 gp.dpissuing(cmd_buf)
1136 exec(cmd_buf)
1137
1138 gp.dprintn(save_stack.sprint_obj())
Michael Walshb5839d02017-04-12 16:11:20 -05001139
Michael Walsh6741f742017-02-20 16:16:38 -06001140 setup()
1141
Michael Walshcd9fbfd2017-09-19 12:00:08 -05001142 init_boot_pass, init_boot_fail = boot_results.return_total_pass_fail()
1143
Michael Walsha20da402017-03-31 16:27:45 -05001144 if ffdc_only:
1145 gp.qprint_timen("Caller requested ffdc_only.")
Michael Walsh986d8ae2019-07-17 10:02:23 -05001146 if do_pre_boot_plug_in_setup:
1147 pre_boot_plug_in_setup()
Michael Walsh83f4bc72017-04-20 16:49:43 -05001148 grk.run_key_u("my_ffdc")
Michael Walsh764d2f82017-04-27 16:01:08 -05001149 return
Michael Walsha20da402017-03-31 16:27:45 -05001150
Michael Walsh409ad352020-02-06 11:46:35 -06001151 if delete_errlogs:
Michael Shepos1a67b082020-08-28 16:01:58 -05001152 # print error logs before delete
1153 status, error_logs = grk.run_key_u("Get Error Logs")
1154 pels = pel.peltool("-l", ignore_err=1)
1155 gp.qprint_vars(error_logs, pels)
1156
Michael Walsh409ad352020-02-06 11:46:35 -06001157 # Delete errlogs prior to doing any boot tests.
1158 grk.run_key(delete_errlogs_cmd, ignore=1)
1159
Michael Walsh6741f742017-02-20 16:16:38 -06001160 # Process caller's boot_stack.
1161 while (len(boot_stack) > 0):
1162 test_loop_body()
1163
Michael Walshb5839d02017-04-12 16:11:20 -05001164 gp.qprint_timen("Finished processing stack.")
Michael Walsh30dadae2017-02-27 14:25:52 -06001165
Michael Walsh89de14a2018-10-01 16:51:37 -05001166 post_stack()
1167
Michael Walsh6741f742017-02-20 16:16:38 -06001168 # Process caller's boot_list.
1169 if len(boot_list) > 0:
1170 for ix in range(1, max_num_tests + 1):
1171 test_loop_body()
1172
Michael Walshb5839d02017-04-12 16:11:20 -05001173 gp.qprint_timen("Completed all requested boot tests.")
1174
1175 boot_pass, boot_fail = boot_results.return_total_pass_fail()
Michael Walshcd9fbfd2017-09-19 12:00:08 -05001176 new_fail = boot_fail - init_boot_fail
1177 if new_fail > boot_fail_threshold:
Michael Walshb5839d02017-04-12 16:11:20 -05001178 error_message = "Boot failures exceed the boot failure" +\
1179 " threshold:\n" +\
Michael Walshcd9fbfd2017-09-19 12:00:08 -05001180 gp.sprint_var(new_fail) +\
Michael Walshb5839d02017-04-12 16:11:20 -05001181 gp.sprint_var(boot_fail_threshold)
1182 BuiltIn().fail(gp.sprint_error(error_message))