blob: 9927678ec793fc751bde07301acb4517f817f157 [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 Walshc9bd2e82019-04-18 11:06:52 -050032import gen_plug_in_utils as gpu
Michael Walsh0bbd8602016-11-22 11:31:49 -060033
Michael Walsh0b93fbf2017-03-02 14:42:41 -060034base_path = os.path.dirname(os.path.dirname(
35 imp.find_module("gen_robot_print")[1])) +\
Michael Walshc9116812017-03-10 14:23:06 -060036 os.sep
Michael Walsh0b93fbf2017-03-02 14:42:41 -060037sys.path.append(base_path + "extended/")
38import run_keyword as rk
Michael Walsh0bbd8602016-11-22 11:31:49 -060039
Michael Walshe1e26442017-03-06 17:50:07 -060040# Setting master_pid correctly influences the behavior of plug-ins like
41# DB_Logging
42program_pid = os.getpid()
43master_pid = os.environ.get('AUTOBOOT_MASTER_PID', program_pid)
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -050044pgm_name = re.sub('\\.py$', '', os.path.basename(__file__))
Michael Walshe1e26442017-03-06 17:50:07 -060045
Michael Walshb5839d02017-04-12 16:11:20 -050046# Set up boot data structures.
Michael Walsh986d8ae2019-07-17 10:02:23 -050047os_host = BuiltIn().get_variable_value("${OS_HOST}", default="")
48boot_table = create_boot_table(os_host=os_host)
Michael Walshb5839d02017-04-12 16:11:20 -050049valid_boot_types = create_valid_boot_list(boot_table)
Michael Walsh0b93fbf2017-03-02 14:42:41 -060050
Michael Walsh6741f742017-02-20 16:16:38 -060051boot_lists = read_boot_lists()
Michael Walsh986d8ae2019-07-17 10:02:23 -050052
53# The maximum number of entries that can be in the boot_history global variable.
Michael Walsh815b1d52018-10-30 13:32:26 -050054max_boot_history = 10
Michael Walsh986d8ae2019-07-17 10:02:23 -050055boot_history = []
Michael Walsh6741f742017-02-20 16:16:38 -060056
Michael Walsh7dc885b2018-03-14 17:51:59 -050057state = st.return_state_constant('default_state')
Michael Walsh6741f742017-02-20 16:16:38 -060058cp_setup_called = 0
59next_boot = ""
60base_tool_dir_path = os.path.normpath(os.environ.get(
61 'AUTOBOOT_BASE_TOOL_DIR_PATH', "/tmp")) + os.sep
Michael Walshb5839d02017-04-12 16:11:20 -050062
Michael Walsh6741f742017-02-20 16:16:38 -060063ffdc_dir_path = os.path.normpath(os.environ.get('FFDC_DIR_PATH', '')) + os.sep
Michael Walsh6741f742017-02-20 16:16:38 -060064boot_success = 0
Michael Walsh6741f742017-02-20 16:16:38 -060065status_dir_path = os.environ.get('STATUS_DIR_PATH', "")
66if status_dir_path != "":
67 status_dir_path = os.path.normpath(status_dir_path) + os.sep
Michael Walsh0b93fbf2017-03-02 14:42:41 -060068default_power_on = "REST Power On"
69default_power_off = "REST Power Off"
Michael Walsh6741f742017-02-20 16:16:38 -060070boot_count = 0
Michael Walsh0bbd8602016-11-22 11:31:49 -060071
Michael Walsh85678942017-03-27 14:34:22 -050072LOG_LEVEL = BuiltIn().get_variable_value("${LOG_LEVEL}")
Michael Walsh986d8ae2019-07-17 10:02:23 -050073AUTOBOOT_FFDC_PREFIX = os.environ.get('AUTOBOOT_FFDC_PREFIX', '')
74ffdc_prefix = AUTOBOOT_FFDC_PREFIX
Sunil M325eb542017-08-10 07:09:43 -050075boot_start_time = ""
76boot_end_time = ""
Michael Walshff340002017-08-29 11:18:27 -050077save_stack = vs.var_stack('save_stack')
78main_func_parm_list = ['boot_stack', 'stack_mode', 'quiet']
Michael Walsh85678942017-03-27 14:34:22 -050079
80
Michael Walsh89de14a2018-10-01 16:51:37 -050081def dump_ffdc_rc():
82 r"""
83 Return the constant dump ffdc test return code value.
84
85 When a plug-in call point program returns this value, it indicates that
86 this program should collect FFDC.
87 """
88
89 return 0x00000200
90
91
92def stop_test_rc():
93 r"""
94 Return the constant stop test return code value.
95
96 When a plug-in call point program returns this value, it indicates that
97 this program should stop running.
98 """
99
100 return 0x00000200
101
102
Michael Walsh0ad0f7f2017-05-04 14:39:58 -0500103def process_host(host,
104 host_var_name=""):
Michael Walsh0ad0f7f2017-05-04 14:39:58 -0500105 r"""
106 Process a host by getting the associated host name and IP address and
107 setting them in global variables.
108
109 If the caller does not pass the host_var_name, this function will try to
110 figure out the name of the variable used by the caller for the host parm.
111 Callers are advised to explicitly specify the host_var_name when calling
112 with an exec command. In such cases, the get_arg_name cannot figure out
113 the host variable name.
114
115 This function will then create similar global variable names by
116 removing "_host" and appending "_host_name" or "_ip" to the host variable
117 name.
118
119 Example:
120
121 If a call is made like this:
122 process_host(openbmc_host)
123
124 Global variables openbmc_host_name and openbmc_ip will be set.
125
126 Description of argument(s):
127 host A host name or IP. The name of the variable used should
128 have a suffix of "_host".
129 host_var_name The name of the variable being used as the host parm.
130 """
131
132 if host_var_name == "":
133 host_var_name = gp.get_arg_name(0, 1, stack_frame_ix=2)
134
135 host_name_var_name = re.sub("host", "host_name", host_var_name)
136 ip_var_name = re.sub("host", "ip", host_var_name)
137 cmd_buf = "global " + host_name_var_name + ", " + ip_var_name + " ; " +\
138 host_name_var_name + ", " + ip_var_name + " = gm.get_host_name_ip('" +\
139 host + "')"
140 exec(cmd_buf)
141
Michael Walsh0ad0f7f2017-05-04 14:39:58 -0500142
Michael Walshb5839d02017-04-12 16:11:20 -0500143def process_pgm_parms():
Michael Walshb5839d02017-04-12 16:11:20 -0500144 r"""
145 Process the program parameters by assigning them all to corresponding
146 globals. Also, set some global values that depend on program parameters.
147 """
148
149 # Program parameter processing.
150 # Assign all program parms to python variables which are global to this
151 # module.
152
153 global parm_list
154 parm_list = BuiltIn().get_variable_value("${parm_list}")
155 # The following subset of parms should be processed as integers.
156 int_list = ['max_num_tests', 'boot_pass', 'boot_fail', 'ffdc_only',
Michael Walsh89de14a2018-10-01 16:51:37 -0500157 'boot_fail_threshold', 'delete_errlogs',
Michael Walsh986d8ae2019-07-17 10:02:23 -0500158 'call_post_stack_plug', 'do_pre_boot_plug_in_setup', 'quiet',
159 'test_mode', 'debug']
Michael Walshb5839d02017-04-12 16:11:20 -0500160 for parm in parm_list:
161 if parm in int_list:
162 sub_cmd = "int(BuiltIn().get_variable_value(\"${" + parm +\
163 "}\", \"0\"))"
164 else:
165 sub_cmd = "BuiltIn().get_variable_value(\"${" + parm + "}\")"
166 cmd_buf = "global " + parm + " ; " + parm + " = " + sub_cmd
Michael Walshff340002017-08-29 11:18:27 -0500167 gp.dpissuing(cmd_buf)
Michael Walshb5839d02017-04-12 16:11:20 -0500168 exec(cmd_buf)
Michael Walsh0ad0f7f2017-05-04 14:39:58 -0500169 if re.match(r".*_host$", parm):
170 cmd_buf = "process_host(" + parm + ", '" + parm + "')"
171 exec(cmd_buf)
172 if re.match(r".*_password$", parm):
173 # Register the value of any parm whose name ends in _password.
174 # This will cause the print functions to replace passwords with
175 # asterisks in the output.
176 cmd_buf = "gp.register_passwords(" + parm + ")"
177 exec(cmd_buf)
Michael Walshb5839d02017-04-12 16:11:20 -0500178
179 global ffdc_dir_path_style
180 global boot_list
181 global boot_stack
182 global boot_results_file_path
183 global boot_results
Michael Walsh986d8ae2019-07-17 10:02:23 -0500184 global boot_history
Michael Walshb5839d02017-04-12 16:11:20 -0500185 global ffdc_list_file_path
Michael Walshe0cf8d72017-05-17 13:20:46 -0500186 global ffdc_report_list_path
Michael Walsh600876d2017-05-30 17:58:58 -0500187 global ffdc_summary_list_path
Michael Walshb5839d02017-04-12 16:11:20 -0500188
189 if ffdc_dir_path_style == "":
190 ffdc_dir_path_style = int(os.environ.get('FFDC_DIR_PATH_STYLE', '0'))
191
192 # Convert these program parms to lists for easier processing..
George Keishing36efbc02018-12-12 10:18:23 -0600193 boot_list = list(filter(None, boot_list.split(":")))
194 boot_stack = list(filter(None, boot_stack.split(":")))
Michael Walshb5839d02017-04-12 16:11:20 -0500195
Michael Walsh903e0b22017-09-19 17:00:33 -0500196 cleanup_boot_results_file()
197 boot_results_file_path = create_boot_results_file_path(pgm_name,
198 openbmc_nickname,
199 master_pid)
Michael Walshb5839d02017-04-12 16:11:20 -0500200
201 if os.path.isfile(boot_results_file_path):
202 # We've been called before in this run so we'll load the saved
Michael Walsh986d8ae2019-07-17 10:02:23 -0500203 # boot_results and boot_history objects.
204 boot_results, boot_history =\
Michael Walsh6c645742018-08-17 15:02:17 -0500205 pickle.load(open(boot_results_file_path, 'rb'))
Michael Walshb5839d02017-04-12 16:11:20 -0500206 else:
207 boot_results = boot_results(boot_table, boot_pass, boot_fail)
208
209 ffdc_list_file_path = base_tool_dir_path + openbmc_nickname +\
210 "/FFDC_FILE_LIST"
Michael Walshe0cf8d72017-05-17 13:20:46 -0500211 ffdc_report_list_path = base_tool_dir_path + openbmc_nickname +\
212 "/FFDC_REPORT_FILE_LIST"
Michael Walshb5839d02017-04-12 16:11:20 -0500213
Michael Walsh600876d2017-05-30 17:58:58 -0500214 ffdc_summary_list_path = base_tool_dir_path + openbmc_nickname +\
215 "/FFDC_SUMMARY_FILE_LIST"
216
Michael Walshb5839d02017-04-12 16:11:20 -0500217
Michael Walsh85678942017-03-27 14:34:22 -0500218def initial_plug_in_setup():
Michael Walsh85678942017-03-27 14:34:22 -0500219 r"""
220 Initialize all plug-in environment variables which do not change for the
221 duration of the program.
222
223 """
224
225 global LOG_LEVEL
226 BuiltIn().set_log_level("NONE")
227
228 BuiltIn().set_global_variable("${master_pid}", master_pid)
229 BuiltIn().set_global_variable("${FFDC_DIR_PATH}", ffdc_dir_path)
230 BuiltIn().set_global_variable("${STATUS_DIR_PATH}", status_dir_path)
231 BuiltIn().set_global_variable("${BASE_TOOL_DIR_PATH}", base_tool_dir_path)
232 BuiltIn().set_global_variable("${FFDC_LIST_FILE_PATH}",
233 ffdc_list_file_path)
Michael Walshe0cf8d72017-05-17 13:20:46 -0500234 BuiltIn().set_global_variable("${FFDC_REPORT_LIST_PATH}",
235 ffdc_report_list_path)
Michael Walsh600876d2017-05-30 17:58:58 -0500236 BuiltIn().set_global_variable("${FFDC_SUMMARY_LIST_PATH}",
237 ffdc_summary_list_path)
Michael Walsh85678942017-03-27 14:34:22 -0500238
239 BuiltIn().set_global_variable("${FFDC_DIR_PATH_STYLE}",
240 ffdc_dir_path_style)
241 BuiltIn().set_global_variable("${FFDC_CHECK}",
242 ffdc_check)
243
244 # For each program parameter, set the corresponding AUTOBOOT_ environment
245 # variable value. Also, set an AUTOBOOT_ environment variable for every
246 # element in additional_values.
247 additional_values = ["program_pid", "master_pid", "ffdc_dir_path",
248 "status_dir_path", "base_tool_dir_path",
Michael Walsh600876d2017-05-30 17:58:58 -0500249 "ffdc_list_file_path", "ffdc_report_list_path",
Michael Walsh0a3bdb42019-01-31 16:21:44 +0000250 "ffdc_summary_list_path", "execdir"]
Michael Walsh85678942017-03-27 14:34:22 -0500251
252 plug_in_vars = parm_list + additional_values
253
254 for var_name in plug_in_vars:
255 var_value = BuiltIn().get_variable_value("${" + var_name + "}")
256 var_name = var_name.upper()
257 if var_value is None:
258 var_value = ""
259 os.environ["AUTOBOOT_" + var_name] = str(var_value)
260
261 BuiltIn().set_log_level(LOG_LEVEL)
262
Michael Walsh68a61162017-04-25 11:54:06 -0500263 # Make sure the ffdc list directory exists.
264 ffdc_list_dir_path = os.path.dirname(ffdc_list_file_path) + os.sep
265 if not os.path.exists(ffdc_list_dir_path):
266 os.makedirs(ffdc_list_dir_path)
Michael Walsh85678942017-03-27 14:34:22 -0500267
Michael Walsh85678942017-03-27 14:34:22 -0500268
Michael Walsh0bbd8602016-11-22 11:31:49 -0600269def plug_in_setup():
Michael Walsh0bbd8602016-11-22 11:31:49 -0600270 r"""
Michael Walsh85678942017-03-27 14:34:22 -0500271 Initialize all changing plug-in environment variables for use by the
272 plug-in programs.
Michael Walsh0bbd8602016-11-22 11:31:49 -0600273 """
274
Michael Walsh85678942017-03-27 14:34:22 -0500275 global LOG_LEVEL
276 global test_really_running
277
278 BuiltIn().set_log_level("NONE")
279
Michael Walsh6741f742017-02-20 16:16:38 -0600280 boot_pass, boot_fail = boot_results.return_total_pass_fail()
Michael Walsh0bbd8602016-11-22 11:31:49 -0600281 if boot_pass > 1:
282 test_really_running = 1
283 else:
284 test_really_running = 0
285
Michael Walsh6741f742017-02-20 16:16:38 -0600286 BuiltIn().set_global_variable("${test_really_running}",
287 test_really_running)
288 BuiltIn().set_global_variable("${boot_type_desc}", next_boot)
Michael Walsh6741f742017-02-20 16:16:38 -0600289 BuiltIn().set_global_variable("${boot_pass}", boot_pass)
290 BuiltIn().set_global_variable("${boot_fail}", boot_fail)
291 BuiltIn().set_global_variable("${boot_success}", boot_success)
292 BuiltIn().set_global_variable("${ffdc_prefix}", ffdc_prefix)
Sunil M325eb542017-08-10 07:09:43 -0500293 BuiltIn().set_global_variable("${boot_start_time}", boot_start_time)
294 BuiltIn().set_global_variable("${boot_end_time}", boot_end_time)
Michael Walsh4c9a6452016-12-13 16:03:11 -0600295
Michael Walsh0bbd8602016-11-22 11:31:49 -0600296 # For each program parameter, set the corresponding AUTOBOOT_ environment
297 # variable value. Also, set an AUTOBOOT_ environment variable for every
298 # element in additional_values.
299 additional_values = ["boot_type_desc", "boot_success", "boot_pass",
Sunil M325eb542017-08-10 07:09:43 -0500300 "boot_fail", "test_really_running", "ffdc_prefix",
301 "boot_start_time", "boot_end_time"]
Michael Walsh0bbd8602016-11-22 11:31:49 -0600302
Michael Walsh85678942017-03-27 14:34:22 -0500303 plug_in_vars = additional_values
Michael Walsh0bbd8602016-11-22 11:31:49 -0600304
305 for var_name in plug_in_vars:
306 var_value = BuiltIn().get_variable_value("${" + var_name + "}")
307 var_name = var_name.upper()
308 if var_value is None:
309 var_value = ""
Michael Walsh6741f742017-02-20 16:16:38 -0600310 os.environ["AUTOBOOT_" + var_name] = str(var_value)
Michael Walsh0bbd8602016-11-22 11:31:49 -0600311
Michael Walsh0bbd8602016-11-22 11:31:49 -0600312 if debug:
Michael Walsh6741f742017-02-20 16:16:38 -0600313 shell_rc, out_buf = \
314 gc.cmd_fnc_u("printenv | egrep AUTOBOOT_ | sort -u")
Michael Walsh0bbd8602016-11-22 11:31:49 -0600315
Michael Walsh85678942017-03-27 14:34:22 -0500316 BuiltIn().set_log_level(LOG_LEVEL)
317
Michael Walsh0bbd8602016-11-22 11:31:49 -0600318
Michael Walshe0cf8d72017-05-17 13:20:46 -0500319def pre_boot_plug_in_setup():
320
321 # Clear the ffdc_list_file_path file. Plug-ins may now write to it.
322 try:
323 os.remove(ffdc_list_file_path)
324 except OSError:
325 pass
326
327 # Clear the ffdc_report_list_path file. Plug-ins may now write to it.
328 try:
329 os.remove(ffdc_report_list_path)
330 except OSError:
331 pass
332
Michael Walsh600876d2017-05-30 17:58:58 -0500333 # Clear the ffdc_summary_list_path file. Plug-ins may now write to it.
334 try:
335 os.remove(ffdc_summary_list_path)
336 except OSError:
337 pass
338
Michael Walshe1974b92017-08-03 13:39:51 -0500339 global ffdc_prefix
340
341 seconds = time.time()
342 loc_time = time.localtime(seconds)
343 time_string = time.strftime("%y%m%d.%H%M%S.", loc_time)
344
345 ffdc_prefix = openbmc_nickname + "." + time_string
346
Michael Walshe0cf8d72017-05-17 13:20:46 -0500347
Michael Walshf566fb12019-02-01 14:35:09 -0600348def default_sigusr1(signal_number=0,
349 frame=None):
350 r"""
351 Handle SIGUSR1 by doing nothing.
352
353 This function assists in debugging SIGUSR1 processing by printing messages
354 to stdout and to the log.html file.
355
356 Description of argument(s):
357 signal_number The signal number (should always be 10 for SIGUSR1).
358 frame The frame data.
359 """
360
361 gp.printn()
362 gp.print_executing()
363 gp.lprint_executing()
364
365
366def set_default_siguser1():
367 r"""
368 Set the default_sigusr1 function to be the SIGUSR1 handler.
369 """
370
371 gp.printn()
372 gp.print_executing()
373 gp.lprint_executing()
374 signal.signal(signal.SIGUSR1, default_sigusr1)
375
376
Michael Walsh6741f742017-02-20 16:16:38 -0600377def setup():
Michael Walsh0bbd8602016-11-22 11:31:49 -0600378 r"""
Michael Walsh6741f742017-02-20 16:16:38 -0600379 Do general program setup tasks.
Michael Walsh0bbd8602016-11-22 11:31:49 -0600380 """
381
Michael Walsh6741f742017-02-20 16:16:38 -0600382 global cp_setup_called
Michael Walsh81816742017-09-27 11:02:29 -0500383 global transitional_boot_selected
Michael Walsh0bbd8602016-11-22 11:31:49 -0600384
Michael Walshb5839d02017-04-12 16:11:20 -0500385 gp.qprintn()
386
Michael Walshf566fb12019-02-01 14:35:09 -0600387 set_default_siguser1()
Michael Walsh81816742017-09-27 11:02:29 -0500388 transitional_boot_selected = False
389
Michael Walsh83f4bc72017-04-20 16:49:43 -0500390 robot_pgm_dir_path = os.path.dirname(__file__) + os.sep
391 repo_bin_path = robot_pgm_dir_path.replace("/lib/", "/bin/")
Michael Walshd061c042017-05-23 14:46:57 -0500392 # If we can't find process_plug_in_packages.py, ssh_pw or
393 # validate_plug_ins.py, then we don't have our repo bin in PATH.
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -0500394 shell_rc, out_buf = gc.cmd_fnc_u("which process_plug_in_packages.py"
395 + " ssh_pw validate_plug_ins.py", quiet=1,
Michael Walshd061c042017-05-23 14:46:57 -0500396 print_output=0, show_err=0)
Michael Walshb5839d02017-04-12 16:11:20 -0500397 if shell_rc != 0:
Michael Walsh83f4bc72017-04-20 16:49:43 -0500398 os.environ['PATH'] = repo_bin_path + ":" + os.environ.get('PATH', "")
399 # Likewise, our repo lib subdir needs to be in sys.path and PYTHONPATH.
400 if robot_pgm_dir_path not in sys.path:
401 sys.path.append(robot_pgm_dir_path)
402 PYTHONPATH = os.environ.get("PYTHONPATH", "")
403 if PYTHONPATH == "":
404 os.environ['PYTHONPATH'] = robot_pgm_dir_path
405 else:
406 os.environ['PYTHONPATH'] = robot_pgm_dir_path + ":" + PYTHONPATH
Michael Walsh6741f742017-02-20 16:16:38 -0600407
408 validate_parms()
409
Michael Walshc108e422019-03-28 12:27:18 -0500410 gp.qprint_pgm_header()
Michael Walsh6741f742017-02-20 16:16:38 -0600411
George Keishingefc3ff22017-12-12 11:49:25 -0600412 grk.run_key("Set BMC Power Policy ALWAYS_POWER_OFF")
Michael Walsh11cfc8c2017-03-31 09:40:55 -0500413
Michael Walsh85678942017-03-27 14:34:22 -0500414 initial_plug_in_setup()
415
Michael Walsh6741f742017-02-20 16:16:38 -0600416 plug_in_setup()
417 rc, shell_rc, failed_plug_in_name = grpi.rprocess_plug_in_packages(
418 call_point='setup')
419 if rc != 0:
420 error_message = "Plug-in setup failed.\n"
Michael Walshc108e422019-03-28 12:27:18 -0500421 gp.print_error_report(error_message)
Michael Walsh6741f742017-02-20 16:16:38 -0600422 BuiltIn().fail(error_message)
423 # Setting cp_setup_called lets our Teardown know that it needs to call
424 # the cleanup plug-in call point.
425 cp_setup_called = 1
426
427 # Keyword "FFDC" will fail if TEST_MESSAGE is not set.
428 BuiltIn().set_global_variable("${TEST_MESSAGE}", "${EMPTY}")
Michael Walsh85678942017-03-27 14:34:22 -0500429 # FFDC_LOG_PATH is used by "FFDC" keyword.
430 BuiltIn().set_global_variable("${FFDC_LOG_PATH}", ffdc_dir_path)
Michael Walsh6741f742017-02-20 16:16:38 -0600431
Michael Walshdc80d672017-05-09 12:58:32 -0500432 # Also printed by FFDC.
433 global host_name
434 global host_ip
435 host = socket.gethostname()
436 host_name, host_ip = gm.get_host_name_ip(host)
437
Michael Walsh986d8ae2019-07-17 10:02:23 -0500438 gp.dprint_var(boot_table)
Michael Walshb5839d02017-04-12 16:11:20 -0500439 gp.dprint_var(boot_lists)
Michael Walsh0bbd8602016-11-22 11:31:49 -0600440
Michael Walsh0bbd8602016-11-22 11:31:49 -0600441
Michael Walsh6741f742017-02-20 16:16:38 -0600442def validate_parms():
Michael Walsh0bbd8602016-11-22 11:31:49 -0600443 r"""
Michael Walsh6741f742017-02-20 16:16:38 -0600444 Validate all program parameters.
Michael Walsh0bbd8602016-11-22 11:31:49 -0600445 """
446
Michael Walshb5839d02017-04-12 16:11:20 -0500447 process_pgm_parms()
Michael Walsh0bbd8602016-11-22 11:31:49 -0600448
Michael Walshb5839d02017-04-12 16:11:20 -0500449 gp.qprintn()
450
451 global openbmc_model
Michael Walsh6741f742017-02-20 16:16:38 -0600452 grv.rvalid_value("openbmc_host")
453 grv.rvalid_value("openbmc_username")
454 grv.rvalid_value("openbmc_password")
Michael Walsh0a3bdb42019-01-31 16:21:44 +0000455 grv.rvalid_value("rest_username")
456 grv.rvalid_value("rest_password")
457 grv.rvalid_value("ipmi_username")
458 grv.rvalid_value("ipmi_password")
Michael Walsh6741f742017-02-20 16:16:38 -0600459 if os_host != "":
460 grv.rvalid_value("os_username")
461 grv.rvalid_value("os_password")
Michael Walsh0bbd8602016-11-22 11:31:49 -0600462
Michael Walsh6741f742017-02-20 16:16:38 -0600463 if pdu_host != "":
464 grv.rvalid_value("pdu_username")
465 grv.rvalid_value("pdu_password")
Michael Walsh85678942017-03-27 14:34:22 -0500466 grv.rvalid_integer("pdu_slot_no")
Michael Walsh6741f742017-02-20 16:16:38 -0600467 if openbmc_serial_host != "":
468 grv.rvalid_integer("openbmc_serial_port")
Michael Walshb5839d02017-04-12 16:11:20 -0500469 if openbmc_model == "":
470 status, ret_values =\
471 grk.run_key_u("Get BMC System Model")
472 openbmc_model = ret_values
473 BuiltIn().set_global_variable("${openbmc_model}", openbmc_model)
Michael Walsh6741f742017-02-20 16:16:38 -0600474 grv.rvalid_value("openbmc_model")
Michael Walshb5839d02017-04-12 16:11:20 -0500475 grv.rvalid_integer("max_num_tests")
Michael Walsh6741f742017-02-20 16:16:38 -0600476 grv.rvalid_integer("boot_pass")
477 grv.rvalid_integer("boot_fail")
478
479 plug_in_packages_list = grpi.rvalidate_plug_ins(plug_in_dir_paths)
480 BuiltIn().set_global_variable("${plug_in_packages_list}",
481 plug_in_packages_list)
482
Michael Walshb5839d02017-04-12 16:11:20 -0500483 grv.rvalid_value("stack_mode", valid_values=['normal', 'skip'])
Michael Walsha20da402017-03-31 16:27:45 -0500484 if len(boot_list) == 0 and len(boot_stack) == 0 and not ffdc_only:
Michael Walsh6741f742017-02-20 16:16:38 -0600485 error_message = "You must provide either a value for either the" +\
486 " boot_list or the boot_stack parm.\n"
487 BuiltIn().fail(gp.sprint_error(error_message))
488
489 valid_boot_list(boot_list, valid_boot_types)
490 valid_boot_list(boot_stack, valid_boot_types)
491
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -0500492 selected_PDU_boots = list(set(boot_list + boot_stack)
493 & set(boot_lists['PDU_reboot']))
Michael Walsh11cfc8c2017-03-31 09:40:55 -0500494
495 if len(selected_PDU_boots) > 0 and pdu_host == "":
496 error_message = "You have selected the following boots which" +\
497 " require a PDU host but no value for pdu_host:\n"
498 error_message += gp.sprint_var(selected_PDU_boots)
Michael Walsh986d8ae2019-07-17 10:02:23 -0500499 error_message += gp.sprint_var(pdu_host, fmt=gp.blank())
Michael Walsh11cfc8c2017-03-31 09:40:55 -0500500 BuiltIn().fail(gp.sprint_error(error_message))
501
Michael Walsh6741f742017-02-20 16:16:38 -0600502 return
Michael Walsh0bbd8602016-11-22 11:31:49 -0600503
Michael Walsh0bbd8602016-11-22 11:31:49 -0600504
Michael Walsh6741f742017-02-20 16:16:38 -0600505def my_get_state():
Michael Walsh0bbd8602016-11-22 11:31:49 -0600506 r"""
Michael Walsh6741f742017-02-20 16:16:38 -0600507 Get the system state plus a little bit of wrapping.
Michael Walsh0bbd8602016-11-22 11:31:49 -0600508 """
509
Michael Walsh6741f742017-02-20 16:16:38 -0600510 global state
511
512 req_states = ['epoch_seconds'] + st.default_req_states
513
Michael Walshb5839d02017-04-12 16:11:20 -0500514 gp.qprint_timen("Getting system state.")
Michael Walsh6741f742017-02-20 16:16:38 -0600515 if test_mode:
516 state['epoch_seconds'] = int(time.time())
517 else:
Michael Walshb5839d02017-04-12 16:11:20 -0500518 state = st.get_state(req_states=req_states, quiet=quiet)
519 gp.qprint_var(state)
Michael Walsh341c21e2017-01-17 16:25:20 -0600520
Michael Walsh341c21e2017-01-17 16:25:20 -0600521
Michael Walsh45ca6e42017-09-14 17:29:12 -0500522def valid_state():
Michael Walsh45ca6e42017-09-14 17:29:12 -0500523 r"""
524 Verify that our state dictionary contains no blank values. If we don't get
525 valid state data, we cannot continue to work.
526 """
527
528 if st.compare_states(state, st.invalid_state_match, 'or'):
529 error_message = "The state dictionary contains blank fields which" +\
530 " is illegal.\n" + gp.sprint_var(state)
531 BuiltIn().fail(gp.sprint_error(error_message))
532
Michael Walsh45ca6e42017-09-14 17:29:12 -0500533
Michael Walsh6741f742017-02-20 16:16:38 -0600534def select_boot():
Michael Walsh341c21e2017-01-17 16:25:20 -0600535 r"""
536 Select a boot test to be run based on our current state and return the
537 chosen boot type.
538
539 Description of arguments:
Michael Walsh6741f742017-02-20 16:16:38 -0600540 state The state of the machine.
Michael Walsh341c21e2017-01-17 16:25:20 -0600541 """
542
Michael Walsh81816742017-09-27 11:02:29 -0500543 global transitional_boot_selected
Michael Walsh30dadae2017-02-27 14:25:52 -0600544 global boot_stack
545
Michael Walshb5839d02017-04-12 16:11:20 -0500546 gp.qprint_timen("Selecting a boot test.")
Michael Walsh6741f742017-02-20 16:16:38 -0600547
Michael Walsh81816742017-09-27 11:02:29 -0500548 if transitional_boot_selected and not boot_success:
549 prior_boot = next_boot
550 boot_candidate = boot_stack.pop()
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -0500551 gp.qprint_timen("The prior '" + next_boot + "' was chosen to"
552 + " transition to a valid state for '" + boot_candidate
553 + "' which was at the top of the boot_stack. Since"
554 + " the '" + next_boot + "' failed, the '"
555 + boot_candidate + "' has been removed from the stack"
556 + " to avoid and endless failure loop.")
Michael Walsh81816742017-09-27 11:02:29 -0500557 if len(boot_stack) == 0:
558 return ""
559
Michael Walsh6741f742017-02-20 16:16:38 -0600560 my_get_state()
Michael Walsh45ca6e42017-09-14 17:29:12 -0500561 valid_state()
Michael Walsh6741f742017-02-20 16:16:38 -0600562
Michael Walsh81816742017-09-27 11:02:29 -0500563 transitional_boot_selected = False
Michael Walsh6741f742017-02-20 16:16:38 -0600564 stack_popped = 0
565 if len(boot_stack) > 0:
566 stack_popped = 1
Michael Walshb5839d02017-04-12 16:11:20 -0500567 gp.qprint_dashes()
568 gp.qprint_var(boot_stack)
569 gp.qprint_dashes()
570 skip_boot_printed = 0
571 while len(boot_stack) > 0:
572 boot_candidate = boot_stack.pop()
573 if stack_mode == 'normal':
574 break
575 else:
576 if st.compare_states(state, boot_table[boot_candidate]['end']):
577 if not skip_boot_printed:
Michael Walshff340002017-08-29 11:18:27 -0500578 gp.qprint_var(stack_mode)
579 gp.qprintn()
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -0500580 gp.qprint_timen("Skipping the following boot tests"
581 + " which are unnecessary since their"
582 + " required end states match the"
583 + " current machine state:")
Michael Walshb5839d02017-04-12 16:11:20 -0500584 skip_boot_printed = 1
Michael Walshff340002017-08-29 11:18:27 -0500585 gp.qprint_var(boot_candidate)
Michael Walshb5839d02017-04-12 16:11:20 -0500586 boot_candidate = ""
587 if boot_candidate == "":
588 gp.qprint_dashes()
589 gp.qprint_var(boot_stack)
590 gp.qprint_dashes()
591 return boot_candidate
Michael Walsh6741f742017-02-20 16:16:38 -0600592 if st.compare_states(state, boot_table[boot_candidate]['start']):
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -0500593 gp.qprint_timen("The machine state is valid for a '"
594 + boot_candidate + "' boot test.")
Michael Walshb5839d02017-04-12 16:11:20 -0500595 gp.qprint_dashes()
596 gp.qprint_var(boot_stack)
597 gp.qprint_dashes()
Michael Walsh6741f742017-02-20 16:16:38 -0600598 return boot_candidate
Michael Walsh341c21e2017-01-17 16:25:20 -0600599 else:
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -0500600 gp.qprint_timen("The machine state does not match the required"
601 + " starting state for a '" + boot_candidate
602 + "' boot test:")
Michael Walsh986d8ae2019-07-17 10:02:23 -0500603 gp.qprint_varx("boot_table_start_entry",
604 boot_table[boot_candidate]['start'])
Michael Walsh6741f742017-02-20 16:16:38 -0600605 boot_stack.append(boot_candidate)
Michael Walsh81816742017-09-27 11:02:29 -0500606 transitional_boot_selected = True
Michael Walsh6741f742017-02-20 16:16:38 -0600607 popped_boot = boot_candidate
608
609 # Loop through your list selecting a boot_candidates
610 boot_candidates = []
611 for boot_candidate in boot_list:
612 if st.compare_states(state, boot_table[boot_candidate]['start']):
613 if stack_popped:
614 if st.compare_states(boot_table[boot_candidate]['end'],
Gunnar Mills096cd562018-03-26 10:19:12 -0500615 boot_table[popped_boot]['start']):
Michael Walsh6741f742017-02-20 16:16:38 -0600616 boot_candidates.append(boot_candidate)
617 else:
618 boot_candidates.append(boot_candidate)
619
620 if len(boot_candidates) == 0:
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -0500621 gp.qprint_timen("The user's boot list contained no boot tests"
622 + " which are valid for the current machine state.")
Michael Walsh6741f742017-02-20 16:16:38 -0600623 boot_candidate = default_power_on
624 if not st.compare_states(state, boot_table[default_power_on]['start']):
625 boot_candidate = default_power_off
626 boot_candidates.append(boot_candidate)
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -0500627 gp.qprint_timen("Using default '" + boot_candidate
628 + "' boot type to transition to valid state.")
Michael Walsh6741f742017-02-20 16:16:38 -0600629
Michael Walshb5839d02017-04-12 16:11:20 -0500630 gp.dprint_var(boot_candidates)
Michael Walsh6741f742017-02-20 16:16:38 -0600631
632 # Randomly select a boot from the candidate list.
633 boot = random.choice(boot_candidates)
Michael Walsh341c21e2017-01-17 16:25:20 -0600634
635 return boot
Michael Walsh0bbd8602016-11-22 11:31:49 -0600636
Michael Walsh55302292017-01-10 11:43:02 -0600637
Michael Walshb2e53ec2017-10-30 15:04:36 -0500638def print_defect_report(ffdc_file_list):
Michael Walsh341c21e2017-01-17 16:25:20 -0600639 r"""
640 Print a defect report.
Michael Walshb2e53ec2017-10-30 15:04:36 -0500641
642 Description of argument(s):
643 ffdc_file_list A list of files which were collected by our ffdc functions.
Michael Walsh341c21e2017-01-17 16:25:20 -0600644 """
645
Michael Walsh600876d2017-05-30 17:58:58 -0500646 # Making deliberate choice to NOT run plug_in_setup(). We don't want
647 # ffdc_prefix updated.
648 rc, shell_rc, failed_plug_in_name = grpi.rprocess_plug_in_packages(
649 call_point='ffdc_report', stop_on_plug_in_failure=0)
650
Michael Walshe0cf8d72017-05-17 13:20:46 -0500651 # Get additional header data which may have been created by ffdc plug-ins.
652 # Also, delete the individual header files to cleanup.
653 cmd_buf = "file_list=$(cat " + ffdc_report_list_path + " 2>/dev/null)" +\
654 " ; [ ! -z \"${file_list}\" ] && cat ${file_list}" +\
655 " 2>/dev/null ; rm -rf ${file_list} 2>/dev/null || :"
656 shell_rc, more_header_info = gc.cmd_fnc_u(cmd_buf, print_output=0,
657 show_err=0)
658
Michael Walshb2e53ec2017-10-30 15:04:36 -0500659 # Get additional summary data which may have been created by ffdc plug-ins.
Michael Walsh600876d2017-05-30 17:58:58 -0500660 # Also, delete the individual header files to cleanup.
661 cmd_buf = "file_list=$(cat " + ffdc_summary_list_path + " 2>/dev/null)" +\
662 " ; [ ! -z \"${file_list}\" ] && cat ${file_list}" +\
663 " 2>/dev/null ; rm -rf ${file_list} 2>/dev/null || :"
664 shell_rc, ffdc_summary_info = gc.cmd_fnc_u(cmd_buf, print_output=0,
665 show_err=0)
666
Michael Walshb2e53ec2017-10-30 15:04:36 -0500667 # ffdc_list_file_path contains a list of any ffdc files created by plug-
668 # ins, etc. Read that data into a list.
Michael Walsh341c21e2017-01-17 16:25:20 -0600669 try:
Michael Walshb2e53ec2017-10-30 15:04:36 -0500670 plug_in_ffdc_list = \
671 open(ffdc_list_file_path, 'r').read().rstrip("\n").split("\n")
George Keishing36efbc02018-12-12 10:18:23 -0600672 plug_in_ffdc_list = list(filter(None, plug_in_ffdc_list))
Michael Walsh341c21e2017-01-17 16:25:20 -0600673 except IOError:
Michael Walshb2e53ec2017-10-30 15:04:36 -0500674 plug_in_ffdc_list = []
675
676 # Combine the files from plug_in_ffdc_list with the ffdc_file_list passed
677 # in. Eliminate duplicates and sort the list.
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -0500678 ffdc_file_list = sorted(set(ffdc_file_list + plug_in_ffdc_list))
Michael Walshb2e53ec2017-10-30 15:04:36 -0500679
680 if status_file_path != "":
681 ffdc_file_list.insert(0, status_file_path)
682
683 # Convert the list to a printable list.
684 printable_ffdc_file_list = "\n".join(ffdc_file_list)
Michael Walsh341c21e2017-01-17 16:25:20 -0600685
Michael Walsh68a61162017-04-25 11:54:06 -0500686 # Open ffdc_file_list for writing. We will write a complete list of
687 # FFDC files to it for possible use by plug-ins like cp_stop_check.
688 ffdc_list_file = open(ffdc_list_file_path, 'w')
Michael Walshb2e53ec2017-10-30 15:04:36 -0500689 ffdc_list_file.write(printable_ffdc_file_list + "\n")
690 ffdc_list_file.close()
691
692 indent = 0
693 width = 90
694 linefeed = 1
695 char = "="
Michael Walsh68a61162017-04-25 11:54:06 -0500696
697 gp.qprintn()
Michael Walshb2e53ec2017-10-30 15:04:36 -0500698 gp.qprint_dashes(indent, width, linefeed, char)
Michael Walsh68a61162017-04-25 11:54:06 -0500699 gp.qprintn("Copy this data to the defect:\n")
700
Michael Walshe0cf8d72017-05-17 13:20:46 -0500701 if len(more_header_info) > 0:
Michael Walshff340002017-08-29 11:18:27 -0500702 gp.qprintn(more_header_info)
Michael Walshdc80d672017-05-09 12:58:32 -0500703 gp.qpvars(host_name, host_ip, openbmc_nickname, openbmc_host,
704 openbmc_host_name, openbmc_ip, openbmc_username,
Michael Walsh0a3bdb42019-01-31 16:21:44 +0000705 openbmc_password, rest_username, rest_password, ipmi_username,
706 ipmi_password, os_host, os_host_name, os_ip, os_username,
Michael Walshdc80d672017-05-09 12:58:32 -0500707 os_password, pdu_host, pdu_host_name, pdu_ip, pdu_username,
708 pdu_password, pdu_slot_no, openbmc_serial_host,
709 openbmc_serial_host_name, openbmc_serial_ip, openbmc_serial_port)
Michael Walsh68a61162017-04-25 11:54:06 -0500710
711 gp.qprintn()
Michael Walsh986d8ae2019-07-17 10:02:23 -0500712 print_boot_history(boot_history)
Michael Walsh68a61162017-04-25 11:54:06 -0500713 gp.qprintn()
714 gp.qprint_var(state)
Michael Walshb5839d02017-04-12 16:11:20 -0500715 gp.qprintn()
716 gp.qprintn("FFDC data files:")
Michael Walshb2e53ec2017-10-30 15:04:36 -0500717 gp.qprintn(printable_ffdc_file_list)
Michael Walshb5839d02017-04-12 16:11:20 -0500718 gp.qprintn()
Michael Walsh341c21e2017-01-17 16:25:20 -0600719
Michael Walsh600876d2017-05-30 17:58:58 -0500720 if len(ffdc_summary_info) > 0:
Michael Walshff340002017-08-29 11:18:27 -0500721 gp.qprintn(ffdc_summary_info)
Michael Walsh600876d2017-05-30 17:58:58 -0500722
Michael Walshb2e53ec2017-10-30 15:04:36 -0500723 gp.qprint_dashes(indent, width, linefeed, char)
Michael Walsh68a61162017-04-25 11:54:06 -0500724
Michael Walsh6741f742017-02-20 16:16:38 -0600725
Michael Walsh6741f742017-02-20 16:16:38 -0600726def my_ffdc():
Michael Walsh6741f742017-02-20 16:16:38 -0600727 r"""
728 Collect FFDC data.
729 """
730
731 global state
732
733 plug_in_setup()
734 rc, shell_rc, failed_plug_in_name = grpi.rprocess_plug_in_packages(
Michael Walsh600876d2017-05-30 17:58:58 -0500735 call_point='ffdc', stop_on_plug_in_failure=0)
Michael Walsh6741f742017-02-20 16:16:38 -0600736
737 AUTOBOOT_FFDC_PREFIX = os.environ['AUTOBOOT_FFDC_PREFIX']
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -0500738 status, ffdc_file_list = grk.run_key_u("FFDC ffdc_prefix="
739 + AUTOBOOT_FFDC_PREFIX
740 + " ffdc_function_list="
741 + ffdc_function_list, ignore=1)
Michael Walsh83f4bc72017-04-20 16:49:43 -0500742 if status != 'PASS':
Michael Walshff340002017-08-29 11:18:27 -0500743 gp.qprint_error("Call to ffdc failed.\n")
Michael Walshc9bd2e82019-04-18 11:06:52 -0500744 if type(ffdc_file_list) is not list:
745 ffdc_file_list = []
746 # Leave a record for caller that "soft" errors occurred.
747 soft_errors = 1
748 gpu.save_plug_in_value(soft_errors, pgm_name)
Michael Walsh6741f742017-02-20 16:16:38 -0600749
750 my_get_state()
751
Michael Walshb2e53ec2017-10-30 15:04:36 -0500752 print_defect_report(ffdc_file_list)
Michael Walsh6741f742017-02-20 16:16:38 -0600753
Michael Walsh6741f742017-02-20 16:16:38 -0600754
Michael Walsh6741f742017-02-20 16:16:38 -0600755def print_test_start_message(boot_keyword):
Michael Walsh6741f742017-02-20 16:16:38 -0600756 r"""
757 Print a message indicating what boot test is about to run.
758
759 Description of arguments:
760 boot_keyword The name of the boot which is to be run
761 (e.g. "BMC Power On").
762 """
763
Michael Walsh986d8ae2019-07-17 10:02:23 -0500764 global boot_history
Sunil M325eb542017-08-10 07:09:43 -0500765 global boot_start_time
Michael Walsh6741f742017-02-20 16:16:38 -0600766
767 doing_msg = gp.sprint_timen("Doing \"" + boot_keyword + "\".")
Sunil M325eb542017-08-10 07:09:43 -0500768
769 # Set boot_start_time for use by plug-ins.
770 boot_start_time = doing_msg[1:33]
771 gp.qprint_var(boot_start_time)
772
Michael Walshb5839d02017-04-12 16:11:20 -0500773 gp.qprint(doing_msg)
Michael Walsh6741f742017-02-20 16:16:38 -0600774
Michael Walsh986d8ae2019-07-17 10:02:23 -0500775 update_boot_history(boot_history, doing_msg, max_boot_history)
Michael Walsh6741f742017-02-20 16:16:38 -0600776
Michael Walsh6741f742017-02-20 16:16:38 -0600777
Michael Walshf566fb12019-02-01 14:35:09 -0600778def stop_boot_test(signal_number=0,
779 frame=None):
780 r"""
781 Handle SIGUSR1 by aborting the boot test that is running.
782
783 Description of argument(s):
784 signal_number The signal number (should always be 10 for SIGUSR1).
785 frame The frame data.
786 """
787
788 gp.printn()
789 gp.print_executing()
790 gp.lprint_executing()
791
792 # Restore original sigusr1 handler.
793 set_default_siguser1()
794
795 message = "The caller has asked that the boot test be stopped and marked"
796 message += " as a failure."
797
798 function_stack = gm.get_function_stack()
799 if "wait_state" in function_stack:
Michael Walshc44aa532019-06-14 13:33:29 -0500800 st.set_exit_wait_early_message(message)
Michael Walshf566fb12019-02-01 14:35:09 -0600801 else:
802 BuiltIn().fail(gp.sprint_error(message))
803
804
Michael Walsh6741f742017-02-20 16:16:38 -0600805def run_boot(boot):
Michael Walsh6741f742017-02-20 16:16:38 -0600806 r"""
807 Run the specified boot.
808
809 Description of arguments:
810 boot The name of the boot test to be performed.
811 """
812
813 global state
814
Michael Walshf566fb12019-02-01 14:35:09 -0600815 signal.signal(signal.SIGUSR1, stop_boot_test)
816 gp.qprint_timen("stop_boot_test is armed.")
817
Michael Walsh6741f742017-02-20 16:16:38 -0600818 print_test_start_message(boot)
819
820 plug_in_setup()
821 rc, shell_rc, failed_plug_in_name = \
822 grpi.rprocess_plug_in_packages(call_point="pre_boot")
823 if rc != 0:
824 error_message = "Plug-in failed with non-zero return code.\n" +\
Michael Walsh986d8ae2019-07-17 10:02:23 -0500825 gp.sprint_var(rc, fmt=gp.hexa())
Michael Walshf566fb12019-02-01 14:35:09 -0600826 set_default_siguser1()
Michael Walsh6741f742017-02-20 16:16:38 -0600827 BuiltIn().fail(gp.sprint_error(error_message))
828
829 if test_mode:
830 # In test mode, we'll pretend the boot worked by assigning its
831 # required end state to the default state value.
Michael Walsh30dadae2017-02-27 14:25:52 -0600832 state = st.strip_anchor_state(boot_table[boot]['end'])
Michael Walsh6741f742017-02-20 16:16:38 -0600833 else:
834 # Assertion: We trust that the state data was made fresh by the
835 # caller.
836
Michael Walshb5839d02017-04-12 16:11:20 -0500837 gp.qprintn()
Michael Walsh6741f742017-02-20 16:16:38 -0600838
839 if boot_table[boot]['method_type'] == "keyword":
Michael Walsh0b93fbf2017-03-02 14:42:41 -0600840 rk.my_run_keywords(boot_table[boot].get('lib_file_path', ''),
Michael Walshb5839d02017-04-12 16:11:20 -0500841 boot_table[boot]['method'],
842 quiet=quiet)
Michael Walsh6741f742017-02-20 16:16:38 -0600843
844 if boot_table[boot]['bmc_reboot']:
845 st.wait_for_comm_cycle(int(state['epoch_seconds']))
Michael Walsh30dadae2017-02-27 14:25:52 -0600846 plug_in_setup()
847 rc, shell_rc, failed_plug_in_name = \
848 grpi.rprocess_plug_in_packages(call_point="post_reboot")
849 if rc != 0:
Michael Walsh0b93fbf2017-03-02 14:42:41 -0600850 error_message = "Plug-in failed with non-zero return code.\n"
Michael Walsh986d8ae2019-07-17 10:02:23 -0500851 error_message += gp.sprint_var(rc, fmt=gp.hexa())
Michael Walshf566fb12019-02-01 14:35:09 -0600852 set_default_siguser1()
Michael Walsh30dadae2017-02-27 14:25:52 -0600853 BuiltIn().fail(gp.sprint_error(error_message))
Michael Walsh6741f742017-02-20 16:16:38 -0600854 else:
855 match_state = st.anchor_state(state)
856 del match_state['epoch_seconds']
857 # Wait for the state to change in any way.
858 st.wait_state(match_state, wait_time=state_change_timeout,
Michael Walsh600876d2017-05-30 17:58:58 -0500859 interval="10 seconds", invert=1)
Michael Walsh6741f742017-02-20 16:16:38 -0600860
Michael Walshb5839d02017-04-12 16:11:20 -0500861 gp.qprintn()
Michael Walsh6741f742017-02-20 16:16:38 -0600862 if boot_table[boot]['end']['chassis'] == "Off":
863 boot_timeout = power_off_timeout
864 else:
865 boot_timeout = power_on_timeout
866 st.wait_state(boot_table[boot]['end'], wait_time=boot_timeout,
Michael Walsh600876d2017-05-30 17:58:58 -0500867 interval="10 seconds")
Michael Walsh6741f742017-02-20 16:16:38 -0600868
869 plug_in_setup()
870 rc, shell_rc, failed_plug_in_name = \
871 grpi.rprocess_plug_in_packages(call_point="post_boot")
872 if rc != 0:
873 error_message = "Plug-in failed with non-zero return code.\n" +\
Michael Walsh986d8ae2019-07-17 10:02:23 -0500874 gp.sprint_var(rc, fmt=gp.hexa())
Michael Walshf566fb12019-02-01 14:35:09 -0600875 set_default_siguser1()
Michael Walsh6741f742017-02-20 16:16:38 -0600876 BuiltIn().fail(gp.sprint_error(error_message))
877
Michael Walshf566fb12019-02-01 14:35:09 -0600878 # Restore original sigusr1 handler.
879 set_default_siguser1()
880
Michael Walsh6741f742017-02-20 16:16:38 -0600881
Michael Walsh6741f742017-02-20 16:16:38 -0600882def test_loop_body():
Michael Walsh6741f742017-02-20 16:16:38 -0600883 r"""
884 The main loop body for the loop in main_py.
885
886 Description of arguments:
887 boot_count The iteration number (starts at 1).
888 """
889
890 global boot_count
891 global state
892 global next_boot
893 global boot_success
Sunil M325eb542017-08-10 07:09:43 -0500894 global boot_end_time
Michael Walsh6741f742017-02-20 16:16:38 -0600895
Michael Walshb5839d02017-04-12 16:11:20 -0500896 gp.qprintn()
Michael Walsh6741f742017-02-20 16:16:38 -0600897
898 next_boot = select_boot()
Michael Walshb5839d02017-04-12 16:11:20 -0500899 if next_boot == "":
900 return True
Michael Walsh6741f742017-02-20 16:16:38 -0600901
Michael Walshb5839d02017-04-12 16:11:20 -0500902 boot_count += 1
903 gp.qprint_timen("Starting boot " + str(boot_count) + ".")
Michael Walsh6741f742017-02-20 16:16:38 -0600904
Michael Walshe0cf8d72017-05-17 13:20:46 -0500905 pre_boot_plug_in_setup()
Michael Walsh6741f742017-02-20 16:16:38 -0600906
907 cmd_buf = ["run_boot", next_boot]
908 boot_status, msg = BuiltIn().run_keyword_and_ignore_error(*cmd_buf)
909 if boot_status == "FAIL":
Michael Walshb5839d02017-04-12 16:11:20 -0500910 gp.qprint(msg)
Michael Walsh6741f742017-02-20 16:16:38 -0600911
Michael Walshb5839d02017-04-12 16:11:20 -0500912 gp.qprintn()
Michael Walsh6741f742017-02-20 16:16:38 -0600913 if boot_status == "PASS":
914 boot_success = 1
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -0500915 completion_msg = gp.sprint_timen("BOOT_SUCCESS: \"" + next_boot
916 + "\" succeeded.")
Michael Walsh6741f742017-02-20 16:16:38 -0600917 else:
918 boot_success = 0
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -0500919 completion_msg = gp.sprint_timen("BOOT_FAILED: \"" + next_boot
920 + "\" failed.")
Sunil M325eb542017-08-10 07:09:43 -0500921
922 # Set boot_end_time for use by plug-ins.
923 boot_end_time = completion_msg[1:33]
924 gp.qprint_var(boot_end_time)
925
926 gp.qprint(completion_msg)
Michael Walsh6741f742017-02-20 16:16:38 -0600927
928 boot_results.update(next_boot, boot_status)
929
930 plug_in_setup()
931 # NOTE: A post_test_case call point failure is NOT counted as a boot
932 # failure.
933 rc, shell_rc, failed_plug_in_name = grpi.rprocess_plug_in_packages(
Michael Walsh600876d2017-05-30 17:58:58 -0500934 call_point='post_test_case', stop_on_plug_in_failure=0)
Michael Walsh6741f742017-02-20 16:16:38 -0600935
936 plug_in_setup()
937 rc, shell_rc, failed_plug_in_name = grpi.rprocess_plug_in_packages(
Michael Walsh89de14a2018-10-01 16:51:37 -0500938 call_point='ffdc_check', shell_rc=dump_ffdc_rc(),
Michael Walsh6741f742017-02-20 16:16:38 -0600939 stop_on_plug_in_failure=1, stop_on_non_zero_rc=1)
Michael Walsh12059e22019-03-21 11:03:45 -0500940 if ffdc_check == "All" or\
Michael Walsh89de14a2018-10-01 16:51:37 -0500941 shell_rc == dump_ffdc_rc():
Michael Walsh83f4bc72017-04-20 16:49:43 -0500942 status, ret_values = grk.run_key_u("my_ffdc", ignore=1)
943 if status != 'PASS':
Michael Walshff340002017-08-29 11:18:27 -0500944 gp.qprint_error("Call to my_ffdc failed.\n")
Michael Walshc9bd2e82019-04-18 11:06:52 -0500945 # Leave a record for caller that "soft" errors occurred.
946 soft_errors = 1
947 gpu.save_plug_in_value(soft_errors, pgm_name)
Michael Walsh6741f742017-02-20 16:16:38 -0600948
Michael Walshaabef1e2017-09-20 15:16:17 -0500949 if delete_errlogs:
950 # We need to purge error logs between boots or they build up.
951 grk.run_key("Delete Error logs", ignore=1)
Michael Walshd139f282017-04-04 18:00:23 -0500952
Michael Walsh952f9b02017-03-09 13:11:14 -0600953 boot_results.print_report()
Michael Walshb5839d02017-04-12 16:11:20 -0500954 gp.qprint_timen("Finished boot " + str(boot_count) + ".")
Michael Walsh952f9b02017-03-09 13:11:14 -0600955
Michael Walsh6741f742017-02-20 16:16:38 -0600956 plug_in_setup()
957 rc, shell_rc, failed_plug_in_name = grpi.rprocess_plug_in_packages(
Michael Walsh89de14a2018-10-01 16:51:37 -0500958 call_point='stop_check', shell_rc=stop_test_rc(),
959 stop_on_non_zero_rc=1)
960 if shell_rc == stop_test_rc():
Michael Walsh3ba8ecd2018-04-24 11:33:25 -0500961 message = "Stopping as requested by user.\n"
962 gp.print_time(message)
963 BuiltIn().fail(message)
Michael Walsh6741f742017-02-20 16:16:38 -0600964
Michael Walshd139f282017-04-04 18:00:23 -0500965 # This should help prevent ConnectionErrors.
Michael Walsh0960b382017-06-22 16:23:37 -0500966 grk.run_key_u("Close All Connections")
Michael Walshd139f282017-04-04 18:00:23 -0500967
Michael Walsh6741f742017-02-20 16:16:38 -0600968 return True
969
Michael Walsh6741f742017-02-20 16:16:38 -0600970
Michael Walsh83f4bc72017-04-20 16:49:43 -0500971def obmc_boot_test_teardown():
Michael Walsh6741f742017-02-20 16:16:38 -0600972 r"""
Michael Walshc9116812017-03-10 14:23:06 -0600973 Clean up after the Main keyword.
Michael Walsh6741f742017-02-20 16:16:38 -0600974 """
975
976 if cp_setup_called:
977 plug_in_setup()
978 rc, shell_rc, failed_plug_in_name = grpi.rprocess_plug_in_packages(
Michael Walsh600876d2017-05-30 17:58:58 -0500979 call_point='cleanup', stop_on_plug_in_failure=0)
Michael Walsh6741f742017-02-20 16:16:38 -0600980
Michael Walsh600876d2017-05-30 17:58:58 -0500981 if 'boot_results_file_path' in globals():
Michael Walsh986d8ae2019-07-17 10:02:23 -0500982 # Save boot_results and boot_history objects to a file in case they are
Michael Walsh6c645742018-08-17 15:02:17 -0500983 # needed again.
Michael Walsh600876d2017-05-30 17:58:58 -0500984 gp.qprint_timen("Saving boot_results to the following path.")
985 gp.qprint_var(boot_results_file_path)
Michael Walsh986d8ae2019-07-17 10:02:23 -0500986 pickle.dump((boot_results, boot_history),
Michael Walsh6c645742018-08-17 15:02:17 -0500987 open(boot_results_file_path, 'wb'),
Michael Walsh600876d2017-05-30 17:58:58 -0500988 pickle.HIGHEST_PROTOCOL)
Michael Walsh0b93fbf2017-03-02 14:42:41 -0600989
Michael Walshff340002017-08-29 11:18:27 -0500990 global save_stack
991 # Restore any global values saved on the save_stack.
992 for parm_name in main_func_parm_list:
993 # Get the parm_value if it was saved on the stack.
994 try:
995 parm_value = save_stack.pop(parm_name)
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -0500996 except BaseException:
Michael Walshff340002017-08-29 11:18:27 -0500997 # If it was not saved, no further action is required.
998 continue
999
1000 # Restore the saved value.
1001 cmd_buf = "BuiltIn().set_global_variable(\"${" + parm_name +\
1002 "}\", parm_value)"
1003 gp.dpissuing(cmd_buf)
1004 exec(cmd_buf)
1005
1006 gp.dprintn(save_stack.sprint_obj())
1007
Michael Walsh6741f742017-02-20 16:16:38 -06001008
Michael Walshc9116812017-03-10 14:23:06 -06001009def test_teardown():
Michael Walshc9116812017-03-10 14:23:06 -06001010 r"""
1011 Clean up after this test case.
1012 """
1013
1014 gp.qprintn()
1015 cmd_buf = ["Print Error",
1016 "A keyword timeout occurred ending this program.\n"]
1017 BuiltIn().run_keyword_if_timeout_occurred(*cmd_buf)
1018
Michael Walshc108e422019-03-28 12:27:18 -05001019 gp.qprint_pgm_footer()
Michael Walshb5839d02017-04-12 16:11:20 -05001020
Michael Walshc9116812017-03-10 14:23:06 -06001021
Michael Walsh89de14a2018-10-01 16:51:37 -05001022def post_stack():
1023 r"""
1024 Process post_stack plug-in programs.
1025 """
1026
1027 if not call_post_stack_plug:
1028 # The caller does not wish to have post_stack plug-in processing done.
1029 return
1030
1031 global boot_success
1032
1033 # NOTE: A post_stack call-point failure is NOT counted as a boot failure.
1034 pre_boot_plug_in_setup()
1035 # For the purposes of the following plug-ins, mark the "boot" as a success.
1036 boot_success = 1
1037 plug_in_setup()
Michael Walsh815b1d52018-10-30 13:32:26 -05001038 rc, shell_rc, failed_plug_in_name, history =\
1039 grpi.rprocess_plug_in_packages(call_point='post_stack',
1040 stop_on_plug_in_failure=0,
1041 return_history=True)
Michael Walsh986d8ae2019-07-17 10:02:23 -05001042 for doing_msg in history:
1043 update_boot_history(boot_history, doing_msg, max_boot_history)
Michael Walsh815b1d52018-10-30 13:32:26 -05001044 if rc != 0:
1045 boot_success = 0
Michael Walsh89de14a2018-10-01 16:51:37 -05001046
1047 plug_in_setup()
Michael Walsh815b1d52018-10-30 13:32:26 -05001048 rc, shell_rc, failed_plug_in_name =\
1049 grpi.rprocess_plug_in_packages(call_point='ffdc_check',
1050 shell_rc=dump_ffdc_rc(),
1051 stop_on_plug_in_failure=1,
1052 stop_on_non_zero_rc=1)
1053 if shell_rc == dump_ffdc_rc():
Michael Walsh89de14a2018-10-01 16:51:37 -05001054 status, ret_values = grk.run_key_u("my_ffdc", ignore=1)
1055 if status != 'PASS':
1056 gp.qprint_error("Call to my_ffdc failed.\n")
Michael Walshc9bd2e82019-04-18 11:06:52 -05001057 # Leave a record for caller that "soft" errors occurred.
1058 soft_errors = 1
1059 gpu.save_plug_in_value(soft_errors, pgm_name)
Michael Walsh89de14a2018-10-01 16:51:37 -05001060
1061 plug_in_setup()
1062 rc, shell_rc, failed_plug_in_name = grpi.rprocess_plug_in_packages(
1063 call_point='stop_check', shell_rc=stop_test_rc(),
1064 stop_on_non_zero_rc=1)
1065 if shell_rc == stop_test_rc():
1066 message = "Stopping as requested by user.\n"
1067 gp.print_time(message)
1068 BuiltIn().fail(message)
1069
1070
Michael Walshff340002017-08-29 11:18:27 -05001071def obmc_boot_test_py(loc_boot_stack=None,
1072 loc_stack_mode=None,
1073 loc_quiet=None):
Michael Walsh6741f742017-02-20 16:16:38 -06001074 r"""
1075 Do main program processing.
1076 """
1077
Michael Walshff340002017-08-29 11:18:27 -05001078 global save_stack
1079
George Keishing36efbc02018-12-12 10:18:23 -06001080 gp.dprintn()
Michael Walshff340002017-08-29 11:18:27 -05001081 # Process function parms.
1082 for parm_name in main_func_parm_list:
1083 # Get parm's value.
George Keishing36efbc02018-12-12 10:18:23 -06001084 parm_value = eval("loc_" + parm_name)
1085 gp.dpvars(parm_name, parm_value)
Michael Walshff340002017-08-29 11:18:27 -05001086
George Keishing36efbc02018-12-12 10:18:23 -06001087 if parm_value is not None:
Michael Walshff340002017-08-29 11:18:27 -05001088 # Save the global value on a stack.
1089 cmd_buf = "save_stack.push(BuiltIn().get_variable_value(\"${" +\
1090 parm_name + "}\"), \"" + parm_name + "\")"
1091 gp.dpissuing(cmd_buf)
1092 exec(cmd_buf)
1093
1094 # Set the global value to the passed value.
1095 cmd_buf = "BuiltIn().set_global_variable(\"${" + parm_name +\
1096 "}\", loc_" + parm_name + ")"
1097 gp.dpissuing(cmd_buf)
1098 exec(cmd_buf)
1099
1100 gp.dprintn(save_stack.sprint_obj())
Michael Walshb5839d02017-04-12 16:11:20 -05001101
Michael Walsh6741f742017-02-20 16:16:38 -06001102 setup()
1103
Michael Walshcd9fbfd2017-09-19 12:00:08 -05001104 init_boot_pass, init_boot_fail = boot_results.return_total_pass_fail()
1105
Michael Walsha20da402017-03-31 16:27:45 -05001106 if ffdc_only:
1107 gp.qprint_timen("Caller requested ffdc_only.")
Michael Walsh986d8ae2019-07-17 10:02:23 -05001108 if do_pre_boot_plug_in_setup:
1109 pre_boot_plug_in_setup()
Michael Walsh83f4bc72017-04-20 16:49:43 -05001110 grk.run_key_u("my_ffdc")
Michael Walsh764d2f82017-04-27 16:01:08 -05001111 return
Michael Walsha20da402017-03-31 16:27:45 -05001112
Michael Walsh6741f742017-02-20 16:16:38 -06001113 # Process caller's boot_stack.
1114 while (len(boot_stack) > 0):
1115 test_loop_body()
1116
Michael Walshb5839d02017-04-12 16:11:20 -05001117 gp.qprint_timen("Finished processing stack.")
Michael Walsh30dadae2017-02-27 14:25:52 -06001118
Michael Walsh89de14a2018-10-01 16:51:37 -05001119 post_stack()
1120
Michael Walsh6741f742017-02-20 16:16:38 -06001121 # Process caller's boot_list.
1122 if len(boot_list) > 0:
1123 for ix in range(1, max_num_tests + 1):
1124 test_loop_body()
1125
Michael Walshb5839d02017-04-12 16:11:20 -05001126 gp.qprint_timen("Completed all requested boot tests.")
1127
1128 boot_pass, boot_fail = boot_results.return_total_pass_fail()
Michael Walshcd9fbfd2017-09-19 12:00:08 -05001129 new_fail = boot_fail - init_boot_fail
1130 if new_fail > boot_fail_threshold:
Michael Walshb5839d02017-04-12 16:11:20 -05001131 error_message = "Boot failures exceed the boot failure" +\
1132 " threshold:\n" +\
Michael Walshcd9fbfd2017-09-19 12:00:08 -05001133 gp.sprint_var(new_fail) +\
Michael Walshb5839d02017-04-12 16:11:20 -05001134 gp.sprint_var(boot_fail_threshold)
1135 BuiltIn().fail(gp.sprint_error(error_message))