Repository: ipython/ipython

Issue:
Control-C kills port forwarding
```
In [1]: from IPython.parallel import Client

In [2]: c = Client() # this works as expected

In [3]: <Control-C> SIGINT: Port forwarding stopped cleanly
SIGINT: Port forwarding stopped cleanly
SIGINT: Port forwarding stopped cleanly
SIGINT: Port forwarding stopped cleanly
SIGINT: Port forwarding stopped cleanly
SIGINT: Port forwarding stopped cleanly

KeyboardInterrupt
```

It seems that pressing Control-C at the prompt propagates to ssh, killing the tunnels.



Discussion:
Can you test #2526?

Commit 6cf3f27eec8a5c8ecbfae014311cc6e315b2cbc1 gives me this, but it's not its fault as the master branch at afa2e6c5136921d9f47f96b02a3f4de195574726 shows the same problem.

```
In [7]: c = Client('/home/abedini/mounts/SFTP on maia/home/hs/staff/abedini/.ipython/profile_default/security/ipcontroller-client.json', paramiko = True)
---------------------------------------------------------------------------
KeyError                                  Traceback (most recent call last)
<ipython-input-7-d5b444c914e2> in <module>()
----> 1 c = Client('/home/abedini/mounts/SFTP on maia/home/hs/staff/abedini/.ipython/profile_default/security/ipcontroller-client.json', paramiko = True)

/home/abedini/ipython/IPython/parallel/client/client.py in __init__(self, url_file, profile, profile_dir, ipython_dir, context, debug, sshserver, sshkey, password, paramiko, timeout, cluster_id, **extra_args)
    410             cfg = json.load(f)
    411 
--> 412         self._task_scheme = cfg['task_scheme']
    413 
    414         # sync defaults from args, json:

KeyError: 'task_scheme'
```

that suggests that you have conflicting versions of IPython on the controller/client.  Can you make sure all of controller/engine/client are running the same version of IPython?

I apologise, I didn't know that was such hard requirement, everything is now running 6cf3f27eec8a5c8ecbfae014311cc6e315b2cbc1 but it doesn't seem to fix the problem for me

'''
In [4]: SIGINT: Port forwarding stopped cleanly
SIGINT: Port forwarding stopped cleanly
SIGINT: Port forwarding stopped cleanly
SIGINT: Port forwarding stopped cleanly

KeyboardInterrupt

In [4]: SIGINT: Port forwarding stopped cleanly
SIGINT: Port forwarding stopped cleanly
'''

Cn you give more platform details (OS Version / distro, Python version, ssh versions, terminal, etc.)?  Because I cannot reproduce this.

Hi, sorry for taking so long to get back to you. I tested everything again and I confirm that the patch does not do the job for me.

Controller is an Red Hat Enterprise Linux Server release 5.8, python 2.7.3 (compiled myself), OpenSSH_4.3p2.

Client is running openSUSE 12.2, Python 2.7.3, OpenSSH_6.0p1.

On both is running iPython at commit 6cf3f27. I also need to say that using openssh I can't get the client to establish a connection with the controller. I'm launching the controller with --ssh option, the Client constructor launches a connection but gets stuck (I seems to have something to do with the Client waiting for a password prompt that is not appearing because I am using ssh keys to get in). So I use paramiko (1.8.0) to connect (and the connection works well, I tested).

Thanks

> [it] seems to have something to do with the Client waiting for a password prompt that is not appearing because I am using ssh keys to get in

Hm, weird.  I only ever use it with passwordless SSH key login, so that definitely works in some cases.  I wonder what could be going wrong.

> So I use paramiko (1.8.0) to connect (and the connection works well, I tested).

Ah, that's important!  I only applied the fix to OpenSSH.  I will add setpgrp to paramiko as well.


Resolving patch:
diff --git a/IPython/external/ssh/tunnel.py b/IPython/external/ssh/tunnel.py
--- a/IPython/external/ssh/tunnel.py
+++ b/IPython/external/ssh/tunnel.py
@@ -22,6 +22,7 @@
 from __future__ import print_function
 
 import os,sys, atexit
+import signal
 import socket
 from multiprocessing import Process
 from getpass import getpass, getuser
@@ -331,9 +332,10 @@ def _paramiko_tunnel(lport, rport, server, remoteip, keyfile=None, password=None
     except Exception as e:
         print ('*** Failed to connect to %s:%d: %r' % (server, port, e))
         sys.exit(1)
-
-    # print ('Now forwarding port %d to %s:%d ...' % (lport, server, rport))
-
+    
+    # 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:


Test patch: