##// END OF EJS Templates
Stripping notebook server flags from kernel's argv.
Brian E. Granger -
Show More
@@ -1,261 +1,270 b''
1 """A tornado based IPython notebook server."""
1 """A tornado based IPython notebook server."""
2
2
3 #-----------------------------------------------------------------------------
3 #-----------------------------------------------------------------------------
4 # Copyright (C) 2011 The IPython Development Team
4 # Copyright (C) 2011 The IPython Development Team
5 #
5 #
6 # Distributed under the terms of the BSD License. The full license is in
6 # Distributed under the terms of the BSD License. The full license is in
7 # the file COPYING.txt, distributed as part of this software.
7 # the file COPYING.txt, distributed as part of this software.
8 #-----------------------------------------------------------------------------
8 #-----------------------------------------------------------------------------
9
9
10 #-----------------------------------------------------------------------------
10 #-----------------------------------------------------------------------------
11 # Imports
11 # Imports
12 #-----------------------------------------------------------------------------
12 #-----------------------------------------------------------------------------
13
13
14 import errno
14 import errno
15 import logging
15 import logging
16 import os
16 import os
17 import signal
17 import signal
18 import socket
18 import socket
19 import sys
19 import sys
20
20
21 import zmq
21 import zmq
22
22
23 # Install the pyzmq ioloop. This has to be done before anything else from
23 # Install the pyzmq ioloop. This has to be done before anything else from
24 # tornado is imported.
24 # tornado is imported.
25 from zmq.eventloop import ioloop
25 from zmq.eventloop import ioloop
26 import tornado.ioloop
26 import tornado.ioloop
27 tornado.ioloop = ioloop
27 tornado.ioloop = ioloop
28
28
29 from tornado import httpserver
29 from tornado import httpserver
30 from tornado import web
30 from tornado import web
31
31
32 from .kernelmanager import MappingKernelManager
32 from .kernelmanager import MappingKernelManager
33 from .handlers import (
33 from .handlers import (
34 NBBrowserHandler, NewHandler, NamedNotebookHandler,
34 NBBrowserHandler, NewHandler, NamedNotebookHandler,
35 MainKernelHandler, KernelHandler, KernelActionHandler, IOPubHandler,
35 MainKernelHandler, KernelHandler, KernelActionHandler, IOPubHandler,
36 ShellHandler, NotebookRootHandler, NotebookHandler, RSTHandler
36 ShellHandler, NotebookRootHandler, NotebookHandler, RSTHandler
37 )
37 )
38 from .notebookmanager import NotebookManager
38 from .notebookmanager import NotebookManager
39
39
40 from IPython.core.application import BaseIPythonApplication
40 from IPython.core.application import BaseIPythonApplication
41 from IPython.core.profiledir import ProfileDir
41 from IPython.core.profiledir import ProfileDir
42 from IPython.zmq.session import Session
42 from IPython.zmq.session import Session
43 from IPython.zmq.zmqshell import ZMQInteractiveShell
43 from IPython.zmq.zmqshell import ZMQInteractiveShell
44 from IPython.zmq.ipkernel import (
44 from IPython.zmq.ipkernel import (
45 flags as ipkernel_flags,
45 flags as ipkernel_flags,
46 aliases as ipkernel_aliases,
46 aliases as ipkernel_aliases,
47 IPKernelApp
47 IPKernelApp
48 )
48 )
49 from IPython.utils.traitlets import Dict, Unicode, Int, List, Enum
49 from IPython.utils.traitlets import Dict, Unicode, Int, List, Enum
50
50
51 #-----------------------------------------------------------------------------
51 #-----------------------------------------------------------------------------
52 # Module globals
52 # Module globals
53 #-----------------------------------------------------------------------------
53 #-----------------------------------------------------------------------------
54
54
55 _kernel_id_regex = r"(?P<kernel_id>\w+-\w+-\w+-\w+-\w+)"
55 _kernel_id_regex = r"(?P<kernel_id>\w+-\w+-\w+-\w+-\w+)"
56 _kernel_action_regex = r"(?P<action>restart|interrupt)"
56 _kernel_action_regex = r"(?P<action>restart|interrupt)"
57 _notebook_id_regex = r"(?P<notebook_id>\w+-\w+-\w+-\w+-\w+)"
57 _notebook_id_regex = r"(?P<notebook_id>\w+-\w+-\w+-\w+-\w+)"
58
58
59 LOCALHOST = '127.0.0.1'
59 LOCALHOST = '127.0.0.1'
60
60
61 _examples = """
61 _examples = """
62 ipython notebook # start the notebook
62 ipython notebook # start the notebook
63 ipython notebook --profile=sympy # use the sympy profile
63 ipython notebook --profile=sympy # use the sympy profile
64 ipython notebook --pylab=inline # pylab in inline plotting mode
64 ipython notebook --pylab=inline # pylab in inline plotting mode
65 ipython notebook --certfile=mycert.pem # use SSL/TLS certificate
65 ipython notebook --certfile=mycert.pem # use SSL/TLS certificate
66 ipython notebook --port=5555 --ip=* # Listen on port 5555, all interfaces
66 ipython notebook --port=5555 --ip=* # Listen on port 5555, all interfaces
67 """
67 """
68
68
69 #-----------------------------------------------------------------------------
69 #-----------------------------------------------------------------------------
70 # The Tornado web application
70 # The Tornado web application
71 #-----------------------------------------------------------------------------
71 #-----------------------------------------------------------------------------
72
72
73 class NotebookWebApplication(web.Application):
73 class NotebookWebApplication(web.Application):
74
74
75 def __init__(self, ipython_app, kernel_manager, notebook_manager, log):
75 def __init__(self, ipython_app, kernel_manager, notebook_manager, log):
76 handlers = [
76 handlers = [
77 (r"/", NBBrowserHandler),
77 (r"/", NBBrowserHandler),
78 (r"/new", NewHandler),
78 (r"/new", NewHandler),
79 (r"/%s" % _notebook_id_regex, NamedNotebookHandler),
79 (r"/%s" % _notebook_id_regex, NamedNotebookHandler),
80 (r"/kernels", MainKernelHandler),
80 (r"/kernels", MainKernelHandler),
81 (r"/kernels/%s" % _kernel_id_regex, KernelHandler),
81 (r"/kernels/%s" % _kernel_id_regex, KernelHandler),
82 (r"/kernels/%s/%s" % (_kernel_id_regex, _kernel_action_regex), KernelActionHandler),
82 (r"/kernels/%s/%s" % (_kernel_id_regex, _kernel_action_regex), KernelActionHandler),
83 (r"/kernels/%s/iopub" % _kernel_id_regex, IOPubHandler),
83 (r"/kernels/%s/iopub" % _kernel_id_regex, IOPubHandler),
84 (r"/kernels/%s/shell" % _kernel_id_regex, ShellHandler),
84 (r"/kernels/%s/shell" % _kernel_id_regex, ShellHandler),
85 (r"/notebooks", NotebookRootHandler),
85 (r"/notebooks", NotebookRootHandler),
86 (r"/notebooks/%s" % _notebook_id_regex, NotebookHandler),
86 (r"/notebooks/%s" % _notebook_id_regex, NotebookHandler),
87 (r"/rstservice/render", RSTHandler)
87 (r"/rstservice/render", RSTHandler)
88 ]
88 ]
89 settings = dict(
89 settings = dict(
90 template_path=os.path.join(os.path.dirname(__file__), "templates"),
90 template_path=os.path.join(os.path.dirname(__file__), "templates"),
91 static_path=os.path.join(os.path.dirname(__file__), "static"),
91 static_path=os.path.join(os.path.dirname(__file__), "static"),
92 )
92 )
93 web.Application.__init__(self, handlers, **settings)
93 web.Application.__init__(self, handlers, **settings)
94
94
95 self.kernel_manager = kernel_manager
95 self.kernel_manager = kernel_manager
96 self.log = log
96 self.log = log
97 self.notebook_manager = notebook_manager
97 self.notebook_manager = notebook_manager
98 self.ipython_app = ipython_app
98 self.ipython_app = ipython_app
99
99
100
100
101 #-----------------------------------------------------------------------------
101 #-----------------------------------------------------------------------------
102 # Aliases and Flags
102 # Aliases and Flags
103 #-----------------------------------------------------------------------------
103 #-----------------------------------------------------------------------------
104
104
105 flags = dict(ipkernel_flags)
105 flags = dict(ipkernel_flags)
106
106
107 # the flags that are specific to the frontend
107 # the flags that are specific to the frontend
108 # these must be scrubbed before being passed to the kernel,
108 # these must be scrubbed before being passed to the kernel,
109 # or it will raise an error on unrecognized flags
109 # or it will raise an error on unrecognized flags
110 notebook_flags = []
110 notebook_flags = []
111
111
112 aliases = dict(ipkernel_aliases)
112 aliases = dict(ipkernel_aliases)
113
113
114 aliases.update({
114 aliases.update({
115 'ip': 'IPythonNotebookApp.ip',
115 'ip': 'IPythonNotebookApp.ip',
116 'port': 'IPythonNotebookApp.port',
116 'port': 'IPythonNotebookApp.port',
117 'keyfile': 'IPythonNotebookApp.keyfile',
117 'keyfile': 'IPythonNotebookApp.keyfile',
118 'certfile': 'IPythonNotebookApp.certfile',
118 'certfile': 'IPythonNotebookApp.certfile',
119 'ws-hostname': 'IPythonNotebookApp.ws_hostname',
119 'ws-hostname': 'IPythonNotebookApp.ws_hostname',
120 'notebook-dir': 'NotebookManager.notebook_dir'
120 'notebook-dir': 'NotebookManager.notebook_dir'
121 })
121 })
122
122
123 notebook_aliases = [u'port', u'ip', u'keyfile', u'certfile', u'ws-hostname',
124 u'notebook-dir']
125
123 #-----------------------------------------------------------------------------
126 #-----------------------------------------------------------------------------
124 # IPythonNotebookApp
127 # IPythonNotebookApp
125 #-----------------------------------------------------------------------------
128 #-----------------------------------------------------------------------------
126
129
127 class IPythonNotebookApp(BaseIPythonApplication):
130 class IPythonNotebookApp(BaseIPythonApplication):
128
131
129 name = 'ipython-notebook'
132 name = 'ipython-notebook'
130 default_config_file_name='ipython_notebook_config.py'
133 default_config_file_name='ipython_notebook_config.py'
131
134
132 description = """
135 description = """
133 The IPython HTML Notebook.
136 The IPython HTML Notebook.
134
137
135 This launches a Tornado based HTML Notebook Server that serves up an
138 This launches a Tornado based HTML Notebook Server that serves up an
136 HTML5/Javascript Notebook client.
139 HTML5/Javascript Notebook client.
137 """
140 """
138 examples = _examples
141 examples = _examples
139
142
140 classes = [IPKernelApp, ZMQInteractiveShell, ProfileDir, Session,
143 classes = [IPKernelApp, ZMQInteractiveShell, ProfileDir, Session,
141 MappingKernelManager, NotebookManager]
144 MappingKernelManager, NotebookManager]
142 flags = Dict(flags)
145 flags = Dict(flags)
143 aliases = Dict(aliases)
146 aliases = Dict(aliases)
144
147
145 kernel_argv = List(Unicode)
148 kernel_argv = List(Unicode)
146
149
147 log_level = Enum((0,10,20,30,40,50,'DEBUG','INFO','WARN','ERROR','CRITICAL'),
150 log_level = Enum((0,10,20,30,40,50,'DEBUG','INFO','WARN','ERROR','CRITICAL'),
148 default_value=logging.INFO,
151 default_value=logging.INFO,
149 config=True,
152 config=True,
150 help="Set the log level by value or name.")
153 help="Set the log level by value or name.")
151
154
152 # Network related information.
155 # Network related information.
153
156
154 ip = Unicode(LOCALHOST, config=True,
157 ip = Unicode(LOCALHOST, config=True,
155 help="The IP address the notebook server will listen on."
158 help="The IP address the notebook server will listen on."
156 )
159 )
157
160
158 def _ip_changed(self, name, old, new):
161 def _ip_changed(self, name, old, new):
159 if new == u'*': self.ip = u''
162 if new == u'*': self.ip = u''
160
163
161 port = Int(8888, config=True,
164 port = Int(8888, config=True,
162 help="The port the notebook server will listen on."
165 help="The port the notebook server will listen on."
163 )
166 )
164
167
165 ws_hostname = Unicode(LOCALHOST, config=True,
168 ws_hostname = Unicode(LOCALHOST, config=True,
166 help="""The FQDN or IP for WebSocket connections. The default will work
169 help="""The FQDN or IP for WebSocket connections. The default will work
167 fine when the server is listening on localhost, but this needs to
170 fine when the server is listening on localhost, but this needs to
168 be set if the ip option is used. It will be used as the hostname part
171 be set if the ip option is used. It will be used as the hostname part
169 of the WebSocket url: ws://hostname/path."""
172 of the WebSocket url: ws://hostname/path."""
170 )
173 )
171
174
172 certfile = Unicode(u'', config=True,
175 certfile = Unicode(u'', config=True,
173 help="""The full path to an SSL/TLS certificate file."""
176 help="""The full path to an SSL/TLS certificate file."""
174 )
177 )
175
178
176 keyfile = Unicode(u'', config=True,
179 keyfile = Unicode(u'', config=True,
177 help="""The full path to a private key file for usage with SSL/TLS."""
180 help="""The full path to a private key file for usage with SSL/TLS."""
178 )
181 )
179
182
180 def get_ws_url(self):
183 def get_ws_url(self):
181 """Return the WebSocket URL for this server."""
184 """Return the WebSocket URL for this server."""
182 if self.certfile:
185 if self.certfile:
183 prefix = u'wss://'
186 prefix = u'wss://'
184 else:
187 else:
185 prefix = u'ws://'
188 prefix = u'ws://'
186 return prefix + self.ws_hostname + u':' + unicode(self.port)
189 return prefix + self.ws_hostname + u':' + unicode(self.port)
187
190
188 def parse_command_line(self, argv=None):
191 def parse_command_line(self, argv=None):
189 super(IPythonNotebookApp, self).parse_command_line(argv)
192 super(IPythonNotebookApp, self).parse_command_line(argv)
190 if argv is None:
193 if argv is None:
191 argv = sys.argv[1:]
194 argv = sys.argv[1:]
192
195
193 self.kernel_argv = list(argv) # copy
196 self.kernel_argv = list(argv) # copy
194 # kernel should inherit default config file from frontend
197 # kernel should inherit default config file from frontend
195 self.kernel_argv.append("--KernelApp.parent_appname='%s'"%self.name)
198 self.kernel_argv.append("--KernelApp.parent_appname='%s'"%self.name)
196 # scrub frontend-specific flags
199 # scrub frontend-specific flags
197 for a in argv:
200 for a in argv:
198 if a.startswith('-') and a.lstrip('-') in notebook_flags:
201 if a.startswith('-') and a.lstrip('-') in notebook_flags:
199 self.kernel_argv.remove(a)
202 self.kernel_argv.remove(a)
203 for a in argv:
204 if a.startswith('-'):
205 alias = a.lstrip('-').split('=')[0]
206 if alias in notebook_aliases:
207 self.kernel_argv.remove(a)
208 print self.kernel_argv
200
209
201 def init_configurables(self):
210 def init_configurables(self):
202 # Don't let Qt or ZMQ swallow KeyboardInterupts.
211 # Don't let Qt or ZMQ swallow KeyboardInterupts.
203 signal.signal(signal.SIGINT, signal.SIG_DFL)
212 signal.signal(signal.SIGINT, signal.SIG_DFL)
204
213
205 # Create a KernelManager and start a kernel.
214 # Create a KernelManager and start a kernel.
206 self.kernel_manager = MappingKernelManager(
215 self.kernel_manager = MappingKernelManager(
207 config=self.config, log=self.log, kernel_argv=self.kernel_argv
216 config=self.config, log=self.log, kernel_argv=self.kernel_argv
208 )
217 )
209 self.notebook_manager = NotebookManager(config=self.config, log=self.log)
218 self.notebook_manager = NotebookManager(config=self.config, log=self.log)
210
219
211 def init_logging(self):
220 def init_logging(self):
212 super(IPythonNotebookApp, self).init_logging()
221 super(IPythonNotebookApp, self).init_logging()
213 # This prevents double log messages because tornado use a root logger that
222 # This prevents double log messages because tornado use a root logger that
214 # self.log is a child of. The logging module dipatches log messages to a log
223 # self.log is a child of. The logging module dipatches log messages to a log
215 # and all of its ancenstors until propagate is set to False.
224 # and all of its ancenstors until propagate is set to False.
216 self.log.propagate = False
225 self.log.propagate = False
217
226
218 def initialize(self, argv=None):
227 def initialize(self, argv=None):
219 super(IPythonNotebookApp, self).initialize(argv)
228 super(IPythonNotebookApp, self).initialize(argv)
220 self.init_configurables()
229 self.init_configurables()
221 self.web_app = NotebookWebApplication(
230 self.web_app = NotebookWebApplication(
222 self, self.kernel_manager, self.notebook_manager, self.log
231 self, self.kernel_manager, self.notebook_manager, self.log
223 )
232 )
224 if self.certfile:
233 if self.certfile:
225 ssl_options = dict(certfile=self.certfile)
234 ssl_options = dict(certfile=self.certfile)
226 if self.keyfile:
235 if self.keyfile:
227 ssl_options['keyfile'] = self.keyfile
236 ssl_options['keyfile'] = self.keyfile
228 else:
237 else:
229 ssl_options = None
238 ssl_options = None
230 self.http_server = httpserver.HTTPServer(self.web_app, ssl_options=ssl_options)
239 self.http_server = httpserver.HTTPServer(self.web_app, ssl_options=ssl_options)
231 if ssl_options is None and not self.ip:
240 if ssl_options is None and not self.ip:
232 self.log.critical('WARNING: the notebook server is listening on all IP addresses '
241 self.log.critical('WARNING: the notebook server is listening on all IP addresses '
233 'but not using any encryption or authentication. This is highly '
242 'but not using any encryption or authentication. This is highly '
234 'insecure and not recommended.')
243 'insecure and not recommended.')
235 for i in range(10):
244 for i in range(10):
236 try:
245 try:
237 port = self.port + i
246 port = self.port + i
238 self.http_server.listen(port, self.ip)
247 self.http_server.listen(port, self.ip)
239 except socket.error, e:
248 except socket.error, e:
240 if e.errno != errno.EADDRINUSE:
249 if e.errno != errno.EADDRINUSE:
241 raise
250 raise
242 self.log.info('The port %i is already in use, trying: %i' % (port, port+1))
251 self.log.info('The port %i is already in use, trying: %i' % (port, port+1))
243 else:
252 else:
244 self.port = port
253 self.port = port
245 break
254 break
246
255
247
256
248 def start(self):
257 def start(self):
249 ip = self.ip if self.ip else '[all ip addresses on your system]'
258 ip = self.ip if self.ip else '[all ip addresses on your system]'
250 self.log.info("The IPython Notebook is running at: http://%s:%i" % (ip, self.port))
259 self.log.info("The IPython Notebook is running at: http://%s:%i" % (ip, self.port))
251 ioloop.IOLoop.instance().start()
260 ioloop.IOLoop.instance().start()
252
261
253 #-----------------------------------------------------------------------------
262 #-----------------------------------------------------------------------------
254 # Main entry point
263 # Main entry point
255 #-----------------------------------------------------------------------------
264 #-----------------------------------------------------------------------------
256
265
257 def launch_new_instance():
266 def launch_new_instance():
258 app = IPythonNotebookApp()
267 app = IPythonNotebookApp()
259 app.initialize()
268 app.initialize()
260 app.start()
269 app.start()
261
270
General Comments 0
You need to be logged in to leave comments. Login now