##// END OF EJS Templates
Merge pull request #5179 from minrk/rm-ws-url...
Brian E. Granger -
r15413:aba5fec1 merge
parent child Browse files
Show More
@@ -0,0 +1,6 b''
1 Simplifying configurable URLs
2 -----------------------------
3
4 - base_kernel_url configurable is removed
5 - websocket_url configurable is removed
6 - base_project_url is renamed to base_url (base_project_url is kept as a deprecates alias, for now)
@@ -120,15 +120,6 b' class IPythonHandler(AuthenticatedHandler):'
120 #---------------------------------------------------------------
120 #---------------------------------------------------------------
121
121
122 @property
122 @property
123 def ws_url(self):
124 """websocket url matching the current request
125
126 By default, this is just `''`, indicating that it should match
127 the same host, protocol, port, etc.
128 """
129 return self.settings.get('websocket_url', '')
130
131 @property
132 def mathjax_url(self):
123 def mathjax_url(self):
133 return self.settings.get('mathjax_url', '')
124 return self.settings.get('mathjax_url', '')
134
125
@@ -430,14 +430,6 b' class NotebookApp(BaseIPythonApplication):'
430 self.log.warn("base_project_url is deprecated, use base_url")
430 self.log.warn("base_project_url is deprecated, use base_url")
431 self.base_url = new
431 self.base_url = new
432
432
433 websocket_url = Unicode("", config=True,
434 help="""The base URL for the websocket server,
435 if it differs from the HTTP server (hint: it almost certainly doesn't).
436
437 Should be in the form of an HTTP origin: ws[s]://hostname[:port]
438 """
439 )
440
441 extra_static_paths = List(Unicode, config=True,
433 extra_static_paths = List(Unicode, config=True,
442 help="""Extra paths to search for serving static files.
434 help="""Extra paths to search for serving static files.
443
435
@@ -38,14 +38,14 b' class MainKernelHandler(IPythonHandler):'
38 @json_errors
38 @json_errors
39 def get(self):
39 def get(self):
40 km = self.kernel_manager
40 km = self.kernel_manager
41 self.finish(jsonapi.dumps(km.list_kernels(self.ws_url)))
41 self.finish(jsonapi.dumps(km.list_kernels()))
42
42
43 @web.authenticated
43 @web.authenticated
44 @json_errors
44 @json_errors
45 def post(self):
45 def post(self):
46 km = self.kernel_manager
46 km = self.kernel_manager
47 kernel_id = km.start_kernel()
47 kernel_id = km.start_kernel()
48 model = km.kernel_model(kernel_id, self.ws_url)
48 model = km.kernel_model(kernel_id)
49 location = url_path_join(self.base_url, 'api', 'kernels', kernel_id)
49 location = url_path_join(self.base_url, 'api', 'kernels', kernel_id)
50 self.set_header('Location', url_escape(location))
50 self.set_header('Location', url_escape(location))
51 self.set_status(201)
51 self.set_status(201)
@@ -61,7 +61,7 b' class KernelHandler(IPythonHandler):'
61 def get(self, kernel_id):
61 def get(self, kernel_id):
62 km = self.kernel_manager
62 km = self.kernel_manager
63 km._check_kernel_id(kernel_id)
63 km._check_kernel_id(kernel_id)
64 model = km.kernel_model(kernel_id, self.ws_url)
64 model = km.kernel_model(kernel_id)
65 self.finish(jsonapi.dumps(model))
65 self.finish(jsonapi.dumps(model))
66
66
67 @web.authenticated
67 @web.authenticated
@@ -84,7 +84,7 b' class KernelActionHandler(IPythonHandler):'
84 self.set_status(204)
84 self.set_status(204)
85 if action == 'restart':
85 if action == 'restart':
86 km.restart_kernel(kernel_id)
86 km.restart_kernel(kernel_id)
87 model = km.kernel_model(kernel_id, self.ws_url)
87 model = km.kernel_model(kernel_id)
88 self.set_header('Location', '{0}api/kernels/{1}'.format(self.base_url, kernel_id))
88 self.set_header('Location', '{0}api/kernels/{1}'.format(self.base_url, kernel_id))
89 self.write(jsonapi.dumps(model))
89 self.write(jsonapi.dumps(model))
90 self.finish()
90 self.finish()
@@ -75,19 +75,19 b' class MappingKernelManager(MultiKernelManager):'
75 self._check_kernel_id(kernel_id)
75 self._check_kernel_id(kernel_id)
76 super(MappingKernelManager, self).shutdown_kernel(kernel_id, now=now)
76 super(MappingKernelManager, self).shutdown_kernel(kernel_id, now=now)
77
77
78 def kernel_model(self, kernel_id, ws_url):
78 def kernel_model(self, kernel_id):
79 """Return a dictionary of kernel information described in the
79 """Return a dictionary of kernel information described in the
80 JSON standard model."""
80 JSON standard model."""
81 self._check_kernel_id(kernel_id)
81 self._check_kernel_id(kernel_id)
82 model = {"id":kernel_id, "ws_url": ws_url}
82 model = {"id":kernel_id}
83 return model
83 return model
84
84
85 def list_kernels(self, ws_url):
85 def list_kernels(self):
86 """Returns a list of kernel_id's of kernels running."""
86 """Returns a list of kernel_id's of kernels running."""
87 kernels = []
87 kernels = []
88 kernel_ids = super(MappingKernelManager, self).list_kernel_ids()
88 kernel_ids = super(MappingKernelManager, self).list_kernel_ids()
89 for kernel_id in kernel_ids:
89 for kernel_id in kernel_ids:
90 model = self.kernel_model(kernel_id, ws_url)
90 model = self.kernel_model(kernel_id)
91 kernels.append(model)
91 kernels.append(model)
92 return kernels
92 return kernels
93
93
@@ -93,7 +93,6 b' class KernelAPITest(NotebookTestBase):'
93 self.assertEqual(r.headers['Location'], '/api/kernels/'+kern2['id'])
93 self.assertEqual(r.headers['Location'], '/api/kernels/'+kern2['id'])
94 rekern = r.json()
94 rekern = r.json()
95 self.assertEqual(rekern['id'], kern2['id'])
95 self.assertEqual(rekern['id'], kern2['id'])
96 self.assertIn('ws_url', rekern)
97
96
98 def test_kernel_handler(self):
97 def test_kernel_handler(self):
99 # GET kernel with given id
98 # GET kernel with given id
@@ -103,7 +102,6 b' class KernelAPITest(NotebookTestBase):'
103 self.assertEqual(r.status_code, 200)
102 self.assertEqual(r.status_code, 200)
104 assert isinstance(kern1, dict)
103 assert isinstance(kern1, dict)
105 self.assertIn('id', kern1)
104 self.assertIn('id', kern1)
106 self.assertIn('ws_url', kern1)
107 self.assertEqual(kern1['id'], kid)
105 self.assertEqual(kern1['id'], kid)
108
106
109 # Request a bad kernel id and check that a JSON
107 # Request a bad kernel id and check that a JSON
@@ -63,7 +63,7 b' class SessionRootHandler(IPythonHandler):'
63 model = sm.get_session(name=name, path=path)
63 model = sm.get_session(name=name, path=path)
64 else:
64 else:
65 kernel_id = km.start_kernel(cwd=nbm.get_os_path(path))
65 kernel_id = km.start_kernel(cwd=nbm.get_os_path(path))
66 model = sm.create_session(name=name, path=path, kernel_id=kernel_id, ws_url=self.ws_url)
66 model = sm.create_session(name=name, path=path, kernel_id=kernel_id)
67 location = url_path_join(self.base_url, 'api', 'sessions', model['id'])
67 location = url_path_join(self.base_url, 'api', 'sessions', model['id'])
68 self.set_header('Location', url_escape(location))
68 self.set_header('Location', url_escape(location))
69 self.set_status(201)
69 self.set_status(201)
@@ -33,7 +33,7 b' class SessionManager(LoggingConfigurable):'
33 # Session database initialized below
33 # Session database initialized below
34 _cursor = None
34 _cursor = None
35 _connection = None
35 _connection = None
36 _columns = {'session_id', 'name', 'path', 'kernel_id', 'ws_url'}
36 _columns = {'session_id', 'name', 'path', 'kernel_id'}
37
37
38 @property
38 @property
39 def cursor(self):
39 def cursor(self):
@@ -41,7 +41,7 b' class SessionManager(LoggingConfigurable):'
41 if self._cursor is None:
41 if self._cursor is None:
42 self._cursor = self.connection.cursor()
42 self._cursor = self.connection.cursor()
43 self._cursor.execute("""CREATE TABLE session
43 self._cursor.execute("""CREATE TABLE session
44 (session_id, name, path, kernel_id, ws_url)""")
44 (session_id, name, path, kernel_id)""")
45 return self._cursor
45 return self._cursor
46
46
47 @property
47 @property
@@ -69,12 +69,12 b' class SessionManager(LoggingConfigurable):'
69 "Create a uuid for a new session"
69 "Create a uuid for a new session"
70 return unicode_type(uuid.uuid4())
70 return unicode_type(uuid.uuid4())
71
71
72 def create_session(self, name=None, path=None, kernel_id=None, ws_url=None):
72 def create_session(self, name=None, path=None, kernel_id=None):
73 """Creates a session and returns its model"""
73 """Creates a session and returns its model"""
74 session_id = self.new_session_id()
74 session_id = self.new_session_id()
75 return self.save_session(session_id, name=name, path=path, kernel_id=kernel_id, ws_url=ws_url)
75 return self.save_session(session_id, name=name, path=path, kernel_id=kernel_id)
76
76
77 def save_session(self, session_id, name=None, path=None, kernel_id=None, ws_url=None):
77 def save_session(self, session_id, name=None, path=None, kernel_id=None):
78 """Saves the items for the session with the given session_id
78 """Saves the items for the session with the given session_id
79
79
80 Given a session_id (and any other of the arguments), this method
80 Given a session_id (and any other of the arguments), this method
@@ -91,16 +91,14 b' class SessionManager(LoggingConfigurable):'
91 the path to the named notebook
91 the path to the named notebook
92 kernel_id : str
92 kernel_id : str
93 a uuid for the kernel associated with this session
93 a uuid for the kernel associated with this session
94 ws_url : str
94
95 the websocket url
96
97 Returns
95 Returns
98 -------
96 -------
99 model : dict
97 model : dict
100 a dictionary of the session model
98 a dictionary of the session model
101 """
99 """
102 self.cursor.execute("INSERT INTO session VALUES (?,?,?,?,?)",
100 self.cursor.execute("INSERT INTO session VALUES (?,?,?,?)",
103 (session_id, name, path, kernel_id, ws_url)
101 (session_id, name, path, kernel_id)
104 )
102 )
105 return self.get_session(session_id=session_id)
103 return self.get_session(session_id=session_id)
106
104
@@ -114,7 +112,7 b' class SessionManager(LoggingConfigurable):'
114 ----------
112 ----------
115 **kwargs : keyword argument
113 **kwargs : keyword argument
116 must be given one of the keywords and values from the session database
114 must be given one of the keywords and values from the session database
117 (i.e. session_id, name, path, kernel_id, ws_url)
115 (i.e. session_id, name, path, kernel_id)
118
116
119 Returns
117 Returns
120 -------
118 -------
@@ -184,7 +182,6 b' class SessionManager(LoggingConfigurable):'
184 },
182 },
185 'kernel': {
183 'kernel': {
186 'id': row['kernel_id'],
184 'id': row['kernel_id'],
187 'ws_url': row['ws_url']
188 }
185 }
189 }
186 }
190 return model
187 return model
@@ -11,16 +11,16 b' class TestSessionManager(TestCase):'
11 def test_get_session(self):
11 def test_get_session(self):
12 sm = SessionManager()
12 sm = SessionManager()
13 session_id = sm.new_session_id()
13 session_id = sm.new_session_id()
14 sm.save_session(session_id=session_id, name='test.ipynb', path='/path/to/', kernel_id='5678', ws_url='ws_url')
14 sm.save_session(session_id=session_id, name='test.ipynb', path='/path/to/', kernel_id='5678')
15 model = sm.get_session(session_id=session_id)
15 model = sm.get_session(session_id=session_id)
16 expected = {'id':session_id, 'notebook':{'name':u'test.ipynb', 'path': u'/path/to/'}, 'kernel':{'id':u'5678', 'ws_url':u'ws_url'}}
16 expected = {'id':session_id, 'notebook':{'name':u'test.ipynb', 'path': u'/path/to/'}, 'kernel':{'id':u'5678'}}
17 self.assertEqual(model, expected)
17 self.assertEqual(model, expected)
18
18
19 def test_bad_get_session(self):
19 def test_bad_get_session(self):
20 # Should raise error if a bad key is passed to the database.
20 # Should raise error if a bad key is passed to the database.
21 sm = SessionManager()
21 sm = SessionManager()
22 session_id = sm.new_session_id()
22 session_id = sm.new_session_id()
23 sm.save_session(session_id=session_id, name='test.ipynb', path='/path/to/', kernel_id='5678', ws_url='ws_url')
23 sm.save_session(session_id=session_id, name='test.ipynb', path='/path/to/', kernel_id='5678')
24 self.assertRaises(TypeError, sm.get_session, bad_id=session_id) # Bad keyword
24 self.assertRaises(TypeError, sm.get_session, bad_id=session_id) # Bad keyword
25
25
26 def test_list_sessions(self):
26 def test_list_sessions(self):
@@ -28,33 +28,33 b' class TestSessionManager(TestCase):'
28 session_id1 = sm.new_session_id()
28 session_id1 = sm.new_session_id()
29 session_id2 = sm.new_session_id()
29 session_id2 = sm.new_session_id()
30 session_id3 = sm.new_session_id()
30 session_id3 = sm.new_session_id()
31 sm.save_session(session_id=session_id1, name='test1.ipynb', path='/path/to/1/', kernel_id='5678', ws_url='ws_url')
31 sm.save_session(session_id=session_id1, name='test1.ipynb', path='/path/to/1/', kernel_id='5678')
32 sm.save_session(session_id=session_id2, name='test2.ipynb', path='/path/to/2/', kernel_id='5678', ws_url='ws_url')
32 sm.save_session(session_id=session_id2, name='test2.ipynb', path='/path/to/2/', kernel_id='5678')
33 sm.save_session(session_id=session_id3, name='test3.ipynb', path='/path/to/3/', kernel_id='5678', ws_url='ws_url')
33 sm.save_session(session_id=session_id3, name='test3.ipynb', path='/path/to/3/', kernel_id='5678')
34 sessions = sm.list_sessions()
34 sessions = sm.list_sessions()
35 expected = [{'id':session_id1, 'notebook':{'name':u'test1.ipynb',
35 expected = [{'id':session_id1, 'notebook':{'name':u'test1.ipynb',
36 'path': u'/path/to/1/'}, 'kernel':{'id':u'5678', 'ws_url': 'ws_url'}},
36 'path': u'/path/to/1/'}, 'kernel':{'id':u'5678'}},
37 {'id':session_id2, 'notebook': {'name':u'test2.ipynb',
37 {'id':session_id2, 'notebook': {'name':u'test2.ipynb',
38 'path': u'/path/to/2/'}, 'kernel':{'id':u'5678', 'ws_url': 'ws_url'}},
38 'path': u'/path/to/2/'}, 'kernel':{'id':u'5678'}},
39 {'id':session_id3, 'notebook':{'name':u'test3.ipynb',
39 {'id':session_id3, 'notebook':{'name':u'test3.ipynb',
40 'path': u'/path/to/3/'}, 'kernel':{'id':u'5678', 'ws_url': 'ws_url'}}]
40 'path': u'/path/to/3/'}, 'kernel':{'id':u'5678'}}]
41 self.assertEqual(sessions, expected)
41 self.assertEqual(sessions, expected)
42
42
43 def test_update_session(self):
43 def test_update_session(self):
44 sm = SessionManager()
44 sm = SessionManager()
45 session_id = sm.new_session_id()
45 session_id = sm.new_session_id()
46 sm.save_session(session_id=session_id, name='test.ipynb', path='/path/to/', kernel_id=None, ws_url='ws_url')
46 sm.save_session(session_id=session_id, name='test.ipynb', path='/path/to/', kernel_id=None)
47 sm.update_session(session_id, kernel_id='5678')
47 sm.update_session(session_id, kernel_id='5678')
48 sm.update_session(session_id, name='new_name.ipynb')
48 sm.update_session(session_id, name='new_name.ipynb')
49 model = sm.get_session(session_id=session_id)
49 model = sm.get_session(session_id=session_id)
50 expected = {'id':session_id, 'notebook':{'name':u'new_name.ipynb', 'path': u'/path/to/'}, 'kernel':{'id':u'5678', 'ws_url': 'ws_url'}}
50 expected = {'id':session_id, 'notebook':{'name':u'new_name.ipynb', 'path': u'/path/to/'}, 'kernel':{'id':u'5678'}}
51 self.assertEqual(model, expected)
51 self.assertEqual(model, expected)
52
52
53 def test_bad_update_session(self):
53 def test_bad_update_session(self):
54 # try to update a session with a bad keyword ~ raise error
54 # try to update a session with a bad keyword ~ raise error
55 sm = SessionManager()
55 sm = SessionManager()
56 session_id = sm.new_session_id()
56 session_id = sm.new_session_id()
57 sm.save_session(session_id=session_id, name='test.ipynb', path='/path/to/', kernel_id='5678', ws_url='ws_url')
57 sm.save_session(session_id=session_id, name='test.ipynb', path='/path/to/', kernel_id='5678')
58 self.assertRaises(TypeError, sm.update_session, session_id=session_id, bad_kw='test.ipynb') # Bad keyword
58 self.assertRaises(TypeError, sm.update_session, session_id=session_id, bad_kw='test.ipynb') # Bad keyword
59
59
60 def test_delete_session(self):
60 def test_delete_session(self):
@@ -62,22 +62,22 b' class TestSessionManager(TestCase):'
62 session_id1 = sm.new_session_id()
62 session_id1 = sm.new_session_id()
63 session_id2 = sm.new_session_id()
63 session_id2 = sm.new_session_id()
64 session_id3 = sm.new_session_id()
64 session_id3 = sm.new_session_id()
65 sm.save_session(session_id=session_id1, name='test1.ipynb', path='/path/to/1/', kernel_id='5678', ws_url='ws_url')
65 sm.save_session(session_id=session_id1, name='test1.ipynb', path='/path/to/1/', kernel_id='5678')
66 sm.save_session(session_id=session_id2, name='test2.ipynb', path='/path/to/2/', kernel_id='5678', ws_url='ws_url')
66 sm.save_session(session_id=session_id2, name='test2.ipynb', path='/path/to/2/', kernel_id='5678')
67 sm.save_session(session_id=session_id3, name='test3.ipynb', path='/path/to/3/', kernel_id='5678', ws_url='ws_url')
67 sm.save_session(session_id=session_id3, name='test3.ipynb', path='/path/to/3/', kernel_id='5678')
68 sm.delete_session(session_id2)
68 sm.delete_session(session_id2)
69 sessions = sm.list_sessions()
69 sessions = sm.list_sessions()
70 expected = [{'id':session_id1, 'notebook':{'name':u'test1.ipynb',
70 expected = [{'id':session_id1, 'notebook':{'name':u'test1.ipynb',
71 'path': u'/path/to/1/'}, 'kernel':{'id':u'5678', 'ws_url': 'ws_url'}},
71 'path': u'/path/to/1/'}, 'kernel':{'id':u'5678'}},
72 {'id':session_id3, 'notebook':{'name':u'test3.ipynb',
72 {'id':session_id3, 'notebook':{'name':u'test3.ipynb',
73 'path': u'/path/to/3/'}, 'kernel':{'id':u'5678', 'ws_url': 'ws_url'}}]
73 'path': u'/path/to/3/'}, 'kernel':{'id':u'5678'}}]
74 self.assertEqual(sessions, expected)
74 self.assertEqual(sessions, expected)
75
75
76 def test_bad_delete_session(self):
76 def test_bad_delete_session(self):
77 # try to delete a session that doesn't exist ~ raise error
77 # try to delete a session that doesn't exist ~ raise error
78 sm = SessionManager()
78 sm = SessionManager()
79 session_id = sm.new_session_id()
79 session_id = sm.new_session_id()
80 sm.save_session(session_id=session_id, name='test.ipynb', path='/path/to/', kernel_id='5678', ws_url='ws_url')
80 sm.save_session(session_id=session_id, name='test.ipynb', path='/path/to/', kernel_id='5678')
81 self.assertRaises(TypeError, sm.delete_session, bad_kwarg='23424') # Bad keyword
81 self.assertRaises(TypeError, sm.delete_session, bad_kwarg='23424') # Bad keyword
82 self.assertRaises(web.HTTPError, sm.delete_session, session_id='23424') # nonexistant
82 self.assertRaises(web.HTTPError, sm.delete_session, session_id='23424') # nonexistant
83
83
@@ -125,16 +125,9 b' var IPython = (function (IPython) {'
125 console.log("Kernel started: ", json.id);
125 console.log("Kernel started: ", json.id);
126 this.running = true;
126 this.running = true;
127 this.kernel_id = json.id;
127 this.kernel_id = json.id;
128 var ws_url = json.ws_url;
128 // trailing 's' in https will become wss for secure web sockets
129 if (ws_url.match(/wss?:\/\//) === null) {
129 this.ws_host = location.protocol.replace('http', 'ws') + "//" + location.host;
130 // trailing 's' in https will become wss for secure web sockets
131 var prot = location.protocol.replace('http', 'ws') + "//";
132 ws_url = prot + location.host + ws_url;
133 }
134 var parsed = utils.parse_url(ws_url);
135 this.ws_host = parsed.protocol + "//" + parsed.host;
136 this.kernel_url = utils.url_path_join(this.kernel_service_url, this.kernel_id);
130 this.kernel_url = utils.url_path_join(this.kernel_service_url, this.kernel_id);
137 this.ws_url = utils.url_path_join(parsed.pathname, this.kernel_url);
138 this.start_channels();
131 this.start_channels();
139 };
132 };
140
133
@@ -155,18 +148,18 b' var IPython = (function (IPython) {'
155 Kernel.prototype.start_channels = function () {
148 Kernel.prototype.start_channels = function () {
156 var that = this;
149 var that = this;
157 this.stop_channels();
150 this.stop_channels();
158 console.log("Starting WebSockets:", this.ws_host + this.ws_url);
151 var ws_host_url = this.ws_host + this.kernel_url;
152 console.log("Starting WebSockets:", ws_host_url);
159 this.shell_channel = new this.WebSocket(
153 this.shell_channel = new this.WebSocket(
160 this.ws_host + utils.url_join_encode(this.ws_url, "shell")
154 this.ws_host + utils.url_join_encode(this.kernel_url, "shell")
161 );
155 );
162 this.stdin_channel = new this.WebSocket(
156 this.stdin_channel = new this.WebSocket(
163 this.ws_host + utils.url_join_encode(this.ws_url, "stdin")
157 this.ws_host + utils.url_join_encode(this.kernel_url, "stdin")
164 );
158 );
165 this.iopub_channel = new this.WebSocket(
159 this.iopub_channel = new this.WebSocket(
166 this.ws_host + utils.url_join_encode(this.ws_url, "iopub")
160 this.ws_host + utils.url_join_encode(this.kernel_url, "iopub")
167 );
161 );
168
162
169 var ws_host_url = this.ws_host + this.ws_url;
170 var already_called_onclose = false; // only alert once
163 var already_called_onclose = false; // only alert once
171 var ws_closed_early = function(evt){
164 var ws_closed_early = function(evt){
172 if (already_called_onclose){
165 if (already_called_onclose){
General Comments 0
You need to be logged in to leave comments. Login now