##// END OF EJS Templates
Removing unused code in the notebook MappingKernelManager....
Brian E. Granger -
Show More
@@ -1,343 +1,338 b''
1 """A kernel manager for multiple kernels.
1 """A kernel manager for multiple kernels.
2
2
3 Authors:
3 Authors:
4
4
5 * Brian Granger
5 * Brian Granger
6 """
6 """
7
7
8 #-----------------------------------------------------------------------------
8 #-----------------------------------------------------------------------------
9 # Copyright (C) 2008-2011 The IPython Development Team
9 # Copyright (C) 2008-2011 The IPython Development Team
10 #
10 #
11 # Distributed under the terms of the BSD License. The full license is in
11 # Distributed under the terms of the BSD License. The full license is in
12 # the file COPYING, distributed as part of this software.
12 # the file COPYING, distributed as part of this software.
13 #-----------------------------------------------------------------------------
13 #-----------------------------------------------------------------------------
14
14
15 #-----------------------------------------------------------------------------
15 #-----------------------------------------------------------------------------
16 # Imports
16 # Imports
17 #-----------------------------------------------------------------------------
17 #-----------------------------------------------------------------------------
18
18
19 import os
19 import os
20 import signal
20 import signal
21 import sys
21 import sys
22 import uuid
22 import uuid
23
23
24 import zmq
24 import zmq
25 from zmq.eventloop.zmqstream import ZMQStream
25 from zmq.eventloop.zmqstream import ZMQStream
26
26
27 from tornado import web
27 from tornado import web
28
28
29 from IPython.config.configurable import LoggingConfigurable
29 from IPython.config.configurable import LoggingConfigurable
30 from IPython.utils.importstring import import_item
30 from IPython.utils.importstring import import_item
31 from IPython.utils.traitlets import (
31 from IPython.utils.traitlets import (
32 Instance, Dict, List, Unicode, Float, Integer, Any, DottedObjectName,
32 Instance, Dict, List, Unicode, Float, Integer, Any, DottedObjectName,
33 )
33 )
34 #-----------------------------------------------------------------------------
34 #-----------------------------------------------------------------------------
35 # Classes
35 # Classes
36 #-----------------------------------------------------------------------------
36 #-----------------------------------------------------------------------------
37
37
38 class DuplicateKernelError(Exception):
38 class DuplicateKernelError(Exception):
39 pass
39 pass
40
40
41
41
42 class MultiKernelManager(LoggingConfigurable):
42 class MultiKernelManager(LoggingConfigurable):
43 """A class for managing multiple kernels."""
43 """A class for managing multiple kernels."""
44
44
45 kernel_manager_class = DottedObjectName(
45 kernel_manager_class = DottedObjectName(
46 "IPython.zmq.blockingkernelmanager.BlockingKernelManager", config=True,
46 "IPython.zmq.blockingkernelmanager.BlockingKernelManager", config=True,
47 help="""The kernel manager class. This is configurable to allow
47 help="""The kernel manager class. This is configurable to allow
48 subclassing of the KernelManager for customized behavior.
48 subclassing of the KernelManager for customized behavior.
49 """
49 """
50 )
50 )
51 def _kernel_manager_class_changed(self, name, old, new):
51 def _kernel_manager_class_changed(self, name, old, new):
52 self.kernel_manager_factory = import_item(new)
52 self.kernel_manager_factory = import_item(new)
53
53
54 kernel_manager_factory = Any(help="this is kernel_manager_class after import")
54 kernel_manager_factory = Any(help="this is kernel_manager_class after import")
55 def _kernel_manager_factory_default(self):
55 def _kernel_manager_factory_default(self):
56 return import_item(self.kernel_manager_class)
56 return import_item(self.kernel_manager_class)
57
57
58 context = Instance('zmq.Context')
58 context = Instance('zmq.Context')
59 def _context_default(self):
59 def _context_default(self):
60 return zmq.Context.instance()
60 return zmq.Context.instance()
61
61
62 connection_dir = Unicode('')
62 connection_dir = Unicode('')
63
63
64 _kernels = Dict()
64 _kernels = Dict()
65
65
66 @property
66 @property
67 def kernel_ids(self):
67 def kernel_ids(self):
68 """Return a list of the kernel ids of the active kernels."""
68 """Return a list of the kernel ids of the active kernels."""
69 return self._kernels.keys()
69 return self._kernels.keys()
70
70
71 def __len__(self):
71 def __len__(self):
72 """Return the number of running kernels."""
72 """Return the number of running kernels."""
73 return len(self.kernel_ids)
73 return len(self.kernel_ids)
74
74
75 def __contains__(self, kernel_id):
75 def __contains__(self, kernel_id):
76 if kernel_id in self.kernel_ids:
76 if kernel_id in self.kernel_ids:
77 return True
77 return True
78 else:
78 else:
79 return False
79 return False
80
80
81 def start_kernel(self, **kwargs):
81 def start_kernel(self, **kwargs):
82 """Start a new kernel."""
82 """Start a new kernel."""
83 kernel_id = unicode(uuid.uuid4())
83 kernel_id = unicode(uuid.uuid4())
84 # use base KernelManager for each Kernel
84 # use base KernelManager for each Kernel
85 km = self.kernel_manager_factory(connection_file=os.path.join(
85 km = self.kernel_manager_factory(connection_file=os.path.join(
86 self.connection_dir, "kernel-%s.json" % kernel_id),
86 self.connection_dir, "kernel-%s.json" % kernel_id),
87 config=self.config,
87 config=self.config,
88 )
88 )
89 km.start_kernel(**kwargs)
89 km.start_kernel(**kwargs)
90 # start just the shell channel, needed for graceful restart
90 # start just the shell channel, needed for graceful restart
91 km.start_channels(shell=True, sub=False, stdin=False, hb=False)
91 km.start_channels(shell=True, sub=False, stdin=False, hb=False)
92 self._kernels[kernel_id] = km
92 self._kernels[kernel_id] = km
93 return kernel_id
93 return kernel_id
94
94
95 def shutdown_kernel(self, kernel_id):
95 def shutdown_kernel(self, kernel_id):
96 """Shutdown a kernel by its kernel uuid.
96 """Shutdown a kernel by its kernel uuid.
97
97
98 Parameters
98 Parameters
99 ==========
99 ==========
100 kernel_id : uuid
100 kernel_id : uuid
101 The id of the kernel to shutdown.
101 The id of the kernel to shutdown.
102 """
102 """
103 self.get_kernel(kernel_id).shutdown_kernel()
103 self.get_kernel(kernel_id).shutdown_kernel()
104 del self._kernels[kernel_id]
104 del self._kernels[kernel_id]
105
105
106 def kill_kernel(self, kernel_id):
106 def kill_kernel(self, kernel_id):
107 """Kill a kernel by its kernel uuid.
107 """Kill a kernel by its kernel uuid.
108
108
109 Parameters
109 Parameters
110 ==========
110 ==========
111 kernel_id : uuid
111 kernel_id : uuid
112 The id of the kernel to kill.
112 The id of the kernel to kill.
113 """
113 """
114 self.get_kernel(kernel_id).kill_kernel()
114 self.get_kernel(kernel_id).kill_kernel()
115 del self._kernels[kernel_id]
115 del self._kernels[kernel_id]
116
116
117 def interrupt_kernel(self, kernel_id):
117 def interrupt_kernel(self, kernel_id):
118 """Interrupt (SIGINT) the kernel by its uuid.
118 """Interrupt (SIGINT) the kernel by its uuid.
119
119
120 Parameters
120 Parameters
121 ==========
121 ==========
122 kernel_id : uuid
122 kernel_id : uuid
123 The id of the kernel to interrupt.
123 The id of the kernel to interrupt.
124 """
124 """
125 return self.get_kernel(kernel_id).interrupt_kernel()
125 return self.get_kernel(kernel_id).interrupt_kernel()
126
126
127 def signal_kernel(self, kernel_id, signum):
127 def signal_kernel(self, kernel_id, signum):
128 """ Sends a signal to the kernel by its uuid.
128 """ Sends a signal to the kernel by its uuid.
129
129
130 Note that since only SIGTERM is supported on Windows, this function
130 Note that since only SIGTERM is supported on Windows, this function
131 is only useful on Unix systems.
131 is only useful on Unix systems.
132
132
133 Parameters
133 Parameters
134 ==========
134 ==========
135 kernel_id : uuid
135 kernel_id : uuid
136 The id of the kernel to signal.
136 The id of the kernel to signal.
137 """
137 """
138 return self.get_kernel(kernel_id).signal_kernel(signum)
138 return self.get_kernel(kernel_id).signal_kernel(signum)
139
139
140 def restart_kernel(self, kernel_id):
141 """Restart a kernel by its uuid, keeping the same ports.
142
143 Parameters
144 ==========
145 kernel_id : uuid
146 The id of the kernel to interrupt.
147 """
148 return self.get_kernel(kernel_id).restart_kernel()
149
140 def get_kernel(self, kernel_id):
150 def get_kernel(self, kernel_id):
141 """Get the single KernelManager object for a kernel by its uuid.
151 """Get the single KernelManager object for a kernel by its uuid.
142
152
143 Parameters
153 Parameters
144 ==========
154 ==========
145 kernel_id : uuid
155 kernel_id : uuid
146 The id of the kernel.
156 The id of the kernel.
147 """
157 """
148 km = self._kernels.get(kernel_id)
158 km = self._kernels.get(kernel_id)
149 if km is not None:
159 if km is not None:
150 return km
160 return km
151 else:
161 else:
152 raise KeyError("Kernel with id not found: %s" % kernel_id)
162 raise KeyError("Kernel with id not found: %s" % kernel_id)
153
163
154 def get_kernel_ports(self, kernel_id):
164 def get_kernel_ports(self, kernel_id):
155 """Return a dictionary of ports for a kernel.
165 """Return a dictionary of ports for a kernel.
156
166
157 Parameters
167 Parameters
158 ==========
168 ==========
159 kernel_id : uuid
169 kernel_id : uuid
160 The id of the kernel.
170 The id of the kernel.
161
171
162 Returns
172 Returns
163 =======
173 =======
164 port_dict : dict
174 port_dict : dict
165 A dict of key, value pairs where the keys are the names
175 A dict of key, value pairs where the keys are the names
166 (stdin_port,iopub_port,shell_port) and the values are the
176 (stdin_port,iopub_port,shell_port) and the values are the
167 integer port numbers for those channels.
177 integer port numbers for those channels.
168 """
178 """
169 # this will raise a KeyError if not found:
179 # this will raise a KeyError if not found:
170 km = self.get_kernel(kernel_id)
180 km = self.get_kernel(kernel_id)
171 return dict(shell_port=km.shell_port,
181 return dict(shell_port=km.shell_port,
172 iopub_port=km.iopub_port,
182 iopub_port=km.iopub_port,
173 stdin_port=km.stdin_port,
183 stdin_port=km.stdin_port,
174 hb_port=km.hb_port,
184 hb_port=km.hb_port,
175 )
185 )
176
186
177 def get_kernel_ip(self, kernel_id):
187 def get_kernel_ip(self, kernel_id):
178 """Return ip address for a kernel.
188 """Return ip address for a kernel.
179
189
180 Parameters
190 Parameters
181 ==========
191 ==========
182 kernel_id : uuid
192 kernel_id : uuid
183 The id of the kernel.
193 The id of the kernel.
184
194
185 Returns
195 Returns
186 =======
196 =======
187 ip : str
197 ip : str
188 The ip address of the kernel.
198 The ip address of the kernel.
189 """
199 """
190 return self.get_kernel(kernel_id).ip
200 return self.get_kernel(kernel_id).ip
191
201
192 def create_connected_stream(self, ip, port, socket_type):
202 def create_connected_stream(self, ip, port, socket_type):
193 sock = self.context.socket(socket_type)
203 sock = self.context.socket(socket_type)
194 addr = "tcp://%s:%i" % (ip, port)
204 addr = "tcp://%s:%i" % (ip, port)
195 self.log.info("Connecting to: %s" % addr)
205 self.log.info("Connecting to: %s" % addr)
196 sock.connect(addr)
206 sock.connect(addr)
197 return ZMQStream(sock)
207 return ZMQStream(sock)
198
208
199 def create_iopub_stream(self, kernel_id):
209 def create_iopub_stream(self, kernel_id):
200 ip = self.get_kernel_ip(kernel_id)
210 ip = self.get_kernel_ip(kernel_id)
201 ports = self.get_kernel_ports(kernel_id)
211 ports = self.get_kernel_ports(kernel_id)
202 iopub_stream = self.create_connected_stream(ip, ports['iopub_port'], zmq.SUB)
212 iopub_stream = self.create_connected_stream(ip, ports['iopub_port'], zmq.SUB)
203 iopub_stream.socket.setsockopt(zmq.SUBSCRIBE, b'')
213 iopub_stream.socket.setsockopt(zmq.SUBSCRIBE, b'')
204 return iopub_stream
214 return iopub_stream
205
215
206 def create_shell_stream(self, kernel_id):
216 def create_shell_stream(self, kernel_id):
207 ip = self.get_kernel_ip(kernel_id)
217 ip = self.get_kernel_ip(kernel_id)
208 ports = self.get_kernel_ports(kernel_id)
218 ports = self.get_kernel_ports(kernel_id)
209 shell_stream = self.create_connected_stream(ip, ports['shell_port'], zmq.DEALER)
219 shell_stream = self.create_connected_stream(ip, ports['shell_port'], zmq.DEALER)
210 return shell_stream
220 return shell_stream
211
221
212 def create_hb_stream(self, kernel_id):
222 def create_hb_stream(self, kernel_id):
213 ip = self.get_kernel_ip(kernel_id)
223 ip = self.get_kernel_ip(kernel_id)
214 ports = self.get_kernel_ports(kernel_id)
224 ports = self.get_kernel_ports(kernel_id)
215 hb_stream = self.create_connected_stream(ip, ports['hb_port'], zmq.REQ)
225 hb_stream = self.create_connected_stream(ip, ports['hb_port'], zmq.REQ)
216 return hb_stream
226 return hb_stream
217
227
218
228
219 class MappingKernelManager(MultiKernelManager):
229 class MappingKernelManager(MultiKernelManager):
220 """A KernelManager that handles notebok mapping and HTTP error handling"""
230 """A KernelManager that handles notebok mapping and HTTP error handling"""
221
231
222 kernel_argv = List(Unicode)
232 kernel_argv = List(Unicode)
223
233
224 time_to_dead = Float(3.0, config=True, help="""Kernel heartbeat interval in seconds.""")
234 time_to_dead = Float(3.0, config=True, help="""Kernel heartbeat interval in seconds.""")
225 first_beat = Float(5.0, config=True, help="Delay (in seconds) before sending first heartbeat.")
235 first_beat = Float(5.0, config=True, help="Delay (in seconds) before sending first heartbeat.")
226
236
227 max_msg_size = Integer(65536, config=True, help="""
237 max_msg_size = Integer(65536, config=True, help="""
228 The max raw message size accepted from the browser
238 The max raw message size accepted from the browser
229 over a WebSocket connection.
239 over a WebSocket connection.
230 """)
240 """)
231
241
232 _notebook_mapping = Dict()
242 _notebook_mapping = Dict()
233
243
234 #-------------------------------------------------------------------------
244 #-------------------------------------------------------------------------
235 # Methods for managing kernels and sessions
245 # Methods for managing kernels and sessions
236 #-------------------------------------------------------------------------
246 #-------------------------------------------------------------------------
237
247
238 def kernel_for_notebook(self, notebook_id):
248 def kernel_for_notebook(self, notebook_id):
239 """Return the kernel_id for a notebook_id or None."""
249 """Return the kernel_id for a notebook_id or None."""
240 return self._notebook_mapping.get(notebook_id)
250 return self._notebook_mapping.get(notebook_id)
241
251
242 def set_kernel_for_notebook(self, notebook_id, kernel_id):
252 def set_kernel_for_notebook(self, notebook_id, kernel_id):
243 """Associate a notebook with a kernel."""
253 """Associate a notebook with a kernel."""
244 if notebook_id is not None:
254 if notebook_id is not None:
245 self._notebook_mapping[notebook_id] = kernel_id
255 self._notebook_mapping[notebook_id] = kernel_id
246
256
247 def notebook_for_kernel(self, kernel_id):
257 def notebook_for_kernel(self, kernel_id):
248 """Return the notebook_id for a kernel_id or None."""
258 """Return the notebook_id for a kernel_id or None."""
249 notebook_ids = [k for k, v in self._notebook_mapping.iteritems() if v == kernel_id]
259 notebook_ids = [k for k, v in self._notebook_mapping.iteritems() if v == kernel_id]
250 if len(notebook_ids) == 1:
260 if len(notebook_ids) == 1:
251 return notebook_ids[0]
261 return notebook_ids[0]
252 else:
262 else:
253 return None
263 return None
254
264
255 def delete_mapping_for_kernel(self, kernel_id):
265 def delete_mapping_for_kernel(self, kernel_id):
256 """Remove the kernel/notebook mapping for kernel_id."""
266 """Remove the kernel/notebook mapping for kernel_id."""
257 notebook_id = self.notebook_for_kernel(kernel_id)
267 notebook_id = self.notebook_for_kernel(kernel_id)
258 if notebook_id is not None:
268 if notebook_id is not None:
259 del self._notebook_mapping[notebook_id]
269 del self._notebook_mapping[notebook_id]
260
270
261 def start_kernel(self, notebook_id=None, **kwargs):
271 def start_kernel(self, notebook_id=None, **kwargs):
262 """Start a kernel for a notebok an return its kernel_id.
272 """Start a kernel for a notebok an return its kernel_id.
263
273
264 Parameters
274 Parameters
265 ----------
275 ----------
266 notebook_id : uuid
276 notebook_id : uuid
267 The uuid of the notebook to associate the new kernel with. If this
277 The uuid of the notebook to associate the new kernel with. If this
268 is not None, this kernel will be persistent whenever the notebook
278 is not None, this kernel will be persistent whenever the notebook
269 requests a kernel.
279 requests a kernel.
270 """
280 """
271 kernel_id = self.kernel_for_notebook(notebook_id)
281 kernel_id = self.kernel_for_notebook(notebook_id)
272 if kernel_id is None:
282 if kernel_id is None:
273 kwargs['extra_arguments'] = self.kernel_argv
283 kwargs['extra_arguments'] = self.kernel_argv
274 kernel_id = super(MappingKernelManager, self).start_kernel(**kwargs)
284 kernel_id = super(MappingKernelManager, self).start_kernel(**kwargs)
275 self.set_kernel_for_notebook(notebook_id, kernel_id)
285 self.set_kernel_for_notebook(notebook_id, kernel_id)
276 self.log.info("Kernel started: %s" % kernel_id)
286 self.log.info("Kernel started: %s" % kernel_id)
277 self.log.debug("Kernel args: %r" % kwargs)
287 self.log.debug("Kernel args: %r" % kwargs)
278 else:
288 else:
279 self.log.info("Using existing kernel: %s" % kernel_id)
289 self.log.info("Using existing kernel: %s" % kernel_id)
280 return kernel_id
290 return kernel_id
281
291
282 def shutdown_kernel(self, kernel_id):
292 def shutdown_kernel(self, kernel_id):
283 """Shutdown a kernel and remove its notebook association."""
293 """Shutdown a kernel and remove its notebook association."""
284 self._check_kernel_id(kernel_id)
294 self._check_kernel_id(kernel_id)
285 super(MappingKernelManager, self).shutdown_kernel(kernel_id)
295 super(MappingKernelManager, self).shutdown_kernel(kernel_id)
286 self.delete_mapping_for_kernel(kernel_id)
296 self.delete_mapping_for_kernel(kernel_id)
287 self.log.info("Kernel shutdown: %s" % kernel_id)
297 self.log.info("Kernel shutdown: %s" % kernel_id)
288
298
289 def kill_kernel(self, kernel_id):
299 def kill_kernel(self, kernel_id):
290 """Kill a kernel and remove its notebook association."""
300 """Kill a kernel and remove its notebook association."""
291 self._check_kernel_id(kernel_id)
301 self._check_kernel_id(kernel_id)
292 super(MappingKernelManager, self).kill_kernel(kernel_id)
302 super(MappingKernelManager, self).kill_kernel(kernel_id)
293 self.delete_mapping_for_kernel(kernel_id)
303 self.delete_mapping_for_kernel(kernel_id)
294 self.log.info("Kernel killed: %s" % kernel_id)
304 self.log.info("Kernel killed: %s" % kernel_id)
295
305
296 def interrupt_kernel(self, kernel_id):
306 def interrupt_kernel(self, kernel_id):
297 """Interrupt a kernel."""
307 """Interrupt a kernel."""
298 self._check_kernel_id(kernel_id)
308 self._check_kernel_id(kernel_id)
299 super(MappingKernelManager, self).interrupt_kernel(kernel_id)
309 super(MappingKernelManager, self).interrupt_kernel(kernel_id)
300 self.log.info("Kernel interrupted: %s" % kernel_id)
310 self.log.info("Kernel interrupted: %s" % kernel_id)
301
311
302 def restart_kernel(self, kernel_id):
312 def restart_kernel(self, kernel_id):
303 """Restart a kernel while keeping clients connected."""
313 """Restart a kernel while keeping clients connected."""
304 self._check_kernel_id(kernel_id)
314 self._check_kernel_id(kernel_id)
305 km = self.get_kernel(kernel_id)
315 super(MappingKernelManager, self).restart_kernel(kernel_id)
306 km.restart_kernel()
307 self.log.info("Kernel restarted: %s" % kernel_id)
316 self.log.info("Kernel restarted: %s" % kernel_id)
308 return kernel_id
317 return kernel_id
309
310 # the following remains, in case the KM restart machinery is
311 # somehow unacceptable
312 # Get the notebook_id to preserve the kernel/notebook association.
313 notebook_id = self.notebook_for_kernel(kernel_id)
314 # Create the new kernel first so we can move the clients over.
315 new_kernel_id = self.start_kernel()
316 # Now kill the old kernel.
317 self.kill_kernel(kernel_id)
318 # Now save the new kernel/notebook association. We have to save it
319 # after the old kernel is killed as that will delete the mapping.
320 self.set_kernel_for_notebook(notebook_id, new_kernel_id)
321 self.log.info("Kernel restarted: %s" % new_kernel_id)
322 return new_kernel_id
323
318
324 def create_iopub_stream(self, kernel_id):
319 def create_iopub_stream(self, kernel_id):
325 """Create a new iopub stream."""
320 """Create a new iopub stream."""
326 self._check_kernel_id(kernel_id)
321 self._check_kernel_id(kernel_id)
327 return super(MappingKernelManager, self).create_iopub_stream(kernel_id)
322 return super(MappingKernelManager, self).create_iopub_stream(kernel_id)
328
323
329 def create_shell_stream(self, kernel_id):
324 def create_shell_stream(self, kernel_id):
330 """Create a new shell stream."""
325 """Create a new shell stream."""
331 self._check_kernel_id(kernel_id)
326 self._check_kernel_id(kernel_id)
332 return super(MappingKernelManager, self).create_shell_stream(kernel_id)
327 return super(MappingKernelManager, self).create_shell_stream(kernel_id)
333
328
334 def create_hb_stream(self, kernel_id):
329 def create_hb_stream(self, kernel_id):
335 """Create a new hb stream."""
330 """Create a new hb stream."""
336 self._check_kernel_id(kernel_id)
331 self._check_kernel_id(kernel_id)
337 return super(MappingKernelManager, self).create_hb_stream(kernel_id)
332 return super(MappingKernelManager, self).create_hb_stream(kernel_id)
338
333
339 def _check_kernel_id(self, kernel_id):
334 def _check_kernel_id(self, kernel_id):
340 """Check a that a kernel_id exists and raise 404 if not."""
335 """Check a that a kernel_id exists and raise 404 if not."""
341 if kernel_id not in self:
336 if kernel_id not in self:
342 raise web.HTTPError(404, u'Kernel does not exist: %s' % kernel_id)
337 raise web.HTTPError(404, u'Kernel does not exist: %s' % kernel_id)
343
338
General Comments 0
You need to be logged in to leave comments. Login now