Skip to content

Commit d6dd8e7

Browse files
author
Brian Ball
committed
Fix when base_url is used in combination with a gateway client.
1 parent 31a8555 commit d6dd8e7

File tree

3 files changed

+39
-9
lines changed

3 files changed

+39
-9
lines changed

jupyter_server/gateway/gateway_client.py

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
from traitlets.config import LoggingConfigurable, SingletonConfigurable
3434

3535
from jupyter_server import DEFAULT_EVENTS_SCHEMA_PATH, JUPYTER_SERVER_EVENTS_URI
36+
from jupyter_server.utils import url_path_join
3637

3738
ERROR_STATUS = "error"
3839
SUCCESS_STATUS = "success"
@@ -170,6 +171,18 @@ def _ws_url_validate(self, proposal):
170171
raise TraitError(message)
171172
return value
172173

174+
base_url = Unicode(
175+
default_value="/",
176+
config=True,
177+
help="""The gateway API base_url for fixing default kernel endpoints""",
178+
)
179+
180+
@observe("base_url")
181+
def _base_url(self, change):
182+
self.kernels_endpoint = self._kernels_endpoint_default()
183+
self.kernelspecs_endpoint = self._kernelspecs_endpoint_default()
184+
self.kernelspecs_resource_endpoint = self._kernelspecs_resource_endpoint_default()
185+
173186
kernels_endpoint_default_value = "/api/kernels"
174187
kernels_endpoint_env = "JUPYTER_GATEWAY_KERNELS_ENDPOINT"
175188
kernels_endpoint = Unicode(
@@ -180,7 +193,7 @@ def _ws_url_validate(self, proposal):
180193

181194
@default("kernels_endpoint")
182195
def _kernels_endpoint_default(self):
183-
return os.environ.get(self.kernels_endpoint_env, self.kernels_endpoint_default_value)
196+
return os.environ.get(self.kernels_endpoint_env, url_path_join(self.base_url, self.kernels_endpoint_default_value))
184197

185198
kernelspecs_endpoint_default_value = "/api/kernelspecs"
186199
kernelspecs_endpoint_env = "JUPYTER_GATEWAY_KERNELSPECS_ENDPOINT"
@@ -193,7 +206,7 @@ def _kernels_endpoint_default(self):
193206
@default("kernelspecs_endpoint")
194207
def _kernelspecs_endpoint_default(self):
195208
return os.environ.get(
196-
self.kernelspecs_endpoint_env, self.kernelspecs_endpoint_default_value
209+
self.kernelspecs_endpoint_env, url_path_join(self.base_url, self.kernelspecs_endpoint_default_value)
197210
)
198211

199212
kernelspecs_resource_endpoint_default_value = "/kernelspecs"
@@ -209,7 +222,7 @@ def _kernelspecs_endpoint_default(self):
209222
def _kernelspecs_resource_endpoint_default(self):
210223
return os.environ.get(
211224
self.kernelspecs_resource_endpoint_env,
212-
self.kernelspecs_resource_endpoint_default_value,
225+
url_path_join(self.base_url, self.kernelspecs_resource_endpoint_default_value),
213226
)
214227

215228
connect_timeout_default_value = 40.0

jupyter_server/gateway/managers.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ def _default_shared_context(self):
5454
def __init__(self, **kwargs):
5555
"""Initialize a gateway mapping kernel manager."""
5656
super().__init__(**kwargs)
57+
GatewayClient.instance().base_url = self.parent.base_url
5758
self.kernels_url = url_path_join(
5859
GatewayClient.instance().url or "", GatewayClient.instance().kernels_endpoint or ""
5960
)
@@ -218,6 +219,8 @@ class GatewayKernelSpecManager(KernelSpecManager):
218219
def __init__(self, **kwargs):
219220
"""Initialize a gateway kernel spec manager."""
220221
super().__init__(**kwargs)
222+
GatewayClient.instance().base_url = self.parent.base_url
223+
221224
base_endpoint = url_path_join(
222225
GatewayClient.instance().url or "", GatewayClient.instance().kernelspecs_endpoint
223226
)
@@ -248,7 +251,7 @@ def _replace_path_kernelspec_resources(self, kernel_specs):
248251
resources = kernelspecs[kernel_name]["resources"]
249252
for resource_name in resources:
250253
original_path = resources[resource_name]
251-
split_eg_base_url = str.rsplit(original_path, sep="/kernelspecs/", maxsplit=1)
254+
split_eg_base_url = str.rsplit(original_path, sep="/kernelspecs", maxsplit=1)
252255
if len(split_eg_base_url) > 1:
253256
new_path = url_path_join(
254257
self.parent.base_url, "kernelspecs", split_eg_base_url[1]

tests/test_gateway.py

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -28,13 +28,14 @@
2828
from jupyter_server.gateway.gateway_client import GatewayTokenRenewerBase, NoOpTokenRenewer
2929
from jupyter_server.gateway.managers import ChannelQueue, GatewayClient, GatewayKernelManager
3030
from jupyter_server.services.kernels.websocket import KernelWebsocketHandler
31+
from jupyter_server.utils import url_path_join
3132

3233
from .utils import expected_http_error
3334

3435
pytest_plugins = ["jupyter_events.pytest_plugin"]
3536

3637

37-
def generate_kernelspec(name):
38+
def generate_kernelspec(name, kernelspecs_endpoint):
3839
argv_stanza = ["python", "-m", "ipykernel_launcher", "-f", "{connection_file}"]
3940
spec_stanza = {
4041
"spec": {
@@ -52,6 +53,7 @@ def generate_kernelspec(name):
5253
"resources": {
5354
"logo-64x64": f"f/kernelspecs/{name}/logo-64x64.png",
5455
"url": "https://example.com/example-url",
56+
"kernelspec": kernelspecs_endpoint,
5557
},
5658
}
5759
return kernelspec_stanza
@@ -61,8 +63,9 @@ def generate_kernelspec(name):
6163
kernelspecs: dict = {
6264
"default": "kspec_foo",
6365
"kernelspecs": {
64-
"kspec_foo": generate_kernelspec("kspec_foo"),
65-
"kspec_bar": generate_kernelspec("kspec_bar"),
66+
"kspec_foo": generate_kernelspec("kspec_foo", "/foo/kernelspecs"),
67+
"kspec_bar": generate_kernelspec("kspec_bar", "/bar/kernelspecs/"),
68+
"kspec_baz": generate_kernelspec("kspec_baz", GatewayClient.kernelspecs_endpoint_default_value),
6669
},
6770
}
6871

@@ -437,11 +440,20 @@ async def test_gateway_get_kernelspecs(init_gateway, jp_fetch, jp_serverapp):
437440
assert r.code == 200
438441
content = json.loads(r.body.decode("utf-8"))
439442
kspecs = content.get("kernelspecs")
440-
assert len(kspecs) == 2
443+
assert len(kspecs) == 3
441444
assert kspecs.get("kspec_bar").get("name") == "kspec_bar"
442445
assert (
443446
kspecs.get("kspec_bar").get("resources")["logo-64x64"].startswith(jp_serverapp.base_url)
444447
)
448+
assert (
449+
kspecs.get("kspec_bar").get("resources")["kernelspec"].startswith(jp_serverapp.base_url)
450+
)
451+
assert (
452+
kspecs.get("kspec_foo").get("resources")["kernelspec"].startswith(jp_serverapp.base_url)
453+
)
454+
assert (
455+
kspecs.get("kspec_baz").get("resources")["kernelspec"].startswith(jp_serverapp.base_url)
456+
)
445457

446458

447459
async def test_gateway_get_named_kernelspec(init_gateway, jp_fetch):
@@ -751,7 +763,9 @@ async def test_websocket_connection_with_session_id(init_gateway, jp_serverapp,
751763
await conn.connect()
752764
assert conn.session_id != None
753765
expected_ws_url = (
754-
f"{mock_gateway_ws_url}/api/kernels/{kernel_id}/channels?session_id={conn.session_id}"
766+
url_path_join(mock_gateway_ws_url,
767+
jp_serverapp.base_url,
768+
f"/api/kernels/{kernel_id}/channels?session_id={conn.session_id}")
755769
)
756770
assert (
757771
expected_ws_url in caplog.text

0 commit comments

Comments
 (0)