mirror of
https://github.com/jupyterhub/the-littlest-jupyterhub.git
synced 2025-12-18 21:54:05 +08:00
126 lines
3.3 KiB
Python
126 lines
3.3 KiB
Python
"""
|
|
Parse YAML config file & update JupyterHub config.
|
|
|
|
Config should never append or mutate, only set. Functions here could
|
|
be called many times per lifetime of a jupyterhub.
|
|
|
|
Traitlets that modify the startup of JupyterHub should not be here.
|
|
FIXME: A strong feeling that JSON Schema should be involved somehow.
|
|
"""
|
|
import copy
|
|
import os
|
|
import yaml
|
|
|
|
# Default configuration for tljh
|
|
# User provided config is merged into this
|
|
default = {
|
|
'auth': {
|
|
'type': 'firstuse',
|
|
'dummy': {},
|
|
'firstuse': {
|
|
'createUsers': False
|
|
}
|
|
},
|
|
'users': {
|
|
'allowed': [],
|
|
'banned': [],
|
|
'admin': []
|
|
},
|
|
'limits': {
|
|
'memory': '1G',
|
|
'cpu': None
|
|
},
|
|
'userEnvironment': {
|
|
'defaultApp': 'classic'
|
|
}
|
|
|
|
}
|
|
|
|
|
|
def apply_yaml_config(path, c):
|
|
if os.path.exists(path):
|
|
with open(path) as f:
|
|
# FIXME: Figure out correct order of merging here
|
|
tljh_config = _merge_dictionaries(dict(default), yaml.safe_load(f))
|
|
else:
|
|
tljh_config = copy.deepcopy(default)
|
|
|
|
update_auth(c, tljh_config)
|
|
update_userlists(c, tljh_config)
|
|
update_limits(c, tljh_config)
|
|
update_user_environment(c, tljh_config)
|
|
|
|
|
|
def update_auth(c, config):
|
|
"""
|
|
Set auth related configuration from YAML config file
|
|
"""
|
|
auth = config.get('auth')
|
|
|
|
if auth['type'] == 'dummy':
|
|
c.JupyterHub.authenticator_class = 'dummyauthenticator.DummyAuthenticator'
|
|
password = auth['dummy'].get('password')
|
|
if password is not None:
|
|
c.DummyAuthenticator.password = password
|
|
return
|
|
elif auth['type'] == 'firstuse':
|
|
c.JupyterHub.authenticator_class = 'firstuseauthenticator.FirstUseAuthenticator'
|
|
c.FirstUseAuthenticator.create_users = auth['firstuse']['createUsers']
|
|
|
|
|
|
def update_userlists(c, config):
|
|
"""
|
|
Set user whitelists & admin lists
|
|
"""
|
|
users = config['users']
|
|
|
|
c.Authenticator.whitelist = set(users['allowed'])
|
|
c.Authenticator.blacklist = set(users['banned'])
|
|
c.Authenticator.admin_users = set(users['admin'])
|
|
|
|
|
|
def update_limits(c, config):
|
|
"""
|
|
Set user server limits
|
|
"""
|
|
limits = config['limits']
|
|
|
|
c.SystemdSpawner.mem_limit = limits['memory']
|
|
c.SystemdSpawner.cpu_limit = limits['cpu']
|
|
|
|
|
|
def update_user_environment(c, config):
|
|
"""
|
|
Set user environment configuration
|
|
"""
|
|
user_env = config['userEnvironment']
|
|
|
|
# Set default application users are launched into
|
|
if user_env['defaultApp'] == 'jupyterlab':
|
|
c.Spawner.default_url = '/lab'
|
|
elif user_env['defaultApp'] == 'nteract':
|
|
c.Spawner.default_url = '/nteract'
|
|
|
|
|
|
def _merge_dictionaries(a, b, path=None, update=True):
|
|
"""
|
|
Merge two dictionaries recursively.
|
|
|
|
From https://stackoverflow.com/a/7205107
|
|
"""
|
|
if path is None:
|
|
path = []
|
|
for key in b:
|
|
if key in a:
|
|
if isinstance(a[key], dict) and isinstance(b[key], dict):
|
|
_merge_dictionaries(a[key], b[key], path + [str(key)])
|
|
elif a[key] == b[key]:
|
|
pass # same leaf value
|
|
elif update:
|
|
a[key] = b[key]
|
|
else:
|
|
raise Exception('Conflict at %s' % '.'.join(path + [str(key)]))
|
|
else:
|
|
a[key] = b[key]
|
|
return a
|