From 7f1835c978e360a6ba1735a2b22177929db40175 Mon Sep 17 00:00:00 2001 From: Joseph Schorr Date: Mon, 24 Sep 2018 15:32:09 -0400 Subject: [PATCH] Add an end-to-end test suite for different versions of Docker This script, when run, will boot up a Container Linux VM (via vagrant) with a specific version of Docker installed, and then run a login, push and pull test against the host machine's Quay instance. --- .dockerignore | 1 + .gitignore | 2 + test/dockerclients/50-insecure-registry.conf | 2 + test/dockerclients/Dockerfile.test | 4 + test/dockerclients/clients_test.py | 152 +++++++++++++++++++ 5 files changed, 161 insertions(+) create mode 100644 test/dockerclients/50-insecure-registry.conf create mode 100644 test/dockerclients/Dockerfile.test create mode 100644 test/dockerclients/clients_test.py diff --git a/.dockerignore b/.dockerignore index 277d8c921..b9809a70a 100644 --- a/.dockerignore +++ b/.dockerignore @@ -31,3 +31,4 @@ static/build/** .gitlab-ci/* .gitlab-ci.* docker-compose.yaml +test/dockerclients/** diff --git a/.gitignore b/.gitignore index f23f57274..b91ee9308 100644 --- a/.gitignore +++ b/.gitignore @@ -27,3 +27,5 @@ build/ *.iml .DS_Store .pytest_cache/* +test/dockerclients/Vagrantfile +test/dockerclients/.* diff --git a/test/dockerclients/50-insecure-registry.conf b/test/dockerclients/50-insecure-registry.conf new file mode 100644 index 000000000..97971974b --- /dev/null +++ b/test/dockerclients/50-insecure-registry.conf @@ -0,0 +1,2 @@ +[Service] +Environment=DOCKER_OPTS='--insecure-registry="0.0.0.0/0"' diff --git a/test/dockerclients/Dockerfile.test b/test/dockerclients/Dockerfile.test new file mode 100644 index 000000000..b5728c23e --- /dev/null +++ b/test/dockerclients/Dockerfile.test @@ -0,0 +1,4 @@ +FROM quay.io/quay/busybox +RUN date > somefile +RUN date +%s%N > anotherfile +RUN date +"%T.%N" > thirdfile diff --git a/test/dockerclients/clients_test.py b/test/dockerclients/clients_test.py new file mode 100644 index 000000000..3b0e2ca8b --- /dev/null +++ b/test/dockerclients/clients_test.py @@ -0,0 +1,152 @@ +import subprocess +import sys +import time + +import unicodedata + +from threading import Thread + +from termcolor import colored + +def remove_control_characters(s): + return "".join(ch for ch in unicode(s) if unicodedata.category(ch)[0]!="C") + +BOXES = [ + ("AntonioMeireles/coreos-stable --box-version=835.8.0", 'v1.8.3'), + ("AntonioMeireles/coreos-stable --box-version=766.3.0", 'v1.7.1'), + ("AntonioMeireles/coreos-stable --box-version=681.0.0", 'v1.6.2'), + ("AntonioMeireles/coreos-stable --box-version=607.0.0", 'v1.5.0'), + ("AntonioMeireles/coreos-stable --box-version=557.2.0", 'v1.4.1'), + + ("yungsang/coreos --box-version=1.3.8", 'v1.3.3'), + ("yungsang/coreos --box-version=1.3.7", 'v1.3.2'), + ("yungsang/coreos --box-version=1.2.9", 'v1.2.0'), + ("yungsang/coreos --box-version=1.1.5", 'v1.1.2'), + ("yungsang/coreos --box-version=1.0.0", 'v1.0.1'), +] + +class CommandFailedException(Exception): + pass + + +class SpinOutputter(Thread): + def __init__(self, initial_message): + super(SpinOutputter, self).__init__() + self.previous_line = '' + self.next_line = initial_message + self.running = True + self.daemon = True + + @staticmethod + def spinning_cursor(): + while 1: + for cursor in '|/-\\': + yield cursor + + def set_next(self, text): + first_line = text.split('\n')[0].strip() + first_line = remove_control_characters(first_line) + self.next_line = first_line[:80] + + def _clear_line(self): + sys.stdout.write('\r') + sys.stdout.write(' ' * (len(self.previous_line) + 2)) + sys.stdout.flush() + + sys.stdout.write('\r') + sys.stdout.flush() + self.previous_line = '' + + def stop(self): + self._clear_line() + self.running = False + + def run(self): + spinner = SpinOutputter.spinning_cursor() + while self.running: + self._clear_line() + sys.stdout.write('\r') + sys.stdout.flush() + + sys.stdout.write(next(spinner)) + sys.stdout.write(" ") + sys.stdout.write(colored(self.next_line, attrs=['dark'])) + sys.stdout.flush() + + self.previous_line = self.next_line + time.sleep(0.25) + + +def _run_and_wait(command, error_allowed=False): + # Run the command itself. + outputter = SpinOutputter('Running command %s' % command) + outputter.start() + + output = '' + process = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) + for line in iter(process.stdout.readline, ''): + output += line + outputter.set_next(line) + + result = process.wait() + outputter.stop() + + if result != 0 and not error_allowed: + print colored('>>> Command `%s` Failed:' % command, 'red') + print output + raise CommandFailedException() + + +def _run_box(box, docker_version, registry): + print (colored('>>> Box: %s' % box, attrs=['bold']) + ' | ' + + colored('Docker version: %s' % docker_version, 'cyan', attrs=['bold'])) + print colored('>>> Starting box', 'yellow') + _run_and_wait(['vagrant', 'destroy', '-f'], error_allowed=True) + _run_and_wait(['rm', 'Vagrantfile'], error_allowed=True) + _run_and_wait(['vagrant', 'init'] + box.split(' ')) + _run_and_wait(['vagrant', 'up', '--provider', 'virtualbox']) + + print colored('>>> Setting up Docker', 'yellow') + _run_and_wait(['vagrant', 'ssh', '-c', 'sudo mkdir -p /etc/systemd/system/docker.service.d/']) + _run_and_wait(['vagrant', 'scp', '50-insecure-registry.conf', '/home/core']) + _run_and_wait(['vagrant', 'scp', 'Dockerfile.test', '/home/core/Dockerfile']) + + cp_command = ('sudo cp /home/core/50-insecure-registry.conf ' + + '/etc/systemd/system/docker.service.d/50-insecure-registry.conf') + _run_and_wait(['vagrant', 'ssh', '-c', cp_command]) + _run_and_wait(['vagrant', 'ssh', '-c', 'sudo systemctl daemon-reload']) + + print colored('>>> Building test image', 'yellow') + _run_and_wait(['vagrant', 'ssh', '-c', 'docker build -t %s/devtable/testrepo .' % registry]) + + print colored('>>> Testing login', 'cyan') + _run_and_wait(['vagrant', 'ssh', '-c', + 'docker login --username=devtable --password=password --email=foo %s' % registry]) + + print colored('>>> Testing push', 'cyan') + _run_and_wait(['vagrant', 'ssh', '-c', 'docker push %s/devtable/testrepo' % registry]) + + print colored('>>> Removing all images', 'yellow') + _run_and_wait(['vagrant', 'ssh', '-c', 'docker rmi -f %s/devtable/testrepo' % registry]) + _run_and_wait(['vagrant', 'ssh', '-c', 'docker rmi -f quay.io/quay/busybox']) + + print colored('>>> Testing pull', 'cyan') + _run_and_wait(['vagrant', 'ssh', '-c', 'docker pull %s/devtable/testrepo' % registry]) + + print colored('>>> Tearing down box', 'magenta') + _run_and_wait(['vagrant', 'destroy', '-f'], error_allowed=True) + + print colored('>>> Successfully tested box %s' % box, 'green') + print "" + +def test_clients(registry='10.0.2.2:5000'): + print colored('>>> Running against registry ', attrs=['bold']) + colored(registry, 'cyan') + for box, docker_version in BOXES: + try: + _run_box(box, docker_version, registry) + except CommandFailedException: + sys.exit(-1) + + +if __name__ == "__main__": + test_clients(sys.argv[1] if len(sys.argv) > 1 else '10.0.2.2:5000')