blob: a575d795b21cdaf1422580b67ab820d667f3efdc [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 Walsh6741f742017-02-20 16:16:38 -060026import gen_robot_valid as grv
27import gen_misc as gm
28import gen_cmd as gc
Michael Walshb5839d02017-04-12 16:11:20 -050029import gen_robot_keyword as grk
Michael Walsh55302292017-01-10 11:43:02 -060030import state as st
Michael Walshff340002017-08-29 11:18:27 -050031import var_stack as vs
Michael Walsh0bbd8602016-11-22 11:31:49 -060032
Michael Walsh0b93fbf2017-03-02 14:42:41 -060033base_path = os.path.dirname(os.path.dirname(
34 imp.find_module("gen_robot_print")[1])) +\
Michael Walshc9116812017-03-10 14:23:06 -060035 os.sep
Michael Walsh0b93fbf2017-03-02 14:42:41 -060036sys.path.append(base_path + "extended/")
37import run_keyword as rk
Michael Walsh0bbd8602016-11-22 11:31:49 -060038
Michael Walshe1e26442017-03-06 17:50:07 -060039# Setting master_pid correctly influences the behavior of plug-ins like
40# DB_Logging
41program_pid = os.getpid()
42master_pid = os.environ.get('AUTOBOOT_MASTER_PID', program_pid)
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -050043pgm_name = re.sub('\\.py$', '', os.path.basename(__file__))
Michael Walshe1e26442017-03-06 17:50:07 -060044
Michael Walshb5839d02017-04-12 16:11:20 -050045# Set up boot data structures.
46boot_table = create_boot_table()
47valid_boot_types = create_valid_boot_list(boot_table)
Michael Walsh0b93fbf2017-03-02 14:42:41 -060048
Michael Walsh6741f742017-02-20 16:16:38 -060049boot_lists = read_boot_lists()
Michael Walsh815b1d52018-10-30 13:32:26 -050050# The maximum number of entries that can be in the last_ten global variable.
51max_boot_history = 10
Michael Walsh6741f742017-02-20 16:16:38 -060052last_ten = []
Michael Walsh6741f742017-02-20 16:16:38 -060053
Michael Walsh7dc885b2018-03-14 17:51:59 -050054state = st.return_state_constant('default_state')
Michael Walsh6741f742017-02-20 16:16:38 -060055cp_setup_called = 0
56next_boot = ""
57base_tool_dir_path = os.path.normpath(os.environ.get(
58 'AUTOBOOT_BASE_TOOL_DIR_PATH', "/tmp")) + os.sep
Michael Walshb5839d02017-04-12 16:11:20 -050059
Michael Walsh6741f742017-02-20 16:16:38 -060060ffdc_dir_path = os.path.normpath(os.environ.get('FFDC_DIR_PATH', '')) + os.sep
Michael Walsh6741f742017-02-20 16:16:38 -060061boot_success = 0
Michael Walsh6741f742017-02-20 16:16:38 -060062status_dir_path = os.environ.get('STATUS_DIR_PATH', "")
63if status_dir_path != "":
64 status_dir_path = os.path.normpath(status_dir_path) + os.sep
Michael Walsh0b93fbf2017-03-02 14:42:41 -060065default_power_on = "REST Power On"
66default_power_off = "REST Power Off"
Michael Walsh6741f742017-02-20 16:16:38 -060067boot_count = 0
Michael Walsh0bbd8602016-11-22 11:31:49 -060068
Michael Walsh85678942017-03-27 14:34:22 -050069LOG_LEVEL = BuiltIn().get_variable_value("${LOG_LEVEL}")
Michael Walshe1974b92017-08-03 13:39:51 -050070ffdc_prefix = ""
Sunil M325eb542017-08-10 07:09:43 -050071boot_start_time = ""
72boot_end_time = ""
Michael Walshff340002017-08-29 11:18:27 -050073save_stack = vs.var_stack('save_stack')
74main_func_parm_list = ['boot_stack', 'stack_mode', 'quiet']
Michael Walsh85678942017-03-27 14:34:22 -050075
76
Michael Walsh89de14a2018-10-01 16:51:37 -050077def dump_ffdc_rc():
78 r"""
79 Return the constant dump ffdc test return code value.
80
81 When a plug-in call point program returns this value, it indicates that
82 this program should collect FFDC.
83 """
84
85 return 0x00000200
86
87
88def stop_test_rc():
89 r"""
90 Return the constant stop test return code value.
91
92 When a plug-in call point program returns this value, it indicates that
93 this program should stop running.
94 """
95
96 return 0x00000200
97
98
Michael Walsh0ad0f7f2017-05-04 14:39:58 -050099def process_host(host,
100 host_var_name=""):
Michael Walsh0ad0f7f2017-05-04 14:39:58 -0500101 r"""
102 Process a host by getting the associated host name and IP address and
103 setting them in global variables.
104
105 If the caller does not pass the host_var_name, this function will try to
106 figure out the name of the variable used by the caller for the host parm.
107 Callers are advised to explicitly specify the host_var_name when calling
108 with an exec command. In such cases, the get_arg_name cannot figure out
109 the host variable name.
110
111 This function will then create similar global variable names by
112 removing "_host" and appending "_host_name" or "_ip" to the host variable
113 name.
114
115 Example:
116
117 If a call is made like this:
118 process_host(openbmc_host)
119
120 Global variables openbmc_host_name and openbmc_ip will be set.
121
122 Description of argument(s):
123 host A host name or IP. The name of the variable used should
124 have a suffix of "_host".
125 host_var_name The name of the variable being used as the host parm.
126 """
127
128 if host_var_name == "":
129 host_var_name = gp.get_arg_name(0, 1, stack_frame_ix=2)
130
131 host_name_var_name = re.sub("host", "host_name", host_var_name)
132 ip_var_name = re.sub("host", "ip", host_var_name)
133 cmd_buf = "global " + host_name_var_name + ", " + ip_var_name + " ; " +\
134 host_name_var_name + ", " + ip_var_name + " = gm.get_host_name_ip('" +\
135 host + "')"
136 exec(cmd_buf)
137
Michael Walsh0ad0f7f2017-05-04 14:39:58 -0500138
Michael Walshb5839d02017-04-12 16:11:20 -0500139def process_pgm_parms():
Michael Walshb5839d02017-04-12 16:11:20 -0500140 r"""
141 Process the program parameters by assigning them all to corresponding
142 globals. Also, set some global values that depend on program parameters.
143 """
144
145 # Program parameter processing.
146 # Assign all program parms to python variables which are global to this
147 # module.
148
149 global parm_list
150 parm_list = BuiltIn().get_variable_value("${parm_list}")
151 # The following subset of parms should be processed as integers.
152 int_list = ['max_num_tests', 'boot_pass', 'boot_fail', 'ffdc_only',
Michael Walsh89de14a2018-10-01 16:51:37 -0500153 'boot_fail_threshold', 'delete_errlogs',
154 'call_post_stack_plug', 'quiet', 'test_mode', 'debug']
Michael Walshb5839d02017-04-12 16:11:20 -0500155 for parm in parm_list:
156 if parm in int_list:
157 sub_cmd = "int(BuiltIn().get_variable_value(\"${" + parm +\
158 "}\", \"0\"))"
159 else:
160 sub_cmd = "BuiltIn().get_variable_value(\"${" + parm + "}\")"
161 cmd_buf = "global " + parm + " ; " + parm + " = " + sub_cmd
Michael Walshff340002017-08-29 11:18:27 -0500162 gp.dpissuing(cmd_buf)
Michael Walshb5839d02017-04-12 16:11:20 -0500163 exec(cmd_buf)
Michael Walsh0ad0f7f2017-05-04 14:39:58 -0500164 if re.match(r".*_host$", parm):
165 cmd_buf = "process_host(" + parm + ", '" + parm + "')"
166 exec(cmd_buf)
167 if re.match(r".*_password$", parm):
168 # Register the value of any parm whose name ends in _password.
169 # This will cause the print functions to replace passwords with
170 # asterisks in the output.
171 cmd_buf = "gp.register_passwords(" + parm + ")"
172 exec(cmd_buf)
Michael Walshb5839d02017-04-12 16:11:20 -0500173
174 global ffdc_dir_path_style
175 global boot_list
176 global boot_stack
177 global boot_results_file_path
178 global boot_results
Michael Walsh6c645742018-08-17 15:02:17 -0500179 global last_ten
Michael Walshb5839d02017-04-12 16:11:20 -0500180 global ffdc_list_file_path
Michael Walshe0cf8d72017-05-17 13:20:46 -0500181 global ffdc_report_list_path
Michael Walsh600876d2017-05-30 17:58:58 -0500182 global ffdc_summary_list_path
Michael Walshb5839d02017-04-12 16:11:20 -0500183
184 if ffdc_dir_path_style == "":
185 ffdc_dir_path_style = int(os.environ.get('FFDC_DIR_PATH_STYLE', '0'))
186
187 # Convert these program parms to lists for easier processing..
George Keishing36efbc02018-12-12 10:18:23 -0600188 boot_list = list(filter(None, boot_list.split(":")))
189 boot_stack = list(filter(None, boot_stack.split(":")))
Michael Walshb5839d02017-04-12 16:11:20 -0500190
Michael Walsh903e0b22017-09-19 17:00:33 -0500191 cleanup_boot_results_file()
192 boot_results_file_path = create_boot_results_file_path(pgm_name,
193 openbmc_nickname,
194 master_pid)
Michael Walshb5839d02017-04-12 16:11:20 -0500195
196 if os.path.isfile(boot_results_file_path):
197 # We've been called before in this run so we'll load the saved
Michael Walsh6c645742018-08-17 15:02:17 -0500198 # boot_results and last_ten objects.
199 boot_results, last_ten =\
200 pickle.load(open(boot_results_file_path, 'rb'))
Michael Walshb5839d02017-04-12 16:11:20 -0500201 else:
202 boot_results = boot_results(boot_table, boot_pass, boot_fail)
203
204 ffdc_list_file_path = base_tool_dir_path + openbmc_nickname +\
205 "/FFDC_FILE_LIST"
Michael Walshe0cf8d72017-05-17 13:20:46 -0500206 ffdc_report_list_path = base_tool_dir_path + openbmc_nickname +\
207 "/FFDC_REPORT_FILE_LIST"
Michael Walshb5839d02017-04-12 16:11:20 -0500208
Michael Walsh600876d2017-05-30 17:58:58 -0500209 ffdc_summary_list_path = base_tool_dir_path + openbmc_nickname +\
210 "/FFDC_SUMMARY_FILE_LIST"
211
Michael Walshb5839d02017-04-12 16:11:20 -0500212
Michael Walsh85678942017-03-27 14:34:22 -0500213def initial_plug_in_setup():
Michael Walsh85678942017-03-27 14:34:22 -0500214 r"""
215 Initialize all plug-in environment variables which do not change for the
216 duration of the program.
217
218 """
219
220 global LOG_LEVEL
221 BuiltIn().set_log_level("NONE")
222
223 BuiltIn().set_global_variable("${master_pid}", master_pid)
224 BuiltIn().set_global_variable("${FFDC_DIR_PATH}", ffdc_dir_path)
225 BuiltIn().set_global_variable("${STATUS_DIR_PATH}", status_dir_path)
226 BuiltIn().set_global_variable("${BASE_TOOL_DIR_PATH}", base_tool_dir_path)
227 BuiltIn().set_global_variable("${FFDC_LIST_FILE_PATH}",
228 ffdc_list_file_path)
Michael Walshe0cf8d72017-05-17 13:20:46 -0500229 BuiltIn().set_global_variable("${FFDC_REPORT_LIST_PATH}",
230 ffdc_report_list_path)
Michael Walsh600876d2017-05-30 17:58:58 -0500231 BuiltIn().set_global_variable("${FFDC_SUMMARY_LIST_PATH}",
232 ffdc_summary_list_path)
Michael Walsh85678942017-03-27 14:34:22 -0500233
234 BuiltIn().set_global_variable("${FFDC_DIR_PATH_STYLE}",
235 ffdc_dir_path_style)
236 BuiltIn().set_global_variable("${FFDC_CHECK}",
237 ffdc_check)
238
239 # For each program parameter, set the corresponding AUTOBOOT_ environment
240 # variable value. Also, set an AUTOBOOT_ environment variable for every
241 # element in additional_values.
242 additional_values = ["program_pid", "master_pid", "ffdc_dir_path",
243 "status_dir_path", "base_tool_dir_path",
Michael Walsh600876d2017-05-30 17:58:58 -0500244 "ffdc_list_file_path", "ffdc_report_list_path",
Michael Walsh0a3bdb42019-01-31 16:21:44 +0000245 "ffdc_summary_list_path", "execdir"]
Michael Walsh85678942017-03-27 14:34:22 -0500246
247 plug_in_vars = parm_list + additional_values
248
249 for var_name in plug_in_vars:
250 var_value = BuiltIn().get_variable_value("${" + var_name + "}")
251 var_name = var_name.upper()
252 if var_value is None:
253 var_value = ""
254 os.environ["AUTOBOOT_" + var_name] = str(var_value)
255
256 BuiltIn().set_log_level(LOG_LEVEL)
257
Michael Walsh68a61162017-04-25 11:54:06 -0500258 # Make sure the ffdc list directory exists.
259 ffdc_list_dir_path = os.path.dirname(ffdc_list_file_path) + os.sep
260 if not os.path.exists(ffdc_list_dir_path):
261 os.makedirs(ffdc_list_dir_path)
Michael Walsh85678942017-03-27 14:34:22 -0500262
Michael Walsh85678942017-03-27 14:34:22 -0500263
Michael Walsh0bbd8602016-11-22 11:31:49 -0600264def plug_in_setup():
Michael Walsh0bbd8602016-11-22 11:31:49 -0600265 r"""
Michael Walsh85678942017-03-27 14:34:22 -0500266 Initialize all changing plug-in environment variables for use by the
267 plug-in programs.
Michael Walsh0bbd8602016-11-22 11:31:49 -0600268 """
269
Michael Walsh85678942017-03-27 14:34:22 -0500270 global LOG_LEVEL
271 global test_really_running
272
273 BuiltIn().set_log_level("NONE")
274
Michael Walsh6741f742017-02-20 16:16:38 -0600275 boot_pass, boot_fail = boot_results.return_total_pass_fail()
Michael Walsh0bbd8602016-11-22 11:31:49 -0600276 if boot_pass > 1:
277 test_really_running = 1
278 else:
279 test_really_running = 0
280
Michael Walsh6741f742017-02-20 16:16:38 -0600281 BuiltIn().set_global_variable("${test_really_running}",
282 test_really_running)
283 BuiltIn().set_global_variable("${boot_type_desc}", next_boot)
Michael Walsh6741f742017-02-20 16:16:38 -0600284 BuiltIn().set_global_variable("${boot_pass}", boot_pass)
285 BuiltIn().set_global_variable("${boot_fail}", boot_fail)
286 BuiltIn().set_global_variable("${boot_success}", boot_success)
287 BuiltIn().set_global_variable("${ffdc_prefix}", ffdc_prefix)
Sunil M325eb542017-08-10 07:09:43 -0500288 BuiltIn().set_global_variable("${boot_start_time}", boot_start_time)
289 BuiltIn().set_global_variable("${boot_end_time}", boot_end_time)
Michael Walsh4c9a6452016-12-13 16:03:11 -0600290
Michael Walsh0bbd8602016-11-22 11:31:49 -0600291 # For each program parameter, set the corresponding AUTOBOOT_ environment
292 # variable value. Also, set an AUTOBOOT_ environment variable for every
293 # element in additional_values.
294 additional_values = ["boot_type_desc", "boot_success", "boot_pass",
Sunil M325eb542017-08-10 07:09:43 -0500295 "boot_fail", "test_really_running", "ffdc_prefix",
296 "boot_start_time", "boot_end_time"]
Michael Walsh0bbd8602016-11-22 11:31:49 -0600297
Michael Walsh85678942017-03-27 14:34:22 -0500298 plug_in_vars = additional_values
Michael Walsh0bbd8602016-11-22 11:31:49 -0600299
300 for var_name in plug_in_vars:
301 var_value = BuiltIn().get_variable_value("${" + var_name + "}")
302 var_name = var_name.upper()
303 if var_value is None:
304 var_value = ""
Michael Walsh6741f742017-02-20 16:16:38 -0600305 os.environ["AUTOBOOT_" + var_name] = str(var_value)
Michael Walsh0bbd8602016-11-22 11:31:49 -0600306
Michael Walsh0bbd8602016-11-22 11:31:49 -0600307 if debug:
Michael Walsh6741f742017-02-20 16:16:38 -0600308 shell_rc, out_buf = \
309 gc.cmd_fnc_u("printenv | egrep AUTOBOOT_ | sort -u")
Michael Walsh0bbd8602016-11-22 11:31:49 -0600310
Michael Walsh85678942017-03-27 14:34:22 -0500311 BuiltIn().set_log_level(LOG_LEVEL)
312
Michael Walsh0bbd8602016-11-22 11:31:49 -0600313
Michael Walshe0cf8d72017-05-17 13:20:46 -0500314def pre_boot_plug_in_setup():
315
316 # Clear the ffdc_list_file_path file. Plug-ins may now write to it.
317 try:
318 os.remove(ffdc_list_file_path)
319 except OSError:
320 pass
321
322 # Clear the ffdc_report_list_path file. Plug-ins may now write to it.
323 try:
324 os.remove(ffdc_report_list_path)
325 except OSError:
326 pass
327
Michael Walsh600876d2017-05-30 17:58:58 -0500328 # Clear the ffdc_summary_list_path file. Plug-ins may now write to it.
329 try:
330 os.remove(ffdc_summary_list_path)
331 except OSError:
332 pass
333
Michael Walshe1974b92017-08-03 13:39:51 -0500334 global ffdc_prefix
335
336 seconds = time.time()
337 loc_time = time.localtime(seconds)
338 time_string = time.strftime("%y%m%d.%H%M%S.", loc_time)
339
340 ffdc_prefix = openbmc_nickname + "." + time_string
341
Michael Walshe0cf8d72017-05-17 13:20:46 -0500342
Michael Walshf566fb12019-02-01 14:35:09 -0600343def default_sigusr1(signal_number=0,
344 frame=None):
345 r"""
346 Handle SIGUSR1 by doing nothing.
347
348 This function assists in debugging SIGUSR1 processing by printing messages
349 to stdout and to the log.html file.
350
351 Description of argument(s):
352 signal_number The signal number (should always be 10 for SIGUSR1).
353 frame The frame data.
354 """
355
356 gp.printn()
357 gp.print_executing()
358 gp.lprint_executing()
359
360
361def set_default_siguser1():
362 r"""
363 Set the default_sigusr1 function to be the SIGUSR1 handler.
364 """
365
366 gp.printn()
367 gp.print_executing()
368 gp.lprint_executing()
369 signal.signal(signal.SIGUSR1, default_sigusr1)
370
371
Michael Walsh6741f742017-02-20 16:16:38 -0600372def setup():
Michael Walsh0bbd8602016-11-22 11:31:49 -0600373 r"""
Michael Walsh6741f742017-02-20 16:16:38 -0600374 Do general program setup tasks.
Michael Walsh0bbd8602016-11-22 11:31:49 -0600375 """
376
Michael Walsh6741f742017-02-20 16:16:38 -0600377 global cp_setup_called
Michael Walsh81816742017-09-27 11:02:29 -0500378 global transitional_boot_selected
Michael Walsh0bbd8602016-11-22 11:31:49 -0600379
Michael Walshb5839d02017-04-12 16:11:20 -0500380 gp.qprintn()
381
Michael Walshf566fb12019-02-01 14:35:09 -0600382 set_default_siguser1()
Michael Walsh81816742017-09-27 11:02:29 -0500383 transitional_boot_selected = False
384
Michael Walsh83f4bc72017-04-20 16:49:43 -0500385 robot_pgm_dir_path = os.path.dirname(__file__) + os.sep
386 repo_bin_path = robot_pgm_dir_path.replace("/lib/", "/bin/")
Michael Walshd061c042017-05-23 14:46:57 -0500387 # If we can't find process_plug_in_packages.py, ssh_pw or
388 # validate_plug_ins.py, then we don't have our repo bin in PATH.
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -0500389 shell_rc, out_buf = gc.cmd_fnc_u("which process_plug_in_packages.py"
390 + " ssh_pw validate_plug_ins.py", quiet=1,
Michael Walshd061c042017-05-23 14:46:57 -0500391 print_output=0, show_err=0)
Michael Walshb5839d02017-04-12 16:11:20 -0500392 if shell_rc != 0:
Michael Walsh83f4bc72017-04-20 16:49:43 -0500393 os.environ['PATH'] = repo_bin_path + ":" + os.environ.get('PATH', "")
394 # Likewise, our repo lib subdir needs to be in sys.path and PYTHONPATH.
395 if robot_pgm_dir_path not in sys.path:
396 sys.path.append(robot_pgm_dir_path)
397 PYTHONPATH = os.environ.get("PYTHONPATH", "")
398 if PYTHONPATH == "":
399 os.environ['PYTHONPATH'] = robot_pgm_dir_path
400 else:
401 os.environ['PYTHONPATH'] = robot_pgm_dir_path + ":" + PYTHONPATH
Michael Walsh6741f742017-02-20 16:16:38 -0600402
403 validate_parms()
404
Michael Walshc108e422019-03-28 12:27:18 -0500405 gp.qprint_pgm_header()
Michael Walsh6741f742017-02-20 16:16:38 -0600406
George Keishingefc3ff22017-12-12 11:49:25 -0600407 grk.run_key("Set BMC Power Policy ALWAYS_POWER_OFF")
Michael Walsh11cfc8c2017-03-31 09:40:55 -0500408
Michael Walsh85678942017-03-27 14:34:22 -0500409 initial_plug_in_setup()
410
Michael Walsh6741f742017-02-20 16:16:38 -0600411 plug_in_setup()
412 rc, shell_rc, failed_plug_in_name = grpi.rprocess_plug_in_packages(
413 call_point='setup')
414 if rc != 0:
415 error_message = "Plug-in setup failed.\n"
Michael Walshc108e422019-03-28 12:27:18 -0500416 gp.print_error_report(error_message)
Michael Walsh6741f742017-02-20 16:16:38 -0600417 BuiltIn().fail(error_message)
418 # Setting cp_setup_called lets our Teardown know that it needs to call
419 # the cleanup plug-in call point.
420 cp_setup_called = 1
421
422 # Keyword "FFDC" will fail if TEST_MESSAGE is not set.
423 BuiltIn().set_global_variable("${TEST_MESSAGE}", "${EMPTY}")
Michael Walsh85678942017-03-27 14:34:22 -0500424 # FFDC_LOG_PATH is used by "FFDC" keyword.
425 BuiltIn().set_global_variable("${FFDC_LOG_PATH}", ffdc_dir_path)
Michael Walsh6741f742017-02-20 16:16:38 -0600426
Michael Walshdc80d672017-05-09 12:58:32 -0500427 # Also printed by FFDC.
428 global host_name
429 global host_ip
430 host = socket.gethostname()
431 host_name, host_ip = gm.get_host_name_ip(host)
432
Michael Walshb5839d02017-04-12 16:11:20 -0500433 gp.dprint_var(boot_table, 1)
434 gp.dprint_var(boot_lists)
Michael Walsh0bbd8602016-11-22 11:31:49 -0600435
Michael Walsh0bbd8602016-11-22 11:31:49 -0600436
Michael Walsh6741f742017-02-20 16:16:38 -0600437def validate_parms():
Michael Walsh0bbd8602016-11-22 11:31:49 -0600438 r"""
Michael Walsh6741f742017-02-20 16:16:38 -0600439 Validate all program parameters.
Michael Walsh0bbd8602016-11-22 11:31:49 -0600440 """
441
Michael Walshb5839d02017-04-12 16:11:20 -0500442 process_pgm_parms()
Michael Walsh0bbd8602016-11-22 11:31:49 -0600443
Michael Walshb5839d02017-04-12 16:11:20 -0500444 gp.qprintn()
445
446 global openbmc_model
Michael Walsh6741f742017-02-20 16:16:38 -0600447 grv.rvalid_value("openbmc_host")
448 grv.rvalid_value("openbmc_username")
449 grv.rvalid_value("openbmc_password")
Michael Walsh0a3bdb42019-01-31 16:21:44 +0000450 grv.rvalid_value("rest_username")
451 grv.rvalid_value("rest_password")
452 grv.rvalid_value("ipmi_username")
453 grv.rvalid_value("ipmi_password")
Michael Walsh6741f742017-02-20 16:16:38 -0600454 if os_host != "":
455 grv.rvalid_value("os_username")
456 grv.rvalid_value("os_password")
Michael Walsh0bbd8602016-11-22 11:31:49 -0600457
Michael Walsh6741f742017-02-20 16:16:38 -0600458 if pdu_host != "":
459 grv.rvalid_value("pdu_username")
460 grv.rvalid_value("pdu_password")
Michael Walsh85678942017-03-27 14:34:22 -0500461 grv.rvalid_integer("pdu_slot_no")
Michael Walsh6741f742017-02-20 16:16:38 -0600462 if openbmc_serial_host != "":
463 grv.rvalid_integer("openbmc_serial_port")
Michael Walshb5839d02017-04-12 16:11:20 -0500464 if openbmc_model == "":
465 status, ret_values =\
466 grk.run_key_u("Get BMC System Model")
467 openbmc_model = ret_values
468 BuiltIn().set_global_variable("${openbmc_model}", openbmc_model)
Michael Walsh6741f742017-02-20 16:16:38 -0600469 grv.rvalid_value("openbmc_model")
Michael Walshb5839d02017-04-12 16:11:20 -0500470 grv.rvalid_integer("max_num_tests")
Michael Walsh6741f742017-02-20 16:16:38 -0600471 grv.rvalid_integer("boot_pass")
472 grv.rvalid_integer("boot_fail")
473
474 plug_in_packages_list = grpi.rvalidate_plug_ins(plug_in_dir_paths)
475 BuiltIn().set_global_variable("${plug_in_packages_list}",
476 plug_in_packages_list)
477
Michael Walshb5839d02017-04-12 16:11:20 -0500478 grv.rvalid_value("stack_mode", valid_values=['normal', 'skip'])
Michael Walsha20da402017-03-31 16:27:45 -0500479 if len(boot_list) == 0 and len(boot_stack) == 0 and not ffdc_only:
Michael Walsh6741f742017-02-20 16:16:38 -0600480 error_message = "You must provide either a value for either the" +\
481 " boot_list or the boot_stack parm.\n"
482 BuiltIn().fail(gp.sprint_error(error_message))
483
484 valid_boot_list(boot_list, valid_boot_types)
485 valid_boot_list(boot_stack, valid_boot_types)
486
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -0500487 selected_PDU_boots = list(set(boot_list + boot_stack)
488 & set(boot_lists['PDU_reboot']))
Michael Walsh11cfc8c2017-03-31 09:40:55 -0500489
490 if len(selected_PDU_boots) > 0 and pdu_host == "":
491 error_message = "You have selected the following boots which" +\
492 " require a PDU host but no value for pdu_host:\n"
493 error_message += gp.sprint_var(selected_PDU_boots)
494 error_message += gp.sprint_var(pdu_host, 2)
495 BuiltIn().fail(gp.sprint_error(error_message))
496
Michael Walsh6741f742017-02-20 16:16:38 -0600497 return
Michael Walsh0bbd8602016-11-22 11:31:49 -0600498
Michael Walsh0bbd8602016-11-22 11:31:49 -0600499
Michael Walsh6741f742017-02-20 16:16:38 -0600500def my_get_state():
Michael Walsh0bbd8602016-11-22 11:31:49 -0600501 r"""
Michael Walsh6741f742017-02-20 16:16:38 -0600502 Get the system state plus a little bit of wrapping.
Michael Walsh0bbd8602016-11-22 11:31:49 -0600503 """
504
Michael Walsh6741f742017-02-20 16:16:38 -0600505 global state
506
507 req_states = ['epoch_seconds'] + st.default_req_states
508
Michael Walshb5839d02017-04-12 16:11:20 -0500509 gp.qprint_timen("Getting system state.")
Michael Walsh6741f742017-02-20 16:16:38 -0600510 if test_mode:
511 state['epoch_seconds'] = int(time.time())
512 else:
Michael Walshb5839d02017-04-12 16:11:20 -0500513 state = st.get_state(req_states=req_states, quiet=quiet)
514 gp.qprint_var(state)
Michael Walsh341c21e2017-01-17 16:25:20 -0600515
Michael Walsh341c21e2017-01-17 16:25:20 -0600516
Michael Walsh45ca6e42017-09-14 17:29:12 -0500517def valid_state():
Michael Walsh45ca6e42017-09-14 17:29:12 -0500518 r"""
519 Verify that our state dictionary contains no blank values. If we don't get
520 valid state data, we cannot continue to work.
521 """
522
523 if st.compare_states(state, st.invalid_state_match, 'or'):
524 error_message = "The state dictionary contains blank fields which" +\
525 " is illegal.\n" + gp.sprint_var(state)
526 BuiltIn().fail(gp.sprint_error(error_message))
527
Michael Walsh45ca6e42017-09-14 17:29:12 -0500528
Michael Walsh6741f742017-02-20 16:16:38 -0600529def select_boot():
Michael Walsh341c21e2017-01-17 16:25:20 -0600530 r"""
531 Select a boot test to be run based on our current state and return the
532 chosen boot type.
533
534 Description of arguments:
Michael Walsh6741f742017-02-20 16:16:38 -0600535 state The state of the machine.
Michael Walsh341c21e2017-01-17 16:25:20 -0600536 """
537
Michael Walsh81816742017-09-27 11:02:29 -0500538 global transitional_boot_selected
Michael Walsh30dadae2017-02-27 14:25:52 -0600539 global boot_stack
540
Michael Walshb5839d02017-04-12 16:11:20 -0500541 gp.qprint_timen("Selecting a boot test.")
Michael Walsh6741f742017-02-20 16:16:38 -0600542
Michael Walsh81816742017-09-27 11:02:29 -0500543 if transitional_boot_selected and not boot_success:
544 prior_boot = next_boot
545 boot_candidate = boot_stack.pop()
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -0500546 gp.qprint_timen("The prior '" + next_boot + "' was chosen to"
547 + " transition to a valid state for '" + boot_candidate
548 + "' which was at the top of the boot_stack. Since"
549 + " the '" + next_boot + "' failed, the '"
550 + boot_candidate + "' has been removed from the stack"
551 + " to avoid and endless failure loop.")
Michael Walsh81816742017-09-27 11:02:29 -0500552 if len(boot_stack) == 0:
553 return ""
554
Michael Walsh6741f742017-02-20 16:16:38 -0600555 my_get_state()
Michael Walsh45ca6e42017-09-14 17:29:12 -0500556 valid_state()
Michael Walsh6741f742017-02-20 16:16:38 -0600557
Michael Walsh81816742017-09-27 11:02:29 -0500558 transitional_boot_selected = False
Michael Walsh6741f742017-02-20 16:16:38 -0600559 stack_popped = 0
560 if len(boot_stack) > 0:
561 stack_popped = 1
Michael Walshb5839d02017-04-12 16:11:20 -0500562 gp.qprint_dashes()
563 gp.qprint_var(boot_stack)
564 gp.qprint_dashes()
565 skip_boot_printed = 0
566 while len(boot_stack) > 0:
567 boot_candidate = boot_stack.pop()
568 if stack_mode == 'normal':
569 break
570 else:
571 if st.compare_states(state, boot_table[boot_candidate]['end']):
572 if not skip_boot_printed:
Michael Walshff340002017-08-29 11:18:27 -0500573 gp.qprint_var(stack_mode)
574 gp.qprintn()
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -0500575 gp.qprint_timen("Skipping the following boot tests"
576 + " which are unnecessary since their"
577 + " required end states match the"
578 + " current machine state:")
Michael Walshb5839d02017-04-12 16:11:20 -0500579 skip_boot_printed = 1
Michael Walshff340002017-08-29 11:18:27 -0500580 gp.qprint_var(boot_candidate)
Michael Walshb5839d02017-04-12 16:11:20 -0500581 boot_candidate = ""
582 if boot_candidate == "":
583 gp.qprint_dashes()
584 gp.qprint_var(boot_stack)
585 gp.qprint_dashes()
586 return boot_candidate
Michael Walsh6741f742017-02-20 16:16:38 -0600587 if st.compare_states(state, boot_table[boot_candidate]['start']):
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -0500588 gp.qprint_timen("The machine state is valid for a '"
589 + boot_candidate + "' boot test.")
Michael Walshb5839d02017-04-12 16:11:20 -0500590 gp.qprint_dashes()
591 gp.qprint_var(boot_stack)
592 gp.qprint_dashes()
Michael Walsh6741f742017-02-20 16:16:38 -0600593 return boot_candidate
Michael Walsh341c21e2017-01-17 16:25:20 -0600594 else:
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -0500595 gp.qprint_timen("The machine state does not match the required"
596 + " starting state for a '" + boot_candidate
597 + "' boot test:")
Michael Walshff340002017-08-29 11:18:27 -0500598 gp.qprint_varx("boot_table[" + boot_candidate + "][start]",
599 boot_table[boot_candidate]['start'], 1)
Michael Walsh6741f742017-02-20 16:16:38 -0600600 boot_stack.append(boot_candidate)
Michael Walsh81816742017-09-27 11:02:29 -0500601 transitional_boot_selected = True
Michael Walsh6741f742017-02-20 16:16:38 -0600602 popped_boot = boot_candidate
603
604 # Loop through your list selecting a boot_candidates
605 boot_candidates = []
606 for boot_candidate in boot_list:
607 if st.compare_states(state, boot_table[boot_candidate]['start']):
608 if stack_popped:
609 if st.compare_states(boot_table[boot_candidate]['end'],
Gunnar Mills096cd562018-03-26 10:19:12 -0500610 boot_table[popped_boot]['start']):
Michael Walsh6741f742017-02-20 16:16:38 -0600611 boot_candidates.append(boot_candidate)
612 else:
613 boot_candidates.append(boot_candidate)
614
615 if len(boot_candidates) == 0:
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -0500616 gp.qprint_timen("The user's boot list contained no boot tests"
617 + " which are valid for the current machine state.")
Michael Walsh6741f742017-02-20 16:16:38 -0600618 boot_candidate = default_power_on
619 if not st.compare_states(state, boot_table[default_power_on]['start']):
620 boot_candidate = default_power_off
621 boot_candidates.append(boot_candidate)
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -0500622 gp.qprint_timen("Using default '" + boot_candidate
623 + "' boot type to transition to valid state.")
Michael Walsh6741f742017-02-20 16:16:38 -0600624
Michael Walshb5839d02017-04-12 16:11:20 -0500625 gp.dprint_var(boot_candidates)
Michael Walsh6741f742017-02-20 16:16:38 -0600626
627 # Randomly select a boot from the candidate list.
628 boot = random.choice(boot_candidates)
Michael Walsh341c21e2017-01-17 16:25:20 -0600629
630 return boot
Michael Walsh0bbd8602016-11-22 11:31:49 -0600631
Michael Walsh55302292017-01-10 11:43:02 -0600632
Michael Walsh341c21e2017-01-17 16:25:20 -0600633def print_last_boots():
Michael Walsh341c21e2017-01-17 16:25:20 -0600634 r"""
635 Print the last ten boots done with their time stamps.
636 """
637
638 # indent 0, 90 chars wide, linefeed, char is "="
Michael Walshb5839d02017-04-12 16:11:20 -0500639 gp.qprint_dashes(0, 90)
640 gp.qprintn("Last 10 boots:\n")
Michael Walsh341c21e2017-01-17 16:25:20 -0600641
642 for boot_entry in last_ten:
Michael Walshc108e422019-03-28 12:27:18 -0500643 gp.qprint(boot_entry)
Michael Walshb5839d02017-04-12 16:11:20 -0500644 gp.qprint_dashes(0, 90)
Michael Walsh341c21e2017-01-17 16:25:20 -0600645
Michael Walsh341c21e2017-01-17 16:25:20 -0600646
Michael Walshb2e53ec2017-10-30 15:04:36 -0500647def print_defect_report(ffdc_file_list):
Michael Walsh341c21e2017-01-17 16:25:20 -0600648 r"""
649 Print a defect report.
Michael Walshb2e53ec2017-10-30 15:04:36 -0500650
651 Description of argument(s):
652 ffdc_file_list A list of files which were collected by our ffdc functions.
Michael Walsh341c21e2017-01-17 16:25:20 -0600653 """
654
Michael Walsh600876d2017-05-30 17:58:58 -0500655 # Making deliberate choice to NOT run plug_in_setup(). We don't want
656 # ffdc_prefix updated.
657 rc, shell_rc, failed_plug_in_name = grpi.rprocess_plug_in_packages(
658 call_point='ffdc_report', stop_on_plug_in_failure=0)
659
Michael Walshe0cf8d72017-05-17 13:20:46 -0500660 # Get additional header data which may have been created by ffdc plug-ins.
661 # Also, delete the individual header files to cleanup.
662 cmd_buf = "file_list=$(cat " + ffdc_report_list_path + " 2>/dev/null)" +\
663 " ; [ ! -z \"${file_list}\" ] && cat ${file_list}" +\
664 " 2>/dev/null ; rm -rf ${file_list} 2>/dev/null || :"
665 shell_rc, more_header_info = gc.cmd_fnc_u(cmd_buf, print_output=0,
666 show_err=0)
667
Michael Walshb2e53ec2017-10-30 15:04:36 -0500668 # Get additional summary data which may have been created by ffdc plug-ins.
Michael Walsh600876d2017-05-30 17:58:58 -0500669 # Also, delete the individual header files to cleanup.
670 cmd_buf = "file_list=$(cat " + ffdc_summary_list_path + " 2>/dev/null)" +\
671 " ; [ ! -z \"${file_list}\" ] && cat ${file_list}" +\
672 " 2>/dev/null ; rm -rf ${file_list} 2>/dev/null || :"
673 shell_rc, ffdc_summary_info = gc.cmd_fnc_u(cmd_buf, print_output=0,
674 show_err=0)
675
Michael Walshb2e53ec2017-10-30 15:04:36 -0500676 # ffdc_list_file_path contains a list of any ffdc files created by plug-
677 # ins, etc. Read that data into a list.
Michael Walsh341c21e2017-01-17 16:25:20 -0600678 try:
Michael Walshb2e53ec2017-10-30 15:04:36 -0500679 plug_in_ffdc_list = \
680 open(ffdc_list_file_path, 'r').read().rstrip("\n").split("\n")
George Keishing36efbc02018-12-12 10:18:23 -0600681 plug_in_ffdc_list = list(filter(None, plug_in_ffdc_list))
Michael Walsh341c21e2017-01-17 16:25:20 -0600682 except IOError:
Michael Walshb2e53ec2017-10-30 15:04:36 -0500683 plug_in_ffdc_list = []
684
685 # Combine the files from plug_in_ffdc_list with the ffdc_file_list passed
686 # in. Eliminate duplicates and sort the list.
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -0500687 ffdc_file_list = sorted(set(ffdc_file_list + plug_in_ffdc_list))
Michael Walshb2e53ec2017-10-30 15:04:36 -0500688
689 if status_file_path != "":
690 ffdc_file_list.insert(0, status_file_path)
691
692 # Convert the list to a printable list.
693 printable_ffdc_file_list = "\n".join(ffdc_file_list)
Michael Walsh341c21e2017-01-17 16:25:20 -0600694
Michael Walsh68a61162017-04-25 11:54:06 -0500695 # Open ffdc_file_list for writing. We will write a complete list of
696 # FFDC files to it for possible use by plug-ins like cp_stop_check.
697 ffdc_list_file = open(ffdc_list_file_path, 'w')
Michael Walshb2e53ec2017-10-30 15:04:36 -0500698 ffdc_list_file.write(printable_ffdc_file_list + "\n")
699 ffdc_list_file.close()
700
701 indent = 0
702 width = 90
703 linefeed = 1
704 char = "="
Michael Walsh68a61162017-04-25 11:54:06 -0500705
706 gp.qprintn()
Michael Walshb2e53ec2017-10-30 15:04:36 -0500707 gp.qprint_dashes(indent, width, linefeed, char)
Michael Walsh68a61162017-04-25 11:54:06 -0500708 gp.qprintn("Copy this data to the defect:\n")
709
Michael Walshe0cf8d72017-05-17 13:20:46 -0500710 if len(more_header_info) > 0:
Michael Walshff340002017-08-29 11:18:27 -0500711 gp.qprintn(more_header_info)
Michael Walshdc80d672017-05-09 12:58:32 -0500712 gp.qpvars(host_name, host_ip, openbmc_nickname, openbmc_host,
713 openbmc_host_name, openbmc_ip, openbmc_username,
Michael Walsh0a3bdb42019-01-31 16:21:44 +0000714 openbmc_password, rest_username, rest_password, ipmi_username,
715 ipmi_password, os_host, os_host_name, os_ip, os_username,
Michael Walshdc80d672017-05-09 12:58:32 -0500716 os_password, pdu_host, pdu_host_name, pdu_ip, pdu_username,
717 pdu_password, pdu_slot_no, openbmc_serial_host,
718 openbmc_serial_host_name, openbmc_serial_ip, openbmc_serial_port)
Michael Walsh68a61162017-04-25 11:54:06 -0500719
720 gp.qprintn()
Michael Walsh68a61162017-04-25 11:54:06 -0500721 print_last_boots()
722 gp.qprintn()
723 gp.qprint_var(state)
Michael Walshb5839d02017-04-12 16:11:20 -0500724 gp.qprintn()
725 gp.qprintn("FFDC data files:")
Michael Walshb2e53ec2017-10-30 15:04:36 -0500726 gp.qprintn(printable_ffdc_file_list)
Michael Walshb5839d02017-04-12 16:11:20 -0500727 gp.qprintn()
Michael Walsh341c21e2017-01-17 16:25:20 -0600728
Michael Walsh600876d2017-05-30 17:58:58 -0500729 if len(ffdc_summary_info) > 0:
Michael Walshff340002017-08-29 11:18:27 -0500730 gp.qprintn(ffdc_summary_info)
Michael Walsh600876d2017-05-30 17:58:58 -0500731
Michael Walshb2e53ec2017-10-30 15:04:36 -0500732 gp.qprint_dashes(indent, width, linefeed, char)
Michael Walsh68a61162017-04-25 11:54:06 -0500733
Michael Walsh6741f742017-02-20 16:16:38 -0600734
Michael Walsh6741f742017-02-20 16:16:38 -0600735def my_ffdc():
Michael Walsh6741f742017-02-20 16:16:38 -0600736 r"""
737 Collect FFDC data.
738 """
739
740 global state
741
742 plug_in_setup()
743 rc, shell_rc, failed_plug_in_name = grpi.rprocess_plug_in_packages(
Michael Walsh600876d2017-05-30 17:58:58 -0500744 call_point='ffdc', stop_on_plug_in_failure=0)
Michael Walsh6741f742017-02-20 16:16:38 -0600745
746 AUTOBOOT_FFDC_PREFIX = os.environ['AUTOBOOT_FFDC_PREFIX']
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -0500747 status, ffdc_file_list = grk.run_key_u("FFDC ffdc_prefix="
748 + AUTOBOOT_FFDC_PREFIX
749 + " ffdc_function_list="
750 + ffdc_function_list, ignore=1)
Michael Walsh83f4bc72017-04-20 16:49:43 -0500751 if status != 'PASS':
Michael Walshff340002017-08-29 11:18:27 -0500752 gp.qprint_error("Call to ffdc failed.\n")
Michael Walsh6741f742017-02-20 16:16:38 -0600753
754 my_get_state()
755
Michael Walshb2e53ec2017-10-30 15:04:36 -0500756 print_defect_report(ffdc_file_list)
Michael Walsh6741f742017-02-20 16:16:38 -0600757
Michael Walsh6741f742017-02-20 16:16:38 -0600758
Michael Walsh6741f742017-02-20 16:16:38 -0600759def print_test_start_message(boot_keyword):
Michael Walsh6741f742017-02-20 16:16:38 -0600760 r"""
761 Print a message indicating what boot test is about to run.
762
763 Description of arguments:
764 boot_keyword The name of the boot which is to be run
765 (e.g. "BMC Power On").
766 """
767
768 global last_ten
Sunil M325eb542017-08-10 07:09:43 -0500769 global boot_start_time
Michael Walsh6741f742017-02-20 16:16:38 -0600770
771 doing_msg = gp.sprint_timen("Doing \"" + boot_keyword + "\".")
Sunil M325eb542017-08-10 07:09:43 -0500772
773 # Set boot_start_time for use by plug-ins.
774 boot_start_time = doing_msg[1:33]
775 gp.qprint_var(boot_start_time)
776
Michael Walshb5839d02017-04-12 16:11:20 -0500777 gp.qprint(doing_msg)
Michael Walsh6741f742017-02-20 16:16:38 -0600778
779 last_ten.append(doing_msg)
780
Michael Walsh815b1d52018-10-30 13:32:26 -0500781 # Trim list to max number of entries.
782 del last_ten[:max(0, len(last_ten) - max_boot_history)]
Michael Walsh6741f742017-02-20 16:16:38 -0600783
Michael Walsh6741f742017-02-20 16:16:38 -0600784
Michael Walshf566fb12019-02-01 14:35:09 -0600785def stop_boot_test(signal_number=0,
786 frame=None):
787 r"""
788 Handle SIGUSR1 by aborting the boot test that is running.
789
790 Description of argument(s):
791 signal_number The signal number (should always be 10 for SIGUSR1).
792 frame The frame data.
793 """
794
795 gp.printn()
796 gp.print_executing()
797 gp.lprint_executing()
798
799 # Restore original sigusr1 handler.
800 set_default_siguser1()
801
802 message = "The caller has asked that the boot test be stopped and marked"
803 message += " as a failure."
804
805 function_stack = gm.get_function_stack()
806 if "wait_state" in function_stack:
807 st.set_wait_early_exit_message(message)
808 else:
809 BuiltIn().fail(gp.sprint_error(message))
810
811
Michael Walsh6741f742017-02-20 16:16:38 -0600812def run_boot(boot):
Michael Walsh6741f742017-02-20 16:16:38 -0600813 r"""
814 Run the specified boot.
815
816 Description of arguments:
817 boot The name of the boot test to be performed.
818 """
819
820 global state
821
Michael Walshf566fb12019-02-01 14:35:09 -0600822 signal.signal(signal.SIGUSR1, stop_boot_test)
823 gp.qprint_timen("stop_boot_test is armed.")
824
Michael Walsh6741f742017-02-20 16:16:38 -0600825 print_test_start_message(boot)
826
827 plug_in_setup()
828 rc, shell_rc, failed_plug_in_name = \
829 grpi.rprocess_plug_in_packages(call_point="pre_boot")
830 if rc != 0:
831 error_message = "Plug-in failed with non-zero return code.\n" +\
832 gp.sprint_var(rc, 1)
Michael Walshf566fb12019-02-01 14:35:09 -0600833 set_default_siguser1()
Michael Walsh6741f742017-02-20 16:16:38 -0600834 BuiltIn().fail(gp.sprint_error(error_message))
835
836 if test_mode:
837 # In test mode, we'll pretend the boot worked by assigning its
838 # required end state to the default state value.
Michael Walsh30dadae2017-02-27 14:25:52 -0600839 state = st.strip_anchor_state(boot_table[boot]['end'])
Michael Walsh6741f742017-02-20 16:16:38 -0600840 else:
841 # Assertion: We trust that the state data was made fresh by the
842 # caller.
843
Michael Walshb5839d02017-04-12 16:11:20 -0500844 gp.qprintn()
Michael Walsh6741f742017-02-20 16:16:38 -0600845
846 if boot_table[boot]['method_type'] == "keyword":
Michael Walsh0b93fbf2017-03-02 14:42:41 -0600847 rk.my_run_keywords(boot_table[boot].get('lib_file_path', ''),
Michael Walshb5839d02017-04-12 16:11:20 -0500848 boot_table[boot]['method'],
849 quiet=quiet)
Michael Walsh6741f742017-02-20 16:16:38 -0600850
851 if boot_table[boot]['bmc_reboot']:
852 st.wait_for_comm_cycle(int(state['epoch_seconds']))
Michael Walsh30dadae2017-02-27 14:25:52 -0600853 plug_in_setup()
854 rc, shell_rc, failed_plug_in_name = \
855 grpi.rprocess_plug_in_packages(call_point="post_reboot")
856 if rc != 0:
Michael Walsh0b93fbf2017-03-02 14:42:41 -0600857 error_message = "Plug-in failed with non-zero return code.\n"
858 error_message += gp.sprint_var(rc, 1)
Michael Walshf566fb12019-02-01 14:35:09 -0600859 set_default_siguser1()
Michael Walsh30dadae2017-02-27 14:25:52 -0600860 BuiltIn().fail(gp.sprint_error(error_message))
Michael Walsh6741f742017-02-20 16:16:38 -0600861 else:
862 match_state = st.anchor_state(state)
863 del match_state['epoch_seconds']
864 # Wait for the state to change in any way.
865 st.wait_state(match_state, wait_time=state_change_timeout,
Michael Walsh600876d2017-05-30 17:58:58 -0500866 interval="10 seconds", invert=1)
Michael Walsh6741f742017-02-20 16:16:38 -0600867
Michael Walshb5839d02017-04-12 16:11:20 -0500868 gp.qprintn()
Michael Walsh6741f742017-02-20 16:16:38 -0600869 if boot_table[boot]['end']['chassis'] == "Off":
870 boot_timeout = power_off_timeout
871 else:
872 boot_timeout = power_on_timeout
873 st.wait_state(boot_table[boot]['end'], wait_time=boot_timeout,
Michael Walsh600876d2017-05-30 17:58:58 -0500874 interval="10 seconds")
Michael Walsh6741f742017-02-20 16:16:38 -0600875
876 plug_in_setup()
877 rc, shell_rc, failed_plug_in_name = \
878 grpi.rprocess_plug_in_packages(call_point="post_boot")
879 if rc != 0:
880 error_message = "Plug-in failed with non-zero return code.\n" +\
881 gp.sprint_var(rc, 1)
Michael Walshf566fb12019-02-01 14:35:09 -0600882 set_default_siguser1()
Michael Walsh6741f742017-02-20 16:16:38 -0600883 BuiltIn().fail(gp.sprint_error(error_message))
884
Michael Walshf566fb12019-02-01 14:35:09 -0600885 # Restore original sigusr1 handler.
886 set_default_siguser1()
887
Michael Walsh6741f742017-02-20 16:16:38 -0600888
Michael Walsh6741f742017-02-20 16:16:38 -0600889def test_loop_body():
Michael Walsh6741f742017-02-20 16:16:38 -0600890 r"""
891 The main loop body for the loop in main_py.
892
893 Description of arguments:
894 boot_count The iteration number (starts at 1).
895 """
896
897 global boot_count
898 global state
899 global next_boot
900 global boot_success
Sunil M325eb542017-08-10 07:09:43 -0500901 global boot_end_time
Michael Walsh6741f742017-02-20 16:16:38 -0600902
Michael Walshb5839d02017-04-12 16:11:20 -0500903 gp.qprintn()
Michael Walsh6741f742017-02-20 16:16:38 -0600904
905 next_boot = select_boot()
Michael Walshb5839d02017-04-12 16:11:20 -0500906 if next_boot == "":
907 return True
Michael Walsh6741f742017-02-20 16:16:38 -0600908
Michael Walshb5839d02017-04-12 16:11:20 -0500909 boot_count += 1
910 gp.qprint_timen("Starting boot " + str(boot_count) + ".")
Michael Walsh6741f742017-02-20 16:16:38 -0600911
Michael Walshe0cf8d72017-05-17 13:20:46 -0500912 pre_boot_plug_in_setup()
Michael Walsh6741f742017-02-20 16:16:38 -0600913
914 cmd_buf = ["run_boot", next_boot]
915 boot_status, msg = BuiltIn().run_keyword_and_ignore_error(*cmd_buf)
916 if boot_status == "FAIL":
Michael Walshb5839d02017-04-12 16:11:20 -0500917 gp.qprint(msg)
Michael Walsh6741f742017-02-20 16:16:38 -0600918
Michael Walshb5839d02017-04-12 16:11:20 -0500919 gp.qprintn()
Michael Walsh6741f742017-02-20 16:16:38 -0600920 if boot_status == "PASS":
921 boot_success = 1
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -0500922 completion_msg = gp.sprint_timen("BOOT_SUCCESS: \"" + next_boot
923 + "\" succeeded.")
Michael Walsh6741f742017-02-20 16:16:38 -0600924 else:
925 boot_success = 0
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -0500926 completion_msg = gp.sprint_timen("BOOT_FAILED: \"" + next_boot
927 + "\" failed.")
Sunil M325eb542017-08-10 07:09:43 -0500928
929 # Set boot_end_time for use by plug-ins.
930 boot_end_time = completion_msg[1:33]
931 gp.qprint_var(boot_end_time)
932
933 gp.qprint(completion_msg)
Michael Walsh6741f742017-02-20 16:16:38 -0600934
935 boot_results.update(next_boot, boot_status)
936
937 plug_in_setup()
938 # NOTE: A post_test_case call point failure is NOT counted as a boot
939 # failure.
940 rc, shell_rc, failed_plug_in_name = grpi.rprocess_plug_in_packages(
Michael Walsh600876d2017-05-30 17:58:58 -0500941 call_point='post_test_case', stop_on_plug_in_failure=0)
Michael Walsh6741f742017-02-20 16:16:38 -0600942
943 plug_in_setup()
944 rc, shell_rc, failed_plug_in_name = grpi.rprocess_plug_in_packages(
Michael Walsh89de14a2018-10-01 16:51:37 -0500945 call_point='ffdc_check', shell_rc=dump_ffdc_rc(),
Michael Walsh6741f742017-02-20 16:16:38 -0600946 stop_on_plug_in_failure=1, stop_on_non_zero_rc=1)
Michael Walsh12059e22019-03-21 11:03:45 -0500947 if ffdc_check == "All" or\
Michael Walsh89de14a2018-10-01 16:51:37 -0500948 shell_rc == dump_ffdc_rc():
Michael Walsh83f4bc72017-04-20 16:49:43 -0500949 status, ret_values = grk.run_key_u("my_ffdc", ignore=1)
950 if status != 'PASS':
Michael Walshff340002017-08-29 11:18:27 -0500951 gp.qprint_error("Call to my_ffdc failed.\n")
Michael Walsh6741f742017-02-20 16:16:38 -0600952
Michael Walshaabef1e2017-09-20 15:16:17 -0500953 if delete_errlogs:
954 # We need to purge error logs between boots or they build up.
955 grk.run_key("Delete Error logs", ignore=1)
Michael Walshd139f282017-04-04 18:00:23 -0500956
Michael Walsh952f9b02017-03-09 13:11:14 -0600957 boot_results.print_report()
Michael Walshb5839d02017-04-12 16:11:20 -0500958 gp.qprint_timen("Finished boot " + str(boot_count) + ".")
Michael Walsh952f9b02017-03-09 13:11:14 -0600959
Michael Walsh6741f742017-02-20 16:16:38 -0600960 plug_in_setup()
961 rc, shell_rc, failed_plug_in_name = grpi.rprocess_plug_in_packages(
Michael Walsh89de14a2018-10-01 16:51:37 -0500962 call_point='stop_check', shell_rc=stop_test_rc(),
963 stop_on_non_zero_rc=1)
964 if shell_rc == stop_test_rc():
Michael Walsh3ba8ecd2018-04-24 11:33:25 -0500965 message = "Stopping as requested by user.\n"
966 gp.print_time(message)
967 BuiltIn().fail(message)
Michael Walsh6741f742017-02-20 16:16:38 -0600968
Michael Walshd139f282017-04-04 18:00:23 -0500969 # This should help prevent ConnectionErrors.
Michael Walsh0960b382017-06-22 16:23:37 -0500970 grk.run_key_u("Close All Connections")
Michael Walshd139f282017-04-04 18:00:23 -0500971
Michael Walsh6741f742017-02-20 16:16:38 -0600972 return True
973
Michael Walsh6741f742017-02-20 16:16:38 -0600974
Michael Walsh83f4bc72017-04-20 16:49:43 -0500975def obmc_boot_test_teardown():
Michael Walsh6741f742017-02-20 16:16:38 -0600976 r"""
Michael Walshc9116812017-03-10 14:23:06 -0600977 Clean up after the Main keyword.
Michael Walsh6741f742017-02-20 16:16:38 -0600978 """
979
980 if cp_setup_called:
981 plug_in_setup()
982 rc, shell_rc, failed_plug_in_name = grpi.rprocess_plug_in_packages(
Michael Walsh600876d2017-05-30 17:58:58 -0500983 call_point='cleanup', stop_on_plug_in_failure=0)
Michael Walsh6741f742017-02-20 16:16:38 -0600984
Michael Walsh600876d2017-05-30 17:58:58 -0500985 if 'boot_results_file_path' in globals():
Michael Walsh6c645742018-08-17 15:02:17 -0500986 # Save boot_results and last_ten objects to a file in case they are
987 # needed again.
Michael Walsh600876d2017-05-30 17:58:58 -0500988 gp.qprint_timen("Saving boot_results to the following path.")
989 gp.qprint_var(boot_results_file_path)
Michael Walsh6c645742018-08-17 15:02:17 -0500990 pickle.dump((boot_results, last_ten),
991 open(boot_results_file_path, 'wb'),
Michael Walsh600876d2017-05-30 17:58:58 -0500992 pickle.HIGHEST_PROTOCOL)
Michael Walsh0b93fbf2017-03-02 14:42:41 -0600993
Michael Walshff340002017-08-29 11:18:27 -0500994 global save_stack
995 # Restore any global values saved on the save_stack.
996 for parm_name in main_func_parm_list:
997 # Get the parm_value if it was saved on the stack.
998 try:
999 parm_value = save_stack.pop(parm_name)
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -05001000 except BaseException:
Michael Walshff340002017-08-29 11:18:27 -05001001 # If it was not saved, no further action is required.
1002 continue
1003
1004 # Restore the saved value.
1005 cmd_buf = "BuiltIn().set_global_variable(\"${" + parm_name +\
1006 "}\", parm_value)"
1007 gp.dpissuing(cmd_buf)
1008 exec(cmd_buf)
1009
1010 gp.dprintn(save_stack.sprint_obj())
1011
Michael Walsh6741f742017-02-20 16:16:38 -06001012
Michael Walshc9116812017-03-10 14:23:06 -06001013def test_teardown():
Michael Walshc9116812017-03-10 14:23:06 -06001014 r"""
1015 Clean up after this test case.
1016 """
1017
1018 gp.qprintn()
1019 cmd_buf = ["Print Error",
1020 "A keyword timeout occurred ending this program.\n"]
1021 BuiltIn().run_keyword_if_timeout_occurred(*cmd_buf)
1022
Michael Walshc108e422019-03-28 12:27:18 -05001023 gp.qprint_pgm_footer()
Michael Walshb5839d02017-04-12 16:11:20 -05001024
Michael Walshc9116812017-03-10 14:23:06 -06001025
Michael Walsh89de14a2018-10-01 16:51:37 -05001026def post_stack():
1027 r"""
1028 Process post_stack plug-in programs.
1029 """
1030
1031 if not call_post_stack_plug:
1032 # The caller does not wish to have post_stack plug-in processing done.
1033 return
1034
1035 global boot_success
1036
1037 # NOTE: A post_stack call-point failure is NOT counted as a boot failure.
1038 pre_boot_plug_in_setup()
1039 # For the purposes of the following plug-ins, mark the "boot" as a success.
1040 boot_success = 1
1041 plug_in_setup()
Michael Walsh815b1d52018-10-30 13:32:26 -05001042 rc, shell_rc, failed_plug_in_name, history =\
1043 grpi.rprocess_plug_in_packages(call_point='post_stack',
1044 stop_on_plug_in_failure=0,
1045 return_history=True)
1046 last_ten.extend(history)
1047 # Trim list to max number of entries.
1048 del last_ten[:max(0, len(last_ten) - max_boot_history)]
1049 if rc != 0:
1050 boot_success = 0
Michael Walsh89de14a2018-10-01 16:51:37 -05001051
1052 plug_in_setup()
Michael Walsh815b1d52018-10-30 13:32:26 -05001053 rc, shell_rc, failed_plug_in_name =\
1054 grpi.rprocess_plug_in_packages(call_point='ffdc_check',
1055 shell_rc=dump_ffdc_rc(),
1056 stop_on_plug_in_failure=1,
1057 stop_on_non_zero_rc=1)
1058 if shell_rc == dump_ffdc_rc():
Michael Walsh89de14a2018-10-01 16:51:37 -05001059 status, ret_values = grk.run_key_u("my_ffdc", ignore=1)
1060 if status != 'PASS':
1061 gp.qprint_error("Call to my_ffdc failed.\n")
1062
1063 plug_in_setup()
1064 rc, shell_rc, failed_plug_in_name = grpi.rprocess_plug_in_packages(
1065 call_point='stop_check', shell_rc=stop_test_rc(),
1066 stop_on_non_zero_rc=1)
1067 if shell_rc == stop_test_rc():
1068 message = "Stopping as requested by user.\n"
1069 gp.print_time(message)
1070 BuiltIn().fail(message)
1071
1072
Michael Walshff340002017-08-29 11:18:27 -05001073def obmc_boot_test_py(loc_boot_stack=None,
1074 loc_stack_mode=None,
1075 loc_quiet=None):
Michael Walsh6741f742017-02-20 16:16:38 -06001076 r"""
1077 Do main program processing.
1078 """
1079
Michael Walshff340002017-08-29 11:18:27 -05001080 global save_stack
1081
George Keishing36efbc02018-12-12 10:18:23 -06001082 gp.dprintn()
Michael Walshff340002017-08-29 11:18:27 -05001083 # Process function parms.
1084 for parm_name in main_func_parm_list:
1085 # Get parm's value.
George Keishing36efbc02018-12-12 10:18:23 -06001086 parm_value = eval("loc_" + parm_name)
1087 gp.dpvars(parm_name, parm_value)
Michael Walshff340002017-08-29 11:18:27 -05001088
George Keishing36efbc02018-12-12 10:18:23 -06001089 if parm_value is not None:
Michael Walshff340002017-08-29 11:18:27 -05001090 # Save the global value on a stack.
1091 cmd_buf = "save_stack.push(BuiltIn().get_variable_value(\"${" +\
1092 parm_name + "}\"), \"" + parm_name + "\")"
1093 gp.dpissuing(cmd_buf)
1094 exec(cmd_buf)
1095
1096 # Set the global value to the passed value.
1097 cmd_buf = "BuiltIn().set_global_variable(\"${" + parm_name +\
1098 "}\", loc_" + parm_name + ")"
1099 gp.dpissuing(cmd_buf)
1100 exec(cmd_buf)
1101
1102 gp.dprintn(save_stack.sprint_obj())
Michael Walshb5839d02017-04-12 16:11:20 -05001103
Michael Walsh6741f742017-02-20 16:16:38 -06001104 setup()
1105
Michael Walshcd9fbfd2017-09-19 12:00:08 -05001106 init_boot_pass, init_boot_fail = boot_results.return_total_pass_fail()
1107
Michael Walsha20da402017-03-31 16:27:45 -05001108 if ffdc_only:
1109 gp.qprint_timen("Caller requested ffdc_only.")
Michael Walshe0cf8d72017-05-17 13:20:46 -05001110 pre_boot_plug_in_setup()
Michael Walsh83f4bc72017-04-20 16:49:43 -05001111 grk.run_key_u("my_ffdc")
Michael Walsh764d2f82017-04-27 16:01:08 -05001112 return
Michael Walsha20da402017-03-31 16:27:45 -05001113
Michael Walsh6741f742017-02-20 16:16:38 -06001114 # Process caller's boot_stack.
1115 while (len(boot_stack) > 0):
1116 test_loop_body()
1117
Michael Walshb5839d02017-04-12 16:11:20 -05001118 gp.qprint_timen("Finished processing stack.")
Michael Walsh30dadae2017-02-27 14:25:52 -06001119
Michael Walsh89de14a2018-10-01 16:51:37 -05001120 post_stack()
1121
Michael Walsh6741f742017-02-20 16:16:38 -06001122 # Process caller's boot_list.
1123 if len(boot_list) > 0:
1124 for ix in range(1, max_num_tests + 1):
1125 test_loop_body()
1126
Michael Walshb5839d02017-04-12 16:11:20 -05001127 gp.qprint_timen("Completed all requested boot tests.")
1128
1129 boot_pass, boot_fail = boot_results.return_total_pass_fail()
Michael Walshcd9fbfd2017-09-19 12:00:08 -05001130 new_fail = boot_fail - init_boot_fail
1131 if new_fail > boot_fail_threshold:
Michael Walshb5839d02017-04-12 16:11:20 -05001132 error_message = "Boot failures exceed the boot failure" +\
1133 " threshold:\n" +\
Michael Walshcd9fbfd2017-09-19 12:00:08 -05001134 gp.sprint_var(new_fail) +\
Michael Walshb5839d02017-04-12 16:11:20 -05001135 gp.sprint_var(boot_fail_threshold)
1136 BuiltIn().fail(gp.sprint_error(error_message))