import logging import paramiko.client as pmc from ._sshfp_policy import SSHFPPolicy class SSHConnection: """ An SSH client connection to a remote server, with support for a proxy "jump" host, like OpenSSH's 'ssh -J'. Uses only SSHFP for host key verification. May be used as a context manager. :param SSHRemote remote: Remote host to connect to. """ _proxy_conn = None _client = None _remote = None _logger = None def __init__(self, remote): self._logger = logging.getLogger('%s.%s' % (self.__class__.__name__, str(remote))) self._logger.debug('Connecting to remote host...') sock = None if remote.proxy_remote is not None: self._proxy_conn = SSHConnection(remote.proxy_remote) t = self._proxy_conn.get_transport() sock = t.open_channel('direct-tcpip', (remote.host, remote.port), ('localhost', 0)) self._client = pmc.SSHClient() self._client.set_missing_host_key_policy(SSHFPPolicy()) self._client.connect(remote.host, remote.port, remote.username, sock = sock) self._logger.debug('Connected to remote host') self._remote = remote def close(self): self._logger.debug('Disconnecting from remote host') if self._client: self._client.close() self._client = None if self._proxy_conn: self._proxy_conn.close() self._proxy_conn = None self._logger.debug('Disconnected from remote host') def exec_command(self, *args, **kwargs): return self._client.exec_command(*args, **kwargs) def get_transport(self): return self._client.get_transport() def __enter__(self): return self def __exit__(self, exc_type, exc_value, traceback): self.close() def __str__(self): return 'ssh:%s' % str(self._remote)