diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 00bb7f43..22cbdcf8 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -24,8 +24,21 @@ that should get you started. ## Running the test suite +Use the test script to run linting checks and then the full test suite: + $ script/test +Tests are run against a Docker daemon inside a container, so that we can test against multiple Docker versions. By default they'll run against only the latest Docker version - set the `DOCKER_VERSIONS` environment variable to "all" to run against all supported versions: + + $ DOCKER_VERSIONS=all script/test + +Arguments to `script/test` are passed through to the `nosetests` executable, so you can specify a test directory, file, module, class or method: + + $ script/test tests/unit + $ script/test tests/unit/cli_test.py + $ script/test tests.integration.service_test + $ script/test tests.integration.service_test:ServiceTest.test_containers + ## Building binaries Linux: diff --git a/Dockerfile b/Dockerfile index ee9fb4a2..d7a6019a 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,5 +1,28 @@ FROM debian:wheezy -RUN apt-get update -qq && apt-get install -qy python python-pip python-dev git && apt-get clean + +RUN set -ex; \ + apt-get update -qq; \ + apt-get install -y \ + python \ + python-pip \ + python-dev \ + git \ + apt-transport-https \ + ca-certificates \ + curl \ + lxc \ + iptables \ + ; \ + rm -rf /var/lib/apt/lists/* + +ENV ALL_DOCKER_VERSIONS 1.3.3 1.4.1 1.5.0 + +RUN set -ex; \ + for v in ${ALL_DOCKER_VERSIONS}; do \ + curl https://get.docker.com/builds/Linux/x86_64/docker-$v -o /usr/local/bin/docker-$v; \ + chmod +x /usr/local/bin/docker-$v; \ + done + RUN useradd -d /home/user -m -s /bin/bash user WORKDIR /code/ diff --git a/script/dind b/script/dind new file mode 100755 index 00000000..f8fae637 --- /dev/null +++ b/script/dind @@ -0,0 +1,88 @@ +#!/bin/bash +set -e + +# DinD: a wrapper script which allows docker to be run inside a docker container. +# Original version by Jerome Petazzoni +# See the blog post: http://blog.docker.com/2013/09/docker-can-now-run-within-docker/ +# +# This script should be executed inside a docker container in privilieged mode +# ('docker run --privileged', introduced in docker 0.6). + +# Usage: dind CMD [ARG...] + +# apparmor sucks and Docker needs to know that it's in a container (c) @tianon +export container=docker + +# First, make sure that cgroups are mounted correctly. +CGROUP=/cgroup + +mkdir -p "$CGROUP" + +if ! mountpoint -q "$CGROUP"; then + mount -n -t tmpfs -o uid=0,gid=0,mode=0755 cgroup $CGROUP || { + echo >&2 'Could not make a tmpfs mount. Did you use --privileged?' + exit 1 + } +fi + +if [ -d /sys/kernel/security ] && ! mountpoint -q /sys/kernel/security; then + mount -t securityfs none /sys/kernel/security || { + echo >&2 'Could not mount /sys/kernel/security.' + echo >&2 'AppArmor detection and -privileged mode might break.' + } +fi + +# Mount the cgroup hierarchies exactly as they are in the parent system. +for SUBSYS in $(cut -d: -f2 /proc/1/cgroup); do + mkdir -p "$CGROUP/$SUBSYS" + if ! mountpoint -q $CGROUP/$SUBSYS; then + mount -n -t cgroup -o "$SUBSYS" cgroup "$CGROUP/$SUBSYS" + fi + + # The two following sections address a bug which manifests itself + # by a cryptic "lxc-start: no ns_cgroup option specified" when + # trying to start containers withina container. + # The bug seems to appear when the cgroup hierarchies are not + # mounted on the exact same directories in the host, and in the + # container. + + # Named, control-less cgroups are mounted with "-o name=foo" + # (and appear as such under /proc//cgroup) but are usually + # mounted on a directory named "foo" (without the "name=" prefix). + # Systemd and OpenRC (and possibly others) both create such a + # cgroup. To avoid the aforementioned bug, we symlink "foo" to + # "name=foo". This shouldn't have any adverse effect. + name="${SUBSYS#name=}" + if [ "$name" != "$SUBSYS" ]; then + ln -s "$SUBSYS" "$CGROUP/$name" + fi + + # Likewise, on at least one system, it has been reported that + # systemd would mount the CPU and CPU accounting controllers + # (respectively "cpu" and "cpuacct") with "-o cpuacct,cpu" + # but on a directory called "cpu,cpuacct" (note the inversion + # in the order of the groups). This tries to work around it. + if [ "$SUBSYS" = 'cpuacct,cpu' ]; then + ln -s "$SUBSYS" "$CGROUP/cpu,cpuacct" + fi +done + +# Note: as I write those lines, the LXC userland tools cannot setup +# a "sub-container" properly if the "devices" cgroup is not in its +# own hierarchy. Let's detect this and issue a warning. +if ! grep -q :devices: /proc/1/cgroup; then + echo >&2 'WARNING: the "devices" cgroup should be in its own hierarchy.' +fi +if ! grep -qw devices /proc/1/cgroup; then + echo >&2 'WARNING: it looks like the "devices" cgroup is not mounted.' +fi + +# Mount /tmp +mount -t tmpfs none /tmp + +if [ $# -gt 0 ]; then + exec "$@" +fi + +echo >&2 'ERROR: No command specified.' +echo >&2 'You probably want to run hack/make.sh, or maybe a shell?' diff --git a/script/test b/script/test index fef16b80..f278023a 100755 --- a/script/test +++ b/script/test @@ -1,5 +1,16 @@ -#!/bin/sh +#!/bin/bash +# See CONTRIBUTING.md for usage. + set -ex -docker build -t docker-compose . -docker run -v /var/run/docker.sock:/var/run/docker.sock --rm --entrypoint flake8 docker-compose compose -docker run -v /var/run/docker.sock:/var/run/docker.sock --rm --entrypoint nosetests docker-compose $@ + +TAG="docker-compose:$(git rev-parse --short HEAD)" + +docker build -t "$TAG" . +docker run \ + --rm \ + --volume="/var/run/docker.sock:/var/run/docker.sock" \ + -e DOCKER_VERSIONS \ + -e "TAG=$TAG" \ + --entrypoint="script/test-versions" \ + "$TAG" \ + "$@" diff --git a/script/test-versions b/script/test-versions new file mode 100755 index 00000000..9f30eeca --- /dev/null +++ b/script/test-versions @@ -0,0 +1,26 @@ +#!/bin/bash +# This should be run inside a container built from the Dockerfile +# at the root of the repo - script/test will do it automatically. + +set -e + +>&2 echo "Running lint checks" +flake8 compose + +if [ "$DOCKER_VERSIONS" == "" ]; then + DOCKER_VERSIONS="1.5.0" +elif [ "$DOCKER_VERSIONS" == "all" ]; then + DOCKER_VERSIONS="$ALL_DOCKER_VERSIONS" +fi + +for version in $DOCKER_VERSIONS; do + >&2 echo "Running tests against Docker $version" + docker-1.5.0 run \ + --rm \ + --privileged \ + --volume="/var/lib/docker" \ + -e "DOCKER_VERSION=$version" \ + --entrypoint="script/dind" \ + "$TAG" \ + script/wrapdocker nosetests "$@" +done diff --git a/script/wrapdocker b/script/wrapdocker new file mode 100755 index 00000000..20dc9e3c --- /dev/null +++ b/script/wrapdocker @@ -0,0 +1,20 @@ +#!/bin/bash + +if [ "$DOCKER_VERSION" == "" ]; then + DOCKER_VERSION="1.5.0" +fi + +ln -s "/usr/local/bin/docker-$DOCKER_VERSION" "/usr/local/bin/docker" + +# If a pidfile is still around (for example after a container restart), +# delete it so that docker can start. +rm -rf /var/run/docker.pid +docker -d $DOCKER_DAEMON_ARGS &>/var/log/docker.log & + +>&2 echo "Waiting for Docker to start..." +while ! docker ps &>/dev/null; do + sleep 1 +done + +>&2 echo ">" "$@" +exec "$@"