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 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 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 execCmd(command, sudo=False, cwd=None, data=None, raw=False, printable=None, env=None, sync=True, nice=None, ioclass=None, ioclassdata=None, setsid=False, execCmdLogger=logging.root, deathSignal=None, resetCpuAffinity=True): """ Executes an external command, optionally via sudo. IMPORTANT NOTE: the new process would receive `deathSignal` when the controlling thread dies, which may not be what you intended: if you create a temporary thread, spawn a sync=False sub-process, and have the thread finish, the new subprocess would die immediately. """ 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)) extra = {} extra['stderr'] = subprocess.PIPE extra['stdout'] = subprocess.PIPE if deathSignal is not None: extra['deathSignal'] = deathSignal p = CPopen(command, close_fds=True, cwd=cwd, env=env, **extra) if not sync: p = AsyncProc(p) if data is not None: p.stdin.write(data) p.stdin.flush() return p with terminating(p): (out, err) = p.communicate(data) if out is None: # Prevent splitlines() from barfing later on out = "" 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 exec_sync(cmds): logging.debug(cmdutils.command_log_line(cmds)) p = Popen( cmds, close_fds=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) out, err = p.communicate() logging.debug(cmdutils.retcode_log_line(p.returncode, err=err)) return p.returncode, out, err
def exec_sync_bytes(cmds): logging.debug(cmdutils.command_log_line(cmds)) p = Popen(cmds, close_fds=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) out, err = p.communicate() logging.debug(cmdutils.retcode_log_line(p.returncode, err=err)) return p.returncode, out, err
def execCmd(command, sudo=False, cwd=None, data=None, raw=False, printable=None, env=None, sync=True, 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) if not sync: p = AsyncProc(p) if data is not None: p.stdin.write(data) p.stdin.flush() return p with terminating(p): (out, err) = p.communicate(data) if out is None: # Prevent splitlines() from barfing later on out = "" 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 watchCmd(command, stop, cwd=None, data=None, nice=None, ioclass=None, execCmdLogger=logging.root, deathSignal=signal.SIGKILL): """ Executes an external command, optionally via sudo with stop abilities. """ proc = execCmd(command, cwd=cwd, data=data, sync=False, nice=nice, ioclass=ioclass, execCmdLogger=execCmdLogger, deathSignal=deathSignal) if not proc.wait(cond=stop): proc.kill() raise ActionStopped() out = stripNewLines(proc.stdout) err = stripNewLines(proc.stderr) execCmdLogger.debug(retcode_log_line(proc.returncode, err=err)) return proc.returncode, out, err
def communicate(proc, input=None): """ A wrapper for subprocess.communicate() which waits for process to be finished and logs the returned code (and error output if any). Arguments: proc: subprocess.Popen instance or commands.PrivilegedPopen if subprocess was created with sudo enabled. input (bytes): input data to be sent to the child process, or None, if no data should be sent to the process. Returns: Tuple of process standard output and error output. """ with terminating(proc): out, err = proc.communicate(input) log.debug(cmdutils.retcode_log_line(proc.returncode, err=err)) return out, err
def _finalize(self, out, err): """ Update operation state after underlying process has terminated. Raises: `exception.ActionStopped` if the command was aborted `cmdutils.Error` if the command failed `RuntimeError` if operation state is invalid """ rc = self._proc.returncode log.debug(common_cmdutils.retcode_log_line(rc, err)) with self._lock: self._proc = None if self._state == ABORTING: self._state = ABORTED raise exception.ActionStopped elif self._state == RUNNING: self._state = TERMINATED if rc != 0: raise cmdutils.Error(self._cmd, rc, out, err) else: raise RuntimeError("Invalid state: %s" % self)
def _finalize(self, out, err): """ Update operation state after underlying process has terminated. Raises: `exception.ActionStopped` if the command was aborted `cmdutils.Error` if the command failed `RuntimeError` if operation state is invalid """ rc = self._proc.returncode log.debug(cmdutils.retcode_log_line(rc, err)) with self._lock: self._proc = None if self._state == ABORTING: self._state = ABORTED raise exception.ActionStopped elif self._state == RUNNING: self._state = TERMINATED if rc != 0: raise CmdError(self._cmd, rc, out, err) else: raise RuntimeError("Invalid state: %s" % self)
def run(args, input=None, cwd=None, env=None, sudo=False, setsid=False, nice=None, ioclass=None, ioclassdata=None, reset_cpu_affinity=True): """ Starts a command communicate with it, and wait until the command terminates. Ensures that the command is killed if an unexpected error is raised. args are logged when command starts, and are included in the exception if a command has failed. If args contain sensitive information that should not be logged, such as passwords, they must be wrapped with ProtectedPassword. The child process stdout and stderr are always buffered. If you have special needs, such as running the command without buffering stdout, or create a pipeline of several commands, use the lower level start() function. Arguments: args (list): Command arguments input (bytes): Data to send to the command via stdin. cwd (str): working directory for the child process env (dict): environment of the new child process sudo (bool): if set to True, run the command via sudo nice (int): if not None, run the command via nice command with the specified nice value ioclass (int): if not None, run the command with the ionice command using specified ioclass value. ioclassdata (int): if ioclass is set, the scheduling class data. 0-7 are valid data (priority levels). reset_cpu_affinity (bool): Run the command via the taskset command, allowing the child process to run on all cpus (default True). Returns: The command output (bytes) Raises: OSError if the command could not start. cmdutils.Error if the command terminated with a non-zero exit code. utils.TerminatingFailure if command could not be terminated. """ p = start(args, stdin=subprocess.PIPE if input else None, stdout=subprocess.PIPE, stderr=subprocess.PIPE, cwd=cwd, env=env, sudo=sudo, setsid=setsid, nice=nice, ioclass=ioclass, ioclassdata=ioclassdata, reset_cpu_affinity=reset_cpu_affinity) with terminating(p): out, err = p.communicate(input) log.debug(cmdutils.retcode_log_line(p.returncode, err)) if p.returncode != 0: raise cmdutils.Error(args, p.returncode, out, err) return out
def run_logging(args, log_tag=None): """ Start a command storing its stdout/stderr into a file, communicate with it, and wait until the command terminates. Ensures that the command is killed if an unexpected error is raised. Note that since the stdout/stderr is redirected to the file it is not piped to VDSM. args are logged when command starts, and are included in the exception if a command has failed. If args contain sensitive information that should not be logged, such as passwords, they must be wrapped with ProtectedPassword. While access to the directory with log files is restricted caution should be taken when logging commands. Avoid storing output of commands that may leak passwords or other sensitive information. The child process stdout and stderr are always buffered. If you have special needs, such as running the command without buffering stdout, or create a pipeline of several commands, use the lower level start() function. If log_tag is not used the log file name is 'virtcmd-<command>-<datetime>-<random_string>.log'. If log_tag is used the format is 'virtcmd-<command>-<log_tag>-<datetime>-<random_string>.log'. The granularity of <datetime> part of the file name is one second. To minimize file collision there is a random string of characters appended to the name. Arguments: args (list): Command arguments log_tag (str): Optional string to be included in log file name to better distinguish the log files and avoid potential name collisions. This could be for example VM ID. Returns: Path to the log file. Raises: LoggingError if the command terminated with a non-zero exit code. TerminatingFailure if command could not be terminated. """ stdout = subprocess.DEVNULL stderr = subprocess.DEVNULL cmd_log_file = None timestamp = time.strftime('%Y%m%dT%H%M%S') command = os.path.basename(str(args[0])) log_tag = '' if log_tag is None else '-%s' % log_tag suffix = ''.join(random.choice(string.ascii_lowercase) for _ in range(4)) cmd_log_path = os.path.join( _COMMANDS_LOG_DIR, 'virtcmd-%s%s-%s-%s.log' % (command, log_tag, timestamp, suffix)) try: os.makedirs(_COMMANDS_LOG_DIR, mode=0o750, exist_ok=True) cmd_log_file = os.open(cmd_log_path, os.O_WRONLY | os.O_CREAT | os.O_APPEND, mode=0o640) except OSError: log.exception('Failed to open log file') cmd_log_path = None else: stdout = cmd_log_file stderr = cmd_log_file log.debug('Running command %r with logs in %s', args, cmd_log_path) p = start(args, stdin=subprocess.PIPE, stdout=stdout, stderr=stderr) with terminating(p): p.communicate() log.debug(cmdutils.retcode_log_line(p.returncode)) if cmd_log_file is not None: os.close(cmd_log_file) if p.returncode != 0: raise LoggingError(args, p.returncode, cmd_log_path) return cmd_log_path
def execCmd(command, sudo=False, cwd=None, data=None, raw=False, printable=None, env=None, sync=True, nice=None, ioclass=None, ioclassdata=None, setsid=False, execCmdLogger=logging.root, deathSignal=None, resetCpuAffinity=True): """ Executes an external command, optionally via sudo. IMPORTANT NOTE: the new process would receive `deathSignal` when the controlling thread dies, which may not be what you intended: if you create a temporary thread, spawn a sync=False sub-process, and have the thread finish, the new subprocess would die immediately. """ 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)) extra = {} extra['stderr'] = subprocess.PIPE extra['stdout'] = subprocess.PIPE if deathSignal is not None: extra['deathSignal'] = deathSignal p = CPopen(command, close_fds=True, cwd=cwd, env=env, **extra) if not sync: p = AsyncProc(p) if data is not None: p.stdin.write(data) p.stdin.flush() return p with terminating(p): (out, err) = p.communicate(data) if out is None: # Prevent splitlines() from barfing later on out = "" 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 run(args, input=None, cwd=None, env=None, sudo=False, setsid=False, nice=None, ioclass=None, ioclassdata=None, reset_cpu_affinity=True): """ Starts a command communicate with it, and wait until the command terminates. Ensures that the command is killed if an unexpected error is raised. args are logged when command starts, and are included in the exception if a command has failed. If args contain sensitive information that should not be logged, such as passwords, they must be wrapped with ProtectedPassword. The child process stdout and stderr are always buffered. If you have special needs, such as running the command without buffering stdout, or create a pipeline of several commands, use the lower level start() function. Arguments: args (list): Command arguments input (bytes): Data to send to the command via stdin. cwd (str): working directory for the child process env (dict): environment of the new child process sudo (bool): if set to True, run the command via sudo nice (int): if not None, run the command via nice command with the specified nice value ioclass (int): if not None, run the command with the ionice command using specified ioclass value. ioclassdata (int): if ioclass is set, the scheduling class data. 0-7 are valid data (priority levels). reset_cpu_affinity (bool): Run the command via the taskset command, allowing the child process to run on all cpus (default True). Returns: The command output (bytes) Raises: OSError if the command could not start. cmdutils.Error if the command terminated with a non-zero exit code. utils.TerminatingFailure if command could not be terminated. """ p = start(args, stdin=subprocess.PIPE if input else None, stdout=subprocess.PIPE, stderr=subprocess.PIPE, cwd=cwd, env=env, sudo=sudo, setsid=setsid, nice=nice, ioclass=ioclass, ioclassdata=ioclassdata, reset_cpu_affinity=reset_cpu_affinity) with terminating(p): out, err = p.communicate(input) log.debug(cmdutils.retcode_log_line(p.returncode, err)) if p.returncode != 0: raise cmdutils.Error(args, p.returncode, out, err) return out