#!/bin/bash # # Script for launching the Docker integration tests # XXX: We currently only support running integration-cli. # set -Eeuo pipefail DOCKER_DIR=/usr/src/docker SCRIPTS_DIR="$DOCKER_DIR/hack" TESTS_EXE="$DOCKER_DIR/integration-cli/tests.main" VERSION="$(cat "$DOCKER_DIR/VERSION")" # working dirs TESTS_DIR=/tmp/docker-int-tests FROZEN_IMAGES=/docker-frozen-images BUNDLES_DIR="$TESTS_DIR/run/bundles" CHECK_TIMEOUT="${CHECK_TIMEOUT:-5m}" TEST_TIMEOUT="${TEST_TIMEOUT:-60m}" TEST_ARGS=("-check.v" "-check.timeout=${CHECK_TIMEOUT}" "-test.timeout=${TEST_TIMEOUT}") TEST_SELECT= TEST_LOG=/tmp/docker-tests.log ENABLE_XUNIT="${ENABLE_XUNIT-yes}" KEEPBUNDLE="${KEEPBUNDLE:-}" # the config file for Docker CFG_DOCKER=/etc/docker/daemon.json ################################################################################ log() { echo ">>> $@" ; } warn() { log "WARNING: $@" ; } error() { log "ERROR: $@" ; } abort() { log "FATAL: $@" ; exit 1 ; } usage() { echo "$USAGE" ; } abort_usage() { usage ; abort "$@" ; } bundle() { local bundle="$1"; shift log "Making bundle: $(basename "$bundle") (in $DEST)" local oldFlags="$-" set +Eeu source "$SCRIPTS_DIR/make/$bundle" "$@" set "-$oldFlags" } fix_expected() { EXPECTED="$1" EXISTING="$2" exp_base="$(basename "$EXPECTED")" exp_dir="$(dirname "$EXPECTED")" [ -d "$exp_dir" ] || mkdir -p "$exp_dir" rm -f "$exp_dir/$exp_base" ( cd "$exp_dir" && ln -sf "$EXISTING" "$exp_base" ) } save_backup() { for x in $@ ; do if [ ! -f "$x" ] ; then touch "$x.nbak" elif [ -f "$x.bak" ] ; then warn "$x.bak already exists: no backup will be done" else cp -f "$x" "$x.bak" fi done } restore_backup() { for x in $@ ; do if [ -f "$x.nbak" ] ; then rm -f "$x.nbak" else if [ -f "$x.bak" ] ; then mv -f "$x.bak" "$x" fi fi done } require_go() { go version >/dev/null 2>&1 ; } require_git() { git version >/dev/null 2>&1 ; } ################################################################################ [ -x "$TESTS_EXE" ] || abort "integration tests executable not found at $TESTS_EXE" [ "$EUID" -eq 0 ] || abort "this script must be run as root" [ -n "$VERSION" ] || abort "could not obtain version" if [ "$#" -gt 0 ] ; then # run only some specific tests TEST_SELECT="-check.f=$(echo $@ | tr ' ' '|')" fi # We want this to fail if the bundles already exist and cannot be removed. # This is to avoid mixing bundles from different versions of the code. mkdir -p "$BUNDLES_DIR" if [ -e "$BUNDLES_DIR/$VERSION" ] && [ -z "$KEEPBUNDLE" ]; then log "$BUNDLES_DIR/$VERSION already exists. Removing." rm -fr "$BUNDLES_DIR/$VERSION" && mkdir "$BUNDLES_DIR/$VERSION" || exit 1 echo fi DEST="$BUNDLES_DIR/$VERSION/" mkdir -p "$DEST" export DEST="$(realpath "$DEST")" if [ -n "$ENABLE_XUNIT" ] ; then if [ ! -x /usr/local/bin/go2xunit ] ; then echo >&2 "Installing go2xunit." require_go || abort "the Go compiler is not installed" export GOPATH="$(mktemp -d)" go get -d github.com/tebeka/go2xunit cd "$GOPATH/src/github.com/tebeka/go2xunit" && go build -o /usr/local/bin/go2xunit . chmod 755 /usr/local/bin/go2xunit [ -x /usr/local/bin/go2xunit ] || abort "go2xunit could not be built" rm -rf "$GOPATH" export -n GOPATH fi fi # tests require this user and group /usr/sbin/groupadd -r docker >/dev/null 2>&1 || /bin/true /usr/sbin/useradd --create-home --gid docker unprivilegeduser >/dev/null 2>&1 || /bin/true # prepare some expected dirs, files, etc... fix_expected "$TESTS_DIR/contrib" "$DOCKER_DIR/contrib" fix_expected "$DEST/fixtures" "$DOCKER_DIR/integration-cli/fixtures" fix_expected "$DEST/../Dockerfile" "$DOCKER_DIR/Dockerfile" export DOCKER_TEST_HOST="tcp://127.0.0.1:2375" export PATH="/usr/local/bin:$PATH" export TZ=utc export DOCKER_GRAPHDRIVER="${DOCKER_GRAPHDRIVER:-vfs}" export DOCKER_USERLANDPROXY="${DOCKER_USERLANDPROXY:-true}" export DOCKER_STORAGE_OPTS="${DOCKER_STORAGE_OPTS:-}" export DOCKER_REMAP_ROOT="${DOCKER_REMAP_ROOT:-}" # "default" uses dockremap # Example usage: DOCKER_STORAGE_OPTS="dm.basesize=20G,dm.loopdatasize=200G". storage_opts=() if [ -n "$DOCKER_STORAGE_OPTS" ]; then IFS=',' for i in ${DOCKER_STORAGE_OPTS}; do storage_opts+=("$i") done unset IFS fi # deal with remapping save_backup /etc/subuid /etc/subgid echo "dockremap:500000:65536" >/etc/subuid echo "dockremap:500000:65536" >/etc/subgid groupadd dockremap >/dev/null 2>&1 || /bin/true useradd -g dockremap dockremap >/dev/null 2>&1 || /bin/true # make sure Docker is stopped, set our config file and then start again save_backup "$CFG_DOCKER" cat <"$CFG_DOCKER" { "log-level": "debug", "log-driver": "json-file", "log-opts": { "max-size": "50m", "max-file": "5" }, "userns-remap": "$DOCKER_REMAP_ROOT", "pidfile": "$DEST/docker.pid", "hosts": [ "tcp://127.0.0.1:2375" ], "storage-driver": "$DOCKER_GRAPHDRIVER", "storage-opts": [ $(printf '"%s",' "${storage_opts[@]}" | sed 's/"",//g;$s/,$//') ], "userland-proxy": $DOCKER_USERLANDPROXY } CFG_DOCKER_EOF systemctl restart docker.service cleanup() { log "Restoring the Docker service..." restore_backup "$CFG_DOCKER" systemctl restart docker.service log "Removing extra files and restoring backups..." restore_backup /etc/subuid /etc/subgid rm -f "$TESTS_DIR/contrib" "$DEST/fixtures" rm -rf "$FROZEN_IMAGES" } trap cleanup EXIT cd "$DOCKER_DIR" log "Preparing the environment..." export MAKEDIR="$SCRIPTS_DIR/make" export DOCKER_HOST="$DOCKER_TEST_HOST" bundle .integration-daemon-setup # XXX: Really this should be sourced from the Dockerfile but this is good # enough for now. This comes from the Docker 18.09.1-ce Dockerfile. log "Downlading frozen images..." mkdir -p "$FROZEN_IMAGES" "$DOCKER_DIR/contrib/download-frozen-image-v2.sh" "$FROZEN_IMAGES" \ buildpack-deps:jessie@sha256:dd86dced7c9cd2a724e779730f0a53f93b7ef42228d4344b25ce9a42a1486251 \ busybox:latest@sha256:bbc3a03235220b170ba48a157dd097dd1379299370e1ed99ce976df0355d24f0 \ busybox:glibc@sha256:0b55a30394294ab23b9afd58fab94e61a923f5834fba7ddbae7f8e0c11ba85e6 \ debian:jessie@sha256:287a20c5f73087ab406e6b364833e3fb7b3ae63ca0eb3486555dc27ed32c6e60 \ hello-world:latest@sha256:be0cd392e45be79ffeffa6b05338b98ebb16c87b255f48e297ec7f98e123905c log "Running integration tests..." cd "$DEST" && \ "$TESTS_EXE" "${TEST_ARGS[@]}" $TEST_SELECT 2>&1 | tee "$TEST_LOG" || /bin/true if [ -n "$ENABLE_XUNIT" ] ; then log "Generating xunit logs..." go2xunit -fail -gocheck -input "$TEST_LOG" -output "$TEST_LOG.xml" fi export -n DOCKER_HOST