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/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")