Exemplo n.º 1
0
Arquivo: sosnode.py Projeto: dmend/sos
    def run_command(self, cmd, timeout=180, get_pty=False, need_root=False,
                    force_local=False, use_container=False):
        """Runs a given cmd, either via the SSH session or locally

        Arguments:
            cmd - the full command to be run
            timeout - time in seconds to wait for the command to complete
            get_pty - If a shell is absolutely needed to run a command, set
                      this to True
            need_root - if a command requires root privileges, setting this to
                        True tells sos-collector to format the command with
                        sudo or su - as appropriate and to input the password
            force_local - force a command to run locally. Mainly used for scp.
            use_container - Run this command in a container *IF* the host is
                            containerized
        """
        if not self.control_socket_exists and not self.local:
            self.log_debug('Control socket does not exist, attempting to '
                           're-create')
            try:
                _sock = self._create_ssh_session()
                if not _sock:
                    self.log_debug('Failed to re-create control socket')
                    raise ControlSocketMissingException
            except Exception as err:
                self.log_error('Cannot run command: control socket does not '
                               'exist')
                self.log_debug("Error while trying to create new SSH control "
                               "socket: %s" % err)
                raise
        if use_container and self.host.containerized:
            cmd = self.host.format_container_command(cmd)
        if need_root:
            get_pty = True
            cmd = self._format_cmd(cmd)
        self.log_debug('Running command %s' % cmd)
        if 'atomic' in cmd:
            get_pty = True
        if not self.local and not force_local:
            cmd = "%s %s" % (self.ssh_cmd, quote(cmd))
        else:
            if get_pty:
                cmd = "/bin/bash -c %s" % quote(cmd)
        res = pexpect.spawn(cmd, encoding='utf-8')
        if need_root:
            if self.need_sudo:
                res.sendline(self.opts.sudo_pw)
            if self.opts.become_root:
                res.sendline(self.opts.root_password)
        output = res.expect([pexpect.EOF, pexpect.TIMEOUT],
                            timeout=timeout)
        if output == 0:
            out = res.before
            res.close()
            rc = res.exitstatus
            return {'status': rc, 'stdout': out}
        elif output == 1:
            raise CommandTimeoutException(cmd)
Exemplo n.º 2
0
    def _run_command_with_pexpect(self, cmd, timeout, need_root, env):
        """Execute the command using pexpect, which allows us to more easily
        handle prompts and timeouts compared to directly leveraging the
        subprocess.Popen() method.

        :param cmd:     The command to execute. This will be automatically
                        formatted to use the transport.
        :type cmd:      ``str``

        :param timeout: The maximum time in seconds to run ``cmd``
        :type timeout:  ``int``

        :param need_root:   Does ``cmd`` need to run as root or with sudo?
        :type need_root:    ``bool``

        :param env:     Any env vars that ``cmd`` should be run with
        :type env:      ``dict``
        """
        cmd = self._format_cmd_for_exec(cmd)

        # if for any reason env is empty, set it to None as otherwise
        # pexpect interprets this to mean "run this command with no env vars of
        # any kind"
        if not env:
            env = None

        try:
            result = pexpect.spawn(cmd, encoding='utf-8', env=env)
        except pexpect.exceptions.ExceptionPexpect as err:
            self.log_debug(err.value)
            return {'status': 127, 'output': ''}

        _expects = [pexpect.EOF, pexpect.TIMEOUT]
        if need_root and self.opts.ssh_user != 'root':
            _expects.extend(['\\[sudo\\] password for .*:', 'Password:'******'status': result.exitstatus, 'output': out}
        elif index == 1:
            raise CommandTimeoutException(cmd)