import functools
import urllib
from sshtunnel import SSHTunnelForwarder
from urllib.parse import urlparse
import socket
from contextlib import closing
def find_free_port():
with closing(socket.socket(socket.AF_INET, socket.SOCK_STREAM)) as s:
s.bind(('', 0))
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
return s.getsockname()[1]
class SshTunnel(SSHTunnelForwarder):
_cache = dict()
@functools.lru_cache
def __init__(self, url: str, remote_port: int):
url = urlparse(url)
local_port = find_free_port()
super().__init__((url.hostname, url.port),
ssh_username=urllib.parse.unquote(url.username),
ssh_password=urllib.parse.unquote(url.password),
remote_bind_address=('localhost', remote_port),
local_bind_address=('localhost', local_port)
)
self.start()
self._server_list[0].block_on_close = False