def rvalid_range(var_name,
                 range):
    r"""
    Validate that a robot integer is within the given range.

    This function is the robot wrapper for gen_robot_print.svalid_range.

    Description of arguments:
    var_name                        The name of the variable whose value is to
                                    be validated.
    range                           A list comprised of one or two elements
                                    which are the lower and upper ends of a
                                    range.  These values must be integers
                                    except where noted.  Valid specifications
                                    may be of the following forms: [lower,
                                    upper], [lower] or [None, upper].  The
                                    caller may also specify this value as a
                                    string which will then be converted to a
                                    list in the aforementioned format:
                                    lower..upper, lower.. or ..upper.

    Examples of robot calls and corresponding output:

    Robot code...
    Rvalid Range  MY_PARM  5..9

    Output...
    #(CDT) 2018/05/09 11:45:00.166344 -    0.004252 - **ERROR** The following
    # variable is not within the expected range:
    MY_PARM:                                          4
    valid_range:                                      5..9
    """

    var_value = BuiltIn().get_variable_value("${" + var_name + "}")

    if var_value is None:
        var_value = ""
        error_message = "Variable \"" + var_name +\
                        "\" not found (i.e. it's undefined).\n"
    else:
        try:
            range = range.split("..")
        except AttributeError:
            pass
        if range[0] == "":
            range[0] = None
        range = [x for x in range if x]
        error_message = gv.svalid_range(var_value, range, var_name)
    if not error_message == "":
        error_message = grp.sprint_error_report(error_message)
        BuiltIn().fail(error_message)
def rvalid_range(var_name,
                 range):
    r"""
    Validate that a robot integer is within the given range.

    This function is the robot wrapper for gen_robot_print.svalid_range.

    Description of arguments:
    var_name                        The name of the variable whose value is to
                                    be validated.
    range                           A list comprised of one or two elements
                                    which are the lower and upper ends of a
                                    range.  These values must be integers
                                    except where noted.  Valid specifications
                                    may be of the following forms: [lower,
                                    upper], [lower] or [None, upper].  The
                                    caller may also specify this value as a
                                    string which will then be converted to a
                                    list in the aforementioned format:
                                    lower..upper, lower.. or ..upper.

    Examples of robot calls and corresponding output:

    Robot code...
    Rvalid Range  MY_PARM  5..9

    Output...
    #(CDT) 2018/05/09 11:45:00.166344 -    0.004252 - **ERROR** The following
    # variable is not within the expected range:
    MY_PARM:                                          4
    valid_range:                                      5..9
    """

    var_value = BuiltIn().get_variable_value("${" + var_name + "}")

    if var_value is None:
        var_value = ""
        error_message = "Variable \"" + var_name +\
                        "\" not found (i.e. it's undefined).\n"
    else:
        if isinstance(range, unicode):
            range = range.split("..")
        if range[0] == "":
            range[0] = None
        range = [x for x in range if x]
        error_message = gv.svalid_range(var_value, range, var_name)
    if not error_message == "":
        error_message = grp.sprint_error_report(error_message)
        BuiltIn().fail(error_message)
Ejemplo n.º 3
0
def rvalid_integer(var_name):

    r"""
    Validate a robot integer.

    This function is the robot wrapper for gen_robot_print.svalid_integer.

    Description of arguments:
    var_name                        The name of the variable whose value is to
                                    be validated.

    Examples of robot calls and corresponding output:

    Robot code...
    Rvalid Integer  MY_PARM

    Output...
    #(CDT) 2016/11/02 10:44:43 - **ERROR** Variable "MY_PARM" not found (i.e.
    #it's undefined).

    or if it is defined but blank:

    Output...
    #(CDT) 2016/11/02 10:45:37 - **ERROR** Invalid integer value:
    MY_PARM:                     <blank>

    Robot code...
    ${MY_PARM}=  Set Variable  HELLO
    Rvalid Integer  MY_PARM

    Output...
    #(CDT) 2016/11/02 10:46:18 - **ERROR** Invalid integer value:
    MY_PARM:                     HELLO

    """

    # Note: get_variable_value() seems to have no trouble with local variables.
    var_value = BuiltIn().get_variable_value("${" + var_name + "}")

    if var_value is None:
        var_value = ""
        error_message = "Variable \"" + var_name +\
                        "\" not found (i.e. it's undefined).\n"
    else:
        error_message = gv.svalid_integer(var_value, var_name)
    if not error_message == "":
        error_message = grp.sprint_error_report(error_message)
        BuiltIn().fail(error_message)
Ejemplo n.º 4
0
def set_ffdc_defaults(ffdc_dir_path=None, ffdc_prefix=None):
    r"""
    Set a default value for ffdc_dir_path and ffdc_prefix if they don't
    already have values.  Return both values.

    Description of arguments:
    ffdc_dir_path  The dir path where FFDC data should be put.
    ffdc_prefix    The prefix to be given to each FFDC file name generated.

    NOTE: If global variable ffdc_dir_path_style is set to ${1}, this function
    will create default values in a newer way.  Otherwise, its behavior
    will remain unchanged.
    """

    # Note: Several subordinate functions like 'Get Test Dir and Name' and
    # 'Header Message' expect global variable FFDC_TIME to be set.
    cmd_buf = ["Get Current Time Stamp"]
    grp.rdpissuing_keyword(cmd_buf)
    FFDC_TIME = BuiltIn().run_keyword(*cmd_buf)
    BuiltIn().set_global_variable("${FFDC_TIME}", FFDC_TIME)

    ffdc_dir_path_style = BuiltIn().get_variable_value(
        "${ffdc_dir_path_style}")

    if ffdc_dir_path is None:
        if ffdc_dir_path_style:
            try:
                ffdc_dir_path = os.environ['FFDC_DIR_PATH']
            except KeyError:
                ffdc_dir_path = os.path.dirname(
                    BuiltIn().get_variable_value("${LOG_FILE}")) + "/"
        else:
            FFDC_LOG_PATH = os.getcwd() + "/logs/"
            if FFDC_LOG_PATH is None:
                FFDC_LOG_PATH = ""
            if FFDC_LOG_PATH == "":
                FFDC_LOG_PATH = os.path.dirname(
                    BuiltIn().get_variable_value("${LOG_FILE}")) + "/"
            error_message = gv.svalid_value(FFDC_LOG_PATH,
                                            var_name="FFDC_LOG_PATH")
            if error_message != "":
                error_message = grp.sprint_error_report(error_message)
                BuiltIn().fail(error_message)
            FFDC_LOG_PATH = os.path.normpath(FFDC_LOG_PATH) + os.sep

            cmd_buf = ["Get Test Dir and Name"]
            grp.rpissuing_keyword(cmd_buf)
            suitename, testname = BuiltIn().run_keyword(*cmd_buf)

            ffdc_dir_path = FFDC_LOG_PATH + suitename + "/" + testname + "/"

    # Add trailing slash.
    ffdc_dir_path = os.path.normpath(ffdc_dir_path) + os.sep

    if ffdc_prefix is None:
        FFDC_TIME = BuiltIn().get_variable_value("${FFDC_TIME}")
        if ffdc_prefix is None:
            if ffdc_dir_path_style:
                OPENBMC_HOST = BuiltIn().get_variable_value("${OPENBMC_HOST}")
                OPENBMC_NICKNAME = BuiltIn().get_variable_value(
                    "${OPENBMC_NICKNAME}", default=OPENBMC_HOST)
                ffdc_prefix = OPENBMC_NICKNAME + "." + FFDC_TIME[2:8] + "." +\
                    FFDC_TIME[8:14] + "."
            else:
                ffdc_prefix = FFDC_TIME + "_"

    BuiltIn().set_global_variable("${FFDC_DIR_PATH}", ffdc_dir_path)
    BuiltIn().set_global_variable("${FFDC_PREFIX}", ffdc_prefix)

    return ffdc_dir_path, ffdc_prefix
Ejemplo n.º 5
0
def ffdc(ffdc_dir_path=None, ffdc_prefix=None, ffdc_function_list=""):
    r"""
    Gather First Failure Data Capture (FFDC).

    This includes:
    - Set global FFDC_TIME.
    - Create FFDC work space directory.
    - Write test info details.
    - Call BMC methods to write/collect FFDC data.

    Description of arguments:
    ffdc_dir_path       The dir path where FFDC data should be put.
    ffdc_prefix         The prefix to be given to each FFDC file name
                        generated.
    ffdc_function_list  A colon-delimited list of all the types of FFDC data
                        you wish to have collected.  A blank value means that
                        all possible kinds of FFDC are to be collected.  See
                        FFDC_METHOD_CALL object in lib/openbmc_ffdc_list.py
                        for possible choices.
    """

    ffdc_file_list = []

    # Check if Ping and SSH connection is alive
    OPENBMC_HOST = BuiltIn().get_variable_value("${OPENBMC_HOST}")

    state = st.get_state(req_states=['ping', 'uptime'])
    gp.qprint_var(state)
    if not int(state['ping']):
        gp.print_error("BMC is not ping-able.  Terminating FFDC collection.\n")
        return ffdc_file_list

    if state['uptime'] == "":
        gp.print_error("BMC is not communicating.  Terminating FFDC" +
                       " collection.\n")
        return ffdc_file_list

    gp.qprint_timen("Collecting FFDC.")

    # Get default values for arguments.
    ffdc_dir_path, ffdc_prefix = set_ffdc_defaults(ffdc_dir_path, ffdc_prefix)
    gp.qprint_var(ffdc_dir_path)
    gp.qprint_var(ffdc_prefix)

    # LOG_PREFIX is used by subordinate functions.
    LOG_PREFIX = ffdc_dir_path + ffdc_prefix
    BuiltIn().set_global_variable("${LOG_PREFIX}", LOG_PREFIX)

    cmd_buf = ["Create Directory", ffdc_dir_path]
    grp.rqpissuing_keyword(cmd_buf)
    status, output = BuiltIn().run_keyword_and_ignore_error(*cmd_buf)
    if status != "PASS":
        error_message = grp.sprint_error_report("Create Directory failed" +
                                                " with the following" +
                                                " error:\n" + output)
        BuiltIn().fail(error_message)

    # FFDC_FILE_PATH is used by Header Message.
    FFDC_FILE_PATH = ffdc_dir_path + ffdc_prefix + "BMC_general.txt"
    BuiltIn().set_global_variable("${FFDC_FILE_PATH}", FFDC_FILE_PATH)

    status, ffdc_file_list = grk.run_key("Header Message")
    status, ffdc_file_sub_list = \
        grk.run_key_u("Call FFDC Methods  ffdc_function_list="
                      + ffdc_function_list)

    # Combine lists, remove duplicates and sort.
    ffdc_file_list = sorted(set(ffdc_file_list + ffdc_file_sub_list))

    gp.qprint_timen("Finished collecting FFDC.")

    return ffdc_file_list
Ejemplo n.º 6
0
def rvalid_value(var_name,
                 invalid_values=[],
                 valid_values=[]):

    r"""
    Validate a robot value.

    This function is the robot wrapper for gen_robot_print.svalid_value.

    Description of arguments:
    var_name                        The name of the variable whose value is to
                                    be validated.
    invalid_values                  A list of invalid values.  If var_value is
                                    equal to any of these, it is invalid.
                                    Note that if you specify anything for
                                    invalid_values (below), the valid_values
                                    list is not even processed.
    valid_values                    A list of invalid values.  var_value must
                                    be equal to one of these values to be
                                    considered valid.

    Examples of robot calls and corresponding output:

    Robot code...
    rvalid_value                    MY_PARM

    Output...
    #(CDT) 2016/11/02 10:04:20 - **ERROR** Variable "MY_PARM" not found (i.e.
    #it's undefined).

    or if it is defined but blank:

    Output...
    #(CDT) 2016/11/02 10:14:24 - **ERROR** The following variable has an
    #invalid value:
    MY_PARM:

    It must NOT be one of the following values:
    invalid_values:
      invalid_values[0]:         <blank>

    Robot code...
    ${invalid_values}=  Create List  one  two  three
    ${MY_PARM}=  Set Variable  one
    rvalid_value                    MY_PARM  invalid_values=${invalid_values}

    Output...
    #(CDT) 2016/11/02 10:20:05 - **ERROR** The following variable has an
    #invalid value:
    MY_PARM:                     one

    It must NOT be one of the following values:
    invalid_values:
        invalid_values[0]:       one
        invalid_values[1]:       two
        invalid_values[2]:       three

    """

    # Note: get_variable_value() seems to have no trouble with local variables.
    var_value = BuiltIn().get_variable_value("${" + var_name + "}")

    if var_value is None:
        var_value = ""
        error_message = "Variable \"" + var_name +\
                        "\" not found (i.e. it's undefined).\n"
    else:
        error_message = gv.svalid_value(var_value, invalid_values,
                                        valid_values, var_name)
    if not error_message == "":
        error_message = grp.sprint_error_report(error_message)
        BuiltIn().fail(error_message)
Ejemplo n.º 7
0
def shell_cmd(command_string,
              quiet=None,
              print_output=1,
              show_err=1,
              test_mode=0,
              time_out=None,
              max_attempts=1,
              retry_sleep_time=5,
              allowed_shell_rcs=[0],
              ignore_err=None,
              return_stderr=0,
              fork=0):
    r"""
    Run the given command string in a shell and return a tuple consisting of
    the shell return code and the output.

    Description of argument(s):
    command_string                  The command string to be run in a shell
                                    (e.g. "ls /tmp").
    quiet                           If set to 0, this function will print
                                    "Issuing: <cmd string>" to stdout.  When
                                    the quiet argument is set to None, this
                                    function will assign a default value by
                                    searching upward in the stack for the
                                    quiet variable value.  If no such value is
                                    found, quiet is set to 0.
    print_output                    If this is set, this function will print
                                    the stdout/stderr generated by the shell
                                    command to stdout.
    show_err                        If show_err is set, this function will
                                    print a standardized error report if the
                                    shell command fails (i.e. if the shell
                                    command returns a shell_rc that is not in
                                    allowed_shell_rcs).  Note: Error text is
                                    only printed if ALL attempts to run the
                                    command_string fail.  In other words, if
                                    the command execution is ultimately
                                    successful, initial failures are hidden.
    test_mode                       If test_mode is set, this function will
                                    not actually run the command.  If
                                    print_output is also set, this function
                                    will print "(test_mode) Issuing: <cmd
                                    string>" to stdout.  A caller should call
                                    shell_cmd directly if they wish to have
                                    the command string run unconditionally.
                                    They should call the t_shell_cmd wrapper
                                    (defined below) if they wish to run the
                                    command string only if the prevailing
                                    test_mode variable is set to 0.
    time_out                        A time-out value expressed in seconds.  If
                                    the command string has not finished
                                    executing within <time_out> seconds, it
                                    will be halted and counted as an error.
    max_attempts                    The max number of attempts that should be
                                    made to run the command string.
    retry_sleep_time                The number of seconds to sleep between
                                    attempts.
    allowed_shell_rcs               A list of integers indicating which
                                    shell_rc values are not to be considered
                                    errors.
    ignore_err                      Ignore error means that a failure
                                    encountered by running the command string
                                    will not be raised as a python exception.
                                    When the ignore_err argument is set to
                                    None, this function will assign a default
                                    value by searching upward in the stack for
                                    the ignore_err variable value.  If no such
                                    value is found, ignore_err is set to 1.
    return_stderr                   If return_stderr is set, this function
                                    will process the stdout and stderr streams
                                    from the shell command separately.  In
                                    such a case, the tuple returned by this
                                    function will consist of three values
                                    rather than just two: rc, stdout, stderr.
    fork                            Run the command string asynchronously
                                    (i.e. don't wait for status of the child
                                    process and don't try to get
                                    stdout/stderr).
    """

    # Assign default values to some of the arguments to this function.
    quiet = int(gm.dft(quiet, gp.get_stack_var('quiet', 0)))
    ignore_err = int(gm.dft(ignore_err, gp.get_stack_var('ignore_err', 1)))

    err_msg = gv.svalid_value(command_string)
    if err_msg != "":
        raise ValueError(err_msg)

    if not quiet:
        gp.print_issuing(command_string, test_mode)

    if test_mode:
        if return_stderr:
            return 0, "", ""
        else:
            return 0, ""

    # Convert each list entry to a signed value.
    allowed_shell_rcs = [gm.to_signed(x) for x in allowed_shell_rcs]

    if return_stderr:
        stderr = subprocess.PIPE
    else:
        stderr = subprocess.STDOUT

    shell_rc = 0
    out_buf = ""
    err_buf = ""
    # Write all output to func_history_stdout rather than directly to stdout.
    # This allows us to decide what to print after all attempts to run the
    # command string have been made.  func_history_stdout will contain the
    # complete stdout history from the current invocation of this function.
    func_history_stdout = ""
    for attempt_num in range(1, max_attempts + 1):
        sub_proc = subprocess.Popen(command_string,
                                    bufsize=1,
                                    shell=True,
                                    executable='/bin/bash',
                                    stdout=subprocess.PIPE,
                                    stderr=stderr)
        out_buf = ""
        err_buf = ""
        # Output from this loop iteration is written to func_stdout for later
        # processing.
        func_stdout = ""
        if fork:
            break
        command_timed_out = False
        if time_out is not None:
            # Designate a SIGALRM handling function and set alarm.
            signal.signal(signal.SIGALRM, shell_cmd_timed_out)
            signal.alarm(time_out)
        try:
            if return_stderr:
                for line in sub_proc.stderr:
                    err_buf += line
                    if not print_output:
                        continue
                    func_stdout += line
            for line in sub_proc.stdout:
                out_buf += line
                if not print_output:
                    continue
                func_stdout += line
        except IOError:
            command_timed_out = True
        sub_proc.communicate()
        shell_rc = sub_proc.returncode
        # Restore the original SIGALRM handler and clear the alarm.
        signal.signal(signal.SIGALRM, original_sigalrm_handler)
        signal.alarm(0)
        if shell_rc in allowed_shell_rcs:
            break
        err_msg = "The prior shell command failed.\n"
        if command_timed_out:
            err_msg += gp.sprint_var(command_timed_out)
            err_msg += gp.sprint_var(time_out)
            err_msg += gp.sprint_varx("child_pid", sub_proc.pid)
        err_msg += gp.sprint_var(attempt_num)
        err_msg += gp.sprint_var(shell_rc, 1)
        err_msg += gp.sprint_var(allowed_shell_rcs, 1)
        if not print_output:
            if return_stderr:
                err_msg += "err_buf:\n" + err_buf
            err_msg += "out_buf:\n" + out_buf
        if show_err:
            if robot_env:
                func_stdout += grp.sprint_error_report(err_msg)
            else:
                func_stdout += gp.sprint_error_report(err_msg)
        func_history_stdout += func_stdout
        if attempt_num < max_attempts:
            func_history_stdout += gp.sprint_issuing("time.sleep("
                                                     + str(retry_sleep_time)
                                                     + ")")
            time.sleep(retry_sleep_time)

    if shell_rc not in allowed_shell_rcs:
        func_stdout = func_history_stdout

    if robot_env:
        grp.rprint(func_stdout)
    else:
        sys.stdout.write(func_stdout)
        sys.stdout.flush()

    if shell_rc not in allowed_shell_rcs:
        if not ignore_err:
            if robot_env:
                BuiltIn().fail(err_msg)
            else:
                raise ValueError("The prior shell command failed.\n")

    if return_stderr:
        return shell_rc, out_buf, err_buf
    else:
        return shell_rc, out_buf
def set_ffdc_defaults(ffdc_dir_path=None,
                      ffdc_prefix=None):
    r"""
    Set a default value for ffdc_dir_path and ffdc_prefix if they don't
    already have values.  Return both values.

    Description of arguments:
    ffdc_dir_path  The dir path where FFDC data should be put.
    ffdc_prefix    The prefix to be given to each FFDC file name generated.

    NOTE: If global variable ffdc_dir_path_style is set to ${1}, this function
    will create default values in a newer way.  Otherwise, its behavior
    will remain unchanged.
    """

    # Note: Several subordinate functions like 'Get Test Dir and Name' and
    # 'Header Message' expect global variable FFDC_TIME to be set.
    cmd_buf = ["Get Current Time Stamp"]
    grp.rdpissuing_keyword(cmd_buf)
    FFDC_TIME = BuiltIn().run_keyword(*cmd_buf)
    BuiltIn().set_global_variable("${FFDC_TIME}", FFDC_TIME)

    ffdc_dir_path_style = BuiltIn().get_variable_value(
        "${ffdc_dir_path_style}")

    if ffdc_dir_path is None:
        if ffdc_dir_path_style:
            try:
                ffdc_dir_path = os.environ['FFDC_DIR_PATH']
            except KeyError:
                ffdc_dir_path = os.path.dirname(
                    BuiltIn().get_variable_value("${LOG_FILE}")) + "/"
        else:
            FFDC_LOG_PATH = os.getcwd() + "/logs/"
            if FFDC_LOG_PATH is None:
                FFDC_LOG_PATH = ""
            if FFDC_LOG_PATH == "":
                FFDC_LOG_PATH = os.path.dirname(
                    BuiltIn().get_variable_value("${LOG_FILE}")) + "/"
            error_message = gv.svalid_value(FFDC_LOG_PATH,
                                            var_name="FFDC_LOG_PATH")
            if error_message != "":
                error_message = grp.sprint_error_report(error_message)
                BuiltIn().fail(error_message)
            FFDC_LOG_PATH = os.path.normpath(FFDC_LOG_PATH) + os.sep

            cmd_buf = ["Get Test Dir and Name"]
            grp.rpissuing_keyword(cmd_buf)
            suitename, testname = BuiltIn().run_keyword(*cmd_buf)

            ffdc_dir_path = FFDC_LOG_PATH + suitename + "/" + testname + "/"

    # Add trailing slash.
    ffdc_dir_path = os.path.normpath(ffdc_dir_path) + os.sep

    if ffdc_prefix is None:
        FFDC_TIME = BuiltIn().get_variable_value("${FFDC_TIME}")
        if ffdc_prefix is None:
            if ffdc_dir_path_style:
                OPENBMC_HOST = BuiltIn().get_variable_value("${OPENBMC_HOST}")
                OPENBMC_NICKNAME = BuiltIn().get_variable_value(
                    "${OPENBMC_NICKNAME}", default=OPENBMC_HOST)
                ffdc_prefix = OPENBMC_NICKNAME + "." + FFDC_TIME[2:8] + "." +\
                    FFDC_TIME[8:14] + "."
            else:
                ffdc_prefix = FFDC_TIME + "_"

    BuiltIn().set_global_variable("${FFDC_DIR_PATH}", ffdc_dir_path)
    BuiltIn().set_global_variable("${FFDC_PREFIX}", ffdc_prefix)

    return ffdc_dir_path, ffdc_prefix
def ffdc(ffdc_dir_path=None,
         ffdc_prefix=None,
         ffdc_function_list=""):
    r"""
    Gather First Failure Data Capture (FFDC).

    This includes:
    - Set global FFDC_TIME.
    - Create FFDC work space directory.
    - Write test info details.
    - Call BMC methods to write/collect FFDC data.

    Description of arguments:
    ffdc_dir_path       The dir path where FFDC data should be put.
    ffdc_prefix         The prefix to be given to each FFDC file name
                        generated.
    ffdc_function_list  A colon-delimited list of all the types of FFDC data
                        you wish to have collected.  A blank value means that
                        all possible kinds of FFDC are to be collected.  See
                        FFDC_METHOD_CALL object in lib/openbmc_ffdc_list.py
                        for possible choices.
    """

    ffdc_file_list = []

    # Check if Ping and SSH connection is alive
    OPENBMC_HOST = BuiltIn().get_variable_value("${OPENBMC_HOST}")

    state = st.get_state(req_states=['ping', 'uptime'])
    gp.qprint_var(state)
    if not int(state['ping']):
        gp.print_error("BMC is not ping-able.  Terminating FFDC collection.\n")
        return ffdc_file_list

    if state['uptime'] == "":
        gp.print_error("BMC is not communicating.  Terminating FFDC"
                       + " collection.\n")
        return ffdc_file_list

    gp.qprint_timen("Collecting FFDC.")

    # Get default values for arguments.
    ffdc_dir_path, ffdc_prefix = set_ffdc_defaults(ffdc_dir_path, ffdc_prefix)
    gp.qprint_var(ffdc_dir_path)
    gp.qprint_var(ffdc_prefix)

    # LOG_PREFIX is used by subordinate functions.
    LOG_PREFIX = ffdc_dir_path + ffdc_prefix
    BuiltIn().set_global_variable("${LOG_PREFIX}", LOG_PREFIX)

    cmd_buf = ["Create Directory", ffdc_dir_path]
    grp.rqpissuing_keyword(cmd_buf)
    status, output = BuiltIn().run_keyword_and_ignore_error(*cmd_buf)
    if status != "PASS":
        error_message = grp.sprint_error_report("Create Directory failed"
                                                + " with the following"
                                                + " error:\n" + output)
        BuiltIn().fail(error_message)

    # FFDC_FILE_PATH is used by Header Message.
    FFDC_FILE_PATH = ffdc_dir_path + ffdc_prefix + "BMC_general.txt"
    BuiltIn().set_global_variable("${FFDC_FILE_PATH}", FFDC_FILE_PATH)

    status, ffdc_file_list = grk.run_key("Header Message")
    status, ffdc_file_sub_list = \
        grk.run_key_u("Call FFDC Methods  ffdc_function_list="
                      + ffdc_function_list)

    # Combine lists, remove duplicates and sort.
    ffdc_file_list = sorted(set(ffdc_file_list + ffdc_file_sub_list))

    gp.qprint_timen("Finished collecting FFDC.")

    return ffdc_file_list
def rvalid_value(var_name,
                 invalid_values=[],
                 valid_values=[]):
    r"""
    Validate a robot value.

    This function is the robot wrapper for gen_robot_print.svalid_value.

    Description of arguments:
    var_name                        The name of the variable whose value is to
                                    be validated.
    invalid_values                  A list of invalid values.  If var_value is
                                    equal to any of these, it is invalid.
                                    Note that if you specify anything for
                                    invalid_values (below), the valid_values
                                    list is not even processed.
    valid_values                    A list of invalid values.  var_value must
                                    be equal to one of these values to be
                                    considered valid.

    If either the invalid_values or the valid_values parms are not of type
    "list", they will be processed as python code in order to generate a list.
    This allows the robot programmer to essentially specify a list literal.
    For example, the robot code could contain the following:

    Rvalid Value  var1  valid_values=['one', 'two']

    Examples of robot calls and corresponding output:

    Robot code...
    rvalid_value                    MY_PARM

    Output...
    #(CDT) 2016/11/02 10:04:20 - **ERROR** Variable "MY_PARM" not found (i.e.
    #it's undefined).

    or if it is defined but blank:

    Output...
    #(CDT) 2016/11/02 10:14:24 - **ERROR** The following variable has an
    #invalid value:
    MY_PARM:

    It must NOT be one of the following values:
    invalid_values:
      invalid_values[0]:         <blank>

    Robot code...
    ${invalid_values}=  Create List  one  two  three
    ${MY_PARM}=  Set Variable  one
    rvalid_value                    MY_PARM  invalid_values=${invalid_values}

    Output...
    #(CDT) 2016/11/02 10:20:05 - **ERROR** The following variable has an
    #invalid value:
    MY_PARM:                     one

    It must NOT be one of the following values:
    invalid_values:
        invalid_values[0]:       one
        invalid_values[1]:       two
        invalid_values[2]:       three

    """

    # Note: get_variable_value() seems to have no trouble with local variables.
    var_value = BuiltIn().get_variable_value("${" + var_name + "}")

    if type(valid_values) is not list:
        # Evaluate python syntax to convert to a list.
        exec("valid_values = " + valid_values)
    if type(invalid_values) is not list:
        # Evaluate python syntax to convert to a list.
        exec("invalid_values = " + invalid_values)

    if var_value is None:
        var_value = ""
        error_message = "Variable \"" + var_name +\
                        "\" not found (i.e. it's undefined).\n"
    else:
        error_message = gv.svalid_value(var_value, invalid_values,
                                        valid_values, var_name)
    if not error_message == "":
        error_message = grp.sprint_error_report(error_message)
        BuiltIn().fail(error_message)