Files
the-littlest-jupyterhub/integration-tests/test_proxy.py

182 lines
5.2 KiB
Python
Raw Normal View History

"""tests for the proxy"""
import os
import shutil
import ssl
import time
from subprocess import check_call
2020-06-08 11:42:10 +03:00
import pytest
import toml
from tornado.httpclient import HTTPClient, HTTPClientError, HTTPRequest
2020-06-18 17:29:50 +03:00
from tljh.config import (
CONFIG_DIR,
CONFIG_FILE,
2020-06-18 17:29:50 +03:00
STATE_DIR,
reload_component,
set_config_value,
2020-06-18 17:29:50 +03:00
)
2020-06-20 02:05:53 +03:00
def send_request(url, max_sleep, validate_cert=True, username=None, password=None):
for i in range(max_sleep):
try:
req = HTTPRequest(
url,
method="GET",
auth_username=username,
auth_password=password,
validate_cert=validate_cert,
follow_redirects=True,
max_redirects=15,
)
return HTTPClient().fetch(req)
2020-06-20 02:05:53 +03:00
except Exception as e:
if i + 1 == max_sleep:
raise
2020-06-20 02:05:53 +03:00
print(e)
time.sleep(i)
2020-06-20 02:05:53 +03:00
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
2020-06-20 02:05:53 +03:00
# verify that we can still connect to the hub
resp = send_request(
url="https://127.0.0.1/hub/api", max_sleep=10, validate_cert=False
)
2020-06-08 11:42:10 +03:00
assert resp.code == 200
# cleanup
shutil.rmtree(ssl_dir)
2020-06-20 02:05:53 +03:00
set_config_value(CONFIG_FILE, "https.enabled", False)
reload_component("proxy")
2020-06-08 11:42:10 +03:00
2020-06-21 13:55:52 +03:00
def test_extra_traefik_config():
2020-06-20 02:05:53 +03:00
extra_static_config_dir = os.path.join(CONFIG_DIR, "traefik_config.d")
os.makedirs(extra_static_config_dir, exist_ok=True)
2020-06-08 11:42:10 +03:00
2020-06-21 13:55:52 +03:00
dynamic_config_dir = os.path.join(STATE_DIR, "rules")
os.makedirs(dynamic_config_dir, exist_ok=True)
2020-06-20 02:05:53 +03:00
extra_static_config = {
"entryPoints": {"alsoHub": {"address": "127.0.0.1:9999"}},
2020-06-08 11:42:10 +03:00
}
2020-06-21 13:55:52 +03:00
extra_dynamic_config = {
"http": {
"middlewares": {
"testHubStripPrefix": {
"stripPrefix": {"prefixes": ["/the/hub/runs/here/too"]}
}
},
"routers": {
"test1": {
"rule": "PathPrefix(`/hub`)",
"entryPoints": ["alsoHub"],
"service": "test",
2020-06-21 13:55:52 +03:00
},
"test2": {
"rule": "PathPrefix(`/the/hub/runs/here/too`)",
"middlewares": ["testHubStripPrefix"],
"entryPoints": ["http"],
"service": "test",
},
},
"services": {
"test": {
"loadBalancer": {
# forward requests to the hub
"servers": [{"url": "http://127.0.0.1:15001"}]
}
}
},
2020-06-21 13:55:52 +03:00
},
}
2020-06-08 11:42:10 +03:00
success = False
for i in range(5):
try:
with pytest.raises(HTTPClientError, match="HTTP 401: Unauthorized"):
# The default api entrypoint requires authentication, so it should fail
HTTPClient().fetch("http://localhost:8099/api")
2020-06-08 11:42:10 +03:00
success = True
break
except Exception as e:
print(e)
time.sleep(i)
2020-06-08 11:42:10 +03:00
assert success == True
2020-06-20 02:05:53 +03:00
# 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
2020-06-18 17:29:50 +03:00
with open(
os.path.join(dynamic_config_dir, "extra_rules.toml"), "w+"
) as extra_config_file:
2020-06-20 02:05:53 +03:00
toml.dump(extra_dynamic_config, extra_config_file)
# load the extra config
2020-06-18 17:29:50 +03:00
reload_component("proxy")
# check hub page
2020-06-21 13:55:52 +03:00
# the new dashboard entrypoint shouldn't require authentication anymore
resp = send_request(url="http://127.0.0.1:9999/hub/login", max_sleep=5)
2020-06-21 13:55:52 +03:00
assert resp.code == 200
2020-06-20 02:05:53 +03:00
# test extra dynamic config
resp = send_request(url="http://127.0.0.1/the/hub/runs/here/too", max_sleep=5)
2020-06-18 17:29:50 +03:00
assert resp.code == 200
assert "http://127.0.0.1/hub/login" in resp.effective_url
2020-06-18 17:29:50 +03:00
# cleanup
2020-06-21 13:55:52 +03:00
os.remove(os.path.join(extra_static_config_dir, "extra.toml"))
2020-06-20 02:05:53 +03:00
os.remove(os.path.join(dynamic_config_dir, "extra_rules.toml"))
2020-06-21 13:55:52 +03:00
open(os.path.join(STATE_DIR, "traefik.toml"), "w").close()