def compose_plug_in_save_dir_path(plug_in_package_name=None): r""" Create and return a directory path name that is suitable for saving plug-in data. The name will be comprised of things such as plug_in package name, pid, etc. in order to guarantee that it is unique for a given test run. Description of argument(s): plug_in_package_name The plug-in package name. This defaults to the name of the caller's plug-in package. However, the caller can specify another value in order to retrieve data saved by another plug-in package. """ plug_in_package_name = gm.dft(plug_in_package_name, get_plug_in_package_name()) BASE_TOOL_DIR_PATH = \ gm.add_trailing_slash(os.environ.get(PLUG_VAR_PREFIX + "_BASE_TOOL_DIR_PATH", "/tmp/")) NICKNAME = os.environ.get("AUTOBOOT_OPENBMC_NICKNAME", "") if NICKNAME == "": NICKNAME = os.environ["AUTOIPL_FSP1_NICKNAME"] MASTER_PID = os.environ[PLUG_VAR_PREFIX + "_MASTER_PID"] gp.print_vars(BASE_TOOL_DIR_PATH, NICKNAME, plug_in_package_name, MASTER_PID) return BASE_TOOL_DIR_PATH + gm.username() + "/" + NICKNAME + "/" +\ plug_in_package_name + "/" + str(MASTER_PID) + "/"
def cmd_fnc(cmd_buf, quiet=None, test_mode=None, debug=0, print_output=1, show_err=1): r""" Run the given command in a shell and return the shell return code. Description of arguments: cmd_buf The command string to be run in a shell. quiet Indicates whether this function should run the pissuing() function prints an "Issuing: <cmd string>" to stdout. test_mode If test_mode is set, this function will not actually run the command. 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. """ 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.svalid_value(cmd_buf) if err_msg != "": raise ValueError(err_msg) if not quiet: gp.pissuing(cmd_buf, test_mode) if test_mode: return 0, "" sub_proc = subprocess.Popen(cmd_buf, bufsize=1, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) out_buf = "" for line in sub_proc.stdout: out_buf += line if not print_output: continue if robot_env: grp.rprint(line) else: sys.stdout.write(line) if print_output and not robot_env: sys.stdout.flush() sub_proc.communicate() shell_rc = sub_proc.returncode if shell_rc != 0 and show_err: if robot_env: grp.rprint_error_report("The prior command failed.\n" + gp.sprint_var(shell_rc, 1)) else: gp.print_error_report("The prior command failed.\n" + gp.sprint_var(shell_rc, 1)) 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 terminate_descendants(): r""" Terminate descendants of the current process according to the requirements layed out in global term_options variable. Note: If term_options is not null, gen_exit_function() will automatically call this function. When this function gets called, descendant processes may be running and may be printing to the same stdout stream being used by this process. If this function writes directly to stdout, its output can be interspersed with any output generated by descendant processes. This makes it very difficult to interpret the output. In order solve this problem, the activity of this process will be logged to a temporary file. After descendant processes have been terminated successfully, the temporary file will be printed to stdout and then deleted. However, if this function should fail to complete (i.e. get hung waiting for descendants to terminate gracefully), the temporary file will not be deleted and can be used by the developer for debugging. If no descendant processes are found, this function will return before creating the temporary file. Note that a general principal being observed here is that each process is responsible for the children it produces. """ message = "\n" + gp.sprint_dashes(width=120) \ + gp.sprint_executing() + "\n" current_process = psutil.Process() descendants, descendant_pids, process_report = get_descendant_info( current_process) if not descendants: # If there are no descendants, then we have nothing to do. return terminate_descendants_temp_file_path = gm.create_temp_file_path() gp.print_vars(terminate_descendants_temp_file_path) message += gp.sprint_varx("pgm_name", gp.pgm_name) \ + gp.sprint_vars(term_options) \ + process_report # Process the termination requests: if term_options['term_requests'] == 'children': term_processes = current_process.children(recursive=False) term_pids = [str(process.pid) for process in term_processes] elif term_options['term_requests'] == 'descendants': term_processes = descendants term_pids = descendant_pids else: # Process term requests by pgm_names. term_processes = [] for pgm_name in term_options['term_requests']['pgm_names']: term_processes.extend( select_processes_by_pgm_name(descendants, pgm_name)) term_pids = [str(process.pid) for process in term_processes] message += gp.sprint_timen("Processes to be terminated:") \ + gp.sprint_var(term_pids) for process in term_processes: process.terminate() message += gp.sprint_timen("Waiting on the following pids: " + ' '.join(descendant_pids)) gm.append_file(terminate_descendants_temp_file_path, message) psutil.wait_procs(descendants) # Checking after the fact to see whether any descendant processes are still alive. If so, a process # report showing this will be included in the output. descendants, descendant_pids, process_report = get_descendant_info( current_process) if descendants: message = "\n" + gp.sprint_timen("Not all of the processes terminated:") \ + process_report gm.append_file(terminate_descendants_temp_file_path, message) message = gp.sprint_dashes(width=120) gm.append_file(terminate_descendants_temp_file_path, message) gp.print_file(terminate_descendants_temp_file_path) os.remove(terminate_descendants_temp_file_path)