Skip to content

Instantly share code, notes, and snippets.

@thepaul
Created May 14, 2014 20:32
Show Gist options
  • Select an option

  • Save thepaul/c3e3c99ff08993d58d4c to your computer and use it in GitHub Desktop.

Select an option

Save thepaul/c3e3c99ff08993d58d4c to your computer and use it in GitHub Desktop.
ssh tunnel up/down
import contextlib
import os
import subprocess
import tempfile
class SshTunnelDefinition:
def __init__(self, host, user=None, executable='ssh', localforwards=(),
remoteforwards=(), port=None, options=None):
self.executable = executable
self.cmd = cmd = [executable, '-N', '-f']
if user is not None:
cmd.extend(('-l', user))
if port is not None:
cmd.extend(('-p', str(port)))
for localport, fwdhost, fwdport in localforwards:
cmd.append('-L%d:%s:%d' % (localport, fwdhost, fwdport))
for remoteport, fwdhost, fwdport in remoteforwards:
cmd.append('-R%d:%s:%d' % (remoteport, fwdhost, fwdport))
for optname, optvalue in (options or {}).items():
cmd.extend(('-o', '%s=%s' % (optname, optvalue)))
self.host = host
def start_tunnel(self):
tmpdir = tempfile.mkdtemp(prefix='dispaaace-tunnel-control')
control = os.path.join(tmpdir, 'controlsock')
cmd = list(self.cmd) + ['-o', 'ControlMaster=yes',
'-o', 'ControlPath=' + control,
'-o', 'ControlPersist=no',
self.host]
result = subprocess.call(cmd, close_fds=True)
if result != 0:
raise RuntimeError('Could not create tunnel to %s' % self.host)
return control
def stop_tunnel(self, control):
cmd = [self.executable, '-O', 'exit', '-o', 'ControlPath=' + control,
'dummyhost']
subprocess.check_call(cmd, close_fds=True)
@contextlib.contextmanager
def establish_tunnel(*a, **kw):
tunneldef = SshTunnelDefinition(*a, **kw)
control = tunneldef.start_tunnel()
try:
yield
finally:
tunneldef.stop_tunnel(control)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment