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
130b93fbf8SMichael Walshimport cPickle as pickle
14dc80d67dSMichael Walshimport socket
150b93fbf8SMichael Walsh
160b93fbf8SMichael Walshfrom robot.utils import DotDict
170b93fbf8SMichael Walshfrom robot.libraries.BuiltIn import BuiltIn
180b93fbf8SMichael Walsh
196741f740SMichael Walshfrom boot_data import *
20c9116811SMichael Walshimport gen_print as gp
210bbd860fSMichael Walshimport gen_robot_print as grp
2255302295SMichael Walshimport gen_robot_plug_in as grpi
236741f740SMichael Walshimport gen_robot_valid as grv
246741f740SMichael Walshimport gen_misc as gm
256741f740SMichael Walshimport gen_cmd as gc
26b5839d00SMichael Walshimport gen_robot_keyword as grk
2755302295SMichael Walshimport state as st
28ff340006SMichael Walshimport var_stack as vs
290bbd860fSMichael Walsh
300b93fbf8SMichael Walshbase_path = os.path.dirname(os.path.dirname(
310b93fbf8SMichael Walsh                            imp.find_module("gen_robot_print")[1])) +\
320b93fbf8SMichael Walsh    os.sep
330b93fbf8SMichael Walshsys.path.append(base_path + "extended/")
340b93fbf8SMichael Walshimport run_keyword as rk
350bbd860fSMichael Walsh
36e1e26448SMichael Walsh# Setting master_pid correctly influences the behavior of plug-ins like
37e1e26448SMichael Walsh# DB_Logging
38e1e26448SMichael Walshprogram_pid = os.getpid()
39e1e26448SMichael Walshmaster_pid = os.environ.get('AUTOBOOT_MASTER_PID', program_pid)
40903e0b20SMichael Walshpgm_name = re.sub('\.py$', '', os.path.basename(__file__))
41e1e26448SMichael Walsh
42b5839d00SMichael Walsh# Set up boot data structures.
43b5839d00SMichael Walshboot_table = create_boot_table()
44b5839d00SMichael Walshvalid_boot_types = create_valid_boot_list(boot_table)
450b93fbf8SMichael Walsh
466741f740SMichael Walshboot_lists = read_boot_lists()
476741f740SMichael Walshlast_ten = []
486741f740SMichael Walsh
497dc885b6SMichael Walshstate = st.return_state_constant('default_state')
506741f740SMichael Walshcp_setup_called = 0
516741f740SMichael Walshnext_boot = ""
526741f740SMichael Walshbase_tool_dir_path = os.path.normpath(os.environ.get(
536741f740SMichael Walsh    'AUTOBOOT_BASE_TOOL_DIR_PATH', "/tmp")) + os.sep
54b5839d00SMichael Walsh
556741f740SMichael Walshffdc_dir_path = os.path.normpath(os.environ.get('FFDC_DIR_PATH', '')) + os.sep
566741f740SMichael Walshboot_success = 0
576741f740SMichael Walshstatus_dir_path = os.environ.get('STATUS_DIR_PATH', "")
586741f740SMichael Walshif status_dir_path != "":
596741f740SMichael Walsh    status_dir_path = os.path.normpath(status_dir_path) + os.sep
600b93fbf8SMichael Walshdefault_power_on = "REST Power On"
610b93fbf8SMichael Walshdefault_power_off = "REST Power Off"
626741f740SMichael Walshboot_count = 0
630bbd860fSMichael Walsh
6485678948SMichael WalshLOG_LEVEL = BuiltIn().get_variable_value("${LOG_LEVEL}")
65e1974b96SMichael Walshffdc_prefix = ""
66325eb548SSunil Mboot_start_time = ""
67325eb548SSunil Mboot_end_time = ""
68ff340006SMichael Walshsave_stack = vs.var_stack('save_stack')
69ff340006SMichael Walshmain_func_parm_list = ['boot_stack', 'stack_mode', 'quiet']
7085678948SMichael Walsh
7185678948SMichael Walsh
720ad0f7f8SMichael Walshdef process_host(host,
730ad0f7f8SMichael Walsh                 host_var_name=""):
740ad0f7f8SMichael Walsh    r"""
750ad0f7f8SMichael Walsh    Process a host by getting the associated host name and IP address and
760ad0f7f8SMichael Walsh    setting them in global variables.
770ad0f7f8SMichael Walsh
780ad0f7f8SMichael Walsh    If the caller does not pass the host_var_name, this function will try to
790ad0f7f8SMichael Walsh    figure out the name of the variable used by the caller for the host parm.
800ad0f7f8SMichael Walsh    Callers are advised to explicitly specify the host_var_name when calling
810ad0f7f8SMichael Walsh    with an exec command.  In such cases, the get_arg_name cannot figure out
820ad0f7f8SMichael Walsh    the host variable name.
830ad0f7f8SMichael Walsh
840ad0f7f8SMichael Walsh    This function will then create similar global variable names by
850ad0f7f8SMichael Walsh    removing "_host" and appending "_host_name" or "_ip" to the host variable
860ad0f7f8SMichael Walsh    name.
870ad0f7f8SMichael Walsh
880ad0f7f8SMichael Walsh    Example:
890ad0f7f8SMichael Walsh
900ad0f7f8SMichael Walsh    If a call is made like this:
910ad0f7f8SMichael Walsh    process_host(openbmc_host)
920ad0f7f8SMichael Walsh
930ad0f7f8SMichael Walsh    Global variables openbmc_host_name and openbmc_ip will be set.
940ad0f7f8SMichael Walsh
950ad0f7f8SMichael Walsh    Description of argument(s):
960ad0f7f8SMichael Walsh    host           A host name or IP.  The name of the variable used should
970ad0f7f8SMichael Walsh                   have a suffix of "_host".
980ad0f7f8SMichael Walsh    host_var_name  The name of the variable being used as the host parm.
990ad0f7f8SMichael Walsh    """
1000ad0f7f8SMichael Walsh
1010ad0f7f8SMichael Walsh    if host_var_name == "":
1020ad0f7f8SMichael Walsh        host_var_name = gp.get_arg_name(0, 1, stack_frame_ix=2)
1030ad0f7f8SMichael Walsh
1040ad0f7f8SMichael Walsh    host_name_var_name = re.sub("host", "host_name", host_var_name)
1050ad0f7f8SMichael Walsh    ip_var_name = re.sub("host", "ip", host_var_name)
1060ad0f7f8SMichael Walsh    cmd_buf = "global " + host_name_var_name + ", " + ip_var_name + " ; " +\
1070ad0f7f8SMichael Walsh        host_name_var_name + ", " + ip_var_name + " = gm.get_host_name_ip('" +\
1080ad0f7f8SMichael Walsh        host + "')"
1090ad0f7f8SMichael Walsh    exec(cmd_buf)
1100ad0f7f8SMichael Walsh
1110ad0f7f8SMichael Walsh
112b5839d00SMichael Walshdef process_pgm_parms():
113b5839d00SMichael Walsh    r"""
114b5839d00SMichael Walsh    Process the program parameters by assigning them all to corresponding
115b5839d00SMichael Walsh    globals.  Also, set some global values that depend on program parameters.
116b5839d00SMichael Walsh    """
117b5839d00SMichael Walsh
118b5839d00SMichael Walsh    # Program parameter processing.
119b5839d00SMichael Walsh    # Assign all program parms to python variables which are global to this
120b5839d00SMichael Walsh    # module.
121b5839d00SMichael Walsh
122b5839d00SMichael Walsh    global parm_list
123b5839d00SMichael Walsh    parm_list = BuiltIn().get_variable_value("${parm_list}")
124b5839d00SMichael Walsh    # The following subset of parms should be processed as integers.
125b5839d00SMichael Walsh    int_list = ['max_num_tests', 'boot_pass', 'boot_fail', 'ffdc_only',
126aabef1e3SMichael Walsh                'boot_fail_threshold', 'delete_errlogs', 'quiet', 'test_mode',
127aabef1e3SMichael Walsh                'debug']
128b5839d00SMichael Walsh    for parm in parm_list:
129b5839d00SMichael Walsh        if parm in int_list:
130b5839d00SMichael Walsh            sub_cmd = "int(BuiltIn().get_variable_value(\"${" + parm +\
131b5839d00SMichael Walsh                      "}\", \"0\"))"
132b5839d00SMichael Walsh        else:
133b5839d00SMichael Walsh            sub_cmd = "BuiltIn().get_variable_value(\"${" + parm + "}\")"
134b5839d00SMichael Walsh        cmd_buf = "global " + parm + " ; " + parm + " = " + sub_cmd
135ff340006SMichael Walsh        gp.dpissuing(cmd_buf)
136b5839d00SMichael Walsh        exec(cmd_buf)
1370ad0f7f8SMichael Walsh        if re.match(r".*_host$", parm):
1380ad0f7f8SMichael Walsh            cmd_buf = "process_host(" + parm + ", '" + parm + "')"
1390ad0f7f8SMichael Walsh            exec(cmd_buf)
1400ad0f7f8SMichael Walsh        if re.match(r".*_password$", parm):
1410ad0f7f8SMichael Walsh            # Register the value of any parm whose name ends in _password.
1420ad0f7f8SMichael Walsh            # This will cause the print functions to replace passwords with
1430ad0f7f8SMichael Walsh            # asterisks in the output.
1440ad0f7f8SMichael Walsh            cmd_buf = "gp.register_passwords(" + parm + ")"
1450ad0f7f8SMichael Walsh            exec(cmd_buf)
146b5839d00SMichael Walsh
147b5839d00SMichael Walsh    global ffdc_dir_path_style
148b5839d00SMichael Walsh    global boot_list
149b5839d00SMichael Walsh    global boot_stack
150b5839d00SMichael Walsh    global boot_results_file_path
151b5839d00SMichael Walsh    global boot_results
152b5839d00SMichael Walsh    global ffdc_list_file_path
153e0cf8d70SMichael Walsh    global ffdc_report_list_path
154600876daSMichael Walsh    global ffdc_summary_list_path
155b5839d00SMichael Walsh
156b5839d00SMichael Walsh    if ffdc_dir_path_style == "":
157b5839d00SMichael Walsh        ffdc_dir_path_style = int(os.environ.get('FFDC_DIR_PATH_STYLE', '0'))
158b5839d00SMichael Walsh
159b5839d00SMichael Walsh    # Convert these program parms to lists for easier processing..
160b5839d00SMichael Walsh    boot_list = filter(None, boot_list.split(":"))
161b5839d00SMichael Walsh    boot_stack = filter(None, boot_stack.split(":"))
162b5839d00SMichael Walsh
163903e0b20SMichael Walsh    cleanup_boot_results_file()
164903e0b20SMichael Walsh    boot_results_file_path = create_boot_results_file_path(pgm_name,
165903e0b20SMichael Walsh                                                           openbmc_nickname,
166903e0b20SMichael Walsh                                                           master_pid)
167b5839d00SMichael Walsh
168b5839d00SMichael Walsh    if os.path.isfile(boot_results_file_path):
169b5839d00SMichael Walsh        # We've been called before in this run so we'll load the saved
170b5839d00SMichael Walsh        # boot_results object.
171b5839d00SMichael Walsh        boot_results = pickle.load(open(boot_results_file_path, 'rb'))
172b5839d00SMichael Walsh    else:
173b5839d00SMichael Walsh        boot_results = boot_results(boot_table, boot_pass, boot_fail)
174b5839d00SMichael Walsh
175b5839d00SMichael Walsh    ffdc_list_file_path = base_tool_dir_path + openbmc_nickname +\
176b5839d00SMichael Walsh        "/FFDC_FILE_LIST"
177e0cf8d70SMichael Walsh    ffdc_report_list_path = base_tool_dir_path + openbmc_nickname +\
178e0cf8d70SMichael Walsh        "/FFDC_REPORT_FILE_LIST"
179b5839d00SMichael Walsh
180600876daSMichael Walsh    ffdc_summary_list_path = base_tool_dir_path + openbmc_nickname +\
181600876daSMichael Walsh        "/FFDC_SUMMARY_FILE_LIST"
182600876daSMichael Walsh
183b5839d00SMichael Walsh
18485678948SMichael Walshdef initial_plug_in_setup():
18585678948SMichael Walsh    r"""
18685678948SMichael Walsh    Initialize all plug-in environment variables which do not change for the
18785678948SMichael Walsh    duration of the program.
18885678948SMichael Walsh
18985678948SMichael Walsh    """
19085678948SMichael Walsh
19185678948SMichael Walsh    global LOG_LEVEL
19285678948SMichael Walsh    BuiltIn().set_log_level("NONE")
19385678948SMichael Walsh
19485678948SMichael Walsh    BuiltIn().set_global_variable("${master_pid}", master_pid)
19585678948SMichael Walsh    BuiltIn().set_global_variable("${FFDC_DIR_PATH}", ffdc_dir_path)
19685678948SMichael Walsh    BuiltIn().set_global_variable("${STATUS_DIR_PATH}", status_dir_path)
19785678948SMichael Walsh    BuiltIn().set_global_variable("${BASE_TOOL_DIR_PATH}", base_tool_dir_path)
19885678948SMichael Walsh    BuiltIn().set_global_variable("${FFDC_LIST_FILE_PATH}",
19985678948SMichael Walsh                                  ffdc_list_file_path)
200e0cf8d70SMichael Walsh    BuiltIn().set_global_variable("${FFDC_REPORT_LIST_PATH}",
201e0cf8d70SMichael Walsh                                  ffdc_report_list_path)
202600876daSMichael Walsh    BuiltIn().set_global_variable("${FFDC_SUMMARY_LIST_PATH}",
203600876daSMichael Walsh                                  ffdc_summary_list_path)
20485678948SMichael Walsh
20585678948SMichael Walsh    BuiltIn().set_global_variable("${FFDC_DIR_PATH_STYLE}",
20685678948SMichael Walsh                                  ffdc_dir_path_style)
20785678948SMichael Walsh    BuiltIn().set_global_variable("${FFDC_CHECK}",
20885678948SMichael Walsh                                  ffdc_check)
20985678948SMichael Walsh
21085678948SMichael Walsh    # For each program parameter, set the corresponding AUTOBOOT_ environment
21185678948SMichael Walsh    # variable value.  Also, set an AUTOBOOT_ environment variable for every
21285678948SMichael Walsh    # element in additional_values.
21385678948SMichael Walsh    additional_values = ["program_pid", "master_pid", "ffdc_dir_path",
21485678948SMichael Walsh                         "status_dir_path", "base_tool_dir_path",
215600876daSMichael Walsh                         "ffdc_list_file_path", "ffdc_report_list_path",
216600876daSMichael Walsh                         "ffdc_summary_list_path"]
21785678948SMichael Walsh
21885678948SMichael Walsh    plug_in_vars = parm_list + additional_values
21985678948SMichael Walsh
22085678948SMichael Walsh    for var_name in plug_in_vars:
22185678948SMichael Walsh        var_value = BuiltIn().get_variable_value("${" + var_name + "}")
22285678948SMichael Walsh        var_name = var_name.upper()
22385678948SMichael Walsh        if var_value is None:
22485678948SMichael Walsh            var_value = ""
22585678948SMichael Walsh        os.environ["AUTOBOOT_" + var_name] = str(var_value)
22685678948SMichael Walsh
22785678948SMichael Walsh    BuiltIn().set_log_level(LOG_LEVEL)
22885678948SMichael Walsh
22968a61162SMichael Walsh    # Make sure the ffdc list directory exists.
23068a61162SMichael Walsh    ffdc_list_dir_path = os.path.dirname(ffdc_list_file_path) + os.sep
23168a61162SMichael Walsh    if not os.path.exists(ffdc_list_dir_path):
23268a61162SMichael Walsh        os.makedirs(ffdc_list_dir_path)
23385678948SMichael Walsh
23485678948SMichael Walsh
2350bbd860fSMichael Walshdef plug_in_setup():
2360bbd860fSMichael Walsh    r"""
23785678948SMichael Walsh    Initialize all changing plug-in environment variables for use by the
23885678948SMichael Walsh    plug-in programs.
2390bbd860fSMichael Walsh    """
2400bbd860fSMichael Walsh
24185678948SMichael Walsh    global LOG_LEVEL
24285678948SMichael Walsh    global test_really_running
24385678948SMichael Walsh
24485678948SMichael Walsh    BuiltIn().set_log_level("NONE")
24585678948SMichael Walsh
2466741f740SMichael Walsh    boot_pass, boot_fail = boot_results.return_total_pass_fail()
2470bbd860fSMichael Walsh    if boot_pass > 1:
2480bbd860fSMichael Walsh        test_really_running = 1
2490bbd860fSMichael Walsh    else:
2500bbd860fSMichael Walsh        test_really_running = 0
2510bbd860fSMichael Walsh
2526741f740SMichael Walsh    BuiltIn().set_global_variable("${test_really_running}",
2536741f740SMichael Walsh                                  test_really_running)
2546741f740SMichael Walsh    BuiltIn().set_global_variable("${boot_type_desc}", next_boot)
2556741f740SMichael Walsh    BuiltIn().set_global_variable("${boot_pass}", boot_pass)
2566741f740SMichael Walsh    BuiltIn().set_global_variable("${boot_fail}", boot_fail)
2576741f740SMichael Walsh    BuiltIn().set_global_variable("${boot_success}", boot_success)
2586741f740SMichael Walsh    BuiltIn().set_global_variable("${ffdc_prefix}", ffdc_prefix)
259325eb548SSunil M    BuiltIn().set_global_variable("${boot_start_time}", boot_start_time)
260325eb548SSunil M    BuiltIn().set_global_variable("${boot_end_time}", boot_end_time)
2614c9a6453SMichael Walsh
2620bbd860fSMichael Walsh    # For each program parameter, set the corresponding AUTOBOOT_ environment
2630bbd860fSMichael Walsh    # variable value.  Also, set an AUTOBOOT_ environment variable for every
2640bbd860fSMichael Walsh    # element in additional_values.
2650bbd860fSMichael Walsh    additional_values = ["boot_type_desc", "boot_success", "boot_pass",
266325eb548SSunil M                         "boot_fail", "test_really_running", "ffdc_prefix",
267325eb548SSunil M                         "boot_start_time", "boot_end_time"]
2680bbd860fSMichael Walsh
26985678948SMichael Walsh    plug_in_vars = additional_values
2700bbd860fSMichael Walsh
2710bbd860fSMichael Walsh    for var_name in plug_in_vars:
2720bbd860fSMichael Walsh        var_value = BuiltIn().get_variable_value("${" + var_name + "}")
2730bbd860fSMichael Walsh        var_name = var_name.upper()
2740bbd860fSMichael Walsh        if var_value is None:
2750bbd860fSMichael Walsh            var_value = ""
2766741f740SMichael Walsh        os.environ["AUTOBOOT_" + var_name] = str(var_value)
2770bbd860fSMichael Walsh
2780bbd860fSMichael Walsh    if debug:
2796741f740SMichael Walsh        shell_rc, out_buf = \
2806741f740SMichael Walsh            gc.cmd_fnc_u("printenv | egrep AUTOBOOT_ | sort -u")
2810bbd860fSMichael Walsh
28285678948SMichael Walsh    BuiltIn().set_log_level(LOG_LEVEL)
28385678948SMichael Walsh
2840bbd860fSMichael Walsh
285e0cf8d70SMichael Walshdef pre_boot_plug_in_setup():
286e0cf8d70SMichael Walsh
287e0cf8d70SMichael Walsh    # Clear the ffdc_list_file_path file.  Plug-ins may now write to it.
288e0cf8d70SMichael Walsh    try:
289e0cf8d70SMichael Walsh        os.remove(ffdc_list_file_path)
290e0cf8d70SMichael Walsh    except OSError:
291e0cf8d70SMichael Walsh        pass
292e0cf8d70SMichael Walsh
293e0cf8d70SMichael Walsh    # Clear the ffdc_report_list_path file.  Plug-ins may now write to it.
294e0cf8d70SMichael Walsh    try:
295e0cf8d70SMichael Walsh        os.remove(ffdc_report_list_path)
296e0cf8d70SMichael Walsh    except OSError:
297e0cf8d70SMichael Walsh        pass
298e0cf8d70SMichael Walsh
299600876daSMichael Walsh    # Clear the ffdc_summary_list_path file.  Plug-ins may now write to it.
300600876daSMichael Walsh    try:
301600876daSMichael Walsh        os.remove(ffdc_summary_list_path)
302600876daSMichael Walsh    except OSError:
303600876daSMichael Walsh        pass
304600876daSMichael Walsh
305e1974b96SMichael Walsh    global ffdc_prefix
306e1974b96SMichael Walsh
307e1974b96SMichael Walsh    seconds = time.time()
308e1974b96SMichael Walsh    loc_time = time.localtime(seconds)
309e1974b96SMichael Walsh    time_string = time.strftime("%y%m%d.%H%M%S.", loc_time)
310e1974b96SMichael Walsh
311e1974b96SMichael Walsh    ffdc_prefix = openbmc_nickname + "." + time_string
312e1974b96SMichael Walsh
313e0cf8d70SMichael Walsh
3146741f740SMichael Walshdef setup():
3150bbd860fSMichael Walsh    r"""
3166741f740SMichael Walsh    Do general program setup tasks.
3170bbd860fSMichael Walsh    """
3180bbd860fSMichael Walsh
3196741f740SMichael Walsh    global cp_setup_called
32081816748SMichael Walsh    global transitional_boot_selected
3210bbd860fSMichael Walsh
322b5839d00SMichael Walsh    gp.qprintn()
323b5839d00SMichael Walsh
32481816748SMichael Walsh    transitional_boot_selected = False
32581816748SMichael Walsh
32683f4bc77SMichael Walsh    robot_pgm_dir_path = os.path.dirname(__file__) + os.sep
32783f4bc77SMichael Walsh    repo_bin_path = robot_pgm_dir_path.replace("/lib/", "/bin/")
328d061c043SMichael Walsh    # If we can't find process_plug_in_packages.py, ssh_pw or
329d061c043SMichael Walsh    # validate_plug_ins.py, then we don't have our repo bin in PATH.
330d061c043SMichael Walsh    shell_rc, out_buf = gc.cmd_fnc_u("which process_plug_in_packages.py" +
331d061c043SMichael Walsh                                     " ssh_pw validate_plug_ins.py", quiet=1,
332d061c043SMichael Walsh                                     print_output=0, show_err=0)
333b5839d00SMichael Walsh    if shell_rc != 0:
33483f4bc77SMichael Walsh        os.environ['PATH'] = repo_bin_path + ":" + os.environ.get('PATH', "")
33583f4bc77SMichael Walsh    # Likewise, our repo lib subdir needs to be in sys.path and PYTHONPATH.
33683f4bc77SMichael Walsh    if robot_pgm_dir_path not in sys.path:
33783f4bc77SMichael Walsh        sys.path.append(robot_pgm_dir_path)
33883f4bc77SMichael Walsh        PYTHONPATH = os.environ.get("PYTHONPATH", "")
33983f4bc77SMichael Walsh        if PYTHONPATH == "":
34083f4bc77SMichael Walsh            os.environ['PYTHONPATH'] = robot_pgm_dir_path
34183f4bc77SMichael Walsh        else:
34283f4bc77SMichael Walsh            os.environ['PYTHONPATH'] = robot_pgm_dir_path + ":" + PYTHONPATH
3436741f740SMichael Walsh
3446741f740SMichael Walsh    validate_parms()
3456741f740SMichael Walsh
3466741f740SMichael Walsh    grp.rqprint_pgm_header()
3476741f740SMichael Walsh
348efc3ff2bSGeorge Keishing    grk.run_key("Set BMC Power Policy  ALWAYS_POWER_OFF")
34911cfc8c0SMichael Walsh
35085678948SMichael Walsh    initial_plug_in_setup()
35185678948SMichael Walsh
3526741f740SMichael Walsh    plug_in_setup()
3536741f740SMichael Walsh    rc, shell_rc, failed_plug_in_name = grpi.rprocess_plug_in_packages(
3546741f740SMichael Walsh        call_point='setup')
3556741f740SMichael Walsh    if rc != 0:
3566741f740SMichael Walsh        error_message = "Plug-in setup failed.\n"
3576741f740SMichael Walsh        grp.rprint_error_report(error_message)
3586741f740SMichael Walsh        BuiltIn().fail(error_message)
3596741f740SMichael Walsh    # Setting cp_setup_called lets our Teardown know that it needs to call
3606741f740SMichael Walsh    # the cleanup plug-in call point.
3616741f740SMichael Walsh    cp_setup_called = 1
3626741f740SMichael Walsh
3636741f740SMichael Walsh    # Keyword "FFDC" will fail if TEST_MESSAGE is not set.
3646741f740SMichael Walsh    BuiltIn().set_global_variable("${TEST_MESSAGE}", "${EMPTY}")
36585678948SMichael Walsh    # FFDC_LOG_PATH is used by "FFDC" keyword.
36685678948SMichael Walsh    BuiltIn().set_global_variable("${FFDC_LOG_PATH}", ffdc_dir_path)
3676741f740SMichael Walsh
368dc80d67dSMichael Walsh    # Also printed by FFDC.
369dc80d67dSMichael Walsh    global host_name
370dc80d67dSMichael Walsh    global host_ip
371dc80d67dSMichael Walsh    host = socket.gethostname()
372dc80d67dSMichael Walsh    host_name, host_ip = gm.get_host_name_ip(host)
373dc80d67dSMichael Walsh
374b5839d00SMichael Walsh    gp.dprint_var(boot_table, 1)
375b5839d00SMichael Walsh    gp.dprint_var(boot_lists)
3760bbd860fSMichael Walsh
3770bbd860fSMichael Walsh
3786741f740SMichael Walshdef validate_parms():
3790bbd860fSMichael Walsh    r"""
3806741f740SMichael Walsh    Validate all program parameters.
3810bbd860fSMichael Walsh    """
3820bbd860fSMichael Walsh
383b5839d00SMichael Walsh    process_pgm_parms()
3840bbd860fSMichael Walsh
385b5839d00SMichael Walsh    gp.qprintn()
386b5839d00SMichael Walsh
387b5839d00SMichael Walsh    global openbmc_model
3886741f740SMichael Walsh    grv.rvalid_value("openbmc_host")
3896741f740SMichael Walsh    grv.rvalid_value("openbmc_username")
3906741f740SMichael Walsh    grv.rvalid_value("openbmc_password")
3916741f740SMichael Walsh    if os_host != "":
3926741f740SMichael Walsh        grv.rvalid_value("os_username")
3936741f740SMichael Walsh        grv.rvalid_value("os_password")
3940bbd860fSMichael Walsh
3956741f740SMichael Walsh    if pdu_host != "":
3966741f740SMichael Walsh        grv.rvalid_value("pdu_username")
3976741f740SMichael Walsh        grv.rvalid_value("pdu_password")
3986741f740SMichael Walsh        grv.rvalid_integer("pdu_slot_no")
3996741f740SMichael Walsh    if openbmc_serial_host != "":
4006741f740SMichael Walsh        grv.rvalid_integer("openbmc_serial_port")
401b5839d00SMichael Walsh    if openbmc_model == "":
402b5839d00SMichael Walsh        status, ret_values =\
403b5839d00SMichael Walsh            grk.run_key_u("Get BMC System Model")
404b5839d00SMichael Walsh        openbmc_model = ret_values
405b5839d00SMichael Walsh        BuiltIn().set_global_variable("${openbmc_model}", openbmc_model)
4066741f740SMichael Walsh    grv.rvalid_value("openbmc_model")
407b5839d00SMichael Walsh    grv.rvalid_integer("max_num_tests")
4086741f740SMichael Walsh    grv.rvalid_integer("boot_pass")
4096741f740SMichael Walsh    grv.rvalid_integer("boot_fail")
4106741f740SMichael Walsh
4116741f740SMichael Walsh    plug_in_packages_list = grpi.rvalidate_plug_ins(plug_in_dir_paths)
4126741f740SMichael Walsh    BuiltIn().set_global_variable("${plug_in_packages_list}",
4136741f740SMichael Walsh                                  plug_in_packages_list)
4146741f740SMichael Walsh
415b5839d00SMichael Walsh    grv.rvalid_value("stack_mode", valid_values=['normal', 'skip'])
416a20da401SMichael Walsh    if len(boot_list) == 0 and len(boot_stack) == 0 and not ffdc_only:
4176741f740SMichael Walsh        error_message = "You must provide either a value for either the" +\
4186741f740SMichael Walsh            " boot_list or the boot_stack parm.\n"
4196741f740SMichael Walsh        BuiltIn().fail(gp.sprint_error(error_message))
4206741f740SMichael Walsh
4216741f740SMichael Walsh    valid_boot_list(boot_list, valid_boot_types)
4226741f740SMichael Walsh    valid_boot_list(boot_stack, valid_boot_types)
4236741f740SMichael Walsh
42411cfc8c0SMichael Walsh    selected_PDU_boots = list(set(boot_list + boot_stack) &
42511cfc8c0SMichael Walsh                              set(boot_lists['PDU_reboot']))
42611cfc8c0SMichael Walsh
42711cfc8c0SMichael Walsh    if len(selected_PDU_boots) > 0 and pdu_host == "":
42811cfc8c0SMichael Walsh        error_message = "You have selected the following boots which" +\
42911cfc8c0SMichael Walsh                        " require a PDU host but no value for pdu_host:\n"
43011cfc8c0SMichael Walsh        error_message += gp.sprint_var(selected_PDU_boots)
43111cfc8c0SMichael Walsh        error_message += gp.sprint_var(pdu_host, 2)
43211cfc8c0SMichael Walsh        BuiltIn().fail(gp.sprint_error(error_message))
43311cfc8c0SMichael Walsh
4346741f740SMichael Walsh    return
4350bbd860fSMichael Walsh
4360bbd860fSMichael Walsh
4376741f740SMichael Walshdef my_get_state():
4380bbd860fSMichael Walsh    r"""
4396741f740SMichael Walsh    Get the system state plus a little bit of wrapping.
4400bbd860fSMichael Walsh    """
4410bbd860fSMichael Walsh
4426741f740SMichael Walsh    global state
4436741f740SMichael Walsh
4446741f740SMichael Walsh    req_states = ['epoch_seconds'] + st.default_req_states
4456741f740SMichael Walsh
446b5839d00SMichael Walsh    gp.qprint_timen("Getting system state.")
4476741f740SMichael Walsh    if test_mode:
4486741f740SMichael Walsh        state['epoch_seconds'] = int(time.time())
4496741f740SMichael Walsh    else:
450b5839d00SMichael Walsh        state = st.get_state(req_states=req_states, quiet=quiet)
451b5839d00SMichael Walsh    gp.qprint_var(state)
452341c21ebSMichael Walsh
453341c21ebSMichael Walsh
45445ca6e4cSMichael Walshdef valid_state():
45545ca6e4cSMichael Walsh    r"""
45645ca6e4cSMichael Walsh    Verify that our state dictionary contains no blank values.  If we don't get
45745ca6e4cSMichael Walsh    valid state data, we cannot continue to work.
45845ca6e4cSMichael Walsh    """
45945ca6e4cSMichael Walsh
46045ca6e4cSMichael Walsh    if st.compare_states(state, st.invalid_state_match, 'or'):
46145ca6e4cSMichael Walsh        error_message = "The state dictionary contains blank fields which" +\
46245ca6e4cSMichael Walsh            " is illegal.\n" + gp.sprint_var(state)
46345ca6e4cSMichael Walsh        BuiltIn().fail(gp.sprint_error(error_message))
46445ca6e4cSMichael Walsh
46545ca6e4cSMichael Walsh
4666741f740SMichael Walshdef select_boot():
467341c21ebSMichael Walsh    r"""
468341c21ebSMichael Walsh    Select a boot test to be run based on our current state and return the
469341c21ebSMichael Walsh    chosen boot type.
470341c21ebSMichael Walsh
471341c21ebSMichael Walsh    Description of arguments:
4726741f740SMichael Walsh    state  The state of the machine.
473341c21ebSMichael Walsh    """
474341c21ebSMichael Walsh
47581816748SMichael Walsh    global transitional_boot_selected
47630dadae2SMichael Walsh    global boot_stack
47730dadae2SMichael Walsh
478b5839d00SMichael Walsh    gp.qprint_timen("Selecting a boot test.")
4796741f740SMichael Walsh
48081816748SMichael Walsh    if transitional_boot_selected and not boot_success:
48181816748SMichael Walsh        prior_boot = next_boot
48281816748SMichael Walsh        boot_candidate = boot_stack.pop()
48381816748SMichael Walsh        gp.qprint_timen("The prior '" + next_boot + "' was chosen to" +
48481816748SMichael Walsh                        " transition to a valid state for '" + boot_candidate +
48581816748SMichael Walsh                        "' which was at the top of the boot_stack.  Since" +
48681816748SMichael Walsh                        " the '" + next_boot + "' failed, the '" +
48781816748SMichael Walsh                        boot_candidate + "' has been removed from the stack" +
48881816748SMichael Walsh                        " to avoid and endless failure loop.")
48981816748SMichael Walsh        if len(boot_stack) == 0:
49081816748SMichael Walsh            return ""
49181816748SMichael Walsh
4926741f740SMichael Walsh    my_get_state()
49345ca6e4cSMichael Walsh    valid_state()
4946741f740SMichael Walsh
49581816748SMichael Walsh    transitional_boot_selected = False
4966741f740SMichael Walsh    stack_popped = 0
4976741f740SMichael Walsh    if len(boot_stack) > 0:
4986741f740SMichael Walsh        stack_popped = 1
499b5839d00SMichael Walsh        gp.qprint_dashes()
500b5839d00SMichael Walsh        gp.qprint_var(boot_stack)
501b5839d00SMichael Walsh        gp.qprint_dashes()
502b5839d00SMichael Walsh        skip_boot_printed = 0
503b5839d00SMichael Walsh        while len(boot_stack) > 0:
5046741f740SMichael Walsh            boot_candidate = boot_stack.pop()
505b5839d00SMichael Walsh            if stack_mode == 'normal':
506b5839d00SMichael Walsh                break
507b5839d00SMichael Walsh            else:
508b5839d00SMichael Walsh                if st.compare_states(state, boot_table[boot_candidate]['end']):
509b5839d00SMichael Walsh                    if not skip_boot_printed:
510ff340006SMichael Walsh                        gp.qprint_var(stack_mode)
511ff340006SMichael Walsh                        gp.qprintn()
512ff340006SMichael Walsh                        gp.qprint_timen("Skipping the following boot tests" +
513b5839d00SMichael Walsh                                        " which are unnecessary since their" +
514b5839d00SMichael Walsh                                        " required end states match the" +
515b5839d00SMichael Walsh                                        " current machine state:")
516b5839d00SMichael Walsh                        skip_boot_printed = 1
517ff340006SMichael Walsh                    gp.qprint_var(boot_candidate)
518b5839d00SMichael Walsh                    boot_candidate = ""
519b5839d00SMichael Walsh        if boot_candidate == "":
520b5839d00SMichael Walsh            gp.qprint_dashes()
521b5839d00SMichael Walsh            gp.qprint_var(boot_stack)
522b5839d00SMichael Walsh            gp.qprint_dashes()
523b5839d00SMichael Walsh            return boot_candidate
5246741f740SMichael Walsh        if st.compare_states(state, boot_table[boot_candidate]['start']):
525b5839d00SMichael Walsh            gp.qprint_timen("The machine state is valid for a '" +
5266741f740SMichael Walsh                            boot_candidate + "' boot test.")
527b5839d00SMichael Walsh            gp.qprint_dashes()
528b5839d00SMichael Walsh            gp.qprint_var(boot_stack)
529b5839d00SMichael Walsh            gp.qprint_dashes()
5306741f740SMichael Walsh            return boot_candidate
531341c21ebSMichael Walsh        else:
532b5839d00SMichael Walsh            gp.qprint_timen("The machine state does not match the required" +
533b5839d00SMichael Walsh                            " starting state for a '" + boot_candidate +
534b5839d00SMichael Walsh                            "' boot test:")
535ff340006SMichael Walsh            gp.qprint_varx("boot_table[" + boot_candidate + "][start]",
536b5839d00SMichael Walsh                           boot_table[boot_candidate]['start'], 1)
5376741f740SMichael Walsh            boot_stack.append(boot_candidate)
53881816748SMichael Walsh            transitional_boot_selected = True
5396741f740SMichael Walsh            popped_boot = boot_candidate
5406741f740SMichael Walsh
5416741f740SMichael Walsh    # Loop through your list selecting a boot_candidates
5426741f740SMichael Walsh    boot_candidates = []
5436741f740SMichael Walsh    for boot_candidate in boot_list:
5446741f740SMichael Walsh        if st.compare_states(state, boot_table[boot_candidate]['start']):
5456741f740SMichael Walsh            if stack_popped:
5466741f740SMichael Walsh                if st.compare_states(boot_table[boot_candidate]['end'],
5476741f740SMichael Walsh                                     boot_table[popped_boot]['start']):
5486741f740SMichael Walsh                    boot_candidates.append(boot_candidate)
549341c21ebSMichael Walsh            else:
5506741f740SMichael Walsh                boot_candidates.append(boot_candidate)
5516741f740SMichael Walsh
5526741f740SMichael Walsh    if len(boot_candidates) == 0:
553b5839d00SMichael Walsh        gp.qprint_timen("The user's boot list contained no boot tests" +
5546741f740SMichael Walsh                        " which are valid for the current machine state.")
5556741f740SMichael Walsh        boot_candidate = default_power_on
5566741f740SMichael Walsh        if not st.compare_states(state, boot_table[default_power_on]['start']):
5576741f740SMichael Walsh            boot_candidate = default_power_off
5586741f740SMichael Walsh        boot_candidates.append(boot_candidate)
559b5839d00SMichael Walsh        gp.qprint_timen("Using default '" + boot_candidate +
560b5839d00SMichael Walsh                        "' boot type to transition to valid state.")
5616741f740SMichael Walsh
562b5839d00SMichael Walsh    gp.dprint_var(boot_candidates)
5636741f740SMichael Walsh
5646741f740SMichael Walsh    # Randomly select a boot from the candidate list.
5656741f740SMichael Walsh    boot = random.choice(boot_candidates)
566341c21ebSMichael Walsh
567341c21ebSMichael Walsh    return boot
5680bbd860fSMichael Walsh
56955302295SMichael Walsh
570341c21ebSMichael Walshdef print_last_boots():
571341c21ebSMichael Walsh    r"""
572341c21ebSMichael Walsh    Print the last ten boots done with their time stamps.
573341c21ebSMichael Walsh    """
574341c21ebSMichael Walsh
575341c21ebSMichael Walsh    # indent 0, 90 chars wide, linefeed, char is "="
576b5839d00SMichael Walsh    gp.qprint_dashes(0, 90)
577b5839d00SMichael Walsh    gp.qprintn("Last 10 boots:\n")
578341c21ebSMichael Walsh
579341c21ebSMichael Walsh    for boot_entry in last_ten:
580341c21ebSMichael Walsh        grp.rqprint(boot_entry)
581b5839d00SMichael Walsh    gp.qprint_dashes(0, 90)
582341c21ebSMichael Walsh
583341c21ebSMichael Walsh
584b2e53ecdSMichael Walshdef print_defect_report(ffdc_file_list):
585341c21ebSMichael Walsh    r"""
586341c21ebSMichael Walsh    Print a defect report.
587b2e53ecdSMichael Walsh
588b2e53ecdSMichael Walsh    Description of argument(s):
589b2e53ecdSMichael Walsh    ffdc_file_list  A list of files which were collected by our ffdc functions.
590341c21ebSMichael Walsh    """
591341c21ebSMichael Walsh
592600876daSMichael Walsh    # Making deliberate choice to NOT run plug_in_setup().  We don't want
593600876daSMichael Walsh    # ffdc_prefix updated.
594600876daSMichael Walsh    rc, shell_rc, failed_plug_in_name = grpi.rprocess_plug_in_packages(
595600876daSMichael Walsh        call_point='ffdc_report', stop_on_plug_in_failure=0)
596600876daSMichael Walsh
597e0cf8d70SMichael Walsh    # Get additional header data which may have been created by ffdc plug-ins.
598e0cf8d70SMichael Walsh    # Also, delete the individual header files to cleanup.
599e0cf8d70SMichael Walsh    cmd_buf = "file_list=$(cat " + ffdc_report_list_path + " 2>/dev/null)" +\
600e0cf8d70SMichael Walsh              " ; [ ! -z \"${file_list}\" ] && cat ${file_list}" +\
601e0cf8d70SMichael Walsh              " 2>/dev/null ; rm -rf ${file_list} 2>/dev/null || :"
602e0cf8d70SMichael Walsh    shell_rc, more_header_info = gc.cmd_fnc_u(cmd_buf, print_output=0,
603e0cf8d70SMichael Walsh                                              show_err=0)
604e0cf8d70SMichael Walsh
605b2e53ecdSMichael Walsh    # Get additional summary data which may have been created by ffdc plug-ins.
606600876daSMichael Walsh    # Also, delete the individual header files to cleanup.
607600876daSMichael Walsh    cmd_buf = "file_list=$(cat " + ffdc_summary_list_path + " 2>/dev/null)" +\
608600876daSMichael Walsh              " ; [ ! -z \"${file_list}\" ] && cat ${file_list}" +\
609600876daSMichael Walsh              " 2>/dev/null ; rm -rf ${file_list} 2>/dev/null || :"
610600876daSMichael Walsh    shell_rc, ffdc_summary_info = gc.cmd_fnc_u(cmd_buf, print_output=0,
611600876daSMichael Walsh                                               show_err=0)
612600876daSMichael Walsh
613b2e53ecdSMichael Walsh    # ffdc_list_file_path contains a list of any ffdc files created by plug-
614b2e53ecdSMichael Walsh    # ins, etc.  Read that data into a list.
615341c21ebSMichael Walsh    try:
616b2e53ecdSMichael Walsh        plug_in_ffdc_list = \
617b2e53ecdSMichael Walsh            open(ffdc_list_file_path, 'r').read().rstrip("\n").split("\n")
618b2e53ecdSMichael Walsh        plug_in_ffdc_list = filter(None, plug_in_ffdc_list)
619341c21ebSMichael Walsh    except IOError:
620b2e53ecdSMichael Walsh        plug_in_ffdc_list = []
621b2e53ecdSMichael Walsh
622b2e53ecdSMichael Walsh    # Combine the files from plug_in_ffdc_list with the ffdc_file_list passed
623b2e53ecdSMichael Walsh    # in.  Eliminate duplicates and sort the list.
624b2e53ecdSMichael Walsh    ffdc_file_list = list(set(ffdc_file_list + plug_in_ffdc_list))
625b2e53ecdSMichael Walsh    ffdc_file_list.sort()
626b2e53ecdSMichael Walsh
627b2e53ecdSMichael Walsh    if status_file_path != "":
628b2e53ecdSMichael Walsh        ffdc_file_list.insert(0, status_file_path)
629b2e53ecdSMichael Walsh
630b2e53ecdSMichael Walsh    # Convert the list to a printable list.
631b2e53ecdSMichael Walsh    printable_ffdc_file_list = "\n".join(ffdc_file_list)
632341c21ebSMichael Walsh
63368a61162SMichael Walsh    # Open ffdc_file_list for writing.  We will write a complete list of
63468a61162SMichael Walsh    # FFDC files to it for possible use by plug-ins like cp_stop_check.
63568a61162SMichael Walsh    ffdc_list_file = open(ffdc_list_file_path, 'w')
636b2e53ecdSMichael Walsh    ffdc_list_file.write(printable_ffdc_file_list + "\n")
637b2e53ecdSMichael Walsh    ffdc_list_file.close()
638b2e53ecdSMichael Walsh
639b2e53ecdSMichael Walsh    indent = 0
640b2e53ecdSMichael Walsh    width = 90
641b2e53ecdSMichael Walsh    linefeed = 1
642b2e53ecdSMichael Walsh    char = "="
64368a61162SMichael Walsh
64468a61162SMichael Walsh    gp.qprintn()
645b2e53ecdSMichael Walsh    gp.qprint_dashes(indent, width, linefeed, char)
64668a61162SMichael Walsh    gp.qprintn("Copy this data to the defect:\n")
64768a61162SMichael Walsh
648e0cf8d70SMichael Walsh    if len(more_header_info) > 0:
649ff340006SMichael Walsh        gp.qprintn(more_header_info)
650dc80d67dSMichael Walsh    gp.qpvars(host_name, host_ip, openbmc_nickname, openbmc_host,
651dc80d67dSMichael Walsh              openbmc_host_name, openbmc_ip, openbmc_username,
652dc80d67dSMichael Walsh              openbmc_password, os_host, os_host_name, os_ip, os_username,
653dc80d67dSMichael Walsh              os_password, pdu_host, pdu_host_name, pdu_ip, pdu_username,
654dc80d67dSMichael Walsh              pdu_password, pdu_slot_no, openbmc_serial_host,
655dc80d67dSMichael Walsh              openbmc_serial_host_name, openbmc_serial_ip, openbmc_serial_port)
65668a61162SMichael Walsh
65768a61162SMichael Walsh    gp.qprintn()
65868a61162SMichael Walsh    print_last_boots()
65968a61162SMichael Walsh    gp.qprintn()
66068a61162SMichael Walsh    gp.qprint_var(state)
661b5839d00SMichael Walsh    gp.qprintn()
662b5839d00SMichael Walsh    gp.qprintn("FFDC data files:")
663b2e53ecdSMichael Walsh    gp.qprintn(printable_ffdc_file_list)
664b5839d00SMichael Walsh    gp.qprintn()
665341c21ebSMichael Walsh
666600876daSMichael Walsh    if len(ffdc_summary_info) > 0:
667ff340006SMichael Walsh        gp.qprintn(ffdc_summary_info)
668600876daSMichael Walsh
669b2e53ecdSMichael Walsh    gp.qprint_dashes(indent, width, linefeed, char)
67068a61162SMichael Walsh
6716741f740SMichael Walsh
6726741f740SMichael Walshdef my_ffdc():
6736741f740SMichael Walsh    r"""
6746741f740SMichael Walsh    Collect FFDC data.
6756741f740SMichael Walsh    """
6766741f740SMichael Walsh
6776741f740SMichael Walsh    global state
6786741f740SMichael Walsh
6796741f740SMichael Walsh    plug_in_setup()
6806741f740SMichael Walsh    rc, shell_rc, failed_plug_in_name = grpi.rprocess_plug_in_packages(
681600876daSMichael Walsh        call_point='ffdc', stop_on_plug_in_failure=0)
6826741f740SMichael Walsh
6836741f740SMichael Walsh    AUTOBOOT_FFDC_PREFIX = os.environ['AUTOBOOT_FFDC_PREFIX']
684b2e53ecdSMichael Walsh    status, ffdc_file_list = grk.run_key_u("FFDC  ffdc_prefix=" +
68583f4bc77SMichael Walsh                                           AUTOBOOT_FFDC_PREFIX +
68683f4bc77SMichael Walsh                                           "  ffdc_function_list=" +
68783f4bc77SMichael Walsh                                           ffdc_function_list, ignore=1)
68883f4bc77SMichael Walsh    if status != 'PASS':
689ff340006SMichael Walsh        gp.qprint_error("Call to ffdc failed.\n")
6906741f740SMichael Walsh
6916741f740SMichael Walsh    my_get_state()
6926741f740SMichael Walsh
693b2e53ecdSMichael Walsh    print_defect_report(ffdc_file_list)
6946741f740SMichael Walsh
6956741f740SMichael Walsh
6966741f740SMichael Walshdef print_test_start_message(boot_keyword):
6976741f740SMichael Walsh    r"""
6986741f740SMichael Walsh    Print a message indicating what boot test is about to run.
6996741f740SMichael Walsh
7006741f740SMichael Walsh    Description of arguments:
7016741f740SMichael Walsh    boot_keyword  The name of the boot which is to be run
7026741f740SMichael Walsh                  (e.g. "BMC Power On").
7036741f740SMichael Walsh    """
7046741f740SMichael Walsh
7056741f740SMichael Walsh    global last_ten
706325eb548SSunil M    global boot_start_time
7076741f740SMichael Walsh
7086741f740SMichael Walsh    doing_msg = gp.sprint_timen("Doing \"" + boot_keyword + "\".")
709325eb548SSunil M
710325eb548SSunil M    # Set boot_start_time for use by plug-ins.
711325eb548SSunil M    boot_start_time = doing_msg[1:33]
712325eb548SSunil M    gp.qprint_var(boot_start_time)
713325eb548SSunil M
714b5839d00SMichael Walsh    gp.qprint(doing_msg)
7156741f740SMichael Walsh
7166741f740SMichael Walsh    last_ten.append(doing_msg)
7176741f740SMichael Walsh
7186741f740SMichael Walsh    if len(last_ten) > 10:
7196741f740SMichael Walsh        del last_ten[0]
7206741f740SMichael Walsh
7216741f740SMichael Walsh
7226741f740SMichael Walshdef run_boot(boot):
7236741f740SMichael Walsh    r"""
7246741f740SMichael Walsh    Run the specified boot.
7256741f740SMichael Walsh
7266741f740SMichael Walsh    Description of arguments:
7276741f740SMichael Walsh    boot  The name of the boot test to be performed.
7286741f740SMichael Walsh    """
7296741f740SMichael Walsh
7306741f740SMichael Walsh    global state
7316741f740SMichael Walsh
7326741f740SMichael Walsh    print_test_start_message(boot)
7336741f740SMichael Walsh
7346741f740SMichael Walsh    plug_in_setup()
7356741f740SMichael Walsh    rc, shell_rc, failed_plug_in_name = \
7366741f740SMichael Walsh        grpi.rprocess_plug_in_packages(call_point="pre_boot")
7376741f740SMichael Walsh    if rc != 0:
7386741f740SMichael Walsh        error_message = "Plug-in failed with non-zero return code.\n" +\
7396741f740SMichael Walsh            gp.sprint_var(rc, 1)
7406741f740SMichael Walsh        BuiltIn().fail(gp.sprint_error(error_message))
7416741f740SMichael Walsh
7426741f740SMichael Walsh    if test_mode:
7436741f740SMichael Walsh        # In test mode, we'll pretend the boot worked by assigning its
7446741f740SMichael Walsh        # required end state to the default state value.
74530dadae2SMichael Walsh        state = st.strip_anchor_state(boot_table[boot]['end'])
7466741f740SMichael Walsh    else:
7476741f740SMichael Walsh        # Assertion:  We trust that the state data was made fresh by the
7486741f740SMichael Walsh        # caller.
7496741f740SMichael Walsh
750b5839d00SMichael Walsh        gp.qprintn()
7516741f740SMichael Walsh
7526741f740SMichael Walsh        if boot_table[boot]['method_type'] == "keyword":
7530b93fbf8SMichael Walsh            rk.my_run_keywords(boot_table[boot].get('lib_file_path', ''),
754b5839d00SMichael Walsh                               boot_table[boot]['method'],
755b5839d00SMichael Walsh                               quiet=quiet)
7566741f740SMichael Walsh
7576741f740SMichael Walsh        if boot_table[boot]['bmc_reboot']:
7586741f740SMichael Walsh            st.wait_for_comm_cycle(int(state['epoch_seconds']))
75930dadae2SMichael Walsh            plug_in_setup()
76030dadae2SMichael Walsh            rc, shell_rc, failed_plug_in_name = \
76130dadae2SMichael Walsh                grpi.rprocess_plug_in_packages(call_point="post_reboot")
76230dadae2SMichael Walsh            if rc != 0:
7630b93fbf8SMichael Walsh                error_message = "Plug-in failed with non-zero return code.\n"
7640b93fbf8SMichael Walsh                error_message += gp.sprint_var(rc, 1)
76530dadae2SMichael Walsh                BuiltIn().fail(gp.sprint_error(error_message))
7666741f740SMichael Walsh        else:
7676741f740SMichael Walsh            match_state = st.anchor_state(state)
7686741f740SMichael Walsh            del match_state['epoch_seconds']
7696741f740SMichael Walsh            # Wait for the state to change in any way.
7706741f740SMichael Walsh            st.wait_state(match_state, wait_time=state_change_timeout,
771600876daSMichael Walsh                          interval="10 seconds", invert=1)
7726741f740SMichael Walsh
773b5839d00SMichael Walsh        gp.qprintn()
7746741f740SMichael Walsh        if boot_table[boot]['end']['chassis'] == "Off":
7756741f740SMichael Walsh            boot_timeout = power_off_timeout
7766741f740SMichael Walsh        else:
7776741f740SMichael Walsh            boot_timeout = power_on_timeout
7786741f740SMichael Walsh        st.wait_state(boot_table[boot]['end'], wait_time=boot_timeout,
779600876daSMichael Walsh                      interval="10 seconds")
7806741f740SMichael Walsh
7816741f740SMichael Walsh    plug_in_setup()
7826741f740SMichael Walsh    rc, shell_rc, failed_plug_in_name = \
7836741f740SMichael Walsh        grpi.rprocess_plug_in_packages(call_point="post_boot")
7846741f740SMichael Walsh    if rc != 0:
7856741f740SMichael Walsh        error_message = "Plug-in failed with non-zero return code.\n" +\
7866741f740SMichael Walsh            gp.sprint_var(rc, 1)
7876741f740SMichael Walsh        BuiltIn().fail(gp.sprint_error(error_message))
7886741f740SMichael Walsh
7896741f740SMichael Walsh
7906741f740SMichael Walshdef test_loop_body():
7916741f740SMichael Walsh    r"""
7926741f740SMichael Walsh    The main loop body for the loop in main_py.
7936741f740SMichael Walsh
7946741f740SMichael Walsh    Description of arguments:
7956741f740SMichael Walsh    boot_count  The iteration number (starts at 1).
7966741f740SMichael Walsh    """
7976741f740SMichael Walsh
7986741f740SMichael Walsh    global boot_count
7996741f740SMichael Walsh    global state
8006741f740SMichael Walsh    global next_boot
8016741f740SMichael Walsh    global boot_success
802325eb548SSunil M    global boot_end_time
8036741f740SMichael Walsh
804b5839d00SMichael Walsh    gp.qprintn()
8056741f740SMichael Walsh
8066741f740SMichael Walsh    next_boot = select_boot()
807b5839d00SMichael Walsh    if next_boot == "":
808b5839d00SMichael Walsh        return True
8096741f740SMichael Walsh
810b5839d00SMichael Walsh    boot_count += 1
811b5839d00SMichael Walsh    gp.qprint_timen("Starting boot " + str(boot_count) + ".")
8126741f740SMichael Walsh
813e0cf8d70SMichael Walsh    pre_boot_plug_in_setup()
8146741f740SMichael Walsh
8156741f740SMichael Walsh    cmd_buf = ["run_boot", next_boot]
8166741f740SMichael Walsh    boot_status, msg = BuiltIn().run_keyword_and_ignore_error(*cmd_buf)
8176741f740SMichael Walsh    if boot_status == "FAIL":
818b5839d00SMichael Walsh        gp.qprint(msg)
8196741f740SMichael Walsh
820b5839d00SMichael Walsh    gp.qprintn()
8216741f740SMichael Walsh    if boot_status == "PASS":
8226741f740SMichael Walsh        boot_success = 1
823ff340006SMichael Walsh        completion_msg = gp.sprint_timen("BOOT_SUCCESS: \"" + next_boot +
824325eb548SSunil M                                         "\" succeeded.")
8256741f740SMichael Walsh    else:
8266741f740SMichael Walsh        boot_success = 0
827ff340006SMichael Walsh        completion_msg = gp.sprint_timen("BOOT_FAILED: \"" + next_boot +
828325eb548SSunil M                                         "\" failed.")
829325eb548SSunil M
830325eb548SSunil M    # Set boot_end_time for use by plug-ins.
831325eb548SSunil M    boot_end_time = completion_msg[1:33]
832325eb548SSunil M    gp.qprint_var(boot_end_time)
833325eb548SSunil M
834325eb548SSunil M    gp.qprint(completion_msg)
8356741f740SMichael Walsh
8366741f740SMichael Walsh    boot_results.update(next_boot, boot_status)
8376741f740SMichael Walsh
8386741f740SMichael Walsh    plug_in_setup()
8396741f740SMichael Walsh    # NOTE: A post_test_case call point failure is NOT counted as a boot
8406741f740SMichael Walsh    # failure.
8416741f740SMichael Walsh    rc, shell_rc, failed_plug_in_name = grpi.rprocess_plug_in_packages(
842600876daSMichael Walsh        call_point='post_test_case', stop_on_plug_in_failure=0)
8436741f740SMichael Walsh
8446741f740SMichael Walsh    plug_in_setup()
8456741f740SMichael Walsh    rc, shell_rc, failed_plug_in_name = grpi.rprocess_plug_in_packages(
8466741f740SMichael Walsh        call_point='ffdc_check', shell_rc=0x00000200,
8476741f740SMichael Walsh        stop_on_plug_in_failure=1, stop_on_non_zero_rc=1)
8486741f740SMichael Walsh    if boot_status != "PASS" or ffdc_check == "All" or shell_rc == 0x00000200:
84983f4bc77SMichael Walsh        status, ret_values = grk.run_key_u("my_ffdc", ignore=1)
85083f4bc77SMichael Walsh        if status != 'PASS':
851ff340006SMichael Walsh            gp.qprint_error("Call to my_ffdc failed.\n")
8526741f740SMichael Walsh
853aabef1e3SMichael Walsh    if delete_errlogs:
854d139f286SMichael Walsh        # We need to purge error logs between boots or they build up.
855b5839d00SMichael Walsh        grk.run_key("Delete Error logs", ignore=1)
856d139f286SMichael Walsh
857952f9b09SMichael Walsh    boot_results.print_report()
858b5839d00SMichael Walsh    gp.qprint_timen("Finished boot " + str(boot_count) + ".")
859952f9b09SMichael Walsh
8606741f740SMichael Walsh    plug_in_setup()
8616741f740SMichael Walsh    rc, shell_rc, failed_plug_in_name = grpi.rprocess_plug_in_packages(
862*3ba8ecdcSMichael Walsh        call_point='stop_check', shell_rc=0x00000200, stop_on_non_zero_rc=1)
863*3ba8ecdcSMichael Walsh    if shell_rc == 0x00000200:
864*3ba8ecdcSMichael Walsh        message = "Stopping as requested by user.\n"
865*3ba8ecdcSMichael Walsh        gp.print_time(message)
866*3ba8ecdcSMichael Walsh        BuiltIn().fail(message)
8676741f740SMichael Walsh
868d139f286SMichael Walsh    # This should help prevent ConnectionErrors.
8690960b384SMichael Walsh    grk.run_key_u("Close All Connections")
870d139f286SMichael Walsh
8716741f740SMichael Walsh    return True
8726741f740SMichael Walsh
8736741f740SMichael Walsh
87483f4bc77SMichael Walshdef obmc_boot_test_teardown():
8756741f740SMichael Walsh    r"""
876c9116811SMichael Walsh    Clean up after the Main keyword.
8776741f740SMichael Walsh    """
8786741f740SMichael Walsh
8796741f740SMichael Walsh    if cp_setup_called:
8806741f740SMichael Walsh        plug_in_setup()
8816741f740SMichael Walsh        rc, shell_rc, failed_plug_in_name = grpi.rprocess_plug_in_packages(
882600876daSMichael Walsh            call_point='cleanup', stop_on_plug_in_failure=0)
8836741f740SMichael Walsh
884600876daSMichael Walsh    if 'boot_results_file_path' in globals():
8850b93fbf8SMichael Walsh        # Save boot_results object to a file in case it is needed again.
886b5839d00SMichael Walsh        gp.qprint_timen("Saving boot_results to the following path.")
887b5839d00SMichael Walsh        gp.qprint_var(boot_results_file_path)
8880b93fbf8SMichael Walsh        pickle.dump(boot_results, open(boot_results_file_path, 'wb'),
8890b93fbf8SMichael Walsh                    pickle.HIGHEST_PROTOCOL)
8900b93fbf8SMichael Walsh
891ff340006SMichael Walsh    global save_stack
892ff340006SMichael Walsh    # Restore any global values saved on the save_stack.
893ff340006SMichael Walsh    for parm_name in main_func_parm_list:
894ff340006SMichael Walsh        # Get the parm_value if it was saved on the stack.
895ff340006SMichael Walsh        try:
896ff340006SMichael Walsh            parm_value = save_stack.pop(parm_name)
897ff340006SMichael Walsh        except:
898ff340006SMichael Walsh            # If it was not saved, no further action is required.
899ff340006SMichael Walsh            continue
900ff340006SMichael Walsh
901ff340006SMichael Walsh        # Restore the saved value.
902ff340006SMichael Walsh        cmd_buf = "BuiltIn().set_global_variable(\"${" + parm_name +\
903ff340006SMichael Walsh            "}\", parm_value)"
904ff340006SMichael Walsh        gp.dpissuing(cmd_buf)
905ff340006SMichael Walsh        exec(cmd_buf)
906ff340006SMichael Walsh
907ff340006SMichael Walsh    gp.dprintn(save_stack.sprint_obj())
908ff340006SMichael Walsh
9096741f740SMichael Walsh
910c9116811SMichael Walshdef test_teardown():
911c9116811SMichael Walsh    r"""
912c9116811SMichael Walsh    Clean up after this test case.
913c9116811SMichael Walsh    """
914c9116811SMichael Walsh
915c9116811SMichael Walsh    gp.qprintn()
916c9116811SMichael Walsh    cmd_buf = ["Print Error",
917c9116811SMichael Walsh               "A keyword timeout occurred ending this program.\n"]
918c9116811SMichael Walsh    BuiltIn().run_keyword_if_timeout_occurred(*cmd_buf)
919c9116811SMichael Walsh
920b5839d00SMichael Walsh    grp.rqprint_pgm_footer()
921b5839d00SMichael Walsh
922c9116811SMichael Walsh
923ff340006SMichael Walshdef obmc_boot_test_py(loc_boot_stack=None,
924ff340006SMichael Walsh                      loc_stack_mode=None,
925ff340006SMichael Walsh                      loc_quiet=None):
9266741f740SMichael Walsh    r"""
9276741f740SMichael Walsh    Do main program processing.
9286741f740SMichael Walsh    """
9296741f740SMichael Walsh
930ff340006SMichael Walsh    global save_stack
931ff340006SMichael Walsh
932ff340006SMichael Walsh    # Process function parms.
933ff340006SMichael Walsh    for parm_name in main_func_parm_list:
934ff340006SMichael Walsh        # Get parm's value.
935ff340006SMichael Walsh        cmd_buf = "parm_value = loc_" + parm_name
936ff340006SMichael Walsh        exec(cmd_buf)
937ff340006SMichael Walsh        gp.dpvar(parm_name)
938ff340006SMichael Walsh        gp.dpvar(parm_value)
939ff340006SMichael Walsh
940ff340006SMichael Walsh        if parm_value is None:
941ff340006SMichael Walsh            # Parm was not specified by the calling function so set it to its
942ff340006SMichael Walsh            # corresponding global value.
943ff340006SMichael Walsh            cmd_buf = "loc_" + parm_name + " = BuiltIn().get_variable_value" +\
944ff340006SMichael Walsh                "(\"${" + parm_name + "}\")"
945ff340006SMichael Walsh            gp.dpissuing(cmd_buf)
946ff340006SMichael Walsh            exec(cmd_buf)
947ff340006SMichael Walsh        else:
948ff340006SMichael Walsh            # Save the global value on a stack.
949ff340006SMichael Walsh            cmd_buf = "save_stack.push(BuiltIn().get_variable_value(\"${" +\
950ff340006SMichael Walsh                parm_name + "}\"), \"" + parm_name + "\")"
951ff340006SMichael Walsh            gp.dpissuing(cmd_buf)
952ff340006SMichael Walsh            exec(cmd_buf)
953ff340006SMichael Walsh
954ff340006SMichael Walsh            # Set the global value to the passed value.
955ff340006SMichael Walsh            cmd_buf = "BuiltIn().set_global_variable(\"${" + parm_name +\
956ff340006SMichael Walsh                "}\", loc_" + parm_name + ")"
957ff340006SMichael Walsh            gp.dpissuing(cmd_buf)
958ff340006SMichael Walsh            exec(cmd_buf)
959ff340006SMichael Walsh
960ff340006SMichael Walsh    gp.dprintn(save_stack.sprint_obj())
961b5839d00SMichael Walsh
9626741f740SMichael Walsh    setup()
9636741f740SMichael Walsh
964cd9fbfd7SMichael Walsh    init_boot_pass, init_boot_fail = boot_results.return_total_pass_fail()
965cd9fbfd7SMichael Walsh
966a20da401SMichael Walsh    if ffdc_only:
967a20da401SMichael Walsh        gp.qprint_timen("Caller requested ffdc_only.")
968e0cf8d70SMichael Walsh        pre_boot_plug_in_setup()
96983f4bc77SMichael Walsh        grk.run_key_u("my_ffdc")
970764d2f83SMichael Walsh        return
971a20da401SMichael Walsh
9726741f740SMichael Walsh    # Process caller's boot_stack.
9736741f740SMichael Walsh    while (len(boot_stack) > 0):
9746741f740SMichael Walsh        test_loop_body()
9756741f740SMichael Walsh
976b5839d00SMichael Walsh    gp.qprint_timen("Finished processing stack.")
97730dadae2SMichael Walsh
9786741f740SMichael Walsh    # Process caller's boot_list.
9796741f740SMichael Walsh    if len(boot_list) > 0:
9806741f740SMichael Walsh        for ix in range(1, max_num_tests + 1):
9816741f740SMichael Walsh            test_loop_body()
9826741f740SMichael Walsh
983b5839d00SMichael Walsh    gp.qprint_timen("Completed all requested boot tests.")
984b5839d00SMichael Walsh
985b5839d00SMichael Walsh    boot_pass, boot_fail = boot_results.return_total_pass_fail()
986cd9fbfd7SMichael Walsh    new_fail = boot_fail - init_boot_fail
987cd9fbfd7SMichael Walsh    if new_fail > boot_fail_threshold:
988b5839d00SMichael Walsh        error_message = "Boot failures exceed the boot failure" +\
989b5839d00SMichael Walsh                        " threshold:\n" +\
990cd9fbfd7SMichael Walsh                        gp.sprint_var(new_fail) +\
991b5839d00SMichael Walsh                        gp.sprint_var(boot_fail_threshold)
992b5839d00SMichael Walsh        BuiltIn().fail(gp.sprint_error(error_message))
993