From ec650ce3c1939d539cc7ce470b5e759a5fb46a8f Mon Sep 17 00:00:00 2001 From: GeorgianaElena Date: Fri, 29 May 2020 17:59:20 +0300 Subject: [PATCH 01/17] Allow extra traefik config --- tljh/traefik.py | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/tljh/traefik.py b/tljh/traefik.py index 3595778..4799668 100644 --- a/tljh/traefik.py +++ b/tljh/traefik.py @@ -1,12 +1,15 @@ """Traefik installation and setup""" import hashlib import os +from glob import glob from jinja2 import Template from passlib.apache import HtpasswdFile import backoff import requests +import toml +from .config import CONFIG_DIR from tljh.configurer import load_config # FIXME: support more than one platform here @@ -18,6 +21,7 @@ checksums = { "linux-amd64": "3c2d153d80890b6fc8875af9f8ced32c4d684e1eb5a46d9815337cb343dfd92e" } +traefik_extra_config_dir = "traefik_config.d" def checksum_file(path): """Compute the sha256 checksum of a path""" @@ -78,6 +82,10 @@ def compute_basic_auth(username, password): hashed_password = str(ht.to_string()).split(":")[1][:-3] return username + ":" + hashed_password +def load_extra_config(std_toml): + extra_configs = sorted(glob(os.path.join(CONFIG_DIR, traefik_extra_config_dir, '*.py'))) + config = toml.load(extra_configs + [std_toml]) + return config def ensure_traefik_config(state_dir): """Render the traefik.toml config file""" @@ -103,9 +111,18 @@ def ensure_traefik_config(state_dir): letsencrypt["domains"] and not letsencrypt["email"] ): raise ValueError("Both email and domains must be set for letsencrypt") + + # Ensure extra config dir exists and is private + for path in [CONFIG_DIR, os.path.join(CONFIG_DIR, traefik_extra_config_dir)]: + os.makedirs(path, mode=0o700, exist_ok=True) + + traefik_toml = load_extra_config(new_toml) + + print(f"Writing traefik config {traefik_toml}...") + with open(os.path.join(state_dir, "traefik.toml"), "w") as f: os.fchmod(f.fileno(), 0o600) - f.write(new_toml) + f.write(traefik_toml) with open(os.path.join(state_dir, "rules.toml"), "w") as f: os.fchmod(f.fileno(), 0o600) From a2ccaef5286ebc6a5a95b4e44f0b857c773a4e0f Mon Sep 17 00:00:00 2001 From: GeorgianaElena Date: Fri, 29 May 2020 18:30:58 +0300 Subject: [PATCH 02/17] Use dump --- tljh/traefik.py | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/tljh/traefik.py b/tljh/traefik.py index 4799668..9983bab 100644 --- a/tljh/traefik.py +++ b/tljh/traefik.py @@ -116,13 +116,16 @@ def ensure_traefik_config(state_dir): for path in [CONFIG_DIR, os.path.join(CONFIG_DIR, traefik_extra_config_dir)]: os.makedirs(path, mode=0o700, exist_ok=True) - traefik_toml = load_extra_config(new_toml) - - print(f"Writing traefik config {traefik_toml}...") - with open(os.path.join(state_dir, "traefik.toml"), "w") as f: os.fchmod(f.fileno(), 0o600) - f.write(traefik_toml) + f.write(new_toml) + + traefik_toml = load_extra_config(os.path.join(state_dir, "traefik.toml")) + + print(f"Writing traefik config {traefik_toml}...") + with open(os.path.join(state_dir, "traefik.toml"), "w") as f: + os.fchmod(f.fileno(), 0o600) + toml.dump(traefik_toml, f) with open(os.path.join(state_dir, "rules.toml"), "w") as f: os.fchmod(f.fileno(), 0o600) From bb4614051bb3e1401919ef522c7fbea9c6f17722 Mon Sep 17 00:00:00 2001 From: GeorgianaElena Date: Tue, 2 Jun 2020 11:38:32 +0300 Subject: [PATCH 03/17] Refactor --- tljh/traefik.py | 26 +++++++++++++++----------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/tljh/traefik.py b/tljh/traefik.py index 9983bab..cc05cd1 100644 --- a/tljh/traefik.py +++ b/tljh/traefik.py @@ -21,8 +21,6 @@ checksums = { "linux-amd64": "3c2d153d80890b6fc8875af9f8ced32c4d684e1eb5a46d9815337cb343dfd92e" } -traefik_extra_config_dir = "traefik_config.d" - def checksum_file(path): """Compute the sha256 checksum of a path""" hasher = hashlib.sha256() @@ -82,13 +80,17 @@ def compute_basic_auth(username, password): hashed_password = str(ht.to_string()).split(":")[1][:-3] return username + ":" + hashed_password -def load_extra_config(std_toml): - extra_configs = sorted(glob(os.path.join(CONFIG_DIR, traefik_extra_config_dir, '*.py'))) - config = toml.load(extra_configs + [std_toml]) +def load_extra_config(std_toml, extra_config_dir): + extra_configs = sorted(glob(os.path.join(extra_config_dir, '*.py'))) + # Load the toml list of files into dicts and merge them + config = toml.load([std_toml] + extra_configs) return config def ensure_traefik_config(state_dir): """Render the traefik.toml config file""" + traefik_std_config_file = os.path.join(state_dir, "traefik.toml") + traefik_extra_config_dir = os.path.join(CONFIG_DIR, "traefik_config.d") + config = load_config() config['traefik_api']['basic_auth'] = compute_basic_auth( config['traefik_api']['username'], @@ -112,18 +114,20 @@ def ensure_traefik_config(state_dir): ): raise ValueError("Both email and domains must be set for letsencrypt") - # Ensure extra config dir exists and is private - for path in [CONFIG_DIR, os.path.join(CONFIG_DIR, traefik_extra_config_dir)]: - os.makedirs(path, mode=0o700, exist_ok=True) + # Ensure extra config dir exists and is private + os.makedirs(traefik_extra_config_dir, mode=0o700, exist_ok=True) - with open(os.path.join(state_dir, "traefik.toml"), "w") as f: + # Write standard config to file + with open(traefik_std_config_file, "w") as f: os.fchmod(f.fileno(), 0o600) f.write(new_toml) - traefik_toml = load_extra_config(os.path.join(state_dir, "traefik.toml")) + # Load standard config file and extra config files into a dict + traefik_toml = load_extra_config(traefik_std_config_file, traefik_extra_config_dir) + # Dump the dict into a toml-formatted string and write it to file print(f"Writing traefik config {traefik_toml}...") - with open(os.path.join(state_dir, "traefik.toml"), "w") as f: + with open(traefik_std_config_file, "w") as f: os.fchmod(f.fileno(), 0o600) toml.dump(traefik_toml, f) From 54bc95668b4a4d2f7c111bb58dc3d68946b77115 Mon Sep 17 00:00:00 2001 From: GeorgianaElena Date: Tue, 2 Jun 2020 18:20:28 +0300 Subject: [PATCH 04/17] Test Traefik extra config --- tests/conftest.py | 1 + tests/test_traefik.py | 32 +++++++++++++++++++++++++++++++- 2 files changed, 32 insertions(+), 1 deletion(-) diff --git a/tests/conftest.py b/tests/conftest.py index 77262e1..7d4ec37 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -22,4 +22,5 @@ def tljh_dir(tmpdir): assert tljh.config.INSTALL_PREFIX == tljh_dir os.makedirs(tljh.config.STATE_DIR) os.makedirs(tljh.config.CONFIG_DIR) + os.makedirs(os.path.join(tljh.config.CONFIG_DIR, "traefik_config.d")) yield tljh_dir diff --git a/tests/test_traefik.py b/tests/test_traefik.py index e15be9c..863b414 100644 --- a/tests/test_traefik.py +++ b/tests/test_traefik.py @@ -2,7 +2,7 @@ import os from unittest import mock -import pytoml as toml +import toml from tljh import config from tljh import traefik @@ -124,3 +124,33 @@ def test_manual_ssl_config(tljh_dir): "whiteList": {"sourceRange": ["127.0.0.1"]} }, } + +def test_extra_config(tmpdir, tljh_dir): + extra_config_dir = os.path.join(tljh_dir, config.CONFIG_DIR, "traefik_config.d") + + state_dir = tmpdir.mkdir("state") + + extra_config = { + # modify existing value + "dashboard": True, + # modify existing value with multiple levels + "entryPoints": { + "auth_api": { + "address": "127.0.0.1:9999" + } + }, + # add new setting + "checkNewVersion": False + } + + with open(os.path.join(extra_config_dir, "extra.py"), "w+") as extra_config_file: + toml.dump(extra_config, extra_config_file) + + # This merges the 2 configs + traefik.ensure_traefik_config(str(state_dir)) + traefik_toml = os.path.join(state_dir, "traefik.toml") + + # Read back the merged config + toml_cfg = toml.load(traefik_toml) + + assert extra_config.items() <= toml_cfg.items() From b290ba2782fb2fb44f8b8bacc8edabb7723cbe17 Mon Sep 17 00:00:00 2001 From: GeorgianaElena Date: Tue, 2 Jun 2020 18:27:56 +0300 Subject: [PATCH 05/17] Remove pytoml (and use toml instead) --- dev-requirements.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/dev-requirements.txt b/dev-requirements.txt index 6296fdd..0c50f19 100644 --- a/dev-requirements.txt +++ b/dev-requirements.txt @@ -2,4 +2,3 @@ pytest pytest-cov pytest-mock codecov -pytoml \ No newline at end of file From 8c14372356a562c5b33a402479055afd1e84babf Mon Sep 17 00:00:00 2001 From: GeorgianaElena Date: Tue, 2 Jun 2020 18:29:12 +0300 Subject: [PATCH 06/17] Remove debug print --- tljh/traefik.py | 1 - 1 file changed, 1 deletion(-) diff --git a/tljh/traefik.py b/tljh/traefik.py index cc05cd1..81342b7 100644 --- a/tljh/traefik.py +++ b/tljh/traefik.py @@ -126,7 +126,6 @@ def ensure_traefik_config(state_dir): traefik_toml = load_extra_config(traefik_std_config_file, traefik_extra_config_dir) # Dump the dict into a toml-formatted string and write it to file - print(f"Writing traefik config {traefik_toml}...") with open(traefik_std_config_file, "w") as f: os.fchmod(f.fileno(), 0o600) toml.dump(traefik_toml, f) From acc1eea251627fd559c53af945420dcc04ba8700 Mon Sep 17 00:00:00 2001 From: GeorgianaElena Date: Tue, 2 Jun 2020 19:09:19 +0300 Subject: [PATCH 07/17] Traefik config files are .toml --- tests/test_traefik.py | 2 +- tljh/traefik.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/test_traefik.py b/tests/test_traefik.py index 863b414..ebe4b45 100644 --- a/tests/test_traefik.py +++ b/tests/test_traefik.py @@ -143,7 +143,7 @@ def test_extra_config(tmpdir, tljh_dir): "checkNewVersion": False } - with open(os.path.join(extra_config_dir, "extra.py"), "w+") as extra_config_file: + with open(os.path.join(extra_config_dir, "extra.toml"), "w+") as extra_config_file: toml.dump(extra_config, extra_config_file) # This merges the 2 configs diff --git a/tljh/traefik.py b/tljh/traefik.py index 81342b7..1dd2312 100644 --- a/tljh/traefik.py +++ b/tljh/traefik.py @@ -81,7 +81,7 @@ def compute_basic_auth(username, password): return username + ":" + hashed_password def load_extra_config(std_toml, extra_config_dir): - extra_configs = sorted(glob(os.path.join(extra_config_dir, '*.py'))) + extra_configs = sorted(glob(os.path.join(extra_config_dir, '*.toml'))) # Load the toml list of files into dicts and merge them config = toml.load([std_toml] + extra_configs) return config From 6409e29fa8bc1602f3f68b05e2cbd95d6a58890f Mon Sep 17 00:00:00 2001 From: GeorgianaElena Date: Fri, 5 Jun 2020 15:03:02 +0300 Subject: [PATCH 08/17] Document traefik config escape hatch --- docs/topic/escape-hatch.rst | 74 ++++++++++++++++++++++++++++++------- 1 file changed, 61 insertions(+), 13 deletions(-) diff --git a/docs/topic/escape-hatch.rst b/docs/topic/escape-hatch.rst index d6beea0..608003d 100644 --- a/docs/topic/escape-hatch.rst +++ b/docs/topic/escape-hatch.rst @@ -1,17 +1,65 @@ .. _topic/escape-hatch: -======================================== -Custom ``jupyterhub_config.py`` snippets -======================================== -Sometimes you need to customize TLJH in ways that are not officially supported. -We provide an easy escape hatch for those cases with a ``jupyterhub_conf.d`` -directory that lets you load multiple ``jupyterhub_config.py`` snippets for -your configuration. You need to create the directory when you use it for -the first time. +============================= +Custom configuration snippets +============================= -Any files in ``/opt/tljh/config/jupyterhub_config.d`` that end in ``.py`` will be -loaded in alphabetical order as python files to provide configuration for -JupyterHub. Any config that can go in a regular ``jupyterhub_config.py`` -file is valid in these files. They will be loaded *after* any of the config -options specified with ``tljh-config`` are loaded. +The two main TLJH components are **JupyterHub** and **Traefik**. + +* JupyterHub takes its configuration from the ``jupyterhub_config.py`` file. +* Traefik takes its configuration from the ``traefik.toml`` file. + +These files are created by TLJH during installation and can be edited by the +user only through ``tljh-config``, so any direct modification to these files, +will be overwritten by TLJH when the components are reloaded. + +But because sometimes TLJH needs to be customized in ways that are not officially +supported, an escape hatch has been introduced to allow easily extending the +configuration. Please follow the sections below for how to extend JupyterHub's +and Traefik's configuration outside of ``tljh-config`` scope. + +Extending ``jupyterhub_config.py`` +================================== + +The ``jupyterhub_config.d`` directory lets you load multiple ``jupyterhub_config.py`` +snippets for your configuration. + +* Any files in ``/opt/tljh/config/jupyterhub_config.d`` that end in ``.py`` will + be loaded in alphabetical order as python files to provide configuration for + JupyterHub. +* The configuration files can have any name, but they need to have the `.py` + extension and to respect this format. +* Any config that can go in a regular ``jupyterhub_config.py`` file is valid in + these files. +* They will be loaded *after* any of the config options specified with ``tljh-config`` + are loaded. + +Once you have created and defined your custom JupyterHub config file/s, just reload the +hub for the new configuration to take effect: + +.. code-block:: bash + + sudo tljh-config reload hub + + +Extending ``traefik.toml`` +========================== + +The ``traefik_config.d`` directory lets you load multiple ``traefik.toml`` +snippets for your configuration. + +* Any files in ``/opt/tljh/config/traefik_config.d`` that end in ``.toml`` will be + loaded in alphabetical order to provide configuration for Traefik. +* The configuration files can have any name, but they need to have the `.toml` + extension and to respect this format. +* Any config that can go in a regular ``traefik.toml`` file is valid in these files. +* They will be loaded *after* any of the config options specified with ``tljh-config`` + are loaded. + +Once you have created and defined your custom Traefik config file/s, just reload the +proxy for the new configuration to take effect: + +.. code-block:: bash + + sudo tljh-config reload proxy From 651425972f899bd3660b41527127e9ba24196ef2 Mon Sep 17 00:00:00 2001 From: GeorgianaElena Date: Fri, 5 Jun 2020 15:04:14 +0300 Subject: [PATCH 09/17] Modify loglevel --- tests/test_traefik.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_traefik.py b/tests/test_traefik.py index ebe4b45..488418f 100644 --- a/tests/test_traefik.py +++ b/tests/test_traefik.py @@ -132,7 +132,7 @@ def test_extra_config(tmpdir, tljh_dir): extra_config = { # modify existing value - "dashboard": True, + "logLevel": "ERROR", # modify existing value with multiple levels "entryPoints": { "auth_api": { From 82f6173828e5c884a8774481f8c138c9ccf969e1 Mon Sep 17 00:00:00 2001 From: GeorgianaElena Date: Mon, 8 Jun 2020 11:41:22 +0300 Subject: [PATCH 10/17] Use merge func instead for multi level dicts --- tljh/traefik.py | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/tljh/traefik.py b/tljh/traefik.py index 1dd2312..97e2a47 100644 --- a/tljh/traefik.py +++ b/tljh/traefik.py @@ -80,12 +80,14 @@ def compute_basic_auth(username, password): hashed_password = str(ht.to_string()).split(":")[1][:-3] return username + ":" + hashed_password -def load_extra_config(std_toml, extra_config_dir): + +def load_extra_config(extra_config_dir): extra_configs = sorted(glob(os.path.join(extra_config_dir, '*.toml'))) # Load the toml list of files into dicts and merge them - config = toml.load([std_toml] + extra_configs) + config = toml.load(extra_configs) return config + def ensure_traefik_config(state_dir): """Render the traefik.toml config file""" traefik_std_config_file = os.path.join(state_dir, "traefik.toml") @@ -99,7 +101,7 @@ def ensure_traefik_config(state_dir): with open(os.path.join(os.path.dirname(__file__), "traefik.toml.tpl")) as f: template = Template(f.read()) - new_toml = template.render(config) + std_config = template.render(config) https = config["https"] letsencrypt = https["letsencrypt"] tls = https["tls"] @@ -117,18 +119,17 @@ def ensure_traefik_config(state_dir): # Ensure extra config dir exists and is private os.makedirs(traefik_extra_config_dir, mode=0o700, exist_ok=True) - # Write standard config to file - with open(traefik_std_config_file, "w") as f: - os.fchmod(f.fileno(), 0o600) - f.write(new_toml) - - # Load standard config file and extra config files into a dict - traefik_toml = load_extra_config(traefik_std_config_file, traefik_extra_config_dir) + try: + # Load standard config file merge it with the extra config files into a dict + extra_config = load_extra_config(traefik_extra_config_dir) + new_toml = _merge_dictionaries(toml.loads(std_config), extra_config) + except FileNotFoundError: + new_toml = toml.loads(std_config) # Dump the dict into a toml-formatted string and write it to file with open(traefik_std_config_file, "w") as f: os.fchmod(f.fileno(), 0o600) - toml.dump(traefik_toml, f) + toml.dump(new_toml, f) with open(os.path.join(state_dir, "rules.toml"), "w") as f: os.fchmod(f.fileno(), 0o600) From f1056339cc8ee52baa91b9520954fc7237dbec83 Mon Sep 17 00:00:00 2001 From: GeorgianaElena Date: Mon, 8 Jun 2020 11:42:10 +0300 Subject: [PATCH 11/17] Add proxy integration test --- .circleci/config.yml | 4 +- integration-tests/test_proxy.py | 66 +++++++++++++++++++++++++++++---- 2 files changed, 62 insertions(+), 8 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 98fde0c..6736b3e 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -58,8 +58,10 @@ commands: .circleci/integration-test.py run-test \ --bootstrap-pip-spec "$BOOTSTRAP_PIP_SPEC" \ - basic-tests test_hub.py test_install.py test_extensions.py \ + basic-tests test_hub.py test_proxy.py \ + test_install.py test_extensions.py \ << parameters.upgrade >> + admin_tests: parameters: upgrade: diff --git a/integration-tests/test_proxy.py b/integration-tests/test_proxy.py index 1ee236f..9b37f40 100644 --- a/integration-tests/test_proxy.py +++ b/integration-tests/test_proxy.py @@ -5,7 +5,9 @@ import ssl from subprocess import check_call import time -import requests +import toml +from tornado.httpclient import HTTPClient, HTTPRequest, HTTPClientError +import pytest from tljh.config import reload_component, set_config_value, CONFIG_FILE @@ -53,14 +55,64 @@ def test_manual_https(preserve_config): # verify that our certificate was loaded by traefik assert server_cert == file_cert - for i in range(5): + for i in range(10): time.sleep(i) # verify that we can still connect to the hub - r = requests.get("https://127.0.0.1/hub/api", verify=False) - if r.status_code == 200: - break; - - r.raise_for_status() + try: + req = HTTPRequest( + "https://127.0.0.1/hub/api", method="GET", validate_cert=False + ) + resp = HTTPClient().fetch(req) + break + except Exception as e: + pass + assert resp.code == 200 # cleanup shutil.rmtree(ssl_dir) + + +def test_extra_traefik_config(): + extra_config_dir = os.path.join(CONFIG_DIR, "traefik_config.d") + os.makedirs(extra_config_dir, exist_ok=True) + + extra_config = { + "entryPoints": {"no_auth_api": {"address": "127.0.0.1:9999"}}, + "api": {"dashboard": True, "entrypoint": "no_auth_api"}, + } + + success = False + for i in range(5): + time.sleep(i) + try: + with pytest.raises(HTTPClientError, match="HTTP 401: Unauthorized"): + # The default dashboard entrypoint requires authentication, so it should fail + req = HTTPRequest("http://127.0.0.1:8099/dashboard/", method="GET") + HTTPClient().fetch(req) + success = True + break + except Exception as e: + pass + + assert success == True + + # Load the extra config + with open(os.path.join(extra_config_dir, "extra.toml"), "w+") as extra_config_file: + toml.dump(extra_config, extra_config_file) + reload_component("proxy") + + for i in range(5): + time.sleep(i) + try: + # The new dashboard entrypoint shouldn't require authentication anymore + req = HTTPRequest("http://127.0.0.1:9999/dashboard/", method="GET") + resp = HTTPClient().fetch(req) + break + except ConnectionRefusedError: + pass + # If the request didn't get through after 5 tries, this should fail + assert resp.code == 200 + + # cleanup + os.remove(os.path.join(extra_config_dir, "extra.toml")) + reload_component("proxy") From a36de0715bba890fdc11f1b2f64adbf459e0e10a Mon Sep 17 00:00:00 2001 From: GeorgianaElena Date: Mon, 8 Jun 2020 11:56:10 +0300 Subject: [PATCH 12/17] Import CONFIG_DIR --- integration-tests/test_proxy.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/integration-tests/test_proxy.py b/integration-tests/test_proxy.py index 9b37f40..fd8946c 100644 --- a/integration-tests/test_proxy.py +++ b/integration-tests/test_proxy.py @@ -9,7 +9,7 @@ import toml from tornado.httpclient import HTTPClient, HTTPRequest, HTTPClientError import pytest -from tljh.config import reload_component, set_config_value, CONFIG_FILE +from tljh.config import reload_component, set_config_value, CONFIG_FILE, CONFIG_DIR def test_manual_https(preserve_config): From fda0282151136e84252d728b6e1f5c777133a92c Mon Sep 17 00:00:00 2001 From: GeorgianaElena Date: Mon, 8 Jun 2020 12:15:42 +0300 Subject: [PATCH 13/17] Import merge dicts method --- tljh/traefik.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tljh/traefik.py b/tljh/traefik.py index 97e2a47..2cbb312 100644 --- a/tljh/traefik.py +++ b/tljh/traefik.py @@ -10,7 +10,7 @@ import requests import toml from .config import CONFIG_DIR -from tljh.configurer import load_config +from tljh.configurer import load_config, _merge_dictionaries # FIXME: support more than one platform here plat = "linux-amd64" From af6b56cf737db6c013ec5040a787880492646416 Mon Sep 17 00:00:00 2001 From: GeorgianaElena Date: Mon, 8 Jun 2020 12:36:26 +0300 Subject: [PATCH 14/17] Update unit test --- docs/topic/escape-hatch.rst | 2 ++ tests/test_traefik.py | 23 +++++++++++++++++++---- 2 files changed, 21 insertions(+), 4 deletions(-) diff --git a/docs/topic/escape-hatch.rst b/docs/topic/escape-hatch.rst index 608003d..f319516 100644 --- a/docs/topic/escape-hatch.rst +++ b/docs/topic/escape-hatch.rst @@ -63,3 +63,5 @@ proxy for the new configuration to take effect: .. code-block:: bash sudo tljh-config reload proxy + +.. warning:: This instructions might change when TLJH will switch to Traefik > 2.0 diff --git a/tests/test_traefik.py b/tests/test_traefik.py index 488418f..d22f68d 100644 --- a/tests/test_traefik.py +++ b/tests/test_traefik.py @@ -3,6 +3,7 @@ import os from unittest import mock import toml +import pytest from tljh import config from tljh import traefik @@ -127,8 +128,20 @@ def test_manual_ssl_config(tljh_dir): def test_extra_config(tmpdir, tljh_dir): extra_config_dir = os.path.join(tljh_dir, config.CONFIG_DIR, "traefik_config.d") - state_dir = tmpdir.mkdir("state") + traefik_toml = os.path.join(state_dir, "traefik.toml") + + # Generate default config + traefik.ensure_traefik_config(str(state_dir)) + + # Read the default config + toml_cfg = toml.load(traefik_toml) + + # Make sure the defaults are what we expect + assert toml_cfg["logLevel"] == "INFO" + with pytest.raises(KeyError): + toml_cfg["checkNewVersion"] + assert toml_cfg["entryPoints"]["auth_api"]["address"] == "127.0.0.1:8099" extra_config = { # modify existing value @@ -146,11 +159,13 @@ def test_extra_config(tmpdir, tljh_dir): with open(os.path.join(extra_config_dir, "extra.toml"), "w+") as extra_config_file: toml.dump(extra_config, extra_config_file) - # This merges the 2 configs + # Merge the extra config with the defaults traefik.ensure_traefik_config(str(state_dir)) - traefik_toml = os.path.join(state_dir, "traefik.toml") # Read back the merged config toml_cfg = toml.load(traefik_toml) - assert extra_config.items() <= toml_cfg.items() + # Check that the defaults were updated by the extra config + assert toml_cfg["logLevel"] == "ERROR" + assert toml_cfg["checkNewVersion"] == False + assert toml_cfg["entryPoints"]["auth_api"]["address"] == "127.0.0.1:9999" From 392fb21059803c458a9f109efbda2530cb2609f3 Mon Sep 17 00:00:00 2001 From: GeorgianaElena Date: Mon, 8 Jun 2020 21:23:12 +0300 Subject: [PATCH 15/17] Fix docs --- docs/topic/escape-hatch.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/topic/escape-hatch.rst b/docs/topic/escape-hatch.rst index f319516..f845fc8 100644 --- a/docs/topic/escape-hatch.rst +++ b/docs/topic/escape-hatch.rst @@ -11,8 +11,8 @@ The two main TLJH components are **JupyterHub** and **Traefik**. * Traefik takes its configuration from the ``traefik.toml`` file. These files are created by TLJH during installation and can be edited by the -user only through ``tljh-config``, so any direct modification to these files, -will be overwritten by TLJH when the components are reloaded. +user only through ``tljh-config``. Any direct modification to these files, +will have no effect. But because sometimes TLJH needs to be customized in ways that are not officially supported, an escape hatch has been introduced to allow easily extending the From 8162a3d6ea64e1640695f720e0144f16aaef373f Mon Sep 17 00:00:00 2001 From: Yuvi Panda Date: Tue, 9 Jun 2020 14:27:46 +0530 Subject: [PATCH 16/17] Update docs/topic/escape-hatch.rst --- docs/topic/escape-hatch.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/topic/escape-hatch.rst b/docs/topic/escape-hatch.rst index f845fc8..44ef67d 100644 --- a/docs/topic/escape-hatch.rst +++ b/docs/topic/escape-hatch.rst @@ -12,7 +12,7 @@ The two main TLJH components are **JupyterHub** and **Traefik**. These files are created by TLJH during installation and can be edited by the user only through ``tljh-config``. Any direct modification to these files, -will have no effect. +is unsupported, and will cause hard to debug issues. But because sometimes TLJH needs to be customized in ways that are not officially supported, an escape hatch has been introduced to allow easily extending the From 9736526edb46d8bf53961801a752a9eb1f1826f3 Mon Sep 17 00:00:00 2001 From: Yuvi Panda Date: Tue, 9 Jun 2020 14:27:54 +0530 Subject: [PATCH 17/17] Update docs/topic/escape-hatch.rst --- docs/topic/escape-hatch.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/topic/escape-hatch.rst b/docs/topic/escape-hatch.rst index 44ef67d..9e2649f 100644 --- a/docs/topic/escape-hatch.rst +++ b/docs/topic/escape-hatch.rst @@ -11,7 +11,7 @@ The two main TLJH components are **JupyterHub** and **Traefik**. * Traefik takes its configuration from the ``traefik.toml`` file. These files are created by TLJH during installation and can be edited by the -user only through ``tljh-config``. Any direct modification to these files, +user only through ``tljh-config``. Any direct modification to these files is unsupported, and will cause hard to debug issues. But because sometimes TLJH needs to be customized in ways that are not officially