diff --git a/.circleci/config.yml b/.circleci/config.yml index 572bcd2..64db5e0 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -57,7 +57,7 @@ jobs: - run: name: setup python3 command: | - apk add --no-cache python3 + apk add --no-cache python3 pytest - checkout - setup_remote_docker @@ -79,6 +79,12 @@ jobs: --installer-args "--plugin /srv/src/integration-tests/plugins/simplest" \ plugins test_simplest_plugin.py + - run: + name: Run bootstrap checks + command: | + py.test integration-tests/test_bootstrap.py + + documentation: docker: diff --git a/bootstrap/bootstrap.py b/bootstrap/bootstrap.py index 324dae9..2424ae6 100644 --- a/bootstrap/bootstrap.py +++ b/bootstrap/bootstrap.py @@ -8,7 +8,8 @@ This script is run as: curl | sudo python3 - Constraints: - - Be compatible with Python 3.4 (since we support Ubuntu 16.04) + - Entire script should be compatible with Python 3.6 (We run on Ubuntu 18.04+) + - Script should parse in Python 3.4 (since we exit with useful error message on Ubuntu 14.04+) - Use stdlib modules only """ import os @@ -17,8 +18,31 @@ import sys import logging +def get_os_release_variable(key): + """ + Return value for key from /etc/os-release + + /etc/os-release is a bash file, so should use bash to parse it. + + Returns empty string if key is not found. + """ + return subprocess.check_output([ + '/bin/bash', '-c', + "source /etc/os-release && echo ${{{key}}}".format(key=key) + ]).decode().strip() def main(): + + # Support only Ubuntu 18.04+ + distro = get_os_release_variable('ID') + version = float(get_os_release_variable('VERSION_ID')) + if distro != 'ubuntu': + print('The Littlest JupyterHub currently supports Ubuntu Linux only') + sys.exit(1) + elif float(version) < 18.04: + print('The Littlest JupyterHub requires Ubuntu 18.04 or higher') + sys.exit(1) + install_prefix = os.environ.get('TLJH_INSTALL_PREFIX', '/opt/tljh') hub_prefix = os.path.join(install_prefix, 'hub') diff --git a/docs/index.rst b/docs/index.rst index ea10e01..3bc5597 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -6,6 +6,7 @@ A simple `JupyterHub `_ distribution f a small (0-100) number of users on a single server. We recommend reading :ref:`topic/whentouse` to determine if this is the right tool for you. + Development Status ================== @@ -18,7 +19,8 @@ Installation ============ The Littlest JupyterHub (TLJH) can run on any server that is running at least -Ubuntu 18.04. We have a bunch of tutorials to get you started. +**Ubuntu 18.04**. Earlier versions of Ubuntu are not supported. +We have a bunch of tutorials to get you started. - Tutorials to create a new server from scratch on a cloud provider & run TLJH on it. These are **recommended** if you do not have much experience setting up diff --git a/integration-tests/conftest.py b/integration-tests/conftest.py index ee0ebbd..82dd70e 100644 --- a/integration-tests/conftest.py +++ b/integration-tests/conftest.py @@ -4,12 +4,14 @@ import os from pytest import fixture -from tljh.config import CONFIG_FILE, reload_component @fixture 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() diff --git a/integration-tests/test_bootstrap.py b/integration-tests/test_bootstrap.py new file mode 100644 index 0000000..5bf143f --- /dev/null +++ b/integration-tests/test_bootstrap.py @@ -0,0 +1,44 @@ +""" +Test running bootstrap script in different circumstances +""" +import subprocess + + +def test_ubuntu_too_old(): + """ + Error with a useful message when running in older Ubuntu + """ + container_name = 'old-distro-test' + + # stop container if it is already running + subprocess.run([ + 'docker', 'rm', '-f', container_name + ]) + + # Start a detached Ubuntu 16.04 container + subprocess.check_call([ + 'docker', 'run', '--detach', '--name', container_name, 'ubuntu:16.04', + '/bin/bash', '-c', 'sleep 1000s' + ]) + # Install python3 inside the ubuntu container + # There is no trusted Ubuntu+Python3 container we can use + subprocess.check_output([ + 'docker', 'exec', container_name, 'apt-get', 'update' + ]) + subprocess.check_output([ + 'docker', 'exec', container_name, 'apt-get', 'install', '--yes', 'python3' + ]) + # Copy only the bootstrap script to container, so this is faster + subprocess.check_call([ + 'docker', + 'cp', + 'bootstrap/', f'{container_name}:/srv' + ]) + + # Run bootstrap script, validate that it fails appropriately + output = subprocess.run([ + 'docker', 'exec', '-i', container_name, + 'python3', '/srv/bootstrap/bootstrap.py' + ], check=False, stdout=subprocess.PIPE, encoding='utf-8') + assert output.stdout == 'The Littlest JupyterHub requires Ubuntu 18.04 or higher\n' + assert output.returncode == 1 \ No newline at end of file