Beispiel #1
0
    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)
Beispiel #2
0
    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)
Beispiel #3
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
Beispiel #4
0
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
Beispiel #5
0
Datei: cmd.py Projekt: EdDev/vdsm
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
Beispiel #6
0
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
Beispiel #7
0
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
Beispiel #8
0
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
Beispiel #9
0
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
Beispiel #10
0
    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)
Beispiel #11
0
    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)
Beispiel #12
0
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
Beispiel #13
0
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
Beispiel #14
0
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
Beispiel #15
0
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