2018-10-30 20:08:47 -07:00
|
|
|
"""
|
2023-06-06 14:25:00 +02:00
|
|
|
This test file tests bootstrap.py ability to
|
|
|
|
|
|
|
|
|
|
- error verbosely for old ubuntu
|
|
|
|
|
- error verbosely for no systemd
|
|
|
|
|
- start and provide a progress page web server
|
2023-06-06 16:53:16 +02:00
|
|
|
|
|
|
|
|
FIXME: The last test stands out and could be part of the other tests, and the
|
|
|
|
|
first two could be more like unit tests. Ideally, this file is
|
|
|
|
|
significantly reduced.
|
2018-10-30 20:08:47 -07:00
|
|
|
"""
|
2020-08-18 23:56:37 +03:00
|
|
|
import concurrent.futures
|
2020-08-21 18:03:57 +03:00
|
|
|
import os
|
2018-10-30 20:08:47 -07:00
|
|
|
import subprocess
|
2020-08-18 23:56:37 +03:00
|
|
|
import time
|
2018-10-30 20:08:47 -07:00
|
|
|
|
2023-06-06 14:25:00 +02:00
|
|
|
GIT_REPO_PATH = os.path.abspath(os.path.dirname(os.path.dirname(__file__)))
|
2023-03-21 10:15:22 +01:00
|
|
|
BASE_IMAGE = os.getenv("BASE_IMAGE", "ubuntu:20.04")
|
|
|
|
|
|
2020-08-21 18:03:57 +03:00
|
|
|
|
2023-06-06 14:25:00 +02:00
|
|
|
def _stop_container():
|
|
|
|
|
"""
|
|
|
|
|
Stops a container if its already running.
|
|
|
|
|
"""
|
|
|
|
|
subprocess.run(
|
|
|
|
|
["docker", "rm", "--force", "test-bootstrap"],
|
|
|
|
|
stdout=subprocess.DEVNULL,
|
|
|
|
|
stderr=subprocess.DEVNULL,
|
2020-08-18 23:56:37 +03:00
|
|
|
)
|
2020-08-21 18:03:57 +03:00
|
|
|
|
|
|
|
|
|
2023-06-06 14:25:00 +02:00
|
|
|
def _run_bootstrap_in_container(image, complete_setup=True):
|
2021-10-17 20:23:31 +02:00
|
|
|
"""
|
2023-06-06 14:25:00 +02:00
|
|
|
1. (Re-)starts a container named test-bootstrap based on image, mounting
|
|
|
|
|
local git repo and exposing port 8080 to the containers port 80.
|
|
|
|
|
2. Installs python3, systemd, git, and curl in container
|
|
|
|
|
3. Runs bootstrap/bootstrap.py in container to install the mounted git
|
|
|
|
|
repo's tljh package in --editable mode.
|
2021-10-17 20:23:31 +02:00
|
|
|
"""
|
2023-06-06 14:25:00 +02:00
|
|
|
_stop_container()
|
2020-08-21 18:03:57 +03:00
|
|
|
|
2020-08-24 13:01:54 +03:00
|
|
|
# Start a detached container
|
2023-06-06 14:25:00 +02:00
|
|
|
subprocess.check_output(
|
2020-08-24 13:01:54 +03:00
|
|
|
[
|
|
|
|
|
"docker",
|
|
|
|
|
"run",
|
2021-10-19 15:18:02 +02:00
|
|
|
"--env=DEBIAN_FRONTEND=noninteractive",
|
2023-06-06 14:25:00 +02:00
|
|
|
"--env=TLJH_BOOTSTRAP_DEV=yes",
|
|
|
|
|
"--env=TLJH_BOOTSTRAP_PIP_SPEC=/srv/src",
|
|
|
|
|
f"--volume={GIT_REPO_PATH}:/srv/src",
|
|
|
|
|
"--publish=8080:80",
|
2020-08-24 13:01:54 +03:00
|
|
|
"--detach",
|
2023-06-06 14:25:00 +02:00
|
|
|
"--name=test-bootstrap",
|
2020-08-24 13:01:54 +03:00
|
|
|
image,
|
2023-06-06 14:25:00 +02:00
|
|
|
"bash",
|
2020-08-24 13:01:54 +03:00
|
|
|
"-c",
|
2023-06-06 14:25:00 +02:00
|
|
|
"sleep 300s",
|
2020-08-24 13:01:54 +03:00
|
|
|
]
|
|
|
|
|
)
|
|
|
|
|
|
2023-06-06 14:25:00 +02:00
|
|
|
run = ["docker", "exec", "-i", "test-bootstrap"]
|
|
|
|
|
subprocess.check_output(run + ["apt-get", "update"])
|
|
|
|
|
subprocess.check_output(run + ["apt-get", "install", "--yes", "python3"])
|
|
|
|
|
if complete_setup:
|
|
|
|
|
subprocess.check_output(
|
|
|
|
|
run + ["apt-get", "install", "--yes", "systemd", "git", "curl"]
|
|
|
|
|
)
|
2020-08-21 18:03:57 +03:00
|
|
|
|
2023-06-06 14:25:00 +02:00
|
|
|
run_bootstrap = run + [
|
2022-11-27 19:03:48 +00:00
|
|
|
"python3",
|
2023-06-06 14:25:00 +02:00
|
|
|
"/srv/src/bootstrap/bootstrap.py",
|
|
|
|
|
"--show-progress-page",
|
2022-11-27 19:03:48 +00:00
|
|
|
]
|
2018-10-30 20:08:47 -07:00
|
|
|
|
2023-06-06 14:25:00 +02:00
|
|
|
# Run bootstrap script inside detached container, return the output
|
2020-08-21 18:03:57 +03:00
|
|
|
return subprocess.run(
|
2023-06-06 14:25:00 +02:00
|
|
|
run_bootstrap,
|
|
|
|
|
text=True,
|
|
|
|
|
capture_output=True,
|
2020-08-21 18:03:57 +03:00
|
|
|
)
|
|
|
|
|
|
2019-05-19 23:00:43 -07:00
|
|
|
|
|
|
|
|
def test_ubuntu_too_old():
|
|
|
|
|
"""
|
|
|
|
|
Error with a useful message when running in older Ubuntu
|
|
|
|
|
"""
|
2023-06-06 14:25:00 +02:00
|
|
|
output = _run_bootstrap_in_container("ubuntu:18.04", False)
|
|
|
|
|
_stop_container()
|
2023-03-21 10:15:22 +01:00
|
|
|
assert output.stdout == "The Littlest JupyterHub requires Ubuntu 20.04 or higher\n"
|
2019-05-19 23:00:43 -07:00
|
|
|
assert output.returncode == 1
|
|
|
|
|
|
|
|
|
|
|
2023-06-06 14:25:00 +02:00
|
|
|
def test_no_systemd():
|
|
|
|
|
output = _run_bootstrap_in_container("ubuntu:22.04", False)
|
2021-10-17 19:43:13 +02:00
|
|
|
assert "Systemd is required to run TLJH" in output.stdout
|
2019-05-19 23:00:43 -07:00
|
|
|
assert output.returncode == 1
|
2020-08-18 23:56:37 +03:00
|
|
|
|
|
|
|
|
|
2023-06-06 14:25:00 +02:00
|
|
|
def _wait_for_progress_page_response(expected_status_code, timeout):
|
2020-08-19 02:33:17 +03:00
|
|
|
start = time.time()
|
2023-06-06 14:25:00 +02:00
|
|
|
while time.time() - start < timeout:
|
2020-08-18 23:56:37 +03:00
|
|
|
try:
|
2020-08-24 13:01:54 +03:00
|
|
|
resp = subprocess.check_output(
|
|
|
|
|
[
|
|
|
|
|
"curl",
|
2023-06-06 14:25:00 +02:00
|
|
|
"--include",
|
|
|
|
|
"http://localhost:8080/index.html",
|
|
|
|
|
],
|
|
|
|
|
text=True,
|
|
|
|
|
stderr=subprocess.DEVNULL,
|
2020-08-24 13:01:54 +03:00
|
|
|
)
|
2023-06-06 14:25:00 +02:00
|
|
|
if "HTTP/1.0 200 OK" in resp:
|
|
|
|
|
return True
|
|
|
|
|
except Exception:
|
|
|
|
|
pass
|
|
|
|
|
time.sleep(1)
|
|
|
|
|
|
|
|
|
|
return False
|
2020-08-18 23:56:37 +03:00
|
|
|
|
|
|
|
|
|
2023-06-06 14:25:00 +02:00
|
|
|
def test_show_progress_page():
|
|
|
|
|
with concurrent.futures.ThreadPoolExecutor() as executor:
|
|
|
|
|
run_bootstrap_job = executor.submit(_run_bootstrap_in_container, BASE_IMAGE)
|
2020-08-19 02:33:17 +03:00
|
|
|
|
2023-06-06 14:25:00 +02:00
|
|
|
# Check that the bootstrap script started the web server reporting
|
|
|
|
|
# progress successfully responded.
|
|
|
|
|
success = _wait_for_progress_page_response(
|
|
|
|
|
expected_status_code=200, timeout=180
|
|
|
|
|
)
|
|
|
|
|
if success:
|
|
|
|
|
# Let's terminate the test here and save a minute or so in test
|
|
|
|
|
# executation time, because we can know that the will be stopped
|
|
|
|
|
# successfully in other tests as otherwise traefik won't be able to
|
|
|
|
|
# start and use the same port for example.
|
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
# Now await an expected failure to startup JupyterHub by tljh.installer,
|
|
|
|
|
# which should have taken over the work started by the bootstrap script.
|
|
|
|
|
#
|
|
|
|
|
# This failure is expected to occur in
|
|
|
|
|
# tljh.installer.ensure_jupyterhub_service calling systemd.reload_daemon
|
|
|
|
|
# like this:
|
|
|
|
|
#
|
|
|
|
|
# > System has not been booted with systemd as init system (PID 1).
|
|
|
|
|
# > Can't operate.
|
|
|
|
|
#
|
|
|
|
|
output = run_bootstrap_job.result()
|
|
|
|
|
print(output.stdout)
|
|
|
|
|
print(output.stderr)
|
|
|
|
|
|
|
|
|
|
# At this point we should be able to see that tljh.installer
|
|
|
|
|
# intentionally stopped the web server reporting progress as the port
|
|
|
|
|
# were about to become needed by Traefik.
|
2020-08-21 18:03:57 +03:00
|
|
|
assert "Progress page server stopped successfully." in output.stdout
|
2023-06-06 14:25:00 +02:00
|
|
|
assert success
|