Example #1
0
def set_default_siguser1():
    r"""
    Set the default_sigusr1 function to be the SIGUSR1 handler.
    """

    gp.printn()
    gp.print_executing()
    gp.lprint_executing()
    signal.signal(signal.SIGUSR1, default_sigusr1)
Example #2
0
def collect_service_data(verify=False):
    r"""
    Run the collect_service_data command and return a list of files generated
    by the command.

    Description of argument(s):
    verify                          If set, verify that all files which can be
                                    created by collect_service_data did, in
                                    fact, get created.
    """

    # Route the output of collect_service_data to a file for easier parsing.
    temp = tempfile.NamedTemporaryFile()
    temp_file_path = temp.name
    openbmctool_execute_command("collect_service_data > " + temp_file_path,
                                ignore_err=False)
    # Isolate the file paths in the collect_service_data output.  We're
    # looking for output lines like this from which to extract the file paths:
    # Inventory collected and stored in /tmp/dummy--2018-09-26_17.59.18/inventory.txt
    rc, file_paths = gc.shell_cmd(
        "egrep 'collected and' " + temp_file_path
        # + " | sed -re 's#.*/tmp#/tmp#g'",
        + " | sed -re 's#[^/]*/#/#'",
        quiet=1,
        print_output=0)
    # Example file_paths value:
    # /tmp/dummy--2018-09-26_17.59.18/inventory.txt
    # /tmp/dummy--2018-09-26_17.59.18/sensorReadings.txt
    # etc.
    # Convert from output to list.
    collect_service_data_file_paths =\
        list(filter(None, file_paths.split("\n")))
    if int(verify):
        # Create a list of files by stripping the dir names from the elements
        # of collect_service_data_file_paths.
        files_obtained = [
            re.sub(r".*/", "", file_path)
            for file_path in collect_service_data_file_paths
        ]
        files_expected = service_data_files()
        files_missing = list(set(files_expected) - set(files_obtained))
        if len(files_missing) > 0:
            gp.printn("collect_service_data output:\n" +
                      gm.file_to_str(temp_file_path))
            err_msg = "The following files are missing from the list of files"
            err_msg += " returned by collect_service_data:\n"
            err_msg += gp.sprint_var(files_missing)
            err_msg += gp.sprint_var(collect_service_data_file_paths)
            BuiltIn().fail(gp.sprint_error(err_msg))

    return collect_service_data_file_paths
Example #3
0
def default_sigusr1(signal_number=0, frame=None):
    r"""
    Handle SIGUSR1 by doing nothing.

    This function assists in debugging SIGUSR1 processing by printing messages
    to stdout and to the log.html file.

    Description of argument(s):
    signal_number  The signal number (should always be 10 for SIGUSR1).
    frame          The frame data.
    """

    gp.printn()
    gp.print_executing()
    gp.lprint_executing()
Example #4
0
def stop_boot_test(signal_number=0, frame=None):
    r"""
    Handle SIGUSR1 by aborting the boot test that is running.

    Description of argument(s):
    signal_number  The signal number (should always be 10 for SIGUSR1).
    frame          The frame data.
    """

    gp.printn()
    gp.print_executing()
    gp.lprint_executing()

    # Restore original sigusr1 handler.
    set_default_siguser1()

    message = "The caller has asked that the boot test be stopped and marked"
    message += " as a failure."

    function_stack = gm.get_function_stack()
    if "wait_state" in function_stack:
        st.set_exit_wait_early_message(message)
    else:
        BuiltIn().fail(gp.sprint_error(message))
Example #5
0
def wait_state(match_state=(),
               wait_time="1 min",
               interval="1 second",
               invert=0,
               openbmc_host="",
               openbmc_username="",
               openbmc_password="",
               os_host="",
               os_username="",
               os_password="",
               quiet=None):
    r"""
    Wait for the Open BMC machine's composite state to match the specified
    state.  On success, this keyword returns the machine's composite state as
    a dictionary.

    Description of argument(s):
    match_state       A dictionary whose key/value pairs are "state field"/
                      "state value".  See check_state (above) for details.
                      This value may also be any string accepted by
                      return_state_constant (e.g. "standby_match_state").
                      In such a case this function will call
                      return_state_constant to convert it to a proper
                      dictionary as described above.
    wait_time         The total amount of time to wait for the desired state.
                      This value may be expressed in Robot Framework's time
                      format (e.g. 1 minute, 2 min 3 s, 4.5).
    interval          The amount of time between state checks.
                      This value may be expressed in Robot Framework's time
                      format (e.g. 1 minute, 2 min 3 s, 4.5).
    invert            If this flag is set, this function will for the state of
                      the machine to cease to match the match state.
    openbmc_host      The DNS name or IP address of the BMC.
                      This defaults to global ${OPENBMC_HOST}.
    openbmc_username  The username to be used to login to the BMC.
                      This defaults to global ${OPENBMC_USERNAME}.
    openbmc_password  The password to be used to login to the BMC.
                      This defaults to global ${OPENBMC_PASSWORD}.
    os_host           The DNS name or IP address of the operating system.
                      This defaults to global ${OS_HOST}.
    os_username       The username to be used to login to the OS.
                      This defaults to global ${OS_USERNAME}.
    os_password       The password to be used to login to the OS.
                      This defaults to global ${OS_PASSWORD}.
    quiet             Indicates whether status details should be written to the
                      console.  Defaults to either global value of ${QUIET} or
                      to 1.
    """

    quiet = int(gp.get_var_value(quiet, 0))

    try:
        match_state = return_state_constant(match_state)
    except TypeError:
        pass

    if not quiet:
        if invert:
            alt_text = "cease to "
        else:
            alt_text = ""
        gp.print_timen("Checking every " + str(interval) + " for up to "
                       + str(wait_time) + " for the state of the machine to "
                       + alt_text + "match the state shown below.")
        gp.print_var(match_state)

    if quiet:
        print_string = ""
    else:
        print_string = "#"

    debug = int(BuiltIn().get_variable_value("${debug}", "0"))
    if debug:
        # In debug we print state so no need to print the "#".
        print_string = ""
    check_state_quiet = 1 - debug
    cmd_buf = ["Check State", match_state, "invert=${" + str(invert) + "}",
               "print_string=" + print_string, "openbmc_host=" + openbmc_host,
               "openbmc_username="******"openbmc_password="******"os_host=" + os_host,
               "os_username="******"os_password="******"quiet=${" + str(check_state_quiet) + "}"]
    gp.dprint_issuing(cmd_buf)
    try:
        state = BuiltIn().wait_until_keyword_succeeds(wait_time, interval,
                                                      *cmd_buf)
    except AssertionError as my_assertion_error:
        gp.printn()
        message = my_assertion_error.args[0]
        BuiltIn().fail(message)

    if exit_wait_early_message:
        # The global exit_wait_early_message was set by a signal handler
        # indicating that we should fail.
        message = exit_wait_early_message
        # Clear the exit_wait_early_message variable for future use.
        set_exit_wait_early_message("")
        BuiltIn().fail(gp.sprint_error(message))

    if not quiet:
        gp.printn()
        if invert:
            gp.print_timen("The states no longer match:")
        else:
            gp.print_timen("The states match:")
        gp.print_var(state)

    return state
def print_defect_report():

    r"""
    Print a defect report.
    """

    # Making deliberate choice to NOT run plug_in_setup().  We don't want
    # ffdc_prefix updated.
    rc, shell_rc, failed_plug_in_name = grpi.rprocess_plug_in_packages(
        call_point='ffdc_report', stop_on_plug_in_failure=0)

    # At some point I'd like to have the 'Call FFDC Methods' return a list
    # of files it has collected.  In that case, the following "ls" command
    # would no longer be needed.  For now, however, glob shows the files
    # named in FFDC_LIST_FILE_PATH so I will refrain from printing those
    # out (so we don't see duplicates in the list).

    # Get additional header data which may have been created by ffdc plug-ins.
    # Also, delete the individual header files to cleanup.
    cmd_buf = "file_list=$(cat " + ffdc_report_list_path + " 2>/dev/null)" +\
              " ; [ ! -z \"${file_list}\" ] && cat ${file_list}" +\
              " 2>/dev/null ; rm -rf ${file_list} 2>/dev/null || :"
    shell_rc, more_header_info = gc.cmd_fnc_u(cmd_buf, print_output=0,
                                              show_err=0)

    # Get additional header data which may have been created by ffdc plug-ins.
    # Also, delete the individual header files to cleanup.
    cmd_buf = "file_list=$(cat " + ffdc_summary_list_path + " 2>/dev/null)" +\
              " ; [ ! -z \"${file_list}\" ] && cat ${file_list}" +\
              " 2>/dev/null ; rm -rf ${file_list} 2>/dev/null || :"
    shell_rc, ffdc_summary_info = gc.cmd_fnc_u(cmd_buf, print_output=0,
                                               show_err=0)

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

    output = '\n'.join(sorted(glob.glob(LOG_PREFIX + '*')))
    try:
        ffdc_list = open(ffdc_list_file_path, 'r')
    except IOError:
        ffdc_list = ""

    # Open ffdc_file_list for writing.  We will write a complete list of
    # FFDC files to it for possible use by plug-ins like cp_stop_check.
    ffdc_list_file = open(ffdc_list_file_path, 'w')

    gp.qprintn()
    # indent=0, width=90, linefeed=1, char="="
    gp.qprint_dashes(0, 90, 1, "=")
    gp.qprintn("Copy this data to the defect:\n")

    if len(more_header_info) > 0:
        gp.printn(more_header_info)
    gp.qpvars(host_name, host_ip, openbmc_nickname, openbmc_host,
              openbmc_host_name, openbmc_ip, openbmc_username,
              openbmc_password, os_host, os_host_name, os_ip, os_username,
              os_password, pdu_host, pdu_host_name, pdu_ip, pdu_username,
              pdu_password, pdu_slot_no, openbmc_serial_host,
              openbmc_serial_host_name, openbmc_serial_ip, openbmc_serial_port)

    gp.qprintn()

    print_last_boots()
    gp.qprintn()
    gp.qprint_var(state)

    gp.qprintn()
    gp.qprintn("FFDC data files:")
    if status_file_path != "":
        gp.qprintn(status_file_path)
        ffdc_list_file.write(status_file_path + "\n")

    gp.qprintn(output)
    # gp.qprintn(ffdc_list)
    gp.qprintn()

    if len(ffdc_summary_info) > 0:
        gp.printn(ffdc_summary_info)

    gp.qprint_dashes(0, 90, 1, "=")

    ffdc_list_file.write(output + "\n")
    ffdc_list_file.close()
def select_boot():

    r"""
    Select a boot test to be run based on our current state and return the
    chosen boot type.

    Description of arguments:
    state  The state of the machine.
    """

    global boot_stack

    gp.qprint_timen("Selecting a boot test.")

    my_get_state()

    stack_popped = 0
    if len(boot_stack) > 0:
        stack_popped = 1
        gp.qprint_dashes()
        gp.qprint_var(boot_stack)
        gp.qprint_dashes()
        skip_boot_printed = 0
        while len(boot_stack) > 0:
            boot_candidate = boot_stack.pop()
            if stack_mode == 'normal':
                break
            else:
                if st.compare_states(state, boot_table[boot_candidate]['end']):
                    if not skip_boot_printed:
                        gp.print_var(stack_mode)
                        gp.printn()
                        gp.print_timen("Skipping the following boot tests" +
                                       " which are unnecessary since their" +
                                       " required end states match the" +
                                       " current machine state:")
                        skip_boot_printed = 1
                    gp.print_var(boot_candidate)
                    boot_candidate = ""
        if boot_candidate == "":
            gp.qprint_dashes()
            gp.qprint_var(boot_stack)
            gp.qprint_dashes()
            return boot_candidate
        if st.compare_states(state, boot_table[boot_candidate]['start']):
            gp.qprint_timen("The machine state is valid for a '" +
                            boot_candidate + "' boot test.")
            gp.qprint_dashes()
            gp.qprint_var(boot_stack)
            gp.qprint_dashes()
            return boot_candidate
        else:
            gp.qprint_timen("The machine state does not match the required" +
                            " starting state for a '" + boot_candidate +
                            "' boot test:")
            gp.print_varx("boot_table[" + boot_candidate + "][start]",
                          boot_table[boot_candidate]['start'], 1)
            boot_stack.append(boot_candidate)
            popped_boot = boot_candidate

    # Loop through your list selecting a boot_candidates
    boot_candidates = []
    for boot_candidate in boot_list:
        if st.compare_states(state, boot_table[boot_candidate]['start']):
            if stack_popped:
                if st.compare_states(boot_table[boot_candidate]['end'],
                   boot_table[popped_boot]['start']):
                    boot_candidates.append(boot_candidate)
            else:
                boot_candidates.append(boot_candidate)

    if len(boot_candidates) == 0:
        gp.qprint_timen("The user's boot list contained no boot tests" +
                        " which are valid for the current machine state.")
        boot_candidate = default_power_on
        if not st.compare_states(state, boot_table[default_power_on]['start']):
            boot_candidate = default_power_off
        boot_candidates.append(boot_candidate)
        gp.qprint_timen("Using default '" + boot_candidate +
                        "' boot type to transition to valid state.")

    gp.dprint_var(boot_candidates)

    # Randomly select a boot from the candidate list.
    boot = random.choice(boot_candidates)

    return boot
def execute_ssh_command(cmd_buf,
                        open_connection_args={},
                        login_args={},
                        print_out=0,
                        print_err=0,
                        ignore_err=1,
                        fork=0,
                        quiet=None,
                        test_mode=None):
    r"""
    Run the given command in an SSH session and return the stdout, stderr and
    the return code.

    If there is no open SSH connection, this function will connect and login.
    Likewise, if the caller has not yet logged in to the connection, this
    function will do the login.

    NOTE: There is special handling when open_connection_args['alias'] equals
    "device_connection".
    - A write, rather than an execute_command, is done.
    - Only stdout is returned (no stderr or rc).
    - print_err, ignore_err and fork are not supported.

    Description of arguments:
    cmd_buf                         The command string to be run in an SSH
                                    session.
    open_connection_args            A dictionary of arg names and values which
                                    are legal to pass to the SSHLibrary
                                    open_connection function as parms/args.
                                    At a minimum, this should contain a 'host'
                                    entry.
    login_args                      A dictionary containing the key/value
                                    pairs which are acceptable to the
                                    SSHLibrary login function as parms/args.
                                    At a minimum, this should contain a
                                    'username' and a 'password' entry.
    print_out                       If this is set, this function will print
                                    the stdout/stderr generated by the shell
                                    command.
    print_err                       If show_err is set, this function will
                                    print a standardized error report if the
                                    shell command returns non-zero.
    ignore_err                      Indicates that errors encountered on the
                                    sshlib.execute_command are to be ignored.
    fork                            Indicates that sshlib.start is to be used
                                    rather than sshlib.execute_command.
    quiet                           Indicates whether this function should run
                                    the pissuing() function which prints an
                                    "Issuing: <cmd string>" to stdout.  This
                                    defaults to the global quiet value.
    test_mode                       If test_mode is set, this function will
                                    not actually run the command.  This
                                    defaults to the global test_mode value.
    """

    gp.lprint_executing()

    # Obtain default values.
    quiet = int(gp.get_var_value(quiet, 0))
    test_mode = int(gp.get_var_value(test_mode, 0))

    if not quiet:
        gp.pissuing(cmd_buf, test_mode)
    gp.lpissuing(cmd_buf, test_mode)

    if test_mode:
        return "", "", 0

    global sshlib

    max_exec_cmd_attempts = 2
    # Look for existing SSH connection.
    # Prepare a search connection dictionary.
    search_connection_args = open_connection_args.copy()
    # Remove keys that don't work well for searches.
    search_connection_args.pop("timeout", None)
    connection = find_connection(search_connection_args)
    if connection:
        gp.lprint_timen("Found the following existing connection:")
        gp.lprintn(sprint_connection(connection))
        if connection.alias == "":
            index_or_alias = connection.index
        else:
            index_or_alias = connection.alias
        gp.lprint_timen("Switching to existing connection: \""
                        + str(index_or_alias) + "\".")
        sshlib.switch_connection(index_or_alias)
    else:
        gp.lprint_timen("Connecting to " + open_connection_args['host'] + ".")
        cix = sshlib.open_connection(**open_connection_args)
        try:
            login_ssh(login_args)
        except Exception as login_exception:
            except_type, except_value, except_traceback = sys.exc_info()
            rc = 1
            stderr = str(except_value)
            stdout = ""
            max_exec_cmd_attempts = 0

    for exec_cmd_attempt_num in range(1, max_exec_cmd_attempts + 1):
        gp.lprint_var(exec_cmd_attempt_num)
        try:
            if fork:
                sshlib.start_command(cmd_buf)
            else:
                if open_connection_args['alias'] == "device_connection":
                    stdout = sshlib.write(cmd_buf)
                    stderr = ""
                    rc = 0
                else:
                    stdout, stderr, rc = \
                        sshlib.execute_command(cmd_buf,
                                               return_stdout=True,
                                               return_stderr=True,
                                               return_rc=True)
        except Exception as execute_exception:
            except_type, except_value, except_traceback = sys.exc_info()
            gp.lprint_var(except_type)
            gp.lprint_varx("except_value", str(except_value))

            if except_type is exceptions.AssertionError and\
               re.match(r"Connection not open", str(except_value)):
                login_ssh(login_args)
                # Now we must continue to next loop iteration to retry the
                # execute_command.
                continue
            if (except_type is paramiko.ssh_exception.SSHException
                and re.match(r"SSH session not active", str(except_value))) or\
               (except_type is socket.error
                and re.match(r"\[Errno 104\] Connection reset by peer",
                             str(except_value))):
                # Close and re-open a connection.
                # Note: close_connection() doesn't appear to get rid of the
                # connection.  It merely closes it.  Since there is a concern
                # about over-consumption of resources, we use
                # close_all_connections() which also gets rid of all
                # connections.
                gp.lprint_timen("Closing all connections.")
                sshlib.close_all_connections()
                gp.lprint_timen("Connecting to "
                                + open_connection_args['host'] + ".")
                cix = sshlib.open_connection(**open_connection_args)
                login_ssh(login_args)
                continue

            # We do not handle any other RuntimeErrors so we will raise the
            # exception again.
            sshlib.close_all_connections()
            raise(execute_exception)

        # If we get to this point, the command was executed.
        break

    if fork:
        return

    if rc != 0 and print_err:
        gp.print_var(rc, 1)
        if not print_out:
            gp.print_var(stderr)
            gp.print_var(stdout)

    if print_out:
        gp.printn(stderr + stdout)

    if not ignore_err:
        message = gp.sprint_error("The prior SSH"
                                  + " command returned a non-zero return"
                                  + " code:\n" + gp.sprint_var(rc, 1) + stderr
                                  + "\n")
        BuiltIn().should_be_equal(rc, 0, message)

    if open_connection_args['alias'] == "device_connection":
        return stdout
    return stdout, stderr, rc
def print_defect_report():
    r"""
    Print a defect report.
    """

    # Making deliberate choice to NOT run plug_in_setup().  We don't want
    # ffdc_prefix updated.
    rc, shell_rc, failed_plug_in_name = grpi.rprocess_plug_in_packages(
        call_point='ffdc_report', stop_on_plug_in_failure=0)

    # At some point I'd like to have the 'Call FFDC Methods' return a list
    # of files it has collected.  In that case, the following "ls" command
    # would no longer be needed.  For now, however, glob shows the files
    # named in FFDC_LIST_FILE_PATH so I will refrain from printing those
    # out (so we don't see duplicates in the list).

    # Get additional header data which may have been created by ffdc plug-ins.
    # Also, delete the individual header files to cleanup.
    cmd_buf = "file_list=$(cat " + ffdc_report_list_path + " 2>/dev/null)" +\
              " ; [ ! -z \"${file_list}\" ] && cat ${file_list}" +\
              " 2>/dev/null ; rm -rf ${file_list} 2>/dev/null || :"
    shell_rc, more_header_info = gc.cmd_fnc_u(cmd_buf,
                                              print_output=0,
                                              show_err=0)

    # Get additional header data which may have been created by ffdc plug-ins.
    # Also, delete the individual header files to cleanup.
    cmd_buf = "file_list=$(cat " + ffdc_summary_list_path + " 2>/dev/null)" +\
              " ; [ ! -z \"${file_list}\" ] && cat ${file_list}" +\
              " 2>/dev/null ; rm -rf ${file_list} 2>/dev/null || :"
    shell_rc, ffdc_summary_info = gc.cmd_fnc_u(cmd_buf,
                                               print_output=0,
                                               show_err=0)

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

    output = '\n'.join(sorted(glob.glob(LOG_PREFIX + '*')))
    try:
        ffdc_list = open(ffdc_list_file_path, 'r')
    except IOError:
        ffdc_list = ""

    # Open ffdc_file_list for writing.  We will write a complete list of
    # FFDC files to it for possible use by plug-ins like cp_stop_check.
    ffdc_list_file = open(ffdc_list_file_path, 'w')

    gp.qprintn()
    # indent=0, width=90, linefeed=1, char="="
    gp.qprint_dashes(0, 90, 1, "=")
    gp.qprintn("Copy this data to the defect:\n")

    if len(more_header_info) > 0:
        gp.printn(more_header_info)
    gp.qpvars(host_name, host_ip, openbmc_nickname, openbmc_host,
              openbmc_host_name, openbmc_ip, openbmc_username,
              openbmc_password, os_host, os_host_name, os_ip, os_username,
              os_password, pdu_host, pdu_host_name, pdu_ip, pdu_username,
              pdu_password, pdu_slot_no, openbmc_serial_host,
              openbmc_serial_host_name, openbmc_serial_ip, openbmc_serial_port)

    gp.qprintn()

    print_last_boots()
    gp.qprintn()
    gp.qprint_var(state)

    gp.qprintn()
    gp.qprintn("FFDC data files:")
    if status_file_path != "":
        gp.qprintn(status_file_path)
        ffdc_list_file.write(status_file_path + "\n")

    gp.qprintn(output)
    # gp.qprintn(ffdc_list)
    gp.qprintn()

    if len(ffdc_summary_info) > 0:
        gp.printn(ffdc_summary_info)

    gp.qprint_dashes(0, 90, 1, "=")

    ffdc_list_file.write(output + "\n")
    ffdc_list_file.close()
def select_boot():
    r"""
    Select a boot test to be run based on our current state and return the
    chosen boot type.

    Description of arguments:
    state  The state of the machine.
    """

    global boot_stack

    gp.qprint_timen("Selecting a boot test.")

    my_get_state()

    stack_popped = 0
    if len(boot_stack) > 0:
        stack_popped = 1
        gp.qprint_dashes()
        gp.qprint_var(boot_stack)
        gp.qprint_dashes()
        skip_boot_printed = 0
        while len(boot_stack) > 0:
            boot_candidate = boot_stack.pop()
            if stack_mode == 'normal':
                break
            else:
                if st.compare_states(state, boot_table[boot_candidate]['end']):
                    if not skip_boot_printed:
                        gp.print_var(stack_mode)
                        gp.printn()
                        gp.print_timen("Skipping the following boot tests" +
                                       " which are unnecessary since their" +
                                       " required end states match the" +
                                       " current machine state:")
                        skip_boot_printed = 1
                    gp.print_var(boot_candidate)
                    boot_candidate = ""
        if boot_candidate == "":
            gp.qprint_dashes()
            gp.qprint_var(boot_stack)
            gp.qprint_dashes()
            return boot_candidate
        if st.compare_states(state, boot_table[boot_candidate]['start']):
            gp.qprint_timen("The machine state is valid for a '" +
                            boot_candidate + "' boot test.")
            gp.qprint_dashes()
            gp.qprint_var(boot_stack)
            gp.qprint_dashes()
            return boot_candidate
        else:
            gp.qprint_timen("The machine state does not match the required" +
                            " starting state for a '" + boot_candidate +
                            "' boot test:")
            gp.print_varx("boot_table[" + boot_candidate + "][start]",
                          boot_table[boot_candidate]['start'], 1)
            boot_stack.append(boot_candidate)
            popped_boot = boot_candidate

    # Loop through your list selecting a boot_candidates
    boot_candidates = []
    for boot_candidate in boot_list:
        if st.compare_states(state, boot_table[boot_candidate]['start']):
            if stack_popped:
                if st.compare_states(boot_table[boot_candidate]['end'],
                                     boot_table[popped_boot]['start']):
                    boot_candidates.append(boot_candidate)
            else:
                boot_candidates.append(boot_candidate)

    if len(boot_candidates) == 0:
        gp.qprint_timen("The user's boot list contained no boot tests" +
                        " which are valid for the current machine state.")
        boot_candidate = default_power_on
        if not st.compare_states(state, boot_table[default_power_on]['start']):
            boot_candidate = default_power_off
        boot_candidates.append(boot_candidate)
        gp.qprint_timen("Using default '" + boot_candidate +
                        "' boot type to transition to valid state.")

    gp.dprint_var(boot_candidates)

    # Randomly select a boot from the candidate list.
    boot = random.choice(boot_candidates)

    return boot
def execute_ssh_command(cmd_buf,
                        open_connection_args={},
                        login_args={},
                        print_out=0,
                        print_err=0,
                        ignore_err=1,
                        fork=0,
                        quiet=None,
                        test_mode=None,
                        time_out=None):
    r"""
    Run the given command in an SSH session and return the stdout, stderr and
    the return code.

    If there is no open SSH connection, this function will connect and login.
    Likewise, if the caller has not yet logged in to the connection, this
    function will do the login.

    NOTE: There is special handling when open_connection_args['alias'] equals
    "device_connection".
    - A write, rather than an execute_command, is done.
    - Only stdout is returned (no stderr or rc).
    - print_err, ignore_err and fork are not supported.

    Description of arguments:
    cmd_buf                         The command string to be run in an SSH
                                    session.
    open_connection_args            A dictionary of arg names and values which
                                    are legal to pass to the SSHLibrary
                                    open_connection function as parms/args.
                                    At a minimum, this should contain a 'host'
                                    entry.
    login_args                      A dictionary containing the key/value
                                    pairs which are acceptable to the
                                    SSHLibrary login function as parms/args.
                                    At a minimum, this should contain a
                                    'username' and a 'password' entry.
    print_out                       If this is set, this function will print
                                    the stdout/stderr generated by the shell
                                    command.
    print_err                       If show_err is set, this function will
                                    print a standardized error report if the
                                    shell command returns non-zero.
    ignore_err                      Indicates that errors encountered on the
                                    sshlib.execute_command are to be ignored.
    fork                            Indicates that sshlib.start is to be used
                                    rather than sshlib.execute_command.
    quiet                           Indicates whether this function should run
                                    the pissuing() function which prints an
                                    "Issuing: <cmd string>" to stdout.  This
                                    defaults to the global quiet value.
    test_mode                       If test_mode is set, this function will
                                    not actually run the command.  This
                                    defaults to the global test_mode value.
    time_out                        The amount of time to allow for the
                                    execution of cmd_buf.  A value of None
                                    means that there is no limit to how long
                                    the command may take.
    """

    gp.lprint_executing()

    # Obtain default values.
    quiet = int(gp.get_var_value(quiet, 0))
    test_mode = int(gp.get_var_value(test_mode, 0))

    if not quiet:
        gp.pissuing(cmd_buf, test_mode)
    gp.lpissuing(cmd_buf, test_mode)

    if test_mode:
        return "", "", 0

    global sshlib

    max_exec_cmd_attempts = 2
    # Look for existing SSH connection.
    # Prepare a search connection dictionary.
    search_connection_args = open_connection_args.copy()
    # Remove keys that don't work well for searches.
    search_connection_args.pop("timeout", None)
    connection = find_connection(search_connection_args)
    if connection:
        gp.lprint_timen("Found the following existing connection:")
        gp.lprintn(sprint_connection(connection))
        if connection.alias == "":
            index_or_alias = connection.index
        else:
            index_or_alias = connection.alias
        gp.lprint_timen("Switching to existing connection: \"" +
                        str(index_or_alias) + "\".")
        sshlib.switch_connection(index_or_alias)
    else:
        gp.lprint_timen("Connecting to " + open_connection_args['host'] + ".")
        cix = sshlib.open_connection(**open_connection_args)
        try:
            login_ssh(login_args)
        except Exception:
            except_type, except_value, except_traceback = sys.exc_info()
            rc = 1
            stderr = str(except_value)
            stdout = ""
            max_exec_cmd_attempts = 0

    for exec_cmd_attempt_num in range(1, max_exec_cmd_attempts + 1):
        gp.lprint_var(exec_cmd_attempt_num)
        try:
            if fork:
                sshlib.start_command(cmd_buf)
            else:
                if open_connection_args['alias'] == "device_connection":
                    stdout = sshlib.write(cmd_buf)
                    stderr = ""
                    rc = 0
                else:
                    stdout, stderr, rc = \
                        func_timer.run(sshlib.execute_command,
                                       cmd_buf,
                                       return_stdout=True,
                                       return_stderr=True,
                                       return_rc=True,
                                       time_out=time_out)
        except Exception:
            except_type, except_value, except_traceback = sys.exc_info()
            gp.lprint_var(except_type)
            gp.lprint_varx("except_value", str(except_value))
            # This may be our last time through the retry loop, so setting
            # return variables.
            rc = 1
            stderr = str(except_value)
            stdout = ""

            if except_type is exceptions.AssertionError and\
               re.match(r"Connection not open", str(except_value)):
                try:
                    login_ssh(login_args)
                    # Now we must continue to next loop iteration to retry the
                    # execute_command.
                    continue
                except Exception:
                    except_type, except_value, except_traceback =\
                        sys.exc_info()
                    rc = 1
                    stderr = str(except_value)
                    stdout = ""
                    break

            if (except_type is paramiko.ssh_exception.SSHException
                and re.match(r"SSH session not active", str(except_value))) or\
               (except_type is socket.error
                and re.match(r"\[Errno 104\] Connection reset by peer",
                             str(except_value))) or\
               (except_type is paramiko.ssh_exception.SSHException
                and re.match(r"Timeout opening channel\.",
                             str(except_value))):
                # Close and re-open a connection.
                # Note: close_connection() doesn't appear to get rid of the
                # connection.  It merely closes it.  Since there is a concern
                # about over-consumption of resources, we use
                # close_all_connections() which also gets rid of all
                # connections.
                gp.lprint_timen("Closing all connections.")
                sshlib.close_all_connections()
                gp.lprint_timen("Connecting to " +
                                open_connection_args['host'] + ".")
                cix = sshlib.open_connection(**open_connection_args)
                login_ssh(login_args)
                continue

            # We do not handle any other RuntimeErrors so we will raise the
            # exception again.
            sshlib.close_all_connections()
            gp.lprintn(traceback.format_exc())
            raise (except_value)

        # If we get to this point, the command was executed.
        break

    if fork:
        return

    if rc != 0 and print_err:
        gp.print_var(rc, gp.hexa())
        if not print_out:
            gp.print_var(stderr)
            gp.print_var(stdout)

    if print_out:
        gp.printn(stderr + stdout)

    if not ignore_err:
        message = gp.sprint_error("The prior SSH" +
                                  " command returned a non-zero return" +
                                  " code:\n" + gp.sprint_var(rc, gp.hexa()) +
                                  stderr + "\n")
        BuiltIn().should_be_equal(rc, 0, message)

    if open_connection_args['alias'] == "device_connection":
        return stdout
    return stdout, stderr, rc
Example #12
0
def execute_ssh_command(cmd_buf,
                        open_connection_args={},
                        login_args={},
                        print_out=0,
                        print_err=0,
                        ignore_err=1,
                        fork=0,
                        quiet=None,
                        test_mode=None):

    r"""
    Run the given command in an SSH session and return the stdout, stderr and
    the return code.

    If there is no open SSH connection, this function will connect and login.
    Likewise, if the caller has not yet logged in to the connection, this
    function will do the login.

    Description of arguments:
    cmd_buf                         The command string to be run in an SSH
                                    session.
    open_connection_args            A dictionary of arg names and values which
                                    are legal to pass to the SSHLibrary
                                    open_connection function as parms/args.
                                    At a minimum, this should contain a 'host'
                                    entry.
    login_args                      A dictionary containing the key/value
                                    pairs which are acceptable to the
                                    SSHLibrary login function as parms/args.
                                    At a minimum, this should contain a
                                    'username' and a 'password' entry.
    print_out                       If this is set, this function will print
                                    the stdout/stderr generated by the shell
                                    command.
    print_err                       If show_err is set, this function will
                                    print a standardized error report if the
                                    shell command returns non-zero.
    ignore_err                      Indicates that errors encountered on the
                                    sshlib.execute_command are to be ignored.
    fork                            Indicates that sshlib.start is to be used
                                    rather than sshlib.execute_command.
    quiet                           Indicates whether this function should run
                                    the pissuing() function which prints an
                                    "Issuing: <cmd string>" to stdout.  This
                                    defaults to the global quiet value.
    test_mode                       If test_mode is set, this function will
                                    not actually run the command.  This
                                    defaults to the global test_mode value.
    """

    gp.dprint_executing()

    # Obtain default values.
    quiet = int(gp.get_var_value(quiet, 0))
    test_mode = int(gp.get_var_value(test_mode, 0))

    if not quiet:
        gp.pissuing(cmd_buf, test_mode)

    if test_mode:
        return "", "", 0

    global sshlib

    # Look for existing SSH connection.
    # Prepare a search connection dictionary.
    search_connection_args = open_connection_args.copy()
    # Remove keys that don't work well for searches.
    search_connection_args.pop("timeout", None)
    connection = find_connection(search_connection_args)
    if connection:
        gp.dprint_timen("Found the following existing connection:")
        gp.dprintn(sprint_connection(connection))
        if connection.alias == "":
            index_or_alias = connection.index
        else:
            index_or_alias = connection.alias
        gp.dprint_timen("Switching to existing connection: \"" +
                        str(index_or_alias) + "\".")
        sshlib.switch_connection(index_or_alias)
    else:
        gp.dprint_timen("Connecting to " + open_connection_args['host'] + ".")
        cix = sshlib.open_connection(**open_connection_args)
        login_ssh(login_args)

    max_exec_cmd_attempts = 2
    for exec_cmd_attempt_num in range(1, max_exec_cmd_attempts + 1):
        gp.dprint_var(exec_cmd_attempt_num)
        try:
            if fork:
                sshlib.start_command(cmd_buf)
            else:
                stdout, stderr, rc = sshlib.execute_command(cmd_buf,
                                                            return_stdout=True,
                                                            return_stderr=True,
                                                            return_rc=True)
        except Exception as execute_exception:
            except_type, except_value, except_traceback = sys.exc_info()
            gp.dprint_var(except_type)
            gp.dprint_varx("except_value", str(except_value))

            if except_type is exceptions.AssertionError and\
               re.match(r"Connection not open", str(except_value)):
                login_ssh(login_args)
                # Now we must continue to next loop iteration to retry the
                # execute_command.
                continue
            if except_type is paramiko.ssh_exception.SSHException and\
               re.match(r"SSH session not active", str(except_value)):
                # Close and re-open a connection.
                sshlib.close_connection()
                gp.dprint_timen("Connecting to " +
                                open_connection_args['host'] + ".")
                cix = sshlib.open_connection(**open_connection_args)
                login_ssh(login_args)
                continue

            # We do not handle any other RuntimeErrors so we will raise the
            # exception again.
            raise(execute_exception)

        # If we get to this point, the command was executed.
        break

    if fork:
        return

    if rc != 0 and print_err:
        gp.print_var(rc, 1)
        if not print_out:
            gp.print_var(stderr)
            gp.print_var(stdout)

    if print_out:
        gp.printn(stderr + stdout)

    if not ignore_err:
        message = gp.sprint_error("The prior SSH" +
                                  " command returned a non-zero return" +
                                  " code:\n" + gp.sprint_var(rc, 1) + stderr +
                                  "\n")
        BuiltIn().should_be_equal(rc, 0, message)

    return stdout, stderr, rc