Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

update: jupyterhub 3, oauthenticator 15, systemdspawner 0.17 (user env: ipywidgets 8) #842

Merged
merged 4 commits into from
Apr 4, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
86 changes: 54 additions & 32 deletions integration-tests/test_hub.py
Original file line number Diff line number Diff line change
Expand Up @@ -346,12 +346,12 @@ async def test_idle_server_culled():
)
).wait()
)
# Check every 10s for idle servers to cull
# Check every 5s for idle servers to cull
assert (
0
== await (
await asyncio.create_subprocess_exec(
*TLJH_CONFIG_PATH, "set", "services.cull.every", "10"
*TLJH_CONFIG_PATH, "set", "services.cull.every", "5"
)
).wait()
)
Expand All @@ -364,12 +364,12 @@ async def test_idle_server_culled():
)
).wait()
)
# Cull servers and users after 60s of activity
# Cull servers and users after 30s, regardless of activity
assert (
0
== await (
await asyncio.create_subprocess_exec(
*TLJH_CONFIG_PATH, "set", "services.cull.max_age", "60"
*TLJH_CONFIG_PATH, "set", "services.cull.max_age", "30"
)
).wait()
)
Expand All @@ -388,25 +388,50 @@ async def test_idle_server_culled():
assert pwd.getpwnam(f"jupyter-{username}") is not None

# Check that we can get to the user's server
r = await u.session.get(
u.hub_url / "hub/api/users" / username,
headers={"Referer": str(u.hub_url / "hub/")},
)
user_url = u.notebook_url / "api/status"
r = await u.session.get(user_url, allow_redirects=False)
assert r.status == 200

async def _check_culling_done():
# Check that after 60s, the user and server have been culled and are not reacheable anymore
# Check that we can talk to JupyterHub itself
# use this as a proxy for whether the user still exists
async def hub_api_request():
r = await u.session.get(
u.hub_url / "hub/api/users" / username,
u.hub_url / "hub/api/user",
headers={"Referer": str(u.hub_url / "hub/")},
allow_redirects=False,
)
print(r.status)
return r

r = await hub_api_request()
assert r.status == 200

# Wait for culling
# step 1: check if the server is still running
timeout = 100

async def server_stopped():
"""Has the server been stopped?"""
r = await u.session.get(user_url, allow_redirects=False)
print(f"{r.status} {r.url}")
return r.status != 200

await exponential_backoff(
server_stopped,
"Server still running!",
timeout=timeout,
)

# step 2. wait for user to be deleted
async def user_removed():
# Check that after 60s, the user has been culled
r = await hub_api_request()
print(f"{r.status} {r.url}")
return r.status == 403

await exponential_backoff(
_check_culling_done,
"Server culling failed!",
timeout=100,
user_removed,
"User still exists!",
timeout=timeout,
)


Expand All @@ -429,12 +454,12 @@ async def test_active_server_not_culled():
)
).wait()
)
# Check every 10s for idle servers to cull
# Check every 5s for idle servers to cull
assert (
0
== await (
await asyncio.create_subprocess_exec(
*TLJH_CONFIG_PATH, "set", "services.cull.every", "10"
*TLJH_CONFIG_PATH, "set", "services.cull.every", "5"
)
).wait()
)
Expand All @@ -447,7 +472,7 @@ async def test_active_server_not_culled():
)
).wait()
)
# Cull servers and users after 60s of activity
# Cull servers and users after 30s, regardless of activity
assert (
0
== await (
Expand All @@ -471,27 +496,24 @@ async def test_active_server_not_culled():
assert pwd.getpwnam(f"jupyter-{username}") is not None

# Check that we can get to the user's server
r = await u.session.get(
u.hub_url / "hub/api/users" / username,
headers={"Referer": str(u.hub_url / "hub/")},
)
user_url = u.notebook_url / "api/status"
r = await u.session.get(user_url, allow_redirects=False)
assert r.status == 200

async def _check_culling_done():
async def server_has_stopped():
# Check that after 30s, we can still reach the user's server
r = await u.session.get(
u.hub_url / "hub/api/users" / username,
headers={"Referer": str(u.hub_url / "hub/")},
)
print(r.status)
r = await u.session.get(user_url, allow_redirects=False)
print(f"{r.status} {r.url}")
return r.status != 200

try:
await exponential_backoff(
_check_culling_done,
"User's server is still reacheable!",
server_has_stopped,
"User's server is still reachable (good!)",
timeout=30,
)
except TimeoutError:
# During the 30s timeout the user's server wasn't culled, which is what we intended.
except asyncio.TimeoutError:
# timeout error means the test passed - the server didn't go away while we were waiting
pass
else:
pytest.fail(f"Server at {user_url} got culled prematurely!")
7 changes: 3 additions & 4 deletions tljh/installer.py
Original file line number Diff line number Diff line change
Expand Up @@ -121,14 +121,13 @@ def ensure_jupyterhub_package(prefix):
conda.ensure_pip_packages(
prefix,
[
"SQLAlchemy<2.0.0",
"jupyterhub==1.*",
"jupyterhub-systemdspawner==0.16.*",
"jupyterhub==3.*",
"jupyterhub-systemdspawner==0.17.*",
"jupyterhub-firstuseauthenticator==1.*",
"jupyterhub-nativeauthenticator==1.*",
"jupyterhub-ldapauthenticator==1.*",
"jupyterhub-tmpauthenticator==0.6.*",
"oauthenticator==14.*",
"oauthenticator==15.*",
"jupyterhub-idle-culler==1.*",
"git+https://github.com/yuvipanda/jupyterhub-configurator@317759e17c8e48de1b1352b836dac2a230536dba",
],
Expand Down
11 changes: 3 additions & 8 deletions tljh/requirements-base.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5,20 +5,15 @@
# the requirements-txt-fixer pre-commit hook that sorted them and made
# our integration tests fail.
#
# For JupyterHub 1.x SQLAlchemy below 2.0.0
SQLAlchemy<2.0.0
# JupyterHub + notebook package are base requirements for user environment
jupyterhub==1.*
jupyterhub==3.*
notebook==6.*
# Install additional notebook frontends!
jupyterlab==3.*
nteract-on-jupyter==2.*
consideRatio marked this conversation as resolved.
Show resolved Hide resolved
# Install jupyterlab extensions from PyPI
# nbgitpuller for easily pulling in Git repositories
nbgitpuller==1.*
# jupyter-resource-usage to show people how much RAM they are using
jupyter-resource-usage==0.6.*
jupyter-resource-usage==0.7.*
# Most people consider ipywidgets to be part of the core notebook experience
ipywidgets==7.*
# Pin tornado
tornado>=6.1
ipywidgets==8.*