mirror of
https://github.com/jupyterhub/jupyterhub.git
synced 2025-10-15 22:13:00 +00:00
review pass on spawner docstring changes
- small wording, spelling tweaks - rst formatting fixes - remove some spurious, cluttering newlines - clearer traitlets default values on first line
This commit is contained in:
@@ -186,9 +186,9 @@ class Authenticator(LoggingConfigurable):
|
|||||||
handler (tornado.web.RequestHandler): the current request handler
|
handler (tornado.web.RequestHandler): the current request handler
|
||||||
data (dict): The formdata of the login form.
|
data (dict): The formdata of the login form.
|
||||||
The default form has 'username' and 'password' fields.
|
The default form has 'username' and 'password' fields.
|
||||||
Return:
|
Returns:
|
||||||
str: the username of the authenticated user
|
username (str or None): The username of the authenticated user,
|
||||||
None: Authentication failed
|
or None if Authentication failed
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def pre_spawn_start(self, user, spawner):
|
def pre_spawn_start(self, user, spawner):
|
||||||
@@ -278,8 +278,9 @@ class Authenticator(LoggingConfigurable):
|
|||||||
app (JupyterHub Application):
|
app (JupyterHub Application):
|
||||||
the application object, in case it needs to be accessed for info.
|
the application object, in case it needs to be accessed for info.
|
||||||
Returns:
|
Returns:
|
||||||
list: list of ``('/url', Handler)`` tuples passed to tornado.
|
handlers (list):
|
||||||
The Hub prefix is added to any URLs.
|
list of ``('/url', Handler)`` tuples passed to tornado.
|
||||||
|
The Hub prefix is added to any URLs.
|
||||||
"""
|
"""
|
||||||
return [
|
return [
|
||||||
('/login', LoginHandler),
|
('/login', LoginHandler),
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
"""
|
"""
|
||||||
Contains abstract base Spawner class & default implementation.
|
Contains base Spawner class & default implementation
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# Copyright (c) Jupyter Development Team.
|
# Copyright (c) Jupyter Development Team.
|
||||||
@@ -31,8 +31,7 @@ from .utils import random_port
|
|||||||
|
|
||||||
|
|
||||||
class Spawner(LoggingConfigurable):
|
class Spawner(LoggingConfigurable):
|
||||||
"""
|
"""Base class for spawning single-user notebook servers.
|
||||||
Abstract base class for spawning single-user notebook servers.
|
|
||||||
|
|
||||||
Subclass this, and override the following methods:
|
Subclass this, and override the following methods:
|
||||||
|
|
||||||
@@ -53,8 +52,7 @@ class Spawner(LoggingConfigurable):
|
|||||||
authenticator = Any()
|
authenticator = Any()
|
||||||
api_token = Unicode()
|
api_token = Unicode()
|
||||||
|
|
||||||
ip = Unicode(
|
ip = Unicode('127.0.0.1',
|
||||||
'127.0.0.1',
|
|
||||||
help="""
|
help="""
|
||||||
The IP address (or hostname) the single-user server should listen on.
|
The IP address (or hostname) the single-user server should listen on.
|
||||||
|
|
||||||
@@ -62,8 +60,7 @@ class Spawner(LoggingConfigurable):
|
|||||||
"""
|
"""
|
||||||
).tag(config=True)
|
).tag(config=True)
|
||||||
|
|
||||||
port = Integer(
|
port = Integer(0,
|
||||||
0,
|
|
||||||
help="""
|
help="""
|
||||||
The port for single-user servers to listen on.
|
The port for single-user servers to listen on.
|
||||||
|
|
||||||
@@ -73,8 +70,7 @@ class Spawner(LoggingConfigurable):
|
|||||||
"""
|
"""
|
||||||
)
|
)
|
||||||
|
|
||||||
start_timeout = Integer(
|
start_timeout = Integer(60,
|
||||||
60,
|
|
||||||
help="""
|
help="""
|
||||||
Timeout (in seconds) before giving up on starting of single-user server.
|
Timeout (in seconds) before giving up on starting of single-user server.
|
||||||
|
|
||||||
@@ -84,8 +80,7 @@ class Spawner(LoggingConfigurable):
|
|||||||
"""
|
"""
|
||||||
).tag(config=True)
|
).tag(config=True)
|
||||||
|
|
||||||
http_timeout = Integer(
|
http_timeout = Integer(30,
|
||||||
30,
|
|
||||||
help="""
|
help="""
|
||||||
Timeout (in seconds) before giving up on a spawned HTTP server
|
Timeout (in seconds) before giving up on a spawned HTTP server
|
||||||
|
|
||||||
@@ -95,8 +90,7 @@ class Spawner(LoggingConfigurable):
|
|||||||
"""
|
"""
|
||||||
).tag(config=True)
|
).tag(config=True)
|
||||||
|
|
||||||
poll_interval = Integer(
|
poll_interval = Integer(30,
|
||||||
30,
|
|
||||||
help="""
|
help="""
|
||||||
Interval (in seconds) on which to poll the spawner for single-user server's status.
|
Interval (in seconds) on which to poll the spawner for single-user server's status.
|
||||||
|
|
||||||
@@ -110,15 +104,13 @@ class Spawner(LoggingConfigurable):
|
|||||||
_poll_callback = Any()
|
_poll_callback = Any()
|
||||||
|
|
||||||
debug = Bool(False,
|
debug = Bool(False,
|
||||||
help="""
|
help="Enable debug-logging of the single-user server"
|
||||||
Enable debug-logging of the single-user server.
|
|
||||||
"""
|
|
||||||
).tag(config=True)
|
).tag(config=True)
|
||||||
|
|
||||||
options_form = Unicode(
|
options_form = Unicode(
|
||||||
"",
|
|
||||||
help="""
|
help="""
|
||||||
An HTML form for options a user can specify on launching their server.
|
An HTML form for options a user can specify on launching their server.
|
||||||
|
|
||||||
The surrounding `<form>` element and the submit button are already provided.
|
The surrounding `<form>` element and the submit button are already provided.
|
||||||
|
|
||||||
For example:
|
For example:
|
||||||
@@ -200,8 +192,7 @@ class Spawner(LoggingConfigurable):
|
|||||||
"""
|
"""
|
||||||
).tag(config=True)
|
).tag(config=True)
|
||||||
|
|
||||||
cmd = Command(
|
cmd = Command(['jupyterhub-singleuser'],
|
||||||
['jupyterhub-singleuser'],
|
|
||||||
help="""
|
help="""
|
||||||
The command used for starting the single-user server.
|
The command used for starting the single-user server.
|
||||||
|
|
||||||
@@ -216,8 +207,7 @@ class Spawner(LoggingConfigurable):
|
|||||||
"""
|
"""
|
||||||
).tag(config=True)
|
).tag(config=True)
|
||||||
|
|
||||||
args = List(
|
args = List(Unicode(),
|
||||||
Unicode(),
|
|
||||||
help="""
|
help="""
|
||||||
Extra arguments to be passed to the single-user server.
|
Extra arguments to be passed to the single-user server.
|
||||||
|
|
||||||
@@ -227,7 +217,6 @@ class Spawner(LoggingConfigurable):
|
|||||||
).tag(config=True)
|
).tag(config=True)
|
||||||
|
|
||||||
notebook_dir = Unicode(
|
notebook_dir = Unicode(
|
||||||
'',
|
|
||||||
help="""
|
help="""
|
||||||
Path to the notebook directory for the single-user server.
|
Path to the notebook directory for the single-user server.
|
||||||
|
|
||||||
@@ -244,7 +233,6 @@ class Spawner(LoggingConfigurable):
|
|||||||
).tag(config=True)
|
).tag(config=True)
|
||||||
|
|
||||||
default_url = Unicode(
|
default_url = Unicode(
|
||||||
'',
|
|
||||||
help="""
|
help="""
|
||||||
The URL the single-user server should start in.
|
The URL the single-user server should start in.
|
||||||
|
|
||||||
@@ -269,8 +257,7 @@ class Spawner(LoggingConfigurable):
|
|||||||
self.log.warning("Converting %r to %r", proposal['value'], v)
|
self.log.warning("Converting %r to %r", proposal['value'], v)
|
||||||
return v
|
return v
|
||||||
|
|
||||||
disable_user_config = Bool(
|
disable_user_config = Bool(False,
|
||||||
False,
|
|
||||||
help="""
|
help="""
|
||||||
Disable per-user configuration of single-user servers.
|
Disable per-user configuration of single-user servers.
|
||||||
|
|
||||||
@@ -282,8 +269,7 @@ class Spawner(LoggingConfigurable):
|
|||||||
"""
|
"""
|
||||||
).tag(config=True)
|
).tag(config=True)
|
||||||
|
|
||||||
mem_limit = MemorySpecification(
|
mem_limit = MemorySpecification(None,
|
||||||
None,
|
|
||||||
help="""
|
help="""
|
||||||
Maximum number of bytes a single-user notebook server is allowed to use.
|
Maximum number of bytes a single-user notebook server is allowed to use.
|
||||||
|
|
||||||
@@ -302,8 +288,7 @@ class Spawner(LoggingConfigurable):
|
|||||||
"""
|
"""
|
||||||
).tag(config=True)
|
).tag(config=True)
|
||||||
|
|
||||||
cpu_limit = Float(
|
cpu_limit = Float(None,
|
||||||
None,
|
|
||||||
allow_none=True,
|
allow_none=True,
|
||||||
help="""
|
help="""
|
||||||
Maximum number of cpu-cores a single-user notebook server is allowed to use.
|
Maximum number of cpu-cores a single-user notebook server is allowed to use.
|
||||||
@@ -319,8 +304,7 @@ class Spawner(LoggingConfigurable):
|
|||||||
"""
|
"""
|
||||||
).tag(config=True)
|
).tag(config=True)
|
||||||
|
|
||||||
mem_guarantee = MemorySpecification(
|
mem_guarantee = MemorySpecification(None,
|
||||||
None,
|
|
||||||
help="""
|
help="""
|
||||||
Minimum number of bytes a single-user notebook server is guaranteed to have available.
|
Minimum number of bytes a single-user notebook server is guaranteed to have available.
|
||||||
|
|
||||||
@@ -334,8 +318,7 @@ class Spawner(LoggingConfigurable):
|
|||||||
"""
|
"""
|
||||||
).tag(config=True)
|
).tag(config=True)
|
||||||
|
|
||||||
cpu_guarantee = Float(
|
cpu_guarantee = Float(None,
|
||||||
None,
|
|
||||||
allow_none=True,
|
allow_none=True,
|
||||||
help="""
|
help="""
|
||||||
Minimum number of cpu-cores a single-user notebook server is guaranteed to have available.
|
Minimum number of cpu-cores a single-user notebook server is guaranteed to have available.
|
||||||
@@ -353,8 +336,7 @@ class Spawner(LoggingConfigurable):
|
|||||||
self.load_state(self.user.state)
|
self.load_state(self.user.state)
|
||||||
|
|
||||||
def load_state(self, state):
|
def load_state(self, state):
|
||||||
"""
|
"""Restore state of spawner from database.
|
||||||
Restore state of spawner from database.
|
|
||||||
|
|
||||||
Called for each user's spawner after the hub process restarts.
|
Called for each user's spawner after the hub process restarts.
|
||||||
|
|
||||||
@@ -367,8 +349,7 @@ class Spawner(LoggingConfigurable):
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
def get_state(self):
|
def get_state(self):
|
||||||
"""
|
"""Save state of spawner into database.
|
||||||
Save state of spawner into database.
|
|
||||||
|
|
||||||
A black box of extra state for custom spawners. The returned value of this is
|
A black box of extra state for custom spawners. The returned value of this is
|
||||||
passed to `load_state`.
|
passed to `load_state`.
|
||||||
@@ -385,8 +366,7 @@ class Spawner(LoggingConfigurable):
|
|||||||
return state
|
return state
|
||||||
|
|
||||||
def clear_state(self):
|
def clear_state(self):
|
||||||
"""
|
"""Clear any state that should be cleared when the single-user server stops.
|
||||||
Clear any state that should be cleared when the single-user server stops.
|
|
||||||
|
|
||||||
State that should be preserved across single-user server instances should not be cleared.
|
State that should be preserved across single-user server instances should not be cleared.
|
||||||
|
|
||||||
@@ -395,8 +375,7 @@ class Spawner(LoggingConfigurable):
|
|||||||
self.api_token = ''
|
self.api_token = ''
|
||||||
|
|
||||||
def get_env(self):
|
def get_env(self):
|
||||||
"""
|
"""Return the environment dict to use for the Spawner.
|
||||||
Return the environment dict to use for the Spawner.
|
|
||||||
|
|
||||||
This applies things like `env_keep`, anything defined in `Spawner.environment`,
|
This applies things like `env_keep`, anything defined in `Spawner.environment`,
|
||||||
and adds the API token to the env.
|
and adds the API token to the env.
|
||||||
@@ -443,8 +422,7 @@ class Spawner(LoggingConfigurable):
|
|||||||
return env
|
return env
|
||||||
|
|
||||||
def template_namespace(self):
|
def template_namespace(self):
|
||||||
"""
|
"""Return the template namespace for format-string formatting.
|
||||||
Return the template namespace for format-string formatting.
|
|
||||||
|
|
||||||
Currently used on default_url and notebook_dir.
|
Currently used on default_url and notebook_dir.
|
||||||
|
|
||||||
@@ -467,8 +445,7 @@ class Spawner(LoggingConfigurable):
|
|||||||
return d
|
return d
|
||||||
|
|
||||||
def format_string(self, s):
|
def format_string(self, s):
|
||||||
"""
|
"""Render a Python format string
|
||||||
Render a Python format string.
|
|
||||||
|
|
||||||
Uses :meth:`Spawner.template_namespace` to populate format namespace.
|
Uses :meth:`Spawner.template_namespace` to populate format namespace.
|
||||||
|
|
||||||
@@ -483,8 +460,7 @@ class Spawner(LoggingConfigurable):
|
|||||||
return s.format(**self.template_namespace())
|
return s.format(**self.template_namespace())
|
||||||
|
|
||||||
def get_args(self):
|
def get_args(self):
|
||||||
"""
|
"""Return the arguments to be passed after self.cmd
|
||||||
Return the arguments to be passed after self.cmd.
|
|
||||||
|
|
||||||
Doesn't expect shell expansion to happen.
|
Doesn't expect shell expansion to happen.
|
||||||
"""
|
"""
|
||||||
@@ -521,11 +497,10 @@ class Spawner(LoggingConfigurable):
|
|||||||
|
|
||||||
@gen.coroutine
|
@gen.coroutine
|
||||||
def start(self):
|
def start(self):
|
||||||
"""
|
"""Start the single-user server
|
||||||
Start the single-user server.
|
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
(ip, port): the ip, port where the Hub can connect to the server.
|
(str, int): the (ip, port) where the Hub can connect to the server.
|
||||||
|
|
||||||
.. versionchanged:: 0.7
|
.. versionchanged:: 0.7
|
||||||
Return ip, port instead of setting on self.user.server directly.
|
Return ip, port instead of setting on self.user.server directly.
|
||||||
@@ -534,24 +509,22 @@ class Spawner(LoggingConfigurable):
|
|||||||
|
|
||||||
@gen.coroutine
|
@gen.coroutine
|
||||||
def stop(self, now=False):
|
def stop(self, now=False):
|
||||||
"""
|
"""Stop the single-user server
|
||||||
Stop the single-user server.
|
|
||||||
|
|
||||||
If `now` is set to `False`, do not wait for the server to stop. Otherwise, wait for
|
If `now` is set to `False`, do not wait for the server to stop. Otherwise, wait for
|
||||||
the server to stop before returning.
|
the server to stop before returning.
|
||||||
|
|
||||||
Must be a Torando coroutine.
|
Must be a Tornado coroutine.
|
||||||
"""
|
"""
|
||||||
raise NotImplementedError("Override in subclass. Must be a Tornado gen.coroutine.")
|
raise NotImplementedError("Override in subclass. Must be a Tornado gen.coroutine.")
|
||||||
|
|
||||||
@gen.coroutine
|
@gen.coroutine
|
||||||
def poll(self):
|
def poll(self):
|
||||||
"""
|
"""Check if the single-user process is running
|
||||||
Check if the single-user process is running
|
|
||||||
|
|
||||||
returns:
|
Returns:
|
||||||
None, if single-user process is running.
|
None if single-user process is running.
|
||||||
Exit status (0 if unknown), if it is not running.
|
Integer exit status (0 if unknown), if it is not running.
|
||||||
|
|
||||||
State transitions, behavior, and return response:
|
State transitions, behavior, and return response:
|
||||||
|
|
||||||
@@ -573,25 +546,20 @@ class Spawner(LoggingConfigurable):
|
|||||||
raise NotImplementedError("Override in subclass. Must be a Tornado gen.coroutine.")
|
raise NotImplementedError("Override in subclass. Must be a Tornado gen.coroutine.")
|
||||||
|
|
||||||
def add_poll_callback(self, callback, *args, **kwargs):
|
def add_poll_callback(self, callback, *args, **kwargs):
|
||||||
"""
|
"""Add a callback to fire when the single-user server stops"""
|
||||||
Add a callback to fire when the single-user server stops.
|
|
||||||
"""
|
|
||||||
if args or kwargs:
|
if args or kwargs:
|
||||||
cb = callback
|
cb = callback
|
||||||
callback = lambda : cb(*args, **kwargs)
|
callback = lambda : cb(*args, **kwargs)
|
||||||
self._callbacks.append(callback)
|
self._callbacks.append(callback)
|
||||||
|
|
||||||
def stop_polling(self):
|
def stop_polling(self):
|
||||||
"""
|
"""Stop polling for single-user server's running state"""
|
||||||
Stop polling for single-user server's running state.
|
|
||||||
"""
|
|
||||||
if self._poll_callback:
|
if self._poll_callback:
|
||||||
self._poll_callback.stop()
|
self._poll_callback.stop()
|
||||||
self._poll_callback = None
|
self._poll_callback = None
|
||||||
|
|
||||||
def start_polling(self):
|
def start_polling(self):
|
||||||
"""
|
"""Start polling periodically for single-user server's running state.
|
||||||
Start polling periodically for single-user server's running state.
|
|
||||||
|
|
||||||
Callbacks registered via `add_poll_callback` will fire if/when the server stops.
|
Callbacks registered via `add_poll_callback` will fire if/when the server stops.
|
||||||
Explicit termination via the stop method will not trigger the callbacks.
|
Explicit termination via the stop method will not trigger the callbacks.
|
||||||
@@ -612,9 +580,7 @@ class Spawner(LoggingConfigurable):
|
|||||||
|
|
||||||
@gen.coroutine
|
@gen.coroutine
|
||||||
def poll_and_notify(self):
|
def poll_and_notify(self):
|
||||||
"""
|
"""Used as a callback to periodically poll the process and notify any watchers"""
|
||||||
Used as a callback to periodically poll the process and notify any watchers
|
|
||||||
"""
|
|
||||||
status = yield self.poll()
|
status = yield self.poll()
|
||||||
if status is None:
|
if status is None:
|
||||||
# still running, nothing to do here
|
# still running, nothing to do here
|
||||||
@@ -632,9 +598,7 @@ class Spawner(LoggingConfigurable):
|
|||||||
death_interval = Float(0.1)
|
death_interval = Float(0.1)
|
||||||
@gen.coroutine
|
@gen.coroutine
|
||||||
def wait_for_death(self, timeout=10):
|
def wait_for_death(self, timeout=10):
|
||||||
"""
|
"""Wait for the single-user server to die, up to timeout seconds"""
|
||||||
Wait for the single-user server to die, up to timeout seconds
|
|
||||||
"""
|
|
||||||
for i in range(int(timeout / self.death_interval)):
|
for i in range(int(timeout / self.death_interval)):
|
||||||
status = yield self.poll()
|
status = yield self.poll()
|
||||||
if status is not None:
|
if status is not None:
|
||||||
@@ -644,8 +608,7 @@ class Spawner(LoggingConfigurable):
|
|||||||
|
|
||||||
|
|
||||||
def _try_setcwd(path):
|
def _try_setcwd(path):
|
||||||
"""
|
"""Try to set CWD to path, walking up until a valid directory is found.
|
||||||
Try to set CWD to path, walking up until a valid directory is found.
|
|
||||||
|
|
||||||
If no valid directory is found, a temp directory is created and cwd is set to that.
|
If no valid directory is found, a temp directory is created and cwd is set to that.
|
||||||
"""
|
"""
|
||||||
@@ -664,11 +627,10 @@ def _try_setcwd(path):
|
|||||||
|
|
||||||
|
|
||||||
def set_user_setuid(username):
|
def set_user_setuid(username):
|
||||||
"""
|
"""Return a preexec_fn for spawning a single-user server as a particular user.
|
||||||
Return a preexec_fn for spawning a single-user server as a particular user.
|
|
||||||
|
|
||||||
Returned preexec_fn will set uid/gid, and attempt to chdir to the target user's
|
Returned preexec_fn will set uid/gid, and attempt to chdir to the target user's
|
||||||
homedirectory.
|
home directory.
|
||||||
"""
|
"""
|
||||||
user = pwd.getpwnam(username)
|
user = pwd.getpwnam(username)
|
||||||
uid = user.pw_uid
|
uid = user.pw_uid
|
||||||
@@ -677,8 +639,9 @@ def set_user_setuid(username):
|
|||||||
gids = [ g.gr_gid for g in grp.getgrall() if username in g.gr_mem ]
|
gids = [ g.gr_gid for g in grp.getgrall() if username in g.gr_mem ]
|
||||||
|
|
||||||
def preexec():
|
def preexec():
|
||||||
"""
|
"""Set uid/gid of current process
|
||||||
Set uid/gid of current process. Executed after fork but before exec by python.
|
|
||||||
|
Executed after fork but before exec by python.
|
||||||
|
|
||||||
Also try to chdir to the user's home directory.
|
Also try to chdir to the user's home directory.
|
||||||
"""
|
"""
|
||||||
@@ -699,14 +662,13 @@ class LocalProcessSpawner(Spawner):
|
|||||||
"""
|
"""
|
||||||
A Spawner that uses `subprocess.Popen` to start single-user servers as local processes.
|
A Spawner that uses `subprocess.Popen` to start single-user servers as local processes.
|
||||||
|
|
||||||
Requires local UNIX users matching the authenticated users to exist. Does not work on
|
Requires local UNIX users matching the authenticated users to exist.
|
||||||
Windows.
|
Does not work on Windows.
|
||||||
|
|
||||||
This is the default spawner for JupyterHub.
|
This is the default spawner for JupyterHub.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
INTERRUPT_TIMEOUT = Integer(
|
INTERRUPT_TIMEOUT = Integer(10,
|
||||||
10,
|
|
||||||
help="""
|
help="""
|
||||||
Seconds to wait for single-user server process to halt after SIGINT.
|
Seconds to wait for single-user server process to halt after SIGINT.
|
||||||
|
|
||||||
@@ -714,8 +676,7 @@ class LocalProcessSpawner(Spawner):
|
|||||||
"""
|
"""
|
||||||
).tag(config=True)
|
).tag(config=True)
|
||||||
|
|
||||||
TERM_TIMEOUT = Integer(
|
TERM_TIMEOUT = Integer(5,
|
||||||
5,
|
|
||||||
help="""
|
help="""
|
||||||
Seconds to wait for single-user server process to halt after SIGTERM.
|
Seconds to wait for single-user server process to halt after SIGTERM.
|
||||||
|
|
||||||
@@ -732,16 +693,14 @@ class LocalProcessSpawner(Spawner):
|
|||||||
"""
|
"""
|
||||||
).tag(config=True)
|
).tag(config=True)
|
||||||
|
|
||||||
proc = Instance(
|
proc = Instance(Popen,
|
||||||
Popen,
|
|
||||||
allow_none=True,
|
allow_none=True,
|
||||||
help="""
|
help="""
|
||||||
The process representing the single-user server process spawned for current user.
|
The process representing the single-user server process spawned for current user.
|
||||||
|
|
||||||
Is None if no process has been spawned yet.
|
Is None if no process has been spawned yet.
|
||||||
""")
|
""")
|
||||||
pid = Integer(
|
pid = Integer(0,
|
||||||
0,
|
|
||||||
help="""
|
help="""
|
||||||
The process id (pid) of the single-user server process spawned for current user.
|
The process id (pid) of the single-user server process spawned for current user.
|
||||||
"""
|
"""
|
||||||
@@ -749,27 +708,25 @@ class LocalProcessSpawner(Spawner):
|
|||||||
|
|
||||||
def make_preexec_fn(self, name):
|
def make_preexec_fn(self, name):
|
||||||
"""
|
"""
|
||||||
Return a function that can be used to set the userid of the spawned process to user with name `name`
|
Return a function that can be used to set the user id of the spawned process to user with name `name`
|
||||||
|
|
||||||
This function can be safely passed to `preexec_fn` of `Popen`
|
This function can be safely passed to `preexec_fn` of `Popen`
|
||||||
"""
|
"""
|
||||||
return set_user_setuid(name)
|
return set_user_setuid(name)
|
||||||
|
|
||||||
def load_state(self, state):
|
def load_state(self, state):
|
||||||
"""
|
"""Restore state about spawned single-user server after a hub restart.
|
||||||
Restore state about spawned single-user server after a hub restart.
|
|
||||||
|
|
||||||
We currently only store/restore the process id.
|
Local processes only need the process id.
|
||||||
"""
|
"""
|
||||||
super(LocalProcessSpawner, self).load_state(state)
|
super(LocalProcessSpawner, self).load_state(state)
|
||||||
if 'pid' in state:
|
if 'pid' in state:
|
||||||
self.pid = state['pid']
|
self.pid = state['pid']
|
||||||
|
|
||||||
def get_state(self):
|
def get_state(self):
|
||||||
"""
|
"""Save state that is needed to restore this spawner instance after a hub restore.
|
||||||
Save state that is needed to restore this spawner instance after a hub restore.
|
|
||||||
|
|
||||||
We currently only store/restore the process id.
|
Local processes only need the process id.
|
||||||
"""
|
"""
|
||||||
state = super(LocalProcessSpawner, self).get_state()
|
state = super(LocalProcessSpawner, self).get_state()
|
||||||
if self.pid:
|
if self.pid:
|
||||||
@@ -777,16 +734,12 @@ class LocalProcessSpawner(Spawner):
|
|||||||
return state
|
return state
|
||||||
|
|
||||||
def clear_state(self):
|
def clear_state(self):
|
||||||
"""
|
"""Clear stored state about this spawner (pid)"""
|
||||||
Clear stored state about this spawner.
|
|
||||||
"""
|
|
||||||
super(LocalProcessSpawner, self).clear_state()
|
super(LocalProcessSpawner, self).clear_state()
|
||||||
self.pid = 0
|
self.pid = 0
|
||||||
|
|
||||||
def user_env(self, env):
|
def user_env(self, env):
|
||||||
"""
|
"""Augment environment of spawned process with user specific env variables."""
|
||||||
Augment environment of spawned process with user specific env variables.
|
|
||||||
"""
|
|
||||||
env['USER'] = self.user.name
|
env['USER'] = self.user.name
|
||||||
home = pwd.getpwnam(self.user.name).pw_dir
|
home = pwd.getpwnam(self.user.name).pw_dir
|
||||||
shell = pwd.getpwnam(self.user.name).pw_shell
|
shell = pwd.getpwnam(self.user.name).pw_shell
|
||||||
@@ -799,18 +752,14 @@ class LocalProcessSpawner(Spawner):
|
|||||||
return env
|
return env
|
||||||
|
|
||||||
def get_env(self):
|
def get_env(self):
|
||||||
"""
|
"""Get the complete set of environment variables to be set in the spawned process."""
|
||||||
Get the complete set of environment variables to be set in the spawned process.
|
|
||||||
"""
|
|
||||||
env = super().get_env()
|
env = super().get_env()
|
||||||
env = self.user_env(env)
|
env = self.user_env(env)
|
||||||
return env
|
return env
|
||||||
|
|
||||||
@gen.coroutine
|
@gen.coroutine
|
||||||
def start(self):
|
def start(self):
|
||||||
"""
|
"""Start the single-user server."""
|
||||||
Start the single-user server.
|
|
||||||
"""
|
|
||||||
self.port = random_port()
|
self.port = random_port()
|
||||||
cmd = []
|
cmd = []
|
||||||
env = self.get_env()
|
env = self.get_env()
|
||||||
@@ -847,8 +796,7 @@ class LocalProcessSpawner(Spawner):
|
|||||||
|
|
||||||
@gen.coroutine
|
@gen.coroutine
|
||||||
def poll(self):
|
def poll(self):
|
||||||
"""
|
"""Poll the spawned process to see if it is still running.
|
||||||
Poll the spawned process to see if it is still running.
|
|
||||||
|
|
||||||
If the process is still running, we return None. If it is not running,
|
If the process is still running, we return None. If it is not running,
|
||||||
we return the exit code of the process if we have access to it, or 0 otherwise.
|
we return the exit code of the process if we have access to it, or 0 otherwise.
|
||||||
@@ -879,12 +827,11 @@ class LocalProcessSpawner(Spawner):
|
|||||||
|
|
||||||
@gen.coroutine
|
@gen.coroutine
|
||||||
def _signal(self, sig):
|
def _signal(self, sig):
|
||||||
"""
|
"""Send given signal to a single-user server's process.
|
||||||
Send given signal to a single-user server's process.
|
|
||||||
|
|
||||||
Returns True if the process still exists, False otherwise.
|
Returns True if the process still exists, False otherwise.
|
||||||
|
|
||||||
The hub process is assumed to be root and hence have enough privilages to do this.
|
The hub process is assumed to have enough privileges to do this (e.g. root).
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
os.kill(self.pid, sig)
|
os.kill(self.pid, sig)
|
||||||
@@ -897,10 +844,10 @@ class LocalProcessSpawner(Spawner):
|
|||||||
|
|
||||||
@gen.coroutine
|
@gen.coroutine
|
||||||
def stop(self, now=False):
|
def stop(self, now=False):
|
||||||
"""
|
"""Stop the single-user server process for the current user.
|
||||||
Stop the single-user server process for the current user.
|
|
||||||
|
|
||||||
If `now` is set to True, do not wait for the process to die. Otherwise, it'll wait.
|
If `now` is set to True, do not wait for the process to die.
|
||||||
|
Otherwise, it'll wait.
|
||||||
"""
|
"""
|
||||||
if not now:
|
if not now:
|
||||||
status = yield self.poll()
|
status = yield self.poll()
|
||||||
|
Reference in New Issue
Block a user