From b1f2991f09c8d40a9f584e2d3c9182d7a790b860 Mon Sep 17 00:00:00 2001 From: Stef Walter Date: Sep 25 2017 17:16:46 +0000 Subject: standard-test-dockerfile: Role for composing a test via a Dockerfile Put this role in your tests.yml playbook. The role will build and execute a test in a Dockerfile. Because such tests often interact heavily with the operating system and kernel, the test will be run in a chroot, rather than by docker. Don't use the VOLUME ENV or other runtime commands. Keep your CMD to a single line. The test subject file system will be mounted at /host while your test is running. You can redefine the following variables: * build: The directory containing the Dockerfile to build * name: The name of the test. Defaults to 'test' --- diff --git a/roles/standard-test-dockerfile/README.md b/roles/standard-test-dockerfile/README.md new file mode 100644 index 0000000..e21f476 --- /dev/null +++ b/roles/standard-test-dockerfile/README.md @@ -0,0 +1,19 @@ +# Ansible role for composing a test in a Dockerfile + +Put this role in your tests.yml playbook. The role will +build and execute a test in a Dockerfile. Because such +tests often interact heavily with the operating system +and kernel, the test will be run in a chroot, rather than +by docker. + +Don't use the VOLUME ENV or other runtime commands. + +Keep your CMD to a single line. + +The test subject file system will be mounted at /host +while your test is running. + +You can redefine the following variables: + + * build: The directory containing the Dockerfile to build + * name: The name of the test. Defaults to 'test' diff --git a/roles/standard-test-dockerfile/tasks/main.yml b/roles/standard-test-dockerfile/tasks/main.yml new file mode 100644 index 0000000..93e60ce --- /dev/null +++ b/roles/standard-test-dockerfile/tasks/main.yml @@ -0,0 +1,79 @@ +--- +- name: Add executor host + add_host: + name: executor + ansible_connection: local + ansible_ssh_host: 127.0.0.1 + ansible_ssh_connection: local + +- block: + - name: Gather facts + setup: + delegate_facts: True + + - name: Install container build requirements + package: name={{ item }} state=present + with_items: + - sed + - util-linux + - docker + - grep + + - name: Make sure docker is started locally + service: name=docker state=started + + - name: Perform the docker build + shell: | + . /etc/os-release + set -e + identifier=$(uuidgen) + sed -e "s/\$ID/$ID/" -e "s/\$VERSION_ID/$VERSION_ID/" {{ build }}/Dockerfile > {{ build }}/Dockerfile.tmp + docker build -t $identifier -f {{ build }}/Dockerfile.tmp {{ build }} >&2 + docker export --output=/var/tmp/testableimage.tar $(docker create $identifier /bin/true) >&2 + sed -n -e 's/^CMD//p' {{ build }}/Dockerfile + register: cmd + + # Everything in the previous block is run on executor + delegate_to: executor + +- name: Copy image to target host + copy: src=/var/tmp/testableimage.tar dest=/var/tmp/testableimage.tar + +- block: + + # We run the container using a chroot because for many test containers + # even --privileged and --pid=host is not enough to get docker to behave + # and --capabilities=all is not enough to get systemd-nspawn to behave + # and have tests interact properly with the kernel + - name: Load and run image on target + shell: | + set -euf + name=$(echo {{ name }} | sed -e 's/\//-/g') + artifacts=/var/tmp/artifacts + root=/var/tmp/tests/$name + rm -rf $artifacts $root + mkdir -p $artifacts $root $root/host + logfile=$artifacts/$name.log + exec 2>>$logfile 1>>$logfile + tar -C $root -xf /var/tmp/testableimage.tar + setfiles -v -r $root /etc/selinux/targeted/contexts/files/file_contexts $root + mount -t proc proc $root/proc/ + mount -t sysfs sys $root/sys/ + mount -o bind /dev $root/dev + mount -t tmpfs tmpfs $root/dev/shm + mount -t devpts devpts $root/dev/pts + mount -t selinuxfs selinuxfs $root/sys/fs/selinux + mount -o bind / $root/host + cp -f /etc/hosts $root/etc/hosts + cp -f /etc/resolv.conf $root/etc/resolv.conf + ln -sf /proc/mounts $root/etc/mtab + chroot $root /bin/sh -c "export LC_ALL=en_US.UTF-8; {{ cmd.stdout }}" + + always: + - name: Pull out the logs + synchronize: + dest: "{{ artifacts }}/" + src: "/var/tmp/artifacts/./" + mode: pull + ssh_args: "-o UserKnownHostsFile=/dev/null" + when: artifacts|default("") != "" diff --git a/roles/standard-test-dockerfile/vars/main.yml b/roles/standard-test-dockerfile/vars/main.yml new file mode 100644 index 0000000..5ab5a5b --- /dev/null +++ b/roles/standard-test-dockerfile/vars/main.yml @@ -0,0 +1,3 @@ +--- +build: "{{ playbook_dir }}/files" +name: test