Skip to content

Commit b887f4e

Browse files
committed
review updates
1 parent dbea9c8 commit b887f4e

File tree

3 files changed

+21
-19
lines changed

3 files changed

+21
-19
lines changed

CHANGES.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@
6262
- new method: by default `DockerSpawner.allowed_images` will be set based on the values of
6363
`JUPYTERHUB_IMAGE_SELECTION_NAMES` and `JUPYTERHUB_DOCKER_NOTEBOOK_IMAGES`. If more than one image
6464
is specified by those variables then the user will be able to select which one they want. If you
65-
want to specify images other than those in the default those can be set using the `JUPYTERHUB_ALLOWED_IMAGES`
65+
want to specify images other than those in the default, those can be set using the `JUPYTERHUB_ALLOWED_IMAGES`
6666
which is a yaml or JSON mapping of image names to jupyterlab docker image tags.
6767
- using the `JUPYTERHUB_ADMIN_USERS` variable to set the `DockerSpawner.admin_users` variable is deprecated.
6868
- why?: this also executes arbitrary code (like above). Also, jupyterhub encourages assigning admin permissions

birdhouse/components/jupyterhub/jupyterhub_custom/jupyterhub_custom/custom_dockerspawner.py

Lines changed: 17 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import os
22
import random
33
import subprocess
4-
from os.path import join
4+
from typing import Any
55

66
import docker
77
from dockerspawner import DockerSpawner
@@ -46,8 +46,9 @@ def _default_environment(self) -> dict[str, str]:
4646
"BIRDHOUSE_HOST_URL": constants.BIRDHOUSE_HOST_URL,
4747
# https://docs.dask.org/en/stable/configuration.html
4848
# https://jupyterhub-on-hadoop.readthedocs.io/en/latest/dask.html
49-
"DASK_DISTRIBUTED__DASHBOARD__LINK": constants.BIRDHOUSE_HOST_URL
50-
+ "{JUPYTERHUB_SERVICE_PREFIX}proxy/{port}/status",
49+
"DASK_DISTRIBUTED__DASHBOARD__LINK": (
50+
constants.BIRDHOUSE_HOST_URL + "{JUPYTERHUB_SERVICE_PREFIX}proxy/{port}/status"
51+
),
5152
}
5253

5354
@default("volumes")
@@ -77,7 +78,7 @@ def _default_volumes(self) -> dict[str, str]:
7778
}
7879
if constants.README:
7980
volumes[constants.README] = {
80-
"bind": join(constants.NOTEBOOK_DIR, "README.ipynb"),
81+
"bind": os.path.join(constants.NOTEBOOK_DIR, "README.ipynb"),
8182
"mode": "ro",
8283
}
8384
return volumes
@@ -140,7 +141,7 @@ def _default_args(self) -> list[str]:
140141
return args
141142

142143
@default("extra_host_config")
143-
def _default_extra_host_config(self) -> dict:
144+
def _default_extra_host_config(self) -> dict[str, Any]:
144145
"""Return extra host configuration dictionary."""
145146
return {
146147
# start init pid 1 process to reap defunct processes
@@ -197,22 +198,22 @@ def _default_allowed_images(self) -> list[str] | dict[str, str]:
197198
# https://jupyterhub.readthedocs.io/en/latest/reference/api/spawner.html#jupyterhub.spawner.Spawner
198199

199200
@default("notebook_dir")
200-
def _default_notebook_dir(self) -> int:
201+
def _default_notebook_dir(self) -> str:
201202
"""Return notebook directory path."""
202203
return constants.NOTEBOOK_DIR
203204

204205
@default("disable_user_config")
205-
def _default_disable_user_config(self) -> int:
206+
def _default_disable_user_config(self) -> bool:
206207
"""Disable per-user configuration of single-user servers."""
207208
return True
208209

209210
@default("default_url")
210-
def _default_default_url(self) -> int:
211+
def _default_default_url(self) -> str:
211212
"""Set the URL the single-user server should start in."""
212213
return "/lab"
213214

214215
@default("debug")
215-
def _default_debug(self) -> int:
216+
def _default_debug(self) -> bool:
216217
"""Debug log output."""
217218
return True
218219

@@ -238,37 +239,37 @@ def escaped_name(self) -> str:
238239

239240
def __create_tutorial_notebook_hook(self) -> None:
240241
"""Mount tutorial notebooks as volumes based on the selected singleuser jupyterlab image."""
241-
container_tutorial_dir = join(constants.NOTEBOOK_DIR, "tutorial-notebooks")
242+
container_tutorial_dir = os.path.join(constants.NOTEBOOK_DIR, "tutorial-notebooks")
242243
if constants.JUPYTERHUB_MOUNT_IMAGE_SPECIFIC_NOTEBOOKS:
243-
host_tutorial_dir = join(
244+
host_tutorial_dir = os.path.join(
244245
constants.JUPYTERHUB_DATA_DIR,
245246
"tutorial-notebooks-specific-images",
246247
)
247248

248249
# Mount a volume with a tutorial-notebook subfolder corresponding to the image name, if it exists
249250
# The names are defined in the JUPYTERHUB_IMAGE_SELECTION_NAMES variable.
250251
image_name = self.user_options["image"]
251-
host_tutorial_subdir = join(host_tutorial_dir, image_name)
252+
host_tutorial_subdir = os.path.join(host_tutorial_dir, image_name)
252253
if not os.path.isdir(host_tutorial_subdir):
253254
# Try again, removing any colons and any following text. Useful if the image name contains
254255
# the version number, which should not be used in the directory name.
255-
host_tutorial_subdir = join(host_tutorial_dir, image_name.split(":")[0])
256+
host_tutorial_subdir = os.path.join(host_tutorial_dir, image_name.split(":")[0])
256257
if os.path.isdir(host_tutorial_subdir):
257258
self.volumes[host_tutorial_subdir] = {
258259
"bind": container_tutorial_dir,
259260
"mode": "ro",
260261
}
261262
else:
262263
# Mount the entire tutorial-notebooks directory
263-
self.volumes[join(constants.JUPYTERHUB_DATA_DIR, "tutorial-notebooks")] = {
264+
self.volumes[os.path.join(constants.JUPYTERHUB_DATA_DIR, "tutorial-notebooks")] = {
264265
"bind": container_tutorial_dir,
265266
"mode": "ro",
266267
}
267268

268269
def __create_dir_hook(self) -> None:
269270
"""Create user workspace directories on the host and update permissions if necessary."""
270271
username = self.user.name
271-
jupyterhub_user_dir = join(constants.JUPYTERHUB_DATA_DIR, username)
272+
jupyterhub_user_dir = os.path.join(constants.JUPYTERHUB_DATA_DIR, username)
272273

273274
if not os.path.exists(jupyterhub_user_dir):
274275
os.mkdir(jupyterhub_user_dir, 0o755)
@@ -285,7 +286,7 @@ def __create_dir_hook(self) -> None:
285286
if constants.COWBIRD_ENABLED:
286287
# Case for cowbird setup. The workspace directory should also have the user's ownership,
287288
# to have working volume mounts with the DockerSpawner.
288-
workspace_user_dir = join(constants.WORKSPACE_DIR, username)
289+
workspace_user_dir = os.path.join(constants.WORKSPACE_DIR, username)
289290
if not os.path.exists(workspace_user_dir):
290291
os.symlink(jupyterhub_user_dir, workspace_user_dir, target_is_directory=True)
291292
subprocess.call(

birdhouse/components/jupyterhub/jupyterhub_custom/jupyterhub_custom/magpie_authenticator.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import json
2+
from typing import Any
23

34
import requests
45
from jupyterhub.app import JupyterHub
@@ -106,15 +107,15 @@ def _default_allow_all(self) -> bool:
106107
return True
107108

108109
@default("blocked_users")
109-
def _default_blocked_users(self) -> set:
110+
def _default_blocked_users(self) -> set[str]:
110111
"""Block user with known hardcoded public password or non real Jupyter users."""
111112
return {"authtest", "anonymous"}
112113

113114
def get_handlers(self, app: JupyterHub) -> list[tuple[str, type[BaseHandler]]]:
114115
"""Return any custom handlers the authenticator needs to register."""
115116
return [("/logout", MagpieLogoutHandler)]
116117

117-
async def authenticate(self, handler: BaseHandler, data: dict) -> dict | None:
118+
async def authenticate(self, handler: BaseHandler, data: dict) -> dict[str, Any] | None:
118119
"""Authenticate a user with login form data."""
119120
signin_url = self.magpie_url.rstrip("/") + "/signin"
120121
userdata_url = self.magpie_url.rstrip("/") + "/users/current"

0 commit comments

Comments
 (0)