#!/usr/bin/env bash set -e IMAGE=server CONTAINER=server LINKED_IMAGE=linked LINKED_CONTAINER=linked WATCHTOWER_INTERVAL=2 function remove_container { docker kill $1 >> /dev/null || true && docker rm -v $1 >> /dev/null || true } function cleanup { # Do cleanup on exit or error echo "Final cleanup" sleep 2 remove_container $CONTAINER remove_container $LINKED_CONTAINER pkill -9 -f watchtower >> /dev/null || true } trap cleanup EXIT DEFAULT_WATCHTOWER="$(dirname "${BASH_SOURCE[0]}")/../watchtower" WATCHTOWER=$1 WATCHTOWER=${WATCHTOWER:-$DEFAULT_WATCHTOWER} echo "watchtower path is $WATCHTOWER" ################################################################################## ##### PREPARATION ################################################################ ################################################################################## # Create Dockerfile template DOCKERFILE=$(cat << EOF FROM node:alpine LABEL com.centurylinklabs.watchtower.lifecycle.pre-update="cat /opt/test/value.txt" LABEL com.centurylinklabs.watchtower.lifecycle.post-update="echo image > /opt/test/value.txt" ENV IMAGE_TIMESTAMP=TIMESTAMP WORKDIR /opt/test ENTRYPOINT ["/usr/local/bin/node", "/opt/test/server.js"] EXPOSE 8888 RUN mkdir -p /opt/test && echo "default" > /opt/test/value.txt COPY server.js /opt/test/server.js EOF ) # Create temporary directory to build docker image TMP_DIR="/tmp/watchtower-commands-test" mkdir -p $TMP_DIR # Create simple http server cat > $TMP_DIR/server.js << EOF const http = require("http"); const fs = require("fs"); http.createServer(function(request, response) { const fileContent = fs.readFileSync("/opt/test/value.txt"); response.writeHead(200, {"Content-Type": "text/plain"}); response.write(fileContent); response.end(); }).listen(8888, () => { console.log('server is listening on 8888'); }); EOF function builddocker { TIMESTAMP=$(date +%s) echo "Building image $TIMESTAMP" echo "${DOCKERFILE/TIMESTAMP/$TIMESTAMP}" > $TMP_DIR/Dockerfile docker build $TMP_DIR -t $IMAGE >> /dev/null } # Start watchtower echo "Starting watchtower" $WATCHTOWER -i $WATCHTOWER_INTERVAL --no-pull --stop-timeout 2s --enable-lifecycle-hooks $CONTAINER $LINKED_CONTAINER & sleep 3 echo "#################################################################" echo "##### TEST CASE 1: Execute commands from base image" echo "#################################################################" # Build base image builddocker # Run container docker run -d -p 0.0.0.0:8888:8888 --name $CONTAINER $IMAGE:latest >> /dev/null sleep 1 echo "Container $CONTAINER is running" # Test default value RESP=$(curl -s http://localhost:8888) if [ $RESP != "default" ]; then echo "Default value of container response is invalid" 1>&2 exit 1 fi # Build updated image to trigger watchtower update builddocker WAIT_AMOUNT=$(($WATCHTOWER_INTERVAL * 3)) echo "Wait for $WAIT_AMOUNT seconds" sleep $WAIT_AMOUNT # Test value after post-update-command RESP=$(curl -s http://localhost:8888) if [[ $RESP != "image" ]]; then echo "Value of container response is invalid. Expected: image. Actual: $RESP" exit 1 fi remove_container $CONTAINER echo "#################################################################" echo "##### TEST CASE 2: Execute commands from container and base image" echo "#################################################################" # Build base image builddocker # Run container docker run -d -p 0.0.0.0:8888:8888 \ --label=com.centurylinklabs.watchtower.lifecycle.post-update="echo container > /opt/test/value.txt" \ --name $CONTAINER $IMAGE:latest >> /dev/null sleep 1 echo "Container $CONTAINER is running" # Test default value RESP=$(curl -s http://localhost:8888) if [ $RESP != "default" ]; then echo "Default value of container response is invalid" 1>&2 exit 1 fi # Build updated image to trigger watchtower update builddocker WAIT_AMOUNT=$(($WATCHTOWER_INTERVAL * 3)) echo "Wait for $WAIT_AMOUNT seconds" sleep $WAIT_AMOUNT # Test value after post-update-command RESP=$(curl -s http://localhost:8888) if [[ $RESP != "container" ]]; then echo "Value of container response is invalid. Expected: container. Actual: $RESP" exit 1 fi remove_container $CONTAINER echo "#################################################################" echo "##### TEST CASE 3: Execute commands with a linked container" echo "#################################################################" # Tag the current image to keep a version for the linked container docker tag $IMAGE:latest $LINKED_IMAGE:latest # Build base image builddocker # Run container docker run -d -p 0.0.0.0:8888:8888 \ --label=com.centurylinklabs.watchtower.lifecycle.post-update="echo container > /opt/test/value.txt" \ --name $CONTAINER $IMAGE:latest >> /dev/null docker run -d -p 0.0.0.0:8989:8888 \ --label=com.centurylinklabs.watchtower.lifecycle.post-update="echo container > /opt/test/value.txt" \ --link $CONTAINER \ --name $LINKED_CONTAINER $LINKED_IMAGE:latest >> /dev/null sleep 1 echo "Container $CONTAINER and $LINKED_CONTAINER are running" # Test default value RESP=$(curl -s http://localhost:8888) if [ $RESP != "default" ]; then echo "Default value of container response is invalid" 1>&2 exit 1 fi # Test default value for linked container RESP=$(curl -s http://localhost:8989) if [ $RESP != "default" ]; then echo "Default value of linked container response is invalid" 1>&2 exit 1 fi # Build updated image to trigger watchtower update builddocker WAIT_AMOUNT=$(($WATCHTOWER_INTERVAL * 3)) echo "Wait for $WAIT_AMOUNT seconds" sleep $WAIT_AMOUNT # Test value after post-update-command RESP=$(curl -s http://localhost:8888) if [[ $RESP != "container" ]]; then echo "Value of container response is invalid. Expected: container. Actual: $RESP" exit 1 fi # Test that linked container did not execute pre/post-update-command RESP=$(curl -s http://localhost:8989) if [[ $RESP != "default" ]]; then echo "Value of linked container response is invalid. Expected: default. Actual: $RESP" exit 1 fi