def join_bg_jobs(bg_jobs, timeout=None): """ Joins the bg_jobs with the current thread. Returns the same list of bg_jobs objects that was passed in. """ ret, timeout_error = 0, False for bg_job in bg_jobs: bg_job.output_prepare(StringIO.StringIO(), StringIO.StringIO()) try: # We are holding ends to stdin, stdout pipes # hence we need to be sure to close those fds no mater what start_time = time.time() timeout_error = _wait_for_commands(bg_jobs, start_time, timeout) for bg_job in bg_jobs: # Process stdout and stderr bg_job.process_output(stdout=True, final_read=True) bg_job.process_output(stdout=False, final_read=True) finally: # close our ends of the pipes to the sp no matter what for bg_job in bg_jobs: bg_job.cleanup() if timeout_error: # TODO: This needs to be fixed to better represent what happens when # running in parallel. However this is backwards compatible, so it will # do for the time being. raise error.CmdError( bg_jobs[0].command, bg_jobs[0].result, "Command(s) did not complete within %d seconds" % timeout) return bg_jobs
def run(command, timeout=None, ignore_status=False, stdout_tee=None, stderr_tee=None, verbose=True, stdin=None, stderr_is_expected=None, args=()): """ run a command on the host. :param stdout_tee: optional file-like object to which stdout data will be written as it is generated (data will be stored in result.stdout) :param stderr_tee: likewise for stderr :param verbose: if True, log the command being run :param args: sequence of strings of arguments to be given to the command inside quotes after they have been escaped for that; each element in the sequence will be given as a seperate command argument :return: a CmdResult object :raise CmdError """ if isinstance(args, basestring): raise TypeError('Got a string for the "args" keyword argument, "\ "need a sequence') for arg in args: command += '"%s"' % sh_escape(arg) if stderr_is_expected is None: stderr_is_expected = ignore_status bg_job = join_bg_jobs( (BgJob(command, stdout_tee, stderr_tee, verbose, stdin=stdin, stderr_level=get_stderr_level(stderr_is_expected)), ), timeout)[0] if not ignore_status and bg_job.result.exit_status: raise error.CmdError(command, bg_job.result, "Command returned non-zero exit status") return bg_job.result