diff options
Diffstat (limited to 'contrib/test')
-rw-r--r-- | contrib/test/integration/README.md | 21 | ||||
-rw-r--r-- | contrib/test/integration/ansible.cfg | 359 | ||||
-rw-r--r-- | contrib/test/integration/build/bats.yml | 17 | ||||
-rw-r--r-- | contrib/test/integration/build/cri-o.yml | 79 | ||||
-rw-r--r-- | contrib/test/integration/build/cri-tools.yml | 16 | ||||
-rw-r--r-- | contrib/test/integration/build/kubernetes.yml | 63 | ||||
-rw-r--r-- | contrib/test/integration/build/plugins.yml | 50 | ||||
-rw-r--r-- | contrib/test/integration/build/runc.yml | 23 | ||||
-rw-r--r-- | contrib/test/integration/callback_plugins/default.py | 156 | ||||
-rw-r--r-- | contrib/test/integration/e2e.yml | 57 | ||||
-rw-r--r-- | contrib/test/integration/golang.yml | 51 | ||||
-rw-r--r-- | contrib/test/integration/main.yml | 58 | ||||
-rw-r--r-- | contrib/test/integration/results.yml | 62 | ||||
-rw-r--r-- | contrib/test/integration/system.yml | 117 | ||||
-rw-r--r-- | contrib/test/integration/test.yml | 25 | ||||
-rw-r--r-- | contrib/test/integration/vars.yml | 8 | ||||
-rw-r--r-- | contrib/test/requirements.txt | 54 | ||||
-rwxr-xr-x | contrib/test/venv-ansible-playbook.sh | 106 |
18 files changed, 1322 insertions, 0 deletions
diff --git a/contrib/test/integration/README.md b/contrib/test/integration/README.md new file mode 100644 index 000000000..f13b8b925 --- /dev/null +++ b/contrib/test/integration/README.md @@ -0,0 +1,21 @@ +# Fedora and RHEL Integration and End-to-End Tests + +This directory contains playbooks to set up for and run the integration and +end-to-end tests for CRI-O on RHEL and Fedora hosts. Two entrypoints exist: + + - `main.yml`: sets up the machine and runs tests + - `results.yml`: gathers test output to `/tmp/artifacts` + +When running `main.yml`, three tags are present: + + - `setup`: run all tasks to set up the system for testing + - `e2e`: build CRI-O from source and run Kubernetes node E2Es + - `integration`: build CRI-O from source and run the local integration suite + +The playbooks assume the following things about your system: + + - on RHEL, the server and extras repos are configured and certs are present + - `ansible` is installed and the host is boot-strapped to allow `ansible` to run against it + - the `$GOPATH` is set and present for all shells (*e.g.* written in `/etc/environment`) + - CRI-O is checked out to the correct state at `${GOPATH}/src/github.com/kubernetes-incubator/cri-o` + - the user running the playbook has access to passwordless `sudo`
\ No newline at end of file diff --git a/contrib/test/integration/ansible.cfg b/contrib/test/integration/ansible.cfg new file mode 100644 index 000000000..92a13a5fb --- /dev/null +++ b/contrib/test/integration/ansible.cfg @@ -0,0 +1,359 @@ +# config file for ansible -- http://ansible.com/ +# ============================================== + +# nearly all parameters can be overridden in ansible-playbook +# or with command line flags. ansible will read ANSIBLE_CONFIG, +# ansible.cfg in the current working directory, .ansible.cfg in +# the home directory or /etc/ansible/ansible.cfg, whichever it +# finds first + +[defaults] + +# some basic default values... + +#inventory = inventory +#library = /usr/share/my_modules/ +#remote_tmp = $HOME/.ansible/tmp +#local_tmp = .ansible/tmp +#forks = 5 +forks = 10 +#poll_interval = 15 +#sudo_user = root +#ask_sudo_pass = True +ask_sudo_pass = False +#ask_pass = True +ask_pass = False +#transport = smart +#remote_port = 22 +#module_lang = C +#module_set_locale = True + +# plays will gather facts by default, which contain information about +# the remote system. +# +# smart - gather by default, but don't regather if already gathered +# implicit - gather by default, turn off with gather_facts: False +# explicit - do not gather by default, must say gather_facts: True +#gathering = implicit +gathering = smart + +# by default retrieve all facts subsets +# all - gather all subsets +# network - gather min and network facts +# hardware - gather hardware facts (longest facts to retrieve) +# virtual - gather min and virtual facts +# facter - import facts from facter +# ohai - import facts from ohai +# You can combine them using comma (ex: network,virtual) +# You can negate them using ! (ex: !hardware,!facter,!ohai) +# A minimal set of facts is always gathered. +gather_subset = network + +# additional paths to search for roles in, colon separated +# N/B: This depends on how ansible is called +#roles_path = $WORKSPACE/kommandir_workspace/roles + +# uncomment this to disable SSH key host checking +#host_key_checking = False +host_key_checking = False + +# change the default callback +#stdout_callback = skippy +# enable additional callbacks +#callback_whitelist = timer, mail + +# Determine whether includes in tasks and handlers are "static" by +# default. As of 2.0, includes are dynamic by default. Setting these +# values to True will make includes behave more like they did in the +# 1.x versions. +task_includes_static = True +handler_includes_static = True + +# change this for alternative sudo implementations +#sudo_exe = sudo + +# What flags to pass to sudo +# WARNING: leaving out the defaults might create unexpected behaviours +#sudo_flags = -H -S -n + +# SSH timeout +#timeout = 10 + +# default user to use for playbooks if user is not specified +# (/usr/bin/ansible will use current user as default) +#remote_user = root +remote_user = root + +# logging is off by default unless this path is defined +# if so defined, consider logrotate +log_path = $ARTIFACTS/main.log + +# default module name for /usr/bin/ansible +#module_name = command + +# use this shell for commands executed under sudo +# you may need to change this to bin/bash in rare instances +# if sudo is constrained +# executable = /bin/sh + +# if inventory variables overlap, does the higher precedence one win +# or are hash values merged together? The default is 'replace' but +# this can also be set to 'merge'. +hash_behaviour = replace + +# by default, variables from roles will be visible in the global variable +# scope. To prevent this, the following option can be enabled, and only +# tasks and handlers within the role will see the variables there +private_role_vars = False + +# list any Jinja2 extensions to enable here: +#jinja2_extensions = jinja2.ext.do,jinja2.ext.i18n + +# if set, always use this private key file for authentication, same as +# if passing --private-key to ansible or ansible-playbook +#private_key_file = /path/to/file + +# If set, configures the path to the Vault password file as an alternative to +# specifying --vault-password-file on the command line. +#vault_password_file = /path/to/vault_password_file + +# format of string {{ ansible_managed }} available within Jinja2 +# templates indicates to users editing templates files will be replaced. +# replacing {file}, {host} and {uid} and strftime codes with proper values. +#ansible_managed = Ansible managed: {file} modified on %Y-%m-%d %H:%M:%S by {uid} on {host} +# This short version is better used in templates as it won't flag the file as changed every run. +#ansible_managed = Ansible managed: {file} on {host} + +# by default, ansible-playbook will display "Skipping [host]" if it determines a task +# should not be run on a host. Set this to "False" if you don't want to see these "Skipping" +# messages. NOTE: the task header will still be shown regardless of whether or not the +# task is skipped. +#display_skipped_hosts = True +display_skipped_hosts = False + +# by default, if a task in a playbook does not include a name: field then +# ansible-playbook will construct a header that includes the task's action but +# not the task's args. This is a security feature because ansible cannot know +# if the *module* considers an argument to be no_log at the time that the +# header is printed. If your environment doesn't have a problem securing +# stdout from ansible-playbook (or you have manually specified no_log in your +# playbook on all of the tasks where you have secret information) then you can +# safely set this to True to get more informative messages. +display_args_to_stdout = False + +# by default (as of 1.3), Ansible will raise errors when attempting to dereference +# Jinja2 variables that are not set in templates or action lines. Uncomment this line +# to revert the behavior to pre-1.3. +#error_on_undefined_vars = False + +# by default (as of 1.6), Ansible may display warnings based on the configuration of the +# system running ansible itself. This may include warnings about 3rd party packages or +# other conditions that should be resolved if possible. +# to disable these warnings, set the following value to False: +system_warnings = False + +# by default (as of 1.4), Ansible may display deprecation warnings for language +# features that should no longer be used and will be removed in future versions. +# to disable these warnings, set the following value to False: +deprecation_warnings = False + +# (as of 1.8), Ansible can optionally warn when usage of the shell and +# command module appear to be simplified by using a default Ansible module +# instead. These warnings can be silenced by adjusting the following +# setting or adding warn=yes or warn=no to the end of the command line +# parameter string. This will for example suggest using the git module +# instead of shelling out to the git command. +command_warnings = False + + +# set plugin path directories here, separate with colons +#action_plugins = /usr/share/ansible/plugins/action +#callback_plugins = /usr/share/ansible/plugins/callback +#connection_plugins = /usr/share/ansible/plugins/connection +#lookup_plugins = /usr/share/ansible/plugins/lookup +#vars_plugins = /usr/share/ansible/plugins/vars +#filter_plugins = /usr/share/ansible/plugins/filter +#test_plugins = /usr/share/ansible/plugins/test +#strategy_plugins = /usr/share/ansible/plugins/strategy + +# Most callbacks shipped with Ansible are disabled by default +# and need to be whitelisted in your ansible.cfg file in order to function. +callback_whitelist = default + +# by default callbacks are not loaded for /bin/ansible, enable this if you +# want, for example, a notification or logging callback to also apply to +# /bin/ansible runs +#bin_ansible_callbacks = False + + +# don't like cows? that's unfortunate. +# set to 1 if you don't want cowsay support or export ANSIBLE_NOCOWS=1 +#nocows = 1 + +# set which cowsay stencil you'd like to use by default. When set to 'random', +# a random stencil will be selected for each task. The selection will be filtered +# against the `cow_whitelist` option below. +#cow_selection = default +#cow_selection = random + +# when using the 'random' option for cowsay, stencils will be restricted to this list. +# it should be formatted as a comma-separated list with no spaces between names. +# NOTE: line continuations here are for formatting purposes only, as the INI parser +# in python does not support them. +#cow_whitelist=bud-frogs,bunny,cheese,daemon,default,dragon,elephant-in-snake,elephant,eyes,\ +# hellokitty,kitty,luke-koala,meow,milk,moofasa,moose,ren,sheep,small,stegosaurus,\ +# stimpy,supermilker,three-eyes,turkey,turtle,tux,udder,vader-koala,vader,www + +# don't like colors either? +# set to 1 if you don't want colors, or export ANSIBLE_NOCOLOR=1 +nocolor = 0 + +# if set to a persistent type (not 'memory', for example 'redis') fact values +# from previous runs in Ansible will be stored. This may be useful when +# wanting to use, for example, IP information from one group of servers +# without having to talk to them in the same playbook run to get their +# current IP information. +#fact_caching = memory + +# retry files +# When a playbook fails by default a .retry file will be created in ~/ +# You can disable this feature by setting retry_files_enabled to False +# and you can change the location of the files by setting retry_files_save_path + +#retry_files_enabled = False +retry_files_enabled = False + +# squash actions +# Ansible can optimise actions that call modules with list parameters +# when looping. Instead of calling the module once per with_ item, the +# module is called once with all items at once. Currently this only works +# under limited circumstances, and only with parameters named 'name'. +squash_actions = apk,apt,dnf,package,pacman,pkgng,yum,zypper + +# prevents logging of task data, off by default +#no_log = False + +# prevents logging of tasks, but only on the targets, data is still logged on the master/controller +no_target_syslog = True + +# controls whether Ansible will raise an error or warning if a task has no +# choice but to create world readable temporary files to execute a module on +# the remote machine. This option is False by default for security. Users may +# turn this on to have behaviour more like Ansible prior to 2.1.x. See +# https://docs.ansible.com/ansible/become.html#becoming-an-unprivileged-user +# for more secure ways to fix this than enabling this option. +#allow_world_readable_tmpfiles = False + +# controls the compression level of variables sent to +# worker processes. At the default of 0, no compression +# is used. This value must be an integer from 0 to 9. +#var_compression_level = 9 + +# controls what compression method is used for new-style ansible modules when +# they are sent to the remote system. The compression types depend on having +# support compiled into both the controller's python and the client's python. +# The names should match with the python Zipfile compression types: +# * ZIP_STORED (no compression. available everywhere) +# * ZIP_DEFLATED (uses zlib, the default) +# These values may be set per host via the ansible_module_compression inventory +# variable +#module_compression = 'ZIP_DEFLATED' + +# This controls the cutoff point (in bytes) on --diff for files +# set to 0 for unlimited (RAM may suffer!). +#max_diff_size = 1048576 + +[privilege_escalation] +#become=True +#become_method=sudo +#become_user=root +become_user=root +#become_ask_pass=False + +[paramiko_connection] + +# uncomment this line to cause the paramiko connection plugin to not record new host +# keys encountered. Increases performance on new host additions. Setting works independently of the +# host key checking setting above. +#record_host_keys=False + +# by default, Ansible requests a pseudo-terminal for commands executed under sudo. Uncomment this +# line to disable this behaviour. +#pty=False + +[ssh_connection] + +# ssh arguments to use +# Leaving off ControlPersist will result in poor performance, so use +# paramiko on older platforms rather than removing it +ssh_args = -o ControlMaster=auto -o ControlPersist=60s -o UserKnownHostsFile=/dev/null -o PreferredAuthentications=publickey -o ConnectTimeout=13 + +# The path to use for the ControlPath sockets. This defaults to +# "%(directory)s/ansible-ssh-%%h-%%p-%%r", however on some systems with +# very long hostnames or very long path names (caused by long user names or +# deeply nested home directories) this can exceed the character limit on +# file socket names (108 characters for most platforms). In that case, you +# may wish to shorten the string below. +# +# Example: +# control_path = %(directory)s/%%h-%%r +#control_path = %(directory)s/ansible-ssh-%%h-%%p-%%r + +# Enabling pipelining reduces the number of SSH operations required to +# execute a module on the remote server. This can result in a significant +# performance improvement when enabled, however when using "sudo:" you must +# first disable 'requiretty' in /etc/sudoers +# +# By default, this option is disabled to preserve compatibility with +# sudoers configurations that have requiretty (the default on many distros). +# +#pipelining = False +pipelining=True + +# if True, make ansible use scp if the connection type is ssh +# (default is sftp) +#scp_if_ssh = True + +# if False, sftp will not use batch mode to transfer files. This may cause some +# types of file transfer failures impossible to catch however, and should +# only be disabled if your sftp version has problems with batch mode +#sftp_batch_mode = False + +[accelerate] +#accelerate_port = 5099 +#accelerate_timeout = 30 +#accelerate_connect_timeout = 5.0 + +# The daemon timeout is measured in minutes. This time is measured +# from the last activity to the accelerate daemon. +#accelerate_daemon_timeout = 30 + +# If set to yes, accelerate_multi_key will allow multiple +# private keys to be uploaded to it, though each user must +# have access to the system via SSH to add a new key. The default +# is "no". +#accelerate_multi_key = yes + +[selinux] +# file systems that require special treatment when dealing with security context +# the default behaviour that copies the existing context or uses the user default +# needs to be changed to use the file system dependent context. +#special_context_filesystems=nfs,vboxsf,fuse,ramfs + +# Set this to yes to allow libvirt_lxc connections to work without SELinux. +#libvirt_lxc_noseclabel = yes + +[colors] +#highlight = white +#verbose = blue +#warn = bright purple +#error = red +#debug = dark gray +#deprecate = purple +#skip = cyan +#unreachable = red +#ok = green +#changed = yellow +#diff_add = green +#diff_remove = red +#diff_lines = cyan diff --git a/contrib/test/integration/build/bats.yml b/contrib/test/integration/build/bats.yml new file mode 100644 index 000000000..d4ea19c65 --- /dev/null +++ b/contrib/test/integration/build/bats.yml @@ -0,0 +1,17 @@ +--- + +- name: clone bats source repo + git: + repo: "https://github.com/sstephenson/bats.git" + dest: "{{ ansible_env.GOPATH }}/src/github.com/sstephenson/bats" + +- name: install bats + command: "./install.sh /usr/local" + args: + chdir: "{{ ansible_env.GOPATH }}/src/github.com/sstephenson/bats" + +- name: link bats + file: + src: /usr/local/bin/bats + dest: /usr/bin/bats + state: link diff --git a/contrib/test/integration/build/cri-o.yml b/contrib/test/integration/build/cri-o.yml new file mode 100644 index 000000000..fa025035c --- /dev/null +++ b/contrib/test/integration/build/cri-o.yml @@ -0,0 +1,79 @@ +--- + +- name: stat the expected cri-o directory + stat: + path: "{{ ansible_env.GOPATH }}/src/github.com/kubernetes-incubator/cri-o" + register: dir_stat + +- name: expect cri-o to be cloned already + fail: + msg: "Expected cri-o to be cloned at {{ ansible_env.GOPATH }}/src/github.com/kubernetes-incubator/cri-o but it wasn't!" + when: not dir_stat.stat.exists + +- name: install cri-o tools + make: + target: install.tools + chdir: "{{ ansible_env.GOPATH }}/src/github.com/kubernetes-incubator/cri-o" + +- name: build cri-o + make: + chdir: "{{ ansible_env.GOPATH }}/src/github.com/kubernetes-incubator/cri-o" + +- name: install cri-o + make: + target: install + chdir: "{{ ansible_env.GOPATH }}/src/github.com/kubernetes-incubator/cri-o" + +- name: install cri-o systemd files + make: + target: install.systemd + chdir: "{{ ansible_env.GOPATH }}/src/github.com/kubernetes-incubator/cri-o" + +- name: install cri-o config + make: + target: install.config + chdir: "{{ ansible_env.GOPATH }}/src/github.com/kubernetes-incubator/cri-o" + +- name: install configs + copy: + src: "{{ ansible_env.GOPATH }}/src/github.com/kubernetes-incubator/cri-o/{{ item.src }}" + dest: "{{ item.dest }}" + remote_src: yes + with_items: + - src: contrib/cni/10-crio-bridge.conf + dest: /etc/cni/net.d/10-crio-bridge.conf + - src: contrib/cni/99-loopback.conf + dest: /etc/cni/net.d/99-loopback.conf + - src: test/redhat_sigstore.yaml + dest: /etc/containers/registries.d/registry.access.redhat.com.yaml + +- name: run with overlay + replace: + regexp: 'storage_driver = ""' + replace: 'storage_driver = "overlay"' + name: /etc/crio/crio.conf + backup: yes + +- name: run with systemd cgroup manager + replace: + regexp: 'cgroup_manager = "cgroupfs"' + replace: 'cgroup_manager = "systemd"' + name: /etc/crio/crio.conf + backup: yes + +- name: add docker.io default registry + lineinfile: + dest: /etc/crio/crio.conf + line: '"docker.io"' + insertafter: 'registries = \[' + regexp: 'docker\.io' + state: present + +- name: add overlay storage opts on RHEL/CentOS + lineinfile: + dest: /etc/crio/crio.conf + line: '"overlay.override_kernel_check=1"' + insertafter: 'storage_option = \[' + regexp: 'overlay\.override_kernel_check=1' + state: present + when: ansible_distribution == 'RedHat' or ansible_distribution == 'CentOS' diff --git a/contrib/test/integration/build/cri-tools.yml b/contrib/test/integration/build/cri-tools.yml new file mode 100644 index 000000000..e314225ef --- /dev/null +++ b/contrib/test/integration/build/cri-tools.yml @@ -0,0 +1,16 @@ +--- + +- name: clone cri-tools source repo + git: + repo: "https://github.com/kubernetes-incubator/cri-tools.git" + dest: "{{ ansible_env.GOPATH }}/src/github.com/kubernetes-incubator/cri-tools" + version: "16e6fe4d7199c5689db4630a9330e6a8a12cecd1" + +- name: install crictl + command: "/usr/bin/go install github.com/kubernetes-incubator/cri-tools/cmd/crictl" + +- name: link crictl + file: + src: "{{ ansible_env.GOPATH }}/bin/crictl" + dest: /usr/bin/crictl + state: link diff --git a/contrib/test/integration/build/kubernetes.yml b/contrib/test/integration/build/kubernetes.yml new file mode 100644 index 000000000..206cba448 --- /dev/null +++ b/contrib/test/integration/build/kubernetes.yml @@ -0,0 +1,63 @@ +--- + +- name: clone kubernetes source repo + git: + repo: "https://github.com/runcom/kubernetes.git" + dest: "{{ ansible_env.GOPATH }}/src/k8s.io/kubernetes" + version: "cri-o-node-e2e-patched" + +- name: install etcd + command: "hack/install-etcd.sh" + args: + chdir: "{{ ansible_env.GOPATH }}/src/k8s.io/kubernetes" + +- name: build kubernetes + make: + chdir: "{{ ansible_env.GOPATH }}/src/k8s.io/kubernetes" + +- name: Add custom cluster service file for the e2e testing + copy: + dest: /etc/systemd/system/customcluster.service + content: | + [Unit] + After=network-online.target + Wants=network-online.target + [Service] + WorkingDirectory={{ ansible_env.GOPATH }}/src/k8s.io/kubernetes + ExecStart=/usr/local/bin/createcluster.sh + User=root + [Install] + WantedBy=multi-user.target + +- name: Add create cluster background script for e2e testing + copy: + dest: /usr/local/bin/createcluster.sh + content: | + #!/bin/bash + + export PATH=/usr/local/go/bin:/usr/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/root/bin:{{ ansible_env.GOPATH }}/bin:{{ ansible_env.GOPATH }}/src/k8s.io/kubernetes/third_party/etcd:{{ ansible_env.GOPATH }}/src/k8s.io/kubernetes/_output/local/bin/linux/amd64/ + export CONTAINER_RUNTIME=remote + export CGROUP_DRIVER=systemd + export CONTAINER_RUNTIME_ENDPOINT='/var/run/crio.sock --runtime-request-timeout=5m' + export ALLOW_SECURITY_CONTEXT="," + export ALLOW_PRIVILEGED=1 + export DNS_SERVER_IP={{ ansible_eth0.ipv4.address }} + export API_HOST={{ ansible_eth0.ipv4.address }} + export API_HOST_IP={{ ansible_eth0.ipv4.address }} + export KUBE_ENABLE_CLUSTER_DNS=true + ./hack/local-up-cluster.sh + mode: "u=rwx,g=rwx,o=x" + +- name: Set kubernetes_provider to be local + lineinfile: + dest: /etc/environment + line: 'KUBERNETES_PROVIDER=local' + regexp: 'KUBERNETES_PROVIDER=' + state: present + +- name: Set KUBECONFIG + lineinfile: + dest: /etc/environment + line: 'KUBECONFIG=/var/run/kubernetes/admin.kubeconfig' + regexp: 'KUBECONFIG=' + state: present diff --git a/contrib/test/integration/build/plugins.yml b/contrib/test/integration/build/plugins.yml new file mode 100644 index 000000000..e342a0b91 --- /dev/null +++ b/contrib/test/integration/build/plugins.yml @@ -0,0 +1,50 @@ +--- + +- name: clone plugins source repo + git: + repo: "https://github.com/containernetworking/plugins.git" + dest: "{{ ansible_env.GOPATH }}/src/github.com/containernetworking/plugins" + version: "dcf7368eeab15e2affc6256f0bb1e84dd46a34de" + +- name: build plugins + command: "./build.sh" + args: + chdir: "{{ ansible_env.GOPATH }}/src/github.com/containernetworking/plugins" + +- name: install plugins + copy: + src: "{{ ansible_env.GOPATH }}/src/github.com/containernetworking/plugins/bin/{{ item }}" + dest: "/opt/cni/bin" + mode: "o=rwx,g=rx,o=rx" + remote_src: yes + with_items: + - bridge + - dhcp + - flannel + - host-local + - ipvlan + - loopback + - macvlan + - ptp + - sample + - tuning + - vlan + +- name: clone runcom plugins source repo + git: + repo: "https://github.com/runcom/plugins.git" + dest: "{{ ansible_env.GOPATH }}/src/github.com/containernetworking/plugins" + version: "custom-bridge" + force: yes + +- name: build plugins + command: "./build.sh" + args: + chdir: "{{ ansible_env.GOPATH }}/src/github.com/containernetworking/plugins" + +- name: install custom bridge + copy: + src: "{{ ansible_env.GOPATH }}/src/github.com/containernetworking/plugins/bin/bridge" + dest: "/opt/cni/bin/bridge-custom" + mode: "o=rwx,g=rx,o=rx" + remote_src: yes diff --git a/contrib/test/integration/build/runc.yml b/contrib/test/integration/build/runc.yml new file mode 100644 index 000000000..7bb0491d4 --- /dev/null +++ b/contrib/test/integration/build/runc.yml @@ -0,0 +1,23 @@ +--- + +- name: clone runc source repo + git: + repo: "https://github.com/opencontainers/runc.git" + dest: "{{ ansible_env.GOPATH }}/src/github.com/opencontainers/runc" + version: "84a082bfef6f932de921437815355186db37aeb1" + +- name: build runc + make: + params: BUILDTAGS="seccomp selinux" + chdir: "{{ ansible_env.GOPATH }}/src/github.com/opencontainers/runc" + +- name: install runc + make: + target: "install" + chdir: "{{ ansible_env.GOPATH }}/src/github.com/opencontainers/runc" + +- name: link runc + file: + src: /usr/local/sbin/runc + dest: /usr/bin/runc + state: link diff --git a/contrib/test/integration/callback_plugins/default.py b/contrib/test/integration/callback_plugins/default.py new file mode 100644 index 000000000..99821f660 --- /dev/null +++ b/contrib/test/integration/callback_plugins/default.py @@ -0,0 +1,156 @@ +'''Plugin to override the default output logic.''' + +# upstream: https://gist.github.com/cliffano/9868180 + +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + + +# For some reason this has to be done +import imp +import os + +ANSIBLE_PATH = imp.find_module('ansible')[1] +DEFAULT_PATH = os.path.join(ANSIBLE_PATH, 'plugins/callback/default.py') +DEFAULT_MODULE = imp.load_source( + 'ansible.plugins.callback.default', + DEFAULT_PATH +) + +try: + from ansible.plugins.callback import CallbackBase + BASECLASS = CallbackBase +except ImportError: # < ansible 2.1 + BASECLASS = DEFAULT_MODULE.CallbackModule + + +class CallbackModule(DEFAULT_MODULE.CallbackModule): # pylint: disable=too-few-public-methods,no-init + ''' + Override for the default callback module. + + Render std err/out outside of the rest of the result which it prints with + indentation. + ''' + CALLBACK_VERSION = 2.0 + CALLBACK_TYPE = 'stdout' + CALLBACK_NAME = 'default' + + def __init__(self, *args, **kwargs): + # pylint: disable=non-parent-init-called + BASECLASS.__init__(self, *args, **kwargs) + self.failed_task = [] + self.result_file = os.environ.get('AHT_RESULT_FILE') + + def _dump_results(self, result): + '''Return the text to output for a result.''' + result['_ansible_verbose_always'] = True + + save = {} + for key in ['stdout', 'stdout_lines', 'stderr', 'stderr_lines', 'msg']: + if key in result: + save[key] = result.pop(key) + + output = BASECLASS._dump_results(self, result) # pylint: disable=protected-access + + for key in ['stdout', 'stderr', 'msg']: + if key in save and save[key]: + output += '\n\n%s:\n---\n%s\n---' % (key.upper(), save[key]) + + for key, value in save.items(): + result[key] = value + + return output + + def v2_runner_on_unreachable(self, result): + self.failed_task = result + + if self._play.strategy == 'free' and self._last_task_banner != result._task._uuid: + self._print_task_banner(result._task) + + delegated_vars = result._result.get('_ansible_delegated_vars', None) + if delegated_vars: + self._display.display("fatal: [%s -> %s]: UNREACHABLE! => %s" % (result._host.get_name(), delegated_vars['ansible_host'], self._dump_results(result._result)), color=C.COLOR_UNREACHABLE) + else: + self._display.display("fatal: [%s]: UNREACHABLE! => %s" % (result._host.get_name(), self._dump_results(result._result)), color=C.COLOR_UNREACHABLE) + + def v2_runner_on_failed(self,result, ignore_errors=False): + if ignore_errors is not True: + # Sets environment variable for test failures for use in playboks. + # Handlers tasks can conditionalize themselves using this variable + # to run only on failure. + os.environ["AHT_FAILURE"] = "1" + + # Save last failure + self.failed_task = result + + if self._play.strategy == 'free' and self._last_task_banner != result._task._uuid: + self._print_task_banner(result._task) + + delegated_vars = result._result.get('_ansible_delegated_vars', None) + if 'exception' in result._result: + if self._display.verbosity < 3: + # extract just the actual error message from the exception text + error = result._result['exception'].strip().split('\n')[-1] + msg = "An exception occurred during task execution. To see the full traceback, use -vvv. The error was: %s" % error + else: + msg = "An exception occurred during task execution. The full traceback is:\n" + result._result['exception'] + + self._display.display(msg, color=C.COLOR_ERROR) + + if result._task.loop and 'results' in result._result: + self._process_items(result) + + else: + if delegated_vars: + self._display.display("fatal: [%s -> %s]: FAILED! => %s" % (result._host.get_name(), delegated_vars['ansible_host'], self._dump_results(result._result)), color=C.COLOR_ERROR) + else: + self._display.display("fatal: [%s]: FAILED! => %s" % (result._host.get_name(), self._dump_results(result._result)), color=C.COLOR_ERROR) + + if ignore_errors: + self._display.display("...ignoring", color=C.COLOR_SKIP) + + def v2_playbook_on_stats(self, stats): + self._display.banner("PLAY RECAP") + + hosts = sorted(stats.processed.keys()) + for h in hosts: + t = stats.summarize(h) + + self._display.display(u"%s : %s %s %s %s" % ( + hostcolor(h, t), + colorize(u'ok', t['ok'], C.COLOR_OK), + colorize(u'changed', t['changed'], C.COLOR_CHANGED), + colorize(u'unreachable', t['unreachable'], C.COLOR_UNREACHABLE), + colorize(u'failed', t['failures'], C.COLOR_ERROR)), + screen_only=True + ) + + self._display.display(u"%s : %s %s %s %s" % ( + hostcolor(h, t, False), + colorize(u'ok', t['ok'], None), + colorize(u'changed', t['changed'], None), + colorize(u'unreachable', t['unreachable'], None), + colorize(u'failed', t['failures'], None)), + log_only=True + ) + + self._display.display("", screen_only=True) + # Save result to file if environment variable exists + if self.result_file is not None: + if self.failed_task: + with open(self.result_file, 'w') as f: + f.write("PLAY: %s\n%s\n%s" % (self._play, \ + self.failed_task._task, \ + self._dump_results(self.failed_task._result))) + else: + open(self.result_file, 'w').close() diff --git a/contrib/test/integration/e2e.yml b/contrib/test/integration/e2e.yml new file mode 100644 index 000000000..5c4d656ef --- /dev/null +++ b/contrib/test/integration/e2e.yml @@ -0,0 +1,57 @@ +--- + +- name: enable and start CRI-O + systemd: + name: crio + state: started + enabled: yes + daemon_reload: yes + +- name: update the server address for the custom cluster + lineinfile: + dest: /usr/local/bin/createcluster.sh + line: "export {{ item }}={{ ansible_eth0.ipv4.address }}" + regexp: "^export {{ item }}=" + state: present + with_items: + - DNS_SERVER_IP + - API_HOST + - API_HOST_IP + +- name: enable and start the custom cluster + systemd: + name: customcluster.service + state: started + enabled: yes + daemon_reload: yes + +- name: wait for the cluster to be running + command: "{{ ansible_env.GOPATH }}/src/k8s.io/kubernetes/_output/bin/kubectl get service kubernetes --namespace default" + register: kube_poll + until: kube_poll | succeeded + retries: 100 + delay: 30 + +- name: ensure directory exists for e2e reports + file: + path: "{{ artifacts }}" + state: directory + +- name: Buffer the e2e testing command to workaround Ansible YAML folding "feature" + set_fact: + e2e_shell_cmd: > + /usr/bin/go run hack/e2e.go + --test + --test_args="-host=https://{{ ansible_default_ipv4.address }}:6443 + --ginkgo.focus=\[Conformance\] + --report-dir={{ artifacts }}" + &> {{ artifacts }}/e2e.log + # Fix vim syntax hilighting: " + +- name: disable SELinux + command: setenforce 0 + +- name: run e2e tests + shell: "{{ e2e_shell_cmd | regex_replace('\\s+', ' ') }}" + args: + chdir: "{{ ansible_env.GOPATH }}/src/k8s.io/kubernetes" diff --git a/contrib/test/integration/golang.yml b/contrib/test/integration/golang.yml new file mode 100644 index 000000000..63e556977 --- /dev/null +++ b/contrib/test/integration/golang.yml @@ -0,0 +1,51 @@ +--- + +- name: fetch Golang + unarchive: + remote_src: yes + src: https://storage.googleapis.com/golang/go1.8.4.linux-amd64.tar.gz + dest: /usr/local + +- name: link go toolchain + file: + src: "/usr/local/go/bin/{{ item }}" + dest: "/usr/bin/{{ item }}" + state: link + with_items: + - go + - gofmt + - godoc + +- name: ensure user profile exists + file: + path: "{{ ansible_user_dir }}/.profile" + state: touch + +- name: set up PATH for Go toolchain and built binaries + lineinfile: + dest: "{{ ansible_user_dir }}/.profile" + line: 'PATH={{ ansible_env.PATH }}:{{ ansible_env.GOPATH }}/bin:/usr/local/go/bin' + regexp: '^PATH=' + state: present + +- name: set up directories + file: + path: "{{ item }}" + state: directory + with_items: + - "{{ ansible_env.GOPATH }}/src/github.com/containernetworking" + - "{{ ansible_env.GOPATH }}/src/github.com/kubernetes-incubator" + - "{{ ansible_env.GOPATH }}/src/github.com/k8s.io" + - "{{ ansible_env.GOPATH }}/src/github.com/sstephenson" + - "{{ ansible_env.GOPATH }}/src/github.com/opencontainers" + +- name: install Go tools and dependencies + shell: /usr/bin/go get -u "github.com/{{ item }}" + with_items: + - tools/godep + - onsi/ginkgo/ginkgo + - onsi/gomega + - cloudflare/cfssl/cmd/... + - jteeuwen/go-bindata/go-bindata + - vbatts/git-validation + - cpuguy83/go-md2man diff --git a/contrib/test/integration/main.yml b/contrib/test/integration/main.yml new file mode 100644 index 000000000..ce4a206fb --- /dev/null +++ b/contrib/test/integration/main.yml @@ -0,0 +1,58 @@ +- hosts: all + remote_user: root + vars_files: + - "{{ playbook_dir }}/vars.yml" + tags: + - setup + tasks: + - name: set up the system + include: system.yml + + - name: install Golang tools + include: golang.yml + + - name: clone build and install bats + include: "build/bats.yml" + + - name: clone build and install cri-tools + include: "build/cri-tools.yml" + + - name: clone build and install kubernetes + include: "build/kubernetes.yml" + + - name: clone build and install runc + include: "build/runc.yml" + + - name: clone build and install networking plugins + include: "build/plugins.yml" + +- hosts: all + remote_user: root + vars_files: + - "{{ playbook_dir }}/vars.yml" + tags: + - integration + - e2e + tasks: + - name: clone build and install cri-o + include: "build/cri-o.yml" + +- hosts: all + remote_user: root + vars_files: + - "{{ playbook_dir }}/vars.yml" + tags: + - integration + tasks: + - name: run cri-o integration tests + include: test.yml + +- hosts: all + remote_user: root + vars_files: + - "{{ playbook_dir }}/vars.yml" + tags: + - e2e + tasks: + - name: run k8s e2e tests + include: e2e.yml diff --git a/contrib/test/integration/results.yml b/contrib/test/integration/results.yml new file mode 100644 index 000000000..c9a96abb1 --- /dev/null +++ b/contrib/test/integration/results.yml @@ -0,0 +1,62 @@ +--- +# vim-syntax: ansible + +- hosts: '{{ hosts | default("all") }}' + vars_files: + - "{{ playbook_dir }}/vars.yml" + vars: + _result_filepaths: [] # do not use + _dstfnbuff: [] # do not use + tasks: + - name: The crio_integration_filepath is required + tags: + - integration + set_fact: + _result_filepaths: "{{ _result_filepaths + [crio_integration_filepath] }}" + + - name: The crio_node_e2e_filepath is required + tags: + - e2e + set_fact: + _result_filepaths: "{{ _result_filepaths + [crio_node_e2e_filepath] }}" + + - name: Verify expectations + assert: + that: + - 'result_dest_basedir | default(False, True)' + - '_result_filepaths | default(False, True)' + - '_dstfnbuff == []' + - 'results_fetched is undefined' + + - name: Results directory exists + file: + path: "{{ result_dest_basedir }}" + state: directory + delegate_to: localhost + + - name: destination file paths are buffered for overwrite-checking and jUnit conversion + set_fact: + _dstfnbuff: > + {{ _dstfnbuff | + union( [result_dest_basedir ~ "/" ~ inventory_hostname ~ "/" ~ item | basename] ) }} + with_items: '{{ _result_filepaths }}' + + - name: Overwriting existing results assumed very very bad + fail: + msg: "Cowardly refusing to overwrite {{ item }}" + when: item | exists + delegate_to: localhost + with_items: '{{ _dstfnbuff }}' + + # fetch module doesn't support directories + - name: Retrieve results from all hosts + synchronize: + checksum: True # Don't rely on date/time being in sync + archive: False # Don't bother with permissions or times + copy_links: True # We want files, not links to files + recursive: True + mode: pull + dest: '{{ result_dest_basedir }}/{{ inventory_hostname }}/' # must end in / + src: '{{ item }}' + register: results_fetched + with_items: '{{ _result_filepaths }}' diff --git a/contrib/test/integration/system.yml b/contrib/test/integration/system.yml new file mode 100644 index 000000000..d07ae0c82 --- /dev/null +++ b/contrib/test/integration/system.yml @@ -0,0 +1,117 @@ +--- + +- name: Make sure we have all required packages + package: + name: "{{ item }}" + state: present + with_items: + - container-selinux + - curl + - device-mapper-devel + - expect + - findutils + - gcc + - git + - glib2-devel + - glibc-devel + - glibc-static + - gpgme-devel + - hostname + - iproute + - iptables + - krb5-workstation + - libassuan-devel + - libffi-devel + - libgpg-error-devel + - libguestfs-tools + - libseccomp-devel + - libvirt-client + - libvirt-python + - libxml2-devel + - libxslt-devel + - make + - mlocate + - nfs-utils + - nmap-ncat + - oci-register-machine + - oci-systemd-hook + - oci-umount + - openssl + - openssl-devel + - ostree-devel + - pkgconfig + - python + - python2-boto + - python2-crypto + - python-devel + - python-virtualenv + - PyYAML + - redhat-rpm-config + - rpcbind + - rsync + - sed + - skopeo-containers + - socat + - tar + - wget + async: 600 + poll: 10 + +- name: Add Btrfs for Fedora + package: + name: "{{ item }}" + state: present + with_items: + - btrfs-progs-devel + when: ansible_distribution in ['Fedora'] + +- name: Update all packages + package: + name: '*' + state: latest + async: 600 + poll: 10 + +- name: Setup swap to prevent kernel firing off the OOM killer + shell: | + truncate -s 8G /root/swap && \ + export SWAPDEV=$(losetup --show -f /root/swap | head -1) && \ + mkswap $SWAPDEV && \ + swapon $SWAPDEV && \ + swapon --show + +- name: ensure directories exist as needed + file: + path: "{{ item }}" + state: directory + with_items: + - /opt/cni/bin + - /etc/cni/net.d + +- name: set sysctl vm.overcommit_memory=1 for CentOS + sysctl: + name: vm.overcommit_memory + state: present + value: 1 + when: ansible_distribution == 'CentOS' + +- name: inject hostname into /etc/hosts + lineinfile: + dest: /etc/hosts + line: '{{ ansible_default_ipv4.address }} {{ ansible_nodename }}' + insertafter: 'EOF' + regexp: '{{ ansible_default_ipv4.address }}\s+{{ ansible_nodename }}' + state: present + +- name: Flush the iptables + command: iptables -F + +- name: Enable localnet routing + command: sysctl -w net.ipv4.conf.all.route_localnet=1 + +- name: Add masquerade for localhost + command: iptables -t nat -I POSTROUTING -s 127.0.0.1 ! -d 127.0.0.1 -j MASQUERADE + +- name: Update the kernel cmdline to include quota support + command: grubby --update-kernel=ALL --args="rootflags=pquota" + when: ansible_distribution in ['RedHat', 'CentOS'] diff --git a/contrib/test/integration/test.yml b/contrib/test/integration/test.yml new file mode 100644 index 000000000..418ceff78 --- /dev/null +++ b/contrib/test/integration/test.yml @@ -0,0 +1,25 @@ +--- + +- name: Make testing output verbose so it can be converted to xunit + lineinfile: + dest: "{{ ansible_env.GOPATH }}/src/k8s.io/kubernetes/hack/make-rules/test.sh" + line: ' go test -v "${goflags[@]:+${goflags[@]}}" \' + regexp: ' go test \"\$' + state: present + +- name: set extra storage options + set_fact: + extra_storage_opts: " --storage-opt overlay.override_kernel_check=1" + when: ansible_distribution == 'RedHat' or ansible_distribution == 'CentOS' + +- name: ensure directory exists for e2e reports + file: + path: "{{ artifacts }}" + state: directory + +- name: run integration tests + shell: "CGROUP_MANAGER=cgroupfs STORAGE_OPTIONS='--storage-driver=overlay{{ extra_storage_opts | default('') }}' make localintegration >& {{ artifacts }}/testout.txt" + args: + chdir: "{{ ansible_env.GOPATH }}/src/github.com/kubernetes-incubator/cri-o" + async: 5400 + poll: 30 diff --git a/contrib/test/integration/vars.yml b/contrib/test/integration/vars.yml new file mode 100644 index 000000000..f1e5e2f73 --- /dev/null +++ b/contrib/test/integration/vars.yml @@ -0,0 +1,8 @@ +--- + +# For results.yml Paths use rsync 'source' conventions +artifacts: "/tmp/artifacts" # Base-directory for collection +crio_integration_filepath: "{{ artifacts }}/testout.txt" +crio_node_e2e_filepath: "{{ artifacts }}/junit_01.xml" +result_dest_basedir: '{{ lookup("env","WORKSPACE") | + default(playbook_dir, True) }}/artifacts' diff --git a/contrib/test/requirements.txt b/contrib/test/requirements.txt new file mode 100644 index 000000000..4dc4531b0 --- /dev/null +++ b/contrib/test/requirements.txt @@ -0,0 +1,54 @@ +# Pip requirements file for Ansible-based integration-testing environment. +# Intended to be utilized by venv-ansible-playbook.sh script +# +# N/B: Hashes are required here | versions frozen for stability + +ansible==2.3.1.0 --hash=sha256:cd4b8f53720fcd0c351156b840fdd15ecfbec22c951b5406ec503de49d40b9f5 + +asn1crypto==0.22.0 --hash=sha256:d232509fefcfcdb9a331f37e9c9dc20441019ad927c7d2176cf18ed5da0ba097 \ + --hash=sha256:cbbadd640d3165ab24b06ef25d1dca09a3441611ac15f6a6b452474fdf0aed1a + +bcrypt==3.1.3 --hash=sha256:05b35b9842b009b44496fa5433ce462f69966291e50fbd471dbb427f399f748f \ + --hash=sha256:6645c8d0ad845308de3eb9be98b6fd22a46ec5412bfc664a423e411cdd8f5488 + +cffi==1.10.0 --hash=sha256:c49187260043bd4c1d6a52186f9774f17d9b1da0a406798ebf4bfc12da166ade \ + --hash=sha256:b3b02911eb1f6ada203b0763ba924234629b51586f72a21faacc638269f4ced5 + +cryptography==1.9 --hash=sha256:5518337022718029e367d982642f3e3523541e098ad671672a90b82474c84882 + +enum34==1.1.6 --hash=sha256:6bd0f6ad48ec2aa117d3d141940d484deccda84d4fcd884f5c3d93c23ecd8c79 \ + --hash=sha256:8ad8c4783bf61ded74527bffb48ed9b54166685e4230386a9ed9b1279e2df5b1 + +idna==2.5 --hash=sha256:cc19709fd6d0cbfed39ea875d29ba6d4e22c0cebc510a76d6302a28385e8bb70 \ + --hash=sha256:3cb5ce08046c4e3a560fc02f138d0ac63e00f8ce5901a56b32ec8b7994082aab + +ipaddress==1.0.18 --hash=sha256:d34cf15d95ce9a734560f7400a8bd2ac2606f378e2a1d0eadbf1c98707e7c74a \ + --hash=sha256:5d8534c8e185f2d8a1fda1ef73f2c8f4b23264e8e30063feeb9511d492a413e1 + +Jinja2==2.9.6 --hash=sha256:2231bace0dfd8d2bf1e5d7e41239c06c9e0ded46e70cc1094a0aa64b0afeb054 \ + --hash=sha256:ddaa01a212cd6d641401cb01b605f4a4d9f37bfc93043d7f760ec70fb99ff9ff + +MarkupSafe==1.0 --hash=sha256:a6be69091dac236ea9c6bc7d012beab42010fa914c459791d627dad4910eb665 + +paramiko==2.2.1 --hash=sha256:9c9402377ba8594889aab1e44a13b78eda685eb2145dc00b2353b4fbb25088cf \ + --hash=sha256:ff94ae65379914ec3c960de731381f49092057b6dd1d24d18842ead5a2eb2277 + +pyasn1==0.2.3 --hash=sha256:0439b9bd518418260c2641a571f0e07fce4370cab13b68f19b5e023306c03cad \ + --hash=sha256:738c4ebd88a718e700ee35c8d129acce2286542daa80a82823a7073644f706ad + +pycparser==2.17 --hash=sha256:0aac31e917c24cb3357f5a4d5566f2cc91a19ca41862f6c3c22dc60a629673b6 + +pycrypto==2.6.1 --hash=sha256:f2ce1e989b272cfcb677616763e0a2e7ec659effa67a88aa92b3a65528f60a3c + +PyNaCl==1.1.2 --hash=sha256:57314a7bad4bd39501dc622942f9921923673e52e126b0fc4f0214b5d25d619a \ + --hash=sha256:32f52b754abf07c319c04ce16905109cab44b0e7f7c79497431d3b2000f8af8c + +PyYAML==3.12 --hash=sha256:592766c6303207a20efc445587778322d7f73b161bd994f227adaa341ba212ab + +six==1.10.0 --hash=sha256:0ff78c403d9bccf5a425a6d31a12aa6b47f1c21ca4dc2573a7e2f32a97335eb1 \ + --hash=sha256:105f8d68616f8248e24bf0e9372ef04d3cc10104f1980f54d57b2ce73a5ad56a + +virtualenv==15.1.0 --hash=sha256:39d88b533b422825d644087a21e78c45cf5af0ef7a99a1fc9fbb7b481e5c85b0 \ + --hash=sha256:02f8102c2436bb03b3ee6dede1919d1dac8a427541652e5ec95171ec8adbc93a + +pip==9.0.1 --hash=sha256:690b762c0a8460c303c089d5d0be034fb15a5ea2b75bdf565f40421f542fefb0 diff --git a/contrib/test/venv-ansible-playbook.sh b/contrib/test/venv-ansible-playbook.sh new file mode 100755 index 000000000..587042154 --- /dev/null +++ b/contrib/test/venv-ansible-playbook.sh @@ -0,0 +1,106 @@ +#!/bin/bash + +# example usage +# $ ./venv-ansible-playbook.sh \ +# -i 192.168.169.170 \ +# --private-key=/path/to/key \ +# --extra-vars "pullrequest=42" \ +# --extra-vars "commit=abcd1234" \ +# --user root \ +# --verbose \ +# $PWD/crio-integration-playbook.yaml + +# All errors are fatal +set -e + +SCRIPT_PATH=`realpath $(dirname $0)` +REQUIREMENTS="$SCRIPT_PATH/requirements.txt" + +echo + +if ! type -P virtualenv &> /dev/null +then + echo "Could not find required 'virtualenv' binary installed on system." + exit 1 +fi + +if [ "$#" -lt "1" ] +then + echo "No ansible-playbook command-line options specified." + echo "usage: $0 -i whatever --private-key=something --extra-vars foo=bar playbook.yml" + exit 2 +fi + +# Avoid dirtying up repository, keep execution bits confined to a known location +if [ -z "$WORKSPACE" ] || [ ! -d "$WORKSPACE" ] +then + export WORKSPACE="$(mktemp -d)" + echo "Using temporary \$WORKSPACE=\"$WORKSPACE\" for execution environment." + echo "Directory will be removed upon exit. Export this variable with path" + echo "to an existing directory to preserve contents." + trap 'rm -rf "$WORKSPACE"' EXIT +else + echo "Using existing \$WORKSPACE=\"$WORKSPACE\" for execution environment." + echo "Directory will be left as-is upon exit." + # Don't recycle cache, next job may have different requirements + trap 'rm -rf "$PIPCACHE"' EXIT +fi + +# Create a directory to contain logs and test artifacts +export ARTIFACTS=$(mkdir -pv $WORKSPACE/artifacts | tail -1 | cut -d \' -f 2) +[ -d "$ARTIFACTS" ] || exit 3 + +# All command failures from now on are fatal +set -e +echo +echo "Bootstrapping trusted virtual environment, this may take a few minutes, depending on networking." +echo "(logs: \"$ARTIFACTS/crio_venv_setup_log.txt\")" +echo + + +( + set -x + cd "$WORKSPACE" + # When running more than once, make it fast by skipping the bootstrap + if [ ! -d "./.cri-o_venv" ]; then + # N/B: local system's virtualenv binary - uncontrolled version fixed below + virtualenv --no-site-packages --python=python2.7 ./.venvbootstrap + # Set up paths to install/operate out of $WORKSPACE/.venvbootstrap + source ./.venvbootstrap/bin/activate + # N/B: local system's pip binary - uncontrolled version fixed below + # pip may not support --cache-dir, force it's location into $WORKSPACE the ugly-way + OLD_HOME="$HOME" + export HOME="$WORKSPACE" + export PIPCACHE="$WORKSPACE/.cache/pip" + pip install --force-reinstall --upgrade pip==9.0.1 + # Undo --cache-dir workaround + export HOME="$OLD_HOME" + # Install fixed, trusted, hashed versions of all requirements (including pip and virtualenv) + pip --cache-dir="$PIPCACHE" install --require-hashes \ + --requirement "$SCRIPT_PATH/requirements.txt" + + # Setup trusted virtualenv using hashed binary from requirements.txt + ./.venvbootstrap/bin/virtualenv --no-site-packages --python=python2.7 ./.cri-o_venv + # Exit untrusted virtualenv + deactivate + fi + # Enter trusted virtualenv + source ./.cri-o_venv/bin/activate + # Upgrade stock-pip to support hashes + pip install --force-reinstall --cache-dir="$PIPCACHE" --upgrade pip==9.0.1 + # Re-install from cache but validate all hashes (including on pip itself) + pip --cache-dir="$PIPCACHE" install --require-hashes \ + --requirement "$SCRIPT_PATH/requirements.txt" + # Remove temporary bootstrap virtualenv + rm -rf ./.venvbootstrap + # Exit trusted virtualenv + +) &> $ARTIFACTS/crio_venv_setup_log.txt; + +echo +echo "Executing \"$WORKSPACE/.cri-o_venv/bin/ansible-playbook $@\"" +echo + +# Execute command-line arguments under virtualenv +source ${WORKSPACE}/.cri-o_venv/bin/activate +${WORKSPACE}/.cri-o_venv/bin/ansible-playbook $@ |