def test_no_fds(self): p = CPopen(["sleep", "1"], stdin=None, stdout=None, stderr=None) try: with self.assertRaises(cmdutils.TimeoutExpired): for _ in cmdutils.receive(p, 0.5): pass finally: p.kill() p.wait()
def test_without_affinity(self): args = [EXT_SLEEP, "3"] popen = Popen(args, close_fds=True) stats = proc.pidstat(popen.pid) pid = int(stats.pid) # procName comes in the format of (procname) name = stats.comm self.assertEqual(pid, popen.pid) self.assertEqual(name, args[0]) popen.kill() popen.wait()
def test_timeout_with_data(self): p = CPopen(["yes"], stdin=None, stdout=subprocess.PIPE, stderr=subprocess.PIPE) try: with self.assertRaises(cmdutils.TimeoutExpired): for _ in cmdutils.receive(p, 0.5): pass finally: p.kill() p.wait()
def test_fds_closed(self): cmd = [ "python", "-c", "import os, time; os.close(1); os.close(2); time.sleep(1)" ] p = CPopen(cmd, stdin=None, stdout=subprocess.PIPE, stderr=subprocess.PIPE) try: with self.assertRaises(cmdutils.TimeoutExpired): for _ in cmdutils.receive(p, 0.5): pass finally: p.kill() p.wait()
def test(self): sleepProcs = [] try: for i in range(3): popen = Popen([EXT_SLEEP, "3"]) sleepProcs.append(popen) # There is no guarantee which process run first after forking a # child process, make sure all the children are runing before we # look for them. time.sleep(0.5) pids = proc.pgrep(EXT_SLEEP) for popen in sleepProcs: self.assertIn(popen.pid, pids) finally: for popen in sleepProcs: popen.kill() popen.wait()
def test_plain_read(self): p = CPopen([ "dd", "if=/dev/zero", "bs=%d" % self.BUFSIZE, "count=%d" % self.COUNT ], stdin=None, stdout=subprocess.PIPE, stderr=subprocess.PIPE) start = monotonic_time() received = 0 while True: data = os.read(p.stdout.fileno(), self.BUFSIZE) if not data: break received += len(data) p.wait() elapsed = monotonic_time() - start received_gb = received / float(1024**3) print("%.2fg in %.2f seconds (%.2fg/s)" % (received_gb, elapsed, received_gb / elapsed), end=" ") self.assertEqual(received, self.COUNT * self.BUFSIZE) self.assertEqual(p.returncode, 0)
class QemuImgOperation(object): REGEXPR = re.compile(r'\s*\(([\d.]+)/100%\)\s*') def __init__(self, cmd, cwd=None): self._lock = threading.Lock() self._aborted = False self._progress = 0.0 self._stdout = bytearray() self._stderr = bytearray() self.cmd = wrap_command(cmd, with_nice=utils.NICENESS.HIGH, with_ioclass=utils.IOCLASS.IDLE) _log.debug(cmdutils.command_log_line(self.cmd, cwd=cwd)) self._command = CPopen(self.cmd, cwd=cwd, deathSignal=signal.SIGKILL) self._stream = utils.CommandStream(self._command, self._recvstdout, self._recvstderr) def _recvstderr(self, buffer): self._stderr += buffer def _recvstdout(self, buffer): self._stdout += buffer # Checking the presence of '\r' before splitting will prevent # generating the array when it's not needed. try: idx = self._stdout.rindex('\r') except ValueError: return # qemu-img updates progress by printing \r (0.00/100%) to standard out. # The output could end with a partial progress so we must discard # everything after the last \r and then try to parse a progress record. valid_progress = self._stdout[:idx] last_progress = valid_progress.rsplit('\r', 1)[-1] # No need to keep old progress information around del self._stdout[:idx + 1] m = self.REGEXPR.match(last_progress) if m is None: raise ValueError('Unable to parse: "%r"' % last_progress) self._progress = float(m.group(1)) @property def progress(self): """ Returns operation progress as float between 0 and 100. This method is threadsafe and may be called from any thread. """ return self._progress @property def error(self): return str(self._stderr) @property def finished(self): return self._command.poll() is not None def poll(self, timeout=None): self._stream.receive(timeout=timeout) if not self._stream.closed: return self._command.wait() if self._aborted: raise exception.ActionStopped() cmdutils.retcode_log_line(self._command.returncode, self.error) if self._command.returncode != 0: raise QImgError(self.cmd, self._command.returncode, "", self.error) def wait_for_completion(self): timeout = config.getint("irs", "progress_interval") while not self.finished: self.poll(timeout) _log.debug('qemu-img operation progress: %s%%', self.progress) def abort(self): """ Aborts running operation by sending a termination signal to the underlying qemu-img process. Note: this is asynchronous operation, returning before the process was terminated. You must use wait_for_completion to wait for the underlying qemu-img process. This method is threadsafe and may be called from any thread. """ with self._lock: if self._command is None: return if self._command.poll() is None: self._aborted = True self._command.terminate() def close(self): with self._lock: self._stream.close() self._command = None
class QemuImgOperation(object): REGEXPR = re.compile(r'\s*\(([\d.]+)/100%\)\s*') def __init__(self, cmd, cwd=None): self._lock = threading.Lock() self._aborted = False self._progress = 0.0 self._stdout = bytearray() self._stderr = bytearray() self.cmd = wrap_command( cmd, with_nice=utils.NICENESS.HIGH, with_ioclass=utils.IOCLASS.IDLE) _log.debug(cmdutils.command_log_line(self.cmd, cwd=cwd)) self._command = CPopen(self.cmd, cwd=cwd, deathSignal=signal.SIGKILL) self._stream = utils.CommandStream( self._command, self._recvstdout, self._recvstderr) def _recvstderr(self, buffer): self._stderr += buffer def _recvstdout(self, buffer): self._stdout += buffer # Checking the presence of '\r' before splitting will prevent # generating the array when it's not needed. try: idx = self._stdout.rindex('\r') except ValueError: return # qemu-img updates progress by printing \r (0.00/100%) to standard out. # The output could end with a partial progress so we must discard # everything after the last \r and then try to parse a progress record. valid_progress = self._stdout[:idx] last_progress = valid_progress.rsplit('\r', 1)[-1] # No need to keep old progress information around del self._stdout[:idx + 1] m = self.REGEXPR.match(last_progress) if m is None: raise ValueError('Unable to parse: "%r"' % last_progress) self._progress = float(m.group(1)) @property def progress(self): """ Returns operation progress as float between 0 and 100. This method is threadsafe and may be called from any thread. """ return self._progress @property def error(self): return str(self._stderr) @property def finished(self): return self._command.poll() is not None def poll(self, timeout=None): self._stream.receive(timeout=timeout) if not self._stream.closed: return self._command.wait() if self._aborted: raise exception.ActionStopped() cmdutils.retcode_log_line(self._command.returncode, self.error) if self._command.returncode != 0: raise QImgError(self.cmd, self._command.returncode, "", self.error) def wait_for_completion(self): timeout = config.getint("irs", "progress_interval") while not self.finished: self.poll(timeout) _log.debug('qemu-img operation progress: %s%%', self.progress) def abort(self): """ Aborts running operation by sending a termination signal to the underlying qemu-img process. Note: this is asynchronous operation, returning before the process was terminated. You must use wait_for_completion to wait for the underlying qemu-img process. This method is threadsafe and may be called from any thread. """ with self._lock: if self._command is None: return if self._command.poll() is None: self._aborted = True self._command.terminate() def close(self): with self._lock: self._stream.close() self._command = None