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
70bbd860fSMichael Walshfrom tally_sheet import *
80bbd860fSMichael Walshimport gen_robot_print as grp
955302295SMichael Walshimport gen_robot_plug_in as grpi
1055302295SMichael Walshimport state as st
110bbd860fSMichael Walsh
120bbd860fSMichael Walshimport os
130bbd860fSMichael Walshimport time
140bbd860fSMichael Walshimport subprocess
15*341c21ebSMichael Walshimport glob
160bbd860fSMichael Walsh
170bbd860fSMichael Walshfrom robot.utils import DotDict
180bbd860fSMichael Walshfrom robot.libraries.BuiltIn import BuiltIn
190bbd860fSMichael Walshfrom robot.libraries.OperatingSystem import OperatingSystem
200bbd860fSMichael Walsh
210bbd860fSMichael Walsh# Create boot_results_fields for use in creating boot_results.
220bbd860fSMichael Walshboot_results_fields = DotDict([('total', 0), ('pass', 0), ('fail', 0)])
230bbd860fSMichael Walsh# Create boot_results which is global to this module.
240bbd860fSMichael Walshboot_results = tally_sheet('boot type',
250bbd860fSMichael Walsh                           boot_results_fields,
260bbd860fSMichael Walsh                           'boot_test_results')
270bbd860fSMichael Walsh
280bbd860fSMichael Walshboot_results.set_sum_fields(['total', 'pass', 'fail'])
290bbd860fSMichael Walshboot_results.set_calc_fields(['total=pass+fail'])
300bbd860fSMichael Walsh
310bbd860fSMichael Walsh
320bbd860fSMichael Walsh###############################################################################
330bbd860fSMichael Walshdef plug_in_setup():
340bbd860fSMichael Walsh
350bbd860fSMichael Walsh    r"""
360bbd860fSMichael Walsh    Initialize all plug-in environment variables for use by the plug-in
370bbd860fSMichael Walsh    programs.
380bbd860fSMichael Walsh    """
390bbd860fSMichael Walsh
400bbd860fSMichael Walsh    boot_pass = int(BuiltIn().get_variable_value("${boot_pass}"))
410bbd860fSMichael Walsh    if boot_pass > 1:
420bbd860fSMichael Walsh        test_really_running = 1
430bbd860fSMichael Walsh    else:
440bbd860fSMichael Walsh        test_really_running = 0
450bbd860fSMichael Walsh
460bbd860fSMichael Walsh    BuiltIn().set_global_variable("${test_really_running}",
470bbd860fSMichael Walsh                                  test_really_running)
480bbd860fSMichael Walsh
490bbd860fSMichael Walsh    next_boot = BuiltIn().get_variable_value("${next_boot}")
500bbd860fSMichael Walsh    BuiltIn().set_global_variable("${boot_type_desc}", next_boot)
510bbd860fSMichael Walsh
520bbd860fSMichael Walsh    # Setting master_pid correctly influences the behavior of plug-ins like
530bbd860fSMichael Walsh    # DB_Logging
540bbd860fSMichael Walsh    program_pid = BuiltIn().get_variable_value("${program_pid}")
550bbd860fSMichael Walsh    try:
560bbd860fSMichael Walsh        master_pid = OperatingSystem().get_environment_variable(
570bbd860fSMichael Walsh            "AUTOBOOT_MASTER_PID")
580bbd860fSMichael Walsh    except RuntimeError:
590bbd860fSMichael Walsh        master_pid = program_pid
600bbd860fSMichael Walsh    if master_pid == "":
610bbd860fSMichael Walsh        master_pid = program_pid
620bbd860fSMichael Walsh
630bbd860fSMichael Walsh    BuiltIn().set_global_variable("${master_pid}", master_pid)
640bbd860fSMichael Walsh
650bbd860fSMichael Walsh    seconds = time.time()
660bbd860fSMichael Walsh    loc_time = time.localtime(seconds)
670bbd860fSMichael Walsh    time_string = time.strftime("%y%m%d.%H%M%S.", loc_time)
680bbd860fSMichael Walsh
690bbd860fSMichael Walsh    openbmc_nickname = BuiltIn().get_variable_value("${openbmc_nickname}")
700bbd860fSMichael Walsh    openbmc_host = BuiltIn().get_variable_value("${openbmc_host}")
71769c2a1bSMichael Walsh    if openbmc_nickname == "":
7255302295SMichael Walsh        openbmc_nickname = openbmc_host
730bbd860fSMichael Walsh    ffdc_prefix = openbmc_nickname
740bbd860fSMichael Walsh
750bbd860fSMichael Walsh    ffdc_prefix += "." + time_string
760bbd860fSMichael Walsh
7786de0d2eSMichael Walsh    try:
7886de0d2eSMichael Walsh        ffdc_dir_path = os.environ['FFDC_DIR_PATH']
790bbd860fSMichael Walsh        # Add trailing slash.
800bbd860fSMichael Walsh        ffdc_dir_path = os.path.normpath(ffdc_dir_path) + os.sep
8186de0d2eSMichael Walsh    except KeyError:
8286de0d2eSMichael Walsh        ffdc_dir_path = ""
830bbd860fSMichael Walsh    BuiltIn().set_global_variable("${FFDC_DIR_PATH}", ffdc_dir_path)
840bbd860fSMichael Walsh
8555302295SMichael Walsh    status_dir_path = os.environ.get('STATUS_DIR_PATH', "")
8655302295SMichael Walsh    if status_dir_path != "":
8755302295SMichael Walsh        # Add trailing slash.
8855302295SMichael Walsh        status_dir_path = os.path.normpath(status_dir_path) + os.sep
8955302295SMichael Walsh    BuiltIn().set_global_variable("${STATUS_DIR_PATH}", status_dir_path)
9055302295SMichael Walsh
9155302295SMichael Walsh    base_tool_dir_path = os.environ.get('AUTOBOOT_BASE_TOOL_DIR_PATH', "/tmp")
924c9a6453SMichael Walsh    base_tool_dir_path = os.path.normpath(base_tool_dir_path) + os.sep
934c9a6453SMichael Walsh    BuiltIn().set_global_variable("${BASE_TOOL_DIR_PATH}", base_tool_dir_path)
944c9a6453SMichael Walsh
9555302295SMichael Walsh    ffdc_list_file_path = base_tool_dir_path + openbmc_nickname +\
9655302295SMichael Walsh        "/FFDC_FILE_LIST"
974c9a6453SMichael Walsh
984c9a6453SMichael Walsh    BuiltIn().set_global_variable("${FFDC_LIST_FILE_PATH}",
994c9a6453SMichael Walsh                                  ffdc_list_file_path)
1004c9a6453SMichael Walsh
1010bbd860fSMichael Walsh    # For each program parameter, set the corresponding AUTOBOOT_ environment
1020bbd860fSMichael Walsh    # variable value.  Also, set an AUTOBOOT_ environment variable for every
1030bbd860fSMichael Walsh    # element in additional_values.
1040bbd860fSMichael Walsh    additional_values = ["boot_type_desc", "boot_success", "boot_pass",
1050bbd860fSMichael Walsh                         "boot_fail", "test_really_running", "program_pid",
1064c9a6453SMichael Walsh                         "master_pid", "ffdc_prefix", "ffdc_dir_path",
10755302295SMichael Walsh                         "status_dir_path", "base_tool_dir_path",
10855302295SMichael Walsh                         "ffdc_list_file_path"]
1090bbd860fSMichael Walsh    BuiltIn().set_global_variable("${ffdc_prefix}", ffdc_prefix)
1100bbd860fSMichael Walsh
1110bbd860fSMichael Walsh    parm_list = BuiltIn().get_variable_value("@{parm_list}")
1120bbd860fSMichael Walsh
1130bbd860fSMichael Walsh    plug_in_vars = parm_list + additional_values
1140bbd860fSMichael Walsh
1150bbd860fSMichael Walsh    for var_name in plug_in_vars:
1160bbd860fSMichael Walsh        var_value = BuiltIn().get_variable_value("${" + var_name + "}")
1170bbd860fSMichael Walsh        var_name = var_name.upper()
1180bbd860fSMichael Walsh        if var_value is None:
1190bbd860fSMichael Walsh            var_value = ""
1200bbd860fSMichael Walsh        OperatingSystem().set_environment_variable(
1210bbd860fSMichael Walsh            "AUTOBOOT_" + var_name, var_value)
1220bbd860fSMichael Walsh
1230bbd860fSMichael Walsh    debug = int(BuiltIn().get_variable_value("${debug}"))
1240bbd860fSMichael Walsh    if debug:
1250bbd860fSMichael Walsh        cmd_buf = "printenv | egrep AUTOBOOT_ | sort -u"
1260bbd860fSMichael Walsh        grp.rpissuing(cmd_buf)
1270bbd860fSMichael Walsh        sub_proc = subprocess.Popen(cmd_buf, shell=True,
1280bbd860fSMichael Walsh                                    stdout=subprocess.PIPE,
1290bbd860fSMichael Walsh                                    stderr=subprocess.STDOUT)
1300bbd860fSMichael Walsh        out_buf, err_buf = sub_proc.communicate()
1310bbd860fSMichael Walsh        shell_rc = sub_proc.returncode
1320bbd860fSMichael Walsh        grp.rprint(out_buf)
1330bbd860fSMichael Walsh
1340bbd860fSMichael Walsh###############################################################################
1350bbd860fSMichael Walsh
1360bbd860fSMichael Walsh
1370bbd860fSMichael Walsh###############################################################################
1380bbd860fSMichael Walshdef create_boot_results_table():
1390bbd860fSMichael Walsh
1400bbd860fSMichael Walsh    r"""
1410bbd860fSMichael Walsh    Create our boot_results_table.
1420bbd860fSMichael Walsh    """
1430bbd860fSMichael Walsh
1440bbd860fSMichael Walsh    # At some point we'll want to change to reading in our boot types from
1450bbd860fSMichael Walsh    # some external source (e.g. file).
1460bbd860fSMichael Walsh
1470bbd860fSMichael Walsh    boot_results.add_row('BMC Power On')
1480bbd860fSMichael Walsh    boot_results.add_row('BMC Power Off')
1490bbd860fSMichael Walsh
1500bbd860fSMichael Walsh###############################################################################
1510bbd860fSMichael Walsh
1520bbd860fSMichael Walsh
1530bbd860fSMichael Walsh###############################################################################
1540bbd860fSMichael Walshdef update_boot_results_table(boot_type,
1550bbd860fSMichael Walsh                              boot_status):
1560bbd860fSMichael Walsh
1570bbd860fSMichael Walsh    r"""
1580bbd860fSMichael Walsh    Update our boot_results_table.  This includes:
1590bbd860fSMichael Walsh    - Updating the record for the given boot_type by incrementing the pass or
1600bbd860fSMichael Walsh      fail field.
1610bbd860fSMichael Walsh    - Calling the calc method to have the totals, etc. calculated.
1620bbd860fSMichael Walsh    - Updating global variables boot_pass/boot_fail.
1630bbd860fSMichael Walsh
1640bbd860fSMichael Walsh    Description of arguments:
1650bbd860fSMichael Walsh    boot_type    The type of boot just done (e.g. "BMC Power On").
1660bbd860fSMichael Walsh    boot_status  The status of the boot just done.  This should be equal to
1670bbd860fSMichael Walsh                 either "pass" or "fail" (case-insensitive).
1680bbd860fSMichael Walsh    """
1690bbd860fSMichael Walsh
1700bbd860fSMichael Walsh    boot_results.inc_row_field(boot_type, boot_status.lower())
1710bbd860fSMichael Walsh    totals_line = boot_results.calc()
1720bbd860fSMichael Walsh
1730bbd860fSMichael Walsh    # The caller of obmc_boot_test can pass boot_pass/boot_fail values because
1740bbd860fSMichael Walsh    # the caller may have already done some testing (e.g. "BMC OOB").  For the
1750bbd860fSMichael Walsh    # sake of DB logging done by plug-ins, we want to include these in our
1760bbd860fSMichael Walsh    # overall totals.
1770bbd860fSMichael Walsh    initial_boot_pass = int(BuiltIn().get_variable_value(
1780bbd860fSMichael Walsh        "${initial_boot_pass}"))
1790bbd860fSMichael Walsh    initial_boot_fail = int(BuiltIn().get_variable_value(
1800bbd860fSMichael Walsh        "${initial_boot_fail}"))
1810bbd860fSMichael Walsh
1820bbd860fSMichael Walsh    BuiltIn().set_global_variable("${boot_pass}",
1830bbd860fSMichael Walsh                                  totals_line['pass'] + initial_boot_pass)
1840bbd860fSMichael Walsh    BuiltIn().set_global_variable("${boot_fail}",
1850bbd860fSMichael Walsh                                  totals_line['fail'] + initial_boot_fail)
1860bbd860fSMichael Walsh
1870bbd860fSMichael Walsh###############################################################################
1880bbd860fSMichael Walsh
1890bbd860fSMichael Walsh
1900bbd860fSMichael Walsh###############################################################################
1910bbd860fSMichael Walshdef print_boot_results_table(header_footer="\n"):
1920bbd860fSMichael Walsh
1930bbd860fSMichael Walsh    r"""
1940bbd860fSMichael Walsh    Print the formatted boot_resuls_table to the console.
1950bbd860fSMichael Walsh    """
1960bbd860fSMichael Walsh
197*341c21ebSMichael Walsh    grp.rqprint(header_footer)
198*341c21ebSMichael Walsh    grp.rqprint(boot_results.sprint_report())
199*341c21ebSMichael Walsh    grp.rqprint(header_footer)
200*341c21ebSMichael Walsh
201*341c21ebSMichael Walsh###############################################################################
202*341c21ebSMichael Walsh
203*341c21ebSMichael Walsh
204*341c21ebSMichael Walsh###############################################################################
205*341c21ebSMichael Walshdef select_boot(state):
206*341c21ebSMichael Walsh
207*341c21ebSMichael Walsh    r"""
208*341c21ebSMichael Walsh    Select a boot test to be run based on our current state and return the
209*341c21ebSMichael Walsh    chosen boot type.
210*341c21ebSMichael Walsh
211*341c21ebSMichael Walsh    Description of arguments:
212*341c21ebSMichael Walsh    state  The state of the machine, which will include the power state..
213*341c21ebSMichael Walsh    """
214*341c21ebSMichael Walsh
215*341c21ebSMichael Walsh    if 'chassis' in state:
216*341c21ebSMichael Walsh        # New style state.
217*341c21ebSMichael Walsh        if state['chassis'] == 'Off':
218*341c21ebSMichael Walsh            boot = 'BMC Power On'
219*341c21ebSMichael Walsh        else:
220*341c21ebSMichael Walsh            boot = 'BMC Power Off'
221*341c21ebSMichael Walsh    else:
222*341c21ebSMichael Walsh        # Old style state.
223*341c21ebSMichael Walsh        if state['power'] == 0:
224*341c21ebSMichael Walsh            boot = 'BMC Power On'
225*341c21ebSMichael Walsh        else:
226*341c21ebSMichael Walsh            boot = 'BMC Power Off'
227*341c21ebSMichael Walsh
228*341c21ebSMichael Walsh    return boot
2290bbd860fSMichael Walsh
2300bbd860fSMichael Walsh###############################################################################
23155302295SMichael Walsh
23255302295SMichael Walsh
23355302295SMichael Walsh###############################################################################
23455302295SMichael Walshdef my_ffdc():
23555302295SMichael Walsh
23655302295SMichael Walsh    r"""
23755302295SMichael Walsh    Collect FFDC data.
23855302295SMichael Walsh    """
23955302295SMichael Walsh
24055302295SMichael Walsh    plug_in_setup()
24155302295SMichael Walsh    rc, shell_rc, failed_plug_in_name = grpi.rprocess_plug_in_packages(
24255302295SMichael Walsh        call_point='ffdc', stop_on_plug_in_failure=1)
24355302295SMichael Walsh
24455302295SMichael Walsh    AUTOBOOT_FFDC_PREFIX = os.environ['AUTOBOOT_FFDC_PREFIX']
24555302295SMichael Walsh
24655302295SMichael Walsh    # FFDC_LOG_PATH is used by "FFDC" keyword.
24755302295SMichael Walsh    FFDC_DIR_PATH = BuiltIn().get_variable_value("${FFDC_DIR_PATH}")
24855302295SMichael Walsh    BuiltIn().set_global_variable("${FFDC_LOG_PATH}",
24955302295SMichael Walsh                                  FFDC_DIR_PATH)
25055302295SMichael Walsh
25155302295SMichael Walsh    cmd_buf = ["FFDC", "ffdc_prefix=" + AUTOBOOT_FFDC_PREFIX]
25255302295SMichael Walsh    grp.rpissuing_keyword(cmd_buf)
25355302295SMichael Walsh    BuiltIn().run_keyword(*cmd_buf)
25455302295SMichael Walsh
25555302295SMichael Walsh    state = st.get_state()
25655302295SMichael Walsh    BuiltIn().set_global_variable("${state}",
25755302295SMichael Walsh                                  state)
25855302295SMichael Walsh
25955302295SMichael Walsh    cmd_buf = ["Print Defect Report"]
26055302295SMichael Walsh    grp.rpissuing_keyword(cmd_buf)
26155302295SMichael Walsh    BuiltIn().run_keyword(*cmd_buf)
26255302295SMichael Walsh
26355302295SMichael Walsh###############################################################################
264*341c21ebSMichael Walsh
265*341c21ebSMichael Walsh
266*341c21ebSMichael Walsh###############################################################################
267*341c21ebSMichael Walshdef print_last_boots():
268*341c21ebSMichael Walsh
269*341c21ebSMichael Walsh    r"""
270*341c21ebSMichael Walsh    Print the last ten boots done with their time stamps.
271*341c21ebSMichael Walsh    """
272*341c21ebSMichael Walsh
273*341c21ebSMichael Walsh    # indent 0, 90 chars wide, linefeed, char is "="
274*341c21ebSMichael Walsh    grp.rqprint_dashes(0, 90)
275*341c21ebSMichael Walsh    grp.rqprintn("Last 10 boots:\n")
276*341c21ebSMichael Walsh    last_ten = BuiltIn().get_variable_value("${LAST_TEN}")
277*341c21ebSMichael Walsh
278*341c21ebSMichael Walsh    for boot_entry in last_ten:
279*341c21ebSMichael Walsh        grp.rqprint(boot_entry)
280*341c21ebSMichael Walsh    grp.rqprint_dashes(0, 90)
281*341c21ebSMichael Walsh
282*341c21ebSMichael Walsh###############################################################################
283*341c21ebSMichael Walsh
284*341c21ebSMichael Walsh
285*341c21ebSMichael Walsh###############################################################################
286*341c21ebSMichael Walshdef print_test_start_message(boot_keyword):
287*341c21ebSMichael Walsh
288*341c21ebSMichael Walsh    r"""
289*341c21ebSMichael Walsh    Print a message indicating what boot test is about to run.
290*341c21ebSMichael Walsh
291*341c21ebSMichael Walsh    Description of arguments:
292*341c21ebSMichael Walsh    boot_keyword  The name of the boot which is to be run
293*341c21ebSMichael Walsh                  (e.g. "BMC Power On").
294*341c21ebSMichael Walsh    """
295*341c21ebSMichael Walsh
296*341c21ebSMichael Walsh    doing_msg = gp.sprint_timen("Doing \"" + boot_keyword + "\".")
297*341c21ebSMichael Walsh    grp.rqprint(doing_msg)
298*341c21ebSMichael Walsh
299*341c21ebSMichael Walsh    last_ten = BuiltIn().get_variable_value("${LAST_TEN}")
300*341c21ebSMichael Walsh    last_ten.append(doing_msg)
301*341c21ebSMichael Walsh
302*341c21ebSMichael Walsh    if len(last_ten) > 10:
303*341c21ebSMichael Walsh        del last_ten[0]
304*341c21ebSMichael Walsh
305*341c21ebSMichael Walsh###############################################################################
306*341c21ebSMichael Walsh
307*341c21ebSMichael Walsh
308*341c21ebSMichael Walsh###############################################################################
309*341c21ebSMichael Walshdef print_defect_report():
310*341c21ebSMichael Walsh
311*341c21ebSMichael Walsh    r"""
312*341c21ebSMichael Walsh    Print a defect report.
313*341c21ebSMichael Walsh    """
314*341c21ebSMichael Walsh
315*341c21ebSMichael Walsh    grp.rqprintn()
316*341c21ebSMichael Walsh    # indent=0, width=90, linefeed=1, char="="
317*341c21ebSMichael Walsh    grp.rqprint_dashes(0, 90, 1, "=")
318*341c21ebSMichael Walsh    grp.rqprintn("Copy this data to the defect:\n")
319*341c21ebSMichael Walsh
320*341c21ebSMichael Walsh    parm_list = BuiltIn().get_variable_value("${parm_list}")
321*341c21ebSMichael Walsh
322*341c21ebSMichael Walsh    grp.rqpvars(*parm_list)
323*341c21ebSMichael Walsh
324*341c21ebSMichael Walsh    grp.rqprintn()
325*341c21ebSMichael Walsh
326*341c21ebSMichael Walsh    print_last_boots()
327*341c21ebSMichael Walsh    grp.rqprintn()
328*341c21ebSMichael Walsh    state = BuiltIn().get_variable_value("${state}")
329*341c21ebSMichael Walsh    grp.rqpvar(state)
330*341c21ebSMichael Walsh
331*341c21ebSMichael Walsh    # At some point I'd like to have the 'Call FFDC Methods' return a list
332*341c21ebSMichael Walsh    # of files it has collected.  In that case, the following "ls" command
333*341c21ebSMichael Walsh    # would no longer be needed.  For now, however, glob shows the files
334*341c21ebSMichael Walsh    # named in FFDC_LIST_FILE_PATH so I will refrain from printing those
335*341c21ebSMichael Walsh    # out (so we don't see duplicates in the list).
336*341c21ebSMichael Walsh
337*341c21ebSMichael Walsh    LOG_PREFIX = BuiltIn().get_variable_value("${LOG_PREFIX}")
338*341c21ebSMichael Walsh
339*341c21ebSMichael Walsh    output = '\n'.join(glob.glob(LOG_PREFIX + '*'))
340*341c21ebSMichael Walsh
341*341c21ebSMichael Walsh    FFDC_LIST_FILE_PATH = \
342*341c21ebSMichael Walsh        BuiltIn().get_variable_value("${FFDC_LIST_FILE_PATH}")
343*341c21ebSMichael Walsh
344*341c21ebSMichael Walsh    try:
345*341c21ebSMichael Walsh        ffdc_list = open(FFDC_LIST_FILE_PATH, 'r')
346*341c21ebSMichael Walsh    except IOError:
347*341c21ebSMichael Walsh        ffdc_list = ""
348*341c21ebSMichael Walsh
349*341c21ebSMichael Walsh    status_file_path = BuiltIn().get_variable_value("${status_file_path}")
350*341c21ebSMichael Walsh
351*341c21ebSMichael Walsh    grp.rqprintn()
352*341c21ebSMichael Walsh    grp.rqprintn("FFDC data files:")
353*341c21ebSMichael Walsh    if status_file_path != "":
354*341c21ebSMichael Walsh        grp.rqprintn(status_file_path)
355*341c21ebSMichael Walsh
356*341c21ebSMichael Walsh    grp.rqprintn(output)
357*341c21ebSMichael Walsh    # grp.rqprintn(ffdc_list)
358*341c21ebSMichael Walsh    grp.rqprintn()
359*341c21ebSMichael Walsh
360*341c21ebSMichael Walsh    grp.rqprint_dashes(0, 90, 1, "=")
361*341c21ebSMichael Walsh
362*341c21ebSMichael Walsh###############################################################################
363