Dynamically set authenticator properties from YAML

We don't wanna explicitly map keys from the YAML to traitlet
config for the authentication - that's a lot of busywork for no
gain. We instead switch to using snake_case everywhere, and
dynamically set traitlet config from YAML config!
This commit is contained in:
yuvipanda
2018-07-15 13:40:17 -07:00
parent ba7545769f
commit 9bf4a64826
2 changed files with 37 additions and 23 deletions

View File

@@ -7,10 +7,6 @@ be called many times per lifetime of a jupyterhub.
Traitlets that modify the startup of JupyterHub should not be here. Traitlets that modify the startup of JupyterHub should not be here.
FIXME: A strong feeling that JSON Schema should be involved somehow. FIXME: A strong feeling that JSON Schema should be involved somehow.
""" """
import copy
import os
import yaml
# Default configuration for tljh # Default configuration for tljh
# User provided config is merged into this # User provided config is merged into this
default = { default = {
@@ -18,7 +14,7 @@ default = {
'type': 'firstuse', 'type': 'firstuse',
'dummy': {}, 'dummy': {},
'firstuse': { 'firstuse': {
'createUsers': False 'create_users': False
} }
}, },
'users': { 'users': {
@@ -30,20 +26,18 @@ default = {
'memory': '1G', 'memory': '1G',
'cpu': None 'cpu': None
}, },
'userEnvironment': { 'user_environment': {
'defaultApp': 'classic' 'default_app': 'classic'
} }
} }
def apply_yaml_config(path, c): def apply_config(config_overrides, c):
if os.path.exists(path): """
with open(path) as f: Merge config_overrides with config defaults & apply to JupyterHub config c
# FIXME: Figure out correct order of merging here """
tljh_config = _merge_dictionaries(dict(default), yaml.safe_load(f)) tljh_config = _merge_dictionaries(dict(default), config_overrides)
else:
tljh_config = copy.deepcopy(default)
update_auth(c, tljh_config) update_auth(c, tljh_config)
update_userlists(c, tljh_config) update_userlists(c, tljh_config)
@@ -52,21 +46,33 @@ def apply_yaml_config(path, c):
update_user_account_config(c, tljh_config) update_user_account_config(c, tljh_config)
def set_if_not_none(parent, key, value):
"""
Set attribute 'key' on parent if value is not None
"""
if value is not None:
setattr(parent, key, value)
def update_auth(c, config): def update_auth(c, config):
""" """
Set auth related configuration from YAML config file Set auth related configuration from YAML config file
Use auth.type to determine authenticator to use. All parameters
in the config under auth.{auth.type} will be passed straight to the
authenticators themselves.
""" """
auth = config.get('auth') auth = config.get('auth')
if auth['type'] == 'dummy': if auth['type'] == 'dummy':
c.JupyterHub.authenticator_class = 'dummyauthenticator.DummyAuthenticator' c.JupyterHub.authenticator_class = 'dummyauthenticator.DummyAuthenticator'
password = auth['dummy'].get('password') authenticator_parent = c.DummyAuthenticator
if password is not None:
c.DummyAuthenticator.password = password
return
elif auth['type'] == 'firstuse': elif auth['type'] == 'firstuse':
c.JupyterHub.authenticator_class = 'firstuseauthenticator.FirstUseAuthenticator' c.JupyterHub.authenticator_class = 'firstuseauthenticator.FirstUseAuthenticator'
c.FirstUseAuthenticator.create_users = auth['firstuse']['createUsers'] authenticator_parent = c.FirstUseAuthenticator
for k, v in auth[auth['type']].items():
set_if_not_none(authenticator_parent, k, v)
def update_userlists(c, config): def update_userlists(c, config):
@@ -94,12 +100,12 @@ def update_user_environment(c, config):
""" """
Set user environment configuration Set user environment configuration
""" """
user_env = config['userEnvironment'] user_env = config['user_environment']
# Set default application users are launched into # Set default application users are launched into
if user_env['defaultApp'] == 'jupyterlab': if user_env['default_app'] == 'jupyterlab':
c.Spawner.default_url = '/lab' c.Spawner.default_url = '/lab'
elif user_env['defaultApp'] == 'nteract': elif user_env['default_app'] == 'nteract':
c.Spawner.default_url = '/nteract' c.Spawner.default_url = '/nteract'

View File

@@ -4,6 +4,8 @@ JupyterHub config for the littlest jupyterhub.
import os import os
from systemdspawner import SystemdSpawner from systemdspawner import SystemdSpawner
from tljh import user, configurer from tljh import user, configurer
import yaml
import copy
INSTALL_PREFIX = os.environ.get('TLJH_INSTALL_PREFIX') INSTALL_PREFIX = os.environ.get('TLJH_INSTALL_PREFIX')
USER_ENV_PREFIX = os.path.join(INSTALL_PREFIX, 'user') USER_ENV_PREFIX = os.path.join(INSTALL_PREFIX, 'user')
@@ -40,4 +42,10 @@ c.SystemdSpawner.default_shell = '/bin/bash'
# Drop the '-singleuser' suffix present in the default template # Drop the '-singleuser' suffix present in the default template
c.SystemdSpawner.unit_name_template = 'jupyter-{USERNAME}' c.SystemdSpawner.unit_name_template = 'jupyter-{USERNAME}'
configurer.apply_yaml_config(os.path.join(INSTALL_PREFIX, 'config.yaml'), c) config_overrides_path = os.path.join(INSTALL_PREFIX, 'config.yaml')
if os.path.exists(config_overrides_path):
with open(config_overrides_path) as f:
config_overrides = yaml.safe_load(f)
else:
config_overrides = {}
configurer.apply_config(config_overrides, c)