diff --git a/docs/development/testing.md b/docs/development/testing.md index 5b4d23c67..90ea77a1a 100644 --- a/docs/development/testing.md +++ b/docs/development/testing.md @@ -32,6 +32,9 @@ While we do provide official packages for a variety of platforms, as our test su # run linter & update vagrant Dokku install from local git clone make lint copyfiles + # build a specific plugin + make go-build-plugin copyplugin PLUGIN_NAME=apps + # execute all bats tests make unit-tests diff --git a/plugins/common/functions b/plugins/common/functions index 1aa97ffde..ae16049dc 100755 --- a/plugins/common/functions +++ b/plugins/common/functions @@ -384,7 +384,10 @@ copy_from_image() { fi fi local CID=$(docker create "$DOKKU_GLOBAL_RUN_ARGS" "$IMAGE") - docker cp "$CID:$SRC_FILE" "$DST_DIR" + if ! docker cp "$CID:$SRC_FILE" "$DST_DIR"; then + docker rm -f "$CID" &>/dev/null + return 1 + fi docker rm -f "$CID" &>/dev/null else return 1 diff --git a/plugins/ps/functions b/plugins/ps/functions index 2a8f0cde4..f2de8ed18 100755 --- a/plugins/ps/functions +++ b/plugins/ps/functions @@ -62,7 +62,12 @@ generate_scale_file() { local DOKKU_PROCFILE="$DOKKU_ROOT/$APP/DOKKU_PROCFILE" verify_app_name "$APP" - copy_from_image "$IMAGE" "DOKKU_SCALE" "$DOKKU_ROOT/$APP" 2>/dev/null || true + if copy_from_image "$IMAGE" "DOKKU_SCALE" "$DOKKU_ROOT/$APP" >/dev/null 2>&1; then + cp "$DOKKU_SCALE_FILE" "${DOKKU_SCALE_FILE}.extracted" + else + rm -f "${DOKKU_SCALE_FILE}.extracted" + fi + if [[ ! -f $DOKKU_SCALE_FILE ]]; then dokku_log_info1_quiet "DOKKU_SCALE file not found in app image. Generating one based on Procfile..." @@ -182,7 +187,7 @@ ps_scale() { local DOKKU_PROCFILE="$DOKKU_ROOT/$APP/DOKKU_PROCFILE" shift 1 - [[ ! -e $DOKKU_SCALE_FILE ]] && generate_scale_file "$APP" "$IMAGE_TAG" + [[ ! -e $DOKKU_SCALE_FILE ]] && generate_scale_file "$APP" "$IMAGE_TAG" >/dev/null 2>&1 if [[ -z "$@" ]]; then dokku_log_info1_quiet "Scaling for $APP" dokku_col_log_msg_quiet "proctype" "qty" @@ -194,8 +199,12 @@ ps_scale() { dokku_col_log_msg "${PROC_NAME}:" "$PROC_COUNT" done <"$DOKKU_SCALE_FILE" else - set_scale "$APP" "$@" - release_and_deploy "$APP" "$IMAGE_TAG" + if [[ "$(fn-ps-can-scale "$APP")" == "true" ]]; then + set_scale "$APP" "$@" + release_and_deploy "$APP" "$IMAGE_TAG" + else + dokku_log_fail "App contains DOKKU_SCALE file and cannot be manually scaled" + fi fi } @@ -241,3 +250,17 @@ fn-ps-is-app-running() { APP_STATUS=$(fn-ps-app-status "$APP") echo "$APP_STATUS" | cut -d ' ' -f 2 } + +fn-ps-can-scale() { + declare APP="$1" + local IMAGE_TAG=$(get_running_image_tag "$APP") + local DOKKU_SCALE_FILE="$DOKKU_ROOT/$APP/DOKKU_SCALE" + local CAN_SCALE=false + + [[ ! -e $DOKKU_SCALE_FILE ]] && generate_scale_file "$APP" "$IMAGE_TAG" >/dev/null 2>&1 + if [[ ! -f "${DOKKU_SCALE_FILE}.extracted" ]]; then + CAN_SCALE=true + fi + + echo "$CAN_SCALE" +} diff --git a/plugins/ps/internal-functions b/plugins/ps/internal-functions index cb145acb3..4cab309cb 100755 --- a/plugins/ps/internal-functions +++ b/plugins/ps/internal-functions @@ -50,7 +50,8 @@ cmd-ps-report-single() { if (is_deployed "$APP"); then DEPLOYED="true"; else DEPLOYED="false"; fi local passed_phases="deploy" - RESTARTPOLICY=$(get_restart_policies "$(get_phase_file_path "$passed_phases")" || true) + local RESTARTPOLICY=$(get_restart_policies "$(get_phase_file_path "$passed_phases")" || true) + local CAN_SCALE="$(fn-ps-can-scale "$APP")" local CONTAINER_FILES="$(find "$DOKKU_ROOT/$APP" -maxdepth 1 -name "CONTAINER.*" -printf "%f\n" 2>/dev/null | sort -t . -k 2 -n | xargs)" local CONTAINER_FILE @@ -70,6 +71,7 @@ cmd-ps-report-single() { "--running: $RUNNING" "--restore: $RESTORE" "--restart-policy: $RESTARTPOLICY" + "--ps-can-scale: $CAN_SCALE" ) if [[ -z "$INFO_FLAG" ]]; then diff --git a/tests/apps/dockerfile-dokku-scale/CHECKS b/tests/apps/dockerfile-dokku-scale/CHECKS new file mode 100644 index 000000000..068926825 --- /dev/null +++ b/tests/apps/dockerfile-dokku-scale/CHECKS @@ -0,0 +1,5 @@ +WAIT=2 # wait 2 seconds +TIMEOUT=5 # set timeout to 5 seconds +ATTEMPTS=2 # try 2 times + +/ nodejs/express diff --git a/tests/apps/dockerfile-dokku-scale/DOKKU_SCALE b/tests/apps/dockerfile-dokku-scale/DOKKU_SCALE new file mode 100644 index 000000000..3cb9829e6 --- /dev/null +++ b/tests/apps/dockerfile-dokku-scale/DOKKU_SCALE @@ -0,0 +1 @@ +web=1 diff --git a/tests/apps/dockerfile-dokku-scale/Dockerfile b/tests/apps/dockerfile-dokku-scale/Dockerfile new file mode 100644 index 000000000..fa82185d5 --- /dev/null +++ b/tests/apps/dockerfile-dokku-scale/Dockerfile @@ -0,0 +1,11 @@ +FROM node:4 + +EXPOSE 3001/udp +EXPOSE 3000/tcp +EXPOSE 3003 + +COPY . /app +WORKDIR /app +RUN npm install + +CMD npm start diff --git a/tests/apps/dockerfile-dokku-scale/Procfile b/tests/apps/dockerfile-dokku-scale/Procfile new file mode 100644 index 000000000..9c49227a7 --- /dev/null +++ b/tests/apps/dockerfile-dokku-scale/Procfile @@ -0,0 +1,8 @@ +############################### +# DEVELOPMENT # +############################### + +# Procfile for development using the new threaded worker (scheduler, twitter stream and delayed job) +cron: node worker.js +web: node web.js +worker: node worker.js diff --git a/tests/apps/dockerfile-dokku-scale/check_deploy b/tests/apps/dockerfile-dokku-scale/check_deploy new file mode 100755 index 000000000..e4519b442 --- /dev/null +++ b/tests/apps/dockerfile-dokku-scale/check_deploy @@ -0,0 +1,5 @@ +#!/usr/bin/env bash +set -e +output="$(curl -s -S "$1")" +echo "$output" +test "$output" == "nodejs/express" diff --git a/tests/apps/dockerfile-dokku-scale/package.json b/tests/apps/dockerfile-dokku-scale/package.json new file mode 100644 index 000000000..397b0ce84 --- /dev/null +++ b/tests/apps/dockerfile-dokku-scale/package.json @@ -0,0 +1,13 @@ +{ + "name": "node-example", + "version": "0.0.1", + "dependencies": { + "express": "2.5.x" + }, + "engines": { + "node": "4.2.x" + }, + "scripts": { + "start": "false" + } +} diff --git a/tests/apps/dockerfile-dokku-scale/web.js b/tests/apps/dockerfile-dokku-scale/web.js new file mode 100644 index 000000000..6b8f4d819 --- /dev/null +++ b/tests/apps/dockerfile-dokku-scale/web.js @@ -0,0 +1,12 @@ +var express = require('express'); + +var app = express.createServer(express.logger()); + +app.get('/', function(request, response) { + response.send('nodejs/express'); +}); + +var port = process.env.PORT || 5000; +app.listen(port, function() { + console.log("Listening on " + port); +}); diff --git a/tests/apps/dockerfile-dokku-scale/worker.js b/tests/apps/dockerfile-dokku-scale/worker.js new file mode 100644 index 000000000..12133530d --- /dev/null +++ b/tests/apps/dockerfile-dokku-scale/worker.js @@ -0,0 +1,6 @@ +function worker() { + console.log('sleeping for 60 seconds'); + setTimeout(worker, 60 * 1000); +} + +worker(); diff --git a/tests/unit/10_ps-dockerfile.bats b/tests/unit/10_ps-dockerfile.bats index 3101dc6b0..2c0061f08 100644 --- a/tests/unit/10_ps-dockerfile.bats +++ b/tests/unit/10_ps-dockerfile.bats @@ -134,6 +134,35 @@ teardown() { assert_success } +@test "(ps:scale) dockerfile dokku-scale" { + run /bin/bash -c "dokku ps:scale $TEST_APP web=2" + echo "output: $output" + echo "status: $status" + assert_success + + deploy_app dockerfile-dokku-scale + CIDS="" + for CID_FILE in $DOKKU_ROOT/$TEST_APP/CONTAINER.web.*; do + CIDS+=$(< $CID_FILE) + CIDS+=" " + done + CIDS_PATTERN=$(echo $CIDS | sed -e "s: :|:g") + run /bin/bash -c "docker ps -q --no-trunc | egrep \"$CIDS_PATTERN\" | wc -l | grep 1" + echo "output: $output" + echo "status: $status" + assert_success + + run /bin/bash -c "dokku ps:scale $TEST_APP web=1" + echo "output: $output" + echo "status: $status" + assert_failure + + run /bin/bash -c "dokku ps:report $TEST_APP --ps-can-scale" + echo "output: $output" + echo "status: $status" + assert_output "false" +} + @test "(ps) dockerfile with procfile" { deploy_app dockerfile-procfile run /bin/bash -c "dokku ps:stop $TEST_APP"