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
13d54bbc22SGeorge Keishingtry:
140b93fbf8SMichael Walsh    import cPickle as pickle
15d54bbc22SGeorge Keishingexcept ImportError:
16d54bbc22SGeorge Keishing    import pickle
17dc80d67dSMichael Walshimport socket
180b93fbf8SMichael Walsh
190b93fbf8SMichael Walshfrom robot.utils import DotDict
200b93fbf8SMichael Walshfrom robot.libraries.BuiltIn import BuiltIn
210b93fbf8SMichael Walsh
226741f740SMichael Walshfrom boot_data import *
23c9116811SMichael Walshimport gen_print as gp
240bbd860fSMichael Walshimport gen_robot_print as grp
2555302295SMichael Walshimport gen_robot_plug_in as grpi
266741f740SMichael Walshimport gen_robot_valid as grv
276741f740SMichael Walshimport gen_misc as gm
286741f740SMichael Walshimport gen_cmd as gc
29b5839d00SMichael Walshimport gen_robot_keyword as grk
3055302295SMichael Walshimport state as st
31ff340006SMichael Walshimport var_stack as vs
320bbd860fSMichael Walsh
330b93fbf8SMichael Walshbase_path = os.path.dirname(os.path.dirname(
340b93fbf8SMichael Walsh                            imp.find_module("gen_robot_print")[1])) +\
350b93fbf8SMichael Walsh    os.sep
360b93fbf8SMichael Walshsys.path.append(base_path + "extended/")
370b93fbf8SMichael Walshimport run_keyword as rk
380bbd860fSMichael Walsh
39e1e26448SMichael Walsh# Setting master_pid correctly influences the behavior of plug-ins like
40e1e26448SMichael Walsh# DB_Logging
41e1e26448SMichael Walshprogram_pid = os.getpid()
42e1e26448SMichael Walshmaster_pid = os.environ.get('AUTOBOOT_MASTER_PID', program_pid)
43004ad3c9SJoy Onyerikwupgm_name = re.sub('\\.py$', '', os.path.basename(__file__))
44e1e26448SMichael Walsh
45b5839d00SMichael Walsh# Set up boot data structures.
46b5839d00SMichael Walshboot_table = create_boot_table()
47b5839d00SMichael Walshvalid_boot_types = create_valid_boot_list(boot_table)
480b93fbf8SMichael Walsh
496741f740SMichael Walshboot_lists = read_boot_lists()
506741f740SMichael Walshlast_ten = []
516741f740SMichael Walsh
527dc885b6SMichael Walshstate = st.return_state_constant('default_state')
536741f740SMichael Walshcp_setup_called = 0
546741f740SMichael Walshnext_boot = ""
556741f740SMichael Walshbase_tool_dir_path = os.path.normpath(os.environ.get(
566741f740SMichael Walsh    'AUTOBOOT_BASE_TOOL_DIR_PATH', "/tmp")) + os.sep
57b5839d00SMichael Walsh
586741f740SMichael Walshffdc_dir_path = os.path.normpath(os.environ.get('FFDC_DIR_PATH', '')) + os.sep
596741f740SMichael Walshboot_success = 0
606741f740SMichael Walshstatus_dir_path = os.environ.get('STATUS_DIR_PATH', "")
616741f740SMichael Walshif status_dir_path != "":
626741f740SMichael Walsh    status_dir_path = os.path.normpath(status_dir_path) + os.sep
630b93fbf8SMichael Walshdefault_power_on = "REST Power On"
640b93fbf8SMichael Walshdefault_power_off = "REST Power Off"
656741f740SMichael Walshboot_count = 0
660bbd860fSMichael Walsh
6785678948SMichael WalshLOG_LEVEL = BuiltIn().get_variable_value("${LOG_LEVEL}")
68e1974b96SMichael Walshffdc_prefix = ""
69325eb548SSunil Mboot_start_time = ""
70325eb548SSunil Mboot_end_time = ""
71ff340006SMichael Walshsave_stack = vs.var_stack('save_stack')
72ff340006SMichael Walshmain_func_parm_list = ['boot_stack', 'stack_mode', 'quiet']
7385678948SMichael Walsh
7485678948SMichael Walsh
75*89de14a4SMichael Walshdef dump_ffdc_rc():
76*89de14a4SMichael Walsh    r"""
77*89de14a4SMichael Walsh    Return the constant dump ffdc test return code value.
78*89de14a4SMichael Walsh
79*89de14a4SMichael Walsh    When a plug-in call point program returns this value, it indicates that
80*89de14a4SMichael Walsh    this program should collect FFDC.
81*89de14a4SMichael Walsh    """
82*89de14a4SMichael Walsh
83*89de14a4SMichael Walsh    return 0x00000200
84*89de14a4SMichael Walsh
85*89de14a4SMichael Walsh
86*89de14a4SMichael Walshdef stop_test_rc():
87*89de14a4SMichael Walsh    r"""
88*89de14a4SMichael Walsh    Return the constant stop test return code value.
89*89de14a4SMichael Walsh
90*89de14a4SMichael Walsh    When a plug-in call point program returns this value, it indicates that
91*89de14a4SMichael Walsh    this program should stop running.
92*89de14a4SMichael Walsh    """
93*89de14a4SMichael Walsh
94*89de14a4SMichael Walsh    return 0x00000200
95*89de14a4SMichael Walsh
96*89de14a4SMichael Walsh
970ad0f7f8SMichael Walshdef process_host(host,
980ad0f7f8SMichael Walsh                 host_var_name=""):
990ad0f7f8SMichael Walsh    r"""
1000ad0f7f8SMichael Walsh    Process a host by getting the associated host name and IP address and
1010ad0f7f8SMichael Walsh    setting them in global variables.
1020ad0f7f8SMichael Walsh
1030ad0f7f8SMichael Walsh    If the caller does not pass the host_var_name, this function will try to
1040ad0f7f8SMichael Walsh    figure out the name of the variable used by the caller for the host parm.
1050ad0f7f8SMichael Walsh    Callers are advised to explicitly specify the host_var_name when calling
1060ad0f7f8SMichael Walsh    with an exec command.  In such cases, the get_arg_name cannot figure out
1070ad0f7f8SMichael Walsh    the host variable name.
1080ad0f7f8SMichael Walsh
1090ad0f7f8SMichael Walsh    This function will then create similar global variable names by
1100ad0f7f8SMichael Walsh    removing "_host" and appending "_host_name" or "_ip" to the host variable
1110ad0f7f8SMichael Walsh    name.
1120ad0f7f8SMichael Walsh
1130ad0f7f8SMichael Walsh    Example:
1140ad0f7f8SMichael Walsh
1150ad0f7f8SMichael Walsh    If a call is made like this:
1160ad0f7f8SMichael Walsh    process_host(openbmc_host)
1170ad0f7f8SMichael Walsh
1180ad0f7f8SMichael Walsh    Global variables openbmc_host_name and openbmc_ip will be set.
1190ad0f7f8SMichael Walsh
1200ad0f7f8SMichael Walsh    Description of argument(s):
1210ad0f7f8SMichael Walsh    host           A host name or IP.  The name of the variable used should
1220ad0f7f8SMichael Walsh                   have a suffix of "_host".
1230ad0f7f8SMichael Walsh    host_var_name  The name of the variable being used as the host parm.
1240ad0f7f8SMichael Walsh    """
1250ad0f7f8SMichael Walsh
1260ad0f7f8SMichael Walsh    if host_var_name == "":
1270ad0f7f8SMichael Walsh        host_var_name = gp.get_arg_name(0, 1, stack_frame_ix=2)
1280ad0f7f8SMichael Walsh
1290ad0f7f8SMichael Walsh    host_name_var_name = re.sub("host", "host_name", host_var_name)
1300ad0f7f8SMichael Walsh    ip_var_name = re.sub("host", "ip", host_var_name)
1310ad0f7f8SMichael Walsh    cmd_buf = "global " + host_name_var_name + ", " + ip_var_name + " ; " +\
1320ad0f7f8SMichael Walsh        host_name_var_name + ", " + ip_var_name + " = gm.get_host_name_ip('" +\
1330ad0f7f8SMichael Walsh        host + "')"
1340ad0f7f8SMichael Walsh    exec(cmd_buf)
1350ad0f7f8SMichael Walsh
1360ad0f7f8SMichael Walsh
137b5839d00SMichael Walshdef process_pgm_parms():
138b5839d00SMichael Walsh    r"""
139b5839d00SMichael Walsh    Process the program parameters by assigning them all to corresponding
140b5839d00SMichael Walsh    globals.  Also, set some global values that depend on program parameters.
141b5839d00SMichael Walsh    """
142b5839d00SMichael Walsh
143b5839d00SMichael Walsh    # Program parameter processing.
144b5839d00SMichael Walsh    # Assign all program parms to python variables which are global to this
145b5839d00SMichael Walsh    # module.
146b5839d00SMichael Walsh
147b5839d00SMichael Walsh    global parm_list
148b5839d00SMichael Walsh    parm_list = BuiltIn().get_variable_value("${parm_list}")
149b5839d00SMichael Walsh    # The following subset of parms should be processed as integers.
150b5839d00SMichael Walsh    int_list = ['max_num_tests', 'boot_pass', 'boot_fail', 'ffdc_only',
151*89de14a4SMichael Walsh                'boot_fail_threshold', 'delete_errlogs',
152*89de14a4SMichael Walsh                'call_post_stack_plug', 'quiet', 'test_mode', 'debug']
153b5839d00SMichael Walsh    for parm in parm_list:
154b5839d00SMichael Walsh        if parm in int_list:
155b5839d00SMichael Walsh            sub_cmd = "int(BuiltIn().get_variable_value(\"${" + parm +\
156b5839d00SMichael Walsh                      "}\", \"0\"))"
157b5839d00SMichael Walsh        else:
158b5839d00SMichael Walsh            sub_cmd = "BuiltIn().get_variable_value(\"${" + parm + "}\")"
159b5839d00SMichael Walsh        cmd_buf = "global " + parm + " ; " + parm + " = " + sub_cmd
160ff340006SMichael Walsh        gp.dpissuing(cmd_buf)
161b5839d00SMichael Walsh        exec(cmd_buf)
1620ad0f7f8SMichael Walsh        if re.match(r".*_host$", parm):
1630ad0f7f8SMichael Walsh            cmd_buf = "process_host(" + parm + ", '" + parm + "')"
1640ad0f7f8SMichael Walsh            exec(cmd_buf)
1650ad0f7f8SMichael Walsh        if re.match(r".*_password$", parm):
1660ad0f7f8SMichael Walsh            # Register the value of any parm whose name ends in _password.
1670ad0f7f8SMichael Walsh            # This will cause the print functions to replace passwords with
1680ad0f7f8SMichael Walsh            # asterisks in the output.
1690ad0f7f8SMichael Walsh            cmd_buf = "gp.register_passwords(" + parm + ")"
1700ad0f7f8SMichael Walsh            exec(cmd_buf)
171b5839d00SMichael Walsh
172b5839d00SMichael Walsh    global ffdc_dir_path_style
173b5839d00SMichael Walsh    global boot_list
174b5839d00SMichael Walsh    global boot_stack
175b5839d00SMichael Walsh    global boot_results_file_path
176b5839d00SMichael Walsh    global boot_results
1776c64574bSMichael Walsh    global last_ten
178b5839d00SMichael Walsh    global ffdc_list_file_path
179e0cf8d70SMichael Walsh    global ffdc_report_list_path
180600876daSMichael Walsh    global ffdc_summary_list_path
181b5839d00SMichael Walsh
182b5839d00SMichael Walsh    if ffdc_dir_path_style == "":
183b5839d00SMichael Walsh        ffdc_dir_path_style = int(os.environ.get('FFDC_DIR_PATH_STYLE', '0'))
184b5839d00SMichael Walsh
185b5839d00SMichael Walsh    # Convert these program parms to lists for easier processing..
186b5839d00SMichael Walsh    boot_list = filter(None, boot_list.split(":"))
187b5839d00SMichael Walsh    boot_stack = filter(None, boot_stack.split(":"))
188b5839d00SMichael Walsh
189903e0b20SMichael Walsh    cleanup_boot_results_file()
190903e0b20SMichael Walsh    boot_results_file_path = create_boot_results_file_path(pgm_name,
191903e0b20SMichael Walsh                                                           openbmc_nickname,
192903e0b20SMichael Walsh                                                           master_pid)
193b5839d00SMichael Walsh
194b5839d00SMichael Walsh    if os.path.isfile(boot_results_file_path):
195b5839d00SMichael Walsh        # We've been called before in this run so we'll load the saved
1966c64574bSMichael Walsh        # boot_results and last_ten objects.
1976c64574bSMichael Walsh        boot_results, last_ten =\
1986c64574bSMichael Walsh            pickle.load(open(boot_results_file_path, 'rb'))
199b5839d00SMichael Walsh    else:
200b5839d00SMichael Walsh        boot_results = boot_results(boot_table, boot_pass, boot_fail)
201b5839d00SMichael Walsh
202b5839d00SMichael Walsh    ffdc_list_file_path = base_tool_dir_path + openbmc_nickname +\
203b5839d00SMichael Walsh        "/FFDC_FILE_LIST"
204e0cf8d70SMichael Walsh    ffdc_report_list_path = base_tool_dir_path + openbmc_nickname +\
205e0cf8d70SMichael Walsh        "/FFDC_REPORT_FILE_LIST"
206b5839d00SMichael Walsh
207600876daSMichael Walsh    ffdc_summary_list_path = base_tool_dir_path + openbmc_nickname +\
208600876daSMichael Walsh        "/FFDC_SUMMARY_FILE_LIST"
209600876daSMichael Walsh
210b5839d00SMichael Walsh
21185678948SMichael Walshdef initial_plug_in_setup():
21285678948SMichael Walsh    r"""
21385678948SMichael Walsh    Initialize all plug-in environment variables which do not change for the
21485678948SMichael Walsh    duration of the program.
21585678948SMichael Walsh
21685678948SMichael Walsh    """
21785678948SMichael Walsh
21885678948SMichael Walsh    global LOG_LEVEL
21985678948SMichael Walsh    BuiltIn().set_log_level("NONE")
22085678948SMichael Walsh
22185678948SMichael Walsh    BuiltIn().set_global_variable("${master_pid}", master_pid)
22285678948SMichael Walsh    BuiltIn().set_global_variable("${FFDC_DIR_PATH}", ffdc_dir_path)
22385678948SMichael Walsh    BuiltIn().set_global_variable("${STATUS_DIR_PATH}", status_dir_path)
22485678948SMichael Walsh    BuiltIn().set_global_variable("${BASE_TOOL_DIR_PATH}", base_tool_dir_path)
22585678948SMichael Walsh    BuiltIn().set_global_variable("${FFDC_LIST_FILE_PATH}",
22685678948SMichael Walsh                                  ffdc_list_file_path)
227e0cf8d70SMichael Walsh    BuiltIn().set_global_variable("${FFDC_REPORT_LIST_PATH}",
228e0cf8d70SMichael Walsh                                  ffdc_report_list_path)
229600876daSMichael Walsh    BuiltIn().set_global_variable("${FFDC_SUMMARY_LIST_PATH}",
230600876daSMichael Walsh                                  ffdc_summary_list_path)
23185678948SMichael Walsh
23285678948SMichael Walsh    BuiltIn().set_global_variable("${FFDC_DIR_PATH_STYLE}",
23385678948SMichael Walsh                                  ffdc_dir_path_style)
23485678948SMichael Walsh    BuiltIn().set_global_variable("${FFDC_CHECK}",
23585678948SMichael Walsh                                  ffdc_check)
23685678948SMichael Walsh
23785678948SMichael Walsh    # For each program parameter, set the corresponding AUTOBOOT_ environment
23885678948SMichael Walsh    # variable value.  Also, set an AUTOBOOT_ environment variable for every
23985678948SMichael Walsh    # element in additional_values.
24085678948SMichael Walsh    additional_values = ["program_pid", "master_pid", "ffdc_dir_path",
24185678948SMichael Walsh                         "status_dir_path", "base_tool_dir_path",
242600876daSMichael Walsh                         "ffdc_list_file_path", "ffdc_report_list_path",
243600876daSMichael Walsh                         "ffdc_summary_list_path"]
24485678948SMichael Walsh
24585678948SMichael Walsh    plug_in_vars = parm_list + additional_values
24685678948SMichael Walsh
24785678948SMichael Walsh    for var_name in plug_in_vars:
24885678948SMichael Walsh        var_value = BuiltIn().get_variable_value("${" + var_name + "}")
24985678948SMichael Walsh        var_name = var_name.upper()
25085678948SMichael Walsh        if var_value is None:
25185678948SMichael Walsh            var_value = ""
25285678948SMichael Walsh        os.environ["AUTOBOOT_" + var_name] = str(var_value)
25385678948SMichael Walsh
25485678948SMichael Walsh    BuiltIn().set_log_level(LOG_LEVEL)
25585678948SMichael Walsh
25668a61162SMichael Walsh    # Make sure the ffdc list directory exists.
25768a61162SMichael Walsh    ffdc_list_dir_path = os.path.dirname(ffdc_list_file_path) + os.sep
25868a61162SMichael Walsh    if not os.path.exists(ffdc_list_dir_path):
25968a61162SMichael Walsh        os.makedirs(ffdc_list_dir_path)
26085678948SMichael Walsh
26185678948SMichael Walsh
2620bbd860fSMichael Walshdef plug_in_setup():
2630bbd860fSMichael Walsh    r"""
26485678948SMichael Walsh    Initialize all changing plug-in environment variables for use by the
26585678948SMichael Walsh    plug-in programs.
2660bbd860fSMichael Walsh    """
2670bbd860fSMichael Walsh
26885678948SMichael Walsh    global LOG_LEVEL
26985678948SMichael Walsh    global test_really_running
27085678948SMichael Walsh
27185678948SMichael Walsh    BuiltIn().set_log_level("NONE")
27285678948SMichael Walsh
2736741f740SMichael Walsh    boot_pass, boot_fail = boot_results.return_total_pass_fail()
2740bbd860fSMichael Walsh    if boot_pass > 1:
2750bbd860fSMichael Walsh        test_really_running = 1
2760bbd860fSMichael Walsh    else:
2770bbd860fSMichael Walsh        test_really_running = 0
2780bbd860fSMichael Walsh
2796741f740SMichael Walsh    BuiltIn().set_global_variable("${test_really_running}",
2806741f740SMichael Walsh                                  test_really_running)
2816741f740SMichael Walsh    BuiltIn().set_global_variable("${boot_type_desc}", next_boot)
2826741f740SMichael Walsh    BuiltIn().set_global_variable("${boot_pass}", boot_pass)
2836741f740SMichael Walsh    BuiltIn().set_global_variable("${boot_fail}", boot_fail)
2846741f740SMichael Walsh    BuiltIn().set_global_variable("${boot_success}", boot_success)
2856741f740SMichael Walsh    BuiltIn().set_global_variable("${ffdc_prefix}", ffdc_prefix)
286325eb548SSunil M    BuiltIn().set_global_variable("${boot_start_time}", boot_start_time)
287325eb548SSunil M    BuiltIn().set_global_variable("${boot_end_time}", boot_end_time)
2884c9a6453SMichael Walsh
2890bbd860fSMichael Walsh    # For each program parameter, set the corresponding AUTOBOOT_ environment
2900bbd860fSMichael Walsh    # variable value.  Also, set an AUTOBOOT_ environment variable for every
2910bbd860fSMichael Walsh    # element in additional_values.
2920bbd860fSMichael Walsh    additional_values = ["boot_type_desc", "boot_success", "boot_pass",
293325eb548SSunil M                         "boot_fail", "test_really_running", "ffdc_prefix",
294325eb548SSunil M                         "boot_start_time", "boot_end_time"]
2950bbd860fSMichael Walsh
29685678948SMichael Walsh    plug_in_vars = additional_values
2970bbd860fSMichael Walsh
2980bbd860fSMichael Walsh    for var_name in plug_in_vars:
2990bbd860fSMichael Walsh        var_value = BuiltIn().get_variable_value("${" + var_name + "}")
3000bbd860fSMichael Walsh        var_name = var_name.upper()
3010bbd860fSMichael Walsh        if var_value is None:
3020bbd860fSMichael Walsh            var_value = ""
3036741f740SMichael Walsh        os.environ["AUTOBOOT_" + var_name] = str(var_value)
3040bbd860fSMichael Walsh
3050bbd860fSMichael Walsh    if debug:
3066741f740SMichael Walsh        shell_rc, out_buf = \
3076741f740SMichael Walsh            gc.cmd_fnc_u("printenv | egrep AUTOBOOT_ | sort -u")
3080bbd860fSMichael Walsh
30985678948SMichael Walsh    BuiltIn().set_log_level(LOG_LEVEL)
31085678948SMichael Walsh
3110bbd860fSMichael Walsh
312e0cf8d70SMichael Walshdef pre_boot_plug_in_setup():
313e0cf8d70SMichael Walsh
314e0cf8d70SMichael Walsh    # Clear the ffdc_list_file_path file.  Plug-ins may now write to it.
315e0cf8d70SMichael Walsh    try:
316e0cf8d70SMichael Walsh        os.remove(ffdc_list_file_path)
317e0cf8d70SMichael Walsh    except OSError:
318e0cf8d70SMichael Walsh        pass
319e0cf8d70SMichael Walsh
320e0cf8d70SMichael Walsh    # Clear the ffdc_report_list_path file.  Plug-ins may now write to it.
321e0cf8d70SMichael Walsh    try:
322e0cf8d70SMichael Walsh        os.remove(ffdc_report_list_path)
323e0cf8d70SMichael Walsh    except OSError:
324e0cf8d70SMichael Walsh        pass
325e0cf8d70SMichael Walsh
326600876daSMichael Walsh    # Clear the ffdc_summary_list_path file.  Plug-ins may now write to it.
327600876daSMichael Walsh    try:
328600876daSMichael Walsh        os.remove(ffdc_summary_list_path)
329600876daSMichael Walsh    except OSError:
330600876daSMichael Walsh        pass
331600876daSMichael Walsh
332e1974b96SMichael Walsh    global ffdc_prefix
333e1974b96SMichael Walsh
334e1974b96SMichael Walsh    seconds = time.time()
335e1974b96SMichael Walsh    loc_time = time.localtime(seconds)
336e1974b96SMichael Walsh    time_string = time.strftime("%y%m%d.%H%M%S.", loc_time)
337e1974b96SMichael Walsh
338e1974b96SMichael Walsh    ffdc_prefix = openbmc_nickname + "." + time_string
339e1974b96SMichael Walsh
340e0cf8d70SMichael Walsh
3416741f740SMichael Walshdef setup():
3420bbd860fSMichael Walsh    r"""
3436741f740SMichael Walsh    Do general program setup tasks.
3440bbd860fSMichael Walsh    """
3450bbd860fSMichael Walsh
3466741f740SMichael Walsh    global cp_setup_called
34781816748SMichael Walsh    global transitional_boot_selected
3480bbd860fSMichael Walsh
349b5839d00SMichael Walsh    gp.qprintn()
350b5839d00SMichael Walsh
35181816748SMichael Walsh    transitional_boot_selected = False
35281816748SMichael Walsh
35383f4bc77SMichael Walsh    robot_pgm_dir_path = os.path.dirname(__file__) + os.sep
35483f4bc77SMichael Walsh    repo_bin_path = robot_pgm_dir_path.replace("/lib/", "/bin/")
355d061c043SMichael Walsh    # If we can't find process_plug_in_packages.py, ssh_pw or
356d061c043SMichael Walsh    # validate_plug_ins.py, then we don't have our repo bin in PATH.
357004ad3c9SJoy Onyerikwu    shell_rc, out_buf = gc.cmd_fnc_u("which process_plug_in_packages.py"
358004ad3c9SJoy Onyerikwu                                     + " ssh_pw validate_plug_ins.py", quiet=1,
359d061c043SMichael Walsh                                     print_output=0, show_err=0)
360b5839d00SMichael Walsh    if shell_rc != 0:
36183f4bc77SMichael Walsh        os.environ['PATH'] = repo_bin_path + ":" + os.environ.get('PATH', "")
36283f4bc77SMichael Walsh    # Likewise, our repo lib subdir needs to be in sys.path and PYTHONPATH.
36383f4bc77SMichael Walsh    if robot_pgm_dir_path not in sys.path:
36483f4bc77SMichael Walsh        sys.path.append(robot_pgm_dir_path)
36583f4bc77SMichael Walsh        PYTHONPATH = os.environ.get("PYTHONPATH", "")
36683f4bc77SMichael Walsh        if PYTHONPATH == "":
36783f4bc77SMichael Walsh            os.environ['PYTHONPATH'] = robot_pgm_dir_path
36883f4bc77SMichael Walsh        else:
36983f4bc77SMichael Walsh            os.environ['PYTHONPATH'] = robot_pgm_dir_path + ":" + PYTHONPATH
3706741f740SMichael Walsh
3716741f740SMichael Walsh    validate_parms()
3726741f740SMichael Walsh
3736741f740SMichael Walsh    grp.rqprint_pgm_header()
3746741f740SMichael Walsh
375efc3ff2bSGeorge Keishing    grk.run_key("Set BMC Power Policy  ALWAYS_POWER_OFF")
37611cfc8c0SMichael Walsh
37785678948SMichael Walsh    initial_plug_in_setup()
37885678948SMichael Walsh
3796741f740SMichael Walsh    plug_in_setup()
3806741f740SMichael Walsh    rc, shell_rc, failed_plug_in_name = grpi.rprocess_plug_in_packages(
3816741f740SMichael Walsh        call_point='setup')
3826741f740SMichael Walsh    if rc != 0:
3836741f740SMichael Walsh        error_message = "Plug-in setup failed.\n"
3846741f740SMichael Walsh        grp.rprint_error_report(error_message)
3856741f740SMichael Walsh        BuiltIn().fail(error_message)
3866741f740SMichael Walsh    # Setting cp_setup_called lets our Teardown know that it needs to call
3876741f740SMichael Walsh    # the cleanup plug-in call point.
3886741f740SMichael Walsh    cp_setup_called = 1
3896741f740SMichael Walsh
3906741f740SMichael Walsh    # Keyword "FFDC" will fail if TEST_MESSAGE is not set.
3916741f740SMichael Walsh    BuiltIn().set_global_variable("${TEST_MESSAGE}", "${EMPTY}")
39285678948SMichael Walsh    # FFDC_LOG_PATH is used by "FFDC" keyword.
39385678948SMichael Walsh    BuiltIn().set_global_variable("${FFDC_LOG_PATH}", ffdc_dir_path)
3946741f740SMichael Walsh
395dc80d67dSMichael Walsh    # Also printed by FFDC.
396dc80d67dSMichael Walsh    global host_name
397dc80d67dSMichael Walsh    global host_ip
398dc80d67dSMichael Walsh    host = socket.gethostname()
399dc80d67dSMichael Walsh    host_name, host_ip = gm.get_host_name_ip(host)
400dc80d67dSMichael Walsh
401b5839d00SMichael Walsh    gp.dprint_var(boot_table, 1)
402b5839d00SMichael Walsh    gp.dprint_var(boot_lists)
4030bbd860fSMichael Walsh
4040bbd860fSMichael Walsh
4056741f740SMichael Walshdef validate_parms():
4060bbd860fSMichael Walsh    r"""
4076741f740SMichael Walsh    Validate all program parameters.
4080bbd860fSMichael Walsh    """
4090bbd860fSMichael Walsh
410b5839d00SMichael Walsh    process_pgm_parms()
4110bbd860fSMichael Walsh
412b5839d00SMichael Walsh    gp.qprintn()
413b5839d00SMichael Walsh
414b5839d00SMichael Walsh    global openbmc_model
4156741f740SMichael Walsh    grv.rvalid_value("openbmc_host")
4166741f740SMichael Walsh    grv.rvalid_value("openbmc_username")
4176741f740SMichael Walsh    grv.rvalid_value("openbmc_password")
4186741f740SMichael Walsh    if os_host != "":
4196741f740SMichael Walsh        grv.rvalid_value("os_username")
4206741f740SMichael Walsh        grv.rvalid_value("os_password")
4210bbd860fSMichael Walsh
4226741f740SMichael Walsh    if pdu_host != "":
4236741f740SMichael Walsh        grv.rvalid_value("pdu_username")
4246741f740SMichael Walsh        grv.rvalid_value("pdu_password")
4256741f740SMichael Walsh        grv.rvalid_integer("pdu_slot_no")
4266741f740SMichael Walsh    if openbmc_serial_host != "":
4276741f740SMichael Walsh        grv.rvalid_integer("openbmc_serial_port")
428b5839d00SMichael Walsh    if openbmc_model == "":
429b5839d00SMichael Walsh        status, ret_values =\
430b5839d00SMichael Walsh            grk.run_key_u("Get BMC System Model")
431b5839d00SMichael Walsh        openbmc_model = ret_values
432b5839d00SMichael Walsh        BuiltIn().set_global_variable("${openbmc_model}", openbmc_model)
4336741f740SMichael Walsh    grv.rvalid_value("openbmc_model")
434b5839d00SMichael Walsh    grv.rvalid_integer("max_num_tests")
4356741f740SMichael Walsh    grv.rvalid_integer("boot_pass")
4366741f740SMichael Walsh    grv.rvalid_integer("boot_fail")
4376741f740SMichael Walsh
4386741f740SMichael Walsh    plug_in_packages_list = grpi.rvalidate_plug_ins(plug_in_dir_paths)
4396741f740SMichael Walsh    BuiltIn().set_global_variable("${plug_in_packages_list}",
4406741f740SMichael Walsh                                  plug_in_packages_list)
4416741f740SMichael Walsh
442b5839d00SMichael Walsh    grv.rvalid_value("stack_mode", valid_values=['normal', 'skip'])
443a20da401SMichael Walsh    if len(boot_list) == 0 and len(boot_stack) == 0 and not ffdc_only:
4446741f740SMichael Walsh        error_message = "You must provide either a value for either the" +\
4456741f740SMichael Walsh            " boot_list or the boot_stack parm.\n"
4466741f740SMichael Walsh        BuiltIn().fail(gp.sprint_error(error_message))
4476741f740SMichael Walsh
4486741f740SMichael Walsh    valid_boot_list(boot_list, valid_boot_types)
4496741f740SMichael Walsh    valid_boot_list(boot_stack, valid_boot_types)
4506741f740SMichael Walsh
451004ad3c9SJoy Onyerikwu    selected_PDU_boots = list(set(boot_list + boot_stack)
452004ad3c9SJoy Onyerikwu                              & set(boot_lists['PDU_reboot']))
45311cfc8c0SMichael Walsh
45411cfc8c0SMichael Walsh    if len(selected_PDU_boots) > 0 and pdu_host == "":
45511cfc8c0SMichael Walsh        error_message = "You have selected the following boots which" +\
45611cfc8c0SMichael Walsh                        " require a PDU host but no value for pdu_host:\n"
45711cfc8c0SMichael Walsh        error_message += gp.sprint_var(selected_PDU_boots)
45811cfc8c0SMichael Walsh        error_message += gp.sprint_var(pdu_host, 2)
45911cfc8c0SMichael Walsh        BuiltIn().fail(gp.sprint_error(error_message))
46011cfc8c0SMichael Walsh
4616741f740SMichael Walsh    return
4620bbd860fSMichael Walsh
4630bbd860fSMichael Walsh
4646741f740SMichael Walshdef my_get_state():
4650bbd860fSMichael Walsh    r"""
4666741f740SMichael Walsh    Get the system state plus a little bit of wrapping.
4670bbd860fSMichael Walsh    """
4680bbd860fSMichael Walsh
4696741f740SMichael Walsh    global state
4706741f740SMichael Walsh
4716741f740SMichael Walsh    req_states = ['epoch_seconds'] + st.default_req_states
4726741f740SMichael Walsh
473b5839d00SMichael Walsh    gp.qprint_timen("Getting system state.")
4746741f740SMichael Walsh    if test_mode:
4756741f740SMichael Walsh        state['epoch_seconds'] = int(time.time())
4766741f740SMichael Walsh    else:
477b5839d00SMichael Walsh        state = st.get_state(req_states=req_states, quiet=quiet)
478b5839d00SMichael Walsh    gp.qprint_var(state)
479341c21ebSMichael Walsh
480341c21ebSMichael Walsh
48145ca6e4cSMichael Walshdef valid_state():
48245ca6e4cSMichael Walsh    r"""
48345ca6e4cSMichael Walsh    Verify that our state dictionary contains no blank values.  If we don't get
48445ca6e4cSMichael Walsh    valid state data, we cannot continue to work.
48545ca6e4cSMichael Walsh    """
48645ca6e4cSMichael Walsh
48745ca6e4cSMichael Walsh    if st.compare_states(state, st.invalid_state_match, 'or'):
48845ca6e4cSMichael Walsh        error_message = "The state dictionary contains blank fields which" +\
48945ca6e4cSMichael Walsh            " is illegal.\n" + gp.sprint_var(state)
49045ca6e4cSMichael Walsh        BuiltIn().fail(gp.sprint_error(error_message))
49145ca6e4cSMichael Walsh
49245ca6e4cSMichael Walsh
4936741f740SMichael Walshdef select_boot():
494341c21ebSMichael Walsh    r"""
495341c21ebSMichael Walsh    Select a boot test to be run based on our current state and return the
496341c21ebSMichael Walsh    chosen boot type.
497341c21ebSMichael Walsh
498341c21ebSMichael Walsh    Description of arguments:
4996741f740SMichael Walsh    state  The state of the machine.
500341c21ebSMichael Walsh    """
501341c21ebSMichael Walsh
50281816748SMichael Walsh    global transitional_boot_selected
50330dadae2SMichael Walsh    global boot_stack
50430dadae2SMichael Walsh
505b5839d00SMichael Walsh    gp.qprint_timen("Selecting a boot test.")
5066741f740SMichael Walsh
50781816748SMichael Walsh    if transitional_boot_selected and not boot_success:
50881816748SMichael Walsh        prior_boot = next_boot
50981816748SMichael Walsh        boot_candidate = boot_stack.pop()
510004ad3c9SJoy Onyerikwu        gp.qprint_timen("The prior '" + next_boot + "' was chosen to"
511004ad3c9SJoy Onyerikwu                        + " transition to a valid state for '" + boot_candidate
512004ad3c9SJoy Onyerikwu                        + "' which was at the top of the boot_stack.  Since"
513004ad3c9SJoy Onyerikwu                        + " the '" + next_boot + "' failed, the '"
514004ad3c9SJoy Onyerikwu                        + boot_candidate + "' has been removed from the stack"
515004ad3c9SJoy Onyerikwu                        + " to avoid and endless failure loop.")
51681816748SMichael Walsh        if len(boot_stack) == 0:
51781816748SMichael Walsh            return ""
51881816748SMichael Walsh
5196741f740SMichael Walsh    my_get_state()
52045ca6e4cSMichael Walsh    valid_state()
5216741f740SMichael Walsh
52281816748SMichael Walsh    transitional_boot_selected = False
5236741f740SMichael Walsh    stack_popped = 0
5246741f740SMichael Walsh    if len(boot_stack) > 0:
5256741f740SMichael Walsh        stack_popped = 1
526b5839d00SMichael Walsh        gp.qprint_dashes()
527b5839d00SMichael Walsh        gp.qprint_var(boot_stack)
528b5839d00SMichael Walsh        gp.qprint_dashes()
529b5839d00SMichael Walsh        skip_boot_printed = 0
530b5839d00SMichael Walsh        while len(boot_stack) > 0:
5316741f740SMichael Walsh            boot_candidate = boot_stack.pop()
532b5839d00SMichael Walsh            if stack_mode == 'normal':
533b5839d00SMichael Walsh                break
534b5839d00SMichael Walsh            else:
535b5839d00SMichael Walsh                if st.compare_states(state, boot_table[boot_candidate]['end']):
536b5839d00SMichael Walsh                    if not skip_boot_printed:
537ff340006SMichael Walsh                        gp.qprint_var(stack_mode)
538ff340006SMichael Walsh                        gp.qprintn()
539004ad3c9SJoy Onyerikwu                        gp.qprint_timen("Skipping the following boot tests"
540004ad3c9SJoy Onyerikwu                                        + " which are unnecessary since their"
541004ad3c9SJoy Onyerikwu                                        + " required end states match the"
542004ad3c9SJoy Onyerikwu                                        + " current machine state:")
543b5839d00SMichael Walsh                        skip_boot_printed = 1
544ff340006SMichael Walsh                    gp.qprint_var(boot_candidate)
545b5839d00SMichael Walsh                    boot_candidate = ""
546b5839d00SMichael Walsh        if boot_candidate == "":
547b5839d00SMichael Walsh            gp.qprint_dashes()
548b5839d00SMichael Walsh            gp.qprint_var(boot_stack)
549b5839d00SMichael Walsh            gp.qprint_dashes()
550b5839d00SMichael Walsh            return boot_candidate
5516741f740SMichael Walsh        if st.compare_states(state, boot_table[boot_candidate]['start']):
552004ad3c9SJoy Onyerikwu            gp.qprint_timen("The machine state is valid for a '"
553004ad3c9SJoy Onyerikwu                            + boot_candidate + "' boot test.")
554b5839d00SMichael Walsh            gp.qprint_dashes()
555b5839d00SMichael Walsh            gp.qprint_var(boot_stack)
556b5839d00SMichael Walsh            gp.qprint_dashes()
5576741f740SMichael Walsh            return boot_candidate
558341c21ebSMichael Walsh        else:
559004ad3c9SJoy Onyerikwu            gp.qprint_timen("The machine state does not match the required"
560004ad3c9SJoy Onyerikwu                            + " starting state for a '" + boot_candidate
561004ad3c9SJoy Onyerikwu                            + "' boot test:")
562ff340006SMichael Walsh            gp.qprint_varx("boot_table[" + boot_candidate + "][start]",
563b5839d00SMichael Walsh                           boot_table[boot_candidate]['start'], 1)
5646741f740SMichael Walsh            boot_stack.append(boot_candidate)
56581816748SMichael Walsh            transitional_boot_selected = True
5666741f740SMichael Walsh            popped_boot = boot_candidate
5676741f740SMichael Walsh
5686741f740SMichael Walsh    # Loop through your list selecting a boot_candidates
5696741f740SMichael Walsh    boot_candidates = []
5706741f740SMichael Walsh    for boot_candidate in boot_list:
5716741f740SMichael Walsh        if st.compare_states(state, boot_table[boot_candidate]['start']):
5726741f740SMichael Walsh            if stack_popped:
5736741f740SMichael Walsh                if st.compare_states(boot_table[boot_candidate]['end'],
5746741f740SMichael Walsh                                     boot_table[popped_boot]['start']):
5756741f740SMichael Walsh                    boot_candidates.append(boot_candidate)
576341c21ebSMichael Walsh            else:
5776741f740SMichael Walsh                boot_candidates.append(boot_candidate)
5786741f740SMichael Walsh
5796741f740SMichael Walsh    if len(boot_candidates) == 0:
580004ad3c9SJoy Onyerikwu        gp.qprint_timen("The user's boot list contained no boot tests"
581004ad3c9SJoy Onyerikwu                        + " which are valid for the current machine state.")
5826741f740SMichael Walsh        boot_candidate = default_power_on
5836741f740SMichael Walsh        if not st.compare_states(state, boot_table[default_power_on]['start']):
5846741f740SMichael Walsh            boot_candidate = default_power_off
5856741f740SMichael Walsh        boot_candidates.append(boot_candidate)
586004ad3c9SJoy Onyerikwu        gp.qprint_timen("Using default '" + boot_candidate
587004ad3c9SJoy Onyerikwu                        + "' boot type to transition to valid state.")
5886741f740SMichael Walsh
589b5839d00SMichael Walsh    gp.dprint_var(boot_candidates)
5906741f740SMichael Walsh
5916741f740SMichael Walsh    # Randomly select a boot from the candidate list.
5926741f740SMichael Walsh    boot = random.choice(boot_candidates)
593341c21ebSMichael Walsh
594341c21ebSMichael Walsh    return boot
5950bbd860fSMichael Walsh
59655302295SMichael Walsh
597341c21ebSMichael Walshdef print_last_boots():
598341c21ebSMichael Walsh    r"""
599341c21ebSMichael Walsh    Print the last ten boots done with their time stamps.
600341c21ebSMichael Walsh    """
601341c21ebSMichael Walsh
602341c21ebSMichael Walsh    # indent 0, 90 chars wide, linefeed, char is "="
603b5839d00SMichael Walsh    gp.qprint_dashes(0, 90)
604b5839d00SMichael Walsh    gp.qprintn("Last 10 boots:\n")
605341c21ebSMichael Walsh
606341c21ebSMichael Walsh    for boot_entry in last_ten:
607341c21ebSMichael Walsh        grp.rqprint(boot_entry)
608b5839d00SMichael Walsh    gp.qprint_dashes(0, 90)
609341c21ebSMichael Walsh
610341c21ebSMichael Walsh
611b2e53ecdSMichael Walshdef print_defect_report(ffdc_file_list):
612341c21ebSMichael Walsh    r"""
613341c21ebSMichael Walsh    Print a defect report.
614b2e53ecdSMichael Walsh
615b2e53ecdSMichael Walsh    Description of argument(s):
616b2e53ecdSMichael Walsh    ffdc_file_list  A list of files which were collected by our ffdc functions.
617341c21ebSMichael Walsh    """
618341c21ebSMichael Walsh
619600876daSMichael Walsh    # Making deliberate choice to NOT run plug_in_setup().  We don't want
620600876daSMichael Walsh    # ffdc_prefix updated.
621600876daSMichael Walsh    rc, shell_rc, failed_plug_in_name = grpi.rprocess_plug_in_packages(
622600876daSMichael Walsh        call_point='ffdc_report', stop_on_plug_in_failure=0)
623600876daSMichael Walsh
624e0cf8d70SMichael Walsh    # Get additional header data which may have been created by ffdc plug-ins.
625e0cf8d70SMichael Walsh    # Also, delete the individual header files to cleanup.
626e0cf8d70SMichael Walsh    cmd_buf = "file_list=$(cat " + ffdc_report_list_path + " 2>/dev/null)" +\
627e0cf8d70SMichael Walsh              " ; [ ! -z \"${file_list}\" ] && cat ${file_list}" +\
628e0cf8d70SMichael Walsh              " 2>/dev/null ; rm -rf ${file_list} 2>/dev/null || :"
629e0cf8d70SMichael Walsh    shell_rc, more_header_info = gc.cmd_fnc_u(cmd_buf, print_output=0,
630e0cf8d70SMichael Walsh                                              show_err=0)
631e0cf8d70SMichael Walsh
632b2e53ecdSMichael Walsh    # Get additional summary data which may have been created by ffdc plug-ins.
633600876daSMichael Walsh    # Also, delete the individual header files to cleanup.
634600876daSMichael Walsh    cmd_buf = "file_list=$(cat " + ffdc_summary_list_path + " 2>/dev/null)" +\
635600876daSMichael Walsh              " ; [ ! -z \"${file_list}\" ] && cat ${file_list}" +\
636600876daSMichael Walsh              " 2>/dev/null ; rm -rf ${file_list} 2>/dev/null || :"
637600876daSMichael Walsh    shell_rc, ffdc_summary_info = gc.cmd_fnc_u(cmd_buf, print_output=0,
638600876daSMichael Walsh                                               show_err=0)
639600876daSMichael Walsh
640b2e53ecdSMichael Walsh    # ffdc_list_file_path contains a list of any ffdc files created by plug-
641b2e53ecdSMichael Walsh    # ins, etc.  Read that data into a list.
642341c21ebSMichael Walsh    try:
643b2e53ecdSMichael Walsh        plug_in_ffdc_list = \
644b2e53ecdSMichael Walsh            open(ffdc_list_file_path, 'r').read().rstrip("\n").split("\n")
645b2e53ecdSMichael Walsh        plug_in_ffdc_list = filter(None, plug_in_ffdc_list)
646341c21ebSMichael Walsh    except IOError:
647b2e53ecdSMichael Walsh        plug_in_ffdc_list = []
648b2e53ecdSMichael Walsh
649b2e53ecdSMichael Walsh    # Combine the files from plug_in_ffdc_list with the ffdc_file_list passed
650b2e53ecdSMichael Walsh    # in.  Eliminate duplicates and sort the list.
651004ad3c9SJoy Onyerikwu    ffdc_file_list = sorted(set(ffdc_file_list + plug_in_ffdc_list))
652b2e53ecdSMichael Walsh
653b2e53ecdSMichael Walsh    if status_file_path != "":
654b2e53ecdSMichael Walsh        ffdc_file_list.insert(0, status_file_path)
655b2e53ecdSMichael Walsh
656b2e53ecdSMichael Walsh    # Convert the list to a printable list.
657b2e53ecdSMichael Walsh    printable_ffdc_file_list = "\n".join(ffdc_file_list)
658341c21ebSMichael Walsh
65968a61162SMichael Walsh    # Open ffdc_file_list for writing.  We will write a complete list of
66068a61162SMichael Walsh    # FFDC files to it for possible use by plug-ins like cp_stop_check.
66168a61162SMichael Walsh    ffdc_list_file = open(ffdc_list_file_path, 'w')
662b2e53ecdSMichael Walsh    ffdc_list_file.write(printable_ffdc_file_list + "\n")
663b2e53ecdSMichael Walsh    ffdc_list_file.close()
664b2e53ecdSMichael Walsh
665b2e53ecdSMichael Walsh    indent = 0
666b2e53ecdSMichael Walsh    width = 90
667b2e53ecdSMichael Walsh    linefeed = 1
668b2e53ecdSMichael Walsh    char = "="
66968a61162SMichael Walsh
67068a61162SMichael Walsh    gp.qprintn()
671b2e53ecdSMichael Walsh    gp.qprint_dashes(indent, width, linefeed, char)
67268a61162SMichael Walsh    gp.qprintn("Copy this data to the defect:\n")
67368a61162SMichael Walsh
674e0cf8d70SMichael Walsh    if len(more_header_info) > 0:
675ff340006SMichael Walsh        gp.qprintn(more_header_info)
676dc80d67dSMichael Walsh    gp.qpvars(host_name, host_ip, openbmc_nickname, openbmc_host,
677dc80d67dSMichael Walsh              openbmc_host_name, openbmc_ip, openbmc_username,
678dc80d67dSMichael Walsh              openbmc_password, os_host, os_host_name, os_ip, os_username,
679dc80d67dSMichael Walsh              os_password, pdu_host, pdu_host_name, pdu_ip, pdu_username,
680dc80d67dSMichael Walsh              pdu_password, pdu_slot_no, openbmc_serial_host,
681dc80d67dSMichael Walsh              openbmc_serial_host_name, openbmc_serial_ip, openbmc_serial_port)
68268a61162SMichael Walsh
68368a61162SMichael Walsh    gp.qprintn()
68468a61162SMichael Walsh    print_last_boots()
68568a61162SMichael Walsh    gp.qprintn()
68668a61162SMichael Walsh    gp.qprint_var(state)
687b5839d00SMichael Walsh    gp.qprintn()
688b5839d00SMichael Walsh    gp.qprintn("FFDC data files:")
689b2e53ecdSMichael Walsh    gp.qprintn(printable_ffdc_file_list)
690b5839d00SMichael Walsh    gp.qprintn()
691341c21ebSMichael Walsh
692600876daSMichael Walsh    if len(ffdc_summary_info) > 0:
693ff340006SMichael Walsh        gp.qprintn(ffdc_summary_info)
694600876daSMichael Walsh
695b2e53ecdSMichael Walsh    gp.qprint_dashes(indent, width, linefeed, char)
69668a61162SMichael Walsh
6976741f740SMichael Walsh
6986741f740SMichael Walshdef my_ffdc():
6996741f740SMichael Walsh    r"""
7006741f740SMichael Walsh    Collect FFDC data.
7016741f740SMichael Walsh    """
7026741f740SMichael Walsh
7036741f740SMichael Walsh    global state
7046741f740SMichael Walsh
7056741f740SMichael Walsh    plug_in_setup()
7066741f740SMichael Walsh    rc, shell_rc, failed_plug_in_name = grpi.rprocess_plug_in_packages(
707600876daSMichael Walsh        call_point='ffdc', stop_on_plug_in_failure=0)
7086741f740SMichael Walsh
7096741f740SMichael Walsh    AUTOBOOT_FFDC_PREFIX = os.environ['AUTOBOOT_FFDC_PREFIX']
710004ad3c9SJoy Onyerikwu    status, ffdc_file_list = grk.run_key_u("FFDC  ffdc_prefix="
711004ad3c9SJoy Onyerikwu                                           + AUTOBOOT_FFDC_PREFIX
712004ad3c9SJoy Onyerikwu                                           + "  ffdc_function_list="
713004ad3c9SJoy Onyerikwu                                           + ffdc_function_list, ignore=1)
71483f4bc77SMichael Walsh    if status != 'PASS':
715ff340006SMichael Walsh        gp.qprint_error("Call to ffdc failed.\n")
7166741f740SMichael Walsh
7176741f740SMichael Walsh    my_get_state()
7186741f740SMichael Walsh
719b2e53ecdSMichael Walsh    print_defect_report(ffdc_file_list)
7206741f740SMichael Walsh
7216741f740SMichael Walsh
7226741f740SMichael Walshdef print_test_start_message(boot_keyword):
7236741f740SMichael Walsh    r"""
7246741f740SMichael Walsh    Print a message indicating what boot test is about to run.
7256741f740SMichael Walsh
7266741f740SMichael Walsh    Description of arguments:
7276741f740SMichael Walsh    boot_keyword  The name of the boot which is to be run
7286741f740SMichael Walsh                  (e.g. "BMC Power On").
7296741f740SMichael Walsh    """
7306741f740SMichael Walsh
7316741f740SMichael Walsh    global last_ten
732325eb548SSunil M    global boot_start_time
7336741f740SMichael Walsh
7346741f740SMichael Walsh    doing_msg = gp.sprint_timen("Doing \"" + boot_keyword + "\".")
735325eb548SSunil M
736325eb548SSunil M    # Set boot_start_time for use by plug-ins.
737325eb548SSunil M    boot_start_time = doing_msg[1:33]
738325eb548SSunil M    gp.qprint_var(boot_start_time)
739325eb548SSunil M
740b5839d00SMichael Walsh    gp.qprint(doing_msg)
7416741f740SMichael Walsh
7426741f740SMichael Walsh    last_ten.append(doing_msg)
7436741f740SMichael Walsh
7446741f740SMichael Walsh    if len(last_ten) > 10:
7456741f740SMichael Walsh        del last_ten[0]
7466741f740SMichael Walsh
7476741f740SMichael Walsh
7486741f740SMichael Walshdef run_boot(boot):
7496741f740SMichael Walsh    r"""
7506741f740SMichael Walsh    Run the specified boot.
7516741f740SMichael Walsh
7526741f740SMichael Walsh    Description of arguments:
7536741f740SMichael Walsh    boot  The name of the boot test to be performed.
7546741f740SMichael Walsh    """
7556741f740SMichael Walsh
7566741f740SMichael Walsh    global state
7576741f740SMichael Walsh
7586741f740SMichael Walsh    print_test_start_message(boot)
7596741f740SMichael Walsh
7606741f740SMichael Walsh    plug_in_setup()
7616741f740SMichael Walsh    rc, shell_rc, failed_plug_in_name = \
7626741f740SMichael Walsh        grpi.rprocess_plug_in_packages(call_point="pre_boot")
7636741f740SMichael Walsh    if rc != 0:
7646741f740SMichael Walsh        error_message = "Plug-in failed with non-zero return code.\n" +\
7656741f740SMichael Walsh            gp.sprint_var(rc, 1)
7666741f740SMichael Walsh        BuiltIn().fail(gp.sprint_error(error_message))
7676741f740SMichael Walsh
7686741f740SMichael Walsh    if test_mode:
7696741f740SMichael Walsh        # In test mode, we'll pretend the boot worked by assigning its
7706741f740SMichael Walsh        # required end state to the default state value.
77130dadae2SMichael Walsh        state = st.strip_anchor_state(boot_table[boot]['end'])
7726741f740SMichael Walsh    else:
7736741f740SMichael Walsh        # Assertion:  We trust that the state data was made fresh by the
7746741f740SMichael Walsh        # caller.
7756741f740SMichael Walsh
776b5839d00SMichael Walsh        gp.qprintn()
7776741f740SMichael Walsh
7786741f740SMichael Walsh        if boot_table[boot]['method_type'] == "keyword":
7790b93fbf8SMichael Walsh            rk.my_run_keywords(boot_table[boot].get('lib_file_path', ''),
780b5839d00SMichael Walsh                               boot_table[boot]['method'],
781b5839d00SMichael Walsh                               quiet=quiet)
7826741f740SMichael Walsh
7836741f740SMichael Walsh        if boot_table[boot]['bmc_reboot']:
7846741f740SMichael Walsh            st.wait_for_comm_cycle(int(state['epoch_seconds']))
78530dadae2SMichael Walsh            plug_in_setup()
78630dadae2SMichael Walsh            rc, shell_rc, failed_plug_in_name = \
78730dadae2SMichael Walsh                grpi.rprocess_plug_in_packages(call_point="post_reboot")
78830dadae2SMichael Walsh            if rc != 0:
7890b93fbf8SMichael Walsh                error_message = "Plug-in failed with non-zero return code.\n"
7900b93fbf8SMichael Walsh                error_message += gp.sprint_var(rc, 1)
79130dadae2SMichael Walsh                BuiltIn().fail(gp.sprint_error(error_message))
7926741f740SMichael Walsh        else:
7936741f740SMichael Walsh            match_state = st.anchor_state(state)
7946741f740SMichael Walsh            del match_state['epoch_seconds']
7956741f740SMichael Walsh            # Wait for the state to change in any way.
7966741f740SMichael Walsh            st.wait_state(match_state, wait_time=state_change_timeout,
797600876daSMichael Walsh                          interval="10 seconds", invert=1)
7986741f740SMichael Walsh
799b5839d00SMichael Walsh        gp.qprintn()
8006741f740SMichael Walsh        if boot_table[boot]['end']['chassis'] == "Off":
8016741f740SMichael Walsh            boot_timeout = power_off_timeout
8026741f740SMichael Walsh        else:
8036741f740SMichael Walsh            boot_timeout = power_on_timeout
8046741f740SMichael Walsh        st.wait_state(boot_table[boot]['end'], wait_time=boot_timeout,
805600876daSMichael Walsh                      interval="10 seconds")
8066741f740SMichael Walsh
8076741f740SMichael Walsh    plug_in_setup()
8086741f740SMichael Walsh    rc, shell_rc, failed_plug_in_name = \
8096741f740SMichael Walsh        grpi.rprocess_plug_in_packages(call_point="post_boot")
8106741f740SMichael Walsh    if rc != 0:
8116741f740SMichael Walsh        error_message = "Plug-in failed with non-zero return code.\n" +\
8126741f740SMichael Walsh            gp.sprint_var(rc, 1)
8136741f740SMichael Walsh        BuiltIn().fail(gp.sprint_error(error_message))
8146741f740SMichael Walsh
8156741f740SMichael Walsh
8166741f740SMichael Walshdef test_loop_body():
8176741f740SMichael Walsh    r"""
8186741f740SMichael Walsh    The main loop body for the loop in main_py.
8196741f740SMichael Walsh
8206741f740SMichael Walsh    Description of arguments:
8216741f740SMichael Walsh    boot_count  The iteration number (starts at 1).
8226741f740SMichael Walsh    """
8236741f740SMichael Walsh
8246741f740SMichael Walsh    global boot_count
8256741f740SMichael Walsh    global state
8266741f740SMichael Walsh    global next_boot
8276741f740SMichael Walsh    global boot_success
828325eb548SSunil M    global boot_end_time
8296741f740SMichael Walsh
830b5839d00SMichael Walsh    gp.qprintn()
8316741f740SMichael Walsh
8326741f740SMichael Walsh    next_boot = select_boot()
833b5839d00SMichael Walsh    if next_boot == "":
834b5839d00SMichael Walsh        return True
8356741f740SMichael Walsh
836b5839d00SMichael Walsh    boot_count += 1
837b5839d00SMichael Walsh    gp.qprint_timen("Starting boot " + str(boot_count) + ".")
8386741f740SMichael Walsh
839e0cf8d70SMichael Walsh    pre_boot_plug_in_setup()
8406741f740SMichael Walsh
8416741f740SMichael Walsh    cmd_buf = ["run_boot", next_boot]
8426741f740SMichael Walsh    boot_status, msg = BuiltIn().run_keyword_and_ignore_error(*cmd_buf)
8436741f740SMichael Walsh    if boot_status == "FAIL":
844b5839d00SMichael Walsh        gp.qprint(msg)
8456741f740SMichael Walsh
846b5839d00SMichael Walsh    gp.qprintn()
8476741f740SMichael Walsh    if boot_status == "PASS":
8486741f740SMichael Walsh        boot_success = 1
849004ad3c9SJoy Onyerikwu        completion_msg = gp.sprint_timen("BOOT_SUCCESS: \"" + next_boot
850004ad3c9SJoy Onyerikwu                                         + "\" succeeded.")
8516741f740SMichael Walsh    else:
8526741f740SMichael Walsh        boot_success = 0
853004ad3c9SJoy Onyerikwu        completion_msg = gp.sprint_timen("BOOT_FAILED: \"" + next_boot
854004ad3c9SJoy Onyerikwu                                         + "\" failed.")
855325eb548SSunil M
856325eb548SSunil M    # Set boot_end_time for use by plug-ins.
857325eb548SSunil M    boot_end_time = completion_msg[1:33]
858325eb548SSunil M    gp.qprint_var(boot_end_time)
859325eb548SSunil M
860325eb548SSunil M    gp.qprint(completion_msg)
8616741f740SMichael Walsh
8626741f740SMichael Walsh    boot_results.update(next_boot, boot_status)
8636741f740SMichael Walsh
8646741f740SMichael Walsh    plug_in_setup()
8656741f740SMichael Walsh    # NOTE: A post_test_case call point failure is NOT counted as a boot
8666741f740SMichael Walsh    # failure.
8676741f740SMichael Walsh    rc, shell_rc, failed_plug_in_name = grpi.rprocess_plug_in_packages(
868600876daSMichael Walsh        call_point='post_test_case', stop_on_plug_in_failure=0)
8696741f740SMichael Walsh
8706741f740SMichael Walsh    plug_in_setup()
8716741f740SMichael Walsh    rc, shell_rc, failed_plug_in_name = grpi.rprocess_plug_in_packages(
872*89de14a4SMichael Walsh        call_point='ffdc_check', shell_rc=dump_ffdc_rc(),
8736741f740SMichael Walsh        stop_on_plug_in_failure=1, stop_on_non_zero_rc=1)
874*89de14a4SMichael Walsh    if boot_status != "PASS" or ffdc_check == "All" or\
875*89de14a4SMichael Walsh       shell_rc == dump_ffdc_rc():
87683f4bc77SMichael Walsh        status, ret_values = grk.run_key_u("my_ffdc", ignore=1)
87783f4bc77SMichael Walsh        if status != 'PASS':
878ff340006SMichael Walsh            gp.qprint_error("Call to my_ffdc failed.\n")
8796741f740SMichael Walsh
880aabef1e3SMichael Walsh    if delete_errlogs:
881d139f286SMichael Walsh        # We need to purge error logs between boots or they build up.
882b5839d00SMichael Walsh        grk.run_key("Delete Error logs", ignore=1)
883d139f286SMichael Walsh
884952f9b09SMichael Walsh    boot_results.print_report()
885b5839d00SMichael Walsh    gp.qprint_timen("Finished boot " + str(boot_count) + ".")
886952f9b09SMichael Walsh
8876741f740SMichael Walsh    plug_in_setup()
8886741f740SMichael Walsh    rc, shell_rc, failed_plug_in_name = grpi.rprocess_plug_in_packages(
889*89de14a4SMichael Walsh        call_point='stop_check', shell_rc=stop_test_rc(),
890*89de14a4SMichael Walsh        stop_on_non_zero_rc=1)
891*89de14a4SMichael Walsh    if shell_rc == stop_test_rc():
8923ba8ecdcSMichael Walsh        message = "Stopping as requested by user.\n"
8933ba8ecdcSMichael Walsh        gp.print_time(message)
8943ba8ecdcSMichael Walsh        BuiltIn().fail(message)
8956741f740SMichael Walsh
896d139f286SMichael Walsh    # This should help prevent ConnectionErrors.
8970960b384SMichael Walsh    grk.run_key_u("Close All Connections")
898d139f286SMichael Walsh
8996741f740SMichael Walsh    return True
9006741f740SMichael Walsh
9016741f740SMichael Walsh
90283f4bc77SMichael Walshdef obmc_boot_test_teardown():
9036741f740SMichael Walsh    r"""
904c9116811SMichael Walsh    Clean up after the Main keyword.
9056741f740SMichael Walsh    """
9066741f740SMichael Walsh
9076741f740SMichael Walsh    if cp_setup_called:
9086741f740SMichael Walsh        plug_in_setup()
9096741f740SMichael Walsh        rc, shell_rc, failed_plug_in_name = grpi.rprocess_plug_in_packages(
910600876daSMichael Walsh            call_point='cleanup', stop_on_plug_in_failure=0)
9116741f740SMichael Walsh
912600876daSMichael Walsh    if 'boot_results_file_path' in globals():
9136c64574bSMichael Walsh        # Save boot_results and last_ten objects to a file in case they are
9146c64574bSMichael Walsh        # needed again.
915b5839d00SMichael Walsh        gp.qprint_timen("Saving boot_results to the following path.")
916b5839d00SMichael Walsh        gp.qprint_var(boot_results_file_path)
9176c64574bSMichael Walsh        pickle.dump((boot_results, last_ten),
9186c64574bSMichael Walsh                    open(boot_results_file_path, 'wb'),
9190b93fbf8SMichael Walsh                    pickle.HIGHEST_PROTOCOL)
9200b93fbf8SMichael Walsh
921ff340006SMichael Walsh    global save_stack
922ff340006SMichael Walsh    # Restore any global values saved on the save_stack.
923ff340006SMichael Walsh    for parm_name in main_func_parm_list:
924ff340006SMichael Walsh        # Get the parm_value if it was saved on the stack.
925ff340006SMichael Walsh        try:
926ff340006SMichael Walsh            parm_value = save_stack.pop(parm_name)
927004ad3c9SJoy Onyerikwu        except BaseException:
928ff340006SMichael Walsh            # If it was not saved, no further action is required.
929ff340006SMichael Walsh            continue
930ff340006SMichael Walsh
931ff340006SMichael Walsh        # Restore the saved value.
932ff340006SMichael Walsh        cmd_buf = "BuiltIn().set_global_variable(\"${" + parm_name +\
933ff340006SMichael Walsh            "}\", parm_value)"
934ff340006SMichael Walsh        gp.dpissuing(cmd_buf)
935ff340006SMichael Walsh        exec(cmd_buf)
936ff340006SMichael Walsh
937ff340006SMichael Walsh    gp.dprintn(save_stack.sprint_obj())
938ff340006SMichael Walsh
9396741f740SMichael Walsh
940c9116811SMichael Walshdef test_teardown():
941c9116811SMichael Walsh    r"""
942c9116811SMichael Walsh    Clean up after this test case.
943c9116811SMichael Walsh    """
944c9116811SMichael Walsh
945c9116811SMichael Walsh    gp.qprintn()
946c9116811SMichael Walsh    cmd_buf = ["Print Error",
947c9116811SMichael Walsh               "A keyword timeout occurred ending this program.\n"]
948c9116811SMichael Walsh    BuiltIn().run_keyword_if_timeout_occurred(*cmd_buf)
949c9116811SMichael Walsh
950b5839d00SMichael Walsh    grp.rqprint_pgm_footer()
951b5839d00SMichael Walsh
952c9116811SMichael Walsh
953*89de14a4SMichael Walshdef post_stack():
954*89de14a4SMichael Walsh    r"""
955*89de14a4SMichael Walsh    Process post_stack plug-in programs.
956*89de14a4SMichael Walsh    """
957*89de14a4SMichael Walsh
958*89de14a4SMichael Walsh    if not call_post_stack_plug:
959*89de14a4SMichael Walsh        # The caller does not wish to have post_stack plug-in processing done.
960*89de14a4SMichael Walsh        return
961*89de14a4SMichael Walsh
962*89de14a4SMichael Walsh    global boot_success
963*89de14a4SMichael Walsh
964*89de14a4SMichael Walsh    # NOTE: A post_stack call-point failure is NOT counted as a boot failure.
965*89de14a4SMichael Walsh    pre_boot_plug_in_setup()
966*89de14a4SMichael Walsh    # For the purposes of the following plug-ins, mark the "boot" as a success.
967*89de14a4SMichael Walsh    boot_success = 1
968*89de14a4SMichael Walsh    plug_in_setup()
969*89de14a4SMichael Walsh    rc, shell_rc, failed_plug_in_name = grpi.rprocess_plug_in_packages(
970*89de14a4SMichael Walsh        call_point='post_stack', stop_on_plug_in_failure=0)
971*89de14a4SMichael Walsh
972*89de14a4SMichael Walsh    plug_in_setup()
973*89de14a4SMichael Walsh    if rc == 0:
974*89de14a4SMichael Walsh        rc, shell_rc, failed_plug_in_name = grpi.rprocess_plug_in_packages(
975*89de14a4SMichael Walsh            call_point='ffdc_check', shell_rc=dump_ffdc_rc(),
976*89de14a4SMichael Walsh            stop_on_plug_in_failure=1, stop_on_non_zero_rc=1)
977*89de14a4SMichael Walsh    if rc != 0 or shell_rc == dump_ffdc_rc():
978*89de14a4SMichael Walsh        status, ret_values = grk.run_key_u("my_ffdc", ignore=1)
979*89de14a4SMichael Walsh        if status != 'PASS':
980*89de14a4SMichael Walsh            gp.qprint_error("Call to my_ffdc failed.\n")
981*89de14a4SMichael Walsh
982*89de14a4SMichael Walsh    plug_in_setup()
983*89de14a4SMichael Walsh    rc, shell_rc, failed_plug_in_name = grpi.rprocess_plug_in_packages(
984*89de14a4SMichael Walsh        call_point='stop_check', shell_rc=stop_test_rc(),
985*89de14a4SMichael Walsh        stop_on_non_zero_rc=1)
986*89de14a4SMichael Walsh    if shell_rc == stop_test_rc():
987*89de14a4SMichael Walsh        message = "Stopping as requested by user.\n"
988*89de14a4SMichael Walsh        gp.print_time(message)
989*89de14a4SMichael Walsh        BuiltIn().fail(message)
990*89de14a4SMichael Walsh
991*89de14a4SMichael Walsh
992ff340006SMichael Walshdef obmc_boot_test_py(loc_boot_stack=None,
993ff340006SMichael Walsh                      loc_stack_mode=None,
994ff340006SMichael Walsh                      loc_quiet=None):
9956741f740SMichael Walsh    r"""
9966741f740SMichael Walsh    Do main program processing.
9976741f740SMichael Walsh    """
9986741f740SMichael Walsh
999ff340006SMichael Walsh    global save_stack
1000ff340006SMichael Walsh
1001ff340006SMichael Walsh    # Process function parms.
1002ff340006SMichael Walsh    for parm_name in main_func_parm_list:
1003ff340006SMichael Walsh        # Get parm's value.
1004ff340006SMichael Walsh        cmd_buf = "parm_value = loc_" + parm_name
1005ff340006SMichael Walsh        exec(cmd_buf)
1006ff340006SMichael Walsh        gp.dpvar(parm_name)
1007ff340006SMichael Walsh        gp.dpvar(parm_value)
1008ff340006SMichael Walsh
1009ff340006SMichael Walsh        if parm_value is None:
1010ff340006SMichael Walsh            # Parm was not specified by the calling function so set it to its
1011ff340006SMichael Walsh            # corresponding global value.
1012ff340006SMichael Walsh            cmd_buf = "loc_" + parm_name + " = BuiltIn().get_variable_value" +\
1013ff340006SMichael Walsh                "(\"${" + parm_name + "}\")"
1014ff340006SMichael Walsh            gp.dpissuing(cmd_buf)
1015ff340006SMichael Walsh            exec(cmd_buf)
1016ff340006SMichael Walsh        else:
1017ff340006SMichael Walsh            # Save the global value on a stack.
1018ff340006SMichael Walsh            cmd_buf = "save_stack.push(BuiltIn().get_variable_value(\"${" +\
1019ff340006SMichael Walsh                parm_name + "}\"), \"" + parm_name + "\")"
1020ff340006SMichael Walsh            gp.dpissuing(cmd_buf)
1021ff340006SMichael Walsh            exec(cmd_buf)
1022ff340006SMichael Walsh
1023ff340006SMichael Walsh            # Set the global value to the passed value.
1024ff340006SMichael Walsh            cmd_buf = "BuiltIn().set_global_variable(\"${" + parm_name +\
1025ff340006SMichael Walsh                "}\", loc_" + parm_name + ")"
1026ff340006SMichael Walsh            gp.dpissuing(cmd_buf)
1027ff340006SMichael Walsh            exec(cmd_buf)
1028ff340006SMichael Walsh
1029ff340006SMichael Walsh    gp.dprintn(save_stack.sprint_obj())
1030b5839d00SMichael Walsh
10316741f740SMichael Walsh    setup()
10326741f740SMichael Walsh
1033cd9fbfd7SMichael Walsh    init_boot_pass, init_boot_fail = boot_results.return_total_pass_fail()
1034cd9fbfd7SMichael Walsh
1035a20da401SMichael Walsh    if ffdc_only:
1036a20da401SMichael Walsh        gp.qprint_timen("Caller requested ffdc_only.")
1037e0cf8d70SMichael Walsh        pre_boot_plug_in_setup()
103883f4bc77SMichael Walsh        grk.run_key_u("my_ffdc")
1039764d2f83SMichael Walsh        return
1040a20da401SMichael Walsh
10416741f740SMichael Walsh    # Process caller's boot_stack.
10426741f740SMichael Walsh    while (len(boot_stack) > 0):
10436741f740SMichael Walsh        test_loop_body()
10446741f740SMichael Walsh
1045b5839d00SMichael Walsh    gp.qprint_timen("Finished processing stack.")
104630dadae2SMichael Walsh
1047*89de14a4SMichael Walsh    post_stack()
1048*89de14a4SMichael Walsh
10496741f740SMichael Walsh    # Process caller's boot_list.
10506741f740SMichael Walsh    if len(boot_list) > 0:
10516741f740SMichael Walsh        for ix in range(1, max_num_tests + 1):
10526741f740SMichael Walsh            test_loop_body()
10536741f740SMichael Walsh
1054b5839d00SMichael Walsh    gp.qprint_timen("Completed all requested boot tests.")
1055b5839d00SMichael Walsh
1056b5839d00SMichael Walsh    boot_pass, boot_fail = boot_results.return_total_pass_fail()
1057cd9fbfd7SMichael Walsh    new_fail = boot_fail - init_boot_fail
1058cd9fbfd7SMichael Walsh    if new_fail > boot_fail_threshold:
1059b5839d00SMichael Walsh        error_message = "Boot failures exceed the boot failure" +\
1060b5839d00SMichael Walsh                        " threshold:\n" +\
1061cd9fbfd7SMichael Walsh                        gp.sprint_var(new_fail) +\
1062b5839d00SMichael Walsh                        gp.sprint_var(boot_fail_threshold)
1063b5839d00SMichael Walsh        BuiltIn().fail(gp.sprint_error(error_message))
1064