diff --git a/docs/docker-options.md b/docs/docker-options.md new file mode 100644 index 000000000..730d64914 --- /dev/null +++ b/docs/docker-options.md @@ -0,0 +1,60 @@ +docker-options +======================== + +Usage +----- + +```bash +$ dokku help +... + docker-options Display apps docker options for all phases + docker-options Display apps docker options for phase (comma seperated phase list) + docker-options:add OPTION Add docker option to app for phase (comma seperated phase list) + docker-options:remove OPTION Remove docker option from app for phase (comma seperated phase list) +... +```` + +Add some options + +```bash +$ dokku docker-options:add myapp deploy "-v /host/path:/container/path" +$ dokku docker-options:add myapp run "-v /another/container/path" +$ dokku docker-options:add myapp "-link container_name:alias" +``` + +Check what we added + +```bash +$ dokku docker-options myapp +-link container_name:alias +-v /host/path:/container/path +-v /another/container/path +``` + +Remove an option +```bash +$ dokku docker-options:remove myapp "-link container_name:alias" +``` + +Advanced Usage (avoid if possible) +------------ + +In your applications folder (/home/dokku/app_name) create a file called DOCKER_OPTIONS. + +Inside this file list one docker option per line. For example: + +```bash +-link container_name:alias +-v /host/path:/container/path +-v /another/container/path +``` + +The above example will result in the following options being passed to docker during deploy and docker run: + +```bash +-link container_name:alias -v /host/path:/container/path -v /another/container/path +``` + +You may also include comments (lines beginning with a #) and blank lines in the DOCKER_OPTIONS file. + +Move information on docker options can be found here: http://docs.docker.io/en/latest/reference/run/ . diff --git a/docs/index.md b/docs/index.md index 3a0a2f750..0b2dd82d3 100644 --- a/docs/index.md +++ b/docs/index.md @@ -17,6 +17,7 @@ Docker powered mini-Heroku. The smallest PaaS implementation you've ever seen. - [DNS Configuration](http://progrium.viewdocs.io/dokku/dns) - [Nginx Configuration](http://progrium.viewdocs.io/dokku/nginx) - [Running Remote commands](http://progrium.viewdocs.io/dokku/remote-commands) +- [Container Options](http://progrium.viewdocs.io/dokku/docker-options) ### Community Contributions diff --git a/docs/plugins.md b/docs/plugins.md index 8ff3b05eb..4a9e6b14b 100644 --- a/docs/plugins.md +++ b/docs/plugins.md @@ -149,7 +149,6 @@ Note: The following plugins have been supplied by our community and may not have | ------------------------------------------------------------------------------------------------- | --------------------- | --------------------- | | [app-url](https://github.com/mikecsh/dokku-app-url) | [mikecsh][] | Works with 0.2.0 | | [Docker Direct](https://github.com/heichblatt/dokku-docker-direct) | [heichblatt][] | | -| [Docker Options](https://github.com/dyson/dokku-docker-options) | [dyson][] | dokku >= [c77cbf1][] | | [Dokku Name](https://github.com/alex-sherwin/dokku-name) | [alex-sherwin][] | dokku >= [c77cbf1][] | | [Dokku Registry](https://github.com/agco-adm/dokku-registry)1 | [agco-adm][] | | | [git rev-parse HEAD in env](https://github.com/nornagon/dokku-git-rev) | [nornagon][] | Compatible with 0.2.0 | @@ -207,15 +206,16 @@ Note: The following plugins have been supplied by our community and may not have The following plugins have been removed as their functionality is now in Dokku Core. -| Plugin | Author | In Dokku Since | -| ------------------------------------------------------------------------------------------------- | --------------------- | ------------------------- | -| [Custom Domains](https://github.com/neam/dokku-custom-domains) | [motin][] | v0.3.10 (domains plugin) | -| [Debug](https://github.com/heichblatt/dokku-debug) | [heichblatt][] | v0.3.9 (trace command) | -| [Multiple Domains](https://github.com/wmluke/dokku-domains-plugin)1 | [wmluke][] | v0.3.10 (domains plugin) | -| [Rebuild application](https://github.com/scottatron/dokku-rebuild) | [scottatron][] | v0.3.14 (ps plugin) | -| [Supply env vars to buildpacks](https://github.com/cameron-martin/dokku-build-env)2 | [cameron-martin][] | v0.3.9 (build-env plugin) | -| [user-env-compile](https://github.com/musicglue/dokku-user-env-compile)2 | [musicglue][] | v0.3.9 (build-env plugin) | -| [user-env-compile](https://github.com/motin/dokku-user-env-compile)2 | [motin][] | v0.3.9 (build-env plugin) | +| Plugin | Author | In Dokku Since | +| ------------------------------------------------------------------------------------------------- | --------------------- | ------------------------------- | +| [Custom Domains](https://github.com/neam/dokku-custom-domains) | [motin][] | v0.3.10 (domains plugin) | +| [Debug](https://github.com/heichblatt/dokku-debug) | [heichblatt][] | v0.3.9 (trace command) | +| [Docker Options](https://github.com/dyson/dokku-docker-options) | [dyson][] | v0.3.17 (docker-options plugin) | +| [Multiple Domains](https://github.com/wmluke/dokku-domains-plugin)1 | [wmluke][] | v0.3.10 (domains plugin) | +| [Rebuild application](https://github.com/scottatron/dokku-rebuild) | [scottatron][] | v0.3.14 (ps plugin) | +| [Supply env vars to buildpacks](https://github.com/cameron-martin/dokku-build-env)2 | [cameron-martin][] | v0.3.9 (build-env plugin) | +| [user-env-compile](https://github.com/musicglue/dokku-user-env-compile)2 | [musicglue][] | v0.3.9 (build-env plugin) | +| [user-env-compile](https://github.com/motin/dokku-user-env-compile)2 | [motin][] | v0.3.9 (build-env plugin) | 1 Conflicts with [VHOSTS Custom Configuration](https://github.com/neam/dokku-nginx-vhosts-custom-configuration) 2 Similar to the heroku-labs feature (see https://devcenter.heroku.com/articles/labs-user-env-compile) diff --git a/plugins/docker-options/commands b/plugins/docker-options/commands new file mode 100755 index 000000000..d2cc8b496 --- /dev/null +++ b/plugins/docker-options/commands @@ -0,0 +1,149 @@ +#!/usr/bin/env bash +set -eo pipefail; [[ $DOKKU_TRACE ]] && set -x +source "$(dirname $0)/../common/functions" + +PHASES=(build deploy run) + +FILE_PREFIX="DOCKER_OPTIONS_" + +get_app() { + [[ -z $1 ]] && dokku_log_fail "Please specify an app to run the command on" + verify_app_name "$1" + APP="$1" +} + +get_phases() { + local passed_phases_list=$1 + local phase + if [[ -n $passed_phases_list ]]; then + IFS=',' read -ra passed_phases <<< "$passed_phases_list" + for phase in "${passed_phases[@]}"; do + verify_phase $phase + done + fi +} + +verify_phase() { + local phase + for phase in "${PHASES[@]}"; do + if [[ "$phase" = "$1" ]]; then + return 0 + fi + done + dokku_log_fail "Phase(s) must be one of [${PHASES[@]}]" +} + +get_phase_file_path() { + local phase=$1 + phase_file_path="${DOKKU_ROOT}/${APP}/${FILE_PREFIX}${phase^^}" +} + +create_phase_file_if_required() { + local phase_file_path=$1 + [[ -f $phase_file_path ]] || { + touch $phase_file_path + } +} + +display_phase_options() { + local phase=$1 + local phase_file_path=$2 + echo "${phase^} options:" + sed -e 's/^/ /' $phase_file_path +} + +display_all_phases_options() { + for phase in "${PHASES[@]}"; do + get_phase_file_path $phase + if [[ -s $phase_file_path ]] ; then + display_phase_options $phase $phase_file_path + fi + done +} + +display_passed_phases_options() { + local passed_phases=("${!1}") + local phase + for phase in "${passed_phases[@]}"; do + get_phase_file_path $phase + if [ ! -s $phase_file_path ] ; then + echo "${phase^} options: none" + else + display_phase_options $phase $phase_file_path + fi + done +} + +get_passed_docker_option() { + [[ -z "$@" ]] && dokku_log_fail "Please specify docker options to add to the phase" + passed_docker_option=("$@") +} + +add_passed_docker_option() { + local passed_phases=("${!1}") + local passed_option_string=$2 + local phase + for phase in "${passed_phases[@]}"; do + get_phase_file_path $phase + create_phase_file_if_required $phase_file_path + echo "${passed_option_string}" >> $phase_file_path + all_phase_options=$(< $phase_file_path) + echo -e "${all_phase_options}" | sed '/^$/d' | sort -u > $phase_file_path + done +} + +remove_passed_docker_option() { + local passed_phases=("${!1}") + local passed_option_string=$2 + local phase + for phase in "${passed_phases[@]}"; do + get_phase_file_path $phase + [[ ! -s $phase_file_path ]] || { + all_phase_options=$(< $phase_file_path) + all_phase_options=$(echo -e "${all_phase_options}" | sed "s#^${passed_option_string}\$##") + echo -e "${all_phase_options}" | sed '/^$/d' | sort -u > $phase_file_path + } + done +} + +case "$1" in + # Display applications docker options + docker-options) + get_app $2 + get_phases $3 + if [[ ! "${passed_phases[@]}" ]]; then + display_all_phases_options + else + display_passed_phases_options passed_phases[@] + fi + ;; + + # Add a docker option to application + docker-options:add) + get_app $2 + get_phases $3 + shift 3 # everything else passed is the docker option + get_passed_docker_option "$@" + add_passed_docker_option passed_phases[@] "${passed_docker_option[@]}" + ;; + + # Remove a docker option from application + docker-options:remove) + get_app $2 + get_phases $3 + shift 3 # everything else passed is the docker option + get_passed_docker_option "$@" + remove_passed_docker_option passed_phases[@] "${passed_docker_option[@]}" + ;; + + # Display usage help + help) + cat && cat< Display apps docker options for all phases + docker-options Display apps docker options for phase (comma seperated phase list) + docker-options:add OPTION Add docker option to app for phase (comma seperated phase list) + docker-options:remove OPTION Remove docker option from app for phase (comma seperated phase list) +EOF + ;; + +esac diff --git a/plugins/docker-options/docker-args-build b/plugins/docker-options/docker-args-build new file mode 120000 index 000000000..68dea362a --- /dev/null +++ b/plugins/docker-options/docker-args-build @@ -0,0 +1 @@ +docker-args-deploy \ No newline at end of file diff --git a/plugins/docker-options/docker-args-deploy b/plugins/docker-options/docker-args-deploy new file mode 100755 index 000000000..019f66f81 --- /dev/null +++ b/plugins/docker-options/docker-args-deploy @@ -0,0 +1,43 @@ +#!/usr/bin/env bash +set -eo pipefail; [[ $DOKKU_TRACE ]] && set -x + +STDIN=$(cat) +APP="$1" + +case "$0" in + *docker-args-build) + PHASE=BUILD + ;; + *docker-args-deploy) + PHASE=DEPLOY + ;; + *docker-args-run) + PHASE=RUN + ;; +esac + +FILE_PREFIX="DOCKER_OPTIONS_" +PHASE_FILE_PATH="${DOKKU_ROOT}/${APP}/${FILE_PREFIX}${PHASE}" + +output="" + +if [[ -f "$PHASE_FILE_PATH" ]]; then + DONE=false + until $DONE; do + read line || DONE=true + + [[ ! -n "$line" ]] && continue + + # shellcheck disable=SC1001 + case "$line" in + \#*) + continue + ;; + *) + output="$output $line" + ;; + esac + done < $PHASE_FILE_PATH +fi + +echo "$STDIN$output" diff --git a/plugins/docker-options/docker-args-run b/plugins/docker-options/docker-args-run new file mode 120000 index 000000000..68dea362a --- /dev/null +++ b/plugins/docker-options/docker-args-run @@ -0,0 +1 @@ +docker-args-deploy \ No newline at end of file diff --git a/tests/unit/docker-options.bats b/tests/unit/docker-options.bats new file mode 100644 index 000000000..c2b097eb2 --- /dev/null +++ b/tests/unit/docker-options.bats @@ -0,0 +1,151 @@ +#!/usr/bin/env bats + +load test_helper + +setup() { + create_app +} + +teardown() { + destroy_app +} + +@test "docker-options:add (all phases)" { + run /bin/bash -c "dokku docker-options:add $TEST_APP build,deploy,run \"-v /tmp\"" + echo "output: "$output + echo "status: "$status + assert_success + run /bin/bash -c "dokku docker-options $TEST_APP | egrep '\-v /tmp' | wc -l | grep -q 3" + echo "output: "$output + echo "status: "$status + assert_success +} + +@test "docker-options:add (build phase)" { + run /bin/bash -c "dokku docker-options:add $TEST_APP build \"-v /tmp\"" + echo "output: "$output + echo "status: "$status + assert_success + run /bin/bash -c "dokku docker-options $TEST_APP build | egrep '\-v /tmp' | wc -l | grep -q 1" + echo "output: "$output + echo "status: "$status + assert_success +} + +@test "docker-options:add (deploy phase)" { + run /bin/bash -c "dokku docker-options:add $TEST_APP deploy \"-v /tmp\"" + echo "output: "$output + echo "status: "$status + assert_success + run /bin/bash -c "dokku docker-options $TEST_APP deploy | egrep '\-v /tmp' | wc -l | grep -q 1" + echo "output: "$output + echo "status: "$status + assert_success +} + +@test "docker-options:add (run phase)" { + run /bin/bash -c "dokku docker-options:add $TEST_APP run \"-v /tmp\"" + echo "output: "$output + echo "status: "$status + assert_success + run /bin/bash -c "dokku docker-options $TEST_APP run | egrep '\-v /tmp' | wc -l | grep -q 1" + echo "output: "$output + echo "status: "$status + assert_success +} + +@test "docker-options:remove (all phases)" { + run /bin/bash -c "dokku docker-options:add $TEST_APP build,deploy,run \"-v /tmp\"" + echo "output: "$output + echo "status: "$status + assert_success + run /bin/bash -c "dokku docker-options $TEST_APP | egrep '\-v /tmp' | wc -l | grep -q 3" + echo "output: "$output + echo "status: "$status + assert_success + run /bin/bash -c "dokku docker-options:remove $TEST_APP build,deploy,run \"-v /tmp\"" + echo "output: "$output + echo "status: "$status + assert_success + run /bin/bash -c "dokku docker-options $TEST_APP | wc -l | grep -q 0" + echo "output: "$output + echo "status: "$status + assert_success +} + +@test "docker-options:remove (build phase)" { + run /bin/bash -c "dokku docker-options:add $TEST_APP build,deploy,run \"-v /tmp\"" + echo "output: "$output + echo "status: "$status + assert_success + run /bin/bash -c "dokku docker-options $TEST_APP | egrep '\-v /tmp' | wc -l | grep -q 3" + echo "output: "$output + echo "status: "$status + assert_success + run /bin/bash -c "dokku docker-options:remove $TEST_APP build \"-v /tmp\"" + echo "output: "$output + echo "status: "$status + assert_success + run /bin/bash -c "dokku docker-options $TEST_APP build" + echo "output: "$output + echo "status: "$status + assert_output "Build options: none" +} + +@test "docker-options:remove (deploy phase)" { + run /bin/bash -c "dokku docker-options:add $TEST_APP build,deploy,run \"-v /tmp\"" + echo "output: "$output + echo "status: "$status + assert_success + run /bin/bash -c "dokku docker-options $TEST_APP deploy | egrep '\-v /tmp' | wc -l | grep -q 1" + echo "output: "$output + echo "status: "$status + assert_success + run /bin/bash -c "dokku docker-options:remove $TEST_APP deploy \"-v /tmp\"" + echo "output: "$output + echo "status: "$status + assert_success + run /bin/bash -c "dokku docker-options $TEST_APP deploy" + echo "output: "$output + echo "status: "$status + assert_output "Deploy options: none" +} + +@test "docker-options:remove (run phase)" { + run /bin/bash -c "dokku docker-options:add $TEST_APP build,deploy,run \"-v /tmp\"" + echo "output: "$output + echo "status: "$status + assert_success + run /bin/bash -c "dokku docker-options $TEST_APP run | egrep '\-v /tmp' | wc -l | grep -q 1" + echo "output: "$output + echo "status: "$status + assert_success + run /bin/bash -c "dokku docker-options:remove $TEST_APP run \"-v /tmp\"" + echo "output: "$output + echo "status: "$status + assert_success + run /bin/bash -c "dokku docker-options $TEST_APP run" + echo "output: "$output + echo "status: "$status + assert_output "Run options: none" +} + +@test "docker-options (deploy with options)" { + run /bin/bash -c "dokku docker-options:add $TEST_APP deploy \"-v /var/tmp\"" + echo "output: "$output + echo "status: "$status + assert_success + run /bin/bash -c "echo '-v /tmp' >> $DOKKU_ROOT/$TEST_APP/DOCKER_OPTIONS_DEPLOY" + echo "output: "$output + echo "status: "$status + assert_success + run /bin/bash -c "echo '# comment' >> $DOKKU_ROOT/$TEST_APP/DOCKER_OPTIONS_DEPLOY" + echo "output: "$output + echo "status: "$status + assert_success + run /bin/bash -c "dokku docker-options $TEST_APP deploy | egrep '\-v /tmp' | wc -l | grep -q 1" + echo "output: "$output + echo "status: "$status + assert_success + deploy_app +}