##// END OF EJS Templates
fix typo in write_connection_file
MinRK -
Show More
@@ -1,538 +1,538 b''
1 """Utilities for connecting to kernels
1 """Utilities for connecting to kernels
2
2
3 Authors:
3 Authors:
4
4
5 * Min Ragan-Kelley
5 * Min Ragan-Kelley
6
6
7 """
7 """
8
8
9 #-----------------------------------------------------------------------------
9 #-----------------------------------------------------------------------------
10 # Copyright (C) 2013 The IPython Development Team
10 # Copyright (C) 2013 The IPython Development Team
11 #
11 #
12 # Distributed under the terms of the BSD License. The full license is in
12 # Distributed under the terms of the BSD License. The full license is in
13 # the file COPYING, distributed as part of this software.
13 # the file COPYING, distributed as part of this software.
14 #-----------------------------------------------------------------------------
14 #-----------------------------------------------------------------------------
15
15
16 #-----------------------------------------------------------------------------
16 #-----------------------------------------------------------------------------
17 # Imports
17 # Imports
18 #-----------------------------------------------------------------------------
18 #-----------------------------------------------------------------------------
19
19
20 from __future__ import absolute_import
20 from __future__ import absolute_import
21
21
22 import glob
22 import glob
23 import json
23 import json
24 import os
24 import os
25 import socket
25 import socket
26 import sys
26 import sys
27 from getpass import getpass
27 from getpass import getpass
28 from subprocess import Popen, PIPE
28 from subprocess import Popen, PIPE
29 import tempfile
29 import tempfile
30
30
31 import zmq
31 import zmq
32
32
33 # external imports
33 # external imports
34 from IPython.external.ssh import tunnel
34 from IPython.external.ssh import tunnel
35
35
36 # IPython imports
36 # IPython imports
37 # from IPython.config import Configurable
37 # from IPython.config import Configurable
38 from IPython.core.profiledir import ProfileDir
38 from IPython.core.profiledir import ProfileDir
39 from IPython.utils.localinterfaces import LOCALHOST
39 from IPython.utils.localinterfaces import LOCALHOST
40 from IPython.utils.path import filefind, get_ipython_dir
40 from IPython.utils.path import filefind, get_ipython_dir
41 from IPython.utils.py3compat import str_to_bytes, bytes_to_str
41 from IPython.utils.py3compat import str_to_bytes, bytes_to_str
42 from IPython.utils.traitlets import (
42 from IPython.utils.traitlets import (
43 Bool, Integer, Unicode, CaselessStrEnum,
43 Bool, Integer, Unicode, CaselessStrEnum,
44 HasTraits,
44 HasTraits,
45 )
45 )
46
46
47
47
48 #-----------------------------------------------------------------------------
48 #-----------------------------------------------------------------------------
49 # Working with Connection Files
49 # Working with Connection Files
50 #-----------------------------------------------------------------------------
50 #-----------------------------------------------------------------------------
51
51
52 def write_connection_file(fname=None, shell_port=0, iopub_port=0, stdin_port=0, hb_port=0,
52 def write_connection_file(fname=None, shell_port=0, iopub_port=0, stdin_port=0, hb_port=0,
53 control_port=0, ip=LOCALHOST, key=b'', transport='tcp'):
53 control_port=0, ip=LOCALHOST, key=b'', transport='tcp'):
54 """Generates a JSON config file, including the selection of random ports.
54 """Generates a JSON config file, including the selection of random ports.
55
55
56 Parameters
56 Parameters
57 ----------
57 ----------
58
58
59 fname : unicode
59 fname : unicode
60 The path to the file to write
60 The path to the file to write
61
61
62 shell_port : int, optional
62 shell_port : int, optional
63 The port to use for ROUTER channel.
63 The port to use for ROUTER (shell) channel.
64
64
65 iopub_port : int, optional
65 iopub_port : int, optional
66 The port to use for the SUB channel.
66 The port to use for the SUB channel.
67
67
68 stdin_port : int, optional
68 stdin_port : int, optional
69 The port to use for the ROUTER (raw input) channel.
69 The port to use for the ROUTER (raw input) channel.
70
70
71 control_port : int, optional
71 control_port : int, optional
72 The port to use for the ROUTER (raw input) channel.
72 The port to use for the ROUTER (control) channel.
73
73
74 hb_port : int, optional
74 hb_port : int, optional
75 The port to use for the hearbeat REP channel.
75 The port to use for the heartbeat REP channel.
76
76
77 ip : str, optional
77 ip : str, optional
78 The ip address the kernel will bind to.
78 The ip address the kernel will bind to.
79
79
80 key : str, optional
80 key : str, optional
81 The Session key used for HMAC authentication.
81 The Session key used for HMAC authentication.
82
82
83 """
83 """
84 # default to temporary connector file
84 # default to temporary connector file
85 if not fname:
85 if not fname:
86 fname = tempfile.mktemp('.json')
86 fname = tempfile.mktemp('.json')
87
87
88 # Find open ports as necessary.
88 # Find open ports as necessary.
89
89
90 ports = []
90 ports = []
91 ports_needed = int(shell_port <= 0) + \
91 ports_needed = int(shell_port <= 0) + \
92 int(iopub_port <= 0) + \
92 int(iopub_port <= 0) + \
93 int(stdin_port <= 0) + \
93 int(stdin_port <= 0) + \
94 int(control_port <= 0) + \
94 int(control_port <= 0) + \
95 int(hb_port <= 0)
95 int(hb_port <= 0)
96 if transport == 'tcp':
96 if transport == 'tcp':
97 for i in range(ports_needed):
97 for i in range(ports_needed):
98 sock = socket.socket()
98 sock = socket.socket()
99 sock.bind(('', 0))
99 sock.bind(('', 0))
100 ports.append(sock)
100 ports.append(sock)
101 for i, sock in enumerate(ports):
101 for i, sock in enumerate(ports):
102 port = sock.getsockname()[1]
102 port = sock.getsockname()[1]
103 sock.close()
103 sock.close()
104 ports[i] = port
104 ports[i] = port
105 else:
105 else:
106 N = 1
106 N = 1
107 for i in range(ports_needed):
107 for i in range(ports_needed):
108 while os.path.exists("%s-%s" % (ip, str(N))):
108 while os.path.exists("%s-%s" % (ip, str(N))):
109 N += 1
109 N += 1
110 ports.append(N)
110 ports.append(N)
111 N += 1
111 N += 1
112 if shell_port <= 0:
112 if shell_port <= 0:
113 shell_port = ports.pop(0)
113 shell_port = ports.pop(0)
114 if iopub_port <= 0:
114 if iopub_port <= 0:
115 iopub_port = ports.pop(0)
115 iopub_port = ports.pop(0)
116 if stdin_port <= 0:
116 if stdin_port <= 0:
117 stdin_port = ports.pop(0)
117 stdin_port = ports.pop(0)
118 if control_port <= 0:
118 if control_port <= 0:
119 control_port = ports.pop(0)
119 control_port = ports.pop(0)
120 if hb_port <= 0:
120 if hb_port <= 0:
121 hb_port = ports.pop(0)
121 hb_port = ports.pop(0)
122
122
123 cfg = dict( shell_port=shell_port,
123 cfg = dict( shell_port=shell_port,
124 iopub_port=iopub_port,
124 iopub_port=iopub_port,
125 stdin_port=stdin_port,
125 stdin_port=stdin_port,
126 control_port=control_port,
126 control_port=control_port,
127 hb_port=hb_port,
127 hb_port=hb_port,
128 )
128 )
129 cfg['ip'] = ip
129 cfg['ip'] = ip
130 cfg['key'] = bytes_to_str(key)
130 cfg['key'] = bytes_to_str(key)
131 cfg['transport'] = transport
131 cfg['transport'] = transport
132
132
133 with open(fname, 'w') as f:
133 with open(fname, 'w') as f:
134 f.write(json.dumps(cfg, indent=2))
134 f.write(json.dumps(cfg, indent=2))
135
135
136 return fname, cfg
136 return fname, cfg
137
137
138
138
139 def get_connection_file(app=None):
139 def get_connection_file(app=None):
140 """Return the path to the connection file of an app
140 """Return the path to the connection file of an app
141
141
142 Parameters
142 Parameters
143 ----------
143 ----------
144 app : IPKernelApp instance [optional]
144 app : IPKernelApp instance [optional]
145 If unspecified, the currently running app will be used
145 If unspecified, the currently running app will be used
146 """
146 """
147 if app is None:
147 if app is None:
148 from IPython.kernel.zmq.kernelapp import IPKernelApp
148 from IPython.kernel.zmq.kernelapp import IPKernelApp
149 if not IPKernelApp.initialized():
149 if not IPKernelApp.initialized():
150 raise RuntimeError("app not specified, and not in a running Kernel")
150 raise RuntimeError("app not specified, and not in a running Kernel")
151
151
152 app = IPKernelApp.instance()
152 app = IPKernelApp.instance()
153 return filefind(app.connection_file, ['.', app.profile_dir.security_dir])
153 return filefind(app.connection_file, ['.', app.profile_dir.security_dir])
154
154
155
155
156 def find_connection_file(filename, profile=None):
156 def find_connection_file(filename, profile=None):
157 """find a connection file, and return its absolute path.
157 """find a connection file, and return its absolute path.
158
158
159 The current working directory and the profile's security
159 The current working directory and the profile's security
160 directory will be searched for the file if it is not given by
160 directory will be searched for the file if it is not given by
161 absolute path.
161 absolute path.
162
162
163 If profile is unspecified, then the current running application's
163 If profile is unspecified, then the current running application's
164 profile will be used, or 'default', if not run from IPython.
164 profile will be used, or 'default', if not run from IPython.
165
165
166 If the argument does not match an existing file, it will be interpreted as a
166 If the argument does not match an existing file, it will be interpreted as a
167 fileglob, and the matching file in the profile's security dir with
167 fileglob, and the matching file in the profile's security dir with
168 the latest access time will be used.
168 the latest access time will be used.
169
169
170 Parameters
170 Parameters
171 ----------
171 ----------
172 filename : str
172 filename : str
173 The connection file or fileglob to search for.
173 The connection file or fileglob to search for.
174 profile : str [optional]
174 profile : str [optional]
175 The name of the profile to use when searching for the connection file,
175 The name of the profile to use when searching for the connection file,
176 if different from the current IPython session or 'default'.
176 if different from the current IPython session or 'default'.
177
177
178 Returns
178 Returns
179 -------
179 -------
180 str : The absolute path of the connection file.
180 str : The absolute path of the connection file.
181 """
181 """
182 from IPython.core.application import BaseIPythonApplication as IPApp
182 from IPython.core.application import BaseIPythonApplication as IPApp
183 try:
183 try:
184 # quick check for absolute path, before going through logic
184 # quick check for absolute path, before going through logic
185 return filefind(filename)
185 return filefind(filename)
186 except IOError:
186 except IOError:
187 pass
187 pass
188
188
189 if profile is None:
189 if profile is None:
190 # profile unspecified, check if running from an IPython app
190 # profile unspecified, check if running from an IPython app
191 if IPApp.initialized():
191 if IPApp.initialized():
192 app = IPApp.instance()
192 app = IPApp.instance()
193 profile_dir = app.profile_dir
193 profile_dir = app.profile_dir
194 else:
194 else:
195 # not running in IPython, use default profile
195 # not running in IPython, use default profile
196 profile_dir = ProfileDir.find_profile_dir_by_name(get_ipython_dir(), 'default')
196 profile_dir = ProfileDir.find_profile_dir_by_name(get_ipython_dir(), 'default')
197 else:
197 else:
198 # find profiledir by profile name:
198 # find profiledir by profile name:
199 profile_dir = ProfileDir.find_profile_dir_by_name(get_ipython_dir(), profile)
199 profile_dir = ProfileDir.find_profile_dir_by_name(get_ipython_dir(), profile)
200 security_dir = profile_dir.security_dir
200 security_dir = profile_dir.security_dir
201
201
202 try:
202 try:
203 # first, try explicit name
203 # first, try explicit name
204 return filefind(filename, ['.', security_dir])
204 return filefind(filename, ['.', security_dir])
205 except IOError:
205 except IOError:
206 pass
206 pass
207
207
208 # not found by full name
208 # not found by full name
209
209
210 if '*' in filename:
210 if '*' in filename:
211 # given as a glob already
211 # given as a glob already
212 pat = filename
212 pat = filename
213 else:
213 else:
214 # accept any substring match
214 # accept any substring match
215 pat = '*%s*' % filename
215 pat = '*%s*' % filename
216 matches = glob.glob( os.path.join(security_dir, pat) )
216 matches = glob.glob( os.path.join(security_dir, pat) )
217 if not matches:
217 if not matches:
218 raise IOError("Could not find %r in %r" % (filename, security_dir))
218 raise IOError("Could not find %r in %r" % (filename, security_dir))
219 elif len(matches) == 1:
219 elif len(matches) == 1:
220 return matches[0]
220 return matches[0]
221 else:
221 else:
222 # get most recent match, by access time:
222 # get most recent match, by access time:
223 return sorted(matches, key=lambda f: os.stat(f).st_atime)[-1]
223 return sorted(matches, key=lambda f: os.stat(f).st_atime)[-1]
224
224
225
225
226 def get_connection_info(connection_file=None, unpack=False, profile=None):
226 def get_connection_info(connection_file=None, unpack=False, profile=None):
227 """Return the connection information for the current Kernel.
227 """Return the connection information for the current Kernel.
228
228
229 Parameters
229 Parameters
230 ----------
230 ----------
231 connection_file : str [optional]
231 connection_file : str [optional]
232 The connection file to be used. Can be given by absolute path, or
232 The connection file to be used. Can be given by absolute path, or
233 IPython will search in the security directory of a given profile.
233 IPython will search in the security directory of a given profile.
234 If run from IPython,
234 If run from IPython,
235
235
236 If unspecified, the connection file for the currently running
236 If unspecified, the connection file for the currently running
237 IPython Kernel will be used, which is only allowed from inside a kernel.
237 IPython Kernel will be used, which is only allowed from inside a kernel.
238 unpack : bool [default: False]
238 unpack : bool [default: False]
239 if True, return the unpacked dict, otherwise just the string contents
239 if True, return the unpacked dict, otherwise just the string contents
240 of the file.
240 of the file.
241 profile : str [optional]
241 profile : str [optional]
242 The name of the profile to use when searching for the connection file,
242 The name of the profile to use when searching for the connection file,
243 if different from the current IPython session or 'default'.
243 if different from the current IPython session or 'default'.
244
244
245
245
246 Returns
246 Returns
247 -------
247 -------
248 The connection dictionary of the current kernel, as string or dict,
248 The connection dictionary of the current kernel, as string or dict,
249 depending on `unpack`.
249 depending on `unpack`.
250 """
250 """
251 if connection_file is None:
251 if connection_file is None:
252 # get connection file from current kernel
252 # get connection file from current kernel
253 cf = get_connection_file()
253 cf = get_connection_file()
254 else:
254 else:
255 # connection file specified, allow shortnames:
255 # connection file specified, allow shortnames:
256 cf = find_connection_file(connection_file, profile=profile)
256 cf = find_connection_file(connection_file, profile=profile)
257
257
258 with open(cf) as f:
258 with open(cf) as f:
259 info = f.read()
259 info = f.read()
260
260
261 if unpack:
261 if unpack:
262 info = json.loads(info)
262 info = json.loads(info)
263 # ensure key is bytes:
263 # ensure key is bytes:
264 info['key'] = str_to_bytes(info.get('key', ''))
264 info['key'] = str_to_bytes(info.get('key', ''))
265 return info
265 return info
266
266
267
267
268 def connect_qtconsole(connection_file=None, argv=None, profile=None):
268 def connect_qtconsole(connection_file=None, argv=None, profile=None):
269 """Connect a qtconsole to the current kernel.
269 """Connect a qtconsole to the current kernel.
270
270
271 This is useful for connecting a second qtconsole to a kernel, or to a
271 This is useful for connecting a second qtconsole to a kernel, or to a
272 local notebook.
272 local notebook.
273
273
274 Parameters
274 Parameters
275 ----------
275 ----------
276 connection_file : str [optional]
276 connection_file : str [optional]
277 The connection file to be used. Can be given by absolute path, or
277 The connection file to be used. Can be given by absolute path, or
278 IPython will search in the security directory of a given profile.
278 IPython will search in the security directory of a given profile.
279 If run from IPython,
279 If run from IPython,
280
280
281 If unspecified, the connection file for the currently running
281 If unspecified, the connection file for the currently running
282 IPython Kernel will be used, which is only allowed from inside a kernel.
282 IPython Kernel will be used, which is only allowed from inside a kernel.
283 argv : list [optional]
283 argv : list [optional]
284 Any extra args to be passed to the console.
284 Any extra args to be passed to the console.
285 profile : str [optional]
285 profile : str [optional]
286 The name of the profile to use when searching for the connection file,
286 The name of the profile to use when searching for the connection file,
287 if different from the current IPython session or 'default'.
287 if different from the current IPython session or 'default'.
288
288
289
289
290 Returns
290 Returns
291 -------
291 -------
292 subprocess.Popen instance running the qtconsole frontend
292 subprocess.Popen instance running the qtconsole frontend
293 """
293 """
294 argv = [] if argv is None else argv
294 argv = [] if argv is None else argv
295
295
296 if connection_file is None:
296 if connection_file is None:
297 # get connection file from current kernel
297 # get connection file from current kernel
298 cf = get_connection_file()
298 cf = get_connection_file()
299 else:
299 else:
300 cf = find_connection_file(connection_file, profile=profile)
300 cf = find_connection_file(connection_file, profile=profile)
301
301
302 cmd = ';'.join([
302 cmd = ';'.join([
303 "from IPython.frontend.qt.console import qtconsoleapp",
303 "from IPython.frontend.qt.console import qtconsoleapp",
304 "qtconsoleapp.main()"
304 "qtconsoleapp.main()"
305 ])
305 ])
306
306
307 return Popen([sys.executable, '-c', cmd, '--existing', cf] + argv, stdout=PIPE, stderr=PIPE)
307 return Popen([sys.executable, '-c', cmd, '--existing', cf] + argv, stdout=PIPE, stderr=PIPE)
308
308
309
309
310 def tunnel_to_kernel(connection_info, sshserver, sshkey=None):
310 def tunnel_to_kernel(connection_info, sshserver, sshkey=None):
311 """tunnel connections to a kernel via ssh
311 """tunnel connections to a kernel via ssh
312
312
313 This will open four SSH tunnels from localhost on this machine to the
313 This will open four SSH tunnels from localhost on this machine to the
314 ports associated with the kernel. They can be either direct
314 ports associated with the kernel. They can be either direct
315 localhost-localhost tunnels, or if an intermediate server is necessary,
315 localhost-localhost tunnels, or if an intermediate server is necessary,
316 the kernel must be listening on a public IP.
316 the kernel must be listening on a public IP.
317
317
318 Parameters
318 Parameters
319 ----------
319 ----------
320 connection_info : dict or str (path)
320 connection_info : dict or str (path)
321 Either a connection dict, or the path to a JSON connection file
321 Either a connection dict, or the path to a JSON connection file
322 sshserver : str
322 sshserver : str
323 The ssh sever to use to tunnel to the kernel. Can be a full
323 The ssh sever to use to tunnel to the kernel. Can be a full
324 `user@server:port` string. ssh config aliases are respected.
324 `user@server:port` string. ssh config aliases are respected.
325 sshkey : str [optional]
325 sshkey : str [optional]
326 Path to file containing ssh key to use for authentication.
326 Path to file containing ssh key to use for authentication.
327 Only necessary if your ssh config does not already associate
327 Only necessary if your ssh config does not already associate
328 a keyfile with the host.
328 a keyfile with the host.
329
329
330 Returns
330 Returns
331 -------
331 -------
332
332
333 (shell, iopub, stdin, hb) : ints
333 (shell, iopub, stdin, hb) : ints
334 The four ports on localhost that have been forwarded to the kernel.
334 The four ports on localhost that have been forwarded to the kernel.
335 """
335 """
336 if isinstance(connection_info, basestring):
336 if isinstance(connection_info, basestring):
337 # it's a path, unpack it
337 # it's a path, unpack it
338 with open(connection_info) as f:
338 with open(connection_info) as f:
339 connection_info = json.loads(f.read())
339 connection_info = json.loads(f.read())
340
340
341 cf = connection_info
341 cf = connection_info
342
342
343 lports = tunnel.select_random_ports(4)
343 lports = tunnel.select_random_ports(4)
344 rports = cf['shell_port'], cf['iopub_port'], cf['stdin_port'], cf['hb_port']
344 rports = cf['shell_port'], cf['iopub_port'], cf['stdin_port'], cf['hb_port']
345
345
346 remote_ip = cf['ip']
346 remote_ip = cf['ip']
347
347
348 if tunnel.try_passwordless_ssh(sshserver, sshkey):
348 if tunnel.try_passwordless_ssh(sshserver, sshkey):
349 password=False
349 password=False
350 else:
350 else:
351 password = getpass("SSH Password for %s: "%sshserver)
351 password = getpass("SSH Password for %s: "%sshserver)
352
352
353 for lp,rp in zip(lports, rports):
353 for lp,rp in zip(lports, rports):
354 tunnel.ssh_tunnel(lp, rp, sshserver, remote_ip, sshkey, password)
354 tunnel.ssh_tunnel(lp, rp, sshserver, remote_ip, sshkey, password)
355
355
356 return tuple(lports)
356 return tuple(lports)
357
357
358
358
359 #-----------------------------------------------------------------------------
359 #-----------------------------------------------------------------------------
360 # Mixin for classes that work with connection files
360 # Mixin for classes that work with connection files
361 #-----------------------------------------------------------------------------
361 #-----------------------------------------------------------------------------
362
362
363 channel_socket_types = {
363 channel_socket_types = {
364 'hb' : zmq.REQ,
364 'hb' : zmq.REQ,
365 'shell' : zmq.DEALER,
365 'shell' : zmq.DEALER,
366 'iopub' : zmq.SUB,
366 'iopub' : zmq.SUB,
367 'stdin' : zmq.DEALER,
367 'stdin' : zmq.DEALER,
368 'control': zmq.DEALER,
368 'control': zmq.DEALER,
369 }
369 }
370
370
371 port_names = [ "%s_port" % channel for channel in ('shell', 'stdin', 'iopub', 'hb', 'control')]
371 port_names = [ "%s_port" % channel for channel in ('shell', 'stdin', 'iopub', 'hb', 'control')]
372
372
373 class ConnectionFileMixin(HasTraits):
373 class ConnectionFileMixin(HasTraits):
374 """Mixin for configurable classes that work with connection files"""
374 """Mixin for configurable classes that work with connection files"""
375
375
376 # The addresses for the communication channels
376 # The addresses for the communication channels
377 connection_file = Unicode('')
377 connection_file = Unicode('')
378 _connection_file_written = Bool(False)
378 _connection_file_written = Bool(False)
379
379
380 transport = CaselessStrEnum(['tcp', 'ipc'], default_value='tcp', config=True)
380 transport = CaselessStrEnum(['tcp', 'ipc'], default_value='tcp', config=True)
381
381
382 ip = Unicode(LOCALHOST, config=True,
382 ip = Unicode(LOCALHOST, config=True,
383 help="""Set the kernel\'s IP address [default localhost].
383 help="""Set the kernel\'s IP address [default localhost].
384 If the IP address is something other than localhost, then
384 If the IP address is something other than localhost, then
385 Consoles on other machines will be able to connect
385 Consoles on other machines will be able to connect
386 to the Kernel, so be careful!"""
386 to the Kernel, so be careful!"""
387 )
387 )
388
388
389 def _ip_default(self):
389 def _ip_default(self):
390 if self.transport == 'ipc':
390 if self.transport == 'ipc':
391 if self.connection_file:
391 if self.connection_file:
392 return os.path.splitext(self.connection_file)[0] + '-ipc'
392 return os.path.splitext(self.connection_file)[0] + '-ipc'
393 else:
393 else:
394 return 'kernel-ipc'
394 return 'kernel-ipc'
395 else:
395 else:
396 return LOCALHOST
396 return LOCALHOST
397
397
398 def _ip_changed(self, name, old, new):
398 def _ip_changed(self, name, old, new):
399 if new == '*':
399 if new == '*':
400 self.ip = '0.0.0.0'
400 self.ip = '0.0.0.0'
401
401
402 # protected traits
402 # protected traits
403
403
404 shell_port = Integer(0)
404 shell_port = Integer(0)
405 iopub_port = Integer(0)
405 iopub_port = Integer(0)
406 stdin_port = Integer(0)
406 stdin_port = Integer(0)
407 control_port = Integer(0)
407 control_port = Integer(0)
408 hb_port = Integer(0)
408 hb_port = Integer(0)
409
409
410 @property
410 @property
411 def ports(self):
411 def ports(self):
412 return [ getattr(self, name) for name in port_names ]
412 return [ getattr(self, name) for name in port_names ]
413
413
414 #--------------------------------------------------------------------------
414 #--------------------------------------------------------------------------
415 # Connection and ipc file management
415 # Connection and ipc file management
416 #--------------------------------------------------------------------------
416 #--------------------------------------------------------------------------
417
417
418 def get_connection_info(self):
418 def get_connection_info(self):
419 """return the connection info as a dict"""
419 """return the connection info as a dict"""
420 return dict(
420 return dict(
421 transport=self.transport,
421 transport=self.transport,
422 ip=self.ip,
422 ip=self.ip,
423 shell_port=self.shell_port,
423 shell_port=self.shell_port,
424 iopub_port=self.iopub_port,
424 iopub_port=self.iopub_port,
425 stdin_port=self.stdin_port,
425 stdin_port=self.stdin_port,
426 hb_port=self.hb_port,
426 hb_port=self.hb_port,
427 control_port=self.control_port,
427 control_port=self.control_port,
428 )
428 )
429
429
430 def cleanup_connection_file(self):
430 def cleanup_connection_file(self):
431 """Cleanup connection file *if we wrote it*
431 """Cleanup connection file *if we wrote it*
432
432
433 Will not raise if the connection file was already removed somehow.
433 Will not raise if the connection file was already removed somehow.
434 """
434 """
435 if self._connection_file_written:
435 if self._connection_file_written:
436 # cleanup connection files on full shutdown of kernel we started
436 # cleanup connection files on full shutdown of kernel we started
437 self._connection_file_written = False
437 self._connection_file_written = False
438 try:
438 try:
439 os.remove(self.connection_file)
439 os.remove(self.connection_file)
440 except (IOError, OSError, AttributeError):
440 except (IOError, OSError, AttributeError):
441 pass
441 pass
442
442
443 def cleanup_ipc_files(self):
443 def cleanup_ipc_files(self):
444 """Cleanup ipc files if we wrote them."""
444 """Cleanup ipc files if we wrote them."""
445 if self.transport != 'ipc':
445 if self.transport != 'ipc':
446 return
446 return
447 for port in self.ports:
447 for port in self.ports:
448 ipcfile = "%s-%i" % (self.ip, port)
448 ipcfile = "%s-%i" % (self.ip, port)
449 try:
449 try:
450 os.remove(ipcfile)
450 os.remove(ipcfile)
451 except (IOError, OSError):
451 except (IOError, OSError):
452 pass
452 pass
453
453
454 def write_connection_file(self):
454 def write_connection_file(self):
455 """Write connection info to JSON dict in self.connection_file."""
455 """Write connection info to JSON dict in self.connection_file."""
456 if self._connection_file_written:
456 if self._connection_file_written:
457 return
457 return
458
458
459 self.connection_file, cfg = write_connection_file(self.connection_file,
459 self.connection_file, cfg = write_connection_file(self.connection_file,
460 transport=self.transport, ip=self.ip, key=self.session.key,
460 transport=self.transport, ip=self.ip, key=self.session.key,
461 stdin_port=self.stdin_port, iopub_port=self.iopub_port,
461 stdin_port=self.stdin_port, iopub_port=self.iopub_port,
462 shell_port=self.shell_port, hb_port=self.hb_port,
462 shell_port=self.shell_port, hb_port=self.hb_port,
463 control_port=self.control_port,
463 control_port=self.control_port,
464 )
464 )
465 # write_connection_file also sets default ports:
465 # write_connection_file also sets default ports:
466 for name in port_names:
466 for name in port_names:
467 setattr(self, name, cfg[name])
467 setattr(self, name, cfg[name])
468
468
469 self._connection_file_written = True
469 self._connection_file_written = True
470
470
471 def load_connection_file(self):
471 def load_connection_file(self):
472 """Load connection info from JSON dict in self.connection_file."""
472 """Load connection info from JSON dict in self.connection_file."""
473 with open(self.connection_file) as f:
473 with open(self.connection_file) as f:
474 cfg = json.loads(f.read())
474 cfg = json.loads(f.read())
475
475
476 self.transport = cfg.get('transport', 'tcp')
476 self.transport = cfg.get('transport', 'tcp')
477 self.ip = cfg['ip']
477 self.ip = cfg['ip']
478 for name in port_names:
478 for name in port_names:
479 setattr(self, name, cfg[name])
479 setattr(self, name, cfg[name])
480 self.session.key = str_to_bytes(cfg['key'])
480 self.session.key = str_to_bytes(cfg['key'])
481
481
482 #--------------------------------------------------------------------------
482 #--------------------------------------------------------------------------
483 # Creating connected sockets
483 # Creating connected sockets
484 #--------------------------------------------------------------------------
484 #--------------------------------------------------------------------------
485
485
486 def _make_url(self, channel):
486 def _make_url(self, channel):
487 """Make a ZeroMQ URL for a given channel."""
487 """Make a ZeroMQ URL for a given channel."""
488 transport = self.transport
488 transport = self.transport
489 ip = self.ip
489 ip = self.ip
490 port = getattr(self, '%s_port' % channel)
490 port = getattr(self, '%s_port' % channel)
491
491
492 if transport == 'tcp':
492 if transport == 'tcp':
493 return "tcp://%s:%i" % (ip, port)
493 return "tcp://%s:%i" % (ip, port)
494 else:
494 else:
495 return "%s://%s-%s" % (transport, ip, port)
495 return "%s://%s-%s" % (transport, ip, port)
496
496
497 def _create_connected_socket(self, channel, identity=None):
497 def _create_connected_socket(self, channel, identity=None):
498 """Create a zmq Socket and connect it to the kernel."""
498 """Create a zmq Socket and connect it to the kernel."""
499 url = self._make_url(channel)
499 url = self._make_url(channel)
500 socket_type = channel_socket_types[channel]
500 socket_type = channel_socket_types[channel]
501 self.log.info("Connecting to: %s" % url)
501 self.log.info("Connecting to: %s" % url)
502 sock = self.context.socket(socket_type)
502 sock = self.context.socket(socket_type)
503 if identity:
503 if identity:
504 sock.identity = identity
504 sock.identity = identity
505 sock.connect(url)
505 sock.connect(url)
506 return sock
506 return sock
507
507
508 def connect_iopub(self, identity=None):
508 def connect_iopub(self, identity=None):
509 """return zmq Socket connected to the IOPub channel"""
509 """return zmq Socket connected to the IOPub channel"""
510 sock = self._create_connected_socket('iopub', identity=identity)
510 sock = self._create_connected_socket('iopub', identity=identity)
511 sock.setsockopt(zmq.SUBSCRIBE, b'')
511 sock.setsockopt(zmq.SUBSCRIBE, b'')
512 return sock
512 return sock
513
513
514 def connect_shell(self, identity=None):
514 def connect_shell(self, identity=None):
515 """return zmq Socket connected to the Shell channel"""
515 """return zmq Socket connected to the Shell channel"""
516 return self._create_connected_socket('shell', identity=identity)
516 return self._create_connected_socket('shell', identity=identity)
517
517
518 def connect_stdin(self, identity=None):
518 def connect_stdin(self, identity=None):
519 """return zmq Socket connected to the StdIn channel"""
519 """return zmq Socket connected to the StdIn channel"""
520 return self._create_connected_socket('stdin', identity=identity)
520 return self._create_connected_socket('stdin', identity=identity)
521
521
522 def connect_hb(self, identity=None):
522 def connect_hb(self, identity=None):
523 """return zmq Socket connected to the Heartbeat channel"""
523 """return zmq Socket connected to the Heartbeat channel"""
524 return self._create_connected_socket('hb', identity=identity)
524 return self._create_connected_socket('hb', identity=identity)
525
525
526 def connect_control(self, identity=None):
526 def connect_control(self, identity=None):
527 """return zmq Socket connected to the Heartbeat channel"""
527 """return zmq Socket connected to the Heartbeat channel"""
528 return self._create_connected_socket('control', identity=identity)
528 return self._create_connected_socket('control', identity=identity)
529
529
530
530
531 __all__ = [
531 __all__ = [
532 'write_connection_file',
532 'write_connection_file',
533 'get_connection_file',
533 'get_connection_file',
534 'find_connection_file',
534 'find_connection_file',
535 'get_connection_info',
535 'get_connection_info',
536 'connect_qtconsole',
536 'connect_qtconsole',
537 'tunnel_to_kernel',
537 'tunnel_to_kernel',
538 ]
538 ]
General Comments 0
You need to be logged in to leave comments. Login now