mirror of
https://github.com/jupyterhub/jupyterhub.git
synced 2025-10-18 15:33:02 +00:00
Edit the custom spawners doc
This commit is contained in:
@@ -1,17 +1,32 @@
|
|||||||
# Writing a custom Spawner
|
# Writing a custom Spawner
|
||||||
|
|
||||||
Each single-user server is started by a [Spawner][].
|
[Spawner][] starts each single-user notebook server.
|
||||||
The Spawner represents an abstract interface to a process,
|
The Spawner represents an abstract interface to a process,
|
||||||
and a custom Spawner needs to be able to take three actions:
|
and a custom Spawner needs to be able to take three actions:
|
||||||
|
|
||||||
1. start the process
|
- start the process
|
||||||
2. poll whether the process is still running
|
- poll whether the process is still running
|
||||||
3. stop the process
|
- stop the process
|
||||||
|
|
||||||
See a list of custom Spawners [on the wiki](https://github.com/jupyter/jupyterhub/wiki/Spawners).
|
## Examples
|
||||||
|
Custom Spawners for JupyterHub can be found on the [JupyterHub wiki](https://github.com/jupyter/jupyterhub/wiki/Spawners). Some examples include:
|
||||||
|
- [DockerSpawner](https://github.com/jupyter/dockerspawner) for spawning user servers in Docker containers
|
||||||
|
* dockerspawner.DockerSpawner for spawning identical Docker containers for
|
||||||
|
each users
|
||||||
|
* dockerspawner.SystemUserSpawner for spawning Docker containers with an
|
||||||
|
environment and home directory for each users
|
||||||
|
- [SudoSpawner](https://github.com/jupyter/sudospawner) enables JupyterHub to
|
||||||
|
run without being root, by spawning an intermediate process via `sudo`
|
||||||
|
- [BatchSpawner](https://github.com/mbmilligan/batchspawner) for spawning remote
|
||||||
|
servers using batch systems
|
||||||
|
- [RemoteSpawner](https://github.com/zonca/remotespawner) to spawn notebooks
|
||||||
|
and a remote server and tunnel the port via SSH
|
||||||
|
- [SwarmSpawner](https://github.com/compmodels/jupyterhub/blob/master/swarmspawner.py)
|
||||||
|
for spawning containers using Docker Swarm
|
||||||
|
|
||||||
|
## Spawner control methods
|
||||||
|
|
||||||
## Spawner.start
|
### Spawner.start
|
||||||
|
|
||||||
`Spawner.start` should start the single-user server for a single user.
|
`Spawner.start` should start the single-user server for a single user.
|
||||||
Information about the user can be retrieved from `self.user`,
|
Information about the user can be retrieved from `self.user`,
|
||||||
@@ -20,8 +35,9 @@ an object encapsulating the user's name, authentication, and server info.
|
|||||||
When `Spawner.start` returns, it should have stored the IP and port
|
When `Spawner.start` returns, it should have stored the IP and port
|
||||||
of the single-user server in `self.user.server`.
|
of the single-user server in `self.user.server`.
|
||||||
|
|
||||||
**NOTE:** when writing coroutines, *never* `yield` in between a db change and a commit.
|
**NOTE:** When writing coroutines, *never* `yield` in between a database change and a commit.
|
||||||
Most `Spawner.start`s should have something looking like:
|
|
||||||
|
Most `Spawner.start` functions will look similar to this example:
|
||||||
|
|
||||||
```python
|
```python
|
||||||
def start(self):
|
def start(self):
|
||||||
@@ -36,33 +52,30 @@ not just requested. JupyterHub can handle `Spawner.start` being very slow
|
|||||||
(such as PBS-style batch queues, or instantiating whole AWS instances)
|
(such as PBS-style batch queues, or instantiating whole AWS instances)
|
||||||
via relaxing the `Spawner.start_timeout` config value.
|
via relaxing the `Spawner.start_timeout` config value.
|
||||||
|
|
||||||
|
### Spawner.poll
|
||||||
## Spawner.poll
|
|
||||||
|
|
||||||
`Spawner.poll` should check if the spawner is still running.
|
`Spawner.poll` should check if the spawner is still running.
|
||||||
It should return `None` if it is still running,
|
It should return `None` if it is still running,
|
||||||
and an integer exit status, otherwise.
|
and an integer exit status, otherwise.
|
||||||
|
|
||||||
For the local process case, this uses `os.kill(PID, 0)`
|
For the local process case, `Spawner.poll` uses `os.kill(PID, 0)`
|
||||||
to check if the process is still around.
|
to check if the local process is still running.
|
||||||
|
|
||||||
|
|
||||||
## Spawner.stop
|
### Spawner.stop
|
||||||
|
|
||||||
`Spawner.stop` should stop the process. It must be a tornado coroutine,
|
|
||||||
and should return when the process has finished exiting.
|
|
||||||
|
|
||||||
|
`Spawner.stop` should stop the process. It must be a tornado coroutine, which should return when the process has finished exiting.
|
||||||
|
|
||||||
## Spawner state
|
## Spawner state
|
||||||
|
|
||||||
JupyterHub should be able to stop and restart without having to teardown
|
JupyterHub should be able to stop and restart without tearing down
|
||||||
single-user servers. This means that a Spawner may need to persist
|
single-user notebook servers. To do this task, a Spawner may need to persist
|
||||||
some information that it can be restored.
|
some information that can be restored later.
|
||||||
A dictionary of JSON-able state can be used to store this information.
|
A JSON-able dictionary of state can be used to store persisted information.
|
||||||
|
|
||||||
Unlike start/stop/poll, the state methods must not be coroutines.
|
Unlike start, stop, and poll methods, the state methods must not be coroutines.
|
||||||
|
|
||||||
In the single-process case, this is only the process ID of the server:
|
For the single-process case, the Spawner state is only the process ID of the server:
|
||||||
|
|
||||||
```python
|
```python
|
||||||
def get_state(self):
|
def get_state(self):
|
||||||
@@ -94,11 +107,11 @@ or docker-based deployments where users can select from a list of base images.
|
|||||||
|
|
||||||
This feature is enabled by setting `Spawner.options_form`, which is an HTML form snippet
|
This feature is enabled by setting `Spawner.options_form`, which is an HTML form snippet
|
||||||
inserted unmodified into the spawn form.
|
inserted unmodified into the spawn form.
|
||||||
If the `Spawner.options_form` is defined, when a user would start their server, they will be directed to a form page, like this:
|
If the `Spawner.options_form` is defined, when a user tries to start their server, they will be directed to a form page, like this:
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
If `Spawner.options_form` is undefined, the users server is spawned directly, and no spawn page is rendered.
|
If `Spawner.options_form` is undefined, the user's server is spawned directly, and no spawn page is rendered.
|
||||||
|
|
||||||
See [this example](https://github.com/jupyter/jupyterhub/blob/master/examples/spawn-form/jupyterhub_config.py) for a form that allows custom CLI args for the local spawner.
|
See [this example](https://github.com/jupyter/jupyterhub/blob/master/examples/spawn-form/jupyterhub_config.py) for a form that allows custom CLI args for the local spawner.
|
||||||
|
|
||||||
@@ -115,9 +128,9 @@ Options from this form will always be a dictionary of lists of strings, e.g.:
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
When formdata arrives, it is passed through `Spawner.options_from_form(formdata)`,
|
When `formdata` arrives, it is passed through `Spawner.options_from_form(formdata)`,
|
||||||
which is a method to turn the form data into the correct structure.
|
which is a method to turn the form data into the correct structure.
|
||||||
This method must return a dictionary, and is meant to interpret the lists-of-strings into the correct types, e.g. for the above form it would look like:
|
This method must return a dictionary, and is meant to interpret the lists-of-strings into the correct types. For example, the `options_from_form` for the above form would look like:
|
||||||
|
|
||||||
```python
|
```python
|
||||||
def options_from_form(self, formdata):
|
def options_from_form(self, formdata):
|
||||||
@@ -140,7 +153,7 @@ which would return:
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
When `Spawner.spawn` is called, this dict is accessible as `self.user_options`.
|
When `Spawner.spawn` is called, this dictionary is accessible as `self.user_options`.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user