def test_reload_proxy(tljh_dir): with mock.patch( "tljh.systemd.restart_service") as restart_service, mock.patch( "tljh.systemd.check_service_active") as check_active: config.reload_component('proxy') assert restart_service.called_with('traefik') assert check_active.called_with('traefik') assert os.path.exists(os.path.join(config.STATE_DIR, 'traefik.toml'))
def test_reload_hub(): with mock.patch( 'tljh.systemd.restart_service') as restart_service, mock.patch( 'tljh.systemd.check_service_active' ) as check_active, mock.patch( 'tljh.config.check_hub_ready') as check_ready: config.reload_component('hub') assert restart_service.called_with('jupyterhub') assert check_active.called_with('jupyterhub')
def test_manual_https(preserve_config): ssl_dir = "/etc/tljh-ssl-test" key = ssl_dir + "/ssl.key" cert = ssl_dir + "/ssl.cert" os.makedirs(ssl_dir, exist_ok=True) os.chmod(ssl_dir, 0o600) # generate key and cert check_call([ "openssl", "req", "-nodes", "-newkey", "rsa:2048", "-keyout", key, "-x509", "-days", "1", "-out", cert, "-subj", "/CN=tljh.jupyer.org", ]) set_config_value(CONFIG_FILE, "https.enabled", True) set_config_value(CONFIG_FILE, "https.tls.key", key) set_config_value(CONFIG_FILE, "https.tls.cert", cert) reload_component("proxy") for i in range(10): time.sleep(i) try: server_cert = ssl.get_server_certificate(("127.0.0.1", 443)) except Exception as e: print(e) else: break with open(cert) as f: file_cert = f.read() # verify that our certificate was loaded by traefik assert server_cert == file_cert for i in range(10): time.sleep(i) # verify that we can still connect to the hub 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")
def preserve_config(request): """Fixture to save and restore config around tests""" if os.path.exists(CONFIG_FILE): with open(CONFIG_FILE) as f: save_config = f.read() else: save_config = None try: yield finally: if save_config: with open(CONFIG_FILE, "w") as f: f.write(save_config) elif os.path.exists(CONFIG_FILE): os.remove(CONFIG_FILE) reload_component("hub") reload_component("proxy")
def preserve_config(request): """Fixture to save and restore config around tests""" # Import TLJH only when needed. This lets us run tests in places # where TLJH is not installed - particularly, the 'distro check' test. from tljh.config import CONFIG_FILE, reload_component if os.path.exists(CONFIG_FILE): with open(CONFIG_FILE) as f: save_config = f.read() else: save_config = None try: yield finally: if save_config: with open(CONFIG_FILE, "w") as f: f.write(save_config) elif os.path.exists(CONFIG_FILE): os.remove(CONFIG_FILE) reload_component("hub") reload_component("proxy")
def test_extra_traefik_config(): extra_static_config_dir = os.path.join(CONFIG_DIR, "traefik_config.d") os.makedirs(extra_static_config_dir, exist_ok=True) dynamic_config_dir = os.path.join(STATE_DIR, "rules") os.makedirs(dynamic_config_dir, exist_ok=True) extra_static_config = { "entryPoints": { "no_auth_api": { "address": "127.0.0.1:9999" } }, "api": { "dashboard": True, "entrypoint": "no_auth_api" }, } extra_dynamic_config = { "frontends": { "test": { "backend": "test", "routes": { "rule1": { "rule": "PathPrefixStrip: /the/hub/runs/here/too" } }, } }, "backends": { # redirect to hub "test": { "servers": { "server1": { "url": "http://127.0.0.1:15001" } } } }, } 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 # write the extra static config with open(os.path.join(extra_static_config_dir, "extra.toml"), "w+") as extra_config_file: toml.dump(extra_static_config, extra_config_file) # write the extra dynamic config with open(os.path.join(dynamic_config_dir, "extra_rules.toml"), "w+") as extra_config_file: toml.dump(extra_dynamic_config, extra_config_file) # load the extra config reload_component("proxy") # the new dashboard entrypoint shouldn't require authentication anymore resp = send_request(url="http://127.0.0.1:9999/dashboard/", max_sleep=5) assert resp.code == 200 # test extra dynamic config resp = send_request(url="http://127.0.0.1/the/hub/runs/here/too", max_sleep=5) assert resp.code == 200 assert resp.effective_url == "http://127.0.0.1/hub/login" # cleanup os.remove(os.path.join(extra_static_config_dir, "extra.toml")) os.remove(os.path.join(dynamic_config_dir, "extra_rules.toml")) open(os.path.join(STATE_DIR, "traefik.toml"), "w").close()