示例#1
0
    def interactive_terminal_open(self, time_out=45):
        """Open interactive terminal on a SSH channel.

        :param time_out: Timeout in seconds.
        :returns: SSH channel with opened terminal.

        .. warning:: Interruptingcow is used here, and it uses
           signal(SIGALRM) to let the operating system interrupt program
           execution. This has the following limitations: Python signal
           handlers only apply to the main thread, so you cannot use this
           from other threads. You must not use this in a program that
           uses SIGALRM itself (this includes certain profilers)
        """
        chan = self._get_client().get_transport().open_session()
        chan.get_pty()
        chan.invoke_shell()
        chan.settimeout(int(time_out))
        chan.set_combine_stderr(True)

        buf = ''
        while not buf.endswith((":~# ", ":~$ ", "~]$ ", "~]# ")):
            try:
                chunk = chan.recv(10 * 1024 * 1024)
                if not chunk:
                    break
                buf += chunk
                if chan.exit_status_ready():
                    self.log.error('Channel exit status ready')
                    break
            except socket.timeout:
                raise exceptions.SSHTimeout(error_msg='Socket timeout: %s' %
                                            buf)
        return chan
示例#2
0
    def _connect(self):
        if not self.is_connected:
            interval = 1
            timeout = self.wait_timeout

            end_time = time.time() + timeout
            while True:
                try:
                    return self._get_client()
                except (socket.error, exceptions.SSHError) as e:
                    self.log.debug("Ssh is still unavailable: %r", e)
                    time.sleep(interval)
                if time.time() > end_time:
                    raise exceptions.SSHTimeout(
                        error_msg='Timeout waiting for "%s"' % self.host)
示例#3
0
    def wait(self, timeout=None, interval=1):
        """Wait for the host will be available via ssh."""
        if timeout is None:
            timeout = self.wait_timeout

        end_time = time.time() + timeout
        while True:
            try:
                return self.execute("uname")
            except (socket.error, exceptions.SSHError) as e:
                self.log.debug("Ssh is still unavailable: %r", e)
                time.sleep(interval)
            if time.time() > end_time:
                raise exceptions.SSHTimeout(
                    error_msg='Timeout waiting for "%s"' % self.host)
示例#4
0
    def interactive_terminal_exec_command(self, chan, cmd, prompt):
        """Execute command on interactive terminal.

        interactive_terminal_open() method has to be called first!

        :param chan: SSH channel with opened terminal.
        :param cmd: Command to be executed.
        :param prompt: Command prompt, sequence of characters used to
        indicate readiness to accept commands.
        :returns: Command output.

        .. warning:: Interruptingcow is used here, and it uses
           signal(SIGALRM) to let the operating system interrupt program
           execution. This has the following limitations: Python signal
           handlers only apply to the main thread, so you cannot use this
           from other threads. You must not use this in a program that
           uses SIGALRM itself (this includes certain profilers)
        """
        chan.sendall('{c}\n'.format(c=cmd))
        buf = ''
        while not buf.endswith(prompt):
            try:
                chunk = chan.recv(10 * 1024 * 1024)
                if not chunk:
                    break
                buf += chunk
                if chan.exit_status_ready():
                    self.log.error('Channel exit status ready')
                    break
            except socket.timeout:
                message = ("Socket timeout during execution of command: "
                           "%(cmd)s\nBuffer content:\n%(buf)s" % {
                               "cmd": cmd,
                               "buf": buf
                           })
                raise exceptions.SSHTimeout(error_msg=message)
        tmp = buf.replace(cmd.replace('\n', ''), '')
        for item in prompt:
            tmp.replace(item, '')
        return tmp
示例#5
0
    def _run(self, client, cmd, stdin=None, stdout=None, stderr=None,
             raise_on_error=True, timeout=3600,
             keep_stdin_open=False, pty=False):

        transport = client.get_transport()
        session = transport.open_session()
        if pty:
            session.get_pty()
        session.exec_command(cmd)
        start_time = time.time()

        # encode on transmit, decode on receive
        data_to_send = encodeutils.safe_encode("", incoming='utf-8')
        stderr_data = None

        # If we have data to be sent to stdin then `select' should also
        # check for stdin availability.
        if stdin and not stdin.closed:
            writes = [session]
        else:
            writes = []

        while True:
            # Block until data can be read/write.
            e = select.select([session], writes, [session], 1)[2]

            if session.recv_ready():
                data = encodeutils.safe_decode(session.recv(4096), 'utf-8')
                self.log.debug("stdout: %r", data)
                if stdout is not None:
                    stdout.write(data)
                continue

            if session.recv_stderr_ready():
                stderr_data = encodeutils.safe_decode(
                    session.recv_stderr(4096), 'utf-8')
                self.log.debug("stderr: %r", stderr_data)
                if stderr is not None:
                    stderr.write(stderr_data)
                continue

            if session.send_ready():
                if stdin is not None and not stdin.closed:
                    if not data_to_send:
                        stdin_txt = stdin.read(4096)
                        if stdin_txt is None:
                            stdin_txt = ''
                        data_to_send = encodeutils.safe_encode(
                            stdin_txt, incoming='utf-8')
                        if not data_to_send:
                            # we may need to keep stdin open
                            if not keep_stdin_open:
                                stdin.close()
                                session.shutdown_write()
                                writes = []
                    if data_to_send:
                        sent_bytes = session.send(data_to_send)
                        # LOG.debug("sent: %s" % data_to_send[:sent_bytes])
                        data_to_send = data_to_send[sent_bytes:]

            if session.exit_status_ready():
                break

            if timeout and (time.time() - timeout) > start_time:
                message = ('Timeout executing command %(cmd)s on host %(host)s'
                           % {"cmd": cmd, "host": self.host})
                raise exceptions.SSHTimeout(error_msg=message)
            if e:
                raise exceptions.SSHError(error_msg='Socket error')

        exit_status = session.recv_exit_status()
        if exit_status != 0 and raise_on_error:
            fmt = "Command '%(cmd)s' failed with exit_status %(status)d."
            details = fmt % {"cmd": cmd, "status": exit_status}
            if stderr_data:
                details += " Last stderr data: '%s'." % stderr_data
            raise exceptions.SSHError(error_msg=details)
        return exit_status