def set_term_options(**kwargs): r""" Set the global term_options. If the global term_options is not None, gen_exit_function() will call terminate_descendants(). Description of arguments(): kwargs Supported keyword options follow: term_requests Requests to terminate specified descendants of this program. The following values for term_requests are supported: children Terminate the direct children of this program. descendants Terminate all descendants of this program. <dictionary> A dictionary with support for the following keys: pgm_names A list of program names which will be used to identify which descendant processes should be terminated. """ global term_options # Validation: arg_names = list(kwargs.keys()) gv.valid_list(arg_names, ['term_requests']) if type(kwargs['term_requests']) is dict: keys = list(kwargs['term_requests'].keys()) gv.valid_list(keys, ['pgm_names']) else: gv.valid_value(kwargs['term_requests'], ['children', 'descendants']) term_options = kwargs
def device_write(cmd_buf, print_out=0, quiet=None, test_mode=None): r""" Write the given command in a device SSH session and return the stdout, stderr and the return code. This function is useful for writing to a switch. This function will obtain the global values for DEVICE_HOST, DEVICE_USERNAME, etc. Description of arguments: cmd_buf The command string to be run in an SSH session. 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 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. """ # Get global DEVICE variable values. device_host = BuiltIn().get_variable_value("${DEVICE_HOST}", default="") device_username = BuiltIn().get_variable_value("${DEVICE_USERNAME}", default="") device_password = BuiltIn().get_variable_value("${DEVICE_PASSWORD}", default="") device_port = BuiltIn().get_variable_value("${DEVICE_PORT}", default="22") if not gv.valid_value(device_host): return "", "", 1 if not gv.valid_value(device_username): return "", "", 1 if not gv.valid_value(device_password): return "", "", 1 if not gv.valid_value(device_port): return "", "", 1 open_connection_args = {'host': device_host, 'alias': 'device_connection', 'port': device_port} login_args = {'username': device_username, 'password': device_password} return grs.execute_ssh_command(cmd_buf, open_connection_args, login_args, print_out, print_err=0, ignore_err=1, fork=0, quiet=quiet, test_mode=test_mode)
def os_execute_command(cmd_buf, print_out=0, print_err=0, ignore_err=0, fork=0, quiet=None, test_mode=None, time_out=None): r""" Run the given command in an OS SSH session and return the stdout, stderr and the return code. This function will obtain the global values for OS_HOST, OS_USERNAME, etc. Description of arguments: cmd_buf The command string to be run in an SSH session. 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 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. """ # Get global OS variable values. os_host = BuiltIn().get_variable_value("${OS_HOST}", default="") os_username = BuiltIn().get_variable_value("${OS_USERNAME}", default="") os_password = BuiltIn().get_variable_value("${OS_PASSWORD}", default="") if not gv.valid_value(os_host): return "", "", 1 if not gv.valid_value(os_username): return "", "", 1 if not gv.valid_value(os_password): return "", "", 1 open_connection_args = {'host': os_host, 'alias': 'os_connection'} login_args = {'username': os_username, 'password': os_password} return grs.execute_ssh_command(cmd_buf, open_connection_args, login_args, print_out, print_err, ignore_err, fork, quiet, test_mode, time_out)
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. """ gv.valid_value(robot_file_path) 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 + "\"" shell_rc, out_buf = gc.shell_cmd(cmd_buf, quiet=(not debug), print_output=0) robot_file_search_paths = out_buf gp.dprint_var(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) gv.valid_file_path(robot_file_path) return robot_file_path
def login(self): r""" Login and return session object. """ http_header = {'Content-Type': 'application/json'} session = requests.session() response = session.post('https://' + self.__host + '/login', headers=http_header, json={"data": [self.__user, self.__password]}, verify=False, timeout=30) gv.valid_value(response.status_code, valid_values=[200]) login_response = json.loads(response.text) gp.qprint_var(login_response) gv.valid_value(login_response['status'], valid_values=['ok']) return session
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 + "\"" shell_rc, out_buf = gc.shell_cmd(cmd_buf, quiet=(not debug), print_output=0) robot_file_search_paths = out_buf gp.dprint_var(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 compare_states(state, match_state, match_type='and'): r""" Compare 2 state dictionaries. Return True if they match and False if they don't. Note that the match_state dictionary does not need to have an entry corresponding to each entry in the state dictionary. But for each entry that it does have, the corresponding state entry will be checked for a match. Description of arguments: state A state dictionary such as the one returned by the get_state function. match_state A dictionary whose key/value pairs are "state field"/ "state value". The state value is interpreted as a regular expression. Every value in this dictionary is considered. When match_type is 'and', if each and every comparison matches, the two dictionaries are considered to be matching. If match_type is 'or', if any two of the elements compared match, the two dictionaries are considered to be matching. 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. match_type This may be 'and' or 'or'. """ error_message = gv.valid_value(match_type, var_name="match_type", valid_values=['and', 'or']) if error_message != "": BuiltIn().fail(gp.sprint_error(error_message)) try: match_state = return_state_constant(match_state) except TypeError: pass default_match = (match_type == 'and') for key, match_state_value in match_state.items(): # Blank match_state_value means "don't care". if match_state_value == "": continue try: match = (re.match(match_state_value, str(state[key])) is not None) except KeyError: match = False if match != default_match: return match return default_match
def valid_boot_list(boot_list, valid_boot_types): r""" Verify that each entry in boot_list is a supported boot test. Description of argument(s): boot_list An array (i.e. list) of boot test types (e.g. "REST Power On"). valid_boot_types A list of valid boot types such as that returned by create_valid_boot_list. """ for boot_name in boot_list: boot_name = boot_name.strip(" ") error_message = gv.valid_value(boot_name, valid_values=valid_boot_types, var_name="boot_name") if error_message != "": BuiltIn().fail(gp.sprint_error(error_message))
def valid_var_name(var_name): r""" Validate the robot variable name and return its value. If the variable is undefined, this function will print an error message and call BuiltIn().fail(). Description of arguments(): var_name The name of the robot variable (e.g. "var1"). Do not include "${}" (e.g. "${var1}". Just provide the simple name of the variable. """ # 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 = "<undefined>" error_message = gv.valid_value(var_value, invalid_values=[var_value], var_name=var_name) BuiltIn().fail(error_message) return var_value
def get_state(openbmc_host="", openbmc_username="", openbmc_password="", os_host="", os_username="", os_password="", req_states=default_req_states, quiet=None): r""" Get component states such as chassis state, bmc state, etc, put them into a dictionary and return them to the caller. Note that all substate values are strings. Note: If elapsed_boot_time is included in req_states, it is the caller's duty to call set_start_boot_seconds() in order to set global start_boot_seconds. elapsed_boot_time is the current time minus start_boot_seconds. Description of argument(s): 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}. req_states This is a list of states whose values are being requested by the caller. quiet Indicates whether status details (e.g. curl commands) should be written to the console. Defaults to either global value of ${QUIET} or to 1. """ quiet = int(gp.get_var_value(quiet, 0)) # Set parm defaults where necessary and validate all parms. if openbmc_host == "": openbmc_host = BuiltIn().get_variable_value("${OPENBMC_HOST}") error_message = gv.valid_value(openbmc_host, invalid_values=[None, ""]) if error_message != "": BuiltIn().fail(gp.sprint_error(error_message)) if openbmc_username == "": openbmc_username = BuiltIn().get_variable_value("${OPENBMC_USERNAME}") error_message = gv.valid_value(openbmc_username, invalid_values=[None, ""]) if error_message != "": BuiltIn().fail(gp.sprint_error(error_message)) if openbmc_password == "": openbmc_password = BuiltIn().get_variable_value("${OPENBMC_PASSWORD}") error_message = gv.valid_value(openbmc_password, invalid_values=[None, ""]) if error_message != "": BuiltIn().fail(gp.sprint_error(error_message)) # NOTE: OS parms are optional. if os_host == "": os_host = BuiltIn().get_variable_value("${OS_HOST}") if os_host is None: os_host = "" if os_username is "": os_username = BuiltIn().get_variable_value("${OS_USERNAME}") if os_username is None: os_username = "" if os_password is "": os_password = BuiltIn().get_variable_value("${OS_PASSWORD}") if os_password is None: os_password = "" invalid_req_states = [sub_state for sub_state in req_states if sub_state not in valid_req_states] if len(invalid_req_states) > 0: error_message = "The following req_states are not supported:\n" +\ gp.sprint_var(invalid_req_states) BuiltIn().fail(gp.sprint_error(error_message)) # Initialize all substate values supported by this function. ping = 0 packet_loss = '' uptime = '' epoch_seconds = '' elapsed_boot_time = '' rest = '' chassis = '' requested_chassis = '' bmc = '' requested_bmc = '' boot_progress = '' operating_system = '' host = '' requested_host = '' attempts_left = '' # Get the component states. if 'ping' in req_states: # See if the OS pings. rc, out_buf = gc.shell_cmd("ping -c 1 -w 2 " + openbmc_host, print_output=0, show_err=0, ignore_err=1) if rc == 0: ping = 1 if 'packet_loss' in req_states: # See if the OS pings. cmd_buf = "ping -c 5 -w 5 " + openbmc_host +\ " | egrep 'packet loss' | sed -re 's/.* ([0-9]+)%.*/\\1/g'" rc, out_buf = gc.shell_cmd(cmd_buf, print_output=0, show_err=0, ignore_err=1) if rc == 0: packet_loss = out_buf.rstrip("\n") if 'uptime' in req_states: # Sometimes reading uptime results in a blank value. Call with # wait_until_keyword_succeeds to ensure a non-blank value is obtained. remote_cmd_buf = "read uptime filler 2>/dev/null < /proc/uptime" +\ " && [ ! -z \"${uptime}\" ] && echo ${uptime}" cmd_buf = ["BMC Execute Command", re.sub('\\$', '\\$', remote_cmd_buf), 'quiet=1', 'test_mode=0'] gp.qprint_issuing(cmd_buf, 0) gp.qprint_issuing(remote_cmd_buf, 0) try: stdout, stderr, rc =\ BuiltIn().wait_until_keyword_succeeds("10 sec", "0 sec", *cmd_buf) if rc == 0 and stderr == "": uptime = stdout except AssertionError as my_assertion_error: pass if 'epoch_seconds' in req_states or 'elapsed_boot_time' in req_states: date_cmd_buf = "date -u +%s" if USE_BMC_EPOCH_TIME: cmd_buf = ["BMC Execute Command", date_cmd_buf, 'quiet=${1}'] if not quiet: gp.print_issuing(cmd_buf) status, ret_values = \ BuiltIn().run_keyword_and_ignore_error(*cmd_buf) if status == "PASS": stdout, stderr, rc = ret_values if rc == 0 and stderr == "": epoch_seconds = stdout.rstrip("\n") else: shell_rc, out_buf = gc.cmd_fnc_u(date_cmd_buf, quiet=quiet, print_output=0) if shell_rc == 0: epoch_seconds = out_buf.rstrip("\n") if 'elapsed_boot_time' in req_states: global start_boot_seconds elapsed_boot_time = int(epoch_seconds) - start_boot_seconds master_req_rest = ['rest', 'host', 'requested_host', 'operating_system', 'attempts_left', 'boot_progress', 'chassis', 'requested_chassis' 'bmc' 'requested_bmc'] req_rest = [sub_state for sub_state in req_states if sub_state in master_req_rest] need_rest = (len(req_rest) > 0) state = DotDict() if need_rest: cmd_buf = ["Read Properties", SYSTEM_STATE_URI + "enumerate", "quiet=${" + str(quiet) + "}"] gp.dprint_issuing(cmd_buf) status, ret_values = \ BuiltIn().run_keyword_and_ignore_error(*cmd_buf) if status == "PASS": state['rest'] = '1' else: state['rest'] = '0' if int(state['rest']): for url_path in ret_values: for attr_name in ret_values[url_path]: # Create a state key value based on the attr_name. try: ret_values[url_path][attr_name] = \ re.sub(r'.*\.', "", ret_values[url_path][attr_name]) except TypeError: pass # Do some key name manipulations. new_attr_name = re.sub(r'^Current|(State|Transition)$', "", attr_name) new_attr_name = re.sub(r'BMC', r'Bmc', new_attr_name) new_attr_name = re.sub(r'([A-Z][a-z])', r'_\1', new_attr_name) new_attr_name = new_attr_name.lower().lstrip("_") new_attr_name = re.sub(r'power', r'chassis', new_attr_name) if new_attr_name in req_states: state[new_attr_name] = ret_values[url_path][attr_name] for sub_state in req_states: if sub_state in state: continue if sub_state.startswith("os_"): # We pass "os_" requests on to get_os_state. continue cmd_buf = "state['" + sub_state + "'] = str(" + sub_state + ")" exec(cmd_buf) if os_host == "": # The caller has not specified an os_host so as far as we're concerned, # it doesn't exist. return state os_req_states = [sub_state for sub_state in req_states if sub_state.startswith('os_')] if len(os_req_states) > 0: # The caller has specified an os_host and they have requested # information on os substates. # Based on the information gathered on bmc, we'll try to make a # determination of whether the os is even up. We'll pass the result # of that assessment to get_os_state to enhance performance. os_up_match = DotDict() for sub_state in master_os_up_match: if sub_state in req_states: os_up_match[sub_state] = master_os_up_match[sub_state] os_up = compare_states(state, os_up_match) os_state = get_os_state(os_host=os_host, os_username=os_username, os_password=os_password, req_states=os_req_states, os_up=os_up, quiet=quiet) # Append os_state dictionary to ours. state.update(os_state) return state
def get_os_state(os_host="", os_username="", os_password="", req_states=default_os_req_states, os_up=True, quiet=None): r""" Get component states for the operating system such as ping, login, etc, put them into a dictionary and return them to the caller. Note that all substate values are strings. Description of argument(s): 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}. req_states This is a list of states whose values are being requested by the caller. os_up If the caller knows that the os can't possibly be up, it can improve performance by passing os_up=False. This function will then simply return default values for all requested os sub states. quiet Indicates whether status details (e.g. curl commands) should be written to the console. Defaults to either global value of ${QUIET} or to 1. """ quiet = int(gp.get_var_value(quiet, 0)) # Set parm defaults where necessary and validate all parms. if os_host == "": os_host = BuiltIn().get_variable_value("${OS_HOST}") error_message = gv.valid_value(os_host, invalid_values=[None, ""]) if error_message != "": BuiltIn().fail(gp.sprint_error(error_message)) if os_username == "": os_username = BuiltIn().get_variable_value("${OS_USERNAME}") error_message = gv.valid_value(os_username, invalid_values=[None, ""]) if error_message != "": BuiltIn().fail(gp.sprint_error(error_message)) if os_password == "": os_password = BuiltIn().get_variable_value("${OS_PASSWORD}") error_message = gv.valid_value(os_password, invalid_values=[None, ""]) if error_message != "": BuiltIn().fail(gp.sprint_error(error_message)) invalid_req_states = [sub_state for sub_state in req_states if sub_state not in valid_os_req_states] if len(invalid_req_states) > 0: error_message = "The following req_states are not supported:\n" +\ gp.sprint_var(invalid_req_states) BuiltIn().fail(gp.sprint_error(error_message)) # Initialize all substate values supported by this function. os_ping = 0 os_login = 0 os_run_cmd = 0 if os_up: if 'os_ping' in req_states: # See if the OS pings. rc, out_buf = gc.shell_cmd("ping -c 1 -w 2 " + os_host, print_output=0, show_err=0, ignore_err=1) if rc == 0: os_ping = 1 # Programming note: All attributes which do not require an ssh login # should have been processed by this point. master_req_login = ['os_login', 'os_run_cmd'] req_login = [sub_state for sub_state in req_states if sub_state in master_req_login] must_login = (len(req_login) > 0) if must_login: output, stderr, rc = bsu.os_execute_command("uptime", quiet=quiet, ignore_err=1, time_out=20) if rc == 0: os_login = 1 os_run_cmd = 1 else: gp.dprint_vars(output, stderr) gp.dprint_vars(rc, 1) os_state = DotDict() for sub_state in req_states: cmd_buf = "os_state['" + sub_state + "'] = str(" + sub_state + ")" exec(cmd_buf) return os_state
def compare_states(state, match_state, match_type='and'): r""" Compare 2 state dictionaries. Return True if they match and False if they don't. Note that the match_state dictionary does not need to have an entry corresponding to each entry in the state dictionary. But for each entry that it does have, the corresponding state entry will be checked for a match. Description of argument(s): state A state dictionary such as the one returned by the get_state function. match_state A dictionary whose key/value pairs are "state field"/ "state value". The state value is interpreted as a regular expression. Every value in this dictionary is considered. When match_type is 'and', if each and every comparison matches, the two dictionaries are considered to be matching. If match_type is 'or', if any two of the elements compared match, the two dictionaries are considered to be matching. 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. Finally, one special value is accepted for the key field: expression_key(). If such an entry exists, its value is taken to be a list of expressions to be evaluated. These expressions may reference state dictionary entries by simply coding them in standard python syntax (e.g. state['key1']). What follows is an example expression: "int(float(state['uptime'])) < int(state['elapsed_boot_time'])" In this example, if the state dictionary's 'uptime' entry is less than its 'elapsed_boot_time' entry, it would qualify as a match. match_type This may be 'and' or 'or'. """ error_message = gv.valid_value(match_type, valid_values=['and', 'or']) if error_message != "": BuiltIn().fail(gp.sprint_error(error_message)) try: match_state = return_state_constant(match_state) except TypeError: pass default_match = (match_type == 'and') for key, match_state_value in match_state.items(): # Blank match_state_value means "don't care". if match_state_value == "": continue if key == expressions_key(): for expr in match_state_value: # Use python interpreter to evaluate the expression. match = eval(expr) if match != default_match: return match else: try: match = (re.match(match_state_value, str(state[key])) is not None) except KeyError: match = False if match != default_match: return match return default_match
def openbmctool_execute_command(command_string, *args, **kwargs): r""" Run the command string as an argument to the openbmctool.py program and return the stdout and the return code. This function provides several benefits versus calling shell_cmd directly: - This function will obtain the global values for OPENBMC_HOST, OPENBMC_USERNAME, etc. - This function will compose the openbmctool.py command string which includes the caller's command_string. - The openbmctool.py produces additional text that clutters the output. This function will remove such text. Example: Attempting login... <actual output> User root has been logged out NOTE: If you have pipe symbols in your command_string, they must be surrounded by a single space on each side (see example below). Example code: ${rc} ${output}= Openbmctool Execute Command fru status | head -n 2 Example output: #(CDT) 2018/09/19 15:16:58 - Issuing: set -o pipefail ; openbmctool.py -H hostname -U root -P ******** ... fru status | tail -n +1 | egrep -v 'Attempting login|User [^ ]+ hasbeen logged out' | head -n 2 Component | Is a FRU | Present | Functional | Has Logs cpu0 | Yes | Yes | Yes | No Description of arguments: command_string The command string to be passed to the openbmctool.py program. All remaining arguments are passed directly to shell_cmd. See the shell_cmd prolog for details on allowable arguments. The caller may code them directly as in this example: openbmctool_execute_command("my command", quiet=1, max_attempts=2). Python will do the work of putting these values into args/kwargs. """ if not gv.valid_value(command_string): return "", "", 1 # Get global BMC variable values. openbmc_host = BuiltIn().get_variable_value("${OPENBMC_HOST}", default="") openbmc_username = BuiltIn().get_variable_value("${OPENBMC_USERNAME}", default="") openbmc_password = BuiltIn().get_variable_value("${OPENBMC_PASSWORD}", default="") if not gv.valid_value(openbmc_host): return "", "", 1 if not gv.valid_value(openbmc_username): return "", "", 1 if not gv.valid_value(openbmc_password): return "", "", 1 # Break the caller's command up into separate piped commands. For # example, the user may have specified "fru status | head -n 2" which # would be broken into 2 list elements. We will also break on ">" # (re-direct). pipeline = list(map(str.strip, re.split(r' ([\|>]) ', str(command_string)))) # The "tail" command below prevents a "egrep: write error: Broken pipe" # error if the user is piping the output to a sub-process. # Use "egrep -v" to get rid of editorial output from openbmctool.py. pipeline.insert(1, "| tail -n +1 | egrep -v 'Attempting login|User [^ ]+" " has been logged out'") command_string = "set -o pipefail ; python3 $(which openbmctool.py) -H "\ + openbmc_host + " -U " + openbmc_username + " -P " + openbmc_password\ + " " + " ".join(pipeline) return gc.shell_cmd(command_string, *args, **kwargs)
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"] gp.dprint_issuing(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.valid_value(FFDC_LOG_PATH, var_name="FFDC_LOG_PATH") if error_message != "": error_message = gp.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"] gp.print_issuing(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 shell_cmd(command_string, quiet=None, print_output=None, 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))) print_output = int(gm.dft(print_output, not quiet)) show_err = int(show_err) global_ignore_err = gp.get_var_value(ignore_err, 1) stack_ignore_err = gp.get_stack_var('ignore_err', global_ignore_err) ignore_err = int(gm.dft(ignore_err, gm.dft(stack_ignore_err, 1))) err_msg = gv.valid_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 = fa.source_to_object(allowed_shell_rcs) 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: try: err_buf += line except TypeError: line = line.decode("utf-8") err_buf += line if not print_output: continue func_stdout += line for line in sub_proc.stdout: try: out_buf += line except TypeError: line = line.decode("utf-8") 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 quiet: err_msg += gp.sprint_var(command_string) 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, gp.hexa()) err_msg += gp.sprint_var(allowed_shell_rcs, gp.hexa()) if not print_output: if return_stderr: err_msg += "err_buf:\n" + err_buf err_msg += "out_buf:\n" + out_buf if show_err: 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 gp.gp_print(func_stdout) 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 cmd_fnc(cmd_buf, quiet=None, test_mode=None, debug=0, print_output=1, show_err=1, return_stderr=0, ignore_err=1): r""" Run the given command in a shell and return the shell return code and the output. Description of arguments: cmd_buf The command string to be run in a shell. quiet Indicates whether this function should run the print_issuing() function which prints "Issuing: <cmd string>" to stdout. test_mode If test_mode is set, this function will not actually run the command. If print_output is set, it will print "(test_mode) Issuing: <cmd string>" to stdout. debug If debug is set, this function will print extra debug info. print_output If this is set, this function will print the stdout/stderr generated by the shell command. show_err If show_err is set, this function will print a standardized error report if the shell command returns non-zero. return_stderr If return_stderr is set, this function will process the stdout and stderr streams from the shell command separately. It will also return stderr in addition to the return code and the stdout. """ # Determine default values. quiet = int(gm.global_default(quiet, 0)) test_mode = int(gm.global_default(test_mode, 0)) if debug: gp.print_vars(cmd_buf, quiet, test_mode, debug) err_msg = gv.valid_value(cmd_buf) if err_msg != "": raise ValueError(err_msg) if not quiet: gp.pissuing(cmd_buf, test_mode) if test_mode: if return_stderr: return 0, "", "" else: return 0, "" if return_stderr: err_buf = "" stderr = subprocess.PIPE else: stderr = subprocess.STDOUT sub_proc = subprocess.Popen(cmd_buf, bufsize=1, shell=True, executable='/bin/bash', stdout=subprocess.PIPE, stderr=stderr) out_buf = "" if return_stderr: for line in sub_proc.stderr: try: err_buf += line except TypeError: line = line.decode("utf-8") err_buf += line if not print_output: continue gp.gp_print(line) for line in sub_proc.stdout: try: out_buf += line except TypeError: line = line.decode("utf-8") out_buf += line if not print_output: continue gp.gp_print(line) if print_output and not robot_env: sys.stdout.flush() sub_proc.communicate() shell_rc = sub_proc.returncode if shell_rc != 0: err_msg = "The prior shell command failed.\n" err_msg += gp.sprint_var(shell_rc, gp.hexa()) if not print_output: err_msg += "out_buf:\n" + out_buf if show_err: gp.print_error_report(err_msg) if not ignore_err: if robot_env: BuiltIn().fail(err_msg) else: raise ValueError(err_msg) if return_stderr: return shell_rc, out_buf, err_buf else: return shell_rc, out_buf
def validate_parms(): r""" Validate all program parameters. """ process_pgm_parms() gp.qprintn() global openbmc_model gv.valid_value(openbmc_host) gv.valid_value(openbmc_username) gv.valid_value(openbmc_password) gv.valid_value(rest_username) gv.valid_value(rest_password) gv.valid_value(ipmi_username) gv.valid_value(ipmi_password) if os_host != "": gv.valid_value(os_username) gv.valid_value(os_password) if pdu_host != "": gv.valid_value(pdu_username) gv.valid_value(pdu_password) gv.valid_integer(pdu_slot_no) if openbmc_serial_host != "": gv.valid_integer(openbmc_serial_port) if openbmc_model == "": status, ret_values =\ grk.run_key_u("Get BMC System Model") openbmc_model = ret_values BuiltIn().set_global_variable("${openbmc_model}", openbmc_model) gv.valid_value(openbmc_model) gv.valid_integer(max_num_tests) gv.valid_integer(boot_pass) gv.valid_integer(boot_fail) plug_in_packages_list = grpi.rvalidate_plug_ins(plug_in_dir_paths) BuiltIn().set_global_variable("${plug_in_packages_list}", plug_in_packages_list) gv.valid_value(stack_mode, valid_values=['normal', 'skip']) if len(boot_list) == 0 and len(boot_stack) == 0 and not ffdc_only: error_message = "You must provide either a value for either the" +\ " boot_list or the boot_stack parm.\n" BuiltIn().fail(gp.sprint_error(error_message)) valid_boot_list(boot_list, valid_boot_types) valid_boot_list(boot_stack, valid_boot_types) selected_PDU_boots = list( set(boot_list + boot_stack) & set(boot_lists['PDU_reboot'])) if len(selected_PDU_boots) > 0 and pdu_host == "": error_message = "You have selected the following boots which" +\ " require a PDU host but no value for pdu_host:\n" error_message += gp.sprint_var(selected_PDU_boots) error_message += gp.sprint_var(pdu_host, fmt=gp.blank()) BuiltIn().fail(gp.sprint_error(error_message)) return
def valid_value(var_name, *args, **kwargs): var_value, args, kwargs = valid_init(var_name, *args, **kwargs) error_message = \ gv.valid_value(var_value, *args, var_name=var_name, **kwargs) process_error_message(error_message)
def shell_cmd(command_string, quiet=None, print_output=None, show_err=1, test_mode=0, time_out=None, max_attempts=1, retry_sleep_time=5, valid_rcs=[0], ignore_err=None, return_stderr=0, fork=0, error_regexes=None): 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 valid_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. valid_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) and return the Popen object created by the subprocess.popen() function. See the kill_cmd function for details on how to process the popen object. error_regexes A list of regular expressions to be used to identify errors in the command output. If there is a match for any of these regular expressions, the command will be considered a failure and the shell_rc will be set to -1. For example, if error_regexes = ['ERROR:'] and the command output contains 'ERROR: Unrecognized option', it will be counted as an error even if the command returned 0. This is useful when running commands that do not always return non-zero on error. """ err_msg = gv.valid_value(command_string) if err_msg: raise ValueError(err_msg) # Assign default values to some of the arguments to this function. quiet = int(gm.dft(quiet, gp.get_stack_var('quiet', 0))) print_output = int(gm.dft(print_output, not quiet)) show_err = int(show_err) ignore_err = int(gm.dft(ignore_err, gp.get_stack_var('ignore_err', 1))) gp.qprint_issuing(command_string, test_mode) if test_mode: return (0, "", "") if return_stderr else (0, "") # Convert a string python dictionary definition to a dictionary. valid_rcs = fa.source_to_object(valid_rcs) # Convert each list entry to a signed value. valid_rcs = [gm.to_signed(x) for x in valid_rcs] stderr = subprocess.PIPE if return_stderr else subprocess.STDOUT # Write all output to func_out_history_buf 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_out_history_buf will # contain the complete history from the current invocation of this function. global command_timed_out command_timed_out = False func_out_history_buf = "" for attempt_num in range(1, max_attempts + 1): sub_proc = subprocess.Popen(command_string, preexec_fn=os.setsid, bufsize=1, shell=True, universal_newlines=True, executable='/bin/bash', stdout=subprocess.PIPE, stderr=stderr) if fork: return sub_proc if time_out: command_timed_out = False # Designate a SIGALRM handling function and set alarm. signal.signal(signal.SIGALRM, shell_cmd_timed_out) signal.alarm(time_out) try: stdout_buf, stderr_buf = sub_proc.communicate() except IOError: command_timed_out = True # Restore the original SIGALRM handler and clear the alarm. signal.signal(signal.SIGALRM, original_sigalrm_handler) signal.alarm(0) # Output from this loop iteration is written to func_out_buf for later processing. This can include # stdout, stderr and our own error messages. func_out_buf = "" if print_output: if return_stderr: func_out_buf += stderr_buf func_out_buf += stdout_buf shell_rc = sub_proc.returncode if shell_rc in valid_rcs: # Check output for text indicating there is an error. if error_regexes and re.match('|'.join(error_regexes), stdout_buf): shell_rc = -1 else: break err_msg = "The prior shell command failed.\n" err_msg += gp.sprint_var(attempt_num) err_msg += gp.sprint_vars(command_string, command_timed_out, time_out) err_msg += gp.sprint_varx("child_pid", sub_proc.pid) err_msg += gp.sprint_vars(shell_rc, valid_rcs, fmt=gp.hexa()) if error_regexes: err_msg += gp.sprint_vars(error_regexes) if not print_output: if return_stderr: err_msg += "stderr_buf:\n" + stderr_buf err_msg += "stdout_buf:\n" + stdout_buf if show_err: func_out_buf += gp.sprint_error_report(err_msg) if attempt_num < max_attempts: cmd_buf = "time.sleep(" + str(retry_sleep_time) + ")" if show_err: func_out_buf += gp.sprint_issuing(cmd_buf) exec(cmd_buf) func_out_history_buf += func_out_buf if shell_rc in valid_rcs: gp.gp_print(func_out_buf) else: if show_err: gp.gp_print(func_out_history_buf, stream='stderr') else: # There is no error information to show so just print output from last loop iteration. gp.gp_print(func_out_buf) if not ignore_err: # If the caller has already asked to show error info, avoid repeating that in the failure message. err_msg = "The prior shell command failed.\n" if show_err \ else err_msg if robot_env: BuiltIn().fail(err_msg) else: raise ValueError(err_msg) return (shell_rc, stdout_buf, stderr_buf) if return_stderr \ else (shell_rc, stdout_buf)
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. shell_rc, out_buf = gc.shell_cmd('dirname $(which gen_print.py)', quiet=(not debug), print_output=0) executable_base_dir_path = os.path.realpath(out_buf.rstrip()) + "/" apollo_dir_path = os.environ['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)
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 # Set global variables to aid in cleanup with process_robot_output_files. global gcr_last_robot_cmd_buf global gcr_last_robot_rc gcr_last_robot_cmd_buf = robot_cmd_buf # 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 os.environ["PATH"] = os.environ.get("SAVED_PATH", "") os.environ["PYTHONPATH"] = os.environ.get("SAVED_PYTHONPATH", "") gcr_last_robot_rc = shell_rc process_robot_output_files() if shell_rc != 0: hex = 1 gp.print_var(shell_rc, hex) return False return True
def robot_cmd_fnc(robot_cmd_buf, robot_jail=os.environ.get('ROBOT_JAIL', ''), quiet=None, test_mode=0): 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. test_mode If test_mode is set, this function will not actually run the command. """ quiet = int(gm.dft(quiet, gp.get_stack_var('quiet', 0))) gv.valid_value(robot_cmd_buf) # Set global variables to aid in cleanup with process_robot_output_files. global gcr_last_robot_cmd_buf global gcr_last_robot_rc gcr_last_robot_cmd_buf = robot_cmd_buf # 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") OPENBMCTOOL_DIR_PATH = gm.get_mod_global("OPENBMCTOOL_DIR_PATH") 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: # Make sure required programs like python and robot can be found in the new restricted PATH. required_programs = "python robot" # It is expected that there will be a "python" program in the tool base bin path which is really a # link to select_version. Ditto for "robot". Call each with the --print_only option to get the # paths to the "real" programs. cmd_buf = "for program in " + required_programs \ + " ; do dirname $(${program} --print_only) ; done 2>/dev/null" rc, out_buf = gc.shell_cmd(cmd_buf, quiet=1, print_output=0) PYTHONPATH = ROBOT_TEST_BASE_DIR_PATH + "lib" NEW_PATH_LIST = [ROBOT_TEST_BASE_DIR_PATH + "bin"] NEW_PATH_LIST.extend(list(set(out_buf.rstrip("\n").split("\n")))) NEW_PATH_LIST.extend([ "/usr/local/sbin", "/usr/local/bin", "/usr/sbin", "/usr/bin", "/sbin", "/bin", OPENBMCTOOL_DIR_PATH.rstrip('/') ]) 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" + ":" + OPENBMCTOOL_DIR_PATH.rstrip('/') 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') 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 os.environ["PATH"] = os.environ.get("SAVED_PATH", "") os.environ["PYTHONPATH"] = os.environ.get("SAVED_PYTHONPATH", "") gcr_last_robot_rc = shell_rc process_robot_output_files() if shell_rc != 0: gp.print_var(shell_rc, gp.hexa()) return False return True