blob: 36d708bf4016dd354db2f84b994163877868aaf7 [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 Shepos0e5f1132020-09-30 16:24:25 -050035import logging_utils as log
Michael Walsh0bbd8602016-11-22 11:31:49 -060036
Michael Walsh0b93fbf2017-03-02 14:42:41 -060037base_path = os.path.dirname(os.path.dirname(
38 imp.find_module("gen_robot_print")[1])) +\
Michael Walshc9116812017-03-10 14:23:06 -060039 os.sep
Michael Walsh0b93fbf2017-03-02 14:42:41 -060040sys.path.append(base_path + "extended/")
41import run_keyword as rk
Michael Walsh0bbd8602016-11-22 11:31:49 -060042
Michael Walshe1e26442017-03-06 17:50:07 -060043# Setting master_pid correctly influences the behavior of plug-ins like
44# DB_Logging
45program_pid = os.getpid()
46master_pid = os.environ.get('AUTOBOOT_MASTER_PID', program_pid)
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -050047pgm_name = re.sub('\\.py$', '', os.path.basename(__file__))
Michael Walshe1e26442017-03-06 17:50:07 -060048
Michael Walshb5839d02017-04-12 16:11:20 -050049# Set up boot data structures.
Michael Walsh986d8ae2019-07-17 10:02:23 -050050os_host = BuiltIn().get_variable_value("${OS_HOST}", default="")
Michael Walsh0b93fbf2017-03-02 14:42:41 -060051
Michael Walsh6741f742017-02-20 16:16:38 -060052boot_lists = read_boot_lists()
Michael Walsh986d8ae2019-07-17 10:02:23 -050053
54# The maximum number of entries that can be in the boot_history global variable.
Michael Walsh815b1d52018-10-30 13:32:26 -050055max_boot_history = 10
Michael Walsh986d8ae2019-07-17 10:02:23 -050056boot_history = []
Michael Walsh6741f742017-02-20 16:16:38 -060057
Michael Walsh7dc885b2018-03-14 17:51:59 -050058state = st.return_state_constant('default_state')
Michael Walsh6741f742017-02-20 16:16:38 -060059cp_setup_called = 0
60next_boot = ""
61base_tool_dir_path = os.path.normpath(os.environ.get(
62 'AUTOBOOT_BASE_TOOL_DIR_PATH', "/tmp")) + os.sep
Michael Walshb5839d02017-04-12 16:11:20 -050063
Michael Walsh6741f742017-02-20 16:16:38 -060064ffdc_dir_path = os.path.normpath(os.environ.get('FFDC_DIR_PATH', '')) + os.sep
Michael Walsh6741f742017-02-20 16:16:38 -060065boot_success = 0
Michael Walsh6741f742017-02-20 16:16:38 -060066status_dir_path = os.environ.get('STATUS_DIR_PATH', "")
67if status_dir_path != "":
68 status_dir_path = os.path.normpath(status_dir_path) + os.sep
Michael Walshe58df1c2019-08-07 09:57:43 -050069redfish_supported = BuiltIn().get_variable_value("${REDFISH_SUPPORTED}", default=False)
George Keishingeb1fe352020-06-19 03:02:22 -050070redfish_rest_supported = BuiltIn().get_variable_value("${REDFISH_REST_SUPPORTED}", default=False)
Michael Walshe58df1c2019-08-07 09:57:43 -050071if redfish_supported:
George Keishing89537a82020-06-17 00:37:25 -050072 redfish = BuiltIn().get_library_instance('redfish')
Michael Walshe58df1c2019-08-07 09:57:43 -050073 default_power_on = "Redfish Power On"
74 default_power_off = "Redfish Power Off"
George Keishingeb1fe352020-06-19 03:02:22 -050075 if redfish_rest_supported:
Michael Sheposcc490b42020-08-26 12:53:01 -050076 delete_errlogs_cmd = "Delete Error Logs ${quiet}=${1}"
George Keishingeb1fe352020-06-19 03:02:22 -050077 default_set_power_policy = "Set BMC Power Policy ALWAYS_POWER_OFF"
78 else:
79 delete_errlogs_cmd = "Redfish Purge Event Log"
80 default_set_power_policy = "Redfish Set Power Restore Policy AlwaysOff"
Michael Walshe58df1c2019-08-07 09:57:43 -050081else:
82 default_power_on = "REST Power On"
83 default_power_off = "REST Power Off"
Michael Sheposcc490b42020-08-26 12:53:01 -050084 delete_errlogs_cmd = "Delete Error Logs ${quiet}=${1}"
George Keishinga54e06f2020-06-12 10:42:41 -050085 default_set_power_policy = "Set BMC Power Policy ALWAYS_POWER_OFF"
Michael Walsh6741f742017-02-20 16:16:38 -060086boot_count = 0
Michael Walsh0bbd8602016-11-22 11:31:49 -060087
Michael Walsh85678942017-03-27 14:34:22 -050088LOG_LEVEL = BuiltIn().get_variable_value("${LOG_LEVEL}")
Michael Walsh986d8ae2019-07-17 10:02:23 -050089AUTOBOOT_FFDC_PREFIX = os.environ.get('AUTOBOOT_FFDC_PREFIX', '')
90ffdc_prefix = AUTOBOOT_FFDC_PREFIX
Sunil M325eb542017-08-10 07:09:43 -050091boot_start_time = ""
92boot_end_time = ""
Michael Walshff340002017-08-29 11:18:27 -050093save_stack = vs.var_stack('save_stack')
94main_func_parm_list = ['boot_stack', 'stack_mode', 'quiet']
Michael Walsh85678942017-03-27 14:34:22 -050095
96
Michael Walsh89de14a2018-10-01 16:51:37 -050097def dump_ffdc_rc():
98 r"""
99 Return the constant dump ffdc test return code value.
100
101 When a plug-in call point program returns this value, it indicates that
102 this program should collect FFDC.
103 """
104
105 return 0x00000200
106
107
108def stop_test_rc():
109 r"""
110 Return the constant stop test return code value.
111
112 When a plug-in call point program returns this value, it indicates that
113 this program should stop running.
114 """
115
116 return 0x00000200
117
118
Michael Walsh0ad0f7f2017-05-04 14:39:58 -0500119def process_host(host,
120 host_var_name=""):
Michael Walsh0ad0f7f2017-05-04 14:39:58 -0500121 r"""
122 Process a host by getting the associated host name and IP address and
123 setting them in global variables.
124
125 If the caller does not pass the host_var_name, this function will try to
126 figure out the name of the variable used by the caller for the host parm.
127 Callers are advised to explicitly specify the host_var_name when calling
128 with an exec command. In such cases, the get_arg_name cannot figure out
129 the host variable name.
130
131 This function will then create similar global variable names by
132 removing "_host" and appending "_host_name" or "_ip" to the host variable
133 name.
134
135 Example:
136
137 If a call is made like this:
138 process_host(openbmc_host)
139
140 Global variables openbmc_host_name and openbmc_ip will be set.
141
142 Description of argument(s):
143 host A host name or IP. The name of the variable used should
144 have a suffix of "_host".
145 host_var_name The name of the variable being used as the host parm.
146 """
147
148 if host_var_name == "":
149 host_var_name = gp.get_arg_name(0, 1, stack_frame_ix=2)
150
151 host_name_var_name = re.sub("host", "host_name", host_var_name)
152 ip_var_name = re.sub("host", "ip", host_var_name)
153 cmd_buf = "global " + host_name_var_name + ", " + ip_var_name + " ; " +\
154 host_name_var_name + ", " + ip_var_name + " = gm.get_host_name_ip('" +\
155 host + "')"
156 exec(cmd_buf)
157
Michael Walsh0ad0f7f2017-05-04 14:39:58 -0500158
Michael Walshb5839d02017-04-12 16:11:20 -0500159def process_pgm_parms():
Michael Walshb5839d02017-04-12 16:11:20 -0500160 r"""
161 Process the program parameters by assigning them all to corresponding
162 globals. Also, set some global values that depend on program parameters.
163 """
164
165 # Program parameter processing.
166 # Assign all program parms to python variables which are global to this
167 # module.
168
169 global parm_list
170 parm_list = BuiltIn().get_variable_value("${parm_list}")
171 # The following subset of parms should be processed as integers.
172 int_list = ['max_num_tests', 'boot_pass', 'boot_fail', 'ffdc_only',
Michael Walsh89de14a2018-10-01 16:51:37 -0500173 'boot_fail_threshold', 'delete_errlogs',
Michael Walsh986d8ae2019-07-17 10:02:23 -0500174 'call_post_stack_plug', 'do_pre_boot_plug_in_setup', 'quiet',
175 'test_mode', 'debug']
Michael Walshb5839d02017-04-12 16:11:20 -0500176 for parm in parm_list:
177 if parm in int_list:
178 sub_cmd = "int(BuiltIn().get_variable_value(\"${" + parm +\
179 "}\", \"0\"))"
180 else:
181 sub_cmd = "BuiltIn().get_variable_value(\"${" + parm + "}\")"
182 cmd_buf = "global " + parm + " ; " + parm + " = " + sub_cmd
Michael Walshff340002017-08-29 11:18:27 -0500183 gp.dpissuing(cmd_buf)
Michael Walshb5839d02017-04-12 16:11:20 -0500184 exec(cmd_buf)
Michael Walsh0ad0f7f2017-05-04 14:39:58 -0500185 if re.match(r".*_host$", parm):
186 cmd_buf = "process_host(" + parm + ", '" + parm + "')"
187 exec(cmd_buf)
188 if re.match(r".*_password$", parm):
189 # Register the value of any parm whose name ends in _password.
190 # This will cause the print functions to replace passwords with
191 # asterisks in the output.
192 cmd_buf = "gp.register_passwords(" + parm + ")"
193 exec(cmd_buf)
Michael Walshb5839d02017-04-12 16:11:20 -0500194
195 global ffdc_dir_path_style
196 global boot_list
197 global boot_stack
198 global boot_results_file_path
199 global boot_results
Michael Walsh986d8ae2019-07-17 10:02:23 -0500200 global boot_history
Michael Walshb5839d02017-04-12 16:11:20 -0500201 global ffdc_list_file_path
Michael Walshe0cf8d72017-05-17 13:20:46 -0500202 global ffdc_report_list_path
Michael Walsh600876d2017-05-30 17:58:58 -0500203 global ffdc_summary_list_path
Michael Walsha3e7b222020-02-03 15:32:16 -0600204 global boot_table
205 global valid_boot_types
Michael Walshb5839d02017-04-12 16:11:20 -0500206
207 if ffdc_dir_path_style == "":
208 ffdc_dir_path_style = int(os.environ.get('FFDC_DIR_PATH_STYLE', '0'))
209
210 # Convert these program parms to lists for easier processing..
George Keishing36efbc02018-12-12 10:18:23 -0600211 boot_list = list(filter(None, boot_list.split(":")))
212 boot_stack = list(filter(None, boot_stack.split(":")))
Michael Walshb5839d02017-04-12 16:11:20 -0500213
Michael Walsha3e7b222020-02-03 15:32:16 -0600214 boot_table = create_boot_table(boot_table_path, os_host=os_host)
215 valid_boot_types = create_valid_boot_list(boot_table)
216
Michael Walsh903e0b22017-09-19 17:00:33 -0500217 cleanup_boot_results_file()
218 boot_results_file_path = create_boot_results_file_path(pgm_name,
219 openbmc_nickname,
220 master_pid)
Michael Walshb5839d02017-04-12 16:11:20 -0500221
222 if os.path.isfile(boot_results_file_path):
223 # We've been called before in this run so we'll load the saved
Michael Walsh986d8ae2019-07-17 10:02:23 -0500224 # boot_results and boot_history objects.
225 boot_results, boot_history =\
Michael Walsh6c645742018-08-17 15:02:17 -0500226 pickle.load(open(boot_results_file_path, 'rb'))
Michael Walshb5839d02017-04-12 16:11:20 -0500227 else:
228 boot_results = boot_results(boot_table, boot_pass, boot_fail)
229
230 ffdc_list_file_path = base_tool_dir_path + openbmc_nickname +\
231 "/FFDC_FILE_LIST"
Michael Walshe0cf8d72017-05-17 13:20:46 -0500232 ffdc_report_list_path = base_tool_dir_path + openbmc_nickname +\
233 "/FFDC_REPORT_FILE_LIST"
Michael Walshb5839d02017-04-12 16:11:20 -0500234
Michael Walsh600876d2017-05-30 17:58:58 -0500235 ffdc_summary_list_path = base_tool_dir_path + openbmc_nickname +\
236 "/FFDC_SUMMARY_FILE_LIST"
237
Michael Walshb5839d02017-04-12 16:11:20 -0500238
Michael Walsh85678942017-03-27 14:34:22 -0500239def initial_plug_in_setup():
Michael Walsh85678942017-03-27 14:34:22 -0500240 r"""
241 Initialize all plug-in environment variables which do not change for the
242 duration of the program.
243
244 """
245
246 global LOG_LEVEL
247 BuiltIn().set_log_level("NONE")
248
249 BuiltIn().set_global_variable("${master_pid}", master_pid)
250 BuiltIn().set_global_variable("${FFDC_DIR_PATH}", ffdc_dir_path)
251 BuiltIn().set_global_variable("${STATUS_DIR_PATH}", status_dir_path)
252 BuiltIn().set_global_variable("${BASE_TOOL_DIR_PATH}", base_tool_dir_path)
253 BuiltIn().set_global_variable("${FFDC_LIST_FILE_PATH}",
254 ffdc_list_file_path)
Michael Walshe0cf8d72017-05-17 13:20:46 -0500255 BuiltIn().set_global_variable("${FFDC_REPORT_LIST_PATH}",
256 ffdc_report_list_path)
Michael Walsh600876d2017-05-30 17:58:58 -0500257 BuiltIn().set_global_variable("${FFDC_SUMMARY_LIST_PATH}",
258 ffdc_summary_list_path)
Michael Walsh85678942017-03-27 14:34:22 -0500259
260 BuiltIn().set_global_variable("${FFDC_DIR_PATH_STYLE}",
261 ffdc_dir_path_style)
262 BuiltIn().set_global_variable("${FFDC_CHECK}",
263 ffdc_check)
264
265 # For each program parameter, set the corresponding AUTOBOOT_ environment
266 # variable value. Also, set an AUTOBOOT_ environment variable for every
267 # element in additional_values.
268 additional_values = ["program_pid", "master_pid", "ffdc_dir_path",
269 "status_dir_path", "base_tool_dir_path",
Michael Walsh600876d2017-05-30 17:58:58 -0500270 "ffdc_list_file_path", "ffdc_report_list_path",
Michael Shepos7fe83b32020-09-21 15:46:01 -0500271 "ffdc_summary_list_path", "execdir", "redfish_supported",
272 "redfish_rest_supported"]
Michael Walsh85678942017-03-27 14:34:22 -0500273
274 plug_in_vars = parm_list + additional_values
275
276 for var_name in plug_in_vars:
277 var_value = BuiltIn().get_variable_value("${" + var_name + "}")
278 var_name = var_name.upper()
279 if var_value is None:
280 var_value = ""
281 os.environ["AUTOBOOT_" + var_name] = str(var_value)
282
283 BuiltIn().set_log_level(LOG_LEVEL)
284
Michael Walsh68a61162017-04-25 11:54:06 -0500285 # Make sure the ffdc list directory exists.
286 ffdc_list_dir_path = os.path.dirname(ffdc_list_file_path) + os.sep
287 if not os.path.exists(ffdc_list_dir_path):
288 os.makedirs(ffdc_list_dir_path)
Michael Walsh85678942017-03-27 14:34:22 -0500289
Michael Walsh85678942017-03-27 14:34:22 -0500290
Michael Walsh0bbd8602016-11-22 11:31:49 -0600291def plug_in_setup():
Michael Walsh0bbd8602016-11-22 11:31:49 -0600292 r"""
Michael Walsh85678942017-03-27 14:34:22 -0500293 Initialize all changing plug-in environment variables for use by the
294 plug-in programs.
Michael Walsh0bbd8602016-11-22 11:31:49 -0600295 """
296
Michael Walsh85678942017-03-27 14:34:22 -0500297 global LOG_LEVEL
298 global test_really_running
299
300 BuiltIn().set_log_level("NONE")
301
Michael Walsh6741f742017-02-20 16:16:38 -0600302 boot_pass, boot_fail = boot_results.return_total_pass_fail()
Michael Walsh0bbd8602016-11-22 11:31:49 -0600303 if boot_pass > 1:
304 test_really_running = 1
305 else:
306 test_really_running = 0
307
Michael Walsh6741f742017-02-20 16:16:38 -0600308 BuiltIn().set_global_variable("${test_really_running}",
309 test_really_running)
310 BuiltIn().set_global_variable("${boot_type_desc}", next_boot)
Michael Walsh6741f742017-02-20 16:16:38 -0600311 BuiltIn().set_global_variable("${boot_pass}", boot_pass)
312 BuiltIn().set_global_variable("${boot_fail}", boot_fail)
313 BuiltIn().set_global_variable("${boot_success}", boot_success)
314 BuiltIn().set_global_variable("${ffdc_prefix}", ffdc_prefix)
Sunil M325eb542017-08-10 07:09:43 -0500315 BuiltIn().set_global_variable("${boot_start_time}", boot_start_time)
316 BuiltIn().set_global_variable("${boot_end_time}", boot_end_time)
Michael Walsh4c9a6452016-12-13 16:03:11 -0600317
Michael Walsh0bbd8602016-11-22 11:31:49 -0600318 # For each program parameter, set the corresponding AUTOBOOT_ environment
319 # variable value. Also, set an AUTOBOOT_ environment variable for every
320 # element in additional_values.
321 additional_values = ["boot_type_desc", "boot_success", "boot_pass",
Sunil M325eb542017-08-10 07:09:43 -0500322 "boot_fail", "test_really_running", "ffdc_prefix",
323 "boot_start_time", "boot_end_time"]
Michael Walsh0bbd8602016-11-22 11:31:49 -0600324
Michael Walsh85678942017-03-27 14:34:22 -0500325 plug_in_vars = additional_values
Michael Walsh0bbd8602016-11-22 11:31:49 -0600326
327 for var_name in plug_in_vars:
328 var_value = BuiltIn().get_variable_value("${" + var_name + "}")
329 var_name = var_name.upper()
330 if var_value is None:
331 var_value = ""
Michael Walsh6741f742017-02-20 16:16:38 -0600332 os.environ["AUTOBOOT_" + var_name] = str(var_value)
Michael Walsh0bbd8602016-11-22 11:31:49 -0600333
Michael Walsh0bbd8602016-11-22 11:31:49 -0600334 if debug:
Michael Walsh6741f742017-02-20 16:16:38 -0600335 shell_rc, out_buf = \
336 gc.cmd_fnc_u("printenv | egrep AUTOBOOT_ | sort -u")
Michael Walsh0bbd8602016-11-22 11:31:49 -0600337
Michael Walsh85678942017-03-27 14:34:22 -0500338 BuiltIn().set_log_level(LOG_LEVEL)
339
Michael Walsh0bbd8602016-11-22 11:31:49 -0600340
Michael Walshe0cf8d72017-05-17 13:20:46 -0500341def pre_boot_plug_in_setup():
342
343 # Clear the ffdc_list_file_path file. Plug-ins may now write to it.
344 try:
345 os.remove(ffdc_list_file_path)
346 except OSError:
347 pass
348
349 # Clear the ffdc_report_list_path file. Plug-ins may now write to it.
350 try:
351 os.remove(ffdc_report_list_path)
352 except OSError:
353 pass
354
Michael Walsh600876d2017-05-30 17:58:58 -0500355 # Clear the ffdc_summary_list_path file. Plug-ins may now write to it.
356 try:
357 os.remove(ffdc_summary_list_path)
358 except OSError:
359 pass
360
Michael Walshe1974b92017-08-03 13:39:51 -0500361 global ffdc_prefix
362
363 seconds = time.time()
364 loc_time = time.localtime(seconds)
365 time_string = time.strftime("%y%m%d.%H%M%S.", loc_time)
366
367 ffdc_prefix = openbmc_nickname + "." + time_string
368
Michael Walshe0cf8d72017-05-17 13:20:46 -0500369
Michael Walshf566fb12019-02-01 14:35:09 -0600370def default_sigusr1(signal_number=0,
371 frame=None):
372 r"""
373 Handle SIGUSR1 by doing nothing.
374
375 This function assists in debugging SIGUSR1 processing by printing messages
376 to stdout and to the log.html file.
377
378 Description of argument(s):
379 signal_number The signal number (should always be 10 for SIGUSR1).
380 frame The frame data.
381 """
382
Michael Walsh80dddde2019-10-22 13:54:38 -0500383 gp.qprintn()
384 gp.qprint_executing()
Michael Walshf566fb12019-02-01 14:35:09 -0600385 gp.lprint_executing()
386
387
388def set_default_siguser1():
389 r"""
390 Set the default_sigusr1 function to be the SIGUSR1 handler.
391 """
392
Michael Walsh80dddde2019-10-22 13:54:38 -0500393 gp.qprintn()
394 gp.qprint_executing()
Michael Walshf566fb12019-02-01 14:35:09 -0600395 gp.lprint_executing()
396 signal.signal(signal.SIGUSR1, default_sigusr1)
397
398
Michael Walsh6741f742017-02-20 16:16:38 -0600399def setup():
Michael Walsh0bbd8602016-11-22 11:31:49 -0600400 r"""
Michael Walsh6741f742017-02-20 16:16:38 -0600401 Do general program setup tasks.
Michael Walsh0bbd8602016-11-22 11:31:49 -0600402 """
403
Michael Walsh6741f742017-02-20 16:16:38 -0600404 global cp_setup_called
Michael Walsh81816742017-09-27 11:02:29 -0500405 global transitional_boot_selected
Michael Walsh0bbd8602016-11-22 11:31:49 -0600406
Michael Walshb5839d02017-04-12 16:11:20 -0500407 gp.qprintn()
408
George Keishinga54e06f2020-06-12 10:42:41 -0500409 if redfish_supported:
410 redfish.login()
411
Michael Walshf566fb12019-02-01 14:35:09 -0600412 set_default_siguser1()
Michael Walsh81816742017-09-27 11:02:29 -0500413 transitional_boot_selected = False
414
Michael Walsh83f4bc72017-04-20 16:49:43 -0500415 robot_pgm_dir_path = os.path.dirname(__file__) + os.sep
416 repo_bin_path = robot_pgm_dir_path.replace("/lib/", "/bin/")
Michael Walshd061c042017-05-23 14:46:57 -0500417 # If we can't find process_plug_in_packages.py, ssh_pw or
418 # validate_plug_ins.py, then we don't have our repo bin in PATH.
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -0500419 shell_rc, out_buf = gc.cmd_fnc_u("which process_plug_in_packages.py"
420 + " ssh_pw validate_plug_ins.py", quiet=1,
Michael Walshd061c042017-05-23 14:46:57 -0500421 print_output=0, show_err=0)
Michael Walshb5839d02017-04-12 16:11:20 -0500422 if shell_rc != 0:
Michael Walsh83f4bc72017-04-20 16:49:43 -0500423 os.environ['PATH'] = repo_bin_path + ":" + os.environ.get('PATH', "")
424 # Likewise, our repo lib subdir needs to be in sys.path and PYTHONPATH.
425 if robot_pgm_dir_path not in sys.path:
426 sys.path.append(robot_pgm_dir_path)
427 PYTHONPATH = os.environ.get("PYTHONPATH", "")
428 if PYTHONPATH == "":
429 os.environ['PYTHONPATH'] = robot_pgm_dir_path
430 else:
431 os.environ['PYTHONPATH'] = robot_pgm_dir_path + ":" + PYTHONPATH
Michael Walsh6741f742017-02-20 16:16:38 -0600432
433 validate_parms()
434
Michael Walshc108e422019-03-28 12:27:18 -0500435 gp.qprint_pgm_header()
Michael Walsh6741f742017-02-20 16:16:38 -0600436
George Keishinga54e06f2020-06-12 10:42:41 -0500437 grk.run_key_u(default_set_power_policy)
Michael Walsh11cfc8c2017-03-31 09:40:55 -0500438
Michael Walsh85678942017-03-27 14:34:22 -0500439 initial_plug_in_setup()
440
Michael Walsh6741f742017-02-20 16:16:38 -0600441 plug_in_setup()
442 rc, shell_rc, failed_plug_in_name = grpi.rprocess_plug_in_packages(
443 call_point='setup')
444 if rc != 0:
445 error_message = "Plug-in setup failed.\n"
Michael Walshc108e422019-03-28 12:27:18 -0500446 gp.print_error_report(error_message)
Michael Walsh6741f742017-02-20 16:16:38 -0600447 BuiltIn().fail(error_message)
448 # Setting cp_setup_called lets our Teardown know that it needs to call
449 # the cleanup plug-in call point.
450 cp_setup_called = 1
451
452 # Keyword "FFDC" will fail if TEST_MESSAGE is not set.
453 BuiltIn().set_global_variable("${TEST_MESSAGE}", "${EMPTY}")
Michael Walsh85678942017-03-27 14:34:22 -0500454 # FFDC_LOG_PATH is used by "FFDC" keyword.
455 BuiltIn().set_global_variable("${FFDC_LOG_PATH}", ffdc_dir_path)
Michael Walsh6741f742017-02-20 16:16:38 -0600456
Michael Walshdc80d672017-05-09 12:58:32 -0500457 # Also printed by FFDC.
458 global host_name
459 global host_ip
460 host = socket.gethostname()
461 host_name, host_ip = gm.get_host_name_ip(host)
462
Michael Walsh986d8ae2019-07-17 10:02:23 -0500463 gp.dprint_var(boot_table)
Michael Walshb5839d02017-04-12 16:11:20 -0500464 gp.dprint_var(boot_lists)
Michael Walsh0bbd8602016-11-22 11:31:49 -0600465
Michael Walsh0bbd8602016-11-22 11:31:49 -0600466
Michael Walsh6741f742017-02-20 16:16:38 -0600467def validate_parms():
Michael Walsh0bbd8602016-11-22 11:31:49 -0600468 r"""
Michael Walsh6741f742017-02-20 16:16:38 -0600469 Validate all program parameters.
Michael Walsh0bbd8602016-11-22 11:31:49 -0600470 """
471
Michael Walshb5839d02017-04-12 16:11:20 -0500472 process_pgm_parms()
Michael Walsh0bbd8602016-11-22 11:31:49 -0600473
Michael Walshb5839d02017-04-12 16:11:20 -0500474 gp.qprintn()
475
476 global openbmc_model
Michael Walshf5ce38c2020-02-27 12:46:20 -0600477 if openbmc_model == "":
478 status, ret_values =\
479 grk.run_key_u("Get BMC System Model")
480 openbmc_model = ret_values
481 BuiltIn().set_global_variable("${openbmc_model}", openbmc_model)
482 gv.set_exit_on_error(True)
Michael Walsh44cef252019-08-01 12:38:56 -0500483 gv.valid_value(openbmc_host)
484 gv.valid_value(openbmc_username)
485 gv.valid_value(openbmc_password)
486 gv.valid_value(rest_username)
487 gv.valid_value(rest_password)
488 gv.valid_value(ipmi_username)
489 gv.valid_value(ipmi_password)
Michael Walsh6741f742017-02-20 16:16:38 -0600490 if os_host != "":
Michael Walsh44cef252019-08-01 12:38:56 -0500491 gv.valid_value(os_username)
492 gv.valid_value(os_password)
Michael Walsh6741f742017-02-20 16:16:38 -0600493 if pdu_host != "":
Michael Walsh44cef252019-08-01 12:38:56 -0500494 gv.valid_value(pdu_username)
495 gv.valid_value(pdu_password)
496 gv.valid_integer(pdu_slot_no)
Michael Walsh6741f742017-02-20 16:16:38 -0600497 if openbmc_serial_host != "":
Michael Walsh44cef252019-08-01 12:38:56 -0500498 gv.valid_integer(openbmc_serial_port)
Michael Walsh44cef252019-08-01 12:38:56 -0500499 gv.valid_value(openbmc_model)
500 gv.valid_integer(max_num_tests)
501 gv.valid_integer(boot_pass)
502 gv.valid_integer(boot_fail)
Michael Walsh6741f742017-02-20 16:16:38 -0600503 plug_in_packages_list = grpi.rvalidate_plug_ins(plug_in_dir_paths)
504 BuiltIn().set_global_variable("${plug_in_packages_list}",
505 plug_in_packages_list)
Michael Walsh44cef252019-08-01 12:38:56 -0500506 gv.valid_value(stack_mode, valid_values=['normal', 'skip'])
Michael Walshf5ce38c2020-02-27 12:46:20 -0600507 gv.set_exit_on_error(False)
Michael Walsha20da402017-03-31 16:27:45 -0500508 if len(boot_list) == 0 and len(boot_stack) == 0 and not ffdc_only:
Michael Walsh6741f742017-02-20 16:16:38 -0600509 error_message = "You must provide either a value for either the" +\
510 " boot_list or the boot_stack parm.\n"
511 BuiltIn().fail(gp.sprint_error(error_message))
Michael Walsh6741f742017-02-20 16:16:38 -0600512 valid_boot_list(boot_list, valid_boot_types)
513 valid_boot_list(boot_stack, valid_boot_types)
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -0500514 selected_PDU_boots = list(set(boot_list + boot_stack)
515 & set(boot_lists['PDU_reboot']))
Michael Walsh11cfc8c2017-03-31 09:40:55 -0500516 if len(selected_PDU_boots) > 0 and pdu_host == "":
517 error_message = "You have selected the following boots which" +\
518 " require a PDU host but no value for pdu_host:\n"
519 error_message += gp.sprint_var(selected_PDU_boots)
Michael Walsh986d8ae2019-07-17 10:02:23 -0500520 error_message += gp.sprint_var(pdu_host, fmt=gp.blank())
Michael Walsh11cfc8c2017-03-31 09:40:55 -0500521 BuiltIn().fail(gp.sprint_error(error_message))
522
Michael Walsh6741f742017-02-20 16:16:38 -0600523 return
Michael Walsh0bbd8602016-11-22 11:31:49 -0600524
Michael Walsh0bbd8602016-11-22 11:31:49 -0600525
Michael Walsh6741f742017-02-20 16:16:38 -0600526def my_get_state():
Michael Walsh0bbd8602016-11-22 11:31:49 -0600527 r"""
Michael Walsh6741f742017-02-20 16:16:38 -0600528 Get the system state plus a little bit of wrapping.
Michael Walsh0bbd8602016-11-22 11:31:49 -0600529 """
530
Michael Walsh6741f742017-02-20 16:16:38 -0600531 global state
532
533 req_states = ['epoch_seconds'] + st.default_req_states
534
Michael Walshb5839d02017-04-12 16:11:20 -0500535 gp.qprint_timen("Getting system state.")
Michael Walsh6741f742017-02-20 16:16:38 -0600536 if test_mode:
537 state['epoch_seconds'] = int(time.time())
538 else:
Michael Walshb5839d02017-04-12 16:11:20 -0500539 state = st.get_state(req_states=req_states, quiet=quiet)
540 gp.qprint_var(state)
Michael Walsh341c21e2017-01-17 16:25:20 -0600541
Michael Walsh341c21e2017-01-17 16:25:20 -0600542
Michael Walsh45ca6e42017-09-14 17:29:12 -0500543def valid_state():
Michael Walsh45ca6e42017-09-14 17:29:12 -0500544 r"""
545 Verify that our state dictionary contains no blank values. If we don't get
546 valid state data, we cannot continue to work.
547 """
548
549 if st.compare_states(state, st.invalid_state_match, 'or'):
550 error_message = "The state dictionary contains blank fields which" +\
551 " is illegal.\n" + gp.sprint_var(state)
552 BuiltIn().fail(gp.sprint_error(error_message))
553
Michael Walsh45ca6e42017-09-14 17:29:12 -0500554
Michael Walsh6741f742017-02-20 16:16:38 -0600555def select_boot():
Michael Walsh341c21e2017-01-17 16:25:20 -0600556 r"""
557 Select a boot test to be run based on our current state and return the
558 chosen boot type.
559
560 Description of arguments:
Michael Walsh6741f742017-02-20 16:16:38 -0600561 state The state of the machine.
Michael Walsh341c21e2017-01-17 16:25:20 -0600562 """
563
Michael Walsh81816742017-09-27 11:02:29 -0500564 global transitional_boot_selected
Michael Walsh30dadae2017-02-27 14:25:52 -0600565 global boot_stack
566
Michael Walshb5839d02017-04-12 16:11:20 -0500567 gp.qprint_timen("Selecting a boot test.")
Michael Walsh6741f742017-02-20 16:16:38 -0600568
Michael Walsh81816742017-09-27 11:02:29 -0500569 if transitional_boot_selected and not boot_success:
570 prior_boot = next_boot
571 boot_candidate = boot_stack.pop()
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -0500572 gp.qprint_timen("The prior '" + next_boot + "' was chosen to"
573 + " transition to a valid state for '" + boot_candidate
574 + "' which was at the top of the boot_stack. Since"
575 + " the '" + next_boot + "' failed, the '"
576 + boot_candidate + "' has been removed from the stack"
577 + " to avoid and endless failure loop.")
Michael Walsh81816742017-09-27 11:02:29 -0500578 if len(boot_stack) == 0:
579 return ""
580
Michael Walsh6741f742017-02-20 16:16:38 -0600581 my_get_state()
Michael Walsh45ca6e42017-09-14 17:29:12 -0500582 valid_state()
Michael Walsh6741f742017-02-20 16:16:38 -0600583
Michael Walsh81816742017-09-27 11:02:29 -0500584 transitional_boot_selected = False
Michael Walsh6741f742017-02-20 16:16:38 -0600585 stack_popped = 0
586 if len(boot_stack) > 0:
587 stack_popped = 1
Michael Walshb5839d02017-04-12 16:11:20 -0500588 gp.qprint_dashes()
589 gp.qprint_var(boot_stack)
590 gp.qprint_dashes()
591 skip_boot_printed = 0
592 while len(boot_stack) > 0:
593 boot_candidate = boot_stack.pop()
594 if stack_mode == 'normal':
595 break
596 else:
597 if st.compare_states(state, boot_table[boot_candidate]['end']):
598 if not skip_boot_printed:
Michael Walshff340002017-08-29 11:18:27 -0500599 gp.qprint_var(stack_mode)
600 gp.qprintn()
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -0500601 gp.qprint_timen("Skipping the following boot tests"
602 + " which are unnecessary since their"
603 + " required end states match the"
604 + " current machine state:")
Michael Walshb5839d02017-04-12 16:11:20 -0500605 skip_boot_printed = 1
Michael Walshff340002017-08-29 11:18:27 -0500606 gp.qprint_var(boot_candidate)
Michael Walshb5839d02017-04-12 16:11:20 -0500607 boot_candidate = ""
608 if boot_candidate == "":
609 gp.qprint_dashes()
610 gp.qprint_var(boot_stack)
611 gp.qprint_dashes()
612 return boot_candidate
Michael Walsh6741f742017-02-20 16:16:38 -0600613 if st.compare_states(state, boot_table[boot_candidate]['start']):
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -0500614 gp.qprint_timen("The machine state is valid for a '"
615 + boot_candidate + "' boot test.")
Michael Walshb5839d02017-04-12 16:11:20 -0500616 gp.qprint_dashes()
617 gp.qprint_var(boot_stack)
618 gp.qprint_dashes()
Michael Walsh6741f742017-02-20 16:16:38 -0600619 return boot_candidate
Michael Walsh341c21e2017-01-17 16:25:20 -0600620 else:
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -0500621 gp.qprint_timen("The machine state does not match the required"
622 + " starting state for a '" + boot_candidate
623 + "' boot test:")
Michael Walsh986d8ae2019-07-17 10:02:23 -0500624 gp.qprint_varx("boot_table_start_entry",
625 boot_table[boot_candidate]['start'])
Michael Walsh6741f742017-02-20 16:16:38 -0600626 boot_stack.append(boot_candidate)
Michael Walsh81816742017-09-27 11:02:29 -0500627 transitional_boot_selected = True
Michael Walsh6741f742017-02-20 16:16:38 -0600628 popped_boot = boot_candidate
629
630 # Loop through your list selecting a boot_candidates
631 boot_candidates = []
632 for boot_candidate in boot_list:
633 if st.compare_states(state, boot_table[boot_candidate]['start']):
634 if stack_popped:
635 if st.compare_states(boot_table[boot_candidate]['end'],
Gunnar Mills096cd562018-03-26 10:19:12 -0500636 boot_table[popped_boot]['start']):
Michael Walsh6741f742017-02-20 16:16:38 -0600637 boot_candidates.append(boot_candidate)
638 else:
639 boot_candidates.append(boot_candidate)
640
641 if len(boot_candidates) == 0:
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -0500642 gp.qprint_timen("The user's boot list contained no boot tests"
643 + " which are valid for the current machine state.")
Michael Walsh6741f742017-02-20 16:16:38 -0600644 boot_candidate = default_power_on
645 if not st.compare_states(state, boot_table[default_power_on]['start']):
646 boot_candidate = default_power_off
647 boot_candidates.append(boot_candidate)
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -0500648 gp.qprint_timen("Using default '" + boot_candidate
649 + "' boot type to transition to valid state.")
Michael Walsh6741f742017-02-20 16:16:38 -0600650
Michael Walshb5839d02017-04-12 16:11:20 -0500651 gp.dprint_var(boot_candidates)
Michael Walsh6741f742017-02-20 16:16:38 -0600652
653 # Randomly select a boot from the candidate list.
654 boot = random.choice(boot_candidates)
Michael Walsh341c21e2017-01-17 16:25:20 -0600655
656 return boot
Michael Walsh0bbd8602016-11-22 11:31:49 -0600657
Michael Walsh55302292017-01-10 11:43:02 -0600658
Michael Walshb2e53ec2017-10-30 15:04:36 -0500659def print_defect_report(ffdc_file_list):
Michael Walsh341c21e2017-01-17 16:25:20 -0600660 r"""
661 Print a defect report.
Michael Walshb2e53ec2017-10-30 15:04:36 -0500662
663 Description of argument(s):
664 ffdc_file_list A list of files which were collected by our ffdc functions.
Michael Walsh341c21e2017-01-17 16:25:20 -0600665 """
666
Michael Walsh600876d2017-05-30 17:58:58 -0500667 # Making deliberate choice to NOT run plug_in_setup(). We don't want
668 # ffdc_prefix updated.
669 rc, shell_rc, failed_plug_in_name = grpi.rprocess_plug_in_packages(
670 call_point='ffdc_report', stop_on_plug_in_failure=0)
671
Michael Walshe0cf8d72017-05-17 13:20:46 -0500672 # Get additional header data which may have been created by ffdc plug-ins.
673 # Also, delete the individual header files to cleanup.
674 cmd_buf = "file_list=$(cat " + ffdc_report_list_path + " 2>/dev/null)" +\
675 " ; [ ! -z \"${file_list}\" ] && cat ${file_list}" +\
676 " 2>/dev/null ; rm -rf ${file_list} 2>/dev/null || :"
677 shell_rc, more_header_info = gc.cmd_fnc_u(cmd_buf, print_output=0,
678 show_err=0)
679
Michael Walshb2e53ec2017-10-30 15:04:36 -0500680 # Get additional summary data which may have been created by ffdc plug-ins.
Michael Walsh600876d2017-05-30 17:58:58 -0500681 # Also, delete the individual header files to cleanup.
682 cmd_buf = "file_list=$(cat " + ffdc_summary_list_path + " 2>/dev/null)" +\
683 " ; [ ! -z \"${file_list}\" ] && cat ${file_list}" +\
684 " 2>/dev/null ; rm -rf ${file_list} 2>/dev/null || :"
685 shell_rc, ffdc_summary_info = gc.cmd_fnc_u(cmd_buf, print_output=0,
686 show_err=0)
687
Michael Walshb2e53ec2017-10-30 15:04:36 -0500688 # ffdc_list_file_path contains a list of any ffdc files created by plug-
689 # ins, etc. Read that data into a list.
Michael Walsh341c21e2017-01-17 16:25:20 -0600690 try:
Michael Walshb2e53ec2017-10-30 15:04:36 -0500691 plug_in_ffdc_list = \
692 open(ffdc_list_file_path, 'r').read().rstrip("\n").split("\n")
George Keishing36efbc02018-12-12 10:18:23 -0600693 plug_in_ffdc_list = list(filter(None, plug_in_ffdc_list))
Michael Walsh341c21e2017-01-17 16:25:20 -0600694 except IOError:
Michael Walshb2e53ec2017-10-30 15:04:36 -0500695 plug_in_ffdc_list = []
696
697 # Combine the files from plug_in_ffdc_list with the ffdc_file_list passed
698 # in. Eliminate duplicates and sort the list.
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -0500699 ffdc_file_list = sorted(set(ffdc_file_list + plug_in_ffdc_list))
Michael Walshb2e53ec2017-10-30 15:04:36 -0500700
701 if status_file_path != "":
702 ffdc_file_list.insert(0, status_file_path)
703
704 # Convert the list to a printable list.
705 printable_ffdc_file_list = "\n".join(ffdc_file_list)
Michael Walsh341c21e2017-01-17 16:25:20 -0600706
Michael Walsh68a61162017-04-25 11:54:06 -0500707 # Open ffdc_file_list for writing. We will write a complete list of
708 # FFDC files to it for possible use by plug-ins like cp_stop_check.
709 ffdc_list_file = open(ffdc_list_file_path, 'w')
Michael Walshb2e53ec2017-10-30 15:04:36 -0500710 ffdc_list_file.write(printable_ffdc_file_list + "\n")
711 ffdc_list_file.close()
712
713 indent = 0
714 width = 90
715 linefeed = 1
716 char = "="
Michael Walsh68a61162017-04-25 11:54:06 -0500717
718 gp.qprintn()
Michael Walshb2e53ec2017-10-30 15:04:36 -0500719 gp.qprint_dashes(indent, width, linefeed, char)
Michael Walsh68a61162017-04-25 11:54:06 -0500720 gp.qprintn("Copy this data to the defect:\n")
721
Michael Walshe0cf8d72017-05-17 13:20:46 -0500722 if len(more_header_info) > 0:
Michael Walshff340002017-08-29 11:18:27 -0500723 gp.qprintn(more_header_info)
Michael Walshdc80d672017-05-09 12:58:32 -0500724 gp.qpvars(host_name, host_ip, openbmc_nickname, openbmc_host,
725 openbmc_host_name, openbmc_ip, openbmc_username,
Michael Walsh0a3bdb42019-01-31 16:21:44 +0000726 openbmc_password, rest_username, rest_password, ipmi_username,
727 ipmi_password, os_host, os_host_name, os_ip, os_username,
Michael Walshdc80d672017-05-09 12:58:32 -0500728 os_password, pdu_host, pdu_host_name, pdu_ip, pdu_username,
729 pdu_password, pdu_slot_no, openbmc_serial_host,
730 openbmc_serial_host_name, openbmc_serial_ip, openbmc_serial_port)
Michael Walsh68a61162017-04-25 11:54:06 -0500731
732 gp.qprintn()
Michael Walsh986d8ae2019-07-17 10:02:23 -0500733 print_boot_history(boot_history)
Michael Walsh68a61162017-04-25 11:54:06 -0500734 gp.qprintn()
735 gp.qprint_var(state)
Michael Walshb5839d02017-04-12 16:11:20 -0500736 gp.qprintn()
737 gp.qprintn("FFDC data files:")
Michael Walshb2e53ec2017-10-30 15:04:36 -0500738 gp.qprintn(printable_ffdc_file_list)
Michael Walshb5839d02017-04-12 16:11:20 -0500739 gp.qprintn()
Michael Walsh341c21e2017-01-17 16:25:20 -0600740
Michael Walsh600876d2017-05-30 17:58:58 -0500741 if len(ffdc_summary_info) > 0:
Michael Walshff340002017-08-29 11:18:27 -0500742 gp.qprintn(ffdc_summary_info)
Michael Walsh600876d2017-05-30 17:58:58 -0500743
Michael Walshb2e53ec2017-10-30 15:04:36 -0500744 gp.qprint_dashes(indent, width, linefeed, char)
Michael Walsh68a61162017-04-25 11:54:06 -0500745
Michael Walsh6741f742017-02-20 16:16:38 -0600746
Michael Walsh6741f742017-02-20 16:16:38 -0600747def my_ffdc():
Michael Walsh6741f742017-02-20 16:16:38 -0600748 r"""
749 Collect FFDC data.
750 """
751
752 global state
753
754 plug_in_setup()
755 rc, shell_rc, failed_plug_in_name = grpi.rprocess_plug_in_packages(
Michael Walsh600876d2017-05-30 17:58:58 -0500756 call_point='ffdc', stop_on_plug_in_failure=0)
Michael Walsh6741f742017-02-20 16:16:38 -0600757
758 AUTOBOOT_FFDC_PREFIX = os.environ['AUTOBOOT_FFDC_PREFIX']
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -0500759 status, ffdc_file_list = grk.run_key_u("FFDC ffdc_prefix="
760 + AUTOBOOT_FFDC_PREFIX
761 + " ffdc_function_list="
762 + ffdc_function_list, ignore=1)
Michael Walsh83f4bc72017-04-20 16:49:43 -0500763 if status != 'PASS':
Michael Walshff340002017-08-29 11:18:27 -0500764 gp.qprint_error("Call to ffdc failed.\n")
Michael Walshc9bd2e82019-04-18 11:06:52 -0500765 if type(ffdc_file_list) is not list:
766 ffdc_file_list = []
767 # Leave a record for caller that "soft" errors occurred.
768 soft_errors = 1
769 gpu.save_plug_in_value(soft_errors, pgm_name)
Michael Walsh6741f742017-02-20 16:16:38 -0600770
771 my_get_state()
772
Michael Walshb2e53ec2017-10-30 15:04:36 -0500773 print_defect_report(ffdc_file_list)
Michael Walsh6741f742017-02-20 16:16:38 -0600774
Michael Walsh6741f742017-02-20 16:16:38 -0600775
Michael Walsh6741f742017-02-20 16:16:38 -0600776def print_test_start_message(boot_keyword):
Michael Walsh6741f742017-02-20 16:16:38 -0600777 r"""
778 Print a message indicating what boot test is about to run.
779
780 Description of arguments:
781 boot_keyword The name of the boot which is to be run
782 (e.g. "BMC Power On").
783 """
784
Michael Walsh986d8ae2019-07-17 10:02:23 -0500785 global boot_history
Sunil M325eb542017-08-10 07:09:43 -0500786 global boot_start_time
Michael Walsh6741f742017-02-20 16:16:38 -0600787
788 doing_msg = gp.sprint_timen("Doing \"" + boot_keyword + "\".")
Sunil M325eb542017-08-10 07:09:43 -0500789
790 # Set boot_start_time for use by plug-ins.
791 boot_start_time = doing_msg[1:33]
792 gp.qprint_var(boot_start_time)
793
Michael Walshb5839d02017-04-12 16:11:20 -0500794 gp.qprint(doing_msg)
Michael Walsh6741f742017-02-20 16:16:38 -0600795
Michael Walsh986d8ae2019-07-17 10:02:23 -0500796 update_boot_history(boot_history, doing_msg, max_boot_history)
Michael Walsh6741f742017-02-20 16:16:38 -0600797
Michael Walsh6741f742017-02-20 16:16:38 -0600798
Michael Walshf566fb12019-02-01 14:35:09 -0600799def stop_boot_test(signal_number=0,
800 frame=None):
801 r"""
802 Handle SIGUSR1 by aborting the boot test that is running.
803
804 Description of argument(s):
805 signal_number The signal number (should always be 10 for SIGUSR1).
806 frame The frame data.
807 """
808
Michael Walsh80dddde2019-10-22 13:54:38 -0500809 gp.qprintn()
810 gp.qprint_executing()
Michael Walshf566fb12019-02-01 14:35:09 -0600811 gp.lprint_executing()
812
813 # Restore original sigusr1 handler.
814 set_default_siguser1()
815
816 message = "The caller has asked that the boot test be stopped and marked"
817 message += " as a failure."
818
819 function_stack = gm.get_function_stack()
820 if "wait_state" in function_stack:
Michael Walshc44aa532019-06-14 13:33:29 -0500821 st.set_exit_wait_early_message(message)
Michael Walshf566fb12019-02-01 14:35:09 -0600822 else:
823 BuiltIn().fail(gp.sprint_error(message))
824
825
Michael Walsh6741f742017-02-20 16:16:38 -0600826def run_boot(boot):
Michael Walsh6741f742017-02-20 16:16:38 -0600827 r"""
828 Run the specified boot.
829
830 Description of arguments:
831 boot The name of the boot test to be performed.
832 """
833
834 global state
835
Michael Walshf566fb12019-02-01 14:35:09 -0600836 signal.signal(signal.SIGUSR1, stop_boot_test)
837 gp.qprint_timen("stop_boot_test is armed.")
838
Michael Walsh6741f742017-02-20 16:16:38 -0600839 print_test_start_message(boot)
840
841 plug_in_setup()
842 rc, shell_rc, failed_plug_in_name = \
843 grpi.rprocess_plug_in_packages(call_point="pre_boot")
844 if rc != 0:
845 error_message = "Plug-in failed with non-zero return code.\n" +\
Michael Walsh986d8ae2019-07-17 10:02:23 -0500846 gp.sprint_var(rc, fmt=gp.hexa())
Michael Walshf566fb12019-02-01 14:35:09 -0600847 set_default_siguser1()
Michael Walsh6741f742017-02-20 16:16:38 -0600848 BuiltIn().fail(gp.sprint_error(error_message))
849
850 if test_mode:
851 # In test mode, we'll pretend the boot worked by assigning its
852 # required end state to the default state value.
Michael Walsh30dadae2017-02-27 14:25:52 -0600853 state = st.strip_anchor_state(boot_table[boot]['end'])
Michael Walsh6741f742017-02-20 16:16:38 -0600854 else:
855 # Assertion: We trust that the state data was made fresh by the
856 # caller.
857
Michael Walshb5839d02017-04-12 16:11:20 -0500858 gp.qprintn()
Michael Walsh6741f742017-02-20 16:16:38 -0600859
860 if boot_table[boot]['method_type'] == "keyword":
Michael Walsh0b93fbf2017-03-02 14:42:41 -0600861 rk.my_run_keywords(boot_table[boot].get('lib_file_path', ''),
Michael Walshb5839d02017-04-12 16:11:20 -0500862 boot_table[boot]['method'],
863 quiet=quiet)
Michael Walsh6741f742017-02-20 16:16:38 -0600864
865 if boot_table[boot]['bmc_reboot']:
866 st.wait_for_comm_cycle(int(state['epoch_seconds']))
Michael Walsh30dadae2017-02-27 14:25:52 -0600867 plug_in_setup()
868 rc, shell_rc, failed_plug_in_name = \
869 grpi.rprocess_plug_in_packages(call_point="post_reboot")
870 if rc != 0:
Michael Walsh0b93fbf2017-03-02 14:42:41 -0600871 error_message = "Plug-in failed with non-zero return code.\n"
Michael Walsh986d8ae2019-07-17 10:02:23 -0500872 error_message += gp.sprint_var(rc, fmt=gp.hexa())
Michael Walshf566fb12019-02-01 14:35:09 -0600873 set_default_siguser1()
Michael Walsh30dadae2017-02-27 14:25:52 -0600874 BuiltIn().fail(gp.sprint_error(error_message))
Michael Walsh6741f742017-02-20 16:16:38 -0600875 else:
876 match_state = st.anchor_state(state)
877 del match_state['epoch_seconds']
878 # Wait for the state to change in any way.
879 st.wait_state(match_state, wait_time=state_change_timeout,
Michael Walsh600876d2017-05-30 17:58:58 -0500880 interval="10 seconds", invert=1)
Michael Walsh6741f742017-02-20 16:16:38 -0600881
Michael Walshb5839d02017-04-12 16:11:20 -0500882 gp.qprintn()
Michael Walsh6741f742017-02-20 16:16:38 -0600883 if boot_table[boot]['end']['chassis'] == "Off":
884 boot_timeout = power_off_timeout
885 else:
886 boot_timeout = power_on_timeout
887 st.wait_state(boot_table[boot]['end'], wait_time=boot_timeout,
Michael Walsh600876d2017-05-30 17:58:58 -0500888 interval="10 seconds")
Michael Walsh6741f742017-02-20 16:16:38 -0600889
890 plug_in_setup()
891 rc, shell_rc, failed_plug_in_name = \
892 grpi.rprocess_plug_in_packages(call_point="post_boot")
893 if rc != 0:
894 error_message = "Plug-in failed with non-zero return code.\n" +\
Michael Walsh986d8ae2019-07-17 10:02:23 -0500895 gp.sprint_var(rc, fmt=gp.hexa())
Michael Walshf566fb12019-02-01 14:35:09 -0600896 set_default_siguser1()
Michael Walsh6741f742017-02-20 16:16:38 -0600897 BuiltIn().fail(gp.sprint_error(error_message))
898
Michael Walshf566fb12019-02-01 14:35:09 -0600899 # Restore original sigusr1 handler.
900 set_default_siguser1()
901
Michael Walsh6741f742017-02-20 16:16:38 -0600902
Michael Walsh6741f742017-02-20 16:16:38 -0600903def test_loop_body():
Michael Walsh6741f742017-02-20 16:16:38 -0600904 r"""
905 The main loop body for the loop in main_py.
906
907 Description of arguments:
908 boot_count The iteration number (starts at 1).
909 """
910
911 global boot_count
912 global state
913 global next_boot
914 global boot_success
Sunil M325eb542017-08-10 07:09:43 -0500915 global boot_end_time
Michael Walsh6741f742017-02-20 16:16:38 -0600916
Michael Walshb5839d02017-04-12 16:11:20 -0500917 gp.qprintn()
Michael Walsh6741f742017-02-20 16:16:38 -0600918
919 next_boot = select_boot()
Michael Walshb5839d02017-04-12 16:11:20 -0500920 if next_boot == "":
921 return True
Michael Walsh6741f742017-02-20 16:16:38 -0600922
Michael Walshb5839d02017-04-12 16:11:20 -0500923 boot_count += 1
924 gp.qprint_timen("Starting boot " + str(boot_count) + ".")
Michael Walsh6741f742017-02-20 16:16:38 -0600925
Michael Walshe0cf8d72017-05-17 13:20:46 -0500926 pre_boot_plug_in_setup()
Michael Walsh6741f742017-02-20 16:16:38 -0600927
928 cmd_buf = ["run_boot", next_boot]
929 boot_status, msg = BuiltIn().run_keyword_and_ignore_error(*cmd_buf)
930 if boot_status == "FAIL":
Michael Walshb5839d02017-04-12 16:11:20 -0500931 gp.qprint(msg)
Michael Walsh6741f742017-02-20 16:16:38 -0600932
Michael Walshb5839d02017-04-12 16:11:20 -0500933 gp.qprintn()
Michael Walsh6741f742017-02-20 16:16:38 -0600934 if boot_status == "PASS":
935 boot_success = 1
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -0500936 completion_msg = gp.sprint_timen("BOOT_SUCCESS: \"" + next_boot
937 + "\" succeeded.")
Michael Walsh6741f742017-02-20 16:16:38 -0600938 else:
939 boot_success = 0
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -0500940 completion_msg = gp.sprint_timen("BOOT_FAILED: \"" + next_boot
941 + "\" failed.")
Sunil M325eb542017-08-10 07:09:43 -0500942
943 # Set boot_end_time for use by plug-ins.
944 boot_end_time = completion_msg[1:33]
945 gp.qprint_var(boot_end_time)
946
947 gp.qprint(completion_msg)
Michael Walsh6741f742017-02-20 16:16:38 -0600948
949 boot_results.update(next_boot, boot_status)
950
951 plug_in_setup()
952 # NOTE: A post_test_case call point failure is NOT counted as a boot
953 # failure.
954 rc, shell_rc, failed_plug_in_name = grpi.rprocess_plug_in_packages(
Michael Walsh600876d2017-05-30 17:58:58 -0500955 call_point='post_test_case', stop_on_plug_in_failure=0)
Michael Walsh6741f742017-02-20 16:16:38 -0600956
957 plug_in_setup()
958 rc, shell_rc, failed_plug_in_name = grpi.rprocess_plug_in_packages(
Michael Walsh89de14a2018-10-01 16:51:37 -0500959 call_point='ffdc_check', shell_rc=dump_ffdc_rc(),
Michael Walsh6741f742017-02-20 16:16:38 -0600960 stop_on_plug_in_failure=1, stop_on_non_zero_rc=1)
Michael Walsh12059e22019-03-21 11:03:45 -0500961 if ffdc_check == "All" or\
Michael Walsh89de14a2018-10-01 16:51:37 -0500962 shell_rc == dump_ffdc_rc():
Michael Walsh83f4bc72017-04-20 16:49:43 -0500963 status, ret_values = grk.run_key_u("my_ffdc", ignore=1)
964 if status != 'PASS':
Michael Walshff340002017-08-29 11:18:27 -0500965 gp.qprint_error("Call to my_ffdc failed.\n")
Michael Walshc9bd2e82019-04-18 11:06:52 -0500966 # Leave a record for caller that "soft" errors occurred.
967 soft_errors = 1
968 gpu.save_plug_in_value(soft_errors, pgm_name)
Michael Walsh6741f742017-02-20 16:16:38 -0600969
Michael Walshaabef1e2017-09-20 15:16:17 -0500970 if delete_errlogs:
Michael Shepos1a67b082020-08-28 16:01:58 -0500971 # print error logs before delete
972 status, error_logs = grk.run_key_u("Get Error Logs")
973 pels = pel.peltool("-l", ignore_err=1)
Michael Shepos0e5f1132020-09-30 16:24:25 -0500974 log.print_error_logs(error_logs, "AdditionalData Message Severity")
975 gp.qprint_var(pels)
Michael Shepos1a67b082020-08-28 16:01:58 -0500976
Michael Walshaabef1e2017-09-20 15:16:17 -0500977 # We need to purge error logs between boots or they build up.
Michael Walsh409ad352020-02-06 11:46:35 -0600978 grk.run_key(delete_errlogs_cmd, ignore=1)
Michael Walshd139f282017-04-04 18:00:23 -0500979
Michael Walsh952f9b02017-03-09 13:11:14 -0600980 boot_results.print_report()
Michael Walshb5839d02017-04-12 16:11:20 -0500981 gp.qprint_timen("Finished boot " + str(boot_count) + ".")
Michael Walsh952f9b02017-03-09 13:11:14 -0600982
Michael Walsh6741f742017-02-20 16:16:38 -0600983 plug_in_setup()
984 rc, shell_rc, failed_plug_in_name = grpi.rprocess_plug_in_packages(
Michael Walsh89de14a2018-10-01 16:51:37 -0500985 call_point='stop_check', shell_rc=stop_test_rc(),
986 stop_on_non_zero_rc=1)
987 if shell_rc == stop_test_rc():
Michael Walsh3ba8ecd2018-04-24 11:33:25 -0500988 message = "Stopping as requested by user.\n"
Michael Walsh80dddde2019-10-22 13:54:38 -0500989 gp.qprint_time(message)
Michael Walsh3ba8ecd2018-04-24 11:33:25 -0500990 BuiltIn().fail(message)
Michael Walsh6741f742017-02-20 16:16:38 -0600991
Michael Walshd139f282017-04-04 18:00:23 -0500992 # This should help prevent ConnectionErrors.
Michael Walsh0960b382017-06-22 16:23:37 -0500993 grk.run_key_u("Close All Connections")
Michael Walshd139f282017-04-04 18:00:23 -0500994
Michael Walsh6741f742017-02-20 16:16:38 -0600995 return True
996
Michael Walsh6741f742017-02-20 16:16:38 -0600997
Michael Walsh83f4bc72017-04-20 16:49:43 -0500998def obmc_boot_test_teardown():
Michael Walsh6741f742017-02-20 16:16:38 -0600999 r"""
Michael Walshf75d4352019-12-05 17:01:20 -06001000 Clean up after the main keyword.
Michael Walsh6741f742017-02-20 16:16:38 -06001001 """
Michael Walshf75d4352019-12-05 17:01:20 -06001002 gp.qprint_executing()
1003
1004 if ga.psutil_imported:
1005 ga.terminate_descendants()
Michael Walsh6741f742017-02-20 16:16:38 -06001006
1007 if cp_setup_called:
1008 plug_in_setup()
1009 rc, shell_rc, failed_plug_in_name = grpi.rprocess_plug_in_packages(
Michael Walsh600876d2017-05-30 17:58:58 -05001010 call_point='cleanup', stop_on_plug_in_failure=0)
Michael Walsh6741f742017-02-20 16:16:38 -06001011
Michael Walsh600876d2017-05-30 17:58:58 -05001012 if 'boot_results_file_path' in globals():
Michael Walsh986d8ae2019-07-17 10:02:23 -05001013 # Save boot_results and boot_history objects to a file in case they are
Michael Walsh6c645742018-08-17 15:02:17 -05001014 # needed again.
Michael Walsh600876d2017-05-30 17:58:58 -05001015 gp.qprint_timen("Saving boot_results to the following path.")
1016 gp.qprint_var(boot_results_file_path)
Michael Walsh986d8ae2019-07-17 10:02:23 -05001017 pickle.dump((boot_results, boot_history),
Michael Walsh6c645742018-08-17 15:02:17 -05001018 open(boot_results_file_path, 'wb'),
Michael Walsh600876d2017-05-30 17:58:58 -05001019 pickle.HIGHEST_PROTOCOL)
Michael Walsh0b93fbf2017-03-02 14:42:41 -06001020
Michael Walshff340002017-08-29 11:18:27 -05001021 global save_stack
1022 # Restore any global values saved on the save_stack.
1023 for parm_name in main_func_parm_list:
1024 # Get the parm_value if it was saved on the stack.
1025 try:
1026 parm_value = save_stack.pop(parm_name)
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -05001027 except BaseException:
Michael Walshff340002017-08-29 11:18:27 -05001028 # If it was not saved, no further action is required.
1029 continue
1030
1031 # Restore the saved value.
1032 cmd_buf = "BuiltIn().set_global_variable(\"${" + parm_name +\
1033 "}\", parm_value)"
1034 gp.dpissuing(cmd_buf)
1035 exec(cmd_buf)
1036
1037 gp.dprintn(save_stack.sprint_obj())
1038
Michael Walsh6741f742017-02-20 16:16:38 -06001039
Michael Walshc9116812017-03-10 14:23:06 -06001040def test_teardown():
Michael Walshc9116812017-03-10 14:23:06 -06001041 r"""
1042 Clean up after this test case.
1043 """
1044
1045 gp.qprintn()
Michael Walshf75d4352019-12-05 17:01:20 -06001046 gp.qprint_executing()
1047
1048 if ga.psutil_imported:
1049 ga.terminate_descendants()
1050
Michael Walshc9116812017-03-10 14:23:06 -06001051 cmd_buf = ["Print Error",
1052 "A keyword timeout occurred ending this program.\n"]
1053 BuiltIn().run_keyword_if_timeout_occurred(*cmd_buf)
1054
George Keishinga54e06f2020-06-12 10:42:41 -05001055 if redfish_supported:
1056 redfish.logout()
1057
Michael Walshc108e422019-03-28 12:27:18 -05001058 gp.qprint_pgm_footer()
Michael Walshb5839d02017-04-12 16:11:20 -05001059
Michael Walshc9116812017-03-10 14:23:06 -06001060
Michael Walsh89de14a2018-10-01 16:51:37 -05001061def post_stack():
1062 r"""
1063 Process post_stack plug-in programs.
1064 """
1065
1066 if not call_post_stack_plug:
1067 # The caller does not wish to have post_stack plug-in processing done.
1068 return
1069
1070 global boot_success
1071
1072 # NOTE: A post_stack call-point failure is NOT counted as a boot failure.
1073 pre_boot_plug_in_setup()
1074 # For the purposes of the following plug-ins, mark the "boot" as a success.
1075 boot_success = 1
1076 plug_in_setup()
Michael Walsh815b1d52018-10-30 13:32:26 -05001077 rc, shell_rc, failed_plug_in_name, history =\
1078 grpi.rprocess_plug_in_packages(call_point='post_stack',
1079 stop_on_plug_in_failure=0,
1080 return_history=True)
Michael Walsh986d8ae2019-07-17 10:02:23 -05001081 for doing_msg in history:
1082 update_boot_history(boot_history, doing_msg, max_boot_history)
Michael Walsh815b1d52018-10-30 13:32:26 -05001083 if rc != 0:
1084 boot_success = 0
Michael Walsh89de14a2018-10-01 16:51:37 -05001085
1086 plug_in_setup()
Michael Walsh815b1d52018-10-30 13:32:26 -05001087 rc, shell_rc, failed_plug_in_name =\
1088 grpi.rprocess_plug_in_packages(call_point='ffdc_check',
1089 shell_rc=dump_ffdc_rc(),
1090 stop_on_plug_in_failure=1,
1091 stop_on_non_zero_rc=1)
1092 if shell_rc == dump_ffdc_rc():
Michael Walsh89de14a2018-10-01 16:51:37 -05001093 status, ret_values = grk.run_key_u("my_ffdc", ignore=1)
1094 if status != 'PASS':
1095 gp.qprint_error("Call to my_ffdc failed.\n")
Michael Walshc9bd2e82019-04-18 11:06:52 -05001096 # Leave a record for caller that "soft" errors occurred.
1097 soft_errors = 1
1098 gpu.save_plug_in_value(soft_errors, pgm_name)
Michael Walsh89de14a2018-10-01 16:51:37 -05001099
1100 plug_in_setup()
1101 rc, shell_rc, failed_plug_in_name = grpi.rprocess_plug_in_packages(
1102 call_point='stop_check', shell_rc=stop_test_rc(),
1103 stop_on_non_zero_rc=1)
1104 if shell_rc == stop_test_rc():
1105 message = "Stopping as requested by user.\n"
Michael Walsh80dddde2019-10-22 13:54:38 -05001106 gp.qprint_time(message)
Michael Walsh89de14a2018-10-01 16:51:37 -05001107 BuiltIn().fail(message)
1108
1109
Michael Walshff340002017-08-29 11:18:27 -05001110def obmc_boot_test_py(loc_boot_stack=None,
1111 loc_stack_mode=None,
1112 loc_quiet=None):
Michael Walsh6741f742017-02-20 16:16:38 -06001113 r"""
1114 Do main program processing.
1115 """
1116
Michael Walshff340002017-08-29 11:18:27 -05001117 global save_stack
1118
Michael Walshf75d4352019-12-05 17:01:20 -06001119 ga.set_term_options(term_requests={'pgm_names': ['process_plug_in_packages.py']})
1120
George Keishing36efbc02018-12-12 10:18:23 -06001121 gp.dprintn()
Michael Walshff340002017-08-29 11:18:27 -05001122 # Process function parms.
1123 for parm_name in main_func_parm_list:
1124 # Get parm's value.
George Keishing36efbc02018-12-12 10:18:23 -06001125 parm_value = eval("loc_" + parm_name)
1126 gp.dpvars(parm_name, parm_value)
Michael Walshff340002017-08-29 11:18:27 -05001127
George Keishing36efbc02018-12-12 10:18:23 -06001128 if parm_value is not None:
Michael Walshff340002017-08-29 11:18:27 -05001129 # Save the global value on a stack.
1130 cmd_buf = "save_stack.push(BuiltIn().get_variable_value(\"${" +\
1131 parm_name + "}\"), \"" + parm_name + "\")"
1132 gp.dpissuing(cmd_buf)
1133 exec(cmd_buf)
1134
1135 # Set the global value to the passed value.
1136 cmd_buf = "BuiltIn().set_global_variable(\"${" + parm_name +\
1137 "}\", loc_" + parm_name + ")"
1138 gp.dpissuing(cmd_buf)
1139 exec(cmd_buf)
1140
1141 gp.dprintn(save_stack.sprint_obj())
Michael Walshb5839d02017-04-12 16:11:20 -05001142
Michael Walsh6741f742017-02-20 16:16:38 -06001143 setup()
1144
Michael Walshcd9fbfd2017-09-19 12:00:08 -05001145 init_boot_pass, init_boot_fail = boot_results.return_total_pass_fail()
1146
Michael Walsha20da402017-03-31 16:27:45 -05001147 if ffdc_only:
1148 gp.qprint_timen("Caller requested ffdc_only.")
Michael Walsh986d8ae2019-07-17 10:02:23 -05001149 if do_pre_boot_plug_in_setup:
1150 pre_boot_plug_in_setup()
Michael Walsh83f4bc72017-04-20 16:49:43 -05001151 grk.run_key_u("my_ffdc")
Michael Walsh764d2f82017-04-27 16:01:08 -05001152 return
Michael Walsha20da402017-03-31 16:27:45 -05001153
Michael Walsh409ad352020-02-06 11:46:35 -06001154 if delete_errlogs:
Michael Shepos1a67b082020-08-28 16:01:58 -05001155 # print error logs before delete
1156 status, error_logs = grk.run_key_u("Get Error Logs")
1157 pels = pel.peltool("-l", ignore_err=1)
Michael Shepos0e5f1132020-09-30 16:24:25 -05001158 log.print_error_logs(error_logs, "AdditionalData Message Severity")
1159 gp.qprint_var(pels)
Michael Shepos1a67b082020-08-28 16:01:58 -05001160
Michael Walsh409ad352020-02-06 11:46:35 -06001161 # Delete errlogs prior to doing any boot tests.
1162 grk.run_key(delete_errlogs_cmd, ignore=1)
1163
Michael Walsh6741f742017-02-20 16:16:38 -06001164 # Process caller's boot_stack.
1165 while (len(boot_stack) > 0):
1166 test_loop_body()
1167
Michael Walshb5839d02017-04-12 16:11:20 -05001168 gp.qprint_timen("Finished processing stack.")
Michael Walsh30dadae2017-02-27 14:25:52 -06001169
Michael Walsh89de14a2018-10-01 16:51:37 -05001170 post_stack()
1171
Michael Walsh6741f742017-02-20 16:16:38 -06001172 # Process caller's boot_list.
1173 if len(boot_list) > 0:
1174 for ix in range(1, max_num_tests + 1):
1175 test_loop_body()
1176
Michael Walshb5839d02017-04-12 16:11:20 -05001177 gp.qprint_timen("Completed all requested boot tests.")
1178
1179 boot_pass, boot_fail = boot_results.return_total_pass_fail()
Michael Walshcd9fbfd2017-09-19 12:00:08 -05001180 new_fail = boot_fail - init_boot_fail
1181 if new_fail > boot_fail_threshold:
Michael Walshb5839d02017-04-12 16:11:20 -05001182 error_message = "Boot failures exceed the boot failure" +\
1183 " threshold:\n" +\
Michael Walshcd9fbfd2017-09-19 12:00:08 -05001184 gp.sprint_var(new_fail) +\
Michael Walshb5839d02017-04-12 16:11:20 -05001185 gp.sprint_var(boot_fail_threshold)
1186 BuiltIn().fail(gp.sprint_error(error_message))