From 89f289b433eb5bf3d24ac497dcddf6cb82b4279a Mon Sep 17 00:00:00 2001 From: "Michael S. Hobbs" Date: Tue, 1 Mar 2016 13:26:35 -0800 Subject: [PATCH] subcommand restructure and bashstyle refactor. closes #1579 --- .gitignore | 1 - docs/development/plugin-creation.md | 84 +++- dokku | 244 ++-------- plugins/00_dokku-standard/commands | 455 +++++++++++++----- .../00_dokku-standard/exec-app-json-scripts | 2 + plugins/20_events/commands | 37 +- plugins/20_events/subcommands/default | 17 + plugins/20_events/subcommands/list | 23 + plugins/20_events/subcommands/off | 12 + plugins/20_events/subcommands/on | 13 + plugins/apps/commands | 67 +-- plugins/apps/functions | 1 + plugins/apps/subcommands/create | 11 + plugins/apps/subcommands/default | 16 + plugins/apps/subcommands/destroy | 42 ++ plugins/apps/subcommands/rename | 26 + plugins/certs/commands | 164 +------ plugins/certs/functions | 4 +- plugins/certs/subcommands/add | 76 +++ plugins/certs/subcommands/generate | 39 ++ plugins/certs/subcommands/info | 38 ++ plugins/certs/subcommands/remove | 21 + plugins/certs/subcommands/update | 1 + plugins/checks/check-deploy | 1 + plugins/checks/commands | 61 +-- plugins/checks/install | 1 + plugins/checks/subcommands/default | 23 + plugins/checks/subcommands/disable | 21 + plugins/checks/subcommands/enable | 21 + plugins/common/functions | 85 +++- plugins/config/commands | 20 +- plugins/config/functions | 10 + plugins/config/subcommands/default | 11 + plugins/config/subcommands/get | 11 + plugins/config/subcommands/set | 11 + plugins/config/subcommands/unset | 11 + plugins/docker-options/commands | 37 +- plugins/docker-options/functions | 8 + plugins/docker-options/subcommands/add | 18 + plugins/docker-options/subcommands/default | 19 + plugins/docker-options/subcommands/remove | 17 + plugins/domains/commands | 59 +-- plugins/domains/functions | 30 -- plugins/domains/install | 3 +- plugins/domains/subcommands/add | 20 + plugins/domains/subcommands/clear | 19 + plugins/domains/subcommands/default | 26 + plugins/domains/subcommands/disable | 13 + plugins/domains/subcommands/enable | 13 + plugins/domains/subcommands/remove | 21 + plugins/domains/subcommands/set-global | 13 + plugins/domains/subcommands/setup | 13 + plugins/enter/commands | 32 +- plugins/enter/subcommands/default | 37 ++ plugins/git/commands | 7 +- plugins/logs/commands | 72 +-- plugins/logs/functions | 12 - plugins/logs/subcommands/default | 65 +++ plugins/nginx-vhosts/commands | 15 +- plugins/nginx-vhosts/functions | 1 + plugins/nginx-vhosts/subcommands/access-logs | 14 + plugins/nginx-vhosts/subcommands/build-config | 14 + plugins/nginx-vhosts/subcommands/error-logs | 1 + plugins/plugin/commands | 60 +-- plugins/plugin/functions | 7 + plugins/plugin/subcommands/default | 11 + plugins/plugin/subcommands/disable | 14 + plugins/plugin/subcommands/enable | 14 + plugins/plugin/subcommands/install | 25 + .../plugin/subcommands/install-dependencies | 13 + plugins/plugin/subcommands/uninstall | 14 + plugins/plugin/subcommands/update | 15 + plugins/proxy/commands | 23 +- plugins/proxy/functions | 52 -- plugins/proxy/subcommands/default | 22 + plugins/proxy/subcommands/disable | 24 + plugins/proxy/subcommands/enable | 24 + plugins/proxy/subcommands/set | 14 + plugins/ps/commands | 57 +-- plugins/ps/functions | 24 +- plugins/ps/subcommands/default | 23 + plugins/ps/subcommands/rebuild | 13 + plugins/ps/subcommands/rebuildall | 14 + plugins/ps/subcommands/restart | 13 + plugins/ps/subcommands/restartall | 14 + plugins/ps/subcommands/restore | 18 + plugins/ps/subcommands/scale | 14 + plugins/ps/subcommands/start | 13 + plugins/ps/subcommands/stop | 13 + plugins/shell/commands | 47 +- plugins/shell/subcommands/default | 52 ++ plugins/tags/commands | 48 +- plugins/tags/functions | 1 + plugins/tags/subcommands/create | 18 + plugins/tags/subcommands/default | 17 + plugins/tags/subcommands/deploy | 16 + plugins/tags/subcommands/destroy | 25 + plugins/tar/commands | 59 +-- plugins/tar/receive-app | 19 +- plugins/tar/subcommands/build | 18 + plugins/tar/subcommands/build-locked | 39 ++ plugins/tar/subcommands/from | 15 + plugins/tar/subcommands/in | 15 + tests/unit/10_apps.bats | 30 +- tests/unit/20_config.bats | 28 +- 105 files changed, 1969 insertions(+), 1306 deletions(-) create mode 100755 plugins/20_events/subcommands/default create mode 100755 plugins/20_events/subcommands/list create mode 100755 plugins/20_events/subcommands/off create mode 100755 plugins/20_events/subcommands/on create mode 100755 plugins/apps/subcommands/create create mode 100755 plugins/apps/subcommands/default create mode 100755 plugins/apps/subcommands/destroy create mode 100755 plugins/apps/subcommands/rename create mode 100755 plugins/certs/subcommands/add create mode 100755 plugins/certs/subcommands/generate create mode 100755 plugins/certs/subcommands/info create mode 100755 plugins/certs/subcommands/remove create mode 120000 plugins/certs/subcommands/update create mode 100755 plugins/checks/subcommands/default create mode 100755 plugins/checks/subcommands/disable create mode 100755 plugins/checks/subcommands/enable create mode 100755 plugins/config/subcommands/default create mode 100755 plugins/config/subcommands/get create mode 100755 plugins/config/subcommands/set create mode 100755 plugins/config/subcommands/unset create mode 100755 plugins/docker-options/subcommands/add create mode 100755 plugins/docker-options/subcommands/default create mode 100755 plugins/docker-options/subcommands/remove create mode 100755 plugins/domains/subcommands/add create mode 100755 plugins/domains/subcommands/clear create mode 100755 plugins/domains/subcommands/default create mode 100755 plugins/domains/subcommands/disable create mode 100755 plugins/domains/subcommands/enable create mode 100755 plugins/domains/subcommands/remove create mode 100755 plugins/domains/subcommands/set-global create mode 100755 plugins/domains/subcommands/setup create mode 100755 plugins/enter/subcommands/default delete mode 100755 plugins/logs/functions create mode 100755 plugins/logs/subcommands/default create mode 100755 plugins/nginx-vhosts/subcommands/access-logs create mode 100755 plugins/nginx-vhosts/subcommands/build-config create mode 120000 plugins/nginx-vhosts/subcommands/error-logs create mode 100755 plugins/plugin/subcommands/default create mode 100755 plugins/plugin/subcommands/disable create mode 100755 plugins/plugin/subcommands/enable create mode 100755 plugins/plugin/subcommands/install create mode 100755 plugins/plugin/subcommands/install-dependencies create mode 100755 plugins/plugin/subcommands/uninstall create mode 100755 plugins/plugin/subcommands/update create mode 100755 plugins/proxy/subcommands/default create mode 100755 plugins/proxy/subcommands/disable create mode 100755 plugins/proxy/subcommands/enable create mode 100755 plugins/proxy/subcommands/set create mode 100755 plugins/ps/subcommands/default create mode 100755 plugins/ps/subcommands/rebuild create mode 100755 plugins/ps/subcommands/rebuildall create mode 100755 plugins/ps/subcommands/restart create mode 100755 plugins/ps/subcommands/restartall create mode 100755 plugins/ps/subcommands/restore create mode 100755 plugins/ps/subcommands/scale create mode 100755 plugins/ps/subcommands/start create mode 100755 plugins/ps/subcommands/stop create mode 100755 plugins/shell/subcommands/default create mode 100755 plugins/tags/subcommands/create create mode 100755 plugins/tags/subcommands/default create mode 100755 plugins/tags/subcommands/deploy create mode 100755 plugins/tags/subcommands/destroy create mode 100755 plugins/tar/subcommands/build create mode 100755 plugins/tar/subcommands/build-locked create mode 100755 plugins/tar/subcommands/from create mode 100755 plugins/tar/subcommands/in diff --git a/.gitignore b/.gitignore index 555f976e9..ad84db0c7 100644 --- a/.gitignore +++ b/.gitignore @@ -1,7 +1,6 @@ .vagrant .DS_Store stack.tgz -build tmp *.deb .ruby-version diff --git a/docs/development/plugin-creation.md b/docs/development/plugin-creation.md index 163ebac7a..f4fd5577d 100644 --- a/docs/development/plugin-creation.md +++ b/docs/development/plugin-creation.md @@ -8,7 +8,89 @@ If you create your own plugin: 4. Edit [this page](/dokku/plugins) and add a link to it. 5. Subscribe to the [dokku development blog](http://progrium.com) to be notified about API changes and releases -### Sample plugin + +### Sample plugin - new structure +The below plugin is a dummy `dokku hello` plugin. + +hello/subcommands/default + +```shell +#!/usr/bin/env bash +set -eo pipefail; [[ $DOKKU_TRACE ]] && set -x +source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions" + +hello_main_cmd() { + local desc="prints Hello \$APP" + local cmd="hello" + # Support --app/$DOKKU_APP_NAME flag + # Use the following lines to reorder args into "$cmd $DOKKU_APP_NAME $@"" + local argv=("$@") + [[ ${argv[0]} == "$cmd" ]] && shift 1 + [[ ! -z $DOKKU_APP_NAME ]] && set -- $DOKKU_APP_NAME $@ + set -- $cmd $@ + ## + + [[ -z $2 ]] && echo "Please specify an app to run the command on" && exit 1 + verify_app_name "$2" + local APP="$2"; + + echo "Hello $APP" +} + +hello_main_cmd "$@" +``` + +hello/subcommands/world + +```shell +#!/usr/bin/env bash +set -eo pipefail; [[ $DOKKU_TRACE ]] && set -x +source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions" + +hello_world_cmd() { + local desc="prints Hello World" + local cmd="hello:world" + # Support --app/$DOKKU_APP_NAME flag + # Use the following lines to reorder args into "$cmd $DOKKU_APP_NAME $@"" + local argv=("$@") + [[ ${argv[0]} == "$cmd" ]] && shift 1 + [[ ! -z $DOKKU_APP_NAME ]] && set -- $DOKKU_APP_NAME $@ + set -- $cmd $@ + ## + + [[ -z $2 ]] && echo "Please specify an app to run the command on" && exit 1 + verify_app_name "$2" + local APP="$2"; + + echo "Hello world" +} + +hello_world_cmd "$@" +``` + +hello/commands + +```shell +#!/usr/bin/env bash +set -eo pipefail; [[ $DOKKU_TRACE ]] && set -x + +case "$1" in + help) + cat<, Says "Hello " + hello:world, Says "Hello world" +EOF + ;; + + *) + exit $DOKKU_NOT_IMPLEMENTED_EXIT + ;; + +esac +``` + + +### Sample plugin - old structure (still supported but not advised) The below plugin is a dummy `dokku hello` plugin. If your plugin exposes commands, this is a good template for your `commands` file: diff --git a/dokku b/dokku index e96f0db2f..91bdcf660 100755 --- a/dokku +++ b/dokku @@ -40,8 +40,6 @@ export DOKKU_CONTAINER_LABEL=dokku export DOKKU_GLOBAL_RUN_ARGS="--label=$DOKKU_CONTAINER_LABEL" source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions" -source "$PLUGIN_CORE_AVAILABLE_PATH/checks/functions" -source "$PLUGIN_CORE_AVAILABLE_PATH/proxy/functions" parse_args "$@" args=("$@") @@ -88,180 +86,57 @@ if ! dokku_auth "$@" ; then exit 1 fi +execute_dokku_cmd() { + local desc="executes dokku sub-commands" + local PLUGIN_NAME="$1" + local PLUGIN_CMD=$PLUGIN_NAME + local implemented=0; local script + local argv=("$@") + + case "$PLUGIN_NAME" in + events|events:*) + local PLUGIN_NAME=${PLUGIN_NAME/events/20_events} + ;; + nginx|nginx:*) + local PLUGIN_NAME=${PLUGIN_NAME/nginx/nginx-vhosts} + ;; + esac + + if [[ "$(readlink -f "$PLUGIN_ENABLED_PATH/${PLUGIN_NAME%%:*}")" == *core-plugins* ]]; then + [[ ${argv[0]} == "$PLUGIN_CMD" ]] && shift 1 + [[ ! -z $DOKKU_APP_NAME ]] && set -- "$DOKKU_APP_NAME" "$@" + set -- "$PLUGIN_NAME" "$@" + fi + + if [[ -x $PLUGIN_ENABLED_PATH/$PLUGIN_NAME/subcommands/default ]]; then + "$PLUGIN_ENABLED_PATH/$PLUGIN_NAME/subcommands/default" "$@" + implemented=1 + elif [[ -x $PLUGIN_ENABLED_PATH/${PLUGIN_NAME%%:*}/subcommands/${1#*:} ]]; then + "$PLUGIN_ENABLED_PATH/${PLUGIN_NAME%%:*}/subcommands/${1#*:}" "$@" + implemented=1 + fi + + if [[ $implemented -eq 0 ]];then + for script in $PLUGIN_ENABLED_PATH/*/commands; do + set +e; $script "$@" ; exit_code=$? ; set -e + if [[ "$exit_code" -eq "$DOKKU_NOT_IMPLEMENTED_EXIT" ]]; then + continue + fi + implemented=1 + if [[ "$exit_code" -ne "$DOKKU_VALID_EXIT" ]]; then + exit $exit_code + fi + done + fi + + if [[ "$implemented" -eq 0 ]]; then + dokku_log_warn "\`$*\` is not a dokku command." + dokku_log_warn "See \`dokku help\` for a list of available commands." + exit 1 + fi +} + case "$1" in - receive) - APP="$2"; IMAGE=$(get_app_image_name "$APP"); IMAGE_SOURCE_TYPE="$3"; TMP_WORK_DIR="$4" - if [[ -z "$DOKKU_SKIP_CLEANUP" ]]; then - dokku_log_info1 "Cleaning up..." - docker_cleanup - else - dokku_log_info1 "DOKKU_SKIP_CLEANUP set. Skipping dokku cleanup" - fi - dokku_log_info1 "Building $APP from $IMAGE_SOURCE_TYPE..." - dokku build "$APP" "$IMAGE_SOURCE_TYPE" "$TMP_WORK_DIR" - release_and_deploy "$APP" - ;; - - deploy) - [[ -z $2 ]] && dokku_log_fail "Please specify an app to deploy" - APP="$2"; IMAGE_TAG="$3"; IMAGE=$(get_app_image_name "$APP" "$IMAGE_TAG") - verify_app_name "$APP" - plugn trigger pre-deploy "$APP" "$IMAGE_TAG" - - is_image_herokuish_based "$IMAGE" && DOKKU_HEROKUISH=true - DOKKU_SCALE_FILE="$DOKKU_ROOT/$APP/DOKKU_SCALE" - oldids=$(get_app_container_ids "$APP") - - DOKKU_DEFAULT_DOCKER_ARGS=$(: | plugn trigger docker-args-deploy "$APP" "$IMAGE_TAG") - DOKKU_IS_APP_PROXY_ENABLED="$(is_app_proxy_enabled "$APP")" - - while read -r line || [[ -n "$line" ]]; do - [[ "$line" =~ ^#.* ]] && continue - TRIM=${line%#*} - PROC_TYPE=${TRIM%%=*} - PROC_COUNT=${TRIM#*=} - CONTAINER_INDEX=1 - - while [[ $CONTAINER_INDEX -le $PROC_COUNT ]]; do - id=""; port=""; ipaddr="" - DOKKU_CONTAINER_ID_FILE="$DOKKU_ROOT/$APP/CONTAINER.$PROC_TYPE.$CONTAINER_INDEX" - DOKKU_IP_FILE="$DOKKU_ROOT/$APP/IP.$PROC_TYPE.$CONTAINER_INDEX" - DOKKU_PORT_FILE="$DOKKU_ROOT/$APP/PORT.$PROC_TYPE.$CONTAINER_INDEX" - - # start the app - DOCKER_ARGS="$DOKKU_DEFAULT_DOCKER_ARGS" - DOCKER_ARGS+=" -e DYNO='$PROC_TYPE.$CONTAINER_INDEX' " - [[ "$DOKKU_TRACE" ]] && DOCKER_ARGS+=" -e TRACE=true " - - [[ -n "$DOKKU_HEROKUISH" ]] && START_CMD="/start $PROC_TYPE" - - if [[ -z "$DOKKU_HEROKUISH" ]]; then - DOKKU_DOCKERFILE_PORTS=($(dokku config:get "$APP" DOKKU_DOCKERFILE_PORTS || true)) - DOKKU_DOCKERFILE_PORT=$(dokku config:get "$APP" DOKKU_DOCKERFILE_PORT || true) - DOKKU_DOCKERFILE_START_CMD=$(dokku config:get "$APP" DOKKU_DOCKERFILE_START_CMD || true) - DOKKU_PROCFILE_START_CMD=$(get_cmd_from_procfile "$APP" "$PROC_TYPE") - START_CMD=${DOKKU_DOCKERFILE_START_CMD:-$DOKKU_PROCFILE_START_CMD} - fi - - if [[ "$PROC_TYPE" == "web" ]]; then - if [[ -z "${DOKKU_DOCKERFILE_PORTS[*]}" ]]; then - port=5000 - DOKKU_DOCKER_PORT_ARGS+="-p $port" - else - for p in ${DOKKU_DOCKERFILE_PORTS[*]};do - if [[ ! "$p" =~ .*udp.* ]]; then - # set port to first non-udp port - p=${p//\/tcp} - port=${port:="$p"} - fi - DOKKU_DOCKER_PORT_ARGS+=" -p $p " - done - fi - if [[ "$DOKKU_IS_APP_PROXY_ENABLED" = "true" ]]; then - # shellcheck disable=SC2086 - id=$(docker run $DOKKU_GLOBAL_RUN_ARGS -d -e PORT=$port $DOCKER_ARGS $IMAGE $START_CMD) - ipaddr=$(docker inspect --format='{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' "$id") - # Docker < 1.9 compatibility - if [[ -z $ipaddr ]]; then - ipaddr=$(docker inspect --format '{{ .NetworkSettings.IPAddress }}' "$id") - fi - else - # shellcheck disable=SC2086 - id=$(docker run $DOKKU_GLOBAL_RUN_ARGS -d $DOKKU_DOCKER_PORT_ARGS -e PORT=$port $DOCKER_ARGS $IMAGE $START_CMD) - port=$(docker port "$id" "$port" | sed 's/[0-9.]*://') - ipaddr=127.0.0.1 - fi - else - # shellcheck disable=SC2086 - id=$(docker run $DOKKU_GLOBAL_RUN_ARGS -d $DOCKER_ARGS $IMAGE $START_CMD) - fi - - # if we can't post-deploy successfully, kill new container - kill_new() { - docker inspect "$id" &> /dev/null && docker stop "$id" > /dev/null && docker kill "$id" > /dev/null - trap - INT TERM EXIT - kill -9 $$ - } - - # run checks first, then post-deploy hooks, which switches Nginx traffic - if [[ "$(is_app_checks_enabled "$APP")" == "false" ]]; then - dokku_log_info1 "zero downtime is disabled for app ($APP). skipping pre-flight checks" - else - trap kill_new INT TERM EXIT - dokku_log_info1 "Running pre-flight checks" - plugn trigger check-deploy "$APP" "$id" "$PROC_TYPE" "$port" "$ipaddr" - trap - INT TERM EXIT - fi - - # now using the new container - [[ -n "$id" ]] && echo "$id" > "$DOKKU_CONTAINER_ID_FILE" - [[ -n "$ipaddr" ]] && echo "$ipaddr" > "$DOKKU_IP_FILE" - [[ -n "$port" ]] && echo "$port" > "$DOKKU_PORT_FILE" - - # cleanup pre-migration files - rm -f "$DOKKU_ROOT/$APP/CONTAINER" "$DOKKU_ROOT/$APP/IP" "$DOKKU_ROOT/$APP/PORT" - - CONTAINER_INDEX=$(( CONTAINER_INDEX + 1 )) - done - # cleanup when we scale down - if [[ "$PROC_COUNT" == 0 ]]; then - CONTAINER_IDX_OFFSET=0 - else - CONTAINER_IDX_OFFSET=$((PROC_COUNT + 1)) - fi - for container_state_filetype in CONTAINER IP PORT; do - cd "$DOKKU_ROOT/$APP" - find . -maxdepth 1 -name "$container_state_filetype.$PROC_TYPE.*" -printf "%f\n" | sort -t . -k 3 -n | tail -n +$CONTAINER_IDX_OFFSET | xargs rm -f - done - done < "$DOKKU_SCALE_FILE" - - dokku_log_info1 "Running post-deploy" - plugn trigger post-deploy "$APP" "$port" "$ipaddr" "$IMAGE_TAG" - - # kill the old container - if [[ -n "$oldids" ]]; then - - if [[ -z "$DOKKU_WAIT_TO_RETIRE" ]]; then - DOKKU_APP_DOKKU_WAIT_TO_RETIRE=$(dokku config:get "$APP" DOKKU_WAIT_TO_RETIRE || true) - DOKKU_GLOBAL_DOKKU_WAIT_TO_RETIRE=$(dokku config:get --global DOKKU_WAIT_TO_RETIRE || true) - DOKKU_WAIT_TO_RETIRE=${DOKKU_APP_DOKKU_WAIT_TO_RETIRE:="$DOKKU_GLOBAL_DOKKU_WAIT_TO_RETIRE"} - fi - - # Let the old container finish processing requests, before terminating it - WAIT="${DOKKU_WAIT_TO_RETIRE:-60}" - dokku_log_info1 "Shutting down old containers in $WAIT seconds" - for oldid in $oldids; do - dokku_log_info2 "$oldid" - done - ( - exec >/dev/null 2>/dev/null [command-specific-options]" echo "" @@ -273,24 +148,7 @@ EOF ;; *) - implemented=0 - for script in $PLUGIN_ENABLED_PATH/*/commands; do - set +e; $script "$@" ; exit_code=$? ; set -e - if [[ "$exit_code" -eq "$DOKKU_NOT_IMPLEMENTED_EXIT" ]]; then - continue - fi - - implemented=1 - if [[ "$exit_code" -ne "$DOKKU_VALID_EXIT" ]]; then - exit $exit_code - fi - done - - if [[ "$implemented" -eq 0 ]]; then - dokku_log_warn "\`$*\` is not a dokku command." - dokku_log_warn "See \`dokku help\` for a list of available commands." - exit 1 - fi + execute_dokku_cmd "$@" ;; esac diff --git a/plugins/00_dokku-standard/commands b/plugins/00_dokku-standard/commands index e9bef16a2..ac5fb4d5d 100755 --- a/plugins/00_dokku-standard/commands +++ b/plugins/00_dokku-standard/commands @@ -1,107 +1,342 @@ #!/usr/bin/env bash -[[ " build release trace delete ls run url urls report version help " == *" $1 "* ]] || exit "$DOKKU_NOT_IMPLEMENTED_EXIT" +[[ " receive deploy build release trace delete ls run cleanup url urls report version help " == *" $1 "* ]] || exit "$DOKKU_NOT_IMPLEMENTED_EXIT" set -eo pipefail; [[ $DOKKU_TRACE ]] && set -x source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions" +source "$PLUGIN_AVAILABLE_PATH/checks/functions" source "$PLUGIN_AVAILABLE_PATH/config/functions" source "$PLUGIN_AVAILABLE_PATH/nginx-vhosts/functions" source "$PLUGIN_CORE_AVAILABLE_PATH/proxy/functions" +dokku_receive() { + local APP="$2"; local IMAGE=$(get_app_image_name "$APP"); local IMAGE_SOURCE_TYPE="$3"; local TMP_WORK_DIR="$4" + if [[ -z "$DOKKU_SKIP_CLEANUP" ]]; then + dokku_log_info1 "Cleaning up..." + docker_cleanup + else + dokku_log_info1 "DOKKU_SKIP_CLEANUP set. Skipping dokku cleanup" + fi + dokku_log_info1 "Building $APP from $IMAGE_SOURCE_TYPE..." + dokku build "$APP" "$IMAGE_SOURCE_TYPE" "$TMP_WORK_DIR" + release_and_deploy "$APP" +} + +dokku_deploy() { + [[ -z $2 ]] && dokku_log_fail "Please specify an app to deploy" + local APP="$2"; local IMAGE_TAG="$3"; local IMAGE=$(get_app_image_name "$APP" "$IMAGE_TAG") + verify_app_name "$APP" + plugn trigger pre-deploy "$APP" "$IMAGE_TAG" + + is_image_herokuish_based "$IMAGE" && local DOKKU_HEROKUISH=true + local DOKKU_SCALE_FILE="$DOKKU_ROOT/$APP/DOKKU_SCALE" + local oldids=$(get_app_container_ids "$APP") + + local DOKKU_DEFAULT_DOCKER_ARGS=$(: | plugn trigger docker-args-deploy "$APP" "$IMAGE_TAG") + local DOKKU_IS_APP_PROXY_ENABLED="$(is_app_proxy_enabled "$APP")" + + local line + while read -r line || [[ -n "$line" ]]; do + [[ "$line" =~ ^#.* ]] && continue + local TRIM=${line%#*} + local PROC_TYPE=${TRIM%%=*} + local PROC_COUNT=${TRIM#*=} + local CONTAINER_INDEX=1 + + while [[ $CONTAINER_INDEX -le $PROC_COUNT ]]; do + local id=""; local port=""; local ipaddr="" + local DOKKU_CONTAINER_ID_FILE="$DOKKU_ROOT/$APP/CONTAINER.$PROC_TYPE.$CONTAINER_INDEX" + local DOKKU_IP_FILE="$DOKKU_ROOT/$APP/IP.$PROC_TYPE.$CONTAINER_INDEX" + local DOKKU_PORT_FILE="$DOKKU_ROOT/$APP/PORT.$PROC_TYPE.$CONTAINER_INDEX" + + # start the app + local DOCKER_ARGS="$DOKKU_DEFAULT_DOCKER_ARGS" + local DOCKER_ARGS+=" -e DYNO='$PROC_TYPE.$CONTAINER_INDEX' " + [[ "$DOKKU_TRACE" ]] && local DOCKER_ARGS+=" -e TRACE=true " + + [[ -n "$DOKKU_HEROKUISH" ]] && local START_CMD="/start $PROC_TYPE" + + if [[ -z "$DOKKU_HEROKUISH" ]]; then + local DOKKU_DOCKERFILE_PORTS=($(dokku config:get "$APP" DOKKU_DOCKERFILE_PORTS || true)) + local DOKKU_DOCKERFILE_PORT=$(dokku config:get "$APP" DOKKU_DOCKERFILE_PORT || true) + local DOKKU_DOCKERFILE_START_CMD=$(dokku config:get "$APP" DOKKU_DOCKERFILE_START_CMD || true) + local DOKKU_PROCFILE_START_CMD=$(get_cmd_from_procfile "$APP" "$PROC_TYPE") + local START_CMD=${DOKKU_DOCKERFILE_START_CMD:-$DOKKU_PROCFILE_START_CMD} + fi + + if [[ "$PROC_TYPE" == "web" ]]; then + if [[ -z "${DOKKU_DOCKERFILE_PORTS[*]}" ]]; then + local port=5000 + local DOKKU_DOCKER_PORT_ARGS+="-p $port" + else + local p + for p in ${DOKKU_DOCKERFILE_PORTS[*]};do + if [[ ! "$p" =~ .*udp.* ]]; then + # set port to first non-udp port + local p=${p//\/tcp} + local port=${port:="$p"} + fi + local DOKKU_DOCKER_PORT_ARGS+=" -p $p " + done + fi + if [[ "$DOKKU_IS_APP_PROXY_ENABLED" = "true" ]]; then + # shellcheck disable=SC2086 + local id=$(docker run $DOKKU_GLOBAL_RUN_ARGS -d -e PORT=$port $DOCKER_ARGS $IMAGE $START_CMD) + local ipaddr=$(docker inspect --format='{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' "$id") + # Docker < 1.9 compatibility + if [[ -z $ipaddr ]]; then + local ipaddr=$(docker inspect --format '{{ .NetworkSettings.IPAddress }}' "$id") + fi + else + # shellcheck disable=SC2086 + local id=$(docker run $DOKKU_GLOBAL_RUN_ARGS -d $DOKKU_DOCKER_PORT_ARGS -e PORT=$port $DOCKER_ARGS $IMAGE $START_CMD) + local port=$(docker port "$id" "$port" | sed 's/[0-9.]*://') + local ipaddr=127.0.0.1 + fi + else + # shellcheck disable=SC2086 + local id=$(docker run $DOKKU_GLOBAL_RUN_ARGS -d $DOCKER_ARGS $IMAGE $START_CMD) + fi + + # if we can't post-deploy successfully, kill new container + kill_new() { + local desc="wrapper function to kill newly started app container" + docker inspect "$id" &> /dev/null && docker stop "$id" > /dev/null && docker kill "$id" > /dev/null + trap - INT TERM EXIT + kill -9 $$ + } + + # run checks first, then post-deploy hooks, which switches Nginx traffic + if [[ "$(is_app_checks_enabled "$APP")" == "false" ]]; then + dokku_log_info1 "zero downtime is disabled for app ($APP). skipping pre-flight checks" + else + trap kill_new INT TERM EXIT + dokku_log_info1 "Running pre-flight checks" + plugn trigger check-deploy "$APP" "$id" "$PROC_TYPE" "$port" "$ipaddr" + trap - INT TERM EXIT + fi + + # now using the new container + [[ -n "$id" ]] && echo "$id" > "$DOKKU_CONTAINER_ID_FILE" + [[ -n "$ipaddr" ]] && echo "$ipaddr" > "$DOKKU_IP_FILE" + [[ -n "$port" ]] && echo "$port" > "$DOKKU_PORT_FILE" + + # cleanup pre-migration files + rm -f "$DOKKU_ROOT/$APP/CONTAINER" "$DOKKU_ROOT/$APP/IP" "$DOKKU_ROOT/$APP/PORT" + + local CONTAINER_INDEX=$(( CONTAINER_INDEX + 1 )) + done + # cleanup when we scale down + if [[ "$PROC_COUNT" == 0 ]]; then + local CONTAINER_IDX_OFFSET=0 + else + local CONTAINER_IDX_OFFSET=$((PROC_COUNT + 1)) + fi + local container_state_filetype + for container_state_filetype in CONTAINER IP PORT; do + cd "$DOKKU_ROOT/$APP" + find . -maxdepth 1 -name "$container_state_filetype.$PROC_TYPE.*" -printf "%f\n" | sort -t . -k 3 -n | tail -n +$CONTAINER_IDX_OFFSET | xargs rm -f + done + done < "$DOKKU_SCALE_FILE" + + dokku_log_info1 "Running post-deploy" + plugn trigger post-deploy "$APP" "$port" "$ipaddr" "$IMAGE_TAG" + + # kill the old container + if [[ -n "$oldids" ]]; then + + if [[ -z "$DOKKU_WAIT_TO_RETIRE" ]]; then + local DOKKU_APP_DOKKU_WAIT_TO_RETIRE=$(dokku config:get "$APP" DOKKU_WAIT_TO_RETIRE || true) + local DOKKU_GLOBAL_DOKKU_WAIT_TO_RETIRE=$(dokku config:get --global DOKKU_WAIT_TO_RETIRE || true) + local DOKKU_WAIT_TO_RETIRE=${DOKKU_APP_DOKKU_WAIT_TO_RETIRE:="$DOKKU_GLOBAL_DOKKU_WAIT_TO_RETIRE"} + fi + + # Let the old container finish processing requests, before terminating it + local WAIT="${DOKKU_WAIT_TO_RETIRE:-60}" + dokku_log_info1 "Shutting down old containers in $WAIT seconds" + local oldid + for oldid in $oldids; do + dokku_log_info2 "$oldid" + done + ( + exec >/dev/null 2>/dev/null /dev/null + + case "$IMAGE_SOURCE_TYPE" in + herokuish) + local id=$(tar -c . | docker run "$DOKKU_GLOBAL_RUN_ARGS" -i -a stdin "$DOKKU_IMAGE" /bin/bash -c "mkdir -p /app && tar -xC /app") + test "$(docker wait "$id")" -eq 0 + docker commit "$id" "$IMAGE" > /dev/null + [[ -d $CACHE_DIR ]] || mkdir "$CACHE_DIR" + plugn trigger pre-build-buildpack "$APP" + + local DOCKER_ARGS=$(: | plugn trigger docker-args-build "$APP" "$IMAGE_SOURCE_TYPE") + [[ "$DOKKU_TRACE" ]] && DOCKER_ARGS+=" -e TRACE=true " + # shellcheck disable=SC2086 + local id=$(docker run $DOKKU_GLOBAL_RUN_ARGS -d -v $CACHE_DIR:/cache -e CACHE_PATH=/cache $DOCKER_ARGS $IMAGE /build) + docker attach "$id" + test "$(docker wait "$id")" -eq 0 + docker commit "$id" "$IMAGE" > /dev/null + + plugn trigger post-build-buildpack "$APP" + ;; + + dockerfile) + # extract first port from Dockerfile + local DOCKERFILE_PORTS=$(get_dockerfile_exposed_ports Dockerfile) + [[ -n "$DOCKERFILE_PORTS" ]] && config_set --no-restart "$APP" DOKKU_DOCKERFILE_PORTS="$DOCKERFILE_PORTS" + plugn trigger pre-build-dockerfile "$APP" + + [[ "$DOKKU_DOCKERFILE_CACHE_BUILD" == "false" ]] && DOKKU_DOCKER_BUILD_OPTS="$DOKKU_DOCKER_BUILD_OPTS --no-cache" + local DOCKER_ARGS=$(: | plugn trigger docker-args-build "$APP" "$IMAGE_SOURCE_TYPE") + # shellcheck disable=SC2086 + docker build $DOCKER_ARGS $DOKKU_DOCKER_BUILD_OPTS -t $IMAGE . + + plugn trigger post-build-dockerfile "$APP" + ;; + + *) + dokku_log_fail "Building image source type $IMAGE_SOURCE_TYPE not supported!" + ;; + esac +} + +dokku_release() { + local APP="$2"; local IMAGE_SOURCE_TYPE="$3"; local IMAGE_TAG="$4"; local IMAGE=$(get_app_image_name "$APP" "$IMAGE_TAG") + verify_app_name "$APP" + + case "$IMAGE_SOURCE_TYPE" in + herokuish) + plugn trigger pre-release-buildpack "$APP" "$IMAGE_TAG" + if [[ -n $(config_export global) ]]; then + local id=$(config_export global | docker run "$DOKKU_GLOBAL_RUN_ARGS" -i -a stdin "$IMAGE" /bin/bash -c "mkdir -p /app/.profile.d && cat > /app/.profile.d/00-global-env.sh") + test "$(docker wait "$id")" -eq 0 + docker commit "$id" "$IMAGE" > /dev/null + fi + if [[ -n $(config_export app "$APP") ]]; then + local id=$(config_export app "$APP" | docker run "$DOKKU_GLOBAL_RUN_ARGS" -i -a stdin "$IMAGE" /bin/bash -c "mkdir -p /app/.profile.d && cat > /app/.profile.d/01-app-env.sh") + test "$(docker wait "$id")" -eq 0 + docker commit "$id" "$IMAGE" > /dev/null + fi + plugn trigger post-release-buildpack "$APP" "$IMAGE_TAG" + ;; + + dockerfile) + # buildstep plugins don't necessarily make sense for dockerfiles. call the new breed!!! + plugn trigger pre-release-dockerfile "$APP" "$IMAGE_TAG" + plugn trigger post-release-dockerfile "$APP" "$IMAGE_TAG" + ;; + + *) + dokku_log_fail "Releasing image source type $IMAGE_SOURCE_TYPE not supported!" + ;; + esac +} + +dokku_trace() { + [[ -d $DOKKU_ROOT/.dokkurc ]] || mkdir -p "$DOKKU_ROOT/.dokkurc" + [[ "$2" == "on" ]] || [[ "$2" == "off" ]] || { + dokku_log_fail "Valid trace options are [on/off]" + } + + if [[ "$2" == "on" ]]; then + echo "Enabling dokku trace" + echo "export DOKKU_TRACE=1" > "$DOKKU_ROOT/.dokkurc/DOKKU_TRACE" + fi + + if [[ "$2" == "off" ]]; then + echo "Disabling dokku trace" + rm -f "$DOKKU_ROOT/.dokkurc/DOKKU_TRACE" + fi +} + +dokku_ls() { + local installed_apps=$(dokku_apps) + local dokku_app + + dokku_col_log_info1_quiet "App Name" "Container Type" "Container Id" "Status" + + for dokku_app in $installed_apps; do + local APP=$(basename "$dokku_app") + local DOKKU_APP_CIDS=$(get_app_container_ids "$APP") + local DOCKER_RUNNING_CONTAINERS=$(docker ps -q --no-trunc) + if [[ -n $DOKKU_APP_CIDS ]]; then + local DOKKU_APP_CID + for DOKKU_APP_CID in $DOKKU_APP_CIDS; do + local DOKKU_APP_CONTAINER_STATUS="stopped" + [[ $DOCKER_RUNNING_CONTAINERS =~ $DOKKU_APP_CID ]] && local DOKKU_APP_CONTAINER_STATUS="running" + local DOKKU_APP_CONTAINER_TYPE=$(grep -l "$DOKKU_APP_CID" "$DOKKU_ROOT/$APP"/CONTAINER.* | awk -F '/' '{ print $5 }' | awk -F '.' '{ print $2 }') + dokku_col_log_msg "$APP" "$DOKKU_APP_CONTAINER_TYPE" "${DOKKU_APP_CID:0:12}" "$DOKKU_APP_CONTAINER_STATUS" + done + else + dokku_col_log_msg "$APP" "NOT_DEPLOYED" "NOT_DEPLOYED" "NOT_DEPLOYED" + fi + done +} + +dokku_run() { + [[ -z $2 ]] && dokku_log_fail "Please specify an app to run the command on" + local APP="$2"; local IMAGE_TAG=$(get_running_image_tag "$APP"); local IMAGE=$(get_app_image_name "$APP" "$IMAGE_TAG") + verify_app_name "$APP" + + shift 2 + + if [[ -z "$DOKKU_RM_CONTAINER" ]]; then + local DOKKU_APP_RM_CONTAINER=$(dokku config:get "$APP" DOKKU_RM_CONTAINER || true) + local DOKKU_GLOBAL_RM_CONTAINER=$(dokku config:get --global DOKKU_RM_CONTAINER || true) + local DOKKU_RM_CONTAINER=${DOKKU_APP_RM_CONTAINER:="$DOKKU_GLOBAL_RM_CONTAINER"} + fi + + local DOCKER_ARGS=$(: | plugn trigger docker-args-run "$APP" "$IMAGE_TAG") + [[ "$DOKKU_TRACE" ]] && local DOCKER_ARGS+=" -e TRACE=true " + [[ "$DOKKU_RM_CONTAINER" ]] && local DOKKU_RUN_OPTS="--rm" + has_tty && local DOKKU_RUN_OPTS+=" -i -t" + is_image_herokuish_based "$IMAGE" && EXEC_CMD="/exec" + # shellcheck disable=SC2086 + docker run $DOKKU_GLOBAL_RUN_ARGS $DOKKU_RUN_OPTS $DOCKER_ARGS $IMAGE $EXEC_CMD "$@" +} + case "$1" in + receive) + dokku_receive "$@" + ;; + + deploy) + dokku_deploy "$@" + ;; + build) - APP="$2"; IMAGE_SOURCE_TYPE="$3"; TMP_WORK_DIR="$4"; IMAGE=$(get_app_image_name "$APP") - verify_app_name "$APP" - - CACHE_DIR="$DOKKU_ROOT/$APP/cache" - - eval "$(config_export app "$APP")" - pushd "$TMP_WORK_DIR" &> /dev/null - - case "$IMAGE_SOURCE_TYPE" in - herokuish) - id=$(tar -c . | docker run "$DOKKU_GLOBAL_RUN_ARGS" -i -a stdin "$DOKKU_IMAGE" /bin/bash -c "mkdir -p /app && tar -xC /app") - test "$(docker wait "$id")" -eq 0 - docker commit "$id" "$IMAGE" > /dev/null - [[ -d $CACHE_DIR ]] || mkdir "$CACHE_DIR" - plugn trigger pre-build-buildpack "$APP" - - DOCKER_ARGS=$(: | plugn trigger docker-args-build "$APP" "$IMAGE_SOURCE_TYPE") - [[ "$DOKKU_TRACE" ]] && DOCKER_ARGS+=" -e TRACE=true " - # shellcheck disable=SC2086 - id=$(docker run $DOKKU_GLOBAL_RUN_ARGS -d -v $CACHE_DIR:/cache -e CACHE_PATH=/cache $DOCKER_ARGS $IMAGE /build) - docker attach "$id" - test "$(docker wait "$id")" -eq 0 - docker commit "$id" "$IMAGE" > /dev/null - - plugn trigger post-build-buildpack "$APP" - ;; - - dockerfile) - # extract first port from Dockerfile - DOCKERFILE_PORTS=$(get_dockerfile_exposed_ports Dockerfile) - [[ -n "$DOCKERFILE_PORTS" ]] && config_set --no-restart "$APP" DOKKU_DOCKERFILE_PORTS="$DOCKERFILE_PORTS" - plugn trigger pre-build-dockerfile "$APP" - - [[ "$DOKKU_DOCKERFILE_CACHE_BUILD" == "false" ]] && DOKKU_DOCKER_BUILD_OPTS="$DOKKU_DOCKER_BUILD_OPTS --no-cache" - DOCKER_ARGS=$(: | plugn trigger docker-args-build "$APP" "$IMAGE_SOURCE_TYPE") - # shellcheck disable=SC2086 - docker build $DOCKER_ARGS $DOKKU_DOCKER_BUILD_OPTS -t $IMAGE . - - plugn trigger post-build-dockerfile "$APP" - ;; - - *) - dokku_log_fail "Building image source type $IMAGE_SOURCE_TYPE not supported!" - ;; - esac + dokku_build "$@" ;; release) - APP="$2"; IMAGE_SOURCE_TYPE="$3"; IMAGE_TAG="$4"; IMAGE=$(get_app_image_name "$APP" "$IMAGE_TAG") - verify_app_name "$APP" - - case "$IMAGE_SOURCE_TYPE" in - herokuish) - plugn trigger pre-release-buildpack "$APP" "$IMAGE_TAG" - if [[ -n $(config_export global) ]]; then - id=$(config_export global | docker run "$DOKKU_GLOBAL_RUN_ARGS" -i -a stdin "$IMAGE" /bin/bash -c "mkdir -p /app/.profile.d && cat > /app/.profile.d/00-global-env.sh") - test "$(docker wait "$id")" -eq 0 - docker commit "$id" "$IMAGE" > /dev/null - fi - if [[ -n $(config_export app "$APP") ]]; then - id=$(config_export app "$APP" | docker run "$DOKKU_GLOBAL_RUN_ARGS" -i -a stdin "$IMAGE" /bin/bash -c "mkdir -p /app/.profile.d && cat > /app/.profile.d/01-app-env.sh") - test "$(docker wait "$id")" -eq 0 - docker commit "$id" "$IMAGE" > /dev/null - fi - plugn trigger post-release-buildpack "$APP" "$IMAGE_TAG" - ;; - - dockerfile) - # buildstep plugins don't necessarily make sense for dockerfiles. call the new breed!!! - plugn trigger pre-release-dockerfile "$APP" "$IMAGE_TAG" - plugn trigger post-release-dockerfile "$APP" "$IMAGE_TAG" - ;; - - *) - dokku_log_fail "Releasing image source type $IMAGE_SOURCE_TYPE not supported!" - ;; - esac + dokku_release "$@" ;; trace) - [[ -d $DOKKU_ROOT/.dokkurc ]] || mkdir -p "$DOKKU_ROOT/.dokkurc" - [[ "$2" == "on" ]] || [[ "$2" == "off" ]] || { - dokku_log_fail "Valid trace options are [on/off]" - } - - if [[ "$2" == "on" ]]; then - echo "Enabling dokku trace" - echo "export DOKKU_TRACE=1" > "$DOKKU_ROOT/.dokkurc/DOKKU_TRACE" - fi - - if [[ "$2" == "off" ]]; then - echo "Disabling dokku trace" - rm -f "$DOKKU_ROOT/.dokkurc/DOKKU_TRACE" - fi + dokku_trace "$@" ;; delete) @@ -109,47 +344,15 @@ case "$1" in ;; ls) - installed_apps=$(dokku_apps) - - dokku_col_log_info1_quiet "App Name" "Container Type" "Container Id" "Status" - - for dokku_app in $installed_apps; do - APP=$(basename "$dokku_app") - DOKKU_APP_CIDS=$(get_app_container_ids "$APP") - DOCKER_RUNNING_CONTAINERS=$(docker ps -q --no-trunc) - if [[ -n $DOKKU_APP_CIDS ]]; then - for DOKKU_APP_CID in $DOKKU_APP_CIDS; do - DOKKU_APP_CONTAINER_STATUS="stopped" - [[ $DOCKER_RUNNING_CONTAINERS =~ $DOKKU_APP_CID ]] && DOKKU_APP_CONTAINER_STATUS="running" - DOKKU_APP_CONTAINER_TYPE=$(grep -l "$DOKKU_APP_CID" "$DOKKU_ROOT/$APP"/CONTAINER.* | awk -F '/' '{ print $5 }' | awk -F '.' '{ print $2 }') - dokku_col_log_msg "$APP" "$DOKKU_APP_CONTAINER_TYPE" "${DOKKU_APP_CID:0:12}" "$DOKKU_APP_CONTAINER_STATUS" - done - else - dokku_col_log_msg "$APP" "NOT_DEPLOYED" "NOT_DEPLOYED" "NOT_DEPLOYED" - fi - done + dokku_ls "$@" ;; run) - [[ -z $2 ]] && dokku_log_fail "Please specify an app to run the command on" - APP="$2"; IMAGE_TAG=$(get_running_image_tag "$APP"); IMAGE=$(get_app_image_name "$APP" "$IMAGE_TAG") - verify_app_name "$APP" + dokku_run "$@" + ;; - shift 2 - - if [[ -z "$DOKKU_RM_CONTAINER" ]]; then - DOKKU_APP_RM_CONTAINER=$(dokku config:get "$APP" DOKKU_RM_CONTAINER || true) - DOKKU_GLOBAL_RM_CONTAINER=$(dokku config:get --global DOKKU_RM_CONTAINER || true) - DOKKU_RM_CONTAINER=${DOKKU_APP_RM_CONTAINER:="$DOKKU_GLOBAL_RM_CONTAINER"} - fi - - DOCKER_ARGS=$(: | plugn trigger docker-args-run "$APP" "$IMAGE_TAG") - [[ "$DOKKU_TRACE" ]] && DOCKER_ARGS+=" -e TRACE=true " - [[ "$DOKKU_RM_CONTAINER" ]] && DOKKU_RUN_OPTS="--rm" - has_tty && DOKKU_RUN_OPTS+=" -i -t" - is_image_herokuish_based "$IMAGE" && EXEC_CMD="/exec" - # shellcheck disable=SC2086 - docker run $DOKKU_GLOBAL_RUN_ARGS $DOKKU_RUN_OPTS $DOCKER_ARGS $IMAGE $EXEC_CMD "$@" + cleanup) + docker_cleanup ;; url | urls) diff --git a/plugins/00_dokku-standard/exec-app-json-scripts b/plugins/00_dokku-standard/exec-app-json-scripts index 009297c0b..a12563511 100755 --- a/plugins/00_dokku-standard/exec-app-json-scripts +++ b/plugins/00_dokku-standard/exec-app-json-scripts @@ -17,6 +17,7 @@ case "$0" in esac get_phase_script() { + local desc="extracts app.json from app image and returns the appropriate json key/value" local PHASE_SCRIPT_KEY="$1" local TMP_WORK_DIR=$(mktemp -d -t "dokku_get_phase_script.XXXX") local APP_JSON_FILE="$TMP_WORK_DIR/app.json" @@ -34,6 +35,7 @@ get_phase_script() { } execute_script() { + local desc="executes appropriate phase script key from app.json" local SCRIPT_CMD=$(get_phase_script "$PHASE_SCRIPT_KEY") if [[ -n "$SCRIPT_CMD" ]];then dokku_log_info1 "Running '$SCRIPT_CMD' in app container" diff --git a/plugins/20_events/commands b/plugins/20_events/commands index d661899bb..07a975254 100755 --- a/plugins/20_events/commands +++ b/plugins/20_events/commands @@ -1,43 +1,8 @@ #!/usr/bin/env bash -[[ " events events:on events:off events:list help events:help " == *" $1 "* ]] || exit "$DOKKU_NOT_IMPLEMENTED_EXIT" +[[ " help events:help " == *" $1 "* ]] || exit "$DOKKU_NOT_IMPLEMENTED_EXIT" set -eo pipefail; [[ $DOKKU_TRACE ]] && set -x -source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions" case "$1" in - events) - if [[ -f $DOKKU_EVENTS_LOGFILE ]]; then - if [[ $2 == "-t" ]]; then - tail -F "$DOKKU_EVENTS_LOGFILE" - else - tail -n 100 "$DOKKU_EVENTS_LOGFILE" - fi - fi - ;; - - events:on) - echo "Enabling dokku events logger" - [[ -d $DOKKU_ROOT/.dokkurc ]] || mkdir -p "$DOKKU_ROOT/.dokkurc" - echo "export DOKKU_EVENTS=1" > "$DOKKU_ROOT/.dokkurc/DOKKU_EVENTS" - ;; - - events:off) - echo "Disabling dokku events logger" - rm -f "$DOKKU_ROOT/.dokkurc/DOKKU_EVENTS" - ;; - - events:list) - PLUGIN_DIR="$(dirname "$0")/" - if [[ "$DOKKU_EVENTS" ]]; then - logged="$(find "$PLUGIN_DIR" -type l -printf '%f ' | sort)" - dokku_col_log_info2_quiet "Events currently logged" - for hook in $logged; do - dokku_col_log_msg "$hook" - done - else - dokku_log_warn "Events logger disabled" - fi - ;; - help | events:help) cat< "$DOKKU_ROOT/.dokkurc/DOKKU_EVENTS" +} + +events_on_cmd "$@" diff --git a/plugins/apps/commands b/plugins/apps/commands index 14a57b379..6a3f21f47 100755 --- a/plugins/apps/commands +++ b/plugins/apps/commands @@ -1,73 +1,8 @@ #!/usr/bin/env bash -[[ " apps apps:create apps:rename apps:destroy help apps:help " == *" $1 "* ]] || exit "$DOKKU_NOT_IMPLEMENTED_EXIT" +[[ " help apps:help " == *" $1 "* ]] || exit "$DOKKU_NOT_IMPLEMENTED_EXIT" set -eo pipefail; [[ $DOKKU_TRACE ]] && set -x -source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions" -source "$PLUGIN_AVAILABLE_PATH/apps/functions" case "$1" in - apps) - dokku_log_info2_quiet "My Apps" - for app in $(dokku_apps); do - echo "$app" - done - ;; - - apps:create) - apps_create "$2" - ;; - - apps:rename) - [[ -z $2 ]] && dokku_log_fail "Please specify an app to run the command on" - [[ -d "$DOKKU_ROOT/$3" ]] && dokku_log_fail "Name is already taken" - OLD_APP="$2" - NEW_APP="$3" - - mkdir -p "$DOKKU_ROOT/$NEW_APP" - docker run "$DOKKU_GLOBAL_RUN_ARGS" --rm -v "$DOKKU_ROOT/$OLD_APP/cache:/cache" "dokku/$OLD_APP" chmod 777 -R /cache - rm -rf "$DOKKU_ROOT/$OLD_APP/cache" - cp -a "$DOKKU_ROOT/$OLD_APP/." "$DOKKU_ROOT/$NEW_APP" - dokku apps:destroy "$OLD_APP" --force - sed -i -e "s/$OLD_APP/$NEW_APP/g" "$DOKKU_ROOT/$NEW_APP/URLS" - sed -i -e "s/$OLD_APP/$NEW_APP/g" "$DOKKU_ROOT/$NEW_APP/VHOST" - sed -i -e "s/git-hook $OLD_APP/git-hook $NEW_APP/g" "$DOKKU_ROOT/$NEW_APP/hooks/pre-receive" - dokku ps:rebuild "$NEW_APP" - plugn trigger post-app-rename "$OLD_APP" "$NEW_APP" - echo "Renaming $OLD_APP to $NEW_APP... done" - ;; - - apps:destroy) - [[ -z $2 ]] && dokku_log_fail "Please specify an app to run the command on" - [[ "$2" == "tls" ]] && dokku_log_fail "Unable to destroy tls directory" - [[ "$3" == "force" ]] && DOKKU_APPS_FORCE_DELETE=1 - APP="$2"; IMAGE_TAG=$(get_running_image_tag "$APP") - verify_app_name "$APP" - - if [[ -z "$DOKKU_APPS_FORCE_DELETE" ]]; then - dokku_log_warn "WARNING: Potentially Destructive Action" - dokku_log_warn "This command will destroy $APP (including all add-ons)." - dokku_log_warn "To proceed, type \"$APP\"" - echo "" - - read -rp "> " app_name - if [[ "$app_name" != "$APP" ]]; then - dokku_log_fail "Confirmation did not match $APP. Aborted." - fi - fi - - echo "Destroying $APP (including all add-ons)" - - plugn trigger pre-delete "$APP" "$IMAGE_TAG" - DOKKU_APP_CIDS=$(get_app_container_ids "$APP") - if [[ -n $DOKKU_APP_CIDS ]]; then - for ID in $DOKKU_APP_CIDS; do - docker stop "$ID" > /dev/null || true - docker rm "$ID" > /dev/null || true - done - fi - - plugn trigger post-delete "$APP" "$IMAGE_TAG" - ;; - help | apps:help) cat< " app_name + if [[ "$app_name" != "$APP" ]]; then + dokku_log_fail "Confirmation did not match $APP. Aborted." + fi + fi + + echo "Destroying $APP (including all add-ons)" + + plugn trigger pre-delete "$APP" "$IMAGE_TAG" + local DOKKU_APP_CIDS=$(get_app_container_ids "$APP") + local cid + + if [[ -n $DOKKU_APP_CIDS ]]; then + for cid in $DOKKU_APP_CIDS; do + docker stop "$cid" > /dev/null || true + docker rm "$cid" > /dev/null || true + done + fi + + plugn trigger post-delete "$APP" "$IMAGE_TAG" +} + +apps_destroy_cmd "$@" diff --git a/plugins/apps/subcommands/rename b/plugins/apps/subcommands/rename new file mode 100755 index 000000000..cac21cf1b --- /dev/null +++ b/plugins/apps/subcommands/rename @@ -0,0 +1,26 @@ +#!/usr/bin/env bash +set -eo pipefail; [[ $DOKKU_TRACE ]] && set -x +source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions" + +apps_rename_cmd() { + local desc="renames an app" + local cmd="apps:rename" + [[ -z $2 ]] && dokku_log_fail "Please specify an app to run the command on" + [[ -d "$DOKKU_ROOT/$3" ]] && dokku_log_fail "Name is already taken" + local OLD_APP="$2" + local NEW_APP="$3" + + mkdir -p "$DOKKU_ROOT/$NEW_APP" + docker run "$DOKKU_GLOBAL_RUN_ARGS" --rm -v "$DOKKU_ROOT/$OLD_APP/cache:/cache" "dokku/$OLD_APP" chmod 777 -R /cache + rm -rf "$DOKKU_ROOT/$OLD_APP/cache" + cp -a "$DOKKU_ROOT/$OLD_APP/." "$DOKKU_ROOT/$NEW_APP" + dokku apps:destroy "$OLD_APP" --force + sed -i -e "s/$OLD_APP/$NEW_APP/g" "$DOKKU_ROOT/$NEW_APP/URLS" + sed -i -e "s/$OLD_APP/$NEW_APP/g" "$DOKKU_ROOT/$NEW_APP/VHOST" + sed -i -e "s/git-hook $OLD_APP/git-hook $NEW_APP/g" "$DOKKU_ROOT/$NEW_APP/hooks/pre-receive" + dokku ps:rebuild "$NEW_APP" + plugn trigger post-app-rename "$OLD_APP" "$NEW_APP" + echo "Renaming $OLD_APP to $NEW_APP... done" +} + +apps_rename_cmd "$@" diff --git a/plugins/certs/commands b/plugins/certs/commands index cddc43bff..ed188e98b 100755 --- a/plugins/certs/commands +++ b/plugins/certs/commands @@ -1,170 +1,8 @@ #!/usr/bin/env bash -[[ " certs:add certs:generate certs:info certs:remove certs:update help certs:help " == *" $1 "* ]] || exit "$DOKKU_NOT_IMPLEMENTED_EXIT" +[[ " help certs:help " == *" $1 "* ]] || exit "$DOKKU_NOT_IMPLEMENTED_EXIT" set -eo pipefail; [[ $DOKKU_TRACE ]] && set -x -source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions" -source "$PLUGIN_AVAILABLE_PATH/certs/functions" -source "$PLUGIN_AVAILABLE_PATH/nginx-vhosts/functions" - -is_tar_import() { - [[ -t 0 ]] && return 1 - return 0 -} - -is_file_import() { - local CRT_FILE="$1" - local KEY_FILE="$2" - - if [[ $CRT_FILE ]] && [[ $KEY_FILE ]]; then - if [[ ! -f $CRT_FILE ]]; then - dokku_log_fail "CRT file specified not found, please check file paths" - elif [[ ! -f $KEY_FILE ]]; then - dokku_log_fail "KEY file specified not found, please check file paths" - else - return 0 - fi - fi - - return 1 -} - -certs_set() { - [[ -z $2 ]] && dokku_log_fail "Please specify an app to run the command on" - verify_app_name "$2" - local APP="$2"; local CRT_FILE="$3"; local KEY_FILE="$4"; local APP_SSL_PATH="$DOKKU_ROOT/$APP/tls" - - is_file_import "$CRT_FILE" "$KEY_FILE" || is_tar_import || dokku_log_fail "Tar archive containing server.crt and server.key expected on stdin" - - if is_tar_import; then - TEMP_DIR=$(mktemp -d -t "dokku_certs_set.XXXX") - pushd "$TEMP_DIR" &> /dev/null - trap 'popd &> /dev/null || true; rm -rf $TEMP_DIR > /dev/null' RETURN - tar xvf - <&0 - - CRT_FILE_SEARCH=$(find . -not -path '*/\.*' -type f -name "*.crt") - CRT_FILE_COUNT=$(printf "%s" "$CRT_FILE_SEARCH" | grep -c '^') - if [[ $CRT_FILE_COUNT -lt 1 ]]; then - dokku_log_fail "Tar archive is missing .crt file" - elif [[ $CRT_FILE_COUNT -gt 1 ]]; then - dokku_log_fail "Tar archive contains more than one .crt file" - else - CRT_FILE=$CRT_FILE_SEARCH - fi - - KEY_FILE_SEARCH=$(find . -not -path '*/\.*' -type f -name "*.key") - KEY_FILE_COUNT=$(printf "%s" "$KEY_FILE_SEARCH" | grep -c '^') - if [[ $KEY_FILE_COUNT -lt 1 ]]; then - dokku_log_fail "Tar archive is missing .key file" - elif [[ $KEY_FILE_COUNT -gt 1 ]]; then - dokku_log_fail "Tar archive contains more than one .key file" - else - KEY_FILE=$KEY_FILE_SEARCH - fi - fi - - mkdir -p "$APP_SSL_PATH" - cp "$CRT_FILE" "$APP_SSL_PATH/server.crt" - cp "$KEY_FILE" "$APP_SSL_PATH/server.key" - chmod 750 "$APP_SSL_PATH" - chmod 640 "$APP_SSL_PATH/server.crt" "$APP_SSL_PATH/server.key" - cd "$DOKKU_ROOT" - nginx_build_config "$APP" -} case "$1" in - certs:add) - certs_set "$@" - ;; - - certs:generate) - [[ -z $2 ]] && dokku_log_fail "Please specify an app to run the command on" - verify_app_name "$2" - APP="$2"; DOMAIN="$3"; APP_SSL_PATH="$DOKKU_ROOT/$APP/tls" - - if [[ ! -f "$APP_SSL_PATH/server.key" ]] && [[ ! -f "$APP_SSL_PATH/server.crt" ]]; then - TMP_WORK_DIR=$(mktemp -d -t "dokku_certs.XXXXXXXXX") - pushd "$TMP_WORK_DIR" > /dev/null - trap 'popd &> /dev/null || true; rm -rf "$TMP_WORK_DIR" > /dev/null' INT TERM EXIT - - openssl genrsa -des3 -passout pass:x -out server.pass.key 2048 - openssl rsa -passin pass:x -in server.pass.key -out server.key - openssl req -new -key server.key -out server.csr - openssl x509 -req -days 365 -in server.csr -signkey server.key -out server.crt - - mkdir -p "$APP_SSL_PATH" - dokku_log_info1 "Installing certificate and key..." - mv -f "$TMP_WORK_DIR/server.key" "$TMP_WORK_DIR/server.crt" "$APP_SSL_PATH" - chmod 750 "$APP_SSL_PATH" - chmod 640 "$APP_SSL_PATH/server.key" "$APP_SSL_PATH/server.crt" - [[ -n "$DOMAIN" ]] && (dokku domains:add "$APP" "$DOMAIN" || nginx_build_config "$APP") - dokku_log_info1 "The following is a certificate signing request that can be used" - dokku_log_info1 "to generate an 'officially' signed SSL certificate for $APP at $DOMAIN" - dokku_log_info1 "by a CA of your choosing." - cat server.csr - else - dokku_log_info1 "$APP has an SSL endpoint already defined" - fi - ;; - - certs:info) - [[ -z $2 ]] && dokku_log_fail "Please specify an app to run the command on" - verify_app_name "$2" - APP="$2"; SSL_TYPE=$(is_ssl_enabled "$APP") - case "$SSL_TYPE" in - app) - SSL_PATH="$DOKKU_ROOT/$APP/tls" - ;; - - global) - SSL_PATH="$DOKKU_ROOT/tls" - ;; - - *) - ;; - esac - - if [[ -n "$SSL_PATH" ]]; then - dokku_log_info1 "Fetching SSL Endpoint info for $APP..." - dokku_log_info1 "Certificate details:" - dokku_log_info2 "Common Name(s): " - - for domain in $(get_ssl_hostnames "$APP" | xargs); do - dokku_log_info2 " $domain" - done - - dokku_log_info2 "Expires At: $(openssl x509 -in "$SSL_PATH/server.crt" -noout -text | grep "Not After :" | awk -F " : " '{ print $2 }')" - dokku_log_info2 "Issuer: $(openssl x509 -in "$SSL_PATH/server.crt" -noout -text | grep "Issuer:" | xargs | sed -e "s/Issuer: //g")" - dokku_log_info2 "Starts At: $(openssl x509 -in "$SSL_PATH/server.crt" -noout -text | grep "Not Before:" | awk -F ": " '{ print $2 }')" - dokku_log_info2 "Subject: $(openssl x509 -in "$SSL_PATH/server.crt" -noout -subject | sed -e "s:subject= ::g"| sed -e "s:^/::g" | sed -e "s:/:; :g")" - SSL_VERIFY_OUTPUT="$(openssl verify -verbose -purpose sslserver "$SSL_PATH/server.crt" | awk -F ':' '{ print $2 }' | tail -1 | xargs || true)" - if [[ "$SSL_VERIFY_OUTPUT" == "OK" ]]; then - SSL_SELF_SIGNED="verified by a certificate authority." - else - SSL_SELF_SIGNED="self signed." - fi - dokku_log_info2 "SSL certificate is $SSL_SELF_SIGNED" - else - dokku_log_info1 "$APP does not have an SSL endpoint" - fi - ;; - - certs:remove) - [[ -z $2 ]] && dokku_log_fail "Please specify an app to run the command on" - verify_app_name "$2" - APP="$2"; APP_SSL_PATH="$DOKKU_ROOT/$APP/tls" - - if [[ -d "$APP_SSL_PATH" ]]; then - dokku_log_info1 "Removing SSL endpoint from $APP" - rm -rf "$APP_SSL_PATH" - plugn trigger post-domains-update "$APP" - else - dokku_log_fail "An app-specific SSL endpoint is not defined" - fi - ;; - - certs:update) - certs_set "$@" - ;; - help | certs:help) cat< CRT KEY, Add an ssl endpoint to an app. Can also import from a tarball on stdin diff --git a/plugins/certs/functions b/plugins/certs/functions index 25200f5bb..b9d5f541d 100755 --- a/plugins/certs/functions +++ b/plugins/certs/functions @@ -2,9 +2,8 @@ set -eo pipefail; [[ $DOKKU_TRACE ]] && set -x source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions" -# returns 'global', 'app', 'false' -# if both are configured, app trumps global is_ssl_enabled() { + local desc="returns 0 if ssl is enabled for given app" local APP=$1; verify_app_name "$APP" APP_SSL_PATH="$DOKKU_ROOT/$APP/tls" @@ -16,6 +15,7 @@ is_ssl_enabled() { } get_ssl_hostnames() { + local desc="returns a string of ssl hostnames extracted from an app's ssl certificate" local APP=$1; verify_app_name "$APP" local SSL_PATH="$DOKKU_ROOT/$APP/tls" diff --git a/plugins/certs/subcommands/add b/plugins/certs/subcommands/add new file mode 100755 index 000000000..15084ee23 --- /dev/null +++ b/plugins/certs/subcommands/add @@ -0,0 +1,76 @@ +#!/usr/bin/env bash +set -eo pipefail; [[ $DOKKU_TRACE ]] && set -x +source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions" +source "$PLUGIN_AVAILABLE_PATH/certs/functions" +source "$PLUGIN_AVAILABLE_PATH/nginx-vhosts/functions" + +is_tar_import() { + local desc="determines if we have STDIN open in an attempt to detect a streamed tar import" + [[ -t 0 ]] && return 1 + return 0 +} + +is_file_import() { + local desc="determines if we have passed in a file and key path for a file import" + local CRT_FILE="$1" + local KEY_FILE="$2" + + if [[ $CRT_FILE ]] && [[ $KEY_FILE ]]; then + if [[ ! -f $CRT_FILE ]]; then + dokku_log_fail "CRT file specified not found, please check file paths" + elif [[ ! -f $KEY_FILE ]]; then + dokku_log_fail "KEY file specified not found, please check file paths" + else + return 0 + fi + fi + + return 1 +} + +certs_set() { + local desc="imports an SSL cert/key combo either on STDIN via a tarball or from specified cert/key filenames" + local cmd="$1" + [[ -z $2 ]] && dokku_log_fail "Please specify an app to run the command on" + verify_app_name "$2" + local APP="$2"; local CRT_FILE="$3"; local KEY_FILE="$4"; local APP_SSL_PATH="$DOKKU_ROOT/$APP/tls" + + is_file_import "$CRT_FILE" "$KEY_FILE" || is_tar_import || dokku_log_fail "Tar archive containing server.crt and server.key expected on stdin" + + if is_tar_import; then + local TEMP_DIR=$(mktemp -d -t "dokku_certs_set.XXXX") + pushd "$TEMP_DIR" &> /dev/null + trap 'popd &> /dev/null || true; rm -rf $TEMP_DIR > /dev/null' RETURN + tar xvf - <&0 + + local CRT_FILE_SEARCH=$(find . -not -path '*/\.*' -type f -name "*.crt") + local CRT_FILE_COUNT=$(printf "%s" "$CRT_FILE_SEARCH" | grep -c '^') + if [[ $CRT_FILE_COUNT -lt 1 ]]; then + dokku_log_fail "Tar archive is missing .crt file" + elif [[ $CRT_FILE_COUNT -gt 1 ]]; then + dokku_log_fail "Tar archive contains more than one .crt file" + else + local CRT_FILE=$CRT_FILE_SEARCH + fi + + local KEY_FILE_SEARCH=$(find . -not -path '*/\.*' -type f -name "*.key") + local KEY_FILE_COUNT=$(printf "%s" "$KEY_FILE_SEARCH" | grep -c '^') + if [[ $KEY_FILE_COUNT -lt 1 ]]; then + dokku_log_fail "Tar archive is missing .key file" + elif [[ $KEY_FILE_COUNT -gt 1 ]]; then + dokku_log_fail "Tar archive contains more than one .key file" + else + local KEY_FILE=$KEY_FILE_SEARCH + fi + fi + + mkdir -p "$APP_SSL_PATH" + cp "$CRT_FILE" "$APP_SSL_PATH/server.crt" + cp "$KEY_FILE" "$APP_SSL_PATH/server.key" + chmod 750 "$APP_SSL_PATH" + chmod 640 "$APP_SSL_PATH/server.crt" "$APP_SSL_PATH/server.key" + cd "$DOKKU_ROOT" + nginx_build_config "$APP" +} + +certs_set "$@" diff --git a/plugins/certs/subcommands/generate b/plugins/certs/subcommands/generate new file mode 100755 index 000000000..1a7e95cb8 --- /dev/null +++ b/plugins/certs/subcommands/generate @@ -0,0 +1,39 @@ +#!/usr/bin/env bash +set -eo pipefail; [[ $DOKKU_TRACE ]] && set -x +source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions" +source "$PLUGIN_AVAILABLE_PATH/domains/functions" +source "$PLUGIN_AVAILABLE_PATH/nginx-vhosts/functions" + +certs_generate_cmd() { + local desc="generates a self-signed SSL certificate/key combo" + local cmd="certs:generate" + [[ -z $2 ]] && dokku_log_fail "Please specify an app to run the command on" + verify_app_name "$2" + local APP="$2"; local DOMAIN="$3"; local APP_SSL_PATH="$DOKKU_ROOT/$APP/tls" + + if [[ ! -f "$APP_SSL_PATH/server.key" ]] && [[ ! -f "$APP_SSL_PATH/server.crt" ]]; then + local TMP_WORK_DIR=$(mktemp -d -t "dokku_certs.XXXXXXXXX") + pushd "$TMP_WORK_DIR" > /dev/null + trap 'popd &> /dev/null || true; rm -rf "$TMP_WORK_DIR" > /dev/null' INT TERM EXIT + + openssl genrsa -des3 -passout pass:x -out server.pass.key 2048 + openssl rsa -passin pass:x -in server.pass.key -out server.key + openssl req -new -key server.key -out server.csr + openssl x509 -req -days 365 -in server.csr -signkey server.key -out server.crt + + mkdir -p "$APP_SSL_PATH" + dokku_log_info1 "Installing certificate and key..." + mv -f "$TMP_WORK_DIR/server.key" "$TMP_WORK_DIR/server.crt" "$APP_SSL_PATH" + chmod 750 "$APP_SSL_PATH" + chmod 640 "$APP_SSL_PATH/server.key" "$APP_SSL_PATH/server.crt" + [[ -n "$DOMAIN" ]] && (domains_add "$APP" "$DOMAIN" || nginx_build_config "$APP") + dokku_log_info1 "The following is a certificate signing request that can be used" + dokku_log_info1 "to generate an 'officially' signed SSL certificate for $APP at $DOMAIN" + dokku_log_info1 "by a CA of your choosing." + cat server.csr + else + dokku_log_info1 "$APP has an SSL endpoint already defined" + fi +} + +certs_generate_cmd "$@" diff --git a/plugins/certs/subcommands/info b/plugins/certs/subcommands/info new file mode 100755 index 000000000..7241eba29 --- /dev/null +++ b/plugins/certs/subcommands/info @@ -0,0 +1,38 @@ +#!/usr/bin/env bash +set -eo pipefail; [[ $DOKKU_TRACE ]] && set -x +source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions" +source "$PLUGIN_AVAILABLE_PATH/certs/functions" + +certs_info_cmd() { + local desc="prints SSL certificate info for app" + local cmd="certs:info" + [[ -z $2 ]] && dokku_log_fail "Please specify an app to run the command on" + verify_app_name "$2" + local APP="$2"; local APP_SSL_PATH="$DOKKU_ROOT/$APP/tls" + + if [[ -n "$APP_SSL_PATH" ]]; then + dokku_log_info1 "Fetching SSL Endpoint info for $APP..." + dokku_log_info1 "Certificate details:" + dokku_log_info2 "Common Name(s): " + + for domain in $(get_ssl_hostnames "$APP" | xargs); do + dokku_log_info2 " $domain" + done + + dokku_log_info2 "Expires At: $(openssl x509 -in "$APP_SSL_PATH/server.crt" -noout -text | grep "Not After :" | awk -F " : " '{ print $2 }')" + dokku_log_info2 "Issuer: $(openssl x509 -in "$APP_SSL_PATH/server.crt" -noout -text | grep "Issuer:" | xargs | sed -e "s/Issuer: //g")" + dokku_log_info2 "Starts At: $(openssl x509 -in "$APP_SSL_PATH/server.crt" -noout -text | grep "Not Before:" | awk -F ": " '{ print $2 }')" + dokku_log_info2 "Subject: $(openssl x509 -in "$APP_SSL_PATH/server.crt" -noout -subject | sed -e "s:subject= ::g"| sed -e "s:^/::g" | sed -e "s:/:; :g")" + SSL_VERIFY_OUTPUT="$(openssl verify -verbose -purpose sslserver "$APP_SSL_PATH/server.crt" | awk -F ':' '{ print $2 }' | tail -1 | xargs || true)" + if [[ "$SSL_VERIFY_OUTPUT" == "OK" ]]; then + SSL_SELF_SIGNED="verified by a certificate authority." + else + SSL_SELF_SIGNED="self signed." + fi + dokku_log_info2 "SSL certificate is $SSL_SELF_SIGNED" + else + dokku_log_info1 "$APP does not have an SSL endpoint" + fi +} + +certs_info_cmd "$@" diff --git a/plugins/certs/subcommands/remove b/plugins/certs/subcommands/remove new file mode 100755 index 000000000..46a93ee13 --- /dev/null +++ b/plugins/certs/subcommands/remove @@ -0,0 +1,21 @@ +#!/usr/bin/env bash +set -eo pipefail; [[ $DOKKU_TRACE ]] && set -x +source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions" + +certs_remove_cmd() { + local desc="removes SSL cert/key from specified app" + local cmd="certs:remove" + [[ -z $2 ]] && dokku_log_fail "Please specify an app to run the command on" + verify_app_name "$2" + local APP="$2"; local APP_SSL_PATH="$DOKKU_ROOT/$APP/tls" + + if [[ -d "$APP_SSL_PATH" ]]; then + dokku_log_info1 "Removing SSL endpoint from $APP" + rm -rf "$APP_SSL_PATH" + plugn trigger post-domains-update "$APP" + else + dokku_log_fail "An app-specific SSL endpoint is not defined" + fi +} + +certs_remove_cmd "$@" diff --git a/plugins/certs/subcommands/update b/plugins/certs/subcommands/update new file mode 120000 index 000000000..d28d40b18 --- /dev/null +++ b/plugins/certs/subcommands/update @@ -0,0 +1 @@ +add \ No newline at end of file diff --git a/plugins/checks/check-deploy b/plugins/checks/check-deploy index d34bd4a22..4a4a08ce9 100755 --- a/plugins/checks/check-deploy +++ b/plugins/checks/check-deploy @@ -78,6 +78,7 @@ docker cp $DOKKU_APP_CONTAINER_ID:/app/CHECKS "$TMPDIR" 2> /dev/null || true FILENAME=${TMPDIR}/CHECKS cleanup() { + local desc="cleans up TMPDIR and print container output" rm -rf "$TMPDIR" dokku_log_info2_quiet "$APP container output:" dokku_container_log_verbose_quiet $DOKKU_APP_CONTAINER_ID diff --git a/plugins/checks/commands b/plugins/checks/commands index 54a4d4f1e..2f95816d0 100755 --- a/plugins/checks/commands +++ b/plugins/checks/commands @@ -1,67 +1,8 @@ #!/usr/bin/env bash -[[ " checks checks:enable checks:disable help ps:help " == *" $1 "* ]] || exit "$DOKKU_NOT_IMPLEMENTED_EXIT" +[[ " help checks:help " == *" $1 "* ]] || exit "$DOKKU_NOT_IMPLEMENTED_EXIT" set -eo pipefail; [[ $DOKKU_TRACE ]] && set -x -source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions" -source "$PLUGIN_AVAILABLE_PATH/checks/functions" - -checks_main() { - local desc="displays app zero-downtime status" - local ALL_APPS=$(dokku_apps) - if [[ -n "$1" ]]; then - local APP="$1" - fi - local APPS=${APP:="$ALL_APPS"} - - dokku_col_log_info1_quiet "App Name" "Zero-Downtime Status" - for app in $APPS; do - verify_app_name "$app" - dokku_col_log_msg "$app" "$(is_app_checks_enabled "$app")" - done -} - -checks_enable() { - local desc="enable zero-downtime for app" - local APP="$1"; verify_app_name "$APP" - - if [[ "$(is_app_checks_enabled "$APP")" == "false" ]]; then - dokku_log_info1 "Enabling zero downtime for app ($APP)" - [[ "$2" == "--no-restart" ]] && local CONFIG_SET_ARGS=$2 - # shellcheck disable=SC2086 - config_set $CONFIG_SET_ARGS $APP DOKKU_CHECKS_ENABLED=1 - else - dokku_log_info1 "zero downtime is already enabled for app ($APP)" - fi -} - -checks_disable() { - local desc="disable zero-downtime for app" - local APP="$1"; verify_app_name "$APP" - - if [[ "$(is_app_checks_enabled "$APP")" == "true" ]]; then - dokku_log_info1 "Disabling zero downtime for app ($APP)" - [[ "$2" == "--no-restart" ]] && local CONFIG_SET_ARGS=$2 - # shellcheck disable=SC2086 - config_set $CONFIG_SET_ARGS $APP DOKKU_CHECKS_ENABLED=0 - else - dokku_log_info1 "zero downtime is already disable for app ($APP)" - fi -} case "$1" in - checks) - checks_main "$2" - ;; - - checks:enable) - [[ -z $2 ]] && dokku_log_fail "Please specify an app to run the command on" - checks_enable "$2" --no-restart - ;; - - checks:disable) - [[ -z $2 ]] && dokku_log_fail "Please specify an app to run the command on" - checks_disable "$2" --no-restart - ;; - help | ps:help) cat<, Show zero-downtime status diff --git a/plugins/checks/install b/plugins/checks/install index 7905c13ed..63965ffa6 100755 --- a/plugins/checks/install +++ b/plugins/checks/install @@ -4,6 +4,7 @@ source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions" source "$PLUGIN_AVAILABLE_PATH/config/functions" migrate_checks_vars() { + local desc="migrates deprecated CHECKS config variables to simplified counter part introduced in 0.5.x" local APPS="$(dokku_apps)" local GLOBAL_SKIP_ALL_CHECKS=$(dokku config:get --global DOKKU_SKIP_ALL_CHECKS || true) local GLOBAL_SKIP_DEFAULT_CHECKS=$(dokku config:get --global DOKKU_SKIP_DEFAULT_CHECKS || true) diff --git a/plugins/checks/subcommands/default b/plugins/checks/subcommands/default new file mode 100755 index 000000000..d8b0c70cd --- /dev/null +++ b/plugins/checks/subcommands/default @@ -0,0 +1,23 @@ +#!/usr/bin/env bash +set -eo pipefail; [[ $DOKKU_TRACE ]] && set -x +source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions" +source "$PLUGIN_AVAILABLE_PATH/checks/functions" + +checks_main_cmd() { + local desc="displays app zero-downtime status" + local cmd="checks" + local ALL_APPS=$(dokku_apps) + if [[ -n "$1" ]]; then + local APP="$1" + fi + local APPS=${APP:="$ALL_APPS"} + + dokku_col_log_info1_quiet "App Name" "Zero-Downtime Status" + local app + for app in $APPS; do + verify_app_name "$app" + dokku_col_log_msg "$app" "$(is_app_checks_enabled "$app")" + done +} + +checks_main_cmd "$2" diff --git a/plugins/checks/subcommands/disable b/plugins/checks/subcommands/disable new file mode 100755 index 000000000..314192481 --- /dev/null +++ b/plugins/checks/subcommands/disable @@ -0,0 +1,21 @@ +#!/usr/bin/env bash +set -eo pipefail; [[ $DOKKU_TRACE ]] && set -x +source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions" +source "$PLUGIN_AVAILABLE_PATH/checks/functions" + +checks_disable_cmd() { + local desc="disable zero-downtime for app" + local cmd="check:disable" + local APP="$1"; verify_app_name "$APP" + + if [[ "$(is_app_checks_enabled "$APP")" == "true" ]]; then + dokku_log_info1 "Disabling zero downtime for app ($APP)" + [[ "$2" == "--no-restart" ]] && local CONFIG_SET_ARGS=$2 + # shellcheck disable=SC2086 + config_set $CONFIG_SET_ARGS $APP DOKKU_CHECKS_ENABLED=0 + else + dokku_log_info1 "zero downtime is already disable for app ($APP)" + fi +} + +checks_disable_cmd "$2" --no-restart diff --git a/plugins/checks/subcommands/enable b/plugins/checks/subcommands/enable new file mode 100755 index 000000000..b28ef4bd7 --- /dev/null +++ b/plugins/checks/subcommands/enable @@ -0,0 +1,21 @@ +#!/usr/bin/env bash +set -eo pipefail; [[ $DOKKU_TRACE ]] && set -x +source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions" +source "$PLUGIN_AVAILABLE_PATH/checks/functions" + +checks_enable_cmd() { + local desc="enable zero-downtime for app" + local cmd="checks:enable" + local APP="$1"; verify_app_name "$APP" + + if [[ "$(is_app_checks_enabled "$APP")" == "false" ]]; then + dokku_log_info1 "Enabling zero downtime for app ($APP)" + [[ "$2" == "--no-restart" ]] && local CONFIG_SET_ARGS=$2 + # shellcheck disable=SC2086 + config_set $CONFIG_SET_ARGS $APP DOKKU_CHECKS_ENABLED=1 + else + dokku_log_info1 "zero downtime is already enabled for app ($APP)" + fi +} + +checks_enable_cmd "$2" --no-restart diff --git a/plugins/common/functions b/plugins/common/functions index 9d6f0f3eb..af99951a4 100755 --- a/plugins/common/functions +++ b/plugins/common/functions @@ -2,6 +2,7 @@ set -eo pipefail; [[ $DOKKU_TRACE ]] && set -x has_tty() { + local desc="return 0 if we have a tty" if [[ "$(/usr/bin/tty || true)" == "not a tty" ]]; then return 1 else @@ -10,19 +11,23 @@ has_tty() { } dokku_apps() { + local desc="prints list of all local apps" local INSTALLED_APPS=$(find "$DOKKU_ROOT" -follow -maxdepth 1 -mindepth 1 -type d ! -name 'tls' ! -name '.*' -printf "%f\n" | sort) || (dokku_log_fail "You haven't deployed any applications yet") [[ $INSTALLED_APPS ]] && echo "$INSTALLED_APPS" } dokku_log_info1() { + local desc="log info1 formatter" echo "-----> $*" } dokku_log_info2() { + local desc="log info2 formatter" echo "=====> $*" } dokku_log_info1_quiet() { + local desc="log info1 formatter (with quiet option)" if [[ -z "$DOKKU_QUIET_OUTPUT" ]]; then echo "-----> $*" else @@ -31,6 +36,7 @@ dokku_log_info1_quiet() { } dokku_log_info2_quiet() { + local desc="log info2 formatter (with quiet option)" if [[ -z "$DOKKU_QUIET_OUTPUT" ]]; then echo "=====> $*" else @@ -39,10 +45,12 @@ dokku_log_info2_quiet() { } dokku_col_log_info1() { + local desc="columnar log info1 formatter" printf "%-6s %-18s %-25s %-25s %-25s\n" "----->" "$@" } dokku_col_log_info1_quiet() { + local desc="columnar log info1 formatter (with quiet option)" if [[ -z "$DOKKU_QUIET_OUTPUT" ]]; then printf "%-6s %-18s %-25s %-25s %-25s\n" "----->" "$@" else @@ -51,10 +59,12 @@ dokku_col_log_info1_quiet() { } dokku_col_log_info2() { + local desc="columnar log info2 formatter" printf "%-6s %-18s %-25s %-25s %-25s\n" "=====>" "$@" } dokku_col_log_info2_quiet() { + local desc="columnar log info2 formatter (with quiet option)" if [[ -z "$DOKKU_QUIET_OUTPUT" ]]; then printf "%-6s %-18s %-25s %-25s %-25s\n" "=====>" "$@" else @@ -63,10 +73,12 @@ dokku_col_log_info2_quiet() { } dokku_col_log_msg() { + local desc="columnar log formatter" printf "%-25s %-25s %-25s %-25s\n" "$@" } dokku_col_log_msg_quiet() { + local desc="columnar log formatter (with quiet option)" if [[ -z "$DOKKU_QUIET_OUTPUT" ]]; then printf "%-25s %-25s %-25s %-25s\n" "$@" else @@ -75,6 +87,7 @@ dokku_col_log_msg_quiet() { } dokku_log_verbose_quiet() { + local desc="log verbose formatter (with quiet option)" if [[ -z "$DOKKU_QUIET_OUTPUT" ]]; then echo " $*" else @@ -83,23 +96,28 @@ dokku_log_verbose_quiet() { } dokku_log_verbose() { + local desc="log verbose formatter" echo " $*" } dokku_log_warn() { + local desc="log warning formatter" echo " ! $*" } dokku_log_fail() { + local desc="log fail formatter" echo "$@" 1>&2 exit 1 } dokku_log_event() { + local desc="log dokku events" logger -t dokku -i -- "$@" } dokku_log_plugn_trigger_call() { + local desc="log plugn trigger calls" local l_hook l_hook="$1" ; shift @@ -107,6 +125,7 @@ dokku_log_plugn_trigger_call() { } dokku_container_log_verbose_quiet() { + local desc="log verbose container output (with quiet option)" local CID=$1; shift @@ -119,6 +138,7 @@ dokku_container_log_verbose_quiet() { } verify_app_name() { + local desc="verify app name format and app existence" local APP="$1" [[ ! -n "$APP" ]] && dokku_log_fail "(verify_app_name) APP must not be null" if [[ ! "$APP" =~ ^[a-z].* && ! "$APP" =~ ^[0-9].* ]]; then @@ -131,6 +151,7 @@ verify_app_name() { } verify_image() { + local desc="verify image existence" local IMAGE="$1" if (docker inspect "$IMAGE" &>/dev/null); then return 0 @@ -140,14 +161,14 @@ verify_image() { } get_app_image_repo() { - # central definition of our image repo pattern + local desc="central definition of image repo pattern" local APP="$1"; local IMAGE_REPO="dokku/$APP" [[ -z "$APP" ]] && dokku_log_fail "(get_app_image_repo) APP must not be null" echo "$IMAGE_REPO" } get_app_image_name() { - # return image identifier for a given app, tag tuple. validate if tag is presented + local desc="return image identifier for a given app, tag tuple. validate if tag is presented" local APP="$1"; local IMAGE_TAG="$2"; local IMAGE_REPO=$(get_app_image_repo "$APP") [[ -z "$APP" ]] && dokku_log_fail "(get_app_image_name) APP must not be null" @@ -161,7 +182,7 @@ get_app_image_name() { } get_running_image_tag() { - # retrieve current image tag for a given app. returns empty string if no deployed containers are found + local desc="retrieve current image tag for a given app. returns empty string if no deployed containers are found" local APP="$1" [[ ! -n "$APP" ]] && dokku_log_fail "(get_running_image_tag) APP must not be null" verify_app_name "$APP" @@ -172,12 +193,14 @@ get_running_image_tag() { } is_image_herokuish_based() { + local desc="returns true if app image is based on herokuish" # circleci can't support --rm as they run lxc in lxc [[ ! -f "/home/ubuntu/.circlerc" ]] && local DOCKER_ARGS="--rm" docker run "$DOKKU_GLOBAL_RUN_ARGS" --entrypoint="/bin/sh" $DOCKER_ARGS "$@" -c "test -f /exec" } is_number() { + local desc="returns 0 if input is a number" local NUMBER=$1; local NUM_RE='^[0-9]+$' if [[ $NUMBER =~ $NUM_RE ]]; then return 0 @@ -187,6 +210,7 @@ is_number() { } is_abs_path() { + local desc="returns 0 if input path is absolute" local TEST_PATH=$1 if [[ "$TEST_PATH" = /* ]]; then return 0 @@ -196,6 +220,7 @@ is_abs_path() { } parse_args() { + local desc="top-level cli arg parser" local next_index=1; local skip=false; local args=("$@") for arg in "$@"; do $skip && skip=false && continue @@ -222,6 +247,7 @@ parse_args() { } copy_from_image() { + local desc="copy file from named image to destination" local IMAGE="$1"; local SRC_FILE="$2"; local DST_DIR="$3" verify_app_name "$APP" @@ -240,6 +266,7 @@ copy_from_image() { } get_app_container_ids() { + local desc="returns list of docker container ids for given app" local APP="$1"; local CONTAINER_TYPE="$2" verify_app_name "$APP" [[ -f $DOKKU_ROOT/$APP/CONTAINER ]] && DOKKU_CIDS+=$(< "$DOKKU_ROOT/$APP/CONTAINER") @@ -265,6 +292,7 @@ get_app_container_ids() { } get_app_running_container_ids() { + local desc="return list of running docker container ids for given apps" local APP=$1 verify_app_name "$APP" @@ -280,6 +308,7 @@ get_app_running_container_ids() { } get_cmd_from_procfile() { + local desc="parse cmd from app Procfile" local APP=$1; local PROC_TYPE=$2; local DOKKU_PROCFILE="$DOKKU_ROOT/$APP/DOKKU_PROCFILE" local name; local command; verify_app_name "$APP" @@ -297,6 +326,7 @@ get_cmd_from_procfile() { } is_deployed() { + local desc="return 0 if given app has a running container" local APP="$1" if [[ -f "$DOKKU_ROOT/$APP/CONTAINER" ]] || [[ $(ls "$DOKKU_ROOT/$APP"/CONTAINER.* &> /dev/null; echo $?) -eq 0 ]]; then return 0 @@ -306,6 +336,7 @@ is_deployed() { } is_container_running () { + local desc="return 0 if given docker container id is in running state" local CID=$1 local CONTAINER_STATUS=$(docker inspect -f '{{.State.Running}}' "$CID" || true) @@ -317,6 +348,7 @@ is_container_running () { } is_container_status () { + local desc="return 0 if given docker container id is in given state" local CID=$1 local TEMPLATE="{{.State.$2}}" local CONTAINER_STATUS=$(docker inspect -f "$TEMPLATE" "$CID" || true) @@ -329,6 +361,7 @@ is_container_status () { } is_app_running() { + local desc="return 0 if given app has a running container" local APP="$1" verify_app_name "$APP" @@ -342,20 +375,21 @@ is_app_running() { } release_and_deploy() { + local desc="main function for releasing and deploying an app" local APP="$1"; local IMAGE_TAG="$2"; local IMAGE=$(get_app_image_name "$APP" "$IMAGE_TAG") verify_app_name "$APP" if verify_image "$IMAGE"; then if is_image_herokuish_based "$IMAGE"; then - IMAGE_SOURCE_TYPE="herokuish" + local IMAGE_SOURCE_TYPE="herokuish" else - IMAGE_SOURCE_TYPE="dockerfile" + local IMAGE_SOURCE_TYPE="dockerfile" fi - DOKKU_APP_SKIP_DEPLOY="$(dokku config:get "$APP" DOKKU_SKIP_DEPLOY || true)" - DOKKU_GLOBAL_SKIP_DEPLOY="$(dokku config:get --global DOKKU_SKIP_DEPLOY || true)" + local DOKKU_APP_SKIP_DEPLOY="$(dokku config:get "$APP" DOKKU_SKIP_DEPLOY || true)" + local DOKKU_GLOBAL_SKIP_DEPLOY="$(dokku config:get --global DOKKU_SKIP_DEPLOY || true)" - DOKKU_SKIP_DEPLOY=${DOKKU_APP_SKIP_DEPLOY:="$DOKKU_GLOBAL_SKIP_DEPLOY"} + local DOKKU_SKIP_DEPLOY=${DOKKU_APP_SKIP_DEPLOY:="$DOKKU_GLOBAL_SKIP_DEPLOY"} dokku_log_info1 "Releasing $APP ($IMAGE)..." dokku release "$APP" "$IMAGE_SOURCE_TYPE" "$IMAGE_TAG" @@ -374,6 +408,7 @@ release_and_deploy() { } docker_cleanup() { + local desc="cleans up all exited/dead containers and removes all dangling images" # delete all non-running containers # shellcheck disable=SC2046 docker rm $(docker ps -a -f 'status=exited' -q) &> /dev/null || true @@ -388,6 +423,7 @@ docker_cleanup() { } get_available_port() { + local desc="returns first currently unused port > 1024" while true; do local port=$(shuf -i 1025-65535 -n 1) if ! nc -z 0.0.0.0 "$port"; then @@ -400,6 +436,7 @@ get_available_port() { } dokku_auth() { + local desc="calls user-auth plugin trigger" export SSH_USER=${SSH_USER:=$USER} export SSH_NAME=${NAME:="default"} if ! plugn trigger user-auth "$SSH_USER" "$SSH_NAME" "$@" ; then @@ -409,10 +446,12 @@ dokku_auth() { } _ipv4_regex() { + local desc="ipv4 regex" echo "([0-9]{1,3}[\.]){3}[0-9]{1,3}" } _ipv6_regex() { + local desc="ipv6 regex" local RE_IPV4="$(_ipv4_regex)" local RE_IPV6="([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|" # TEST: 1:2:3:4:5:6:7:8 RE_IPV6="${RE_IPV6}([0-9a-fA-F]{1,4}:){1,7}:|" # TEST: 1:: 1:2:3:4:5:6:7:: @@ -430,6 +469,7 @@ _ipv6_regex() { } get_ipv4_regex() { + local desc="returns ipv4 regex" local RE_IPV4="$(_ipv4_regex)" # Ensure the ip address continues to the end of the line # Fixes using a wildcard dns service such as xip.io which allows for *..xip.io @@ -437,6 +477,7 @@ get_ipv4_regex() { } get_ipv6_regex() { + local desc="returns ipv6 regex" local RE_IPV6="$(_ipv6_regex)" # Ensure the ip address continues to the end of the line # Fixes using a wildcard dns service such as xip.io which allows for *..xip.io @@ -444,9 +485,10 @@ get_ipv6_regex() { } get_global_vhost() { - local GLOBAL_VHOST_FILE="$DOKKU_ROOT/VHOST" - [[ -f "$GLOBAL_VHOST_FILE" ]] && local GLOBAL_VHOST=$(< "$GLOBAL_VHOST_FILE") - echo "$GLOBAL_VHOST" + local desc="return global vhost" + local GLOBAL_VHOST_FILE="$DOKKU_ROOT/VHOST" + [[ -f "$GLOBAL_VHOST_FILE" ]] && local GLOBAL_VHOST=$(< "$GLOBAL_VHOST_FILE") + echo "$GLOBAL_VHOST" } is_global_vhost_enabled() { @@ -464,8 +506,9 @@ is_global_vhost_enabled() { is_app_vhost_enabled() { local desc="returns true or false if vhost support is enabled for a given application" - local APP=$1; verify_app_name "$APP" + source "$PLUGIN_AVAILABLE_PATH/config/functions" + local APP=$1; verify_app_name "$APP" local NO_VHOST=$(config_get "$APP" NO_VHOST) local APP_VHOST_ENABLED=true @@ -478,6 +521,8 @@ is_app_vhost_enabled() { disable_app_vhost() { local desc="disable vhost support for given application" + source "$PLUGIN_AVAILABLE_PATH/config/functions" + local APP=$1; verify_app_name "$APP" local APP_VHOST_FILE="$DOKKU_ROOT/$APP/VHOST" local APP_URLS_FILE="$DOKKU_ROOT/$APP/URLS" @@ -506,6 +551,8 @@ disable_app_vhost() { enable_app_vhost() { local desc="enable vhost support for given application" + source "$PLUGIN_AVAILABLE_PATH/config/functions" + local APP=$1; verify_app_name "$APP" config_unset --no-restart "$APP" DOKKU_NGINX_PORT DOKKU_NGINX_SSL_PORT @@ -515,11 +562,15 @@ enable_app_vhost() { } get_dockerfile_exposed_ports() { + local desc="return all exposed ports from passed file path" local DOCKERFILE_PORTS=$(egrep "^EXPOSE " "$1" | awk '{ print $2 }' | xargs) || true echo "$DOCKERFILE_PORTS" } get_app_raw_tcp_ports() { + local desc="extracts raw tcp port numbers from DOCKERFILE_PORTS config variable" + source "$PLUGIN_AVAILABLE_PATH/config/functions" + local APP="$1"; verify_app_name "$APP" local DOCKERFILE_PORTS="$(config_get "$APP" DOKKU_DOCKERFILE_PORTS)" for p in $DOCKERFILE_PORTS; do @@ -528,11 +579,12 @@ get_app_raw_tcp_ports() { raw_tcp_ports+="$p " fi done - raw_tcp_ports="$(echo "$raw_tcp_ports"| xargs)" + local raw_tcp_ports="$(echo "$raw_tcp_ports"| xargs)" echo "$raw_tcp_ports" } get_container_ports() { + local desc="returns published ports from app containers" local APP="$1"; verify_app_name "$APP" local APP_CIDS="$(get_app_container_ids "$APP")" local cid @@ -545,6 +597,9 @@ get_container_ports() { } get_app_urls() { + local desc="print an app's available urls" + source "$PLUGIN_AVAILABLE_PATH/config/functions" + local APP="$2"; verify_app_name "$APP" local RAW_TCP_PORTS="$(get_app_raw_tcp_ports "$APP")" local URLS_FILE="$DOKKU_ROOT/$APP/URLS" @@ -609,7 +664,7 @@ get_app_urls() { } get_json_value() { - # return value of provided json key from a json stream on stdin + local desc="return value of provided json key from a json stream on stdin" # JSON_NODE should be expresses as either a top-level object that has no children # or in the format of json.node.path local JSON_NODE="$1" @@ -619,7 +674,7 @@ get_json_value() { } get_json_keys() { - # return space-separated list of json keys from json provided on stdin + local desc="return space-separated list of json keys from json provided on stdin" # JSON_NODE should be expressed as json.node.path and is expected to have children local JSON_NODE="$1" local JSON_NODE=${JSON_NODE//\./\"][\"} diff --git a/plugins/config/commands b/plugins/config/commands index 36b1c013b..ddd9c0699 100755 --- a/plugins/config/commands +++ b/plugins/config/commands @@ -1,26 +1,8 @@ #!/usr/bin/env bash -[[ " config config:get config:set config:unset help config:help " == *" $1 "* ]] || exit "$DOKKU_NOT_IMPLEMENTED_EXIT" +[[ " help config:help " == *" $1 "* ]] || exit "$DOKKU_NOT_IMPLEMENTED_EXIT" set -eo pipefail; [[ $DOKKU_TRACE ]] && set -x -source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions" -source "$PLUGIN_AVAILABLE_PATH/config/functions" case "$1" in - config) - config_all "$@" - ;; - - config:get) - config_get "$@" - ;; - - config:set) - config_set "$@" - ;; - - config:unset) - config_unset "$@" - ;; - help | config:help) cat<|--global), Display all global or app-specific config vars diff --git a/plugins/config/functions b/plugins/config/functions index b63dd2ac1..02f41b3f6 100644 --- a/plugins/config/functions +++ b/plugins/config/functions @@ -3,6 +3,7 @@ set -eo pipefail; [[ $DOKKU_TRACE ]] && set -x source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions" config_export() { + local desc="returns export command for config variable of specified type (app/global)" local CONFIG_TYPE="$1" local APP="$2" local ENV_FILE="$DOKKU_ROOT/$APP/ENV" @@ -17,6 +18,7 @@ config_export() { } config_parse_args() { + local desc="parse config plugin args" unset APP ENV_FILE DOKKU_CONFIG_TYPE DOKKU_CONFIG_RESTART case "$2" in --global) @@ -48,11 +50,13 @@ config_parse_args() { } config_create () { + local desc="create config env file" local ENV_FILE=$1 [[ -f $ENV_FILE ]] || touch "$ENV_FILE" } config_styled_hash () { + local desc="internal config hash" local vars="$1" local prefix="$2" local longest="" @@ -79,6 +83,7 @@ config_styled_hash () { } config_write() { + local desc="writes config vars out to appropriate file path" local ENV_TEMP="$1" local ENV_FILE_TEMP="${ENV_FILE}.tmp" @@ -91,6 +96,7 @@ config_write() { } is_config_export() { + local desc="return 0 if we're supposed to export" for var in "$@"; do if [[ "$var" == "--export" ]]; then return 0 @@ -100,6 +106,7 @@ is_config_export() { } config_all() { + local desc="print or export config vars" [[ "$1" == "config" ]] || set -- "config" "$@" config_parse_args "$@" @@ -123,6 +130,7 @@ config_all() { } config_get() { + local desc="get value of given config var" [[ "$1" == "config:get" ]] || set -- "config:get" "$@" config_parse_args "$@" @@ -143,6 +151,7 @@ config_get() { } config_set() { + local desc="set value of given config var" [[ "$1" == "config:set" ]] || set -- "config:set" "$@" config_parse_args "$@" [[ "$2" = "--no-restart" ]] && set -- "${@:1:1}" "${@:3}" @@ -200,6 +209,7 @@ ${var}" } config_unset() { + local desc="unset given config var" [[ "$1" == "config:unset" ]] || set -- "config:unset" "$@" config_parse_args "$@" [[ "$2" = "--no-restart" ]] && set -- "${@:1:1}" "${@:3}" diff --git a/plugins/config/subcommands/default b/plugins/config/subcommands/default new file mode 100755 index 000000000..47837d4c1 --- /dev/null +++ b/plugins/config/subcommands/default @@ -0,0 +1,11 @@ +#!/usr/bin/env bash +set -eo pipefail; [[ $DOKKU_TRACE ]] && set -x +source "$PLUGIN_AVAILABLE_PATH/config/functions" + +config_main_cmd() { + local desc="print config vars for app via command line" + local cmd="config" + config_all "$@" +} + +config_main_cmd "$@" diff --git a/plugins/config/subcommands/get b/plugins/config/subcommands/get new file mode 100755 index 000000000..ba514b8d2 --- /dev/null +++ b/plugins/config/subcommands/get @@ -0,0 +1,11 @@ +#!/usr/bin/env bash +set -eo pipefail; [[ $DOKKU_TRACE ]] && set -x +source "$PLUGIN_AVAILABLE_PATH/config/functions" + +config_get_cmd() { + local desc="get specified config vars from app via command line" + local cmd="config:get" + config_get "$@" +} + +config_get_cmd "$@" diff --git a/plugins/config/subcommands/set b/plugins/config/subcommands/set new file mode 100755 index 000000000..ef30dd4ed --- /dev/null +++ b/plugins/config/subcommands/set @@ -0,0 +1,11 @@ +#!/usr/bin/env bash +set -eo pipefail; [[ $DOKKU_TRACE ]] && set -x +source "$PLUGIN_AVAILABLE_PATH/config/functions" + +config_set_cmd() { + local desc="set specified config vars for app via command line" + local cmd="config:set" + config_set "$@" +} + +config_set_cmd "$@" diff --git a/plugins/config/subcommands/unset b/plugins/config/subcommands/unset new file mode 100755 index 000000000..4569c5793 --- /dev/null +++ b/plugins/config/subcommands/unset @@ -0,0 +1,11 @@ +#!/usr/bin/env bash +set -eo pipefail; [[ $DOKKU_TRACE ]] && set -x +source "$PLUGIN_AVAILABLE_PATH/config/functions" + +config_unset_cmd() { + local desc="unset specified config vars for app via command line" + local cmd="config:unset" + config_unset "$@" +} + +config_unset_cmd "$@" diff --git a/plugins/docker-options/commands b/plugins/docker-options/commands index 2dadcbd0a..5c934c8d5 100755 --- a/plugins/docker-options/commands +++ b/plugins/docker-options/commands @@ -1,43 +1,8 @@ #!/usr/bin/env bash -[[ " docker-options docker-options:add docker-options:remove help docker-options:help " == *" $1 "* ]] || exit "$DOKKU_NOT_IMPLEMENTED_EXIT" +[[ " help docker-options:help " == *" $1 "* ]] || exit "$DOKKU_NOT_IMPLEMENTED_EXIT" set -eo pipefail; [[ $DOKKU_TRACE ]] && set -x -source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions" -source "$PLUGIN_CORE_AVAILABLE_PATH/docker-options/functions" - -declare APP # global assigned in case case "$1" in - # Display applications docker options - docker-options) - verify_app_name "$2" && APP="$2" - read -ra passed_phases <<< "$(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) - verify_app_name "$2" && APP="$2" - read -ra passed_phases <<< "$(get_phases "$3")" - shift 3 # everything else passed is the docker option - passed_docker_option="$*" - [[ -z "$passed_docker_option" ]] && dokku_log_fail "Please specify docker options to add to the phase" - add_passed_docker_option passed_phases[@] "${passed_docker_option[@]}" - ;; - - # Remove a docker option from application - docker-options:remove) - verify_app_name "$2" && APP="$2" - read -ra passed_phases <<< "$(get_phases "$3")" - shift 3 # everything else passed is the docker option - [[ -z ${passed_docker_option="$@"} ]] && dokku_log_fail "Please specify docker options to add to the phase" - remove_passed_docker_option passed_phases[@] "${passed_docker_option[@]}" - ;; - - # Display usage help help | docker-options:help) cat<, Display app's Docker options for all phases diff --git a/plugins/docker-options/functions b/plugins/docker-options/functions index 07ae08b64..7450736cb 100644 --- a/plugins/docker-options/functions +++ b/plugins/docker-options/functions @@ -5,6 +5,7 @@ source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions" AVAILABLE_PHASES=(build deploy run) get_phase_file_path() { + local desc="return docker-options config file path for specified phase" local phase_file_prefix="DOCKER_OPTIONS_" local phase=$1 [[ "$DOKKU_ROOT" && "$APP" && "$phase_file_prefix" && "$phase" ]] || dokku_log_fail "Error: phase_file_path is incomplete." @@ -12,6 +13,7 @@ get_phase_file_path() { } get_phases() { + local desc="returns array of passed passes if all are in allowed array" local passed_phases_list="$1" local -r phases_allowed=$(sed -e 's/ /\|/g' <<< "${AVAILABLE_PHASES[@]}") local phase @@ -28,6 +30,7 @@ get_phases() { } create_phase_file_if_required() { + local desc="create phase file" local phase_file_path="$1" [[ -f "$phase_file_path" ]] || { touch "$phase_file_path" @@ -35,6 +38,7 @@ create_phase_file_if_required() { } display_phase_options() { + local desc="print docker-options for specified phase" local phase="$1" local phase_file_path="$2" echo "${phase^} options:" @@ -42,6 +46,7 @@ display_phase_options() { } display_all_phases_options() { + local desc="print docker-options for all phases" local phases=("${AVAILABLE_PHASES[@]}") for phase in "${phases[@]}"; do local phase_file_path @@ -53,6 +58,7 @@ display_all_phases_options() { } display_passed_phases_options() { + local desc="print docker options for list of specified phases" local passed_phases=("${!1}") local phase for phase in "${passed_phases[@]}"; do @@ -67,6 +73,7 @@ display_passed_phases_options() { } add_passed_docker_option() { + local desc="adds docker option to specified phases" local passed_phases=("${!1}") shift local passed_option_string="$*" @@ -82,6 +89,7 @@ add_passed_docker_option() { } remove_passed_docker_option() { + local desc="removes docker option from specified phases" local passed_phases=("${!1}") shift local passed_option_string="$*" diff --git a/plugins/docker-options/subcommands/add b/plugins/docker-options/subcommands/add new file mode 100755 index 000000000..7ac05d6ac --- /dev/null +++ b/plugins/docker-options/subcommands/add @@ -0,0 +1,18 @@ +#!/usr/bin/env bash +set -eo pipefail; [[ $DOKKU_TRACE ]] && set -x +source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions" +source "$PLUGIN_CORE_AVAILABLE_PATH/docker-options/functions" + +docker_options_add_cmd() { + local desc="Add a docker option to application" + local cmd="docker-options:add" + + verify_app_name "$2" && local APP="$2" + read -ra passed_phases <<< "$(get_phases "$3")" + shift 3 # everything else passed is the docker option + passed_docker_option="$*" + [[ -z "$passed_docker_option" ]] && dokku_log_fail "Please specify docker options to add to the phase" + add_passed_docker_option passed_phases[@] "${passed_docker_option[@]}" +} + +docker_options_add_cmd "$@" diff --git a/plugins/docker-options/subcommands/default b/plugins/docker-options/subcommands/default new file mode 100755 index 000000000..742dee2b4 --- /dev/null +++ b/plugins/docker-options/subcommands/default @@ -0,0 +1,19 @@ +#!/usr/bin/env bash +set -eo pipefail; [[ $DOKKU_TRACE ]] && set -x +source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions" +source "$PLUGIN_CORE_AVAILABLE_PATH/docker-options/functions" + +docker_options_main_cmd() { + local desc="Display applications docker options" + local cmd="docker-options" + + verify_app_name "$2" && local APP="$2" + read -ra passed_phases <<< "$(get_phases "$3")" + if [[ ! "${passed_phases[@]}" ]]; then + display_all_phases_options + else + display_passed_phases_options passed_phases[@] + fi +} + +docker_options_main_cmd "$@" diff --git a/plugins/docker-options/subcommands/remove b/plugins/docker-options/subcommands/remove new file mode 100755 index 000000000..52d98f018 --- /dev/null +++ b/plugins/docker-options/subcommands/remove @@ -0,0 +1,17 @@ +#!/usr/bin/env bash +set -eo pipefail; [[ $DOKKU_TRACE ]] && set -x +source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions" +source "$PLUGIN_CORE_AVAILABLE_PATH/docker-options/functions" + +docker_options_remove_cmd() { + local desc="Remove a docker option from application" + local cmd="docker-options:remove" + + verify_app_name "$2" && local APP="$2" + read -ra passed_phases <<< "$(get_phases "$3")" + shift 3 # everything else passed is the docker option + [[ -z ${passed_docker_option="$@"} ]] && dokku_log_fail "Please specify docker options to add to the phase" + remove_passed_docker_option passed_phases[@] "${passed_docker_option[@]}" +} + +docker_options_remove_cmd "$@" diff --git a/plugins/domains/commands b/plugins/domains/commands index b860ba70f..72e869845 100755 --- a/plugins/domains/commands +++ b/plugins/domains/commands @@ -1,65 +1,8 @@ #!/usr/bin/env bash -[[ " domains domains:setup domains:add domains:clear domains:remove domains:disable domains:enable domains:set-global help domains:help " == *" $1 "* ]] || exit "$DOKKU_NOT_IMPLEMENTED_EXIT" +[[ " help domains:help " == *" $1 "* ]] || exit "$DOKKU_NOT_IMPLEMENTED_EXIT" set -eo pipefail; [[ $DOKKU_TRACE ]] && set -x -source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions" -source "$PLUGIN_AVAILABLE_PATH/domains/functions" -source "$PLUGIN_AVAILABLE_PATH/nginx-vhosts/functions" case "$1" in - domains) - domains_main "$2" - ;; - - domains:setup) - [[ -z $2 ]] && dokku_log_fail "Please specify an app to run the command on" - domains_setup "$2" - ;; - - domains:add) - [[ -z $2 ]] && dokku_log_fail "Please specify an app to run the command on" - - if [[ -z "${*:3}" ]]; then - echo "Usage: dokku $1 $2 DOMAIN [DOMAIN ...]" - echo "Must specify DOMAIN." - exit 1 - fi - shift 1 - domains_add "$@" - ;; - - domains:clear) - [[ -z $2 ]] && dokku_log_fail "Please specify an app to run the command on" - domains_clear "$2" - ;; - - domains:remove) - [[ -z $2 ]] && dokku_log_fail "Please specify an app to run the command on" - - if [[ -z "${*:3}" ]]; then - echo "Usage: dokku $1 $2 DOMAIN [DOMAIN ...]" - echo "Must specify DOMAIN." - exit 1 - fi - - shift 1 - domains_remove "$@" - ;; - - domains:disable) - [[ -z $2 ]] && dokku_log_fail "Please specify an app to run the command on" - domains_disable "$2" - ;; - - domains:enable) - [[ -z $2 ]] && dokku_log_fail "Please specify an app to run the command on" - domains_enable "$2" - ;; - - domains:set-global) - [[ -z $2 ]] && dokku_log_fail "Please specify a global domain name" - domains_set_global "$2" - ;; - help | domains:help) cat<], List domains diff --git a/plugins/domains/functions b/plugins/domains/functions index 334eff569..79e032262 100755 --- a/plugins/domains/functions +++ b/plugins/domains/functions @@ -61,25 +61,6 @@ domains_setup() { fi } -domains_main() { - local desc="print app domains" - local APP="$1" - - if [[ "$(is_global_vhost_enabled)" == "true" ]]; then - dokku_log_info2_quiet "Global Domain Name" - get_global_vhost - fi - if [[ -n "$APP" ]]; then - verify_app_name "$APP" - if [[ -f "$DOKKU_ROOT/$APP/VHOST" ]]; then - dokku_log_info2_quiet "$APP Domain Names" - get_app_domains "$APP" - else - dokku_log_fail "No domain names set for $APP" - fi - fi -} - domains_add() { local desc="add list of domains to app" verify_app_name "$1" @@ -103,17 +84,6 @@ domains_add() { plugn trigger post-domains-update "$APP" "add" "$@" } -domains_clear() { - local desc="clear all app domains" - verify_app_name "$1" - local APP="$1"; local APP_VHOST_PATH="$DOKKU_ROOT/$APP/VHOST" - - rm -f "$APP_VHOST_PATH" - domains_setup "$APP" - plugn trigger post-domains-update "$APP" "clear" - dokku_log_info1 "Cleared domains in $APP" -} - domains_remove() { local desc="remove list of app domains" verify_app_name "$1" diff --git a/plugins/domains/install b/plugins/domains/install index ca32d9a94..6fd5a2a58 100755 --- a/plugins/domains/install +++ b/plugins/domains/install @@ -1,8 +1,9 @@ #!/usr/bin/env bash set -eo pipefail; [[ $DOKKU_TRACE ]] && set -x +source "$PLUGIN_AVAILABLE_PATH/domains/functions" shopt -s nullglob for app in $DOKKU_ROOT/*/CONTAINER; do APP=$(basename "$(dirname "$app")"); - dokku domains:setup "$APP" + domains_setup "$APP" done diff --git a/plugins/domains/subcommands/add b/plugins/domains/subcommands/add new file mode 100755 index 000000000..99de16a59 --- /dev/null +++ b/plugins/domains/subcommands/add @@ -0,0 +1,20 @@ +#!/usr/bin/env bash +set -eo pipefail; [[ $DOKKU_TRACE ]] && set -x +source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions" +source "$PLUGIN_AVAILABLE_PATH/domains/functions" + +domains_add_cmd() { + local desc="adds domain to app via command line" + local cmd="domains:add" + [[ -z $2 ]] && dokku_log_fail "Please specify an app to run the command on" + + if [[ -z "${*:3}" ]]; then + echo "Usage: dokku $1 $2 DOMAIN [DOMAIN ...]" + echo "Must specify DOMAIN." + exit 1 + fi + shift 1 + domains_add "$@" +} + +domains_add_cmd "$@" diff --git a/plugins/domains/subcommands/clear b/plugins/domains/subcommands/clear new file mode 100755 index 000000000..ff8db2c73 --- /dev/null +++ b/plugins/domains/subcommands/clear @@ -0,0 +1,19 @@ +#!/usr/bin/env bash +set -eo pipefail; [[ $DOKKU_TRACE ]] && set -x +source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions" +source "$PLUGIN_AVAILABLE_PATH/domains/functions" + +domains_clear_cmd() { + local desc="clear all app domains" + local cmd="domains:clear" + [[ -z $2 ]] && dokku_log_fail "Please specify an app to run the command on" + verify_app_name "$2" + local APP="$2"; local APP_VHOST_PATH="$DOKKU_ROOT/$APP/VHOST" + + rm -f "$APP_VHOST_PATH" + domains_setup "$APP" + plugn trigger post-domains-update "$APP" "clear" + dokku_log_info1 "Cleared domains in $APP" +} + +domains_clear_cmd "$@" diff --git a/plugins/domains/subcommands/default b/plugins/domains/subcommands/default new file mode 100755 index 000000000..ee6204b9b --- /dev/null +++ b/plugins/domains/subcommands/default @@ -0,0 +1,26 @@ +#!/usr/bin/env bash +set -eo pipefail; [[ $DOKKU_TRACE ]] && set -x +source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions" +source "$PLUGIN_AVAILABLE_PATH/domains/functions" + +domains_main_cmd() { + local desc="print app domains" + local cmd="domains" + local APP="$2" + + if [[ "$(is_global_vhost_enabled)" == "true" ]]; then + dokku_log_info2_quiet "Global Domain Name" + get_global_vhost + fi + if [[ -n "$APP" ]]; then + verify_app_name "$APP" + if [[ -f "$DOKKU_ROOT/$APP/VHOST" ]]; then + dokku_log_info2_quiet "$APP Domain Names" + get_app_domains "$APP" + else + dokku_log_fail "No domain names set for $APP" + fi + fi +} + +domains_main_cmd "$@" diff --git a/plugins/domains/subcommands/disable b/plugins/domains/subcommands/disable new file mode 100755 index 000000000..2fdd17441 --- /dev/null +++ b/plugins/domains/subcommands/disable @@ -0,0 +1,13 @@ +#!/usr/bin/env bash +set -eo pipefail; [[ $DOKKU_TRACE ]] && set -x +source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions" +source "$PLUGIN_AVAILABLE_PATH/domains/functions" + +domains_disable_cmd() { + local desc="disable domains/VHOST support via command line" + local cmd="domains:disable" + [[ -z $2 ]] && dokku_log_fail "Please specify an app to run the command on" + domains_disable "$2" +} + +domains_disable_cmd "$@" diff --git a/plugins/domains/subcommands/enable b/plugins/domains/subcommands/enable new file mode 100755 index 000000000..399f9f723 --- /dev/null +++ b/plugins/domains/subcommands/enable @@ -0,0 +1,13 @@ +#!/usr/bin/env bash +set -eo pipefail; [[ $DOKKU_TRACE ]] && set -x +source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions" +source "$PLUGIN_AVAILABLE_PATH/domains/functions" + +domains_enable_cmd() { + local desc="enable domains/VHOST support via command line" + local cmd="domains:enable" + [[ -z $2 ]] && dokku_log_fail "Please specify an app to run the command on" + domains_enable "$2" +} + +domains_enable_cmd "$@" diff --git a/plugins/domains/subcommands/remove b/plugins/domains/subcommands/remove new file mode 100755 index 000000000..745bf82ce --- /dev/null +++ b/plugins/domains/subcommands/remove @@ -0,0 +1,21 @@ +#!/usr/bin/env bash +set -eo pipefail; [[ $DOKKU_TRACE ]] && set -x +source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions" +source "$PLUGIN_AVAILABLE_PATH/domains/functions" + +domains_remove_cmd() { + local desc="removes domains from app via command line" + local cmd="domains:remove" + [[ -z $2 ]] && dokku_log_fail "Please specify an app to run the command on" + + if [[ -z "${*:3}" ]]; then + echo "Usage: dokku $1 $2 DOMAIN [DOMAIN ...]" + echo "Must specify DOMAIN." + exit 1 + fi + + shift 1 + domains_remove "$@" +} + +domains_remove_cmd "$@" diff --git a/plugins/domains/subcommands/set-global b/plugins/domains/subcommands/set-global new file mode 100755 index 000000000..6b0c7f6b8 --- /dev/null +++ b/plugins/domains/subcommands/set-global @@ -0,0 +1,13 @@ +#!/usr/bin/env bash +set -eo pipefail; [[ $DOKKU_TRACE ]] && set -x +source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions" +source "$PLUGIN_AVAILABLE_PATH/domains/functions" + +domains_set_global_cmd() { + local desc="set global domain name from command line" + local cmd="domains:set-global" + [[ -z $2 ]] && dokku_log_fail "Please specify a global domain name" + domains_set_global "$2" +} + +domains_set_global_cmd "$@" diff --git a/plugins/domains/subcommands/setup b/plugins/domains/subcommands/setup new file mode 100755 index 000000000..d2999f2f2 --- /dev/null +++ b/plugins/domains/subcommands/setup @@ -0,0 +1,13 @@ +#!/usr/bin/env bash +set -eo pipefail; [[ $DOKKU_TRACE ]] && set -x +source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions" +source "$PLUGIN_AVAILABLE_PATH/domains/functions" + +domains_setup_cmd() { + local desc="setup domains to default state via command line" + local cmd="domains:setup" + [[ -z $2 ]] && dokku_log_fail "Please specify an app to run the command on" + domains_setup "$2" +} + +domains_setup_cmd "$@" diff --git a/plugins/enter/commands b/plugins/enter/commands index df0997a38..94709c05e 100755 --- a/plugins/enter/commands +++ b/plugins/enter/commands @@ -1,38 +1,8 @@ #!/usr/bin/env bash -[[ " enter help enter:help " == *" $1 "* ]] || exit "$DOKKU_NOT_IMPLEMENTED_EXIT" +[[ " help enter:help " == *" $1 "* ]] || exit "$DOKKU_NOT_IMPLEMENTED_EXIT" set -eo pipefail; [[ $DOKKU_TRACE ]] && set -x -source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions" case "$1" in - enter) - APP="$2"; CONTAINER_TYPE="$3"; IMAGE_TAG=$(get_running_image_tag "$APP"); IMAGE=$(get_app_image_name "$APP" "$IMAGE_TAG") - verify_app_name "$APP" - - [[ ! -n "$3" ]] && dokku_log_fail "No container id specified" - - if [[ "$3" == "--container-id" ]]; then - [[ ! -n "$4" ]] && dokku_log_fail "No container id specified" - - DOKKU_APP_CIDS=( $(get_app_container_ids "$APP") ) - printf -- '%s\n' "${DOKKU_APP_CIDS[@]}" | grep -q -e "^$4" || dokku_log_fail "Invalid container id for app" - ID=$(printf -- '%s\n' "${DOKKU_APP_CIDS[@]}" | grep -e "^$4") - shift 4 - else - DOKKU_APP_CIDS=( $(get_app_container_ids "$APP" "$CONTAINER_TYPE") ) - ID=${DOKKU_APP_CIDS[0]} - [[ ! -n $ID ]] && dokku_log_fail "No containers found for type '$CONTAINER_TYPE'" - shift 3 - fi - - docker ps -aq --no-trunc | grep -e "^$ID" > /dev/null || dokku_log_fail "Container does not exist" - docker ps -q --no-trunc | grep -e "^$ID" > /dev/null || dokku_log_fail "Container is not running" - - EXEC_CMD="" - has_tty && DOKKU_RUN_OPTS+=" -i -t" - is_image_herokuish_based "$IMAGE" && EXEC_CMD="/exec" - docker exec "$DOKKU_RUN_OPTS" $ID $EXEC_CMD "${@:-/bin/bash}" - ;; - help | enter:help) cat< [ || --container-id ], Connect to a specific app container diff --git a/plugins/enter/subcommands/default b/plugins/enter/subcommands/default new file mode 100755 index 000000000..79600ef8e --- /dev/null +++ b/plugins/enter/subcommands/default @@ -0,0 +1,37 @@ +#!/usr/bin/env bash +set -eo pipefail; [[ $DOKKU_TRACE ]] && set -x +source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions" + +enter_default_cmd() { + local desc="enters running app container of specified proc type" + local cmd="enter" + local APP="$2"; local CONTAINER_TYPE="$3"; local IMAGE_TAG=$(get_running_image_tag "$APP"); local IMAGE=$(get_app_image_name "$APP" "$IMAGE_TAG") + verify_app_name "$APP" + + [[ ! -n "$3" ]] && dokku_log_fail "No container id specified" + + if [[ "$3" == "--container-id" ]]; then + [[ ! -n "$4" ]] && dokku_log_fail "No container id specified" + + local DOKKU_APP_CIDS=( $(get_app_container_ids "$APP") ) + printf -- '%s\n' "${DOKKU_APP_CIDS[@]}" | grep -q -e "^$4" || dokku_log_fail "Invalid container id for app" + local ID=$(printf -- '%s\n' "${DOKKU_APP_CIDS[@]}" | grep -e "^$4") + shift 4 + else + local DOKKU_APP_CIDS=( $(get_app_container_ids "$APP" "$CONTAINER_TYPE") ) + local ID=${DOKKU_APP_CIDS[0]} + [[ ! -n $ID ]] && dokku_log_fail "No containers found for type '$CONTAINER_TYPE'" + shift 3 + fi + + docker ps -aq --no-trunc | grep -e "^$ID" > /dev/null || dokku_log_fail "Container does not exist" + docker ps -q --no-trunc | grep -e "^$ID" > /dev/null || dokku_log_fail "Container is not running" + + local EXEC_CMD="" + has_tty && local DOKKU_RUN_OPTS+=" -i -t" + is_image_herokuish_based "$IMAGE" && local EXEC_CMD="/exec" + # shellcheck disable=SC2086 + docker exec $DOKKU_RUN_OPTS $ID $EXEC_CMD "${@:-/bin/bash}" +} + +enter_default_cmd "$@" diff --git a/plugins/git/commands b/plugins/git/commands index 8cc9fec8b..ee4a5a4da 100755 --- a/plugins/git/commands +++ b/plugins/git/commands @@ -4,18 +4,19 @@ source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions" source "$PLUGIN_AVAILABLE_PATH/apps/functions" git_build_app_repo() { + local desc="builds local git app repo for app" verify_app_name "$1" - APP="$1"; REV="$2" + local APP="$1"; local REV="$2" # clean up after ourselves - TMP_WORK_DIR=$(mktemp -d -t "dokku_git.XXXX") + local TMP_WORK_DIR=$(mktemp -d -t "dokku_git.XXXX") trap 'rm -rf "$TMP_WORK_DIR" > /dev/null' RETURN INT TERM EXIT # git clone - this method creates a new git repository and adds the primary # repo as a remote, then does a fetch depth=1 to avoid cloning # the entire repo - TMP_TAG="dokku/$REV" + local TMP_TAG="dokku/$REV" chmod 755 "$TMP_WORK_DIR" unset GIT_DIR GIT_WORK_TREE pushd "$TMP_WORK_DIR" > /dev/null diff --git a/plugins/logs/commands b/plugins/logs/commands index d3e1534dc..49c0cbd1b 100755 --- a/plugins/logs/commands +++ b/plugins/logs/commands @@ -1,67 +1,19 @@ #!/usr/bin/env bash -[[ " logs help logs:help " == *" $1 "* ]] || exit "$DOKKU_NOT_IMPLEMENTED_EXIT" +[[ " help logs:help " == *" $1 "* ]] || exit "$DOKKU_NOT_IMPLEMENTED_EXIT" set -eo pipefail; [[ $DOKKU_TRACE ]] && set -x -source "$(dirname "$0")/functions" -source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions" -source "$PLUGIN_AVAILABLE_PATH/config/functions" + +usage() { + local desc="logs specific usage" + echo "Usage: dokku logs " + echo " display recent log output" + echo "" + echo " -n, --num NUM # the number of lines to display" + echo " -p, --ps PS # only display logs from the given process" + echo " -t, --tail # continually stream logs" + echo " -q, --quiet # display raw logs without colors, time and names" +} case "$1" in - logs) - [[ -z $2 ]] && dokku_log_fail "Please specify an app to run the command on" - APP="$2"; verify_app_name "$2" - APP_ROOT="$DOKKU_ROOT/$APP" - COLORS=(36 33 32 35 31) - - if ! (is_deployed "$APP"); then - echo "Application's container not found" - exit 1 - fi - - shift 2; - TEMP=$(getopt -o htqn:p: --long help,tail,quiet,num:,ps: -n 'dokku logs' -- "$@") - if [[ $? != 0 ]]; then usage >&2 ; exit 1 ; fi - eval set -- "$TEMP" - - DOKKU_LOGS_LINE_NUMBERS="100" - while true; do - case "$1" in - -t|--tail) DOKKU_LOGS_ARGS+="--follow "; shift ;; - -n|--num) DOKKU_LOGS_LINE_NUMBERS="$2"; shift 2 ;; - -p|--ps) DOKKU_LOGS_ONLY_PROCESS="$2"; shift 2 ;; - -q|--quiet) DOKKU_LOGS_NO_PRETTY_PRINT="true"; shift ;; - --) shift; break ;; - *) echo "Internal error"; exit 1;; - esac - done - - if [[ -n $DOKKU_LOGS_ONLY_PROCESS ]]; then - CONTAINERS=("$APP_ROOT/CONTAINER.$DOKKU_LOGS_ONLY_PROCESS".*) - else - CONTAINERS=("$APP_ROOT"/CONTAINER.*) - fi - [[ -z $(stat -t "${CONTAINERS[0]}" 2>/dev/null) ]] && exit 0 - - DOKKU_LOGS_ARGS+="--tail $DOKKU_LOGS_LINE_NUMBERS" - ((MAX_INDEX=${#CONTAINERS[*]} - 1)) || true - for i in ${!CONTAINERS[*]}; do - DYNO=$(echo "${CONTAINERS[i]}" | sed -r 's/.*CONTAINER\.(.*)/\1/') - CID=$(< "${CONTAINERS[i]}") - COLOR=${COLORS[i % ${#COLORS[*]}]} - if [[ $DOKKU_LOGS_NO_PRETTY_PRINT == "true" ]]; then - DOKKU_LOGS_CMD+="(docker logs $DOKKU_LOGS_ARGS $CID 2>&1)" - else - DOKKU_LOGS_PRETTY_PRINT_CMD="sed -r 's/^([^Z]+Z )/\x1b[${COLOR}m\1app[$DYNO]:\x1b[0m /gm'" - DOKKU_LOGS_CMD+="(docker logs -t $DOKKU_LOGS_ARGS $CID 2>&1 | $DOKKU_LOGS_PRETTY_PRINT_CMD)" - fi - if [[ $i != "$MAX_INDEX" ]]; then - DOKKU_LOGS_CMD+="& " - else - DOKKU_LOGS_CMD+="; " - fi - done - bash -c "($DOKKU_LOGS_CMD)" - ;; - logs:help) usage ;; diff --git a/plugins/logs/functions b/plugins/logs/functions deleted file mode 100755 index 71ad638f8..000000000 --- a/plugins/logs/functions +++ /dev/null @@ -1,12 +0,0 @@ -#!/usr/bin/env bash -set -eo pipefail; [[ $DOKKU_TRACE ]] && set -x - -usage() { - echo "Usage: dokku logs " - echo " display recent log output" - echo "" - echo " -n, --num NUM # the number of lines to display" - echo " -p, --ps PS # only display logs from the given process" - echo " -t, --tail # continually stream logs" - echo " -q, --quiet # display raw logs without colors, time and names" -} diff --git a/plugins/logs/subcommands/default b/plugins/logs/subcommands/default new file mode 100755 index 000000000..769d26bd5 --- /dev/null +++ b/plugins/logs/subcommands/default @@ -0,0 +1,65 @@ +#!/usr/bin/env bash +set -eo pipefail; [[ $DOKKU_TRACE ]] && set -x +source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions" +source "$PLUGIN_AVAILABLE_PATH/config/functions" +source "$PLUGIN_AVAILABLE_PATH/logs/functions" + +logs_default_cmd() { + local desc="shows the last logs for an app via command line" + local cmd="logs" + [[ -z $2 ]] && dokku_log_fail "Please specify an app to run the command on" + local APP="$2"; verify_app_name "$2" + local APP_ROOT="$DOKKU_ROOT/$APP" + local COLORS=(36 33 32 35 31) + + if ! (is_deployed "$APP"); then + echo "Application's container not found" + exit 1 + fi + + shift 2; + local TEMP=$(getopt -o htqn:p: --long help,tail,quiet,num:,ps: -n 'dokku logs' -- "$@") + if [[ $? != 0 ]]; then usage >&2 ; exit 1 ; fi + eval set -- "$TEMP" + + local DOKKU_LOGS_LINE_NUMBERS="100" + while true; do + case "$1" in + -t|--tail) local DOKKU_LOGS_ARGS+="--follow "; shift ;; + -n|--num) local DOKKU_LOGS_LINE_NUMBERS="$2"; shift 2 ;; + -p|--ps) local DOKKU_LOGS_ONLY_PROCESS="$2"; shift 2 ;; + -q|--quiet) local DOKKU_LOGS_NO_PRETTY_PRINT="true"; shift ;; + --) shift; break ;; + *) echo "Internal error"; exit 1;; + esac + done + + if [[ -n $DOKKU_LOGS_ONLY_PROCESS ]]; then + local CONTAINERS=("$APP_ROOT/CONTAINER.$DOKKU_LOGS_ONLY_PROCESS".*) + else + local CONTAINERS=("$APP_ROOT"/CONTAINER.*) + fi + [[ -z $(stat -t "${CONTAINERS[0]}" 2>/dev/null) ]] && exit 0 + + local DOKKU_LOGS_ARGS+="--tail $DOKKU_LOGS_LINE_NUMBERS" + ((MAX_INDEX=${#CONTAINERS[*]} - 1)) || true + for i in ${!CONTAINERS[*]}; do + local DYNO=$(echo "${CONTAINERS[i]}" | sed -r 's/.*CONTAINER\.(.*)/\1/') + local CID=$(< "${CONTAINERS[i]}") + local COLOR=${COLORS[i % ${#COLORS[*]}]} + if [[ $DOKKU_LOGS_NO_PRETTY_PRINT == "true" ]]; then + local DOKKU_LOGS_CMD+="(docker logs $DOKKU_LOGS_ARGS $CID 2>&1)" + else + local DOKKU_LOGS_PRETTY_PRINT_CMD="sed -r 's/^([^Z]+Z )/\x1b[${COLOR}m\1app[$DYNO]:\x1b[0m /gm'" + local DOKKU_LOGS_CMD+="(docker logs -t $DOKKU_LOGS_ARGS $CID 2>&1 | $DOKKU_LOGS_PRETTY_PRINT_CMD)" + fi + if [[ $i != "$MAX_INDEX" ]]; then + local DOKKU_LOGS_CMD+="& " + else + local DOKKU_LOGS_CMD+="; " + fi + done + bash -c "($DOKKU_LOGS_CMD)" +} + +logs_default_cmd "$@" diff --git a/plugins/nginx-vhosts/commands b/plugins/nginx-vhosts/commands index 190a25a10..ef0100b77 100755 --- a/plugins/nginx-vhosts/commands +++ b/plugins/nginx-vhosts/commands @@ -1,21 +1,8 @@ #!/usr/bin/env bash -[[ " nginx:build-config nginx:access-logs nginx:error-logs help nginx:help " == *" $1 "* ]] || exit "$DOKKU_NOT_IMPLEMENTED_EXIT" +[[ " help nginx:help " == *" $1 "* ]] || exit "$DOKKU_NOT_IMPLEMENTED_EXIT" set -eo pipefail; [[ $DOKKU_TRACE ]] && set -x -source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions" -source "$PLUGIN_AVAILABLE_PATH/config/functions" -source "$PLUGIN_AVAILABLE_PATH/nginx-vhosts/functions" case "$1" in - nginx:build-config) - [[ -z $2 ]] && echo "Please specify an app to run the command on" && exit 1 - nginx_build_config "$2" - ;; - - nginx:access-logs|nginx:error-logs) - [[ -z $2 ]] && echo "Please specify an app to run the command on" && exit 1 - nginx_logs "$@" - ;; - help | nginx:help) cat<, (Re)builds nginx config for given app diff --git a/plugins/nginx-vhosts/functions b/plugins/nginx-vhosts/functions index ada62cfcf..fa47560dc 100755 --- a/plugins/nginx-vhosts/functions +++ b/plugins/nginx-vhosts/functions @@ -110,6 +110,7 @@ validate_ssl_domains() { } get_custom_nginx_template() { + local desc="attempts to copy custom nginx template from app image" local APP="$1"; verify_app_name "$APP" local DESTINATION="$2" local IMAGE_TAG="$(get_running_image_tag "$APP")" diff --git a/plugins/nginx-vhosts/subcommands/access-logs b/plugins/nginx-vhosts/subcommands/access-logs new file mode 100755 index 000000000..8ad94cf53 --- /dev/null +++ b/plugins/nginx-vhosts/subcommands/access-logs @@ -0,0 +1,14 @@ +#!/usr/bin/env bash +set -eo pipefail; [[ $DOKKU_TRACE ]] && set -x +source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions" +source "$PLUGIN_AVAILABLE_PATH/config/functions" +source "$PLUGIN_AVAILABLE_PATH/nginx-vhosts/functions" + +nginx_logs_cmd() { + local desc="display app nginx logs from command line" + local cmd="$1" + [[ -z $2 ]] && echo "Please specify an app to run the command on" && exit 1 + nginx_logs "$@" +} + +nginx_logs_cmd "$@" diff --git a/plugins/nginx-vhosts/subcommands/build-config b/plugins/nginx-vhosts/subcommands/build-config new file mode 100755 index 000000000..185c4e2f6 --- /dev/null +++ b/plugins/nginx-vhosts/subcommands/build-config @@ -0,0 +1,14 @@ +#!/usr/bin/env bash +set -eo pipefail; [[ $DOKKU_TRACE ]] && set -x +source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions" +source "$PLUGIN_AVAILABLE_PATH/config/functions" +source "$PLUGIN_AVAILABLE_PATH/nginx-vhosts/functions" + +nginx_build_config_cmd() { + local desc="build nginx config to proxy app containers from command line" + local cmd="nginx:build-config" + [[ -z $2 ]] && echo "Please specify an app to run the command on" && exit 1 + nginx_build_config "$2" +} + +nginx_build_config_cmd "$@" diff --git a/plugins/nginx-vhosts/subcommands/error-logs b/plugins/nginx-vhosts/subcommands/error-logs new file mode 120000 index 000000000..8069b30c1 --- /dev/null +++ b/plugins/nginx-vhosts/subcommands/error-logs @@ -0,0 +1 @@ +access-logs \ No newline at end of file diff --git a/plugins/plugin/commands b/plugins/plugin/commands index 6916719e7..d331361df 100755 --- a/plugins/plugin/commands +++ b/plugins/plugin/commands @@ -1,66 +1,8 @@ #!/usr/bin/env bash -[[ " plugin plugin:install plugin:install-dependencies plugin:update plugin:disable plugin:enable plugin:uninstall help plugin:help " == *" $1 "* ]] || exit "$DOKKU_NOT_IMPLEMENTED_EXIT" +[[ " help plugin:help " == *" $1 "* ]] || exit "$DOKKU_NOT_IMPLEMENTED_EXIT" set -eo pipefail; [[ $DOKKU_TRACE ]] && set -x -source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions" -source "$PLUGIN_AVAILABLE_PATH/plugin/functions" case "$1" in - plugin) - plugn version - plugn list - ;; - - plugin:install) - case "$2" in - --core) - [[ "$#" -gt 2 ]] && dokku_log_info1_quiet "Cannot install additional core plugins, running core plugin install trigger" - PLUGIN_PATH="$PLUGIN_CORE_PATH" plugn trigger install - ;; - https:*|git*|ssh:*) - shift - download_and_enable_plugin "$@" - plugn trigger install - ;; - *) - plugn trigger install - ;; - esac - ;; - - plugin:install-dependencies) - if [[ $2 == "--core" ]]; then - export PLUGIN_PATH="$PLUGIN_CORE_PATH" - fi - plugn trigger dependencies - ;; - - plugin:update) - if [[ -n "$2" ]]; then - PLUGIN="$2" - PLUGIN_COMMITTISH="$3" - plugn update "$PLUGIN" "$PLUGIN_COMMITTISH" - fi - plugn trigger update - ;; - - plugin:disable) - [[ -z $2 ]] && dokku_log_fail "Please specify a plugin to disable" - PLUGIN="$2" - disable_plugin "$PLUGIN" - ;; - - plugin:enable) - [[ -z $2 ]] && dokku_log_fail "Please specify a plugin to enable" - PLUGIN="$2" - enable_plugin "$PLUGIN" - ;; - - plugin:uninstall) - [[ -z $2 ]] && dokku_log_fail "Please specify a plugin to enable" - PLUGIN="$2" - uninstall_plugin "$PLUGIN" - ;; - help | plugin:help) cat<, Show proxy for app diff --git a/plugins/proxy/functions b/plugins/proxy/functions index ad6935a46..931fb607c 100755 --- a/plugins/proxy/functions +++ b/plugins/proxy/functions @@ -22,55 +22,3 @@ get_app_proxy_type() { echo $APP_PROXY_TYPE } - -proxy_main() { - local desc="displays app proxy implementation" - local ALL_APPS=$(dokku_apps) - if [[ -n "$1" ]]; then - local APP="$1" - fi - local APPS=${APP:="$ALL_APPS"} - - dokku_col_log_info1_quiet "App Name" "Proxy Type" - for app in $APPS; do - verify_app_name "$app" - dokku_col_log_msg "$app" "$(get_app_proxy_type "$app")" - done -} - -proxy_set() { - local desc="enable proxy for app" - local APP="$1"; verify_app_name "$APP" - - dokku_log_info1 "proxy:set not implemented" -} - -proxy_enable() { - local desc="enable proxy for app" - local APP="$1"; verify_app_name "$APP" - - if [[ "$(is_app_proxy_enabled "$APP")" == "false" ]]; then - dokku_log_info1 "Enabling proxy for app ($APP)" - [[ "$2" == "--no-restart" ]] && local CONFIG_SET_ARGS=$2 - # shellcheck disable=SC2086 - config_unset $CONFIG_SET_ARGS $APP DOKKU_DISABLE_PROXY - plugn trigger proxy-enable "$APP" - else - dokku_log_info1 "proxy is already enabled for app ($APP)" - fi -} - -proxy_disable() { - local desc="disable proxy for app" - local APP="$1"; verify_app_name "$APP" - - if [[ "$(is_app_proxy_enabled "$APP")" == "true" ]]; then - dokku_log_info1 "Disabling proxy for app ($APP)" - [[ "$2" == "--no-restart" ]] && local CONFIG_SET_ARGS=$2 - # shellcheck disable=SC2086 - config_set $CONFIG_SET_ARGS $APP DOKKU_DISABLE_PROXY=1 - plugn trigger proxy-disable "$APP" - else - dokku_log_info1 "proxy is already disable for app ($APP)" - fi -} diff --git a/plugins/proxy/subcommands/default b/plugins/proxy/subcommands/default new file mode 100755 index 000000000..d7e8b30f7 --- /dev/null +++ b/plugins/proxy/subcommands/default @@ -0,0 +1,22 @@ +#!/usr/bin/env bash +set -eo pipefail; [[ $DOKKU_TRACE ]] && set -x +source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions" +source "$PLUGIN_AVAILABLE_PATH/proxy/functions" + +proxy_main_cmd() { + local desc="displays app proxy implementation via command line" + local cmd="proxy" + local ALL_APPS=$(dokku_apps) + if [[ -n "$2" ]]; then + local APP="$2" + fi + local APPS=${APP:="$ALL_APPS"} + + dokku_col_log_info1_quiet "App Name" "Proxy Type" + for app in $APPS; do + verify_app_name "$app" + dokku_col_log_msg "$app" "$(get_app_proxy_type "$app")" + done +} + +proxy_main_cmd "$@" diff --git a/plugins/proxy/subcommands/disable b/plugins/proxy/subcommands/disable new file mode 100755 index 000000000..e54b3c46d --- /dev/null +++ b/plugins/proxy/subcommands/disable @@ -0,0 +1,24 @@ +#!/usr/bin/env bash +set -eo pipefail; [[ $DOKKU_TRACE ]] && set -x +source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions" +source "$PLUGIN_AVAILABLE_PATH/config/functions" +source "$PLUGIN_AVAILABLE_PATH/proxy/functions" + +proxy_disable_cmd() { + local desc="disable proxy for app via command line" + local cmd="proxy:disable" + [[ -z $1 ]] && dokku_log_fail "Please specify an app to run the command on" + local APP="$1"; verify_app_name "$APP" + + if [[ "$(is_app_proxy_enabled "$APP")" == "true" ]]; then + dokku_log_info1 "Disabling proxy for app ($APP)" + [[ "$2" == "--no-restart" ]] && local CONFIG_SET_ARGS=$2 + # shellcheck disable=SC2086 + config_set $CONFIG_SET_ARGS $APP DOKKU_DISABLE_PROXY=1 + plugn trigger proxy-disable "$APP" + else + dokku_log_info1 "proxy is already disable for app ($APP)" + fi +} + +proxy_disable_cmd "$2" --no-restart diff --git a/plugins/proxy/subcommands/enable b/plugins/proxy/subcommands/enable new file mode 100755 index 000000000..96b1a2e38 --- /dev/null +++ b/plugins/proxy/subcommands/enable @@ -0,0 +1,24 @@ +#!/usr/bin/env bash +set -eo pipefail; [[ $DOKKU_TRACE ]] && set -x +source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions" +source "$PLUGIN_AVAILABLE_PATH/config/functions" +source "$PLUGIN_AVAILABLE_PATH/proxy/functions" + +proxy_enable_cmd() { + local desc="enable proxy for app via command line" + local cmd="proxy:enable" + [[ -z $1 ]] && dokku_log_fail "Please specify an app to run the command on" + local APP="$1"; verify_app_name "$APP" + + if [[ "$(is_app_proxy_enabled "$APP")" == "false" ]]; then + dokku_log_info1 "Enabling proxy for app ($APP)" + [[ "$2" == "--no-restart" ]] && local CONFIG_SET_ARGS=$2 + # shellcheck disable=SC2086 + config_unset $CONFIG_SET_ARGS $APP DOKKU_DISABLE_PROXY + plugn trigger proxy-enable "$APP" + else + dokku_log_info1 "proxy is already enabled for app ($APP)" + fi +} + +proxy_enable_cmd "$2" --no-restart diff --git a/plugins/proxy/subcommands/set b/plugins/proxy/subcommands/set new file mode 100755 index 000000000..c999a1b1e --- /dev/null +++ b/plugins/proxy/subcommands/set @@ -0,0 +1,14 @@ +#!/usr/bin/env bash +set -eo pipefail; [[ $DOKKU_TRACE ]] && set -x +source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions" + +proxy_set_cmd() { + local desc="enable proxy for app via command line" + local cmd="proxy:set" + [[ -z $2 ]] && dokku_log_fail "Please specify an app to run the command on" + + local APP="$2"; verify_app_name "$APP" + dokku_log_info1 "proxy:set not implemented" +} + +proxy_set_cmd "$@" diff --git a/plugins/ps/commands b/plugins/ps/commands index 71472b8a1..a445b22fd 100755 --- a/plugins/ps/commands +++ b/plugins/ps/commands @@ -1,63 +1,8 @@ #!/usr/bin/env bash -[[ " ps ps:start ps:stop ps:rebuild ps:rebuildall ps:restart ps:restartall ps:restore ps:scale help ps:help " == *" $1 "* ]] || exit "$DOKKU_NOT_IMPLEMENTED_EXIT" +[[ " help ps:help " == *" $1 "* ]] || exit "$DOKKU_NOT_IMPLEMENTED_EXIT" set -eo pipefail; [[ $DOKKU_TRACE ]] && set -x -source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions" -source "$PLUGIN_AVAILABLE_PATH/ps/functions" case "$1" in - ps) - [[ -z $2 ]] && dokku_log_fail "Please specify an app to run the command on" - ps_main "$2" - ;; - - ps:start) - [[ -z $2 ]] && dokku_log_fail "Please specify an app to run the command on" - ps_start "$2" - ;; - - ps:stop) - [[ -z $2 ]] && dokku_log_fail "Please specify an app to run the command on" - ps_stop "$2" - ;; - - ps:rebuild) - [[ -z $2 ]] && dokku_log_fail "Please specify an app to run the command on" - ps_rebuild "$2" - ;; - - ps:rebuildall) - for app in $(dokku_apps); do - is_deployed "$app" && ps_rebuild "$app" - done - ;; - - ps:restart) - [[ -z $2 ]] && dokku_log_fail "Please specify an app to run the command on" - ps_restart "$2" - ;; - - ps:restartall) - for app in $(dokku_apps); do - ps_restart "$app" - done - ;; - - ps:restore) - for app in $(dokku_apps); do - DOKKU_APP_RESTORE=$(dokku config:get "$app" DOKKU_APP_RESTORE || true) - if [[ $DOKKU_APP_RESTORE != 0 ]]; then - echo "Restoring app $app ..." - ps_start "$app" - fi - done - ;; - - ps:scale) - [[ -z $2 ]] && dokku_log_fail "Please specify an app to run the command on" - shift 1 - ps_scale "$@" - ;; - help | ps:help) cat<, List processes running in app container(s) diff --git a/plugins/ps/functions b/plugins/ps/functions index 7bf9d6bee..a015bbf4e 100755 --- a/plugins/ps/functions +++ b/plugins/ps/functions @@ -3,6 +3,7 @@ set -eo pipefail; [[ $DOKKU_TRACE ]] && set -x source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions" print_dokku_scale_file() { + local desc="prints contents of DOKKU_SCALE file" local APP="$1"; local DOKKU_SCALE_FILE="$DOKKU_ROOT/$APP/DOKKU_SCALE" while read -r line || [[ -n "$line" ]]; do dokku_log_info2_quiet "$line" @@ -10,6 +11,7 @@ print_dokku_scale_file() { } extract_procfile() { + local desc="extracts procfile from app image" local APP="$1" local IMAGE_TAG="$(get_running_image_tag "$APP")" local IMAGE="$(get_app_image_name "$APP" "$IMAGE_TAG")" @@ -25,6 +27,7 @@ extract_procfile() { } remove_procfile() { + local desc="removes DOKKU_PROCFILE" local APP="$1"; local DOKKU_PROCFILE="$DOKKU_ROOT/$APP/DOKKU_PROCFILE" if [[ -f "$DOKKU_PROCFILE" ]]; then rm -f "$DOKKU_PROCFILE" @@ -32,6 +35,7 @@ remove_procfile() { } generate_scale_file() { + local desc="generates DOKKU_SCALE file" local APP="$1"; local IMAGE_TAG="$2"; local IMAGE=$(get_app_image_name "$APP" "$IMAGE_TAG"); local DOKKU_SCALE_FILE="$DOKKU_ROOT/$APP/DOKKU_SCALE" local DOKKU_PROCFILE="$DOKKU_ROOT/$APP/DOKKU_PROCFILE" verify_app_name "$APP" @@ -64,6 +68,7 @@ generate_scale_file() { } set_scale() { + local desc="sets app proc type scaling" local APP="$1"; local DOKKU_SCALE_FILE="$DOKKU_ROOT/$APP/DOKKU_SCALE" shift 1 local SCALE_SETTINGS=("$@") @@ -80,21 +85,8 @@ set_scale() { done } -ps_main() { - local APP="$1"; verify_app_name "$APP" - local DOKKU_APP_RUNNING_CONTAINER_IDS=$(get_app_running_container_ids "$APP") - - ! (is_deployed "$APP") && echo "App $APP has not been deployed" && exit 0 - - for CID in $DOKKU_APP_RUNNING_CONTAINER_IDS; do - has_tty && DOKKU_RUN_OPTS="-i -t" - dokku_log_info1_quiet "running processes in container: $CID" - # shellcheck disable=SC2086 - docker exec $DOKKU_RUN_OPTS $CID /bin/sh -c "ps auxwww" - done -} - ps_start() { + local desc="starts app" local APP="$1"; verify_app_name "$APP" local IMAGE_TAG=$(get_running_image_tag "$APP"); @@ -108,6 +100,7 @@ ps_start() { } ps_stop() { + local desc="stops app" local APP="$1"; verify_app_name "$APP" local DOKKU_APP_RUNNING_CONTAINER_IDS=$(get_app_running_container_ids "$APP") @@ -124,12 +117,14 @@ ps_stop() { } ps_rebuild() { + local desc="rebuilds app from base image" local APP="$1"; verify_app_name "$APP" plugn trigger receive-app "$APP" } ps_restart() { + local desc="restarts app" local APP="$1"; verify_app_name "$APP" local IMAGE_TAG=$(get_running_image_tag "$APP") @@ -139,6 +134,7 @@ ps_restart() { } ps_scale() { + local desc="sets app scaling config according arguments; otherwise according to DOKKU_SCALE file" local APP="$1"; verify_app_name "$APP" local IMAGE_TAG=$(get_running_image_tag "$APP") local DOKKU_SCALE_FILE="$DOKKU_ROOT/$APP/DOKKU_SCALE" diff --git a/plugins/ps/subcommands/default b/plugins/ps/subcommands/default new file mode 100755 index 000000000..5852be554 --- /dev/null +++ b/plugins/ps/subcommands/default @@ -0,0 +1,23 @@ +#!/usr/bin/env bash +set -eo pipefail; [[ $DOKKU_TRACE ]] && set -x +source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions" + +ps_main_cmd() { + local desc="shows running processes in all running app containers" + local cmd="ps" + [[ -z $2 ]] && dokku_log_fail "Please specify an app to run the command on" + + local APP="$2"; verify_app_name "$APP" + local DOKKU_APP_RUNNING_CONTAINER_IDS=$(get_app_running_container_ids "$APP") + + ! (is_deployed "$APP") && echo "App $APP has not been deployed" && exit 0 + + for CID in $DOKKU_APP_RUNNING_CONTAINER_IDS; do + has_tty && DOKKU_RUN_OPTS="-i -t" + dokku_log_info1_quiet "running processes in container: $CID" + # shellcheck disable=SC2086 + docker exec $DOKKU_RUN_OPTS $CID /bin/sh -c "ps auxwww" + done +} + +ps_main_cmd "$@" diff --git a/plugins/ps/subcommands/rebuild b/plugins/ps/subcommands/rebuild new file mode 100755 index 000000000..06ecb8190 --- /dev/null +++ b/plugins/ps/subcommands/rebuild @@ -0,0 +1,13 @@ +#!/usr/bin/env bash +set -eo pipefail; [[ $DOKKU_TRACE ]] && set -x +source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions" +source "$PLUGIN_AVAILABLE_PATH/ps/functions" + +ps_rebuild_cmd() { + local desc="rebuilds app via command line" + local cmd="ps:rebuild" + [[ -z $2 ]] && dokku_log_fail "Please specify an app to run the command on" + ps_rebuild "$2" +} + +ps_rebuild_cmd "$@" diff --git a/plugins/ps/subcommands/rebuildall b/plugins/ps/subcommands/rebuildall new file mode 100755 index 000000000..ba00b1d92 --- /dev/null +++ b/plugins/ps/subcommands/rebuildall @@ -0,0 +1,14 @@ +#!/usr/bin/env bash +set -eo pipefail; [[ $DOKKU_TRACE ]] && set -x +source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions" +source "$PLUGIN_AVAILABLE_PATH/ps/functions" + +ps_rebuildall_cmd() { + local desc="rebuilds all deployed apps via command line" + local cmd="ps:rebuildall" + for app in $(dokku_apps); do + is_deployed "$app" && ps_rebuild "$app" + done +} + +ps_rebuildall_cmd "$@" diff --git a/plugins/ps/subcommands/restart b/plugins/ps/subcommands/restart new file mode 100755 index 000000000..0498f76cc --- /dev/null +++ b/plugins/ps/subcommands/restart @@ -0,0 +1,13 @@ +#!/usr/bin/env bash +set -eo pipefail; [[ $DOKKU_TRACE ]] && set -x +source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions" +source "$PLUGIN_AVAILABLE_PATH/ps/functions" + +ps_restart_cmd() { + local desc="restarts app via command line" + local cmd="ps:restart" + [[ -z $2 ]] && dokku_log_fail "Please specify an app to run the command on" + ps_restart "$2" +} + +ps_restart_cmd "$@" diff --git a/plugins/ps/subcommands/restartall b/plugins/ps/subcommands/restartall new file mode 100755 index 000000000..afe4e4f07 --- /dev/null +++ b/plugins/ps/subcommands/restartall @@ -0,0 +1,14 @@ +#!/usr/bin/env bash +set -eo pipefail; [[ $DOKKU_TRACE ]] && set -x +source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions" +source "$PLUGIN_AVAILABLE_PATH/ps/functions" + +ps_restartall_cmd() { + local desc="restarts all apps via command line" + local cmd="ps:restartall" + for app in $(dokku_apps); do + ps_restart "$app" + done +} + +ps_restartall_cmd "$@" diff --git a/plugins/ps/subcommands/restore b/plugins/ps/subcommands/restore new file mode 100755 index 000000000..f3bfb2353 --- /dev/null +++ b/plugins/ps/subcommands/restore @@ -0,0 +1,18 @@ +#!/usr/bin/env bash +set -eo pipefail; [[ $DOKKU_TRACE ]] && set -x +source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions" +source "$PLUGIN_AVAILABLE_PATH/ps/functions" + +ps_restore_cmd() { + local desc="starts all apps with DOKKU_APP_RESTORE not set to 0 via command line" + local cmd="ps:restore" + for app in $(dokku_apps); do + local DOKKU_APP_RESTORE=$(dokku config:get "$app" DOKKU_APP_RESTORE || true) + if [[ $DOKKU_APP_RESTORE != 0 ]]; then + echo "Restoring app $app ..." + ps_start "$app" + fi + done +} + +ps_restore_cmd "$@" diff --git a/plugins/ps/subcommands/scale b/plugins/ps/subcommands/scale new file mode 100755 index 000000000..c285c5364 --- /dev/null +++ b/plugins/ps/subcommands/scale @@ -0,0 +1,14 @@ +#!/usr/bin/env bash +set -eo pipefail; [[ $DOKKU_TRACE ]] && set -x +source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions" +source "$PLUGIN_AVAILABLE_PATH/ps/functions" + +ps_scale_cmd() { + local desc="sets app scaling config via command line" + local cmd="ps:scale" + [[ -z $2 ]] && dokku_log_fail "Please specify an app to run the command on" + shift 1 + ps_scale "$@" +} + +ps_scale_cmd "$@" diff --git a/plugins/ps/subcommands/start b/plugins/ps/subcommands/start new file mode 100755 index 000000000..67c18235b --- /dev/null +++ b/plugins/ps/subcommands/start @@ -0,0 +1,13 @@ +#!/usr/bin/env bash +set -eo pipefail; [[ $DOKKU_TRACE ]] && set -x +source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions" +source "$PLUGIN_AVAILABLE_PATH/ps/functions" + +ps_start_cmd() { + local desc="starts app via command line" + local cmd="ps:start" + [[ -z $2 ]] && dokku_log_fail "Please specify an app to run the command on" + ps_start "$2" +} + +ps_start_cmd "$@" diff --git a/plugins/ps/subcommands/stop b/plugins/ps/subcommands/stop new file mode 100755 index 000000000..9088415eb --- /dev/null +++ b/plugins/ps/subcommands/stop @@ -0,0 +1,13 @@ +#!/usr/bin/env bash +set -eo pipefail; [[ $DOKKU_TRACE ]] && set -x +source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions" +source "$PLUGIN_AVAILABLE_PATH/ps/functions" + +ps_stop_cmd() { + local desc="stops app via command line" + local cmd="ps:stop" + [[ -z $2 ]] && dokku_log_fail "Please specify an app to run the command on" + ps_stop "$2" +} + +ps_stop_cmd "$@" diff --git a/plugins/shell/commands b/plugins/shell/commands index 182c33b95..361a41d56 100755 --- a/plugins/shell/commands +++ b/plugins/shell/commands @@ -1,53 +1,8 @@ #!/usr/bin/env bash -[[ " shell help shell:help " == *" $1 "* ]] || exit "$DOKKU_NOT_IMPLEMENTED_EXIT" +[[ " help shell:help " == *" $1 "* ]] || exit "$DOKKU_NOT_IMPLEMENTED_EXIT" set -eo pipefail; [[ $DOKKU_TRACE ]] && set -x case "$1" in - shell) - INPUTRC="$PLUGIN_ROOT/inputrc" - HISTFILE=~/.dokku_history - - history -r || true - - trim() - { - sed -e 's/^[[:space:]]*//g' -e 's/[[:space:]]*$//g' - } - - trap 'history -w' EXIT - - while true; do - trap '' SIGINT - read -rep "dokku> " line || { - echo; true; break - } - trap - SIGINT - - line=$(echo "$line" | trim) - CMD=$(echo "$line" | awk '{ print $1 }') - - [[ -z $CMD ]] && continue - - [[ "$line" != "$(fc -ln -1 | trim)" ]] && history -s "$line" - - case $CMD in - # shell builtins - clear) - clear - ;; - - quit|exit) - break - ;; - - # Not a built-in, run as regular dokku command - *) - dokku "$line" || true - esac - - done - ;; - help | shell:help) cat< " line || { + echo; true; break + } + trap - SIGINT + + local line=$(echo "$line" | trim) + local CMD=$(echo "$line" | awk '{ print $1 }') + + [[ -z $CMD ]] && continue + + [[ "$line" != "$(fc -ln -1 | trim)" ]] && history -s "$line" + + case $CMD in + # shell builtins + clear) + clear + ;; + + quit|exit) + break + ;; + + # Not a built-in, run as regular dokku command + *) + # shellcheck disable=SC2086 + dokku $line || true + esac + + done +} + +shell_cmd diff --git a/plugins/tags/commands b/plugins/tags/commands index 5d76164a8..8dc78b2be 100755 --- a/plugins/tags/commands +++ b/plugins/tags/commands @@ -1,54 +1,8 @@ #!/usr/bin/env bash -[[ " tags tags:create tags:deploy tags:destroy help tags:help " == *" $1 "* ]] || exit "$DOKKU_NOT_IMPLEMENTED_EXIT" +[[ " help tags:help " == *" $1 "* ]] || exit "$DOKKU_NOT_IMPLEMENTED_EXIT" set -eo pipefail; [[ $DOKKU_TRACE ]] && set -x -source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions" -source "$PLUGIN_AVAILABLE_PATH/tags/functions" case "$1" in - tags) - [[ -z $2 ]] && dokku_log_fail "Please specify an app to run the command on" - APP="$2"; IMAGE_REPO=$(get_app_image_repo "$APP") - verify_app_name "$APP" - - dokku_log_info2_quiet "Image tags for $IMAGE_REPO" - docker images "$IMAGE_REPO" - ;; - - tags:create) - [[ -z $2 ]] && dokku_log_fail "Please specify an app to run the command on" - APP="$2"; IMAGE_TAG="$3"; IMAGE_REPO=$(get_app_image_repo "$APP") - verify_app_name "$APP" - - tag_image "$IMAGE_REPO:latest" "$IMAGE_REPO:$IMAGE_TAG" - dokku_log_info2_quiet "Added $IMAGE_TAG tag to $IMAGE_REPO" - plugn trigger tags-create "$APP" "$IMAGE_TAG" - ;; - - tags:deploy) - [[ -z $2 ]] && dokku_log_fail "Please specify an app to run the command on" - APP="$2"; IMAGE_TAG="$3" - verify_app_name "$APP" - - release_and_deploy "$APP" "$IMAGE_TAG" - ;; - - tags:destroy) - [[ -z $2 ]] && dokku_log_fail "Please specify an app to run the command on" - APP="$2"; IMAGE_TAG="$3"; IMAGE_REPO=$(get_app_image_repo "$APP") - verify_app_name "$2" - - case "$IMAGE_TAG" in - latest) - dokku_log_fail "You can't remove internal dokku tag ($IMAGE_TAG) for $IMAGE_REPO" - ;; - - *) - docker rmi "$IMAGE_REPO:$IMAGE_TAG" - ;; - esac - plugn trigger tags-destroy "$APP" "$IMAGE_TAG" - ;; - help | tags:help) cat<, List all app image tags diff --git a/plugins/tags/functions b/plugins/tags/functions index df1721dfd..3cda584bf 100755 --- a/plugins/tags/functions +++ b/plugins/tags/functions @@ -3,5 +3,6 @@ set -eo pipefail; [[ $DOKKU_TRACE ]] && set -x source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions" tag_image() { + local desc="convenience method for docker tag interface" docker tag -f "$1" "$2" } diff --git a/plugins/tags/subcommands/create b/plugins/tags/subcommands/create new file mode 100755 index 000000000..f8104fd7f --- /dev/null +++ b/plugins/tags/subcommands/create @@ -0,0 +1,18 @@ +#!/usr/bin/env bash +set -eo pipefail; [[ $DOKKU_TRACE ]] && set -x +source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions" +source "$PLUGIN_AVAILABLE_PATH/tags/functions" + +tags_create_cmd() { + local desc="creates an images tag for app via command line" + local cmd="tags:create" + [[ -z $2 ]] && dokku_log_fail "Please specify an app to run the command on" + local APP="$2"; local IMAGE_TAG="$3"; local IMAGE_REPO=$(get_app_image_repo "$APP") + verify_app_name "$APP" + + tag_image "$IMAGE_REPO:latest" "$IMAGE_REPO:$IMAGE_TAG" + dokku_log_info2_quiet "Added $IMAGE_TAG tag to $IMAGE_REPO" + plugn trigger tags-create "$APP" "$IMAGE_TAG" +} + +tags_create_cmd "$@" diff --git a/plugins/tags/subcommands/default b/plugins/tags/subcommands/default new file mode 100755 index 000000000..a7b4bb200 --- /dev/null +++ b/plugins/tags/subcommands/default @@ -0,0 +1,17 @@ +#!/usr/bin/env bash +set -eo pipefail; [[ $DOKKU_TRACE ]] && set -x +source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions" +source "$PLUGIN_AVAILABLE_PATH/tags/functions" + +tags_main_cmd() { + local desc="shows docker images tags for app via command line" + local cmd="tags" + [[ -z $2 ]] && dokku_log_fail "Please specify an app to run the command on" + local APP="$2"; local IMAGE_REPO=$(get_app_image_repo "$APP") + verify_app_name "$APP" + + dokku_log_info2_quiet "Image tags for $IMAGE_REPO" + docker images "$IMAGE_REPO" +} + +tags_main_cmd "$@" diff --git a/plugins/tags/subcommands/deploy b/plugins/tags/subcommands/deploy new file mode 100755 index 000000000..67906dc41 --- /dev/null +++ b/plugins/tags/subcommands/deploy @@ -0,0 +1,16 @@ +#!/usr/bin/env bash +set -eo pipefail; [[ $DOKKU_TRACE ]] && set -x +source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions" +source "$PLUGIN_AVAILABLE_PATH/tags/functions" + +tags_deploy_cmd() { + local desc="deploys an app with a given tagged image via command line" + local cmd="tags:deploy" + [[ -z $2 ]] && dokku_log_fail "Please specify an app to run the command on" + local APP="$2"; local IMAGE_TAG="$3" + verify_app_name "$APP" + + release_and_deploy "$APP" "$IMAGE_TAG" +} + +tags_deploy_cmd "$@" diff --git a/plugins/tags/subcommands/destroy b/plugins/tags/subcommands/destroy new file mode 100755 index 000000000..46fbfb4e8 --- /dev/null +++ b/plugins/tags/subcommands/destroy @@ -0,0 +1,25 @@ +#!/usr/bin/env bash +set -eo pipefail; [[ $DOKKU_TRACE ]] && set -x +source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions" +source "$PLUGIN_AVAILABLE_PATH/tags/functions" + +tags_destroy_cmd() { + local desc="destroys an app image tag via command line" + local cmd="tags:destroy" + [[ -z $2 ]] && dokku_log_fail "Please specify an app to run the command on" + APP="$2"; IMAGE_TAG="$3"; IMAGE_REPO=$(get_app_image_repo "$APP") + verify_app_name "$2" + + case "$IMAGE_TAG" in + latest) + dokku_log_fail "You can't remove internal dokku tag ($IMAGE_TAG) for $IMAGE_REPO" + ;; + + *) + docker rmi "$IMAGE_REPO:$IMAGE_TAG" + ;; + esac + plugn trigger tags-destroy "$APP" "$IMAGE_TAG" +} + +tags_destroy_cmd "$@" diff --git a/plugins/tar/commands b/plugins/tar/commands index 4d6eaa488..c83149ba5 100755 --- a/plugins/tar/commands +++ b/plugins/tar/commands @@ -1,65 +1,8 @@ #!/usr/bin/env bash -[[ " tar-from tar:from tar-in tar:in tar-build tar-build-locked help tar:help " == *" $1 "* ]] || exit "$DOKKU_NOT_IMPLEMENTED_EXIT" +[[ " help tar:help " == *" $1 "* ]] || exit "$DOKKU_NOT_IMPLEMENTED_EXIT" set -eo pipefail; [[ $DOKKU_TRACE ]] && set -x -source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions" case "$1" in - tar-from|tar:from) - verify_app_name "$2" - APP=$2 - URL=$3 - shift 3 - curl -# --insecure -L "$URL" | dokku tar-in "$APP" "$@" - ;; - - tar-in|tar:in) - APP="$2" - verify_app_name "$2" - tee "$DOKKU_ROOT/$APP/src.tar" | wc -c - plugn trigger receive-app "$APP" - ;; - - tar-build) - verify_app_name "$2" - APP="$2"; APP_BUILD_LOCK="$DOKKU_ROOT/$APP/.build.lock" - APP_BUILD_LOCK_MSG="$APP is currently being deployed or locked. Waiting..." - [[ $(flock -n "$APP_BUILD_LOCK" true &>/dev/null ; echo $?) -ne 0 ]] && echo "$APP_BUILD_LOCK_MSG" - - shift 1 - flock -o "$APP_BUILD_LOCK" dokku tar-build-locked "$@" - ;; - - tar-build-locked) - APP="$2" - verify_app_name "$2" - shift 2 - - # clean up after ourselves - TMP_WORK_DIR=$(mktemp -d -t "dokku_tar.XXXX") - trap 'rm -rf "$TMP_WORK_DIR" > /dev/null' INT TERM EXIT - - # extract tar file - chmod 755 "$TMP_WORK_DIR" - pushd "$TMP_WORK_DIR" > /dev/null - - # Detect a common prefix that all files in the tar have, and strip off each directory found in it - COMMON_PREFIX=$(tar -tf "$DOKKU_ROOT/$APP/src.tar" | sed -e 'N;s/^\(.*\).*\n\1.*$/\1\n\1/;D') - BOGUS_PARTS=$(echo "$COMMON_PREFIX " | awk 'BEGIN{FS="/"} {print NF-1}') - - dokku_log_info1_quiet "Striping $BOGUS_PARTS worth of directories from tarball" - - tar -x -C "$TMP_WORK_DIR" -f "$DOKKU_ROOT/$APP/src.tar" --strip-components="$BOGUS_PARTS" - chmod -R u+r "$TMP_WORK_DIR" - - if [[ -f Dockerfile ]] && [[ "$([[ -f .env ]] && grep -q BUILDPACK_URL .env; echo $?)" != "0" ]] && [[ ! -f ".buildpacks" ]]; then - plugn trigger pre-receive-app "$APP" "dockerfile" "$TMP_WORK_DIR" - dokku receive "$APP" "dockerfile" "$TMP_WORK_DIR" | sed -u "s/^/"$'\e[1G'"/" - else - plugn trigger pre-receive-app "$APP" "herokuish" "$TMP_WORK_DIR" - dokku receive "$APP" "herokuish" "$TMP_WORK_DIR" | sed -u "s/^/"$'\e[1G'"/" - fi - ;; - help | tar:help) cat<, Reads an tarball containing the app from stdin diff --git a/plugins/tar/receive-app b/plugins/tar/receive-app index 99ab62017..94e33c5fa 100755 --- a/plugins/tar/receive-app +++ b/plugins/tar/receive-app @@ -2,11 +2,16 @@ set -eo pipefail; [[ $DOKKU_TRACE ]] && set -x source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions" -APP="$1"; REV="$2" +tar_receive_app() { + local desc="receives app tarball and calls tar:build" + local APP="$1"; local REV="$2" -# Don't trigger tar build if there is no tarball. -if [[ ! -f "$DOKKU_ROOT/$APP/src.tar" ]]; then - true -else - dokku tar-build "$APP" -fi + # Don't trigger tar build if there is no tarball. + if [[ ! -f "$DOKKU_ROOT/$APP/src.tar" ]]; then + true + else + dokku tar:build "$APP" + fi +} + +tar_receive_app "$@" diff --git a/plugins/tar/subcommands/build b/plugins/tar/subcommands/build new file mode 100755 index 000000000..c5f479aa6 --- /dev/null +++ b/plugins/tar/subcommands/build @@ -0,0 +1,18 @@ +#!/usr/bin/env bash +set -eo pipefail; [[ $DOKKU_TRACE ]] && set -x +source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions" + +tar_build_cmd() { + local desc="calls tar:build-locked via command line" + local cmd="tar:build" + + verify_app_name "$2" + local APP="$2"; local APP_BUILD_LOCK="$DOKKU_ROOT/$APP/.build.lock" + local APP_BUILD_LOCK_MSG="$APP is currently being deployed or locked. Waiting..." + [[ $(flock -n "$APP_BUILD_LOCK" true &>/dev/null ; echo $?) -ne 0 ]] && echo "$APP_BUILD_LOCK_MSG" + + shift 1 + flock -o "$APP_BUILD_LOCK" dokku tar:build-locked "$@" +} + +tar_build_cmd "$@" diff --git a/plugins/tar/subcommands/build-locked b/plugins/tar/subcommands/build-locked new file mode 100755 index 000000000..4a13a994f --- /dev/null +++ b/plugins/tar/subcommands/build-locked @@ -0,0 +1,39 @@ +#!/usr/bin/env bash +set -eo pipefail; [[ $DOKKU_TRACE ]] && set -x +source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions" + +tar_build_locked_cmd() { + local desc="builds apps from tarball via command line" + local cmd="tar:build-locked" + local APP="$2" + + verify_app_name "$2" + shift 2 + + # clean up after ourselves + local TMP_WORK_DIR=$(mktemp -d -t "dokku_tar.XXXX") + trap 'rm -rf "$TMP_WORK_DIR" > /dev/null' INT TERM EXIT + + # extract tar file + chmod 755 "$TMP_WORK_DIR" + pushd "$TMP_WORK_DIR" > /dev/null + + # Detect a common prefix that all files in the tar have, and strip off each directory found in it + local COMMON_PREFIX=$(tar -tf "$DOKKU_ROOT/$APP/src.tar" | sed -e 'N;s/^\(.*\).*\n\1.*$/\1\n\1/;D') + local BOGUS_PARTS=$(echo "$COMMON_PREFIX " | awk 'BEGIN{FS="/"} {print NF-1}') + + dokku_log_info1_quiet "Striping $BOGUS_PARTS worth of directories from tarball" + + tar -x -C "$TMP_WORK_DIR" -f "$DOKKU_ROOT/$APP/src.tar" --strip-components="$BOGUS_PARTS" + chmod -R u+r "$TMP_WORK_DIR" + + if [[ -f Dockerfile ]] && [[ "$([[ -f .env ]] && grep -q BUILDPACK_URL .env; echo $?)" != "0" ]] && [[ ! -f ".buildpacks" ]]; then + plugn trigger pre-receive-app "$APP" "dockerfile" "$TMP_WORK_DIR" + dokku receive "$APP" "dockerfile" "$TMP_WORK_DIR" | sed -u "s/^/"$'\e[1G'"/" + else + plugn trigger pre-receive-app "$APP" "herokuish" "$TMP_WORK_DIR" + dokku receive "$APP" "herokuish" "$TMP_WORK_DIR" | sed -u "s/^/"$'\e[1G'"/" + fi +} + +tar_build_locked_cmd "$@" diff --git a/plugins/tar/subcommands/from b/plugins/tar/subcommands/from new file mode 100755 index 000000000..61477098a --- /dev/null +++ b/plugins/tar/subcommands/from @@ -0,0 +1,15 @@ +#!/usr/bin/env bash +set -eo pipefail; [[ $DOKKU_TRACE ]] && set -x +source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions" + +tar_from_cmd() { + local desc="deploys app from tarball at URL via command line" + local cmd="tar:from" + verify_app_name "$2" + local APP=$2 + local URL=$3 + shift 3 + curl -# --insecure -L "$URL" | dokku tar:in "$APP" "$@" +} + +tar_from_cmd "$@" diff --git a/plugins/tar/subcommands/in b/plugins/tar/subcommands/in new file mode 100755 index 000000000..f080e1076 --- /dev/null +++ b/plugins/tar/subcommands/in @@ -0,0 +1,15 @@ +#!/usr/bin/env bash +set -eo pipefail; [[ $DOKKU_TRACE ]] && set -x +source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions" + +tar_in_cmd() { + local desc="deploys app from tarball on STDIN via command line" + local cmd="tar:in" + local APP="$2" + + verify_app_name "$2" + tee "$DOKKU_ROOT/$APP/src.tar" | wc -c + plugn trigger receive-app "$APP" +} + +tar_in_cmd "$@" diff --git a/tests/unit/10_apps.bats b/tests/unit/10_apps.bats index 118bf9561..cf8287237 100644 --- a/tests/unit/10_apps.bats +++ b/tests/unit/10_apps.bats @@ -2,20 +2,15 @@ load test_helper -@test "(apps) apps" { - create_app - run bash -c "dokku apps | grep $TEST_APP" - echo "output: "$output - echo "status: "$status - assert_output $TEST_APP - destroy_app -} - @test "(apps) apps:create" { run dokku apps:create $TEST_APP echo "output: "$output echo "status: "$status assert_success + run bash -c "dokku apps | grep $TEST_APP" + echo "output: "$output + echo "status: "$status + assert_output $TEST_APP destroy_app run dokku apps:create 1994testapp @@ -28,6 +23,17 @@ load test_helper echo "output: "$output echo "status: "$status assert_failure + + run bash -c "dokku --app $TEST_APP apps:create" + echo "output: "$output + echo "status: "$status + assert_success + run bash -c "dokku apps | grep $TEST_APP" + echo "output: "$output + echo "status: "$status + assert_output $TEST_APP + + destroy_app } @test "(apps) apps:destroy" { @@ -36,6 +42,12 @@ load test_helper echo "output: "$output echo "status: "$status assert_success + + create_app + run bash -c "dokku --force --app $TEST_APP apps:destroy" + echo "output: "$output + echo "status: "$status + assert_success } @test "(apps) apps:rename" { diff --git a/tests/unit/20_config.bats b/tests/unit/20_config.bats index fed7612d5..e4afc432b 100644 --- a/tests/unit/20_config.bats +++ b/tests/unit/20_config.bats @@ -57,26 +57,36 @@ teardown() { assert_output "" } -@test "(config) config:set" { - run ssh dokku@dokku.me config:set $TEST_APP test_var=true test_var2=\"hello world\" +@test "(config) config:set/get" { + run ssh dokku@dokku.me config:set $TEST_APP test_var1=true test_var2=\"hello world\" echo "output: "$output echo "status: "$status assert_success + + run bash -c "dokku config:get $TEST_APP test_var1 | grep true" + echo "output: "$output + echo "status: "$status + assert_output "true" + run bash -c "dokku config:get $TEST_APP test_var2 | grep 'hello world'" + echo "output: "$output + echo "status: "$status + assert_output "hello world" } -@test "(config) config:get" { - run ssh dokku@dokku.me config:set $TEST_APP test_var=true test_var2=\"hello world\" test_var3=\"with\\nnewline\" +@test "(config) config:set/get (with --app)" { + run bash -c "dokku --app $TEST_APP config:set test_var1=true test_var2=\"hello world\"" echo "output: "$output echo "status: "$status assert_success - run dokku config:get $TEST_APP test_var2 + + run bash -c "dokku --app $TEST_APP config:get test_var1 | grep true" echo "output: "$output echo "status: "$status - assert_output 'hello world' - run dokku config:get $TEST_APP test_var3 + assert_output "true" + run bash -c "dokku --app $TEST_APP config:get test_var2 | grep 'hello world'" echo "output: "$output echo "status: "$status - assert_output 'with\nnewline' + assert_output "hello world" } @test "(config) config:unset" { @@ -87,7 +97,7 @@ teardown() { run dokku config:get $TEST_APP test_var echo "output: "$output echo "status: "$status - assert_success + assert_output "true" run dokku config:unset $TEST_APP test_var echo "output: "$output echo "status: "$status