def execute(self, cmd, quiet=False): """Execute a command on a remote SSH server. :param cmd: Command for execution. :type cmd: str :param quiet: if quiet is True don't print error messages :return: Handlers of stdin, stdout and stderr :rtype: tuple :raise SshDestinationError: if any error """ try: with self._shell() as shell: LOG.debug('Executing %s', cmd) stdin_, stdout_, stderr_ = shell.exec_command(cmd) # while not stdout_.channel.exit_status_ready(): # LOG.debug('%s: waiting', cmd) # time.sleep(1) exit_code = stdout_.channel.recv_exit_status() if exit_code != 0: if not quiet: LOG.error("Failed while execute command %s", cmd) LOG.error(stderr_.read()) raise SshClientException('%s exited with code %d' % (cmd, exit_code)) return stdin_, stdout_, stderr_ except (SSHException, IOError) as err: if not quiet: LOG.error('Failed to execute %s: %s', cmd, err) raise SshClientException('Failed to execute %s: %s' % (cmd, err))
def execute(self, cmd, quiet=False, background=False): """Execute a command on a remote SSH server. :param cmd: Command for execution. :type cmd: str :param quiet: if quiet is True don't print error messages :param background: Don't wait until the command exits. :type background: bool :return: Strings with stdout and stderr. If command is executed in background the method will return None. :rtype: tuple :raise SshClientException: if any error or non-zero exit code """ max_chunk_size = 1024 * 1024 try: with self._shell() as shell: if not background: LOG.debug('Executing command: %s', cmd) stdin_, stdout_, _ = shell.exec_command(cmd) channel = stdout_.channel stdin_.close() channel.shutdown_write() stdout_chunks = [] stderr_chunks = [] while not channel.closed \ or channel.recv_ready() \ or channel.recv_stderr_ready(): if channel.recv_ready(): stdout_chunks.append( channel.recv(max_chunk_size).decode("utf-8")) if channel.recv_stderr_ready(): stderr_chunks.append( channel.recv_stderr(max_chunk_size).decode( "utf-8")) exit_code = channel.recv_exit_status() if exit_code != 0: if not quiet: LOG.error("Failed to execute command %s", cmd) LOG.error(''.join(stderr_chunks)) raise SshClientException('%s exited with code %d' % (cmd, exit_code)) return ''.join(stdout_chunks), ''.join(stderr_chunks) else: LOG.debug('Executing in background: %s', cmd) transport = shell.get_transport() channel = transport.open_session() channel.exec_command(cmd) LOG.debug('Ran %s in background', cmd) except (SSHException, IOError) as err: if not quiet: LOG.error('Failed to execute %s: %s', cmd, err) raise SshClientException('Failed to execute %s: %s' % (cmd, err))
def _shell(self): """ Create SSHClient instance and connect to the destination host. :return: Connected to the remote destination host shell. :rtype: generator(SSHClient) :raise SshDestinationError: if the ssh client fails to connect. """ shell = SSHClient() shell.set_missing_host_key_policy(AutoAddPolicy()) try: LOG.debug("Connecting to %s:%d as %s with key %s", self._host, self._port, self._user, self._key) shell.connect(hostname=self._host, key_filename=self._key, port=self._port, username=self._user) yield shell except FileNotFoundError: raise except (AuthenticationException, SSHException, socket.error) as err: # print(type(err)) raise SshClientException(err) finally: shell.close()
def get_remote_handlers(self, cmd): """Get remote stdin, stdout and stderr handler :param cmd: Command for execution :type cmd: str :return: Remote stdin, stdout and stderr handler :rtype: tuple(generator, generator, generator) :raise SshDestinationError: if any error """ try: with self._shell() as shell: stdin_, stdout_, stderr_ = shell.exec_command(cmd) yield stdin_, stdout_, stderr_ except SSHException as err: LOG.error('Failed to execute %s', cmd) raise SshClientException(err)
def _shell(self): """ Create SSHClient instance and connect to the destination host. :return: Connected to the remote destination host shell. :rtype: generator(SSHClient) :raise SshDestinationError: if the ssh client fails to connect. """ shell = SSHClient() shell.set_missing_host_key_policy(AutoAddPolicy()) try: shell.connect(hostname=self.ssh_connect_info.host, key_filename=self.ssh_connect_info.key, port=self.ssh_connect_info.port, username=self.ssh_connect_info.user) yield shell except (AuthenticationException, SSHException, socket.error) as err: raise SshClientException(err) finally: shell.close()