Add post-spawn hook

This commit is contained in:
James Curtin
2018-05-04 19:56:34 -04:00
parent 10ea92dcea
commit 2f3f8d7826
4 changed files with 32 additions and 3 deletions

View File

@@ -25,6 +25,9 @@ Another use would be to copy initial content, such as tutorial files or referenc
You can define your own bootstrap process by implementing a `pre_spawn_hook` on any spawner.
The Spawner itself is passed as parameter to your hook and you can easily get the contextual information out of the spawning process.
Similarly, there may be cases where you would like to clean up after a spawner stops.
You may implement a `post_spawn_hook` that is always executed after the spawner stops.
If you implement a hook, make sure that it is *idempotent*. It will be executed every time
a notebook server is spawned to the user. That means you should somehow
ensure that things which should run only once are not running again and again.

View File

@@ -2,6 +2,7 @@
# create a directory for the user before the spawner starts
import os
import shutil
def create_dir_hook(spawner):
username = spawner.user.name # get the username
volume_path = os.path.join('/volumes/jupyterhub', username)
@@ -10,8 +11,15 @@ def create_dir_hook(spawner):
# now do whatever you think your user needs
# ...
# attach the hook function to the spawner
def clean_dir_hook(spawner):
username = spawner.user.name # get the username
temp_path = os.path.join('/volumes/jupyterhub', username, 'temp')
if os.path.exists(temp_path) and os.path.isdir(temp_path):
shutil.rmtree(temp_path)
# attach the hook functions to the spawner
c.Spawner.pre_spawn_hook = create_dir_hook
c.Spawner.post_spawn_hook = clean_dir_hook
# Use the DockerSpawner to serve your users' notebooks
c.JupyterHub.spawner_class = 'dockerspawner.DockerSpawner'

View File

@@ -515,6 +515,15 @@ class Spawner(LoggingConfigurable):
"""
).tag(config=True)
post_spawn_hook = Any(
help="""
An optional hook function that you can implement to do work after
the spawner stops.
This can be set independent of any concrete spawner implementation.
"""
).tag(config=True)
def load_state(self, state):
"""Restore state of spawner from database.
@@ -692,6 +701,13 @@ class Spawner(LoggingConfigurable):
if self.pre_spawn_hook:
return self.pre_spawn_hook(self)
def run_post_spawn_hook(self):
"""Run the post_spawn_hook if defined"""
try:
return self.post_spawn_hook(self)
except Exception:
self.log.exception("post_spawn_hook failed with exception: %s", self)
@property
def _progress_url(self):
return self.user.progress_url(self.name)

View File

@@ -559,6 +559,8 @@ class User:
finally:
spawner.orm_spawner.started = None
self.db.commit()
# trigger post-spawner hook
await maybe_future(spawner.run_post_spawn_hook())
# trigger post-spawner hook on authenticator
auth = spawner.authenticator
try: