#61 standard-test-dockerfile: Role for composing a test via a Dockerfile
Opened 7 years ago by stefw. Modified 7 years ago
stefw/standard-test-roles standard-test-dockerfile  into  master

@@ -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'

@@ -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 }}"

Do we want to set the locale to this in all cases? I'd be fine with a default here, but this is very constricting.

+ 

+   always:

+   - name: Pull out the logs

+     synchronize:

+       dest: "{{ artifacts }}/"

+       src: "/var/tmp/artifacts/./"

+       mode: pull

+       ssh_args: "-o UserKnownHostsFile=/dev/null"

+     when: artifacts|default("") != ""

@@ -0,0 +1,3 @@ 

+ ---

+ build: "{{ playbook_dir }}/files"

+ name: test

Ansible is (understandably) not happy with this choice of variable name:

 [WARNING]: Found variable using reserved name: name

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'

Rebased with fixes from use in selinux-policy pull request.

rebased onto b1f2991

7 years ago

Ansible is (understandably) not happy with this choice of variable name:

 [WARNING]: Found variable using reserved name: name

I have attempted to put this new role to use via the tests.yml playbook and associated files from selinux-policy PR#1 referenced above, but I'm not having any luck. It fails during the docker build at step 2 of 5--apparently due to failure of the %posttrans(kernel-core-4.12.13-300.fc26.x86_64) scriptlet.

Sending build context to Docker daemon 14.16 MB

Step 1/5 : FROM registry.fedoraproject.org/fedora:26
 ---> 838d0d45610f
Step 2/5 : RUN dnf install -y     attr     checkpolicy     expect     findutils     gcc     git     ipsec-tools     libibverbs-devel     libselinux-devel     libsemanage     libsepol-devel     make     nc     net-tools     netlabel_tools     nmap-ncat     perl-Test     perl-Test-Harness     perl-Test-Simple     policycoreutils-devel     python2     rsync     secilc     selinux-policy     selinux-policy-devel     selinux-policy-targeted
 ---> Running in 10ed1a403a7a
Fedora 26 - x86_64 - Updates                    1.8 MB/s |  15 MB     00:08
Fedora 26 - x86_64                              3.5 MB/s |  53 MB     00:15
Last metadata expiration check: 0:00:07 ago on Mon Sep 25 20:56:46 2017.
\u001b[91mPackage libsemanage-2.6-4.fc26.x86_64 is already installed, skipping.
\u001b[0mDependencies resolved.
================================================================================
 Package                      Arch   Version                      Repository
                                                                           Size
================================================================================
Installing:
 attr                         x86_64 2.4.47-18.fc26               fedora   64 k
 checkpolicy                  x86_64 2.6-1.fc26                   fedora  296 k
.
. _many lines deleted of dnf output have been removed_
.
  Installing       : grubby-8.40-4.fc26.x86_64                          136/141
  Cleanup          : libcrypt-nss-2.25-9.fc26.x86_64                    137/141
  Running scriptlet: libcrypt-nss-2.25-9.fc26.x86_64                    137/141
  Cleanup          : glibc-common-2.25-9.fc26.x86_64                    138/141
  Cleanup          : glibc-langpack-en-2.25-9.fc26.x86_64               139/141
  Cleanup          : glibc-2.25-9.fc26.x86_64                           140/141
  Running scriptlet: glibc-2.25-9.fc26.x86_64                           140/141
  Cleanup          : libgcc-7.1.1-3.fc26.x86_64                         141/141
  Running scriptlet: libgcc-7.1.1-3.fc26.x86_64                         141/141
  Running scriptlet: guile-5:2.0.14-1.fc26.x86_64                       141/141
  Running scriptlet: kernel-core-4.12.13-300.fc26.x86_64                141/141
Could not determine your machine ID from /etc/machine-id.
Please run 'systemd-machine-id-setup' as root. See man:machine-id(5)
warning: %posttrans(kernel-core-4.12.13-300.fc26.x86_64) scriptlet failed, exit status 1
  Running scriptlet: libgcc-7.1.1-3.fc26.x86_64                         141/141\u001b[91mFailed to connect to bus: No such file or directory
\u001b[0m\u001b[91mBDB1539 Build signature doesn't match environment
\u001b[0m\u001b[91mNon-fatal POSTTRANS scriptlet failure in rpm package kernel-core
Non-fatal POSTTRANS scriptlet failure in rpm package kernel-core
failed loading RPMDB
\u001b[0m
The downloaded packages were saved in cache until the next successful transaction.
You can remove cached packages by executing 'dnf clean packages'.
The command '/bin/sh -c dnf install -y     attr     checkpolicy     expect     findutils     gcc     git     ipsec-tools     libibverbs-devel     libselinux-devel     libsemanage     libsepol-devel     make     nc     net-tools     netlabel_tools     nmap-ncat     perl-Test     perl-Test-Harness     perl-Test-Simple     policycoreutils-devel     python2     rsync     secilc     selinux-policy     selinux-policy-devel     selinux-policy-targeted' returned a non-zero code: 1

It's very possible I'm just doing something wrong. Unfortunately, I don't fully understand what this new role is doing or what the above failure means.

Any ideas what may be going wrong?

Additionally, I have noted there are several differences between standard-test-dockerfile/tasks/main.yml in the latest commit to this PR and the latest commit in selinux-policy PR#1 referenced above. Perhaps there's a commit to selinux-policy that hasn't been pushed? However, I experience the same failures using either version.

Can we add a sample Dockerfile to this role?

Do we want to set the locale to this in all cases? I'd be fine with a default here, but this is very constricting.

Can we add a sample Dockerfile to this role?

I'd like to change this around to avoid docker. I'm working on a new role.

Do we want to set the locale to this in all cases? I'd be fine with a default here, but this is very constricting.

We need some locale, and it ends up being reset and missing here with chroot. For one perl likes to complain about this. Do you know of another way to solve the missing locale?

I'd like to change this around to avoid docker. I'm working on a new role.

Ok, that sounds good.

We need some locale, and it ends up being reset and missing here with chroot. For one perl likes to complain about this. Do you know of another way to solve the missing locale?

I understand the benefits. Maybe we can instead expose that as a variable with a default. Since there's no pressing need (one could argue we should only expose this if someone needs it), I think it's good to at least mention it in the description.