diff --git a/.circleci/config.yml b/.circleci/config.yml index 591c4a5..3a95f84 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -60,23 +60,21 @@ jobs: - run: name: build systemd image command: | - docker build -t tljh-systemd . + python3 .circleci/integration-test.py build-image - run: name: start systemd image command: | - docker run \ - --privileged \ - --detach \ - --name=tljh-systemd-ci \ - tljh-systemd + python3 .circleci/integration-test.py start-container + - run: name: run tljh installer command: | - docker cp . tljh-systemd-ci:/srv/src - docker exec -it tljh-systemd-ci python3 /srv/src/bootstrap/bootstrap.py + python3 .circleci/integration-test.py cp . /srv/src + python3 .circleci/integration-test.py run 'python3 /srv/src/bootstrap/bootstrap.py' - run: name: check jupyterhub is up command: | - docker exec -it tljh-systemd-ci curl -L --fail http://localhost + python3 .circleci/integration-test.py run 'journalctl -u jupyterhub' + python3 .circleci/integration-test.py run 'curl -L --fail http://localhost' diff --git a/.circleci/integration-test.py b/.circleci/integration-test.py new file mode 100644 index 0000000..6fab030 --- /dev/null +++ b/.circleci/integration-test.py @@ -0,0 +1,112 @@ +import argparse +import subprocess +import os + + +def build_systemd_image(image_name, source_path): + """ + Build docker image with systemd at source_path. + + Built image is tagged with image_name + """ + subprocess.check_call([ + 'docker', 'build', '-t', image_name, source_path + ]) + + +def run_systemd_image(image_name, container_name, external_port, source_path): + """ + Run docker image with systemd + + Image named image_name should be built with build_systemd_image. + + source_path is mounted to /srv/src in the container, so all changes to the + source are reflected in the host. + + Port 80 inside the container is made available to the host at external_port. + + Container named container_name will be started. + """ + subprocess.check_call([ + 'docker', 'run', + '--privileged', + '--detach', + '--name', container_name, + '--publish', f'{external_port}:80', + '--mount', f'type=bind,source={source_path},target=/srv/src', + image_name + ]) + + +def remove_systemd_container(container_name): + """ + Stop & remove docker container if it exists. + """ + try: + subprocess.check_output([ + 'docker', 'inspect', container_name + ]) + except subprocess.CalledProcessError: + # No such container exists, nothing to do + return + subprocess.check_call([ + 'docker', 'rm', '-f', container_name + ]) + + +def run_container_command(container_name, cmd): + """ + Run cmd in a running container with a bash shell + """ + subprocess.check_call([ + 'docker', 'exec', + '-it', container_name, + '/bin/bash', '-c', cmd + ]) + + +def copy_to_container(container_name, src_path, dest_path): + """ + Copy files from src_path to dest_path inside container_name + """ + subprocess.check_call([ + 'docker', 'cp', + src_path, f'{container_name}:{dest_path}'' + ]) + + +def main(): + argparser = argparse.ArgumentParser() + subparsers = argparser.add_subparsers(dest='action') + + subparsers.add_parser('build-image') + subparsers.add_parser('start-container') + subparsers.add_parser('stop-container') + subparsers.add_parser('run').add_argument( + 'command', + ) + copy_parser = subparsers.add_parser('copy') + copy_parser.add_argument('src') + copy_parser.add_argument('dest') + + args = argparser.parse_args() + + image_name = 'tljh-systemd' + container_name = 'tljh-ci-run' + + source_path = os.path.abspath(os.path.join(os.path.dirname(__file__), '..')) + + if args.action == 'build-image': + build_systemd_image(image_name, source_path) + elif args.action == 'start-container': + run_systemd_image(image_name, container_name, 12000, source_path) + elif args.action == 'stop-container': + remove_systemd_container(container_name) + elif args.action == 'run': + run_container_command(container_name, args.command) + elif args.action == 'copy': + copy_to_container(container_name, args.src, args.dest) + + +if __name__ == '__main__': + main()