#64 standard-test-chroot: Execute test scripts in a chroot
Opened 6 years ago by stefw. Modified 6 years ago
stefw/standard-test-roles standard-test-chroot  into  master

@@ -0,0 +1,26 @@ 

+ # Ansible role for executing test scripts in a chroot

+ 

+ Put this role in your tests.yml playbook and specify a

+ number of test scripts to execute as tests. These will

+ be executed in a prepared chroot including all the packages

+ that are listed.

+ 

+ The results of each script will be piped into log file in the

+ artifacts directory. If any script exits with a non-zero exit

+ code the role will fail.

+ 

+ In the case of test subjects such a host or container, these

+ test scripts and related files will be copied to the target into

+ /var/tmp/tests before execution.

+ 

+ You should define the following variables:

+ 

+  * tests: An array of scripts to run

+  * files: A list of files or directories needed by the scripts

+  * packages: A list of packages to install in the chroot

+ 

+ You can define these variables:

+ 

+  * root: The path for the chroot. Defaults to /var/tmp/tests/test

+  * target: A target directory inside the chroot to which to

+    place the files. Defaults to /var/tmp/tests

@@ -0,0 +1,95 @@ 

+ ---

+ - 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 chroot build requirements

+     package: name={{ item }} state=present

+     with_items:

+      - dnf

+      - rsync

+ 

+   - name: Perform the chroot build

+     shell: |

+       . /etc/os-release

+       set -eufx

+       cd "{{ playbook_dir }}"

+       rm -rf "{{ root }}"

+       dnf -y --installroot="{{ root }}" --releasever=$VERSION_ID install dnf fedora-release {{ packages | join(" ") }}

+       for path in {{ files | map("quote") | join(" ") }}; do

+            mkdir -p "{{ root }}/{{ target }}/$(basename $path)"

+            rsync -Hvax $path/./ "{{ root }}/{{ target }}/$(basename $path)/./"

+       done

+ 

+   # Everything in the previous block is run on executor

+   delegate_to: executor

+ 

+ - name: Create target directory

+   file:

+     path: "{{ root }}/"

+     state: directory

+ 

+ - name: Sync the chroot into the test subject

+   synchronize:

+     dest: "{{ root }}/"

+     src: "{{ root }}/"

+     mode: push

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

+ 

+ # We run the container using a chroot because for many test containers

+ # --capabilities=all is not enough to get systemd-nspawn to behave

+ # and have tests interact properly with the kernel

+ - name: Prepare the chroot on the target

+   shell: |

+     set -eufx

+     name=$(basename {{ root }} | tr -d ' /.')

+     rm -rf /var/tmp/artifacts

+     mkdir -p /var/tmp/artifacts {{ root }}/host

+     logfile=/var/tmp/artifacts/$name.log

+     exec 2>>$logfile 1>>$logfile

+     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/

+     cp -f /etc/resolv.conf {{ root }}/etc/resolv.conf

+     ln -sf /proc/mounts {{ root }}/etc/mtab

+ 

+ - block:

+   - name: Execute test scripts

+     shell: |

+       set -eufx

+       logfile=/var/tmp/artifacts/test.$(basename "{{ item }}" | tr -d ' /.').log

+       exec 2>>$logfile 1>>$logfile

+       chroot {{ root }} /bin/sh -c "export LC_ALL=en_US.UTF-8; cd {{ target }}; {{ item }}" && result="PASS" || result="FAIL"

+       echo "$result {{ item }}" >> /var/tmp/artifacts/test.log

+     with_items:

+     - "{{ tests }}"

+ 

+   always:

+   - name: Pull out the logs

+     synchronize:

+       dest: "{{ artifacts }}/"

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

+       mode: pull

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

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

+ 

+   # Can't go in block. See

+   # https://github.com/ansible/ansible/issues/20736

+   - name: Check the results

+     shell: grep "^FAIL" /var/tmp/artifacts/test.log

+     register: test_fails

+     failed_when: test_fails.stdout or test_fails.stderr

@@ -0,0 +1,6 @@ 

+ ---

+ packages: [ ]

+ files: [ ]

+ tests: [ ]

+ target: /var/tmp/tests/

+ root: /var/tmp/tests/test

@@ -12,6 +12,10 @@ 

  

  You should define the following variables:

  

-  * tests: An array of scripts to run

-  * files: A list of files or directories needed by the scripts

+  * tests: An array of scripts or commands to run

+  * files: A list of script files or needed files or directories

  

+ You can define these variables:

+ 

+  * target: A target directory to place the files. Defaults to

+    /var/tmp/tests

@@ -5,13 +5,12 @@ 

     - rsync

    when: ansible_pkg_mgr != 'unknown'

  

- - name: Copy test scripts to target

+ - name: Copy test files to target

    synchronize:

      src: "{{ item }}"

-     dest: /var/tmp/tests/

+     dest: "{{ target }}"

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

    with_items:

-   - "{{ tests }}"

    - "{{ files }}"

  

  - block:
@@ -19,14 +18,10 @@ 

      shell: |

        set -e

        mkdir -p /var/tmp/artifacts

-       logfile=/var/tmp/artifacts/test.$(echo {{ item }} | sed -e 's/\//-/g').log

+       logfile=/var/tmp/artifacts/test.$(basename "{{ item }}" | tr -d ' /.').log

        exec 2>>$logfile 1>>$logfile

-       cd /var/tmp/tests

-       if [ -x {{ item }} ]; then

-         ./$(basename {{ item }}) && result="PASS" || result="FAIL"

-       else

-         /bin/sh -e ./$(basename {{ item }}) && result="PASS" || result="FAIL"

-       fi

+       cd "{{ target }}"

+       {{ item }} && result="PASS" || result="FAIL"

        echo "$result {{ item }}" >> /var/tmp/artifacts/test.log

      with_items:

      - "{{ tests }}"

@@ -1,3 +1,4 @@ 

  ---

- tests: []

- files: []

+ tests: [ ]

+ files: [ ]

+ target: /var/tmp/tests/

Put this role in your tests.yml playbook and specify a
number of test scripts to execute as tests. These will
be executed in a prepared chroot including all the packages
that are listed.

The results of each script will be piped into log file in the
artifacts directory. If any script exits with a non-zero exit
code the role will fail.

In the case of test subjects such a host or container, these
test scripts and related files will be copied to the target into
/var/tmp/tests before execution.

You should define the following variables:

  • tests: An array of scripts to run
  • files: A list of files or directories needed by the scripts
  • packages: A list of packages to install in the chroot

You can define these variables:

  • root: The path for the chroot. Defaults to /var/tmp/tests/test
  • target: A target directory inside the chroot to which to place the files. Defaults to /var/tmp/tests

I had much better luck using this than PR #61. However, see my very recent comment on https://src.fedoraproject.org/rpms/selinux-policy/pull-request/1 regarding the disconnect between the standard-test-source and standard-test-chroot roles that caused some difficulties for me.

rebased onto 22ac51f

6 years ago