New stop plug-in

A means of controlling when OBMC Boot Test stops.

Also, added additional plug-in support.

Change-Id: I77051805451ecf4431b79b54b090860ac858ec0b
Signed-off-by: Michael Walsh <micwalsh@us.ibm.com>
diff --git a/bin/plug_ins/Stop/cp_stop_check b/bin/plug_ins/Stop/cp_stop_check
new file mode 100755
index 0000000..471be4e
--- /dev/null
+++ b/bin/plug_ins/Stop/cp_stop_check
@@ -0,0 +1,199 @@
+#!/usr/bin/env python
+
+r"""
+Check for stop conditions.  Return code of 2 if stop conditions are found.
+"""
+
+import sys
+import subprocess
+
+save_path_0 = sys.path[0]
+del sys.path[0]
+
+from gen_print import *
+from gen_valid import *
+from gen_arg import *
+from gen_misc import *
+from gen_cmd import *
+from gen_plug_in_utils import *
+from gen_call_robot import *
+
+# Restore sys.path[0].
+sys.path.insert(0, save_path_0)
+
+# Initialize.
+STOP_REST_FAIL = ''
+STOP_COMMAND = ''
+stop_test_rc = 2
+
+# Create parser object to process command line parameters and args.
+
+# Create parser object.
+parser = argparse.ArgumentParser(
+    usage='%(prog)s [OPTIONS]',
+    description="If the \"Stop\" plug-in is selected by the user, %(prog)s" +
+    " is called by OBMC Boot Test after each boot test.  If %(prog)s returns" +
+    " " + str(stop_test_rc) + ", then OBMC Boot Test will stop.  The user" +
+    " may set environment variable STOP_COMMAND to contain any valid bash" +
+    " command or program.  %(prog)s will run this stop command.  If the stop" +
+    " command returns non-zero, then %(prog)s will return " +
+    str(stop_test_rc) + ".  %(prog)s recognizes some special values for" +
+    " STOP_COMMAND: 1) \"FAIL\" means that OBMC Boot Test should stop" +
+    " whenever a boot test fails. 2) \"ALL\" means that OBMC Boot Test" +
+    " should stop after any boot test.  If environment variable" +
+    " STOP_REST_FAIL is set, OBMC Boot Test will stop if REST commands are" +
+    " no longer working.",
+    formatter_class=argparse.RawTextHelpFormatter,
+    prefix_chars='-+')
+
+# The stock_list will be passed to gen_get_options.  We populate it with the
+# names of stock parm options we want.  These stock parms are pre-defined by
+# gen_get_options.
+stock_list = [("test_mode", 0),
+              ("quiet", get_plug_default("quiet", 0)),
+              ("debug", get_plug_default("debug", 0))]
+
+
+def exit_function(signal_number=0,
+                  frame=None):
+
+    r"""
+    Execute whenever the program ends normally or with the signals that we
+    catch (i.e. TERM, INT).
+    """
+
+    dprint_executing()
+    dprint_var(signal_number)
+
+    qprint_pgm_footer()
+
+
+def signal_handler(signal_number,
+                   frame):
+
+    r"""
+    Handle signals.  Without a function to catch a SIGTERM or SIGINT, our
+    program would terminate immediately with return code 143 and without
+    calling our exit_function.
+    """
+
+    # Our convention is to set up exit_function with atexit.register() so
+    # there is no need to explicitly call exit_function from here.
+
+    dprint_executing()
+
+    # Calling exit prevents us from returning to the code that was running
+    # when we received the signal.
+    exit(0)
+
+
+def validate_parms():
+
+    r"""
+    Validate program parameters, etc.  Return True or False (i.e. pass/fail)
+    accordingly.
+    """
+
+    get_plug_vars()
+
+    if not valid_value(AUTOBOOT_OPENBMC_HOST, ["", None]):
+        return False
+
+    gen_post_validation(exit_function, signal_handler)
+
+    return True
+
+
+def rest_fail():
+
+    r"""
+    If STOP_REST_FAIL, then this function will determine whether REST commands
+    to the target are working.  If not, this function will stop the program by
+    returning stop_test_rc.
+    """
+
+    if STOP_REST_FAIL != '1':
+        return
+
+    print_timen("Checking to see whether REST commands are working.")
+    init_robot_out_parms(get_plug_in_package_name() + ".")
+    lib_file_path = init_robot_file_path("lib/state.py")
+    set_mod_global(lib_file_path)
+    timeout = '0 seconds'
+    interval = '1 second'
+    keyword_string = "${match_state}=  Create Dictionary  rest=1 ;" +\
+        " ${state}=  Wait State  ${match_state}  " + timeout + "  " +\
+        interval + "  quiet=${1} ; Rpvar  state"
+    set_mod_global(keyword_string)
+
+    cmd_buf = create_robot_cmd_string("extended/run_keyword.robot",
+                                      OPENBMC_HOST, keyword_string,
+                                      lib_file_path, quiet, test_mode, debug,
+                                      outputdir, output, log, report, loglevel)
+    if not robot_cmd_fnc(cmd_buf):
+        print_timen("The caller wishes to stop test execution if REST" +
+                    " commands are failing.")
+        exit(stop_test_rc)
+    print_timen("REST commands are working so no reason as of yet to stop" +
+                " the test.")
+
+
+def esel_stop_check():
+
+    r"""
+    Run the esel_stop_check program to determine whether any eSEL entries
+    found warrent stopping the test run.  See esel_stop_check help text for
+    details.
+    """
+
+    if STOP_ESEL_STOP_FILE_PATH == "":
+        return
+
+    cmd_buf = "esel_stop_check --esel_stop_file_path=" +\
+        STOP_ESEL_STOP_FILE_PATH
+    shell_rc, out_buf = cmd_fnc_u(cmd_buf, show_err=0)
+    if shell_rc == stop_test_rc:
+        print_timen("The caller wishes to stop test execution based on the" +
+                    " presence of certain esel entries.")
+        exit(stop_test_rc)
+
+
+def main():
+
+    if not gen_get_options(parser, stock_list):
+        return False
+
+    if not validate_parms():
+        return False
+
+    qprint_pgm_header()
+
+    if not debug:
+        qprint_vars(STOP_REST_FAIL, STOP_COMMAND, AUTOBOOT_BOOT_SUCCESS)
+
+    dprint_plug_vars()
+
+    rest_fail()
+
+    esel_stop_check()
+
+    if STOP_COMMAND.upper() == "FAIL":
+        if AUTOBOOT_BOOT_SUCCESS == "0":
+            print_timen("The caller wishes to stop after each boot failure.")
+            exit(stop_test_rc)
+    elif STOP_COMMAND.upper() == "ALL":
+        print_timen("The caller wishes to stop after each boot test.")
+        exit(stop_test_rc)
+    elif len(STOP_COMMAND) > 0:
+        shell_rc, out_buf = cmd_fnc_u(STOP_COMMAND, quiet=quiet, show_err=0)
+        if shell_rc != 0:
+            print_timen("The caller wishes to stop test execution.")
+            exit(stop_test_rc)
+
+    qprint_timen("The caller does not wish to stop the test run.")
+    return True
+
+# Main
+
+if not main():
+    exit(1)
diff --git a/bin/plug_ins/Stop/parm_def b/bin/plug_ins/Stop/parm_def
new file mode 100755
index 0000000..b2574bb
--- /dev/null
+++ b/bin/plug_ins/Stop/parm_def
@@ -0,0 +1,11 @@
+# "command" may contain a bash command string to be run to determine whether
+# the test program should be stopped.  If the command returns non-zero, the
+# test program should be stopped.
+command=string
+# "rest_fail" indicates that the Stop plug-in should fail if REST commands to
+# the BMC are failing.
+rest_fail=boolean
+# "esel_stop_file_path" may contain the path to a file with specifications
+# for which eSELs warrant stopping the test run.  See esel_stop_check help
+# text for details.
+esel_stop_file_path=string
diff --git a/bin/plug_ins/Stop/supports_obmc b/bin/plug_ins/Stop/supports_obmc
new file mode 100644
index 0000000..d965c8a
--- /dev/null
+++ b/bin/plug_ins/Stop/supports_obmc
@@ -0,0 +1 @@
+# The presence of this file tells obmc_boot_test that this plug-in supports Open BMC.
diff --git a/bin/process_plug_in_packages.py b/bin/process_plug_in_packages.py
index 75881fe..49fc21c 100755
--- a/bin/process_plug_in_packages.py
+++ b/bin/process_plug_in_packages.py
@@ -251,8 +251,8 @@
     else:
         autoscript_subcmd = ""
 
-    cmd_buf = "PATH=" + plug_in_dir_path + ":${PATH} ; " + autoscript_subcmd +\
-              cp_prefix + call_point
+    cmd_buf = "PATH=" + plug_in_dir_path.rstrip("/") + ":${PATH} ; " +\
+        autoscript_subcmd + cp_prefix + call_point
     pissuing(cmd_buf)
 
     sub_proc = subprocess.Popen(cmd_buf, shell=True)
@@ -263,6 +263,8 @@
     if shell_rc != 0 and shell_rc != allow_shell_rc:
         rc = 1
         failed_plug_in_name = plug_in_name
+    if shell_rc != 0:
+        failed_plug_in_name = plug_in_name
 
     print("------------------------------------------------- Ending plug-in" +
           " -------------------------------------------------")
diff --git a/lib/gen_call_robot.py b/lib/gen_call_robot.py
new file mode 100755
index 0000000..5b4b01c
--- /dev/null
+++ b/lib/gen_call_robot.py
@@ -0,0 +1,430 @@
+#!/usr/bin/env python
+
+r"""
+This module provides functions which are useful to plug-ins call-point
+programs that wish to make external robot program calls.
+"""
+
+import sys
+import os
+import subprocess
+import re
+import time
+import imp
+
+import gen_print as gp
+import gen_valid as gv
+import gen_misc as gm
+import gen_cmd as gc
+
+auto_base_path = "/afs/rchland.ibm.com/projects/esw/dvt/autoipl/"
+
+base_path = \
+    os.path.dirname(os.path.dirname(imp.find_module("gen_robot_print")[1])) +\
+    os.sep
+
+
+def init_robot_out_parms(extra_prefix=""):
+
+    r"""
+    Initialize robot output parms such as outputdir, output, etc.
+
+    This function will set global values for the following robot output parms.
+
+    outputdir, output, log, report, loglevel
+
+    This function would typically be called prior to calling
+    create_robot_cmd_string.
+    """
+
+    AUTOBOOT_OPENBMC_NICKNAME = gm.get_mod_global("AUTOBOOT_OPENBMC_NICKNAME")
+
+    FFDC_DIR_PATH_STYLE = os.environ.get('FFDC_DIR_PATH_STYLE', '0')
+    if FFDC_DIR_PATH_STYLE == '1':
+        default_ffdc_dir_path = "/tmp/"
+    else:
+        default_ffdc_dir_path = base_path
+    # Set values for call to create_robot_cmd_string.
+    outputdir = gm.add_trailing_slash(os.environ.get("FFDC_DIR_PATH",
+                                                     default_ffdc_dir_path))
+    seconds = time.time()
+    loc_time = time.localtime(seconds)
+    time_string = time.strftime("%y%m%d.%H%M%S", loc_time)
+    file_prefix = AUTOBOOT_OPENBMC_NICKNAME + "." + extra_prefix +\
+        time_string + "."
+    output = file_prefix + "output.xml"
+    log = file_prefix + "log.html"
+    report = file_prefix + "report.html"
+    loglevel = "TRACE"
+
+    # Make create_robot_cmd_string values global.
+    gm.set_mod_global(outputdir)
+    gm.set_mod_global(output)
+    gm.set_mod_global(log)
+    gm.set_mod_global(report)
+    gm.set_mod_global(loglevel)
+
+
+def init_robot_test_base_dir_path():
+
+    r"""
+    Initialize and validate the environment variable, ROBOT_TEST_BASE_DIR_PATH
+    and set corresponding global variable ROBOT_TEST_RUNNING_FROM_SB.
+
+    If ROBOT_TEST_BASE_DIR_PATH is already set, this function will merely
+    validate it.  This function will also set environment variable
+    ROBOT_TEST_RUNNING_FROM_SB when ROBOT_TEST_BASE_DIR_PATH is not pre-set.
+    """
+
+    # ROBOT_TEST_BASE_DIR_PATH will be set as follows:
+    # This function will determine whether we are running in a user sandbox
+    # or from a standard apolloxxx environment.
+    # - User sandbox:
+    # If there is a <developer's home dir>/git/openbmc-test-automation/,
+    # ROBOT_TEST_BASE_DIR_PATH will be set to that path.  Otherwise, we set it
+    # to <program dir path>/git/openbmc-test-automation/
+    # - Not in user sandbox:
+    # ROBOT_TEST_BASE_DIR_PATH will be set to <program dir
+    # path>/git/openbmc-test-automation/
+
+    ROBOT_TEST_BASE_DIR_PATH = os.environ.get('ROBOT_TEST_BASE_DIR_PATH', "")
+
+    ROBOT_TEST_RUNNING_FROM_SB = \
+        int(os.environ.get('ROBOT_TEST_RUNNING_FROM_SB', "0"))
+    if ROBOT_TEST_BASE_DIR_PATH == "":
+        # ROBOT_TEST_BASE_DIR_PATH was not set by user/caller.
+
+        AUTOIPL_VERSION = os.environ.get('AUTOIPL_VERSION', '')
+
+        if AUTOIPL_VERSION == "":
+            ROBOT_TEST_BASE_DIR_PATH = base_path
+        else:
+            suffix = "git/openbmc-test-automation/"
+
+            # Determine whether we're running out of a developer sandbox or
+            # simply out of an apolloxxx/bin path.
+            cmd_buf = 'dirname $(which gen_print.py)'
+            gp.dpissuing(cmd_buf)
+            sub_proc = \
+                subprocess.Popen(cmd_buf, shell=True, stdout=subprocess.PIPE,
+                                 stderr=subprocess.STDOUT)
+            out_buf, err_buf = sub_proc.communicate()
+            shell_rc = sub_proc.returncode
+            executable_base_dir_path = out_buf.rstrip() + "/"
+
+            # Strip the "land.ibm.com" for truer comparison with
+            # apollo_dir_path.
+            executable_base_dir_path = \
+                executable_base_dir_path.replace('land.ibm.com', '')
+
+            apollo_dir_path = re.sub('land\.ibm\.com', '', auto_base_path) +\
+                AUTOIPL_VERSION + "/bin/"
+
+            developer_home_dir_path = re.sub('/sandbox.*', '',
+                                             executable_base_dir_path)
+            developer_home_dir_path = \
+                gm.add_trailing_slash(developer_home_dir_path)
+            gp.dprint_vars(executable_base_dir_path, developer_home_dir_path,
+                           apollo_dir_path)
+
+            ROBOT_TEST_RUNNING_FROM_SB = 0
+            if executable_base_dir_path != apollo_dir_path:
+                ROBOT_TEST_RUNNING_FROM_SB = 1
+                gp.dprint_vars(ROBOT_TEST_RUNNING_FROM_SB)
+                ROBOT_TEST_BASE_DIR_PATH = developer_home_dir_path + suffix
+                if not os.path.isdir(ROBOT_TEST_BASE_DIR_PATH):
+                    gp.dprint_timen("NOTE: Sandbox directory" +
+                                    " ${ROBOT_TEST_BASE_DIR_PATH} does not" +
+                                    " exist.")
+                    # Fall back to the apollo dir path.
+                    ROBOT_TEST_BASE_DIR_PATH = apollo_dir_path + suffix
+            else:
+                # Use to the apollo dir path.
+                ROBOT_TEST_BASE_DIR_PATH = apollo_dir_path + suffix
+
+    if not gv.valid_value(ROBOT_TEST_BASE_DIR_PATH):
+        return False
+    gp.dprint_vars(ROBOT_TEST_RUNNING_FROM_SB, ROBOT_TEST_BASE_DIR_PATH)
+    if not gv.valid_dir_path(ROBOT_TEST_BASE_DIR_PATH):
+        return False
+
+    ROBOT_TEST_BASE_DIR_PATH = gm.add_trailing_slash(ROBOT_TEST_BASE_DIR_PATH)
+    gm.set_mod_global(ROBOT_TEST_BASE_DIR_PATH)
+    os.environ['ROBOT_TEST_BASE_DIR_PATH'] = ROBOT_TEST_BASE_DIR_PATH
+
+    gm.set_mod_global(ROBOT_TEST_RUNNING_FROM_SB)
+    os.environ['ROBOT_TEST_RUNNING_FROM_SB'] = str(ROBOT_TEST_RUNNING_FROM_SB)
+
+
+raw_robot_file_search_path = "${ROBOT_TEST_BASE_DIR_PATH}:" +\
+    "${ROBOT_TEST_BASE_DIR_PATH}tests:${ROBOT_TEST_BASE_DIR_PATH}extended:" +\
+    "${ROBOT_TEST_BASE_DIR_PATH}scratch:${PATH}"
+
+
+def init_robot_file_path(robot_file_path):
+
+    r"""
+    Determine full path name for the file path passed in robot_file_path and
+    return it.
+
+    If robot_file_path contains a fully qualified path name, this function
+    will verify that the file exists.  If robot_file_path contains a relative
+    path, this function will search for the file and set robot_file_path so
+    that it contains the absolute path to the robot file.  This function will
+    search for the robot file using the raw_robot_file_search_path (defined
+    above).  Note that if ROBOT_TEST_BASE_DIR_PATH is not set, this function
+    will call init_robot_test_base_dir_path to set it.
+
+    Description of arguments:
+    robot_file_path                 The absolute or relative path to a robot
+                                    file.
+    """
+
+    if not gv.valid_value(robot_file_path):
+        raise ValueError('Programmer error.')
+
+    try:
+        if ROBOT_TEST_BASE_DIR_PATH is NONE:
+            init_robot_test_base_dir_path()
+    except NameError:
+        init_robot_test_base_dir_path()
+
+    if not re.match(r".*\.(robot|py)$", robot_file_path):
+        # No suffix so we'll assign one of "\.robot".
+        robot_file_path = robot_file_path + ".robot"
+
+    abs_path = 0
+    if robot_file_path[0:1] == "/":
+        abs_path = 1
+
+    gp.dprint_vars(abs_path, robot_file_path)
+
+    if not abs_path:
+        cmd_buf = "echo -n \"" + raw_robot_file_search_path + "\""
+        gp.dpissuing(cmd_buf)
+        sub_proc = subprocess.Popen(cmd_buf, shell=True,
+                                    stdout=subprocess.PIPE,
+                                    stderr=subprocess.STDOUT)
+        out_buf, err_buf = sub_proc.communicate()
+        shell_rc = sub_proc.returncode
+        robot_file_search_paths = out_buf
+        gp.dpvar(robot_file_search_paths)
+
+        robot_file_search_paths_list = robot_file_search_paths.split(':')
+        for search_path in robot_file_search_paths_list:
+            search_path = gm.add_trailing_slash(search_path)
+            candidate_file_path = search_path + robot_file_path
+            gp.dprint_var(candidate_file_path)
+            if os.path.isfile(candidate_file_path):
+                gp.dprint_timen("Found full path to " + robot_file_path + ".")
+                robot_file_path = candidate_file_path
+                break
+
+    gp.dprint_var(robot_file_path)
+    if not gv.valid_file_path(robot_file_path):
+        raise ValueError('Programmer error.')
+
+    return robot_file_path
+
+
+def get_robot_parm_names():
+
+    r"""
+    Return a list containing all of the long parm names (e.g. --outputdir)
+    supported by the robot program.  Double dashes are not included in the
+    names returned.
+    """
+
+    cmd_buf = "robot -h | egrep " +\
+        "'^([ ]\-[a-zA-Z0-9])?[ ]+--[a-zA-Z0-9]+[ ]+' | sed -re" +\
+        " s'/.*\-\-//g' -e s'/ .*//g' | sort -u"
+    sub_proc = subprocess.Popen(cmd_buf, shell=True, stdout=subprocess.PIPE,
+                                stderr=subprocess.STDOUT)
+    out_buf, err_buf = sub_proc.communicate()
+    shell_rc = sub_proc.returncode
+    if shell_rc != 0:
+        hex = 1
+        print_var(shell_rc, hex)
+        print(out_buf)
+
+    return out_buf.split("\n")
+
+
+def create_robot_cmd_string(robot_file_path, *parms):
+
+    r"""
+    Create a robot command string and return it.  On failure, return an empty
+    string.
+
+    Description of arguments:
+    robot_file_path                 The path to the robot file to be run.
+    parms                           The list of parms to be included in the
+                                    command string.  The name of each variable
+                                    in this list must be the same as the name
+                                    of the corresponding parm.  This function
+                                    figures out that name.  This function is
+                                    also able to distinguish robot parms (e.g.
+                                    --outputdir) from robot program parms (all
+                                    other parms which will be passed as "-v
+                                    PARM_NAME:parm_value")..
+
+    Example:
+
+    The following call to this function...
+    cmd_buf = create_robot_cmd_string("tools/start_sol_console.robot",
+    OPENBMC_HOST, quiet, test_mode, debug, outputdir, output, log, report)
+
+    Would return a string something like this.
+    robot -v OPENBMC_HOST:beye6 -v quiet:0 -v test_mode:1 -v debug:1
+    --outputdir=/gsa/ausgsa/projects/a/autoipl/status
+    --output=beye6.OS_Console.output.xml --log=beye6.OS_Console.log.html
+    --report=beye6.OS_Console.report.html tools/start_sol_console.robot
+    """
+
+    robot_file_path = init_robot_file_path(robot_file_path)
+
+    robot_parm_names = get_robot_parm_names()
+
+    robot_parm_list = []
+
+    stack_frame = 2
+    ix = 2
+    for arg in parms:
+        parm = arg
+        parm = gm.quote_bash_parm(gm.escape_bash_quotes(str(parm)))
+        var_name = gp.get_arg_name(None, ix, stack_frame)
+        if var_name in robot_parm_names:
+            p_string = "--" + var_name + "=" + str(parm)
+            robot_parm_list.append(p_string)
+        else:
+            p_string = "-v " + var_name + ":" + str(parm)
+            robot_parm_list.append(p_string)
+        ix += 1
+
+    robot_cmd_buf = "robot " + ' '.join(robot_parm_list) + " " +\
+        robot_file_path
+
+    return robot_cmd_buf
+
+
+def robot_cmd_fnc(robot_cmd_buf,
+                  robot_jail=os.environ.get('ROBOT_JAIL', ''),
+                  gzip=1):
+
+    r"""
+    Run the robot command string.
+
+    This function will set the various PATH variables correctly so that you
+    are running the proper version of all imported files, etc.
+
+    Description of argument(s):
+    robot_cmd_buf                   The complete robot command string.
+    robot_jail                      Indicates that this is to run in "robot
+                                    jail" meaning without visibility to any
+                                    apolloxxx import files, programs, etc.
+    gqip                            This indicates that the log, report and
+                                    output files produced by robot should be
+                                    gzipped to save space.
+    """
+
+    if not gv.valid_value(robot_cmd_buf):
+        return False
+
+    # Get globals set by init_robot_test_base_dir_path().
+    module = sys.modules["__main__"]
+    try:
+        ROBOT_TEST_BASE_DIR_PATH = getattr(module, "ROBOT_TEST_BASE_DIR_PATH")
+    except NameError:
+        init_robot_test_base_dir_path()
+        ROBOT_TEST_BASE_DIR_PATH = getattr(module, "ROBOT_TEST_BASE_DIR_PATH")
+
+    ROBOT_TEST_RUNNING_FROM_SB = \
+        gm.get_mod_global("ROBOT_TEST_RUNNING_FROM_SB")
+
+    if robot_jail == "":
+        if ROBOT_TEST_RUNNING_FROM_SB:
+            robot_jail = 0
+        else:
+            robot_jail = 1
+
+    robot_jail = int(robot_jail)
+    ROBOT_JAIL = os.environ.get('ROBOT_JAIL', '')
+    gp.dprint_vars(ROBOT_TEST_BASE_DIR_PATH, ROBOT_TEST_RUNNING_FROM_SB,
+                   ROBOT_JAIL, robot_jail)
+
+    # Save PATH and PYTHONPATH to be restored later.
+    os.environ["SAVED_PYTHONPATH"] = os.environ.get("PYTHONPATH", "")
+    os.environ["SAVED_PATH"] = os.environ.get("PATH", "")
+
+    if robot_jail:
+        PYTHONPATH = ROBOT_TEST_BASE_DIR_PATH + "lib"
+        NEW_PATH_LIST = [ROBOT_TEST_BASE_DIR_PATH + "bin"]
+        # Coding special case to preserve python27_path.
+        python27_path = "/opt/rh/python27/root/usr/bin"
+        PATH_LIST = os.environ.get("PATH", "").split(":")
+        if python27_path in PATH_LIST:
+            NEW_PATH_LIST.append(python27_path)
+        NEW_PATH_LIST.extend(["/usr/local/sbin", "/usr/local/bin", "/usr/sbin",
+                              "/usr/bin", "/sbin", "/bin"])
+        PATH = ":".join(NEW_PATH_LIST)
+    else:
+        PYTHONPATH = os.environ.get('PYTHONPATH', '') + ":" +\
+            ROBOT_TEST_BASE_DIR_PATH + "lib/"
+        PATH = os.environ.get('PATH', '') + ":" + ROBOT_TEST_BASE_DIR_PATH +\
+            "bin/"
+
+    os.environ['PYTHONPATH'] = PYTHONPATH
+    os.environ['PATH'] = PATH
+    gp.dprint_vars(PATH, PYTHONPATH)
+
+    os.environ['FFDC_DIR_PATH_STYLE'] = os.environ.get('FFDC_DIR_PATH_STYLE',
+                                                       '1')
+
+    test_mode = getattr(module, "test_mode")
+
+    gp.qpissuing(robot_cmd_buf, test_mode)
+    if test_mode:
+        os.environ["PATH"] = os.environ.get("SAVED_PATH", "")
+        os.environ["PYTHONPATH"] = os.environ.get("SAVED_PYTHONPATH", "")
+        return True
+
+    if quiet:
+        DEVNULL = open(os.devnull, 'wb')
+        stdout = DEVNULL
+    else:
+        stdout = None
+    sub_proc = subprocess.Popen(robot_cmd_buf, stdout=stdout, shell=True)
+    sub_proc.communicate()
+    shell_rc = sub_proc.returncode
+    if shell_rc != 0:
+        hex = 1
+        gp.pvar(shell_rc, hex)
+        os.environ["PATH"] = os.environ.get("SAVED_PATH", "")
+        os.environ["PYTHONPATH"] = os.environ.get("SAVED_PYTHONPATH", "")
+        return False
+
+    os.environ["PATH"] = os.environ.get("SAVED_PATH", "")
+    os.environ["PYTHONPATH"] = os.environ.get("SAVED_PYTHONPATH", "")
+
+    if not gzip:
+        return True
+
+    # gzip the output files.
+    # Retrieve the parms from the robot command buffer.
+    robot_cmd_buf_dict = gc.parse_command_string(robot_cmd_buf)
+    # Get prefix from the log parm.
+    prefix = re.sub('log\.html$', '', robot_cmd_buf_dict['log'])
+    gp.qprintn()
+    rc, outbuf = gc.cmd_fnc("cd " + robot_cmd_buf_dict['outputdir'] +
+                            " ; gzip " + robot_cmd_buf_dict['output'] +
+                            " " + robot_cmd_buf_dict['log'] +
+                            " " + robot_cmd_buf_dict['report'])
+
+    outputdir = gm.add_trailing_slash(robot_cmd_buf_dict['outputdir'])
+    Output = outputdir + robot_cmd_buf_dict['output'] + ".gz"
+    Log = outputdir + robot_cmd_buf_dict['log'] + ".gz"
+    Report = outputdir + robot_cmd_buf_dict['report'] + ".gz"
+    gp.qprintn("\ngzipped output:")
+    gp.qpvars(0, 9, Output, Log, Report)
+
+    return True
diff --git a/lib/gen_cmd.py b/lib/gen_cmd.py
index 8f0c249..f9bd3cf 100644
--- a/lib/gen_cmd.py
+++ b/lib/gen_cmd.py
@@ -85,6 +85,7 @@
     sub_proc = subprocess.Popen(cmd_buf,
                                 bufsize=1,
                                 shell=True,
+                                executable='/bin/bash',
                                 stdout=subprocess.PIPE,
                                 stderr=stderr)
     out_buf = ""
diff --git a/lib/gen_plug_in_utils.py b/lib/gen_plug_in_utils.py
index 4c378fc..f1d647f 100755
--- a/lib/gen_plug_in_utils.py
+++ b/lib/gen_plug_in_utils.py
@@ -10,6 +10,7 @@
 import collections
 
 import gen_print as gp
+import gen_misc as gm
 
 
 def get_plug_in_package_name(case=None):
@@ -59,6 +60,34 @@
         os.environ['AUTOBOOT_OPENBMC_NICKNAME'] = \
             os.environ.get("AUTOBOOT_OPENBMC_HOST", "")
 
+    # For all variables specified in the parm_def file, we want them to
+    # default to "" rather than being unset.
+    # Process the parm_def file if it exists.
+    parm_def_file_path = gp.pgm_dir_path + "parm_def"
+    if os.path.exists(parm_def_file_path):
+        parm_defs = gm.my_parm_file(parm_def_file_path)
+    else:
+        parm_defs = collections.OrderedDict()
+    # Example parm_defs:
+    # parm_defs:
+    #   parm_defs[rest_fail]:           boolean
+    #   parm_defs[command]:             string
+    #   parm_defs[esel_stop_file_path]: string
+
+    # Create a list of plug-in environment variables by pre-pending <all caps
+    # plug-in package name>_<all caps var name>
+    plug_in_parm_names = [plug_in_package_name + "_" + x for x in
+                          map(str.upper, parm_defs.keys())]
+    # Example plug_in_parm_names:
+    # plug_in_parm_names:
+    #  plug_in_parm_names[0]: STOP_REST_FAIL
+    #  plug_in_parm_names[1]: STOP_COMMAND
+    #  plug_in_parm_names[2]: STOP_ESEL_STOP_FILE_PATH
+
+    # Initialize unset plug-in vars.
+    for var_name in plug_in_parm_names:
+        os.environ[var_name] = os.environ.get(var_name, "")
+
     plug_var_dict = \
         collections.OrderedDict(sorted({k: v for (k, v) in
                                         os.environ.items()
diff --git a/lib/gen_print.py b/lib/gen_print.py
index 90f78be..61cb726 100755
--- a/lib/gen_print.py
+++ b/lib/gen_print.py
@@ -38,7 +38,8 @@
 # importing this module.
 pgm_file_path = sys.argv[0]
 pgm_name = os.path.basename(pgm_file_path)
-pgm_dir_path = re.sub("/" + pgm_name, "", pgm_file_path) + "/"
+pgm_dir_path = os.path.normpath(re.sub("/" + pgm_name, "", pgm_file_path)) +\
+    os.path.sep
 
 
 # Some functions (e.g. sprint_pgm_header) have need of a program name value
diff --git a/lib/gen_robot_plug_in.py b/lib/gen_robot_plug_in.py
index ec79d6b..1dc8983 100755
--- a/lib/gen_robot_plug_in.py
+++ b/lib/gen_robot_plug_in.py
@@ -177,7 +177,8 @@
             grp.rprint_timen("Processing " + call_point +
                              " call point programs.")
 
-    proc_plug_pkg_rc = subprocess.call(cmd_buf, shell=True)
+    proc_plug_pkg_rc = subprocess.call(cmd_buf, shell=True,
+                                       executable='/bin/bash')
 
     # As process_plug_in_packages.py help text states, it will print the
     # values of failed_plug_in_name and shell_rc in the following format:
diff --git a/lib/obmc_boot_test.py b/lib/obmc_boot_test.py
index e431804..8b6040a 100755
--- a/lib/obmc_boot_test.py
+++ b/lib/obmc_boot_test.py
@@ -859,11 +859,11 @@
 
     plug_in_setup()
     rc, shell_rc, failed_plug_in_name = grpi.rprocess_plug_in_packages(
-        call_point='stop_check')
-    if rc != 0:
-        error_message = "Stopping as requested by user.\n"
-        grp.rprint_error_report(error_message)
-        BuiltIn().fail(error_message)
+        call_point='stop_check', shell_rc=0x00000200, stop_on_non_zero_rc=1)
+    if shell_rc == 0x00000200:
+        message = "Stopping as requested by user.\n"
+        gp.print_time(message)
+        BuiltIn().fail(message)
 
     # This should help prevent ConnectionErrors.
     grk.run_key_u("Close All Connections")