Esempio n. 1
0
 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()
Esempio n. 2
0
 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()
Esempio n. 3
0
 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()
Esempio n. 4
0
 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()
Esempio n. 5
0
 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()
Esempio n. 6
0
 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)
Esempio n. 7
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
Esempio n. 8
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