diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 00000000..a724b900 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,48 @@ +dist: trusty +sudo: required + +language: bash + +addons: + hosts: + - www.example1.com + - example1.com + - example2.wtf + - boulder + +env: + global: + - IMAGE=jrcs/letsencrypt-nginx-proxy-companion + - NGINX_CONTAINER_NAME=nginx-proxy + - DOCKER_GEN_CONTAINER_NAME=nginx-proxy-gen + - LETSENCRYPT_CONTAINER_NAME=nginx-proxy-le + matrix: + - SETUP=2containers TEST_DOMAINS=www.example1.com + - SETUP=3containers TEST_DOMAINS=www.example1.com + - SETUP=2containers TEST_DOMAINS="www.example1.com,example1.com,example2.wtf" + - SETUP=3containers TEST_DOMAINS="www.example1.com,example1.com,example2.wtf" + +before_install: + - sudo rm /usr/local/bin/docker-compose + - curl -L https://github.com/docker/compose/releases/download/1.16.1/docker-compose-`uname -s`-`uname -m` > docker-compose.temp + - chmod +x docker-compose.temp + - sudo mv docker-compose.temp /usr/local/bin/docker-compose + +install: + - docker build -t "$IMAGE" . + - docker inspect "$IMAGE" + - docker run --rm "$IMAGE" simp_le --version + - docker run --rm "$IMAGE" simp_le -v --test + - docker images + +before_script: + - git clone https://github.com/docker-library/official-images.git official-images + - tests/setup-boulder.sh + - tests/setup-nginx-proxy.sh $SETUP + +script: + - official-images/test/run.sh "$IMAGE" + - tests/test.sh $SETUP + +after_failure: + - tests/after-failure.sh $SETUP diff --git a/README.md b/README.md index 74732017..a8bc5661 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,4 @@ +[![Build Status](https://travis-ci.org/JrCs/docker-letsencrypt-nginx-proxy-companion.svg?branch=master)](https://travis-ci.org/JrCs/docker-letsencrypt-nginx-proxy-companion) [![](https://images.microbadger.com/badges/version/jrcs/letsencrypt-nginx-proxy-companion.svg)](https://hub.docker.com/r/jrcs/letsencrypt-nginx-proxy-companion "Click to view the image on Docker Hub") [![](https://images.microbadger.com/badges/image/jrcs/letsencrypt-nginx-proxy-companion.svg)](https://hub.docker.com/r/jrcs/letsencrypt-nginx-proxy-companion "Click to view the image on Docker Hub") [![](https://img.shields.io/docker/stars/jrcs/letsencrypt-nginx-proxy-companion.svg)](https://hub.docker.com/r/jrcs/letsencrypt-nginx-proxy-companion "Click to view the image on Docker Hub") diff --git a/tests/after-failure.sh b/tests/after-failure.sh new file mode 100755 index 00000000..4fa6ae94 --- /dev/null +++ b/tests/after-failure.sh @@ -0,0 +1,23 @@ +#!/bin/bash + +set -e + +case $1 in + 2containers) + echo "Logs of $NGINX_CONTAINER_NAME container:" + docker logs $NGINX_CONTAINER_NAME + echo -e "\nLogs of $LETSENCRYPT_CONTAINER_NAME container:" + docker logs $LETSENCRYPT_CONTAINER_NAME + ;; + 3containers) + echo "Logs of $NGINX_CONTAINER_NAME container:" + docker logs $NGINX_CONTAINER_NAME + echo -e "\nLogs of $DOCKER_GEN_CONTAINER_NAME container:" + docker logs $DOCKER_GEN_CONTAINER_NAME + echo -e "\nLogs of $LETSENCRYPT_CONTAINER_NAME container:" + docker logs $LETSENCRYPT_CONTAINER_NAME + ;; + *) + echo "$0 $1: invalid option." + exit 1 +esac diff --git a/tests/setup-boulder.sh b/tests/setup-boulder.sh new file mode 100755 index 00000000..c24df17b --- /dev/null +++ b/tests/setup-boulder.sh @@ -0,0 +1,40 @@ +#!/bin/bash + +set -e + +SERVER=http://localhost:4000/directory + +setup_boulder() { + # Per the boulder README: + nginx_proxy_ip=$(ifconfig docker0 | grep "inet addr:" | cut -d: -f2 | awk '{ print $1}') + + export GOPATH=${TRAVIS_BUILD_DIR}/go + git clone --depth=1 https://github.com/letsencrypt/boulder \ + $GOPATH/src/github.com/letsencrypt/boulder + cd $GOPATH/src/github.com/letsencrypt/boulder + sed --in-place 's/ 5002/ 80/g' test/config/va.json + sed --in-place 's/ 5001/ 443/g' test/config/va.json + docker-compose pull + docker-compose build + docker-compose run \ + -e FAKE_DNS=$nginx_proxy_ip \ + --service-ports \ + boulder & + cd - +} + +wait_for_boulder() { + i=0 + until curl ${SERVER?} >/dev/null 2>&1; do + if [ $i -gt 300 ]; then + echo "Boulder has not started for 5 minutes, timing out." + exit 1 + fi + i=$((i + 5)) + echo "$SERVER : connection refused. Waiting." + sleep 5 + done +} + +setup_boulder +wait_for_boulder diff --git a/tests/setup-nginx-proxy.sh b/tests/setup-nginx-proxy.sh new file mode 100755 index 00000000..ad7eaa18 --- /dev/null +++ b/tests/setup-nginx-proxy.sh @@ -0,0 +1,37 @@ +#!/bin/bash + +set -e + +case $1 in + 2containers) + docker run -d -p 80:80 -p 443:443 \ + --name $NGINX_CONTAINER_NAME \ + -v /etc/nginx/vhost.d \ + -v /usr/share/nginx/html \ + -v /var/run/docker.sock:/tmp/docker.sock:ro \ + jwilder/nginx-proxy + ;; + 3containers) + curl https://raw.githubusercontent.com/jwilder/nginx-proxy/master/nginx.tmpl > ${TRAVIS_BUILD_DIR}/nginx.tmpl + + docker run -d -p 80:80 -p 443:443 \ + --name $NGINX_CONTAINER_NAME \ + -v /etc/nginx/conf.d \ + -v /etc/nginx/certs \ + -v /etc/nginx/vhost.d \ + -v /usr/share/nginx/html \ + nginx:alpine + + docker run -d \ + --name $DOCKER_GEN_CONTAINER_NAME \ + --volumes-from $NGINX_CONTAINER_NAME \ + -v ${TRAVIS_BUILD_DIR}/nginx.tmpl:/etc/docker-gen/templates/nginx.tmpl:ro \ + -v /var/run/docker.sock:/tmp/docker.sock:ro \ + --label com.github.jrcs.letsencrypt_nginx_proxy_companion.docker_gen \ + jwilder/docker-gen \ + -notify-sighup $NGINX_CONTAINER_NAME -watch -wait 5s:30s /etc/docker-gen/templates/nginx.tmpl /etc/nginx/conf.d/default.conf + ;; + *) + echo "$0 $1: invalid option." + exit 1 +esac diff --git a/tests/test-functions.sh b/tests/test-functions.sh new file mode 100755 index 00000000..80fef808 --- /dev/null +++ b/tests/test-functions.sh @@ -0,0 +1,63 @@ +#!/bin/bash + +set -e + +function get_base_domain { + awk -F ',' '{print $1}' <(echo ${1:?}) +} + +function run_le_container { + docker run -d \ + --name ${1:?} \ + --volumes-from ${2:?} \ + -v /var/run/docker.sock:/var/run/docker.sock:ro \ + --add-host boulder:${3:?} \ + -e "DEBUG=true" \ + -e "ACME_CA_URI=http://${3:?}:4000/directory" \ + -e "ACME_TOS_HASH=b16e15764b8bc06c5c3f9f19bc8b99fa48e7894aa5a6ccdad65da49bbf564793" \ + $IMAGE +} + +wait_for_dhparam() { + local i=0 + sleep 1 + echo -n "Waiting for the ${1:?} container to generate a DH parameters file." + until docker exec ${1:?} [ -f /etc/nginx/certs/dhparam.pem ]; do + if [ $i -gt 600 ]; then + echo "DH parameters file was not generated under ten minutes by the ${1:?} container, timing out." + exit 1 + fi + i=$((i + 5)) + sleep 5 + echo -n "." + done + echo " Done." +} + +wait_for_cert() { + local i=0 + echo "Waiting for the ${2:?} container to generate the certificate for ${1:?}." + until docker exec ${2:?} [ -f /etc/nginx/certs/${1:?}/cert.pem ]; do + if [ $i -gt 60 ]; then + echo "Certificate for ${1:?} was not generated under one minute, timing out." + exit 1 + fi + i=$((i + 2)) + sleep 2 + done + echo "Certificate for ${1:?} has been generated." +} + +wait_for_conn() { + local i=0 + echo "Waiting for a successful connection to http://${1:?}" + until curl -k https://${1:?} > /dev/null 2>&1; do + if [ $i -gt 60 ]; then + echo "Could not connect to ${1:?} using https under one minute, timing out." + exit 1 + fi + i=$((i + 2)) + sleep 2 + done + echo "Connection to ${1:?} using https was successfull." +} diff --git a/tests/test.sh b/tests/test.sh new file mode 100755 index 00000000..7aee208a --- /dev/null +++ b/tests/test.sh @@ -0,0 +1,67 @@ +#!/bin/bash + +set -e + +boulder_ip="$(ifconfig docker0 | grep "inet addr:" | cut -d: -f2 | awk '{ print $1}')" + +# shellcheck source=test-functions.sh +source ${TRAVIS_BUILD_DIR}/tests/test-functions.sh + +echo "Starting $LETSENCRYPT_CONTAINER_NAME container." + +case $1 in + 2containers) + run_le_container $LETSENCRYPT_CONTAINER_NAME $NGINX_CONTAINER_NAME $boulder_ip + wait_for_dhparam $LETSENCRYPT_CONTAINER_NAME + ;; + 3containers) + run_le_container $LETSENCRYPT_CONTAINER_NAME $NGINX_CONTAINER_NAME $boulder_ip + wait_for_dhparam $LETSENCRYPT_CONTAINER_NAME + ;; + *) + echo "$0 $1: invalid option." + exit 1 +esac + +echo "Starting test web server for ${TEST_DOMAINS}." + +docker run -d \ + --name webapp-test \ + -e "VIRTUAL_HOST=${TEST_DOMAINS}" \ + -e "VIRTUAL_PORT=80" \ + -e "LETSENCRYPT_HOST=${TEST_DOMAINS}" \ + -e "LETSENCRYPT_EMAIL=foo@bar.com" \ + nginx:alpine + +base_domain=$(get_base_domain "$TEST_DOMAINS") + +wait_for_cert $base_domain $LETSENCRYPT_CONTAINER_NAME + +created_cert="$(docker exec $LETSENCRYPT_CONTAINER_NAME openssl x509 -in /etc/nginx/certs/${base_domain}/cert.pem -text -noout)" + +wait_for_conn $base_domain + +while IFS=',' read -ra DOMAINS; do + for domain in "${DOMAINS[@]}"; do + if grep -q "$domain" <<< "$created_cert"; then + echo "$domain is on certificate." + else + echo "$domain did not appear on certificate." + exit 1 + fi + + served_cert="$(echo \ + | openssl s_client -showcerts -servername $domain -connect $domain:443 2>/dev/null \ + | openssl x509 -inform pem -text -noout)" + + if [ "$created_cert" != "$served_cert" ]; then + echo "Nginx served an incorrect certificate for $domain." + diff -u <"$(echo "$created_cert")" <"$(echo "$served_cert")" + exit 1 + else + echo "The correct certificate for $domain was served by Nginx." + fi + done +done <<< "$TEST_DOMAINS" + +echo "$served_cert"