10bbd860fSMichael Walsh#!/usr/bin/env python
20bbd860fSMichael Walsh
30bbd860fSMichael Walshr"""
40bbd860fSMichael WalshThis module is the python counterpart to obmc_boot_test.
50bbd860fSMichael Walsh"""
60bbd860fSMichael Walsh
70b93fbf8SMichael Walshimport os
80b93fbf8SMichael Walshimport imp
90b93fbf8SMichael Walshimport time
100b93fbf8SMichael Walshimport glob
110b93fbf8SMichael Walshimport random
120ad0f7f8SMichael Walshimport re
13f566fb1fSMichael Walshimport signal
14d54bbc22SGeorge Keishingtry:
150b93fbf8SMichael Walsh    import cPickle as pickle
16d54bbc22SGeorge Keishingexcept ImportError:
17d54bbc22SGeorge Keishing    import pickle
18dc80d67dSMichael Walshimport socket
190b93fbf8SMichael Walsh
200b93fbf8SMichael Walshfrom robot.utils import DotDict
210b93fbf8SMichael Walshfrom robot.libraries.BuiltIn import BuiltIn
220b93fbf8SMichael Walsh
236741f740SMichael Walshfrom boot_data import *
24c9116811SMichael Walshimport gen_print as gp
2555302295SMichael Walshimport gen_robot_plug_in as grpi
26f75d4354SMichael Walshimport gen_arg as ga
2744cef258SMichael Walshimport gen_valid as gv
286741f740SMichael Walshimport gen_misc as gm
296741f740SMichael Walshimport gen_cmd as gc
30b5839d00SMichael Walshimport gen_robot_keyword as grk
3155302295SMichael Walshimport state as st
32ff340006SMichael Walshimport var_stack as vs
33c9bd2e87SMichael Walshimport gen_plug_in_utils as gpu
341a67b08aSMichael Sheposimport pel_utils as pel
350e5f1137SMichael Sheposimport logging_utils as log
360bbd860fSMichael Walsh
370b93fbf8SMichael Walshbase_path = os.path.dirname(os.path.dirname(
380b93fbf8SMichael Walsh                            imp.find_module("gen_robot_print")[1])) +\
390b93fbf8SMichael Walsh    os.sep
400b93fbf8SMichael Walshsys.path.append(base_path + "extended/")
410b93fbf8SMichael Walshimport run_keyword as rk
420bbd860fSMichael Walsh
43e1e26448SMichael Walsh# Setting master_pid correctly influences the behavior of plug-ins like
44e1e26448SMichael Walsh# DB_Logging
45e1e26448SMichael Walshprogram_pid = os.getpid()
46e1e26448SMichael Walshmaster_pid = os.environ.get('AUTOBOOT_MASTER_PID', program_pid)
47004ad3c9SJoy Onyerikwupgm_name = re.sub('\\.py$', '', os.path.basename(__file__))
48e1e26448SMichael Walsh
49b5839d00SMichael Walsh# Set up boot data structures.
50986d8aeeSMichael Walshos_host = BuiltIn().get_variable_value("${OS_HOST}", default="")
510b93fbf8SMichael Walsh
526741f740SMichael Walshboot_lists = read_boot_lists()
53986d8aeeSMichael Walsh
54986d8aeeSMichael Walsh# The maximum number of entries that can be in the boot_history global variable.
55815b1d5bSMichael Walshmax_boot_history = 10
56986d8aeeSMichael Walshboot_history = []
576741f740SMichael Walsh
587dc885b6SMichael Walshstate = st.return_state_constant('default_state')
596741f740SMichael Walshcp_setup_called = 0
606741f740SMichael Walshnext_boot = ""
616741f740SMichael Walshbase_tool_dir_path = os.path.normpath(os.environ.get(
626741f740SMichael Walsh    'AUTOBOOT_BASE_TOOL_DIR_PATH', "/tmp")) + os.sep
63b5839d00SMichael Walsh
646741f740SMichael Walshffdc_dir_path = os.path.normpath(os.environ.get('FFDC_DIR_PATH', '')) + os.sep
656741f740SMichael Walshboot_success = 0
666741f740SMichael Walshstatus_dir_path = os.environ.get('STATUS_DIR_PATH', "")
676741f740SMichael Walshif status_dir_path != "":
686741f740SMichael Walsh    status_dir_path = os.path.normpath(status_dir_path) + os.sep
6934c7956cSMichael Sheposredfish_support_trans_state = int(os.environ.get('REDFISH_SUPPORT_TRANS_STATE', 0)) or \
7034c7956cSMichael Shepos    int(BuiltIn().get_variable_value("${REDFISH_SUPPORT_TRANS_STATE}", default=0))
71e58df1c8SMichael Walshredfish_supported = BuiltIn().get_variable_value("${REDFISH_SUPPORTED}", default=False)
72eb1fe352SGeorge Keishingredfish_rest_supported = BuiltIn().get_variable_value("${REDFISH_REST_SUPPORTED}", default=False)
73d86e45c6SGeorge Keishingredfish_delete_sessions = int(BuiltIn().get_variable_value("${REDFISH_DELETE_SESSIONS}", default=1))
74e58df1c8SMichael Walshif redfish_supported:
7589537a85SGeorge Keishing    redfish = BuiltIn().get_library_instance('redfish')
76e58df1c8SMichael Walsh    default_power_on = "Redfish Power On"
77e58df1c8SMichael Walsh    default_power_off = "Redfish Power Off"
78870999aaSGeorge Keishing    if not redfish_support_trans_state:
79cc490b41SMichael Shepos        delete_errlogs_cmd = "Delete Error Logs  ${quiet}=${1}"
8092a54bf5SMichael Shepos        delete_bmcdump_cmd = "Delete All BMC Dump"
81763902a1SGeorge Keishing        default_set_power_policy = "Set BMC Power Policy  ALWAYS_POWER_OFF"
82e58df1c8SMichael Walsh    else:
83eb1fe352SGeorge Keishing        delete_errlogs_cmd = "Redfish Purge Event Log"
8492a54bf5SMichael Shepos        delete_bmcdump_cmd = "Redfish Delete All BMC Dumps"
852ef6a7dbSGeorge Keishing        delete_sysdump_cmd = "Redfish Delete All System Dumps"
86eb1fe352SGeorge Keishing        default_set_power_policy = "Redfish Set Power Restore Policy  AlwaysOff"
87eb1fe352SGeorge Keishingelse:
880b93fbf8SMichael Walsh    default_power_on = "REST Power On"
890b93fbf8SMichael Walsh    default_power_off = "REST Power Off"
90cc490b41SMichael Shepos    delete_errlogs_cmd = "Delete Error Logs  ${quiet}=${1}"
9192a54bf5SMichael Shepos    delete_bmcdump_cmd = "Delete All BMC Dump"
92a54e06f5SGeorge Keishing    default_set_power_policy = "Set BMC Power Policy  ALWAYS_POWER_OFF"
936741f740SMichael Walshboot_count = 0
940bbd860fSMichael Walsh
9585678948SMichael WalshLOG_LEVEL = BuiltIn().get_variable_value("${LOG_LEVEL}")
96986d8aeeSMichael WalshAUTOBOOT_FFDC_PREFIX = os.environ.get('AUTOBOOT_FFDC_PREFIX', '')
97986d8aeeSMichael Walshffdc_prefix = AUTOBOOT_FFDC_PREFIX
98325eb548SSunil Mboot_start_time = ""
99325eb548SSunil Mboot_end_time = ""
100ff340006SMichael Walshsave_stack = vs.var_stack('save_stack')
101ff340006SMichael Walshmain_func_parm_list = ['boot_stack', 'stack_mode', 'quiet']
10285678948SMichael Walsh
10385678948SMichael Walsh
10489de14a4SMichael Walshdef dump_ffdc_rc():
10589de14a4SMichael Walsh    r"""
10689de14a4SMichael Walsh    Return the constant dump ffdc test return code value.
10789de14a4SMichael Walsh
10889de14a4SMichael Walsh    When a plug-in call point program returns this value, it indicates that
10989de14a4SMichael Walsh    this program should collect FFDC.
11089de14a4SMichael Walsh    """
11189de14a4SMichael Walsh
11289de14a4SMichael Walsh    return 0x00000200
11389de14a4SMichael Walsh
11489de14a4SMichael Walsh
11589de14a4SMichael Walshdef stop_test_rc():
11689de14a4SMichael Walsh    r"""
11789de14a4SMichael Walsh    Return the constant stop test return code value.
11889de14a4SMichael Walsh
11989de14a4SMichael Walsh    When a plug-in call point program returns this value, it indicates that
12089de14a4SMichael Walsh    this program should stop running.
12189de14a4SMichael Walsh    """
12289de14a4SMichael Walsh
12389de14a4SMichael Walsh    return 0x00000200
12489de14a4SMichael Walsh
12589de14a4SMichael Walsh
1260ad0f7f8SMichael Walshdef process_host(host,
1270ad0f7f8SMichael Walsh                 host_var_name=""):
1280ad0f7f8SMichael Walsh    r"""
1290ad0f7f8SMichael Walsh    Process a host by getting the associated host name and IP address and
1300ad0f7f8SMichael Walsh    setting them in global variables.
1310ad0f7f8SMichael Walsh
1320ad0f7f8SMichael Walsh    If the caller does not pass the host_var_name, this function will try to
1330ad0f7f8SMichael Walsh    figure out the name of the variable used by the caller for the host parm.
1340ad0f7f8SMichael Walsh    Callers are advised to explicitly specify the host_var_name when calling
1350ad0f7f8SMichael Walsh    with an exec command.  In such cases, the get_arg_name cannot figure out
1360ad0f7f8SMichael Walsh    the host variable name.
1370ad0f7f8SMichael Walsh
1380ad0f7f8SMichael Walsh    This function will then create similar global variable names by
1390ad0f7f8SMichael Walsh    removing "_host" and appending "_host_name" or "_ip" to the host variable
1400ad0f7f8SMichael Walsh    name.
1410ad0f7f8SMichael Walsh
1420ad0f7f8SMichael Walsh    Example:
1430ad0f7f8SMichael Walsh
1440ad0f7f8SMichael Walsh    If a call is made like this:
1450ad0f7f8SMichael Walsh    process_host(openbmc_host)
1460ad0f7f8SMichael Walsh
1470ad0f7f8SMichael Walsh    Global variables openbmc_host_name and openbmc_ip will be set.
1480ad0f7f8SMichael Walsh
1490ad0f7f8SMichael Walsh    Description of argument(s):
1500ad0f7f8SMichael Walsh    host           A host name or IP.  The name of the variable used should
1510ad0f7f8SMichael Walsh                   have a suffix of "_host".
1520ad0f7f8SMichael Walsh    host_var_name  The name of the variable being used as the host parm.
1530ad0f7f8SMichael Walsh    """
1540ad0f7f8SMichael Walsh
1550ad0f7f8SMichael Walsh    if host_var_name == "":
1560ad0f7f8SMichael Walsh        host_var_name = gp.get_arg_name(0, 1, stack_frame_ix=2)
1570ad0f7f8SMichael Walsh
1580ad0f7f8SMichael Walsh    host_name_var_name = re.sub("host", "host_name", host_var_name)
1590ad0f7f8SMichael Walsh    ip_var_name = re.sub("host", "ip", host_var_name)
1600ad0f7f8SMichael Walsh    cmd_buf = "global " + host_name_var_name + ", " + ip_var_name + " ; " +\
1610ad0f7f8SMichael Walsh        host_name_var_name + ", " + ip_var_name + " = gm.get_host_name_ip('" +\
1620ad0f7f8SMichael Walsh        host + "')"
1630ad0f7f8SMichael Walsh    exec(cmd_buf)
1640ad0f7f8SMichael Walsh
1650ad0f7f8SMichael Walsh
166b5839d00SMichael Walshdef process_pgm_parms():
167b5839d00SMichael Walsh    r"""
168b5839d00SMichael Walsh    Process the program parameters by assigning them all to corresponding
169b5839d00SMichael Walsh    globals.  Also, set some global values that depend on program parameters.
170b5839d00SMichael Walsh    """
171b5839d00SMichael Walsh
172b5839d00SMichael Walsh    # Program parameter processing.
173b5839d00SMichael Walsh    # Assign all program parms to python variables which are global to this
174b5839d00SMichael Walsh    # module.
175b5839d00SMichael Walsh
176b5839d00SMichael Walsh    global parm_list
177b5839d00SMichael Walsh    parm_list = BuiltIn().get_variable_value("${parm_list}")
178b5839d00SMichael Walsh    # The following subset of parms should be processed as integers.
179b5839d00SMichael Walsh    int_list = ['max_num_tests', 'boot_pass', 'boot_fail', 'ffdc_only',
18089de14a4SMichael Walsh                'boot_fail_threshold', 'delete_errlogs',
181986d8aeeSMichael Walsh                'call_post_stack_plug', 'do_pre_boot_plug_in_setup', 'quiet',
182986d8aeeSMichael Walsh                'test_mode', 'debug']
183b5839d00SMichael Walsh    for parm in parm_list:
184b5839d00SMichael Walsh        if parm in int_list:
185b5839d00SMichael Walsh            sub_cmd = "int(BuiltIn().get_variable_value(\"${" + parm +\
186b5839d00SMichael Walsh                      "}\", \"0\"))"
187b5839d00SMichael Walsh        else:
188b5839d00SMichael Walsh            sub_cmd = "BuiltIn().get_variable_value(\"${" + parm + "}\")"
189b5839d00SMichael Walsh        cmd_buf = "global " + parm + " ; " + parm + " = " + sub_cmd
190ff340006SMichael Walsh        gp.dpissuing(cmd_buf)
191b5839d00SMichael Walsh        exec(cmd_buf)
1920ad0f7f8SMichael Walsh        if re.match(r".*_host$", parm):
1930ad0f7f8SMichael Walsh            cmd_buf = "process_host(" + parm + ", '" + parm + "')"
1940ad0f7f8SMichael Walsh            exec(cmd_buf)
1950ad0f7f8SMichael Walsh        if re.match(r".*_password$", parm):
1960ad0f7f8SMichael Walsh            # Register the value of any parm whose name ends in _password.
1970ad0f7f8SMichael Walsh            # This will cause the print functions to replace passwords with
1980ad0f7f8SMichael Walsh            # asterisks in the output.
1990ad0f7f8SMichael Walsh            cmd_buf = "gp.register_passwords(" + parm + ")"
2000ad0f7f8SMichael Walsh            exec(cmd_buf)
201b5839d00SMichael Walsh
202b5839d00SMichael Walsh    global ffdc_dir_path_style
203b5839d00SMichael Walsh    global boot_list
204b5839d00SMichael Walsh    global boot_stack
205b5839d00SMichael Walsh    global boot_results_file_path
206b5839d00SMichael Walsh    global boot_results
207986d8aeeSMichael Walsh    global boot_history
208b5839d00SMichael Walsh    global ffdc_list_file_path
209e0cf8d70SMichael Walsh    global ffdc_report_list_path
210600876daSMichael Walsh    global ffdc_summary_list_path
211a3e7b222SMichael Walsh    global boot_table
212a3e7b222SMichael Walsh    global valid_boot_types
213b5839d00SMichael Walsh
214b5839d00SMichael Walsh    if ffdc_dir_path_style == "":
215b5839d00SMichael Walsh        ffdc_dir_path_style = int(os.environ.get('FFDC_DIR_PATH_STYLE', '0'))
216b5839d00SMichael Walsh
217b5839d00SMichael Walsh    # Convert these program parms to lists for easier processing..
21836efbc04SGeorge Keishing    boot_list = list(filter(None, boot_list.split(":")))
21936efbc04SGeorge Keishing    boot_stack = list(filter(None, boot_stack.split(":")))
220b5839d00SMichael Walsh
221a3e7b222SMichael Walsh    boot_table = create_boot_table(boot_table_path, os_host=os_host)
222a3e7b222SMichael Walsh    valid_boot_types = create_valid_boot_list(boot_table)
223a3e7b222SMichael Walsh
224903e0b20SMichael Walsh    cleanup_boot_results_file()
225903e0b20SMichael Walsh    boot_results_file_path = create_boot_results_file_path(pgm_name,
226903e0b20SMichael Walsh                                                           openbmc_nickname,
227903e0b20SMichael Walsh                                                           master_pid)
228b5839d00SMichael Walsh
229b5839d00SMichael Walsh    if os.path.isfile(boot_results_file_path):
230b5839d00SMichael Walsh        # We've been called before in this run so we'll load the saved
231986d8aeeSMichael Walsh        # boot_results and boot_history objects.
232986d8aeeSMichael Walsh        boot_results, boot_history =\
2336c64574bSMichael Walsh            pickle.load(open(boot_results_file_path, 'rb'))
234b5839d00SMichael Walsh    else:
235b5839d00SMichael Walsh        boot_results = boot_results(boot_table, boot_pass, boot_fail)
236b5839d00SMichael Walsh
237b5839d00SMichael Walsh    ffdc_list_file_path = base_tool_dir_path + openbmc_nickname +\
238b5839d00SMichael Walsh        "/FFDC_FILE_LIST"
239e0cf8d70SMichael Walsh    ffdc_report_list_path = base_tool_dir_path + openbmc_nickname +\
240e0cf8d70SMichael Walsh        "/FFDC_REPORT_FILE_LIST"
241b5839d00SMichael Walsh
242600876daSMichael Walsh    ffdc_summary_list_path = base_tool_dir_path + openbmc_nickname +\
243600876daSMichael Walsh        "/FFDC_SUMMARY_FILE_LIST"
244600876daSMichael Walsh
245b5839d00SMichael Walsh
24685678948SMichael Walshdef initial_plug_in_setup():
24785678948SMichael Walsh    r"""
24885678948SMichael Walsh    Initialize all plug-in environment variables which do not change for the
24985678948SMichael Walsh    duration of the program.
25085678948SMichael Walsh
25185678948SMichael Walsh    """
25285678948SMichael Walsh
25385678948SMichael Walsh    global LOG_LEVEL
25485678948SMichael Walsh    BuiltIn().set_log_level("NONE")
25585678948SMichael Walsh
25685678948SMichael Walsh    BuiltIn().set_global_variable("${master_pid}", master_pid)
25785678948SMichael Walsh    BuiltIn().set_global_variable("${FFDC_DIR_PATH}", ffdc_dir_path)
25885678948SMichael Walsh    BuiltIn().set_global_variable("${STATUS_DIR_PATH}", status_dir_path)
25985678948SMichael Walsh    BuiltIn().set_global_variable("${BASE_TOOL_DIR_PATH}", base_tool_dir_path)
26085678948SMichael Walsh    BuiltIn().set_global_variable("${FFDC_LIST_FILE_PATH}",
26185678948SMichael Walsh                                  ffdc_list_file_path)
262e0cf8d70SMichael Walsh    BuiltIn().set_global_variable("${FFDC_REPORT_LIST_PATH}",
263e0cf8d70SMichael Walsh                                  ffdc_report_list_path)
264600876daSMichael Walsh    BuiltIn().set_global_variable("${FFDC_SUMMARY_LIST_PATH}",
265600876daSMichael Walsh                                  ffdc_summary_list_path)
26685678948SMichael Walsh
26785678948SMichael Walsh    BuiltIn().set_global_variable("${FFDC_DIR_PATH_STYLE}",
26885678948SMichael Walsh                                  ffdc_dir_path_style)
26985678948SMichael Walsh    BuiltIn().set_global_variable("${FFDC_CHECK}",
27085678948SMichael Walsh                                  ffdc_check)
27185678948SMichael Walsh
27285678948SMichael Walsh    # For each program parameter, set the corresponding AUTOBOOT_ environment
27385678948SMichael Walsh    # variable value.  Also, set an AUTOBOOT_ environment variable for every
27485678948SMichael Walsh    # element in additional_values.
27585678948SMichael Walsh    additional_values = ["program_pid", "master_pid", "ffdc_dir_path",
27685678948SMichael Walsh                         "status_dir_path", "base_tool_dir_path",
277600876daSMichael Walsh                         "ffdc_list_file_path", "ffdc_report_list_path",
2787fe83b32SMichael Shepos                         "ffdc_summary_list_path", "execdir", "redfish_supported",
27934c7956cSMichael Shepos                         "redfish_rest_supported", "redfish_support_trans_state"]
28085678948SMichael Walsh
28185678948SMichael Walsh    plug_in_vars = parm_list + additional_values
28285678948SMichael Walsh
28385678948SMichael Walsh    for var_name in plug_in_vars:
28485678948SMichael Walsh        var_value = BuiltIn().get_variable_value("${" + var_name + "}")
28585678948SMichael Walsh        var_name = var_name.upper()
28685678948SMichael Walsh        if var_value is None:
28785678948SMichael Walsh            var_value = ""
28885678948SMichael Walsh        os.environ["AUTOBOOT_" + var_name] = str(var_value)
28985678948SMichael Walsh
29085678948SMichael Walsh    BuiltIn().set_log_level(LOG_LEVEL)
29185678948SMichael Walsh
29268a61162SMichael Walsh    # Make sure the ffdc list directory exists.
29368a61162SMichael Walsh    ffdc_list_dir_path = os.path.dirname(ffdc_list_file_path) + os.sep
29468a61162SMichael Walsh    if not os.path.exists(ffdc_list_dir_path):
29568a61162SMichael Walsh        os.makedirs(ffdc_list_dir_path)
29685678948SMichael Walsh
29785678948SMichael Walsh
2980bbd860fSMichael Walshdef plug_in_setup():
2990bbd860fSMichael Walsh    r"""
30085678948SMichael Walsh    Initialize all changing plug-in environment variables for use by the
30185678948SMichael Walsh    plug-in programs.
3020bbd860fSMichael Walsh    """
3030bbd860fSMichael Walsh
30485678948SMichael Walsh    global LOG_LEVEL
30585678948SMichael Walsh    global test_really_running
30685678948SMichael Walsh
30785678948SMichael Walsh    BuiltIn().set_log_level("NONE")
30885678948SMichael Walsh
3096741f740SMichael Walsh    boot_pass, boot_fail = boot_results.return_total_pass_fail()
3100bbd860fSMichael Walsh    if boot_pass > 1:
3110bbd860fSMichael Walsh        test_really_running = 1
3120bbd860fSMichael Walsh    else:
3130bbd860fSMichael Walsh        test_really_running = 0
3140bbd860fSMichael Walsh
3156741f740SMichael Walsh    BuiltIn().set_global_variable("${test_really_running}",
3166741f740SMichael Walsh                                  test_really_running)
3176741f740SMichael Walsh    BuiltIn().set_global_variable("${boot_type_desc}", next_boot)
3186741f740SMichael Walsh    BuiltIn().set_global_variable("${boot_pass}", boot_pass)
3196741f740SMichael Walsh    BuiltIn().set_global_variable("${boot_fail}", boot_fail)
3206741f740SMichael Walsh    BuiltIn().set_global_variable("${boot_success}", boot_success)
3216741f740SMichael Walsh    BuiltIn().set_global_variable("${ffdc_prefix}", ffdc_prefix)
322325eb548SSunil M    BuiltIn().set_global_variable("${boot_start_time}", boot_start_time)
323325eb548SSunil M    BuiltIn().set_global_variable("${boot_end_time}", boot_end_time)
3244c9a6453SMichael Walsh
3250bbd860fSMichael Walsh    # For each program parameter, set the corresponding AUTOBOOT_ environment
3260bbd860fSMichael Walsh    # variable value.  Also, set an AUTOBOOT_ environment variable for every
3270bbd860fSMichael Walsh    # element in additional_values.
3280bbd860fSMichael Walsh    additional_values = ["boot_type_desc", "boot_success", "boot_pass",
329325eb548SSunil M                         "boot_fail", "test_really_running", "ffdc_prefix",
330325eb548SSunil M                         "boot_start_time", "boot_end_time"]
3310bbd860fSMichael Walsh
33285678948SMichael Walsh    plug_in_vars = additional_values
3330bbd860fSMichael Walsh
3340bbd860fSMichael Walsh    for var_name in plug_in_vars:
3350bbd860fSMichael Walsh        var_value = BuiltIn().get_variable_value("${" + var_name + "}")
3360bbd860fSMichael Walsh        var_name = var_name.upper()
3370bbd860fSMichael Walsh        if var_value is None:
3380bbd860fSMichael Walsh            var_value = ""
3396741f740SMichael Walsh        os.environ["AUTOBOOT_" + var_name] = str(var_value)
3400bbd860fSMichael Walsh
3410bbd860fSMichael Walsh    if debug:
3426741f740SMichael Walsh        shell_rc, out_buf = \
3436741f740SMichael Walsh            gc.cmd_fnc_u("printenv | egrep AUTOBOOT_ | sort -u")
3440bbd860fSMichael Walsh
34585678948SMichael Walsh    BuiltIn().set_log_level(LOG_LEVEL)
34685678948SMichael Walsh
3470bbd860fSMichael Walsh
348e0cf8d70SMichael Walshdef pre_boot_plug_in_setup():
349e0cf8d70SMichael Walsh
350e0cf8d70SMichael Walsh    # Clear the ffdc_list_file_path file.  Plug-ins may now write to it.
351e0cf8d70SMichael Walsh    try:
352e0cf8d70SMichael Walsh        os.remove(ffdc_list_file_path)
353e0cf8d70SMichael Walsh    except OSError:
354e0cf8d70SMichael Walsh        pass
355e0cf8d70SMichael Walsh
356e0cf8d70SMichael Walsh    # Clear the ffdc_report_list_path file.  Plug-ins may now write to it.
357e0cf8d70SMichael Walsh    try:
358e0cf8d70SMichael Walsh        os.remove(ffdc_report_list_path)
359e0cf8d70SMichael Walsh    except OSError:
360e0cf8d70SMichael Walsh        pass
361e0cf8d70SMichael Walsh
362600876daSMichael Walsh    # Clear the ffdc_summary_list_path file.  Plug-ins may now write to it.
363600876daSMichael Walsh    try:
364600876daSMichael Walsh        os.remove(ffdc_summary_list_path)
365600876daSMichael Walsh    except OSError:
366600876daSMichael Walsh        pass
367600876daSMichael Walsh
368e1974b96SMichael Walsh    global ffdc_prefix
369e1974b96SMichael Walsh
370e1974b96SMichael Walsh    seconds = time.time()
371e1974b96SMichael Walsh    loc_time = time.localtime(seconds)
372e1974b96SMichael Walsh    time_string = time.strftime("%y%m%d.%H%M%S.", loc_time)
373e1974b96SMichael Walsh
374e1974b96SMichael Walsh    ffdc_prefix = openbmc_nickname + "." + time_string
375e1974b96SMichael Walsh
376e0cf8d70SMichael Walsh
377f566fb1fSMichael Walshdef default_sigusr1(signal_number=0,
378f566fb1fSMichael Walsh                    frame=None):
379f566fb1fSMichael Walsh    r"""
380f566fb1fSMichael Walsh    Handle SIGUSR1 by doing nothing.
381f566fb1fSMichael Walsh
382f566fb1fSMichael Walsh    This function assists in debugging SIGUSR1 processing by printing messages
383f566fb1fSMichael Walsh    to stdout and to the log.html file.
384f566fb1fSMichael Walsh
385f566fb1fSMichael Walsh    Description of argument(s):
386f566fb1fSMichael Walsh    signal_number  The signal number (should always be 10 for SIGUSR1).
387f566fb1fSMichael Walsh    frame          The frame data.
388f566fb1fSMichael Walsh    """
389f566fb1fSMichael Walsh
39080dddde9SMichael Walsh    gp.qprintn()
39180dddde9SMichael Walsh    gp.qprint_executing()
392f566fb1fSMichael Walsh    gp.lprint_executing()
393f566fb1fSMichael Walsh
394f566fb1fSMichael Walsh
395f566fb1fSMichael Walshdef set_default_siguser1():
396f566fb1fSMichael Walsh    r"""
397f566fb1fSMichael Walsh    Set the default_sigusr1 function to be the SIGUSR1 handler.
398f566fb1fSMichael Walsh    """
399f566fb1fSMichael Walsh
40080dddde9SMichael Walsh    gp.qprintn()
40180dddde9SMichael Walsh    gp.qprint_executing()
402f566fb1fSMichael Walsh    gp.lprint_executing()
403f566fb1fSMichael Walsh    signal.signal(signal.SIGUSR1, default_sigusr1)
404f566fb1fSMichael Walsh
405f566fb1fSMichael Walsh
4066741f740SMichael Walshdef setup():
4070bbd860fSMichael Walsh    r"""
4086741f740SMichael Walsh    Do general program setup tasks.
4090bbd860fSMichael Walsh    """
4100bbd860fSMichael Walsh
4116741f740SMichael Walsh    global cp_setup_called
41281816748SMichael Walsh    global transitional_boot_selected
4130bbd860fSMichael Walsh
414b5839d00SMichael Walsh    gp.qprintn()
415b5839d00SMichael Walsh
416a54e06f5SGeorge Keishing    if redfish_supported:
417a54e06f5SGeorge Keishing        redfish.login()
418a54e06f5SGeorge Keishing
419f566fb1fSMichael Walsh    set_default_siguser1()
42081816748SMichael Walsh    transitional_boot_selected = False
42181816748SMichael Walsh
42283f4bc77SMichael Walsh    robot_pgm_dir_path = os.path.dirname(__file__) + os.sep
42383f4bc77SMichael Walsh    repo_bin_path = robot_pgm_dir_path.replace("/lib/", "/bin/")
424d061c043SMichael Walsh    # If we can't find process_plug_in_packages.py, ssh_pw or
425d061c043SMichael Walsh    # validate_plug_ins.py, then we don't have our repo bin in PATH.
426004ad3c9SJoy Onyerikwu    shell_rc, out_buf = gc.cmd_fnc_u("which process_plug_in_packages.py"
427004ad3c9SJoy Onyerikwu                                     + " ssh_pw validate_plug_ins.py", quiet=1,
428d061c043SMichael Walsh                                     print_output=0, show_err=0)
429b5839d00SMichael Walsh    if shell_rc != 0:
43083f4bc77SMichael Walsh        os.environ['PATH'] = repo_bin_path + ":" + os.environ.get('PATH', "")
43183f4bc77SMichael Walsh    # Likewise, our repo lib subdir needs to be in sys.path and PYTHONPATH.
43283f4bc77SMichael Walsh    if robot_pgm_dir_path not in sys.path:
43383f4bc77SMichael Walsh        sys.path.append(robot_pgm_dir_path)
43483f4bc77SMichael Walsh        PYTHONPATH = os.environ.get("PYTHONPATH", "")
43583f4bc77SMichael Walsh        if PYTHONPATH == "":
43683f4bc77SMichael Walsh            os.environ['PYTHONPATH'] = robot_pgm_dir_path
43783f4bc77SMichael Walsh        else:
43883f4bc77SMichael Walsh            os.environ['PYTHONPATH'] = robot_pgm_dir_path + ":" + PYTHONPATH
4396741f740SMichael Walsh
4406741f740SMichael Walsh    validate_parms()
4416741f740SMichael Walsh
442c108e429SMichael Walsh    gp.qprint_pgm_header()
4436741f740SMichael Walsh
444a54e06f5SGeorge Keishing    grk.run_key_u(default_set_power_policy)
44511cfc8c0SMichael Walsh
44685678948SMichael Walsh    initial_plug_in_setup()
44785678948SMichael Walsh
4486741f740SMichael Walsh    plug_in_setup()
4496741f740SMichael Walsh    rc, shell_rc, failed_plug_in_name = grpi.rprocess_plug_in_packages(
4506741f740SMichael Walsh        call_point='setup')
4516741f740SMichael Walsh    if rc != 0:
4526741f740SMichael Walsh        error_message = "Plug-in setup failed.\n"
453c108e429SMichael Walsh        gp.print_error_report(error_message)
4546741f740SMichael Walsh        BuiltIn().fail(error_message)
4556741f740SMichael Walsh    # Setting cp_setup_called lets our Teardown know that it needs to call
4566741f740SMichael Walsh    # the cleanup plug-in call point.
4576741f740SMichael Walsh    cp_setup_called = 1
4586741f740SMichael Walsh
4596741f740SMichael Walsh    # Keyword "FFDC" will fail if TEST_MESSAGE is not set.
4606741f740SMichael Walsh    BuiltIn().set_global_variable("${TEST_MESSAGE}", "${EMPTY}")
46185678948SMichael Walsh    # FFDC_LOG_PATH is used by "FFDC" keyword.
46285678948SMichael Walsh    BuiltIn().set_global_variable("${FFDC_LOG_PATH}", ffdc_dir_path)
4636741f740SMichael Walsh
464dc80d67dSMichael Walsh    # Also printed by FFDC.
465dc80d67dSMichael Walsh    global host_name
466dc80d67dSMichael Walsh    global host_ip
467dc80d67dSMichael Walsh    host = socket.gethostname()
468dc80d67dSMichael Walsh    host_name, host_ip = gm.get_host_name_ip(host)
469dc80d67dSMichael Walsh
470986d8aeeSMichael Walsh    gp.dprint_var(boot_table)
471b5839d00SMichael Walsh    gp.dprint_var(boot_lists)
4720bbd860fSMichael Walsh
4730bbd860fSMichael Walsh
4746741f740SMichael Walshdef validate_parms():
4750bbd860fSMichael Walsh    r"""
4766741f740SMichael Walsh    Validate all program parameters.
4770bbd860fSMichael Walsh    """
4780bbd860fSMichael Walsh
479b5839d00SMichael Walsh    process_pgm_parms()
4800bbd860fSMichael Walsh
481b5839d00SMichael Walsh    gp.qprintn()
482b5839d00SMichael Walsh
483b5839d00SMichael Walsh    global openbmc_model
484f5ce38c3SMichael Walsh    if openbmc_model == "":
485f5ce38c3SMichael Walsh        status, ret_values =\
486f5ce38c3SMichael Walsh            grk.run_key_u("Get BMC System Model")
487f5ce38c3SMichael Walsh        openbmc_model = ret_values
488f5ce38c3SMichael Walsh        BuiltIn().set_global_variable("${openbmc_model}", openbmc_model)
489f5ce38c3SMichael Walsh    gv.set_exit_on_error(True)
49044cef258SMichael Walsh    gv.valid_value(openbmc_host)
49144cef258SMichael Walsh    gv.valid_value(openbmc_username)
49244cef258SMichael Walsh    gv.valid_value(openbmc_password)
49344cef258SMichael Walsh    gv.valid_value(rest_username)
49444cef258SMichael Walsh    gv.valid_value(rest_password)
49544cef258SMichael Walsh    gv.valid_value(ipmi_username)
49644cef258SMichael Walsh    gv.valid_value(ipmi_password)
4976741f740SMichael Walsh    if os_host != "":
49844cef258SMichael Walsh        gv.valid_value(os_username)
49944cef258SMichael Walsh        gv.valid_value(os_password)
5006741f740SMichael Walsh    if pdu_host != "":
50144cef258SMichael Walsh        gv.valid_value(pdu_username)
50244cef258SMichael Walsh        gv.valid_value(pdu_password)
50344cef258SMichael Walsh        gv.valid_integer(pdu_slot_no)
5046741f740SMichael Walsh    if openbmc_serial_host != "":
50544cef258SMichael Walsh        gv.valid_integer(openbmc_serial_port)
50644cef258SMichael Walsh    gv.valid_value(openbmc_model)
50744cef258SMichael Walsh    gv.valid_integer(max_num_tests)
50844cef258SMichael Walsh    gv.valid_integer(boot_pass)
50944cef258SMichael Walsh    gv.valid_integer(boot_fail)
5106741f740SMichael Walsh    plug_in_packages_list = grpi.rvalidate_plug_ins(plug_in_dir_paths)
5116741f740SMichael Walsh    BuiltIn().set_global_variable("${plug_in_packages_list}",
5126741f740SMichael Walsh                                  plug_in_packages_list)
51344cef258SMichael Walsh    gv.valid_value(stack_mode, valid_values=['normal', 'skip'])
514f5ce38c3SMichael Walsh    gv.set_exit_on_error(False)
515a20da401SMichael Walsh    if len(boot_list) == 0 and len(boot_stack) == 0 and not ffdc_only:
5166741f740SMichael Walsh        error_message = "You must provide either a value for either the" +\
5176741f740SMichael Walsh            " boot_list or the boot_stack parm.\n"
5186741f740SMichael Walsh        BuiltIn().fail(gp.sprint_error(error_message))
5196741f740SMichael Walsh    valid_boot_list(boot_list, valid_boot_types)
5206741f740SMichael Walsh    valid_boot_list(boot_stack, valid_boot_types)
521004ad3c9SJoy Onyerikwu    selected_PDU_boots = list(set(boot_list + boot_stack)
522004ad3c9SJoy Onyerikwu                              & set(boot_lists['PDU_reboot']))
52311cfc8c0SMichael Walsh    if len(selected_PDU_boots) > 0 and pdu_host == "":
52411cfc8c0SMichael Walsh        error_message = "You have selected the following boots which" +\
52511cfc8c0SMichael Walsh                        " require a PDU host but no value for pdu_host:\n"
52611cfc8c0SMichael Walsh        error_message += gp.sprint_var(selected_PDU_boots)
527986d8aeeSMichael Walsh        error_message += gp.sprint_var(pdu_host, fmt=gp.blank())
52811cfc8c0SMichael Walsh        BuiltIn().fail(gp.sprint_error(error_message))
52911cfc8c0SMichael Walsh
5306741f740SMichael Walsh    return
5310bbd860fSMichael Walsh
5320bbd860fSMichael Walsh
5336741f740SMichael Walshdef my_get_state():
5340bbd860fSMichael Walsh    r"""
5356741f740SMichael Walsh    Get the system state plus a little bit of wrapping.
5360bbd860fSMichael Walsh    """
5370bbd860fSMichael Walsh
5386741f740SMichael Walsh    global state
5396741f740SMichael Walsh
5406741f740SMichael Walsh    req_states = ['epoch_seconds'] + st.default_req_states
5416741f740SMichael Walsh
542b5839d00SMichael Walsh    gp.qprint_timen("Getting system state.")
5436741f740SMichael Walsh    if test_mode:
5446741f740SMichael Walsh        state['epoch_seconds'] = int(time.time())
5456741f740SMichael Walsh    else:
546b5839d00SMichael Walsh        state = st.get_state(req_states=req_states, quiet=quiet)
547b5839d00SMichael Walsh    gp.qprint_var(state)
548341c21ebSMichael Walsh
549341c21ebSMichael Walsh
55045ca6e4cSMichael Walshdef valid_state():
55145ca6e4cSMichael Walsh    r"""
55245ca6e4cSMichael Walsh    Verify that our state dictionary contains no blank values.  If we don't get
55345ca6e4cSMichael Walsh    valid state data, we cannot continue to work.
55445ca6e4cSMichael Walsh    """
55545ca6e4cSMichael Walsh
55645ca6e4cSMichael Walsh    if st.compare_states(state, st.invalid_state_match, 'or'):
55745ca6e4cSMichael Walsh        error_message = "The state dictionary contains blank fields which" +\
55845ca6e4cSMichael Walsh            " is illegal.\n" + gp.sprint_var(state)
55945ca6e4cSMichael Walsh        BuiltIn().fail(gp.sprint_error(error_message))
56045ca6e4cSMichael Walsh
56145ca6e4cSMichael Walsh
5626741f740SMichael Walshdef select_boot():
563341c21ebSMichael Walsh    r"""
564341c21ebSMichael Walsh    Select a boot test to be run based on our current state and return the
565341c21ebSMichael Walsh    chosen boot type.
566341c21ebSMichael Walsh
567341c21ebSMichael Walsh    Description of arguments:
5686741f740SMichael Walsh    state  The state of the machine.
569341c21ebSMichael Walsh    """
570341c21ebSMichael Walsh
57181816748SMichael Walsh    global transitional_boot_selected
57230dadae2SMichael Walsh    global boot_stack
57330dadae2SMichael Walsh
574b5839d00SMichael Walsh    gp.qprint_timen("Selecting a boot test.")
5756741f740SMichael Walsh
57681816748SMichael Walsh    if transitional_boot_selected and not boot_success:
57781816748SMichael Walsh        prior_boot = next_boot
57881816748SMichael Walsh        boot_candidate = boot_stack.pop()
579004ad3c9SJoy Onyerikwu        gp.qprint_timen("The prior '" + next_boot + "' was chosen to"
580004ad3c9SJoy Onyerikwu                        + " transition to a valid state for '" + boot_candidate
581004ad3c9SJoy Onyerikwu                        + "' which was at the top of the boot_stack.  Since"
582004ad3c9SJoy Onyerikwu                        + " the '" + next_boot + "' failed, the '"
583004ad3c9SJoy Onyerikwu                        + boot_candidate + "' has been removed from the stack"
584004ad3c9SJoy Onyerikwu                        + " to avoid and endless failure loop.")
58581816748SMichael Walsh        if len(boot_stack) == 0:
58681816748SMichael Walsh            return ""
58781816748SMichael Walsh
5886741f740SMichael Walsh    my_get_state()
58945ca6e4cSMichael Walsh    valid_state()
5906741f740SMichael Walsh
59181816748SMichael Walsh    transitional_boot_selected = False
5926741f740SMichael Walsh    stack_popped = 0
5936741f740SMichael Walsh    if len(boot_stack) > 0:
5946741f740SMichael Walsh        stack_popped = 1
595b5839d00SMichael Walsh        gp.qprint_dashes()
596b5839d00SMichael Walsh        gp.qprint_var(boot_stack)
597b5839d00SMichael Walsh        gp.qprint_dashes()
598b5839d00SMichael Walsh        skip_boot_printed = 0
599b5839d00SMichael Walsh        while len(boot_stack) > 0:
6006741f740SMichael Walsh            boot_candidate = boot_stack.pop()
601b5839d00SMichael Walsh            if stack_mode == 'normal':
602b5839d00SMichael Walsh                break
603b5839d00SMichael Walsh            else:
604b5839d00SMichael Walsh                if st.compare_states(state, boot_table[boot_candidate]['end']):
605b5839d00SMichael Walsh                    if not skip_boot_printed:
606ff340006SMichael Walsh                        gp.qprint_var(stack_mode)
607ff340006SMichael Walsh                        gp.qprintn()
608004ad3c9SJoy Onyerikwu                        gp.qprint_timen("Skipping the following boot tests"
609004ad3c9SJoy Onyerikwu                                        + " which are unnecessary since their"
610004ad3c9SJoy Onyerikwu                                        + " required end states match the"
611004ad3c9SJoy Onyerikwu                                        + " current machine state:")
612b5839d00SMichael Walsh                        skip_boot_printed = 1
613ff340006SMichael Walsh                    gp.qprint_var(boot_candidate)
614b5839d00SMichael Walsh                    boot_candidate = ""
615b5839d00SMichael Walsh        if boot_candidate == "":
616b5839d00SMichael Walsh            gp.qprint_dashes()
617b5839d00SMichael Walsh            gp.qprint_var(boot_stack)
618b5839d00SMichael Walsh            gp.qprint_dashes()
619b5839d00SMichael Walsh            return boot_candidate
6206741f740SMichael Walsh        if st.compare_states(state, boot_table[boot_candidate]['start']):
621004ad3c9SJoy Onyerikwu            gp.qprint_timen("The machine state is valid for a '"
622004ad3c9SJoy Onyerikwu                            + boot_candidate + "' boot test.")
623b5839d00SMichael Walsh            gp.qprint_dashes()
624b5839d00SMichael Walsh            gp.qprint_var(boot_stack)
625b5839d00SMichael Walsh            gp.qprint_dashes()
6266741f740SMichael Walsh            return boot_candidate
627341c21ebSMichael Walsh        else:
628004ad3c9SJoy Onyerikwu            gp.qprint_timen("The machine state does not match the required"
629004ad3c9SJoy Onyerikwu                            + " starting state for a '" + boot_candidate
630004ad3c9SJoy Onyerikwu                            + "' boot test:")
631986d8aeeSMichael Walsh            gp.qprint_varx("boot_table_start_entry",
632986d8aeeSMichael Walsh                           boot_table[boot_candidate]['start'])
6336741f740SMichael Walsh            boot_stack.append(boot_candidate)
63481816748SMichael Walsh            transitional_boot_selected = True
6356741f740SMichael Walsh            popped_boot = boot_candidate
6366741f740SMichael Walsh
6376741f740SMichael Walsh    # Loop through your list selecting a boot_candidates
6386741f740SMichael Walsh    boot_candidates = []
6396741f740SMichael Walsh    for boot_candidate in boot_list:
6406741f740SMichael Walsh        if st.compare_states(state, boot_table[boot_candidate]['start']):
6416741f740SMichael Walsh            if stack_popped:
6426741f740SMichael Walsh                if st.compare_states(boot_table[boot_candidate]['end'],
6436741f740SMichael Walsh                                     boot_table[popped_boot]['start']):
6446741f740SMichael Walsh                    boot_candidates.append(boot_candidate)
645341c21ebSMichael Walsh            else:
6466741f740SMichael Walsh                boot_candidates.append(boot_candidate)
6476741f740SMichael Walsh
6486741f740SMichael Walsh    if len(boot_candidates) == 0:
649004ad3c9SJoy Onyerikwu        gp.qprint_timen("The user's boot list contained no boot tests"
650004ad3c9SJoy Onyerikwu                        + " which are valid for the current machine state.")
6516741f740SMichael Walsh        boot_candidate = default_power_on
6526741f740SMichael Walsh        if not st.compare_states(state, boot_table[default_power_on]['start']):
6536741f740SMichael Walsh            boot_candidate = default_power_off
6546741f740SMichael Walsh        boot_candidates.append(boot_candidate)
655004ad3c9SJoy Onyerikwu        gp.qprint_timen("Using default '" + boot_candidate
656004ad3c9SJoy Onyerikwu                        + "' boot type to transition to valid state.")
6576741f740SMichael Walsh
658b5839d00SMichael Walsh    gp.dprint_var(boot_candidates)
6596741f740SMichael Walsh
6606741f740SMichael Walsh    # Randomly select a boot from the candidate list.
6616741f740SMichael Walsh    boot = random.choice(boot_candidates)
662341c21ebSMichael Walsh
663341c21ebSMichael Walsh    return boot
6640bbd860fSMichael Walsh
66555302295SMichael Walsh
666b2e53ecdSMichael Walshdef print_defect_report(ffdc_file_list):
667341c21ebSMichael Walsh    r"""
668341c21ebSMichael Walsh    Print a defect report.
669b2e53ecdSMichael Walsh
670b2e53ecdSMichael Walsh    Description of argument(s):
671b2e53ecdSMichael Walsh    ffdc_file_list  A list of files which were collected by our ffdc functions.
672341c21ebSMichael Walsh    """
673341c21ebSMichael Walsh
674600876daSMichael Walsh    # Making deliberate choice to NOT run plug_in_setup().  We don't want
675600876daSMichael Walsh    # ffdc_prefix updated.
676600876daSMichael Walsh    rc, shell_rc, failed_plug_in_name = grpi.rprocess_plug_in_packages(
677600876daSMichael Walsh        call_point='ffdc_report', stop_on_plug_in_failure=0)
678600876daSMichael Walsh
679e0cf8d70SMichael Walsh    # Get additional header data which may have been created by ffdc plug-ins.
680e0cf8d70SMichael Walsh    # Also, delete the individual header files to cleanup.
681e0cf8d70SMichael Walsh    cmd_buf = "file_list=$(cat " + ffdc_report_list_path + " 2>/dev/null)" +\
682e0cf8d70SMichael Walsh              " ; [ ! -z \"${file_list}\" ] && cat ${file_list}" +\
683e0cf8d70SMichael Walsh              " 2>/dev/null ; rm -rf ${file_list} 2>/dev/null || :"
684e0cf8d70SMichael Walsh    shell_rc, more_header_info = gc.cmd_fnc_u(cmd_buf, print_output=0,
685e0cf8d70SMichael Walsh                                              show_err=0)
686e0cf8d70SMichael Walsh
687b2e53ecdSMichael Walsh    # Get additional summary data which may have been created by ffdc plug-ins.
688600876daSMichael Walsh    # Also, delete the individual header files to cleanup.
689600876daSMichael Walsh    cmd_buf = "file_list=$(cat " + ffdc_summary_list_path + " 2>/dev/null)" +\
690600876daSMichael Walsh              " ; [ ! -z \"${file_list}\" ] && cat ${file_list}" +\
691600876daSMichael Walsh              " 2>/dev/null ; rm -rf ${file_list} 2>/dev/null || :"
692600876daSMichael Walsh    shell_rc, ffdc_summary_info = gc.cmd_fnc_u(cmd_buf, print_output=0,
693600876daSMichael Walsh                                               show_err=0)
694600876daSMichael Walsh
695b2e53ecdSMichael Walsh    # ffdc_list_file_path contains a list of any ffdc files created by plug-
696b2e53ecdSMichael Walsh    # ins, etc.  Read that data into a list.
697341c21ebSMichael Walsh    try:
698b2e53ecdSMichael Walsh        plug_in_ffdc_list = \
699b2e53ecdSMichael Walsh            open(ffdc_list_file_path, 'r').read().rstrip("\n").split("\n")
70036efbc04SGeorge Keishing        plug_in_ffdc_list = list(filter(None, plug_in_ffdc_list))
701341c21ebSMichael Walsh    except IOError:
702b2e53ecdSMichael Walsh        plug_in_ffdc_list = []
703b2e53ecdSMichael Walsh
704b2e53ecdSMichael Walsh    # Combine the files from plug_in_ffdc_list with the ffdc_file_list passed
705b2e53ecdSMichael Walsh    # in.  Eliminate duplicates and sort the list.
706004ad3c9SJoy Onyerikwu    ffdc_file_list = sorted(set(ffdc_file_list + plug_in_ffdc_list))
707b2e53ecdSMichael Walsh
708b2e53ecdSMichael Walsh    if status_file_path != "":
709b2e53ecdSMichael Walsh        ffdc_file_list.insert(0, status_file_path)
710b2e53ecdSMichael Walsh
711b2e53ecdSMichael Walsh    # Convert the list to a printable list.
712b2e53ecdSMichael Walsh    printable_ffdc_file_list = "\n".join(ffdc_file_list)
713341c21ebSMichael Walsh
71468a61162SMichael Walsh    # Open ffdc_file_list for writing.  We will write a complete list of
71568a61162SMichael Walsh    # FFDC files to it for possible use by plug-ins like cp_stop_check.
71668a61162SMichael Walsh    ffdc_list_file = open(ffdc_list_file_path, 'w')
717b2e53ecdSMichael Walsh    ffdc_list_file.write(printable_ffdc_file_list + "\n")
718b2e53ecdSMichael Walsh    ffdc_list_file.close()
719b2e53ecdSMichael Walsh
720b2e53ecdSMichael Walsh    indent = 0
721b2e53ecdSMichael Walsh    width = 90
722b2e53ecdSMichael Walsh    linefeed = 1
723b2e53ecdSMichael Walsh    char = "="
72468a61162SMichael Walsh
72568a61162SMichael Walsh    gp.qprintn()
726b2e53ecdSMichael Walsh    gp.qprint_dashes(indent, width, linefeed, char)
72768a61162SMichael Walsh    gp.qprintn("Copy this data to the defect:\n")
72868a61162SMichael Walsh
729e0cf8d70SMichael Walsh    if len(more_header_info) > 0:
730ff340006SMichael Walsh        gp.qprintn(more_header_info)
731dc80d67dSMichael Walsh    gp.qpvars(host_name, host_ip, openbmc_nickname, openbmc_host,
732dc80d67dSMichael Walsh              openbmc_host_name, openbmc_ip, openbmc_username,
7330a3bdb4cSMichael Walsh              openbmc_password, rest_username, rest_password, ipmi_username,
7340a3bdb4cSMichael Walsh              ipmi_password, os_host, os_host_name, os_ip, os_username,
735dc80d67dSMichael Walsh              os_password, pdu_host, pdu_host_name, pdu_ip, pdu_username,
736dc80d67dSMichael Walsh              pdu_password, pdu_slot_no, openbmc_serial_host,
737dc80d67dSMichael Walsh              openbmc_serial_host_name, openbmc_serial_ip, openbmc_serial_port)
73868a61162SMichael Walsh
73968a61162SMichael Walsh    gp.qprintn()
740986d8aeeSMichael Walsh    print_boot_history(boot_history)
74168a61162SMichael Walsh    gp.qprintn()
74268a61162SMichael Walsh    gp.qprint_var(state)
743b5839d00SMichael Walsh    gp.qprintn()
744b5839d00SMichael Walsh    gp.qprintn("FFDC data files:")
745b2e53ecdSMichael Walsh    gp.qprintn(printable_ffdc_file_list)
746b5839d00SMichael Walsh    gp.qprintn()
747341c21ebSMichael Walsh
748600876daSMichael Walsh    if len(ffdc_summary_info) > 0:
749ff340006SMichael Walsh        gp.qprintn(ffdc_summary_info)
750600876daSMichael Walsh
751b2e53ecdSMichael Walsh    gp.qprint_dashes(indent, width, linefeed, char)
75268a61162SMichael Walsh
7536741f740SMichael Walsh
7546741f740SMichael Walshdef my_ffdc():
7556741f740SMichael Walsh    r"""
7566741f740SMichael Walsh    Collect FFDC data.
7576741f740SMichael Walsh    """
7586741f740SMichael Walsh
7596741f740SMichael Walsh    global state
7606741f740SMichael Walsh
7616741f740SMichael Walsh    plug_in_setup()
7626741f740SMichael Walsh    rc, shell_rc, failed_plug_in_name = grpi.rprocess_plug_in_packages(
763600876daSMichael Walsh        call_point='ffdc', stop_on_plug_in_failure=0)
7646741f740SMichael Walsh
7656741f740SMichael Walsh    AUTOBOOT_FFDC_PREFIX = os.environ['AUTOBOOT_FFDC_PREFIX']
766004ad3c9SJoy Onyerikwu    status, ffdc_file_list = grk.run_key_u("FFDC  ffdc_prefix="
767004ad3c9SJoy Onyerikwu                                           + AUTOBOOT_FFDC_PREFIX
768004ad3c9SJoy Onyerikwu                                           + "  ffdc_function_list="
769004ad3c9SJoy Onyerikwu                                           + ffdc_function_list, ignore=1)
77083f4bc77SMichael Walsh    if status != 'PASS':
771ff340006SMichael Walsh        gp.qprint_error("Call to ffdc failed.\n")
772c9bd2e87SMichael Walsh        if type(ffdc_file_list) is not list:
773c9bd2e87SMichael Walsh            ffdc_file_list = []
774c9bd2e87SMichael Walsh        # Leave a record for caller that "soft" errors occurred.
775c9bd2e87SMichael Walsh        soft_errors = 1
776c9bd2e87SMichael Walsh        gpu.save_plug_in_value(soft_errors, pgm_name)
7776741f740SMichael Walsh
7786741f740SMichael Walsh    my_get_state()
7796741f740SMichael Walsh
780b2e53ecdSMichael Walsh    print_defect_report(ffdc_file_list)
7816741f740SMichael Walsh
7826741f740SMichael Walsh
7836741f740SMichael Walshdef print_test_start_message(boot_keyword):
7846741f740SMichael Walsh    r"""
7856741f740SMichael Walsh    Print a message indicating what boot test is about to run.
7866741f740SMichael Walsh
7876741f740SMichael Walsh    Description of arguments:
7886741f740SMichael Walsh    boot_keyword  The name of the boot which is to be run
7896741f740SMichael Walsh                  (e.g. "BMC Power On").
7906741f740SMichael Walsh    """
7916741f740SMichael Walsh
792986d8aeeSMichael Walsh    global boot_history
793325eb548SSunil M    global boot_start_time
7946741f740SMichael Walsh
7956741f740SMichael Walsh    doing_msg = gp.sprint_timen("Doing \"" + boot_keyword + "\".")
796325eb548SSunil M
797325eb548SSunil M    # Set boot_start_time for use by plug-ins.
798325eb548SSunil M    boot_start_time = doing_msg[1:33]
799325eb548SSunil M    gp.qprint_var(boot_start_time)
800325eb548SSunil M
801b5839d00SMichael Walsh    gp.qprint(doing_msg)
8026741f740SMichael Walsh
803986d8aeeSMichael Walsh    update_boot_history(boot_history, doing_msg, max_boot_history)
8046741f740SMichael Walsh
8056741f740SMichael Walsh
806f566fb1fSMichael Walshdef stop_boot_test(signal_number=0,
807f566fb1fSMichael Walsh                   frame=None):
808f566fb1fSMichael Walsh    r"""
809f566fb1fSMichael Walsh    Handle SIGUSR1 by aborting the boot test that is running.
810f566fb1fSMichael Walsh
811f566fb1fSMichael Walsh    Description of argument(s):
812f566fb1fSMichael Walsh    signal_number  The signal number (should always be 10 for SIGUSR1).
813f566fb1fSMichael Walsh    frame          The frame data.
814f566fb1fSMichael Walsh    """
815f566fb1fSMichael Walsh
81680dddde9SMichael Walsh    gp.qprintn()
81780dddde9SMichael Walsh    gp.qprint_executing()
818f566fb1fSMichael Walsh    gp.lprint_executing()
819f566fb1fSMichael Walsh
820f566fb1fSMichael Walsh    # Restore original sigusr1 handler.
821f566fb1fSMichael Walsh    set_default_siguser1()
822f566fb1fSMichael Walsh
823f566fb1fSMichael Walsh    message = "The caller has asked that the boot test be stopped and marked"
824f566fb1fSMichael Walsh    message += " as a failure."
825f566fb1fSMichael Walsh
826f566fb1fSMichael Walsh    function_stack = gm.get_function_stack()
827f566fb1fSMichael Walsh    if "wait_state" in function_stack:
828c44aa538SMichael Walsh        st.set_exit_wait_early_message(message)
829f566fb1fSMichael Walsh    else:
830f566fb1fSMichael Walsh        BuiltIn().fail(gp.sprint_error(message))
831f566fb1fSMichael Walsh
832f566fb1fSMichael Walsh
8336741f740SMichael Walshdef run_boot(boot):
8346741f740SMichael Walsh    r"""
8356741f740SMichael Walsh    Run the specified boot.
8366741f740SMichael Walsh
8376741f740SMichael Walsh    Description of arguments:
8386741f740SMichael Walsh    boot  The name of the boot test to be performed.
8396741f740SMichael Walsh    """
8406741f740SMichael Walsh
8416741f740SMichael Walsh    global state
8426741f740SMichael Walsh
843f566fb1fSMichael Walsh    signal.signal(signal.SIGUSR1, stop_boot_test)
844f566fb1fSMichael Walsh    gp.qprint_timen("stop_boot_test is armed.")
845f566fb1fSMichael Walsh
8466741f740SMichael Walsh    print_test_start_message(boot)
8476741f740SMichael Walsh
8486741f740SMichael Walsh    plug_in_setup()
8496741f740SMichael Walsh    rc, shell_rc, failed_plug_in_name = \
8506741f740SMichael Walsh        grpi.rprocess_plug_in_packages(call_point="pre_boot")
8516741f740SMichael Walsh    if rc != 0:
8526741f740SMichael Walsh        error_message = "Plug-in failed with non-zero return code.\n" +\
853986d8aeeSMichael Walsh            gp.sprint_var(rc, fmt=gp.hexa())
854f566fb1fSMichael Walsh        set_default_siguser1()
8556741f740SMichael Walsh        BuiltIn().fail(gp.sprint_error(error_message))
8566741f740SMichael Walsh
8576741f740SMichael Walsh    if test_mode:
8586741f740SMichael Walsh        # In test mode, we'll pretend the boot worked by assigning its
8596741f740SMichael Walsh        # required end state to the default state value.
86030dadae2SMichael Walsh        state = st.strip_anchor_state(boot_table[boot]['end'])
8616741f740SMichael Walsh    else:
8626741f740SMichael Walsh        # Assertion:  We trust that the state data was made fresh by the
8636741f740SMichael Walsh        # caller.
8646741f740SMichael Walsh
865b5839d00SMichael Walsh        gp.qprintn()
8666741f740SMichael Walsh
8676741f740SMichael Walsh        if boot_table[boot]['method_type'] == "keyword":
8680b93fbf8SMichael Walsh            rk.my_run_keywords(boot_table[boot].get('lib_file_path', ''),
869b5839d00SMichael Walsh                               boot_table[boot]['method'],
870b5839d00SMichael Walsh                               quiet=quiet)
8716741f740SMichael Walsh
8726741f740SMichael Walsh        if boot_table[boot]['bmc_reboot']:
8736741f740SMichael Walsh            st.wait_for_comm_cycle(int(state['epoch_seconds']))
87430dadae2SMichael Walsh            plug_in_setup()
87530dadae2SMichael Walsh            rc, shell_rc, failed_plug_in_name = \
87630dadae2SMichael Walsh                grpi.rprocess_plug_in_packages(call_point="post_reboot")
87730dadae2SMichael Walsh            if rc != 0:
8780b93fbf8SMichael Walsh                error_message = "Plug-in failed with non-zero return code.\n"
879986d8aeeSMichael Walsh                error_message += gp.sprint_var(rc, fmt=gp.hexa())
880f566fb1fSMichael Walsh                set_default_siguser1()
88130dadae2SMichael Walsh                BuiltIn().fail(gp.sprint_error(error_message))
8826741f740SMichael Walsh        else:
8836741f740SMichael Walsh            match_state = st.anchor_state(state)
8846741f740SMichael Walsh            del match_state['epoch_seconds']
8856741f740SMichael Walsh            # Wait for the state to change in any way.
8866741f740SMichael Walsh            st.wait_state(match_state, wait_time=state_change_timeout,
887600876daSMichael Walsh                          interval="10 seconds", invert=1)
8886741f740SMichael Walsh
889b5839d00SMichael Walsh        gp.qprintn()
8906741f740SMichael Walsh        if boot_table[boot]['end']['chassis'] == "Off":
8916741f740SMichael Walsh            boot_timeout = power_off_timeout
8926741f740SMichael Walsh        else:
8936741f740SMichael Walsh            boot_timeout = power_on_timeout
8946741f740SMichael Walsh        st.wait_state(boot_table[boot]['end'], wait_time=boot_timeout,
895600876daSMichael Walsh                      interval="10 seconds")
8966741f740SMichael Walsh
8976741f740SMichael Walsh    plug_in_setup()
8986741f740SMichael Walsh    rc, shell_rc, failed_plug_in_name = \
8996741f740SMichael Walsh        grpi.rprocess_plug_in_packages(call_point="post_boot")
9006741f740SMichael Walsh    if rc != 0:
9016741f740SMichael Walsh        error_message = "Plug-in failed with non-zero return code.\n" +\
902986d8aeeSMichael Walsh            gp.sprint_var(rc, fmt=gp.hexa())
903f566fb1fSMichael Walsh        set_default_siguser1()
9046741f740SMichael Walsh        BuiltIn().fail(gp.sprint_error(error_message))
9056741f740SMichael Walsh
906f566fb1fSMichael Walsh    # Restore original sigusr1 handler.
907f566fb1fSMichael Walsh    set_default_siguser1()
908f566fb1fSMichael Walsh
9096741f740SMichael Walsh
9106741f740SMichael Walshdef test_loop_body():
9116741f740SMichael Walsh    r"""
9126741f740SMichael Walsh    The main loop body for the loop in main_py.
9136741f740SMichael Walsh
9146741f740SMichael Walsh    Description of arguments:
9156741f740SMichael Walsh    boot_count  The iteration number (starts at 1).
9166741f740SMichael Walsh    """
9176741f740SMichael Walsh
9186741f740SMichael Walsh    global boot_count
9196741f740SMichael Walsh    global state
9206741f740SMichael Walsh    global next_boot
9216741f740SMichael Walsh    global boot_success
922325eb548SSunil M    global boot_end_time
9236741f740SMichael Walsh
924b5839d00SMichael Walsh    gp.qprintn()
9256741f740SMichael Walsh
9266741f740SMichael Walsh    next_boot = select_boot()
927b5839d00SMichael Walsh    if next_boot == "":
928b5839d00SMichael Walsh        return True
9296741f740SMichael Walsh
930b5839d00SMichael Walsh    boot_count += 1
931b5839d00SMichael Walsh    gp.qprint_timen("Starting boot " + str(boot_count) + ".")
9326741f740SMichael Walsh
933e0cf8d70SMichael Walsh    pre_boot_plug_in_setup()
9346741f740SMichael Walsh
9356741f740SMichael Walsh    cmd_buf = ["run_boot", next_boot]
9366741f740SMichael Walsh    boot_status, msg = BuiltIn().run_keyword_and_ignore_error(*cmd_buf)
9376741f740SMichael Walsh    if boot_status == "FAIL":
938b5839d00SMichael Walsh        gp.qprint(msg)
9396741f740SMichael Walsh
940b5839d00SMichael Walsh    gp.qprintn()
9416741f740SMichael Walsh    if boot_status == "PASS":
9426741f740SMichael Walsh        boot_success = 1
943004ad3c9SJoy Onyerikwu        completion_msg = gp.sprint_timen("BOOT_SUCCESS: \"" + next_boot
944004ad3c9SJoy Onyerikwu                                         + "\" succeeded.")
9456741f740SMichael Walsh    else:
9466741f740SMichael Walsh        boot_success = 0
947004ad3c9SJoy Onyerikwu        completion_msg = gp.sprint_timen("BOOT_FAILED: \"" + next_boot
948004ad3c9SJoy Onyerikwu                                         + "\" failed.")
949325eb548SSunil M
950325eb548SSunil M    # Set boot_end_time for use by plug-ins.
951325eb548SSunil M    boot_end_time = completion_msg[1:33]
952325eb548SSunil M    gp.qprint_var(boot_end_time)
953325eb548SSunil M
954325eb548SSunil M    gp.qprint(completion_msg)
9556741f740SMichael Walsh
9566741f740SMichael Walsh    boot_results.update(next_boot, boot_status)
9576741f740SMichael Walsh
9586741f740SMichael Walsh    plug_in_setup()
9596741f740SMichael Walsh    # NOTE: A post_test_case call point failure is NOT counted as a boot
9606741f740SMichael Walsh    # failure.
9616741f740SMichael Walsh    rc, shell_rc, failed_plug_in_name = grpi.rprocess_plug_in_packages(
962600876daSMichael Walsh        call_point='post_test_case', stop_on_plug_in_failure=0)
9636741f740SMichael Walsh
9646741f740SMichael Walsh    plug_in_setup()
9656741f740SMichael Walsh    rc, shell_rc, failed_plug_in_name = grpi.rprocess_plug_in_packages(
96689de14a4SMichael Walsh        call_point='ffdc_check', shell_rc=dump_ffdc_rc(),
9676741f740SMichael Walsh        stop_on_plug_in_failure=1, stop_on_non_zero_rc=1)
96812059e26SMichael Walsh    if ffdc_check == "All" or\
96989de14a4SMichael Walsh       shell_rc == dump_ffdc_rc():
97083f4bc77SMichael Walsh        status, ret_values = grk.run_key_u("my_ffdc", ignore=1)
97183f4bc77SMichael Walsh        if status != 'PASS':
972ff340006SMichael Walsh            gp.qprint_error("Call to my_ffdc failed.\n")
973c9bd2e87SMichael Walsh            # Leave a record for caller that "soft" errors occurred.
974c9bd2e87SMichael Walsh            soft_errors = 1
975c9bd2e87SMichael Walsh            gpu.save_plug_in_value(soft_errors, pgm_name)
9766741f740SMichael Walsh
977aabef1e3SMichael Walsh    if delete_errlogs:
9781a67b08aSMichael Shepos        # print error logs before delete
979*438fd3b6SGeorge Keishing        if redfish_support_trans_state:
980*438fd3b6SGeorge Keishing            status, error_logs = grk.run_key_u("Get Redfish Event Logs")
981*438fd3b6SGeorge Keishing            log.print_error_logs(error_logs, "AdditionalDataURI Message Severity")
982*438fd3b6SGeorge Keishing        else:
9831a67b08aSMichael Shepos            status, error_logs = grk.run_key_u("Get Error Logs")
9840e5f1137SMichael Shepos            log.print_error_logs(error_logs, "AdditionalData Message Severity")
985*438fd3b6SGeorge Keishing        pels = pel.peltool("-l", ignore_err=1)
9860e5f1137SMichael Shepos        gp.qprint_var(pels)
9871a67b08aSMichael Shepos
988d139f286SMichael Walsh        # We need to purge error logs between boots or they build up.
989409ad35aSMichael Walsh        grk.run_key(delete_errlogs_cmd, ignore=1)
99092a54bf5SMichael Shepos        grk.run_key(delete_bmcdump_cmd, ignore=1)
9912ef6a7dbSGeorge Keishing        if redfish_support_trans_state:
9922ef6a7dbSGeorge Keishing            grk.run_key(delete_sysdump_cmd, ignore=1)
993d139f286SMichael Walsh
994952f9b09SMichael Walsh    boot_results.print_report()
995b5839d00SMichael Walsh    gp.qprint_timen("Finished boot " + str(boot_count) + ".")
996952f9b09SMichael Walsh
9976741f740SMichael Walsh    plug_in_setup()
9986741f740SMichael Walsh    rc, shell_rc, failed_plug_in_name = grpi.rprocess_plug_in_packages(
99989de14a4SMichael Walsh        call_point='stop_check', shell_rc=stop_test_rc(),
100089de14a4SMichael Walsh        stop_on_non_zero_rc=1)
100189de14a4SMichael Walsh    if shell_rc == stop_test_rc():
10023ba8ecdcSMichael Walsh        message = "Stopping as requested by user.\n"
100380dddde9SMichael Walsh        gp.qprint_time(message)
10043ba8ecdcSMichael Walsh        BuiltIn().fail(message)
10056741f740SMichael Walsh
1006d139f286SMichael Walsh    # This should help prevent ConnectionErrors.
10074d65c86dSGeorge Keishing    # Purge all redfish and REST connection sessions.
1008d86e45c6SGeorge Keishing    if redfish_delete_sessions:
10094d65c86dSGeorge Keishing        grk.run_key_u("Close All Connections", ignore=1)
10104d65c86dSGeorge Keishing        grk.run_key_u("Delete All Redfish Sessions", ignore=1)
1011d139f286SMichael Walsh
10126741f740SMichael Walsh    return True
10136741f740SMichael Walsh
10146741f740SMichael Walsh
101583f4bc77SMichael Walshdef obmc_boot_test_teardown():
10166741f740SMichael Walsh    r"""
1017f75d4354SMichael Walsh    Clean up after the main keyword.
10186741f740SMichael Walsh    """
1019f75d4354SMichael Walsh    gp.qprint_executing()
1020f75d4354SMichael Walsh
1021f75d4354SMichael Walsh    if ga.psutil_imported:
1022f75d4354SMichael Walsh        ga.terminate_descendants()
10236741f740SMichael Walsh
10246741f740SMichael Walsh    if cp_setup_called:
10256741f740SMichael Walsh        plug_in_setup()
10266741f740SMichael Walsh        rc, shell_rc, failed_plug_in_name = grpi.rprocess_plug_in_packages(
1027600876daSMichael Walsh            call_point='cleanup', stop_on_plug_in_failure=0)
10286741f740SMichael Walsh
1029600876daSMichael Walsh    if 'boot_results_file_path' in globals():
1030986d8aeeSMichael Walsh        # Save boot_results and boot_history objects to a file in case they are
10316c64574bSMichael Walsh        # needed again.
1032b5839d00SMichael Walsh        gp.qprint_timen("Saving boot_results to the following path.")
1033b5839d00SMichael Walsh        gp.qprint_var(boot_results_file_path)
1034986d8aeeSMichael Walsh        pickle.dump((boot_results, boot_history),
10356c64574bSMichael Walsh                    open(boot_results_file_path, 'wb'),
10360b93fbf8SMichael Walsh                    pickle.HIGHEST_PROTOCOL)
10370b93fbf8SMichael Walsh
1038ff340006SMichael Walsh    global save_stack
1039ff340006SMichael Walsh    # Restore any global values saved on the save_stack.
1040ff340006SMichael Walsh    for parm_name in main_func_parm_list:
1041ff340006SMichael Walsh        # Get the parm_value if it was saved on the stack.
1042ff340006SMichael Walsh        try:
1043ff340006SMichael Walsh            parm_value = save_stack.pop(parm_name)
1044004ad3c9SJoy Onyerikwu        except BaseException:
1045ff340006SMichael Walsh            # If it was not saved, no further action is required.
1046ff340006SMichael Walsh            continue
1047ff340006SMichael Walsh
1048ff340006SMichael Walsh        # Restore the saved value.
1049ff340006SMichael Walsh        cmd_buf = "BuiltIn().set_global_variable(\"${" + parm_name +\
1050ff340006SMichael Walsh            "}\", parm_value)"
1051ff340006SMichael Walsh        gp.dpissuing(cmd_buf)
1052ff340006SMichael Walsh        exec(cmd_buf)
1053ff340006SMichael Walsh
1054ff340006SMichael Walsh    gp.dprintn(save_stack.sprint_obj())
1055ff340006SMichael Walsh
10566741f740SMichael Walsh
1057c9116811SMichael Walshdef test_teardown():
1058c9116811SMichael Walsh    r"""
1059c9116811SMichael Walsh    Clean up after this test case.
1060c9116811SMichael Walsh    """
1061c9116811SMichael Walsh
1062c9116811SMichael Walsh    gp.qprintn()
1063f75d4354SMichael Walsh    gp.qprint_executing()
1064f75d4354SMichael Walsh
1065f75d4354SMichael Walsh    if ga.psutil_imported:
1066f75d4354SMichael Walsh        ga.terminate_descendants()
1067f75d4354SMichael Walsh
1068c9116811SMichael Walsh    cmd_buf = ["Print Error",
1069c9116811SMichael Walsh               "A keyword timeout occurred ending this program.\n"]
1070c9116811SMichael Walsh    BuiltIn().run_keyword_if_timeout_occurred(*cmd_buf)
1071c9116811SMichael Walsh
1072a54e06f5SGeorge Keishing    if redfish_supported:
1073a54e06f5SGeorge Keishing        redfish.logout()
1074a54e06f5SGeorge Keishing
1075c108e429SMichael Walsh    gp.qprint_pgm_footer()
1076b5839d00SMichael Walsh
1077c9116811SMichael Walsh
107889de14a4SMichael Walshdef post_stack():
107989de14a4SMichael Walsh    r"""
108089de14a4SMichael Walsh    Process post_stack plug-in programs.
108189de14a4SMichael Walsh    """
108289de14a4SMichael Walsh
108389de14a4SMichael Walsh    if not call_post_stack_plug:
108489de14a4SMichael Walsh        # The caller does not wish to have post_stack plug-in processing done.
108589de14a4SMichael Walsh        return
108689de14a4SMichael Walsh
108789de14a4SMichael Walsh    global boot_success
108889de14a4SMichael Walsh
108989de14a4SMichael Walsh    # NOTE: A post_stack call-point failure is NOT counted as a boot failure.
109089de14a4SMichael Walsh    pre_boot_plug_in_setup()
109189de14a4SMichael Walsh    # For the purposes of the following plug-ins, mark the "boot" as a success.
109289de14a4SMichael Walsh    boot_success = 1
109389de14a4SMichael Walsh    plug_in_setup()
1094815b1d5bSMichael Walsh    rc, shell_rc, failed_plug_in_name, history =\
1095815b1d5bSMichael Walsh        grpi.rprocess_plug_in_packages(call_point='post_stack',
1096815b1d5bSMichael Walsh                                       stop_on_plug_in_failure=0,
1097815b1d5bSMichael Walsh                                       return_history=True)
1098986d8aeeSMichael Walsh    for doing_msg in history:
1099986d8aeeSMichael Walsh        update_boot_history(boot_history, doing_msg, max_boot_history)
1100815b1d5bSMichael Walsh    if rc != 0:
1101815b1d5bSMichael Walsh        boot_success = 0
110289de14a4SMichael Walsh
110389de14a4SMichael Walsh    plug_in_setup()
1104815b1d5bSMichael Walsh    rc, shell_rc, failed_plug_in_name =\
1105815b1d5bSMichael Walsh        grpi.rprocess_plug_in_packages(call_point='ffdc_check',
1106815b1d5bSMichael Walsh                                       shell_rc=dump_ffdc_rc(),
1107815b1d5bSMichael Walsh                                       stop_on_plug_in_failure=1,
1108815b1d5bSMichael Walsh                                       stop_on_non_zero_rc=1)
1109815b1d5bSMichael Walsh    if shell_rc == dump_ffdc_rc():
111089de14a4SMichael Walsh        status, ret_values = grk.run_key_u("my_ffdc", ignore=1)
111189de14a4SMichael Walsh        if status != 'PASS':
111289de14a4SMichael Walsh            gp.qprint_error("Call to my_ffdc failed.\n")
1113c9bd2e87SMichael Walsh            # Leave a record for caller that "soft" errors occurred.
1114c9bd2e87SMichael Walsh            soft_errors = 1
1115c9bd2e87SMichael Walsh            gpu.save_plug_in_value(soft_errors, pgm_name)
111689de14a4SMichael Walsh
111789de14a4SMichael Walsh    plug_in_setup()
111889de14a4SMichael Walsh    rc, shell_rc, failed_plug_in_name = grpi.rprocess_plug_in_packages(
111989de14a4SMichael Walsh        call_point='stop_check', shell_rc=stop_test_rc(),
112089de14a4SMichael Walsh        stop_on_non_zero_rc=1)
112189de14a4SMichael Walsh    if shell_rc == stop_test_rc():
112289de14a4SMichael Walsh        message = "Stopping as requested by user.\n"
112380dddde9SMichael Walsh        gp.qprint_time(message)
112489de14a4SMichael Walsh        BuiltIn().fail(message)
112589de14a4SMichael Walsh
112689de14a4SMichael Walsh
1127ff340006SMichael Walshdef obmc_boot_test_py(loc_boot_stack=None,
1128ff340006SMichael Walsh                      loc_stack_mode=None,
1129ff340006SMichael Walsh                      loc_quiet=None):
11306741f740SMichael Walsh    r"""
11316741f740SMichael Walsh    Do main program processing.
11326741f740SMichael Walsh    """
11336741f740SMichael Walsh
1134ff340006SMichael Walsh    global save_stack
1135ff340006SMichael Walsh
1136f75d4354SMichael Walsh    ga.set_term_options(term_requests={'pgm_names': ['process_plug_in_packages.py']})
1137f75d4354SMichael Walsh
113836efbc04SGeorge Keishing    gp.dprintn()
1139ff340006SMichael Walsh    # Process function parms.
1140ff340006SMichael Walsh    for parm_name in main_func_parm_list:
1141ff340006SMichael Walsh        # Get parm's value.
114236efbc04SGeorge Keishing        parm_value = eval("loc_" + parm_name)
114336efbc04SGeorge Keishing        gp.dpvars(parm_name, parm_value)
1144ff340006SMichael Walsh
114536efbc04SGeorge Keishing        if parm_value is not None:
1146ff340006SMichael Walsh            # Save the global value on a stack.
1147ff340006SMichael Walsh            cmd_buf = "save_stack.push(BuiltIn().get_variable_value(\"${" +\
1148ff340006SMichael Walsh                parm_name + "}\"), \"" + parm_name + "\")"
1149ff340006SMichael Walsh            gp.dpissuing(cmd_buf)
1150ff340006SMichael Walsh            exec(cmd_buf)
1151ff340006SMichael Walsh
1152ff340006SMichael Walsh            # Set the global value to the passed value.
1153ff340006SMichael Walsh            cmd_buf = "BuiltIn().set_global_variable(\"${" + parm_name +\
1154ff340006SMichael Walsh                "}\", loc_" + parm_name + ")"
1155ff340006SMichael Walsh            gp.dpissuing(cmd_buf)
1156ff340006SMichael Walsh            exec(cmd_buf)
1157ff340006SMichael Walsh
1158ff340006SMichael Walsh    gp.dprintn(save_stack.sprint_obj())
1159b5839d00SMichael Walsh
11606741f740SMichael Walsh    setup()
11616741f740SMichael Walsh
1162cd9fbfd7SMichael Walsh    init_boot_pass, init_boot_fail = boot_results.return_total_pass_fail()
1163cd9fbfd7SMichael Walsh
1164a20da401SMichael Walsh    if ffdc_only:
1165a20da401SMichael Walsh        gp.qprint_timen("Caller requested ffdc_only.")
1166986d8aeeSMichael Walsh        if do_pre_boot_plug_in_setup:
1167e0cf8d70SMichael Walsh            pre_boot_plug_in_setup()
116883f4bc77SMichael Walsh        grk.run_key_u("my_ffdc")
1169764d2f83SMichael Walsh        return
1170a20da401SMichael Walsh
1171409ad35aSMichael Walsh    if delete_errlogs:
11721a67b08aSMichael Shepos        # print error logs before delete
1173*438fd3b6SGeorge Keishing        if redfish_support_trans_state:
1174*438fd3b6SGeorge Keishing            status, error_logs = grk.run_key_u("Get Redfish Event Logs")
1175*438fd3b6SGeorge Keishing            log.print_error_logs(error_logs, "AdditionalDataURI Message Severity")
1176*438fd3b6SGeorge Keishing        else:
11771a67b08aSMichael Shepos            status, error_logs = grk.run_key_u("Get Error Logs")
11780e5f1137SMichael Shepos            log.print_error_logs(error_logs, "AdditionalData Message Severity")
1179*438fd3b6SGeorge Keishing        pels = pel.peltool("-l", ignore_err=1)
11800e5f1137SMichael Shepos        gp.qprint_var(pels)
11811a67b08aSMichael Shepos
1182409ad35aSMichael Walsh        # Delete errlogs prior to doing any boot tests.
1183409ad35aSMichael Walsh        grk.run_key(delete_errlogs_cmd, ignore=1)
118492a54bf5SMichael Shepos        grk.run_key(delete_bmcdump_cmd, ignore=1)
11852ef6a7dbSGeorge Keishing        if redfish_support_trans_state:
11862ef6a7dbSGeorge Keishing            grk.run_key(delete_sysdump_cmd, ignore=1)
1187409ad35aSMichael Walsh
11886741f740SMichael Walsh    # Process caller's boot_stack.
11896741f740SMichael Walsh    while (len(boot_stack) > 0):
11906741f740SMichael Walsh        test_loop_body()
11916741f740SMichael Walsh
1192b5839d00SMichael Walsh    gp.qprint_timen("Finished processing stack.")
119330dadae2SMichael Walsh
119489de14a4SMichael Walsh    post_stack()
119589de14a4SMichael Walsh
11966741f740SMichael Walsh    # Process caller's boot_list.
11976741f740SMichael Walsh    if len(boot_list) > 0:
11986741f740SMichael Walsh        for ix in range(1, max_num_tests + 1):
11996741f740SMichael Walsh            test_loop_body()
12006741f740SMichael Walsh
1201b5839d00SMichael Walsh    gp.qprint_timen("Completed all requested boot tests.")
1202b5839d00SMichael Walsh
1203b5839d00SMichael Walsh    boot_pass, boot_fail = boot_results.return_total_pass_fail()
1204cd9fbfd7SMichael Walsh    new_fail = boot_fail - init_boot_fail
1205cd9fbfd7SMichael Walsh    if new_fail > boot_fail_threshold:
1206b5839d00SMichael Walsh        error_message = "Boot failures exceed the boot failure" +\
1207b5839d00SMichael Walsh                        " threshold:\n" +\
1208cd9fbfd7SMichael Walsh                        gp.sprint_var(new_fail) +\
1209b5839d00SMichael Walsh                        gp.sprint_var(boot_fail_threshold)
1210b5839d00SMichael Walsh        BuiltIn().fail(gp.sprint_error(error_message))
1211