mirror of
https://github.com/jupyterhub/the-littlest-jupyterhub.git
synced 2025-12-18 21:54:05 +08:00
Merge pull request #842 from yuvipanda/upgrade-things
update: jupyterhub 3, oauthenticator 15, systemdspawner 0.17 (user env: ipywidgets 8)
This commit is contained in:
@@ -346,12 +346,12 @@ async def test_idle_server_culled():
|
|||||||
)
|
)
|
||||||
).wait()
|
).wait()
|
||||||
)
|
)
|
||||||
# Check every 10s for idle servers to cull
|
# Check every 5s for idle servers to cull
|
||||||
assert (
|
assert (
|
||||||
0
|
0
|
||||||
== await (
|
== await (
|
||||||
await asyncio.create_subprocess_exec(
|
await asyncio.create_subprocess_exec(
|
||||||
*TLJH_CONFIG_PATH, "set", "services.cull.every", "10"
|
*TLJH_CONFIG_PATH, "set", "services.cull.every", "5"
|
||||||
)
|
)
|
||||||
).wait()
|
).wait()
|
||||||
)
|
)
|
||||||
@@ -364,12 +364,12 @@ async def test_idle_server_culled():
|
|||||||
)
|
)
|
||||||
).wait()
|
).wait()
|
||||||
)
|
)
|
||||||
# Cull servers and users after 60s of activity
|
# Cull servers and users after 30s, regardless of activity
|
||||||
assert (
|
assert (
|
||||||
0
|
0
|
||||||
== await (
|
== await (
|
||||||
await asyncio.create_subprocess_exec(
|
await asyncio.create_subprocess_exec(
|
||||||
*TLJH_CONFIG_PATH, "set", "services.cull.max_age", "60"
|
*TLJH_CONFIG_PATH, "set", "services.cull.max_age", "30"
|
||||||
)
|
)
|
||||||
).wait()
|
).wait()
|
||||||
)
|
)
|
||||||
@@ -388,25 +388,50 @@ async def test_idle_server_culled():
|
|||||||
assert pwd.getpwnam(f"jupyter-{username}") is not None
|
assert pwd.getpwnam(f"jupyter-{username}") is not None
|
||||||
|
|
||||||
# Check that we can get to the user's server
|
# Check that we can get to the user's server
|
||||||
r = await u.session.get(
|
user_url = u.notebook_url / "api/status"
|
||||||
u.hub_url / "hub/api/users" / username,
|
r = await u.session.get(user_url, allow_redirects=False)
|
||||||
headers={"Referer": str(u.hub_url / "hub/")},
|
|
||||||
)
|
|
||||||
assert r.status == 200
|
assert r.status == 200
|
||||||
|
|
||||||
async def _check_culling_done():
|
# Check that we can talk to JupyterHub itself
|
||||||
# Check that after 60s, the user and server have been culled and are not reacheable anymore
|
# use this as a proxy for whether the user still exists
|
||||||
|
async def hub_api_request():
|
||||||
r = await u.session.get(
|
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/")},
|
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
|
return r.status == 403
|
||||||
|
|
||||||
await exponential_backoff(
|
await exponential_backoff(
|
||||||
_check_culling_done,
|
user_removed,
|
||||||
"Server culling failed!",
|
"User still exists!",
|
||||||
timeout=100,
|
timeout=timeout,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@@ -429,12 +454,12 @@ async def test_active_server_not_culled():
|
|||||||
)
|
)
|
||||||
).wait()
|
).wait()
|
||||||
)
|
)
|
||||||
# Check every 10s for idle servers to cull
|
# Check every 5s for idle servers to cull
|
||||||
assert (
|
assert (
|
||||||
0
|
0
|
||||||
== await (
|
== await (
|
||||||
await asyncio.create_subprocess_exec(
|
await asyncio.create_subprocess_exec(
|
||||||
*TLJH_CONFIG_PATH, "set", "services.cull.every", "10"
|
*TLJH_CONFIG_PATH, "set", "services.cull.every", "5"
|
||||||
)
|
)
|
||||||
).wait()
|
).wait()
|
||||||
)
|
)
|
||||||
@@ -447,7 +472,7 @@ async def test_active_server_not_culled():
|
|||||||
)
|
)
|
||||||
).wait()
|
).wait()
|
||||||
)
|
)
|
||||||
# Cull servers and users after 60s of activity
|
# Cull servers and users after 30s, regardless of activity
|
||||||
assert (
|
assert (
|
||||||
0
|
0
|
||||||
== await (
|
== await (
|
||||||
@@ -471,27 +496,24 @@ async def test_active_server_not_culled():
|
|||||||
assert pwd.getpwnam(f"jupyter-{username}") is not None
|
assert pwd.getpwnam(f"jupyter-{username}") is not None
|
||||||
|
|
||||||
# Check that we can get to the user's server
|
# Check that we can get to the user's server
|
||||||
r = await u.session.get(
|
user_url = u.notebook_url / "api/status"
|
||||||
u.hub_url / "hub/api/users" / username,
|
r = await u.session.get(user_url, allow_redirects=False)
|
||||||
headers={"Referer": str(u.hub_url / "hub/")},
|
|
||||||
)
|
|
||||||
assert r.status == 200
|
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
|
# Check that after 30s, we can still reach the user's server
|
||||||
r = await u.session.get(
|
r = await u.session.get(user_url, allow_redirects=False)
|
||||||
u.hub_url / "hub/api/users" / username,
|
print(f"{r.status} {r.url}")
|
||||||
headers={"Referer": str(u.hub_url / "hub/")},
|
|
||||||
)
|
|
||||||
print(r.status)
|
|
||||||
return r.status != 200
|
return r.status != 200
|
||||||
|
|
||||||
try:
|
try:
|
||||||
await exponential_backoff(
|
await exponential_backoff(
|
||||||
_check_culling_done,
|
server_has_stopped,
|
||||||
"User's server is still reacheable!",
|
"User's server is still reachable (good!)",
|
||||||
timeout=30,
|
timeout=30,
|
||||||
)
|
)
|
||||||
except TimeoutError:
|
except asyncio.TimeoutError:
|
||||||
# During the 30s timeout the user's server wasn't culled, which is what we intended.
|
# timeout error means the test passed - the server didn't go away while we were waiting
|
||||||
pass
|
pass
|
||||||
|
else:
|
||||||
|
pytest.fail(f"Server at {user_url} got culled prematurely!")
|
||||||
|
|||||||
@@ -121,14 +121,13 @@ def ensure_jupyterhub_package(prefix):
|
|||||||
conda.ensure_pip_packages(
|
conda.ensure_pip_packages(
|
||||||
prefix,
|
prefix,
|
||||||
[
|
[
|
||||||
"SQLAlchemy<2.0.0",
|
"jupyterhub==3.*",
|
||||||
"jupyterhub==1.*",
|
"jupyterhub-systemdspawner==0.17.*",
|
||||||
"jupyterhub-systemdspawner==0.16.*",
|
|
||||||
"jupyterhub-firstuseauthenticator==1.*",
|
"jupyterhub-firstuseauthenticator==1.*",
|
||||||
"jupyterhub-nativeauthenticator==1.*",
|
"jupyterhub-nativeauthenticator==1.*",
|
||||||
"jupyterhub-ldapauthenticator==1.*",
|
"jupyterhub-ldapauthenticator==1.*",
|
||||||
"jupyterhub-tmpauthenticator==0.6.*",
|
"jupyterhub-tmpauthenticator==0.6.*",
|
||||||
"oauthenticator==14.*",
|
"oauthenticator==15.*",
|
||||||
"jupyterhub-idle-culler==1.*",
|
"jupyterhub-idle-culler==1.*",
|
||||||
"git+https://github.com/yuvipanda/jupyterhub-configurator@317759e17c8e48de1b1352b836dac2a230536dba",
|
"git+https://github.com/yuvipanda/jupyterhub-configurator@317759e17c8e48de1b1352b836dac2a230536dba",
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -5,20 +5,15 @@
|
|||||||
# the requirements-txt-fixer pre-commit hook that sorted them and made
|
# the requirements-txt-fixer pre-commit hook that sorted them and made
|
||||||
# our integration tests fail.
|
# 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 + notebook package are base requirements for user environment
|
||||||
jupyterhub==1.*
|
jupyterhub==3.*
|
||||||
notebook==6.*
|
notebook==6.*
|
||||||
# Install additional notebook frontends!
|
# Install additional notebook frontends!
|
||||||
jupyterlab==3.*
|
jupyterlab==3.*
|
||||||
nteract-on-jupyter==2.*
|
nteract-on-jupyter==2.*
|
||||||
# Install jupyterlab extensions from PyPI
|
|
||||||
# nbgitpuller for easily pulling in Git repositories
|
# nbgitpuller for easily pulling in Git repositories
|
||||||
nbgitpuller==1.*
|
nbgitpuller==1.*
|
||||||
# jupyter-resource-usage to show people how much RAM they are using
|
# 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
|
# Most people consider ipywidgets to be part of the core notebook experience
|
||||||
ipywidgets==7.*
|
ipywidgets==8.*
|
||||||
# Pin tornado
|
|
||||||
tornado>=6.1
|
|
||||||
|
|||||||
Reference in New Issue
Block a user