diff options
Diffstat (limited to 'contrib/python/podman/libs/tunnel.py')
-rw-r--r-- | contrib/python/podman/libs/tunnel.py | 138 |
1 files changed, 0 insertions, 138 deletions
diff --git a/contrib/python/podman/libs/tunnel.py b/contrib/python/podman/libs/tunnel.py deleted file mode 100644 index 9effdff6c..000000000 --- a/contrib/python/podman/libs/tunnel.py +++ /dev/null @@ -1,138 +0,0 @@ -"""Cache for SSH tunnels.""" -import collections -import logging -import os -import subprocess -import threading -import time -import weakref - -Context = collections.namedtuple('Context', ( - 'uri', - 'interface', - 'local_socket', - 'remote_socket', - 'username', - 'hostname', - 'identity_file', -)) - - -class Portal(collections.MutableMapping): - """Expiring container for tunnels.""" - - def __init__(self, sweap=25): - """Construct portal, reap tunnels every sweap seconds.""" - self.data = collections.OrderedDict() - self.sweap = sweap - self.ttl = sweap * 2 - self.lock = threading.RLock() - self._schedule_reaper() - - def __getitem__(self, key): - """Given uri return tunnel and update TTL.""" - with self.lock: - value, _ = self.data[key] - self.data[key] = (value, time.time() + self.ttl) - self.data.move_to_end(key) - return value - - def __setitem__(self, key, value): - """Store given tunnel keyed with uri.""" - if not isinstance(value, Tunnel): - raise ValueError('Portals only support Tunnels.') - - with self.lock: - self.data[key] = (value, time.time() + self.ttl) - self.data.move_to_end(key) - - def __delitem__(self, key): - """Remove and close tunnel from portal.""" - with self.lock: - value, _ = self.data[key] - del self.data[key] - value.close(key) - del value - - def __iter__(self): - """Iterate tunnels.""" - with self.lock: - values = self.data.values() - - for tunnel, _ in values: - yield tunnel - - def __len__(self): - """Return number of tunnels in portal.""" - with self.lock: - return len(self.data) - - def _schedule_reaper(self): - timer = threading.Timer(interval=self.sweap, function=self.reap) - timer.setName('PortalReaper') - timer.setDaemon(True) - timer.start() - - def reap(self): - """Remove tunnels who's TTL has expired.""" - now = time.time() - with self.lock: - reaped_data = self.data.copy() - for entry in reaped_data.items(): - if entry[1][1] < now: - del self.data[entry[0]] - else: - # StopIteration as soon as possible - break - self._schedule_reaper() - - -class Tunnel(object): - """SSH tunnel.""" - - def __init__(self, context): - """Construct Tunnel.""" - self.context = context - self._tunnel = None - - def bore(self, id): - """Create SSH tunnel from given context.""" - ssh_opts = '-nNT' - if logging.getLogger().getEffectiveLevel() == logging.DEBUG: - ssh_opts += 'v' - else: - ssh_opts += 'q' - - cmd = [ - 'ssh', - ssh_opts, - '-L', - '{}:{}'.format(self.context.local_socket, - self.context.remote_socket), - '-i', - self.context.identity_file, - 'ssh://{}@{}'.format(self.context.username, self.context.hostname), - ] - logging.debug('Tunnel cmd "{}"'.format(' '.join(cmd))) - - self._tunnel = subprocess.Popen(cmd, close_fds=True) - for i in range(10): - # TODO: Make timeout configurable - if os.path.exists(self.context.local_socket): - break - time.sleep(0.5) - else: - raise TimeoutError('Failed to create tunnel using: {}'.format( - ' '.join(cmd))) - weakref.finalize(self, self.close, id) - return self - - def close(self, id): - """Close SSH tunnel.""" - if self._tunnel is None: - return - - self._tunnel.kill() - self._tunnel.wait(300) - os.remove(self.context.local_socket) - self._tunnel = None |