def exec_cmd(cmd, env=None): """ Execute cmd in an external process, collect its output and returncode :param cmd: an iterator of strings to be passed as exec(2)'s argv :param env: an optional dictionary to be placed as environment variables of the external process. If None, the environment of the calling process is used. :returns: a 3-tuple of the process's (returncode, stdout content, stderr content.) This is a bare-bones version of `commands.execCmd`. Unlike the latter, this function * uses Vdsm cpu pinning, and must not be used for long CPU-bound processes. * does not guarantee to kill underlying process if Popen.communicate() raises. Commands that access shared storage may not use this api. * does not hide passwords in logs if they are passed in cmd """ logging.debug(command_log_line(cmd)) p = subprocess.Popen(cmd, close_fds=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, env=env) out, err = p.communicate() logging.debug(retcode_log_line(p.returncode, err=err)) return p.returncode, out, err
def _simple_exec_cmd(command, env=None, nice=None, ioclass=None, stdin=None, stdout=None, stderr=None): command = wrap_command(command, with_ioclass=ioclass, ioclassdata=None, with_nice=nice, with_setsid=False, with_sudo=False, reset_cpu_affinity=True) logging.debug(cmdutils.command_log_line(command, cwd=None)) p = subprocess.Popen(command, close_fds=True, cwd=None, env=env, stdin=stdin, stdout=stdout, stderr=stderr) return p
def test_kill(self): p = subprocess.Popen(["sleep", "1"], stdin=None, stdout=subprocess.PIPE, stderr=subprocess.PIPE) p.kill() list(cmdutils.receive(p)) self.assertEqual(p.returncode, -signal.SIGKILL)
def test_no_output_error(self): p = subprocess.Popen(["false"], stdin=None, stdout=subprocess.PIPE, stderr=subprocess.PIPE) received = list(cmdutils.receive(p)) self.assertEqual(received, []) self.assertEqual(p.returncode, 1)
def test_stdout(self): p = subprocess.Popen(["echo", "output"], stdin=None, stdout=subprocess.PIPE, stderr=subprocess.PIPE) received = list(cmdutils.receive(p)) self.assertEqual(received, [(cmdutils.OUT, b"output\n")]) self.assertEqual(p.returncode, 0)
def test_stderr(self): p = subprocess.Popen(["sh", "-c", "echo error >/dev/stderr"], stdin=None, stdout=subprocess.PIPE, stderr=subprocess.PIPE) received = list(cmdutils.receive(p)) self.assertEqual(received, [(cmdutils.ERR, b"error\n")]) self.assertEqual(p.returncode, 0)
def execCmd(command, sudo=False, cwd=None, data=None, raw=False, printable=None, env=None, nice=None, ioclass=None, ioclassdata=None, setsid=False, execCmdLogger=logging.root, resetCpuAffinity=True): """ Executes an external command, optionally via sudo. """ command = cmdutils.wrap_command(command, with_ioclass=ioclass, ioclassdata=ioclassdata, with_nice=nice, with_setsid=setsid, with_sudo=sudo, reset_cpu_affinity=resetCpuAffinity) # Unsubscriptable objects (e.g. generators) need conversion if not callable(getattr(command, '__getitem__', None)): command = tuple(command) if not printable: printable = command execCmdLogger.debug(command_log_line(printable, cwd=cwd)) p = subprocess.Popen(command, close_fds=True, cwd=cwd, env=env, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE) with terminating(p): (out, err) = p.communicate(data) if out is None: # Prevent splitlines() from barfing later on out = b"" execCmdLogger.debug(retcode_log_line(p.returncode, err=err)) if not raw: out = out.splitlines(False) err = err.splitlines(False) return p.returncode, out, err
def test_without_affinity(self): args = [EXT_SLEEP, "3"] popen = subprocess.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_both_stdout_stderr(self): p = subprocess.Popen( ["sh", "-c", "echo output; echo error >/dev/stderr;"], stdin=None, stdout=subprocess.PIPE, stderr=subprocess.PIPE) received = list(cmdutils.receive(p)) self.assertEqual(sorted(received), sorted([ (cmdutils.OUT, b"output\n"), (cmdutils.ERR, b"error\n") ])) self.assertEqual(p.returncode, 0)
def test_timeout_with_data(self): p = subprocess.Popen(["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_no_fds(self): p = subprocess.Popen(["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_fds_closed(self): cmd = ["python", "-c", "import os, time; os.close(1); os.close(2); time.sleep(1)"] p = subprocess.Popen(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 _child_processes(self): proc = subprocess.Popen(self.PGREP_CMD, stdin=None, stdout=subprocess.PIPE, stderr=subprocess.PIPE) out, err = proc.communicate() # EXIT STATUS # 0 One or more processes matched the criteria. # 1 No processes matched. if proc.returncode not in (0, 1): raise RuntimeError("Error running pgrep: [%d] %s" % (proc.returncode, err)) return frozenset(int(pid) for pid in out.splitlines())
def _start_process(self): """ Starts a dd process performing direct I/O to path, reading the process stderr. When stderr has closed, _read_completed will be called. """ cmd = [constants.EXT_DD, "if=%s" % self._path, "of=/dev/null", "bs=4096", "count=1", "iflag=direct"] cmd = cmdutils.wrap_command(cmd) self._proc = subprocess.Popen( cmd, stdin=None, stdout=None, stderr=subprocess.PIPE) self._reader = self._loop.create_dispatcher( asyncevent.BufferedReader, self._proc.stderr, self._read_completed)
def checkSudo(cmd): try: p = subprocess.Popen(['sudo', '-l', '-n'] + cmd, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE) except OSError as e: if e.errno == errno.ENOENT: raise SkipTest("Test requires SUDO executable (%s)" % e) else: raise out, err = p.communicate() if p.returncode != 0: raise SkipTest("Test requires SUDO configuration (%s)" % err.strip())
def test(self): sleepProcs = [] try: for i in range(3): popen = subprocess.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 _start_process(self): """ Start the underlying process. Raises: `RuntimeError` if invoked more then once """ with self._lock: if self._state == ABORTED: raise exception.ActionStopped if self._state != CREATED: raise RuntimeError("Attempt to run an operation twice") log.debug(cmdutils.command_log_line(self._cmd, cwd=self._cwd)) self._proc = subprocess.Popen(self._cmd, cwd=self._cwd, stdin=None, stdout=subprocess.PIPE, stderr=subprocess.PIPE) self._state = RUNNING
def test_terminate(self, signo): # Start bash process printing its pid and sleeping. p = subprocess.Popen( ['./py-watch', '10', 'bash', '-c', 'echo $$; sleep 10'], stdout=subprocess.PIPE) # Wait until the underlying bash process prints its pid. for src, data in cmdutils.receive(p): if src == cmdutils.OUT: child_pid = int(data) break # Terminate py-watch, and check its exit code. p.send_signal(signo) assert p.wait() == 128 + signo # Check that the child process was terminated. with pytest.raises(OSError) as e: assert os.kill(child_pid, 0) assert e.value.errno == errno.ESRCH
def test_terminate(self, signo): # Start bash process printing its pid and sleeping. The short sleep # before printing the pid avoids a race when we got the pid before # py-watch started to wait for the child. p = subprocess.Popen([ sys.executable, 'py-watch', '10', 'bash', '-c', 'sleep 0.5; echo $$; sleep 10' ], stdout=subprocess.PIPE) # Wait until the underlying bash process prints its pid. for src, data in cmdutils.receive(p): if src == cmdutils.OUT: child_pid = int(data) break # Terminate py-watch, and check its exit code. p.send_signal(signo) assert p.wait() == 128 + signo # Check that the child process was terminated. with pytest.raises(OSError) as e: assert os.kill(child_pid, 0) assert e.value.errno == errno.ESRCH
def netns_exec(netns_name, command): cmds = [_IP_BINARY.cmd, 'netns', 'exec', netns_name] + command return subprocess.Popen(cmds)