diff --git a/IPython/external/ssh/__init__.py b/IPython/external/ssh/__init__.py deleted file mode 100644 index 9e5e8b9..0000000 --- a/IPython/external/ssh/__init__.py +++ /dev/null @@ -1,7 +0,0 @@ -"""This is a copy of zmq.ssh""" - -try: - from zmq.ssh import * -except ImportError: - from . import tunnel - from .tunnel import * diff --git a/IPython/external/ssh/forward.py b/IPython/external/ssh/forward.py deleted file mode 100644 index 2d61946..0000000 --- a/IPython/external/ssh/forward.py +++ /dev/null @@ -1,91 +0,0 @@ -# -# This file is adapted from a paramiko demo, and thus licensed under LGPL 2.1. -# Original Copyright (C) 2003-2007 Robey Pointer -# Edits Copyright (C) 2010 The IPython Team -# -# Paramiko is free software; you can redistribute it and/or modify it under the -# terms of the GNU Lesser General Public License as published by the Free -# Software Foundation; either version 2.1 of the License, or (at your option) -# any later version. -# -# Paramiko is distrubuted in the hope that it will be useful, but WITHOUT ANY -# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR -# A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more -# details. -# -# You should have received a copy of the GNU Lesser General Public License -# along with Paramiko; if not, write to the Free Software Foundation, Inc., -# 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA. - -""" -Sample script showing how to do local port forwarding over paramiko. - -This script connects to the requested SSH server and sets up local port -forwarding (the openssh -L option) from a local port through a tunneled -connection to a destination reachable from the SSH server machine. -""" - -from __future__ import print_function - -import logging -import select -try: # Python 3 - import socketserver -except ImportError: # Python 2 - import SocketServer as socketserver - -logger = logging.getLogger('ssh') - -class ForwardServer (socketserver.ThreadingTCPServer): - daemon_threads = True - allow_reuse_address = True - - -class Handler (socketserver.BaseRequestHandler): - - def handle(self): - try: - chan = self.ssh_transport.open_channel('direct-tcpip', - (self.chain_host, self.chain_port), - self.request.getpeername()) - except Exception as e: - logger.debug('Incoming request to %s:%d failed: %s' % (self.chain_host, - self.chain_port, - repr(e))) - return - if chan is None: - logger.debug('Incoming request to %s:%d was rejected by the SSH server.' % - (self.chain_host, self.chain_port)) - return - - logger.debug('Connected! Tunnel open %r -> %r -> %r' % (self.request.getpeername(), - chan.getpeername(), (self.chain_host, self.chain_port))) - while True: - r, w, x = select.select([self.request, chan], [], []) - if self.request in r: - data = self.request.recv(1024) - if len(data) == 0: - break - chan.send(data) - if chan in r: - data = chan.recv(1024) - if len(data) == 0: - break - self.request.send(data) - chan.close() - self.request.close() - logger.debug('Tunnel closed ') - - -def forward_tunnel(local_port, remote_host, remote_port, transport): - # this is a little convoluted, but lets me configure things for the Handler - # object. (SocketServer doesn't give Handlers any way to access the outer - # server normally.) - class SubHander (Handler): - chain_host = remote_host - chain_port = remote_port - ssh_transport = transport - ForwardServer(('127.0.0.1', local_port), SubHander).serve_forever() - - -__all__ = ['forward_tunnel'] diff --git a/IPython/external/ssh/tunnel.py b/IPython/external/ssh/tunnel.py deleted file mode 100644 index 0cf9bcb..0000000 --- a/IPython/external/ssh/tunnel.py +++ /dev/null @@ -1,356 +0,0 @@ -"""Basic ssh tunnel utilities, and convenience functions for tunneling -zeromq connections. - -Authors -------- -* Min RK -""" - -#----------------------------------------------------------------------------- -# Copyright (C) 2010-2011 The IPython Development Team -# -# Distributed under the terms of the BSD License. The full license is in -# the file COPYING, distributed as part of this software. -#----------------------------------------------------------------------------- - - - -#----------------------------------------------------------------------------- -# Imports -#----------------------------------------------------------------------------- - -from __future__ import print_function - -import os,sys, atexit -import signal -import socket -from multiprocessing import Process -from getpass import getpass, getuser -import warnings - -try: - with warnings.catch_warnings(): - warnings.simplefilter('ignore', DeprecationWarning) - import paramiko -except ImportError: - paramiko = None -else: - from .forward import forward_tunnel - -try: - from IPython.external import pexpect -except ImportError: - pexpect = None - -#----------------------------------------------------------------------------- -# Code -#----------------------------------------------------------------------------- - -# select_random_ports copied from IPython.parallel.util -_random_ports = set() - -def select_random_ports(n): - """Selects and return n random ports that are available.""" - ports = [] - for i in xrange(n): - sock = socket.socket() - sock.bind(('', 0)) - while sock.getsockname()[1] in _random_ports: - sock.close() - sock = socket.socket() - sock.bind(('', 0)) - ports.append(sock) - for i, sock in enumerate(ports): - port = sock.getsockname()[1] - sock.close() - ports[i] = port - _random_ports.add(port) - return ports - - -#----------------------------------------------------------------------------- -# Check for passwordless login -#----------------------------------------------------------------------------- - -def try_passwordless_ssh(server, keyfile, paramiko=None): - """Attempt to make an ssh connection without a password. - This is mainly used for requiring password input only once - when many tunnels may be connected to the same server. - - If paramiko is None, the default for the platform is chosen. - """ - if paramiko is None: - paramiko = sys.platform == 'win32' - if not paramiko: - f = _try_passwordless_openssh - else: - f = _try_passwordless_paramiko - return f(server, keyfile) - -def _try_passwordless_openssh(server, keyfile): - """Try passwordless login with shell ssh command.""" - if pexpect is None: - raise ImportError("pexpect unavailable, use paramiko") - cmd = 'ssh -f '+ server - if keyfile: - cmd += ' -i ' + keyfile - cmd += ' exit' - p = pexpect.spawn(cmd) - while True: - try: - p.expect('[Pp]assword:', timeout=.1) - except pexpect.TIMEOUT: - continue - except pexpect.EOF: - return True - else: - return False - -def _try_passwordless_paramiko(server, keyfile): - """Try passwordless login with paramiko.""" - if paramiko is None: - msg = "Paramiko unavaliable, " - if sys.platform == 'win32': - msg += "Paramiko is required for ssh tunneled connections on Windows." - else: - msg += "use OpenSSH." - raise ImportError(msg) - username, server, port = _split_server(server) - client = paramiko.SSHClient() - client.load_system_host_keys() - client.set_missing_host_key_policy(paramiko.WarningPolicy()) - try: - client.connect(server, port, username=username, key_filename=keyfile, - look_for_keys=True) - except paramiko.AuthenticationException: - return False - else: - client.close() - return True - - -def tunnel_connection(socket, addr, server, keyfile=None, password=None, paramiko=None, timeout=60): - """Connect a socket to an address via an ssh tunnel. - - This is a wrapper for socket.connect(addr), when addr is not accessible - from the local machine. It simply creates an ssh tunnel using the remaining args, - and calls socket.connect('tcp://localhost:lport') where lport is the randomly - selected local port of the tunnel. - - """ - new_url, tunnel = open_tunnel(addr, server, keyfile=keyfile, password=password, paramiko=paramiko, timeout=timeout) - socket.connect(new_url) - return tunnel - - -def open_tunnel(addr, server, keyfile=None, password=None, paramiko=None, timeout=60): - """Open a tunneled connection from a 0MQ url. - - For use inside tunnel_connection. - - Returns - ------- - - (url, tunnel): The 0MQ url that has been forwarded, and the tunnel object - """ - - lport = select_random_ports(1)[0] - transport, addr = addr.split('://') - ip,rport = addr.split(':') - rport = int(rport) - if paramiko is None: - paramiko = sys.platform == 'win32' - if paramiko: - tunnelf = paramiko_tunnel - else: - tunnelf = openssh_tunnel - - tunnel = tunnelf(lport, rport, server, remoteip=ip, keyfile=keyfile, password=password, timeout=timeout) - return 'tcp://127.0.0.1:%i'%lport, tunnel - -def openssh_tunnel(lport, rport, server, remoteip='127.0.0.1', keyfile=None, password=None, timeout=60): - """Create an ssh tunnel using command-line ssh that connects port lport - on this machine to localhost:rport on server. The tunnel - will automatically close when not in use, remaining open - for a minimum of timeout seconds for an initial connection. - - This creates a tunnel redirecting `localhost:lport` to `remoteip:rport`, - as seen from `server`. - - keyfile and password may be specified, but ssh config is checked for defaults. - - Parameters - ---------- - - lport : int - local port for connecting to the tunnel from this machine. - rport : int - port on the remote machine to connect to. - server : str - The ssh server to connect to. The full ssh server string will be parsed. - user@server:port - remoteip : str [Default: 127.0.0.1] - The remote ip, specifying the destination of the tunnel. - Default is localhost, which means that the tunnel would redirect - localhost:lport on this machine to localhost:rport on the *server*. - - keyfile : str; path to public key file - This specifies a key to be used in ssh login, default None. - Regular default ssh keys will be used without specifying this argument. - password : str; - Your ssh password to the ssh server. Note that if this is left None, - you will be prompted for it if passwordless key based login is unavailable. - timeout : int [default: 60] - The time (in seconds) after which no activity will result in the tunnel - closing. This prevents orphaned tunnels from running forever. - """ - if pexpect is None: - raise ImportError("pexpect unavailable, use paramiko_tunnel") - ssh="ssh " - if keyfile: - ssh += "-i " + keyfile - - if ':' in server: - server, port = server.split(':') - ssh += " -p %s" % port - - cmd = "%s -f -S none -L 127.0.0.1:%i:%s:%i %s sleep %i" % ( - ssh, lport, remoteip, rport, server, timeout) - tunnel = pexpect.spawn(cmd) - failed = False - while True: - try: - tunnel.expect('[Pp]assword:', timeout=.1) - except pexpect.TIMEOUT: - continue - except pexpect.EOF: - if tunnel.exitstatus: - print (tunnel.exitstatus) - print (tunnel.before) - print (tunnel.after) - raise RuntimeError("tunnel '%s' failed to start"%(cmd)) - else: - return tunnel.pid - else: - if failed: - print("Password rejected, try again") - password=None - if password is None: - password = getpass("%s's password: "%(server)) - tunnel.sendline(password) - failed = True - -def _split_server(server): - if '@' in server: - username,server = server.split('@', 1) - else: - username = getuser() - if ':' in server: - server, port = server.split(':') - port = int(port) - else: - port = 22 - return username, server, port - -def paramiko_tunnel(lport, rport, server, remoteip='127.0.0.1', keyfile=None, password=None, timeout=60): - """launch a tunner with paramiko in a subprocess. This should only be used - when shell ssh is unavailable (e.g. Windows). - - This creates a tunnel redirecting `localhost:lport` to `remoteip:rport`, - as seen from `server`. - - If you are familiar with ssh tunnels, this creates the tunnel: - - ssh server -L localhost:lport:remoteip:rport - - keyfile and password may be specified, but ssh config is checked for defaults. - - - Parameters - ---------- - - lport : int - local port for connecting to the tunnel from this machine. - rport : int - port on the remote machine to connect to. - server : str - The ssh server to connect to. The full ssh server string will be parsed. - user@server:port - remoteip : str [Default: 127.0.0.1] - The remote ip, specifying the destination of the tunnel. - Default is localhost, which means that the tunnel would redirect - localhost:lport on this machine to localhost:rport on the *server*. - - keyfile : str; path to public key file - This specifies a key to be used in ssh login, default None. - Regular default ssh keys will be used without specifying this argument. - password : str; - Your ssh password to the ssh server. Note that if this is left None, - you will be prompted for it if passwordless key based login is unavailable. - timeout : int [default: 60] - The time (in seconds) after which no activity will result in the tunnel - closing. This prevents orphaned tunnels from running forever. - - """ - if paramiko is None: - raise ImportError("Paramiko not available") - - if password is None: - if not _try_passwordless_paramiko(server, keyfile): - password = getpass("%s's password: "%(server)) - - p = Process(target=_paramiko_tunnel, - args=(lport, rport, server, remoteip), - kwargs=dict(keyfile=keyfile, password=password)) - p.daemon=False - p.start() - atexit.register(_shutdown_process, p) - return p - -def _shutdown_process(p): - if p.is_alive(): - p.terminate() - -def _paramiko_tunnel(lport, rport, server, remoteip, keyfile=None, password=None): - """Function for actually starting a paramiko tunnel, to be passed - to multiprocessing.Process(target=this), and not called directly. - """ - username, server, port = _split_server(server) - client = paramiko.SSHClient() - client.load_system_host_keys() - client.set_missing_host_key_policy(paramiko.WarningPolicy()) - - try: - client.connect(server, port, username=username, key_filename=keyfile, - look_for_keys=True, password=password) -# except paramiko.AuthenticationException: -# if password is None: -# password = getpass("%s@%s's password: "%(username, server)) -# client.connect(server, port, username=username, password=password) -# else: -# raise - except Exception as e: - print ('*** Failed to connect to %s:%d: %r' % (server, port, e)) - sys.exit(1) - - # Don't let SIGINT kill the tunnel subprocess - signal.signal(signal.SIGINT, signal.SIG_IGN) - - try: - forward_tunnel(lport, remoteip, rport, client.get_transport()) - except KeyboardInterrupt: - print ('SIGINT: Port forwarding stopped cleanly') - sys.exit(0) - except Exception as e: - print ("Port forwarding stopped uncleanly: %s"%e) - sys.exit(255) - -if sys.platform == 'win32': - ssh_tunnel = paramiko_tunnel -else: - ssh_tunnel = openssh_tunnel - - -__all__ = ['tunnel_connection', 'ssh_tunnel', 'openssh_tunnel', 'paramiko_tunnel', 'try_passwordless_ssh'] - - diff --git a/IPython/kernel/connect.py b/IPython/kernel/connect.py index 122b7de..c5b82a2 100644 --- a/IPython/kernel/connect.py +++ b/IPython/kernel/connect.py @@ -22,9 +22,7 @@ from subprocess import Popen, PIPE import tempfile import zmq - -# external imports -from IPython.external.ssh import tunnel +from zmq.ssh import tunnel # IPython imports from IPython.config import LoggingConfigurable diff --git a/IPython/parallel/client/client.py b/IPython/parallel/client/client.py index 87ad3aa..6ad1689 100644 --- a/IPython/parallel/client/client.py +++ b/IPython/parallel/client/client.py @@ -18,6 +18,7 @@ from pprint import pprint pjoin = os.path.join import zmq +from zmq.ssh import tunnel from IPython.config.configurable import MultipleInstanceError from IPython.core.application import BaseIPythonApplication @@ -32,7 +33,6 @@ from IPython.utils.py3compat import cast_bytes, string_types, xrange, iteritems from IPython.utils.traitlets import (HasTraits, Integer, Instance, Unicode, Dict, List, Bool, Set, Any) from IPython.external.decorator import decorator -from IPython.external.ssh import tunnel from IPython.parallel import Reference from IPython.parallel import error diff --git a/IPython/parallel/engine/engine.py b/IPython/parallel/engine/engine.py index 5cd289d..4ae801c 100644 --- a/IPython/parallel/engine/engine.py +++ b/IPython/parallel/engine/engine.py @@ -14,9 +14,8 @@ from getpass import getpass import zmq from zmq.eventloop import ioloop, zmqstream +from zmq.ssh import tunnel -from IPython.external.ssh import tunnel -# internal from IPython.utils.localinterfaces import localhost from IPython.utils.traitlets import ( Instance, Dict, Integer, Type, Float, Integer, Unicode, CBytes, Bool