host.connections

Connection management for remote hosts.

ConnectionManager owns all raw transport connections (SSH, SFTP, FTP, Telnet) for a single remote host. It provides lazy-connect coroutines that create the connection on first call and reuse it thereafter.

When a HopTransport is provided (via the hop parameter), all connections are routed through the hop’s SSH tunnel:

  • SSH connections use asyncssh’s native tunnel parameter.

  • Telnet connections use SSH local port forwarding to reach the target through the tunnel.

  • SFTP piggybacks on the (already tunneled) SSH connection.

  • FTP uses TunneledFtpClient, which forwards the control port and dynamically forwards each PASV data port through the tunnel.

  • Netcat transfers use forward_port to reach the remote nc listener through the tunnel (both PUT and GET directions).

Inject a subclass via RemoteHost._connection_factory to replace the real transport with a test double — no monkeypatching of library functions needed.

class otto.host.connections.TunneledFtpClient(hop, dest_host, **kwargs)

Bases: Client

aioftp Client that routes FTP data connections through an SSH hop.

FTP passive mode announces dynamic data ports via PASV responses. This subclass intercepts each data connection attempt and creates a corresponding SSH port forward so the data flows through the tunnel alongside the control connection.

The control connection (port 21) is already forwarded by ConnectionManager before connect() is called, so the tunnel override is only activated after the control connection is established.

async connect(host, port=21)

asyncio.coroutine()

Connect to server.

Parameters:
host

host name for connection

port=21

port number for connection

Return type:

list[str]

class otto.host.connections.ConnectionManager(ip, creds, user, term, name, hop=None, ssh_options=None, telnet_options=None, sftp_options=None, ftp_options=None)

Bases: object

Owns all raw transport connections for a single remote host.

Connections are created lazily and reused across calls. Call close() to release all open connections.

When a HopTransport is provided (via the hop parameter), an SSH tunnel to the hop host is established lazily on first use. All protocol connections are then routed through this tunnel rather than connecting directly to the target IP.

Subclass and inject via RemoteHost._connection_factory to swap in test doubles without monkeypatching library functions:

class FakeConnections(ConnectionManager):
    def __init__(self, ip, creds, user, term, name):
        self._ssh_conn = AsyncMock(spec=SSHClientConnection)
        self._sftp_conn = None
        self._ftp_conn = None
        self._telnet_conn = None

    async def ssh(self):
        return self._ssh_conn

host = RemoteHost(..., _connection_factory=FakeConnections)
property telnet_options : TelnetOptions

Expose the stored TelnetOptions so callers that build their own TelnetClient (e.g. SessionManager.open_session) can honor the same configuration.

property credentials : tuple[str, str]

Return the active (username, password) pair.

property ip : str
property term : 'ssh' | 'telnet'
property connected : bool

Whether any raw connection is currently open.

property has_tunnel : bool

Whether this connection manager is configured to use a tunnel.

async ssh()

Return the live SSH connection, opening it if needed.

Return type:

SSHClientConnection

async sftp()

Return the live SFTP client, opening it (and SSH if needed) first.

Return type:

SFTPClient

async ftp()

Return the live FTP client, opening it if needed.

Return type:

Client

async telnet()

Return the live TelnetClient, opening it if needed.

Return type:

TelnetClient

async forward_port(dest_port)

Forward a local ephemeral port to self._ip:dest_port through the tunnel.

This is the public interface for protocols (like netcat) that need additional port forwards beyond the standard ones managed internally.

Returns the local port number to connect to.

Raises RuntimeError if no tunnel is configured.

Return type:

int

async close()

Close all open connections, port forwards, and the tunnel.

Return type:

None