diff --git a/plugins/00_dokku-standard/commands b/plugins/00_dokku-standard/commands index ac5fb4d5d..2f13af10d 100755 --- a/plugins/00_dokku-standard/commands +++ b/plugins/00_dokku-standard/commands @@ -8,6 +8,8 @@ source "$PLUGIN_AVAILABLE_PATH/nginx-vhosts/functions" source "$PLUGIN_CORE_AVAILABLE_PATH/proxy/functions" dokku_receive() { + local desc="receives an app kicks off deploy process" + local cmd="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..." @@ -21,6 +23,8 @@ dokku_receive() { } dokku_deploy() { + local desc="deploy phase" + local cmd="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" @@ -55,9 +59,9 @@ dokku_deploy() { [[ -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_DOCKERFILE_PORTS=($(config_get "$APP" DOKKU_DOCKERFILE_PORTS || true)) + local DOKKU_DOCKERFILE_PORT=$(config_get "$APP" DOKKU_DOCKERFILE_PORT || true) + local DOKKU_DOCKERFILE_START_CMD=$(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 @@ -77,7 +81,7 @@ dokku_deploy() { local DOKKU_DOCKER_PORT_ARGS+=" -p $p " done fi - if [[ "$DOKKU_IS_APP_PROXY_ENABLED" = "true" ]]; then + 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") @@ -99,7 +103,8 @@ dokku_deploy() { # 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 + local id="$1" + docker inspect "$id" &> /dev/null && docker stop "$id" > /dev/null && docker kill "$id" &> /dev/null trap - INT TERM EXIT kill -9 $$ } @@ -108,7 +113,7 @@ dokku_deploy() { 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 + trap 'kill_new $id' INT TERM EXIT dokku_log_info1 "Running pre-flight checks" plugn trigger check-deploy "$APP" "$id" "$PROC_TYPE" "$port" "$ipaddr" trap - INT TERM EXIT @@ -144,8 +149,8 @@ dokku_deploy() { 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_APP_DOKKU_WAIT_TO_RETIRE=$(config_get "$APP" DOKKU_WAIT_TO_RETIRE || true) + local DOKKU_GLOBAL_DOKKU_WAIT_TO_RETIRE=$(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 @@ -176,6 +181,8 @@ dokku_deploy() { } dokku_build() { + local desc="build phase" + local cmd="build" local APP="$2"; local IMAGE_SOURCE_TYPE="$3"; local TMP_WORK_DIR="$4"; local IMAGE=$(get_app_image_name "$APP") verify_app_name "$APP" @@ -224,6 +231,8 @@ dokku_build() { } dokku_release() { + local desc="release phase" + local cmd="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" @@ -256,6 +265,8 @@ dokku_release() { } dokku_trace() { + local desc="enables/disables DOKKU_TRACE" + local cmd="trace" [[ -d $DOKKU_ROOT/.dokkurc ]] || mkdir -p "$DOKKU_ROOT/.dokkurc" [[ "$2" == "on" ]] || [[ "$2" == "off" ]] || { dokku_log_fail "Valid trace options are [on/off]" @@ -273,6 +284,8 @@ dokku_trace() { } dokku_ls() { + local desc="lists installed apps with status" + local cmd="ls" local installed_apps=$(dokku_apps) local dokku_app @@ -297,6 +310,8 @@ dokku_ls() { } dokku_run() { + local desc="runs command in container based on app image" + local cmd="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" @@ -304,8 +319,8 @@ dokku_run() { 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_APP_RM_CONTAINER=$(config_get "$APP" DOKKU_RM_CONTAINER || true) + local DOKKU_GLOBAL_RM_CONTAINER=$(config_get --global DOKKU_RM_CONTAINER || true) local DOKKU_RM_CONTAINER=${DOKKU_APP_RM_CONTAINER:="$DOKKU_GLOBAL_RM_CONTAINER"} fi @@ -313,7 +328,7 @@ dokku_run() { [[ "$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" + is_image_herokuish_based "$IMAGE" && local EXEC_CMD="/exec" # shellcheck disable=SC2086 docker run $DOKKU_GLOBAL_RUN_ARGS $DOKKU_RUN_OPTS $DOCKER_ARGS $IMAGE $EXEC_CMD "$@" } diff --git a/plugins/00_dokku-standard/exec-app-json-scripts b/plugins/00_dokku-standard/exec-app-json-scripts index a12563511..88d5a39cb 100755 --- a/plugins/00_dokku-standard/exec-app-json-scripts +++ b/plugins/00_dokku-standard/exec-app-json-scripts @@ -1,27 +1,13 @@ #!/usr/bin/env bash set -eo pipefail; [[ $DOKKU_TRACE ]] && set -x source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions" -APP="$1" - -case "$0" in - *pre-deploy) - IMAGE_TAG="$2" - IMAGE=$(get_app_image_name "$APP" "$IMAGE_TAG") - PHASE_SCRIPT_KEY="predeploy" - ;; - *post-deploy) - IMAGE_TAG="$4" - IMAGE=$(get_app_image_name "$APP" "$IMAGE_TAG") - PHASE_SCRIPT_KEY="postdeploy" - ;; -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 IMAGE="$1"; local PHASE_SCRIPT_KEY="$2" local TMP_WORK_DIR=$(mktemp -d -t "dokku_get_phase_script.XXXX") local APP_JSON_FILE="$TMP_WORK_DIR/app.json" - trap 'rm -rf "$TMP_WORK_DIR" > /dev/null' RETURN + trap 'rm -rf "$TMP_WORK_DIR" > /dev/null' RETURN INT TERM copy_from_image "$IMAGE" "/app/app.json" "$TMP_WORK_DIR" 2>/dev/null || true @@ -36,7 +22,8 @@ get_phase_script() { execute_script() { local desc="executes appropriate phase script key from app.json" - local SCRIPT_CMD=$(get_phase_script "$PHASE_SCRIPT_KEY") + local APP="$1"; local IMAGE="$2"; local PHASE_SCRIPT_KEY="$3" + local SCRIPT_CMD=$(get_phase_script "$IMAGE" "$PHASE_SCRIPT_KEY") if [[ -n "$SCRIPT_CMD" ]];then dokku_log_info1 "Running '$SCRIPT_CMD' in app container" local COMMAND="cd /app ; " @@ -49,7 +36,7 @@ execute_script() { local DOCKER_ARGS=$(: | plugn trigger docker-args-deploy "$APP") local CACHE_DIR="$DOKKU_ROOT/$APP/cache" # shellcheck disable=SC2086 - id=$(docker run "$DOKKU_GLOBAL_RUN_ARGS" --label=dokku_phase_script="${PHASE_SCRIPT_KEY}" -d -v "$CACHE_DIR:/cache" $DOCKER_ARGS "$IMAGE" /bin/bash -c "$COMMAND") + local id=$(docker run "$DOKKU_GLOBAL_RUN_ARGS" --label=dokku_phase_script="${PHASE_SCRIPT_KEY}" -d -v "$CACHE_DIR:/cache" $DOCKER_ARGS "$IMAGE" /bin/bash -c "$COMMAND") test "$(docker wait "$id")" -eq 0 dokku_container_log_verbose_quiet "$id" if [[ "$PHASE_SCRIPT_KEY" != "postdeploy" ]];then @@ -58,5 +45,26 @@ execute_script() { fi } -dokku_log_info1 "Attempting to run scripts.dokku.$PHASE_SCRIPT_KEY from app.json (if defined)" -execute_script +exec_app_json_scripts() { + local desc="core app.json scripts execution" + local trigger="$0 app_json_scripts" + local APP="$1" + + case "$0" in + *pre-deploy) + local IMAGE_TAG="$2" + local IMAGE=$(get_app_image_name "$APP" "$IMAGE_TAG") + local PHASE_SCRIPT_KEY="predeploy" + ;; + *post-deploy) + local IMAGE_TAG="$4" + local IMAGE=$(get_app_image_name "$APP" "$IMAGE_TAG") + local PHASE_SCRIPT_KEY="postdeploy" + ;; + esac + + dokku_log_info1 "Attempting to run scripts.dokku.$PHASE_SCRIPT_KEY from app.json (if defined)" + execute_script "$APP" "$IMAGE" "$PHASE_SCRIPT_KEY" +} + +exec_app_json_scripts "$@" diff --git a/plugins/apps/functions b/plugins/apps/functions index 7674e91a4..1e49f4569 100755 --- a/plugins/apps/functions +++ b/plugins/apps/functions @@ -13,3 +13,35 @@ apps_create() { echo "Creating $APP... done" plugn trigger post-create "$APP" } + +apps_destroy() { + local APP="$1"; local 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" + 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" +} diff --git a/plugins/apps/post-delete b/plugins/apps/post-delete index 081f0af17..3ee28e259 100755 --- a/plugins/apps/post-delete +++ b/plugins/apps/post-delete @@ -2,11 +2,17 @@ set -eo pipefail; [[ $DOKKU_TRACE ]] && set -x source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions" -APP="$1"; IMAGE_REPO=$(get_app_image_repo "$APP") -[[ -n $APP ]] && rm -rf "${DOKKU_ROOT:?}/$APP" > /dev/null +app_post_delete() { + local desc="apps post-delete plugin trigger" + local trigger="app_post_delete" + local APP="$1"; local IMAGE_REPO=$(get_app_image_repo "$APP") + [[ -n $APP ]] && rm -rf "${DOKKU_ROOT:?}/$APP" > /dev/null -# remove all application containers & images -# shellcheck disable=SC2046 -docker rm -f $(docker ps -a --no-trunc | egrep "dokku/${APP}:" | awk '{ print $1 }' | xargs) &>/dev/null || true -# shellcheck disable=SC2046 -docker rmi $(docker images -q "$IMAGE_REPO" | xargs) &>/dev/null || true + # remove all application containers & images + # shellcheck disable=SC2046 + docker rm -f $(docker ps -a --no-trunc | egrep "dokku/${APP}:" | awk '{ print $1 }' | xargs) &>/dev/null || true + # shellcheck disable=SC2046 + docker rmi $(docker images -q "$IMAGE_REPO" | xargs) &>/dev/null || true +} + +app_post_delete "$@" diff --git a/plugins/apps/pre-delete b/plugins/apps/pre-delete index 8ace7bca3..59d29fe86 100755 --- a/plugins/apps/pre-delete +++ b/plugins/apps/pre-delete @@ -2,9 +2,15 @@ set -eo pipefail; [[ $DOKKU_TRACE ]] && set -x source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions" -APP="$1"; IMAGE_TAG="$2"; IMAGE=$(get_app_image_name "$APP" "$IMAGE_TAG"); CACHE_DIR="$DOKKU_ROOT/$APP/cache" -verify_app_name "$APP" +apps_pre_delete() { + local desc="apps pre-delete plugin trigger" + local trigger="apps_pre_delete" + local APP="$1"; local IMAGE_TAG="$2"; local IMAGE=$(get_app_image_name "$APP" "$IMAGE_TAG"); local CACHE_DIR="$DOKKU_ROOT/$APP/cache" + verify_app_name "$APP" -if [[ -d $CACHE_DIR ]]; then - docker run "$DOKKU_GLOBAL_RUN_ARGS" --rm -v "$CACHE_DIR:/cache" "$IMAGE" find /cache -depth -mindepth 1 -maxdepth 1 -exec rm -Rf {} \; || true -fi + if [[ -d $CACHE_DIR ]]; then + docker run "$DOKKU_GLOBAL_RUN_ARGS" --rm -v "$CACHE_DIR:/cache" "$IMAGE" find /cache -depth -mindepth 1 -maxdepth 1 -exec rm -Rf {} \; || true + fi +} + +apps_pre_delete "$@" diff --git a/plugins/apps/subcommands/destroy b/plugins/apps/subcommands/destroy index 5fa01aedb..72e3d27f5 100755 --- a/plugins/apps/subcommands/destroy +++ b/plugins/apps/subcommands/destroy @@ -1,6 +1,7 @@ #!/usr/bin/env bash set -eo pipefail; [[ $DOKKU_TRACE ]] && set -x source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions" +source "$PLUGIN_AVAILABLE_PATH/apps/functions" apps_destroy_cmd() { local desc="destroys an app" @@ -8,35 +9,8 @@ apps_destroy_cmd() { [[ -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" ]] && export DOKKU_APPS_FORCE_DELETE=1 - local APP="$2"; local 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" - 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" + local APP="$2" + apps_destroy "$APP" } apps_destroy_cmd "$@" diff --git a/plugins/apps/subcommands/rename b/plugins/apps/subcommands/rename index cac21cf1b..8b5d3cd11 100755 --- a/plugins/apps/subcommands/rename +++ b/plugins/apps/subcommands/rename @@ -1,6 +1,8 @@ #!/usr/bin/env bash set -eo pipefail; [[ $DOKKU_TRACE ]] && set -x source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions" +source "$PLUGIN_AVAILABLE_PATH/apps/functions" +source "$PLUGIN_AVAILABLE_PATH/ps/functions" apps_rename_cmd() { local desc="renames an app" @@ -14,11 +16,11 @@ apps_rename_cmd() { 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 + DOKKU_APPS_FORCE_DELETE=1 apps_destroy "$OLD_APP" 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" + ps_rebuild "$NEW_APP" plugn trigger post-app-rename "$OLD_APP" "$NEW_APP" echo "Renaming $OLD_APP to $NEW_APP... done" } diff --git a/plugins/build-env/pre-build-buildpack b/plugins/build-env/pre-build-buildpack index fac11f261..37cbc6688 100755 --- a/plugins/build-env/pre-build-buildpack +++ b/plugins/build-env/pre-build-buildpack @@ -3,33 +3,39 @@ set -eo pipefail; [[ $DOKKU_TRACE ]] && set -x source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions" source "$PLUGIN_AVAILABLE_PATH/config/functions" -APP="$1"; IMAGE=$(get_app_image_name "$APP"); BUILD_ENV="" -verify_app_name "$APP" +build_env_pre_build_buildpack() { + local desc="build-env pre-build-buildpack plugin trigger" + local trigger="build_env_pre_build_buildpack" + local APP="$1"; local IMAGE=$(get_app_image_name "$APP"); local BUILD_ENV="" + verify_app_name "$APP" -[[ -z $(config_get --global CURL_CONNECT_TIMEOUT) ]] && config_set --global CURL_CONNECT_TIMEOUT=5 -[[ -z $(config_get --global CURL_TIMEOUT) ]] && config_set --global CURL_TIMEOUT=30 + [[ -z $(config_get --global CURL_CONNECT_TIMEOUT) ]] && config_set --global CURL_CONNECT_TIMEOUT=5 + [[ -z $(config_get --global CURL_TIMEOUT) ]] && config_set --global CURL_TIMEOUT=30 -if [[ -n $(config_export global) ]]; then - BUILD_ENV+=$'\n' - BUILD_ENV+=$(config_export global) - BUILD_ENV+=$'\n' -fi -if [[ -n $(config_export app "$APP") ]]; then - BUILD_ENV+=$'\n' - BUILD_ENV+=$(config_export app "$APP") - BUILD_ENV+=$'\n' -fi + if [[ -n $(config_export global) ]]; then + local BUILD_ENV+=$'\n' + local BUILD_ENV+=$(config_export global) + local BUILD_ENV+=$'\n' + fi + if [[ -n $(config_export app "$APP") ]]; then + local BUILD_ENV+=$'\n' + local BUILD_ENV+=$(config_export app "$APP") + local BUILD_ENV+=$'\n' + fi -if [[ ! -z "$BUILD_ENV" ]]; then - dokku_log_info1 "Adding BUILD_ENV to build environment..." - # create build env files for use in buildpacks like this: - # https://github.com/niteoweb/heroku-buildpack-buildout/blob/5879fa3418f7d8e079f1aa5816ba1adde73f4948/bin/compile#L34 - id=$(echo $BUILD_ENV |sed -e 's@export @@g' -e 's@\\n@ @g' | docker run "$DOKKU_GLOBAL_RUN_ARGS" -i -a stdin "$IMAGE" /bin/bash -c "for ENV_VAR in $(cat); do echo \$ENV_VAR |sed 's@^\([^=]*\)=\(.*\)\$@echo \\\"\2\\\" >/tmp/env/\1@g' >>/tmp/set_env.sh; done && mkdir -p /tmp/env && /bin/bash /tmp/set_env.sh") - test "$(docker wait "$id")" -eq 0 - docker commit "$id" "$IMAGE" > /dev/null + if [[ ! -z "$BUILD_ENV" ]]; then + dokku_log_info1 "Adding BUILD_ENV to build environment..." + # create build env files for use in buildpacks like this: + # https://github.com/niteoweb/heroku-buildpack-buildout/blob/5879fa3418f7d8e079f1aa5816ba1adde73f4948/bin/compile#L34 + local id=$(echo $BUILD_ENV |sed -e 's@export @@g' -e 's@\\n@ @g' | docker run "$DOKKU_GLOBAL_RUN_ARGS" -i -a stdin "$IMAGE" /bin/bash -c "for ENV_VAR in $(cat); do echo \$ENV_VAR |sed 's@^\([^=]*\)=\(.*\)\$@echo \\\"\2\\\" >/tmp/env/\1@g' >>/tmp/set_env.sh; done && mkdir -p /tmp/env && /bin/bash /tmp/set_env.sh") + test "$(docker wait "$id")" -eq 0 + docker commit "$id" "$IMAGE" > /dev/null - # create build env for 'old style' buildpacks and dokku plugins - id=$(echo -e "$BUILD_ENV" | docker run "$DOKKU_GLOBAL_RUN_ARGS" -i -a stdin "$IMAGE" /bin/bash -c "cat >> /app/.env") - test "$(docker wait "$id")" -eq 0 - docker commit "$id" "$IMAGE" > /dev/null -fi + # create build env for 'old style' buildpacks and dokku plugins + local id=$(echo -e "$BUILD_ENV" | docker run "$DOKKU_GLOBAL_RUN_ARGS" -i -a stdin "$IMAGE" /bin/bash -c "cat >> /app/.env") + test "$(docker wait "$id")" -eq 0 + docker commit "$id" "$IMAGE" > /dev/null + fi +} + +build_env_pre_build_buildpack "$@" diff --git a/plugins/certs/functions b/plugins/certs/functions index b9d5f541d..ad6e56732 100755 --- a/plugins/certs/functions +++ b/plugins/certs/functions @@ -5,7 +5,7 @@ source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions" 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" + local APP_SSL_PATH="$DOKKU_ROOT/$APP/tls" if [[ -e "$APP_SSL_PATH/server.crt" ]] && [[ -e "$APP_SSL_PATH/server.key" ]]; then return 0 diff --git a/plugins/certs/subcommands/info b/plugins/certs/subcommands/info index 7241eba29..bfbecdad6 100755 --- a/plugins/certs/subcommands/info +++ b/plugins/certs/subcommands/info @@ -23,11 +23,11 @@ certs_info_cmd() { 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)" + local 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." + local SSL_SELF_SIGNED="verified by a certificate authority." else - SSL_SELF_SIGNED="self signed." + local SSL_SELF_SIGNED="self signed." fi dokku_log_info2 "SSL certificate is $SSL_SELF_SIGNED" else diff --git a/plugins/checks/check-deploy b/plugins/checks/check-deploy index 4a4a08ce9..55209afe5 100755 --- a/plugins/checks/check-deploy +++ b/plugins/checks/check-deploy @@ -33,189 +33,198 @@ # TIMEOUT=60 # Timeout after a minute # ATTEMPTS=10 # retry checks 10 times # - 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" -APP="$1"; DOKKU_APP_CONTAINER_ID="$2"; DOKKU_APP_CONTAINER_TYPE="$3"; DOKKU_APP_LISTEN_PORT="$4"; DOKKU_APP_LISTEN_IP="$5" -if [[ -z "$DOKKU_APP_LISTEN_PORT" ]] && [[ -f "$DOKKU_ROOT/$APP/PORT" ]]; then - DOKKU_APP_LISTEN_PORT=$(< "$DOKKU_ROOT/$APP/PORT") -fi -if [[ -z "$DOKKU_APP_LISTEN_IP" ]] && [[ -f "$DOKKU_ROOT/$APP/IP" ]]; then - DOKKU_APP_LISTEN_IP=$(< "$DOKKU_ROOT/$APP/IP") -fi -if [[ -z "$DOKKU_APP_CONTAINER_ID" ]]; then - DOKKU_APP_CIDS=( $(get_app_container_ids "$APP") ) - DOKKU_APP_CONTAINER_ID=${DOKKU_APP_CIDS[0]} -fi - - -# source global and in-app envs to get DOKKU_CHECKS_WAIT and any other necessary vars -eval "$(config_export global)" -eval "$(config_export app "$APP")" - -if [[ "$(is_app_checks_enabled "$APP")" == "false" ]];then - dokku_log_info2_quiet "Zero downtime checks for app ($APP) have been disabled. moving on..." - exit 0 -fi - -# Wait this many seconds (default 5) for server to start before running checks. -WAIT="${DOKKU_CHECKS_WAIT:-5}" -# Wait this many seconds (default 30) for each response. -TIMEOUT="${DOKKU_CHECKS_TIMEOUT:-30}" -# use this number of retries for checks -ATTEMPTS="${DOKKU_CHECKS_ATTEMPTS:-5}" - -# try to copy CHECKS from container if not in APP dir & quit gracefully if it doesn't exist -# docker cp exits with status 1 when run as non-root user when it tries to chown the file -# after successfully copying the file. Thus, we suppress stderr. -# ref: https://github.com/dotcloud/docker/issues/3986 -TMPDIR=$(mktemp -d /tmp/dokku_CHECKS.XXXXX) -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 - dokku_log_info2_quiet "end $APP container output" -} -trap cleanup EXIT - -if [[ ! -s "${TMPDIR}/CHECKS" ]] || [[ "$DOKKU_APP_CONTAINER_TYPE" != "web" ]]; then - # We allow custom check for web instances only - if [[ "$DOKKU_APP_CONTAINER_TYPE" == "web" ]]; then - dokku_log_verbose "For more efficient zero downtime deployments, create a file CHECKS." - dokku_log_verbose "See http://dokku.viewdocs.io/dokku/checks-examples.md for examples" - dokku_log_verbose "CHECKS file not found in container: Running simple container check..." - else - dokku_log_verbose "Non web container detected: Running default container check..." +checks_check_deploy() { + local desc="checks check-deploy plugin trigger" + local trigger="checks_check_deploy" + local APP="$1"; local DOKKU_APP_CONTAINER_ID="$2"; local DOKKU_APP_CONTAINER_TYPE="$3"; local DOKKU_APP_LISTEN_PORT="$4"; local DOKKU_APP_LISTEN_IP="$5" + if [[ -z "$DOKKU_APP_LISTEN_PORT" ]] && [[ -f "$DOKKU_ROOT/$APP/PORT" ]]; then + local DOKKU_APP_LISTEN_PORT=$(< "$DOKKU_ROOT/$APP/PORT") + fi + if [[ -z "$DOKKU_APP_LISTEN_IP" ]] && [[ -f "$DOKKU_ROOT/$APP/IP" ]]; then + local DOKKU_APP_LISTEN_IP=$(< "$DOKKU_ROOT/$APP/IP") + fi + if [[ -z "$DOKKU_APP_CONTAINER_ID" ]]; then + local DOKKU_APP_CIDS=( $(get_app_container_ids "$APP") ) + local DOKKU_APP_CONTAINER_ID=${DOKKU_APP_CIDS[0]} fi - rm -rf "$TMPDIR" - # simple default check to see if the container stuck around - DOKKU_DEFAULT_CHECKS_WAIT="${DOKKU_DEFAULT_CHECKS_WAIT:-10}" - dokku_log_info1 "Waiting for $DOKKU_DEFAULT_CHECKS_WAIT seconds ..." - sleep "$DOKKU_DEFAULT_CHECKS_WAIT" + # source global and in-app envs to get DOKKU_CHECKS_WAIT and any other necessary vars + eval "$(config_export global)" + eval "$(config_export app "$APP")" - ! (is_container_running $DOKKU_APP_CONTAINER_ID) && dokku_log_fail "App container failed to start!!" - container_restarts=$(docker inspect -f "{{ .RestartCount }}" $DOKKU_APP_CONTAINER_ID) - if [[ $container_restarts -ne 0 ]]; then - docker stop "$DOKKU_APP_CONTAINER_ID" || true - dokku_log_fail "App container failed to start!!" + if [[ "$(is_app_checks_enabled "$APP")" == "false" ]];then + dokku_log_info2_quiet "Zero downtime checks for app ($APP) have been disabled. moving on..." + exit 0 fi - dokku_log_info1 "Default container check successful!" && exit 0 -fi + # Wait this many seconds (default 5) for server to start before running checks. + local WAIT="${DOKKU_CHECKS_WAIT:-5}" + # Wait this many seconds (default 30) for each response. + local TIMEOUT="${DOKKU_CHECKS_TIMEOUT:-30}" + # use this number of retries for checks + local ATTEMPTS="${DOKKU_CHECKS_ATTEMPTS:-5}" -# Reads name/value pairs, sets the WAIT and TIMEOUT variables -exec < "$FILENAME" -while read -r LINE; do - # Name/value pair - if [[ "$LINE" =~ ^.+= ]]; then - TRIM=${LINE%#*} - NAME=${TRIM%=*} - VALUE=${TRIM#*=} - [[ "$NAME" = "WAIT" ]] && WAIT=$VALUE - [[ "$NAME" = "TIMEOUT" ]] && TIMEOUT=$VALUE - [[ "$NAME" = "ATTEMPTS" ]] && ATTEMPTS=$VALUE - fi -done + # try to copy CHECKS from container if not in APP dir & quit gracefully if it doesn't exist + # docker cp exits with status 1 when run as non-root user when it tries to chown the file + # after successfully copying the file. Thus, we suppress stderr. + # ref: https://github.com/dotcloud/docker/issues/3986 + local TMPDIR=$(mktemp -d /tmp/dokku_CHECKS.XXXXX) + docker cp $DOKKU_APP_CONTAINER_ID:/app/CHECKS "$TMPDIR" 2> /dev/null || true -ATTEMPT=0 + local FILENAME=${TMPDIR}/CHECKS -until [[ $SUCCESS == 1 || $ATTEMPT -ge $ATTEMPTS ]] -do - FAILEDCHECKS=0 - ATTEMPT=$(( ATTEMPT + 1 )) - dokku_log_info1 "Attempt $ATTEMPT/$ATTEMPTS Waiting for $WAIT seconds ..." - sleep "$WAIT" + cleanup() { + local desc="cleans up TMPDIR and print container output" + local id="$1" + rm -rf "$TMPDIR" + dokku_log_info2_quiet "$APP container output:" + dokku_container_log_verbose_quiet "$id" + dokku_log_info2_quiet "end $APP container output" + } + trap 'cleanup $DOKKU_APP_CONTAINER_ID' RETURN INT TERM EXIT + if [[ ! -s "${TMPDIR}/CHECKS" ]] || [[ "$DOKKU_APP_CONTAINER_TYPE" != "web" ]]; then + # We allow custom check for web instances only + if [[ "$DOKKU_APP_CONTAINER_TYPE" == "web" ]]; then + dokku_log_verbose "For more efficient zero downtime deployments, create a file CHECKS." + dokku_log_verbose "See http://dokku.viewdocs.io/dokku/checks-examples.md for examples" + dokku_log_verbose "CHECKS file not found in container: Running simple container check..." + else + dokku_log_verbose "Non web container detected: Running default container check..." + fi - # -q do not use .curlrc (must come first) - # --compressed Test compression handled correctly - # --fail Fail on server errors (4xx, 5xx) - # --location Follow redirects - CURL_OPTIONS="-q --compressed --fail --location --max-time $TIMEOUT" + rm -rf "$TMPDIR" - # Set X-Forwarded-Proto header if TLS is enabled. - SSL="$DOKKU_ROOT/$APP/tls"; WILDCARD_SSL="$DOKKU_ROOT/tls" - if [[ -e "$SSL/server.crt" && -e "$SSL/server.key" ]] || [[ -e "$WILDCARD_SSL/server.crt" && -e "$WILDCARD_SSL/server.key" ]]; then - CURL_OPTIONS+=" -H X-Forwarded-Proto:https" + # simple default check to see if the container stuck around + local DOKKU_DEFAULT_CHECKS_WAIT="${DOKKU_DEFAULT_CHECKS_WAIT:-10}" + dokku_log_info1 "Waiting for $DOKKU_DEFAULT_CHECKS_WAIT seconds ..." + sleep "$DOKKU_DEFAULT_CHECKS_WAIT" + + ! (is_container_running $DOKKU_APP_CONTAINER_ID) && dokku_log_fail "App container failed to start!!" + local container_restarts=$(docker inspect -f "{{ .RestartCount }}" $DOKKU_APP_CONTAINER_ID) + if [[ $container_restarts -ne 0 ]]; then + docker stop "$DOKKU_APP_CONTAINER_ID" || true + dokku_log_fail "App container failed to start!!" + fi + + dokku_log_info1 "Default container check successful!" && exit 0 fi + # Reads name/value pairs, sets the WAIT and TIMEOUT variables exec < "$FILENAME" - while read -r CHECK_URL EXPECTED; do - # Ignore empty lines and lines starting with # - # shellcheck disable=SC1001 - [[ -z "$CHECK_URL" || "$CHECK_URL" =~ ^\# ]] && continue - # Ignore if it's not a URL in a supported format - # shellcheck disable=SC1001 - ! [[ "$CHECK_URL" =~ ^(http(s)?:)?\/.* ]] && continue + local LINE + while read -r LINE; do + # Name/value pair + if [[ "$LINE" =~ ^.+= ]]; then + local TRIM=${LINE%#*} + local NAME=${TRIM%=*} + local VALUE=${TRIM#*=} + [[ "$NAME" = "WAIT" ]] && local WAIT=$VALUE + [[ "$NAME" = "TIMEOUT" ]] && local TIMEOUT=$VALUE + [[ "$NAME" = "ATTEMPTS" ]] && local ATTEMPTS=$VALUE + fi + done - if [[ "$CHECK_URL" =~ ^https?: ]]; then - URL_PROTOCOL=${CHECK_URL%:*} - CHECK_URL=${CHECK_URL#*:} - else - URL_PROTOCOL="http" + local ATTEMPT=0 + + until [[ $SUCCESS == 1 || $ATTEMPT -ge $ATTEMPTS ]] + do + local FAILEDCHECKS=0 + local ATTEMPT=$(( ATTEMPT + 1 )) + dokku_log_info1 "Attempt $ATTEMPT/$ATTEMPTS Waiting for $WAIT seconds ..." + sleep "$WAIT" + + + # -q do not use .curlrc (must come first) + # --compressed Test compression handled correctly + # --fail Fail on server errors (4xx, 5xx) + # --location Follow redirects + local CURL_OPTIONS="-q --compressed --fail --location --max-time $TIMEOUT" + + # Set X-Forwarded-Proto header if TLS is enabled. + local SSL="$DOKKU_ROOT/$APP/tls"; local WILDCARD_SSL="$DOKKU_ROOT/tls" + if [[ -e "$SSL/server.crt" && -e "$SSL/server.key" ]] || [[ -e "$WILDCARD_SSL/server.crt" && -e "$WILDCARD_SSL/server.key" ]]; then + local CURL_OPTIONS+=" -H X-Forwarded-Proto:https" fi - if [[ "$CHECK_URL" =~ ^//.+ ]]; then - # To test a URL with specific host name, we still make request to localhost, - # but we set Host header to $SEND_HOST. - # - # The pattern is - # //SEND_HOST/PATHNAME - UNPREFIXED=${CHECK_URL#//} - URL_HOSTNAME=${UNPREFIXED%%/*} - URL_PATHNAME=${UNPREFIXED#$URL_HOSTNAME} + exec < "$FILENAME" + local CHECK_URL + local EXPECTED + while read -r CHECK_URL EXPECTED; do + # Ignore empty lines and lines starting with # + # shellcheck disable=SC1001 + [[ -z "$CHECK_URL" || "$CHECK_URL" =~ ^\# ]] && continue + # Ignore if it's not a URL in a supported format + # shellcheck disable=SC1001 + ! [[ "$CHECK_URL" =~ ^(http(s)?:)?\/.* ]] && continue - HEADERS="-H Host:$URL_HOSTNAME" - else - URL_HOSTNAME=localhost - URL_PATHNAME=$CHECK_URL - fi - - # This URL will show up in the messages - LOG_URL="$URL_PROTOCOL://$URL_HOSTNAME$URL_PATHNAME" - # And how we formulate the CURL request - CURL_ARGS="$CURL_OPTIONS $URL_PROTOCOL://$DOKKU_APP_LISTEN_IP:$DOKKU_APP_LISTEN_PORT$URL_PATHNAME $HEADERS" - - dokku_log_verbose "CHECKS expected result:" - dokku_log_verbose "$LOG_URL => \"$EXPECTED\"" - [[ $DOKKU_TRACE ]] && dokku_log_verbose "$ curl $CURL_ARGS" - - # Capture HTTP response or CURL error message - # shellcheck disable=SC2086 - if OUTPUT=$(curl -# $CURL_ARGS 2>&1); then - # OUTPUT contains the HTTP response - if [[ ! "$OUTPUT" =~ $EXPECTED ]]; then - dokku_log_warn "$LOG_URL: expected to but did not find: \"$EXPECTED\"" - FAILEDCHECKS=$(( FAILEDCHECKS + 1 )) + if [[ "$CHECK_URL" =~ ^https?: ]]; then + local URL_PROTOCOL=${CHECK_URL%:*} + local CHECK_URL=${CHECK_URL#*:} + else + local URL_PROTOCOL="http" fi + + if [[ "$CHECK_URL" =~ ^//.+ ]]; then + # To test a URL with specific host name, we still make request to localhost, + # but we set Host header to $SEND_HOST. + # + # The pattern is + # //SEND_HOST/PATHNAME + local UNPREFIXED=${CHECK_URL#//} + local URL_HOSTNAME=${UNPREFIXED%%/*} + local URL_PATHNAME=${UNPREFIXED#$URL_HOSTNAME} + + local HEADERS="-H Host:$URL_HOSTNAME" + else + local URL_HOSTNAME=localhost + local URL_PATHNAME=$CHECK_URL + fi + + # This URL will show up in the messages + local LOG_URL="$URL_PROTOCOL://$URL_HOSTNAME$URL_PATHNAME" + # And how we formulate the CURL request + local CURL_ARGS="$CURL_OPTIONS $URL_PROTOCOL://$DOKKU_APP_LISTEN_IP:$DOKKU_APP_LISTEN_PORT$URL_PATHNAME $HEADERS" + + dokku_log_verbose "CHECKS expected result:" + dokku_log_verbose "$LOG_URL => \"$EXPECTED\"" + [[ $DOKKU_TRACE ]] && dokku_log_verbose "$ curl $CURL_ARGS" + + # Capture HTTP response or CURL error message + # shellcheck disable=SC2086 + if OUTPUT=$(curl -# $CURL_ARGS 2>&1); then + # OUTPUT contains the HTTP response + if [[ ! "$OUTPUT" =~ $EXPECTED ]]; then + dokku_log_warn "$LOG_URL: expected to but did not find: \"$EXPECTED\"" + local FAILEDCHECKS=$(( FAILEDCHECKS + 1 )) + fi + else + # Failed to connect/no response, OUTPUT contains error message + dokku_log_warn "$OUTPUT" + local FAILEDCHECKS=$(( FAILEDCHECKS + 1 )) + fi + done + + if [[ $FAILEDCHECKS -gt 0 ]]; then + dokku_log_warn "Check attempt $ATTEMPT/$ATTEMPTS failed." + local SUCCESS=0 else - # Failed to connect/no response, OUTPUT contains error message - dokku_log_warn "$OUTPUT" - FAILEDCHECKS=$(( FAILEDCHECKS + 1 )) + local SUCCESS=1 fi done if [[ $FAILEDCHECKS -gt 0 ]]; then - dokku_log_warn "Check attempt $ATTEMPT/$ATTEMPTS failed." - SUCCESS=0 - else - SUCCESS=1 + dokku_log_fail "Could not start due to $FAILEDCHECKS failed checks." + exit 1 fi -done -if [[ $FAILEDCHECKS -gt 0 ]]; then - dokku_log_fail "Could not start due to $FAILEDCHECKS failed checks." - exit 1 -fi + dokku_log_info1 "All checks successful!" +} -dokku_log_info1 "All checks successful!" +checks_check_deploy "$@" diff --git a/plugins/common/functions b/plugins/common/functions index af99951a4..0d971d31b 100755 --- a/plugins/common/functions +++ b/plugins/common/functions @@ -118,9 +118,8 @@ dokku_log_event() { dokku_log_plugn_trigger_call() { local desc="log plugn trigger calls" - local l_hook - l_hook="$1" ; shift + local l_hook="$1" ; shift dokku_log_event "INVOKED: ${l_hook}( $* ) NAME=$NAME FINGERPRINT=$FINGERPRINT" } @@ -131,6 +130,7 @@ dokku_container_log_verbose_quiet() { OIFS=$IFS IFS=$'\n' + local line for line in $(docker logs "$CID" 2>&1); do dokku_log_verbose_quiet "$line" done @@ -173,10 +173,10 @@ get_app_image_name() { [[ -z "$APP" ]] && dokku_log_fail "(get_app_image_name) APP must not be null" if [[ -n "$IMAGE_TAG" ]]; then - IMAGE="$IMAGE_REPO:$IMAGE_TAG" + local IMAGE="$IMAGE_REPO:$IMAGE_TAG" verify_image "$IMAGE" || dokku_log_fail "app image ($IMAGE) not found" else - IMAGE="$IMAGE_REPO:latest" + local IMAGE="$IMAGE_REPO:latest" fi echo "$IMAGE" } @@ -187,8 +187,8 @@ get_running_image_tag() { [[ ! -n "$APP" ]] && dokku_log_fail "(get_running_image_tag) APP must not be null" verify_app_name "$APP" - CIDS=( $(get_app_container_ids "$APP") ) - RUNNING_IMAGE_TAG=$(docker inspect -f '{{ .Config.Image }}' ${CIDS[0]} 2>/dev/null | awk -F: '{ print $2 }' || echo '') + local CIDS=( $(get_app_container_ids "$APP") ) + local RUNNING_IMAGE_TAG=$(docker inspect -f '{{ .Config.Image }}' ${CIDS[0]} 2>/dev/null | awk -F: '{ print $2 }' || echo '') echo "$RUNNING_IMAGE_TAG" } @@ -212,7 +212,7 @@ is_number() { is_abs_path() { local desc="returns 0 if input path is absolute" local TEST_PATH=$1 - if [[ "$TEST_PATH" = /* ]]; then + if [[ "$TEST_PATH" == /* ]]; then return 0 else return 1 @@ -241,7 +241,7 @@ parse_args() { export DOKKU_APP_NAME=${args[$next_index]}; skip=true ;; esac - next_index=$(( next_index + 1 )) + local next_index=$(( next_index + 1 )) done return 0 } @@ -254,10 +254,10 @@ copy_from_image() { if verify_image "$IMAGE"; then if ! is_abs_path "$SRC_FILE"; then local WORKDIR=$(docker inspect -f '{{.Config.WorkingDir}}' "$IMAGE") - [[ -z "$WORKDIR" ]] && WORKDIR=/app - SRC_FILE="$WORKDIR/$SRC_FILE" + [[ -z "$WORKDIR" ]] && local WORKDIR=/app + local SRC_FILE="$WORKDIR/$SRC_FILE" fi - CID=$(docker run "$DOKKU_GLOBAL_RUN_ARGS" -d "$IMAGE" bash) + local CID=$(docker run "$DOKKU_GLOBAL_RUN_ARGS" -d "$IMAGE" bash) docker cp "$CID:$SRC_FILE" "$DST_DIR" docker rm -f "$CID" &> /dev/null else @@ -272,20 +272,21 @@ get_app_container_ids() { [[ -f $DOKKU_ROOT/$APP/CONTAINER ]] && DOKKU_CIDS+=$(< "$DOKKU_ROOT/$APP/CONTAINER") if [[ -n "$CONTAINER_TYPE" ]]; then - CONTAINER_PATTERN="$DOKKU_ROOT/$APP/CONTAINER.$CONTAINER_TYPE.*" + local CONTAINER_PATTERN="$DOKKU_ROOT/$APP/CONTAINER.$CONTAINER_TYPE.*" if [[ $CONTAINER_TYPE == *.* ]]; then - CONTAINER_PATTERN="$DOKKU_ROOT/$APP/CONTAINER.$CONTAINER_TYPE" + local CONTAINER_PATTERN="$DOKKU_ROOT/$APP/CONTAINER.$CONTAINER_TYPE" [[ ! -f $CONTAINER_PATTERN ]] && echo "" && return 0 fi else - CONTAINER_PATTERN="$DOKKU_ROOT/$APP/CONTAINER.*" + local CONTAINER_PATTERN="$DOKKU_ROOT/$APP/CONTAINER.*" fi shopt -s nullglob + local DOKKU_CID_FILE for DOKKU_CID_FILE in $CONTAINER_PATTERN; do - DOKKU_CIDS+=" " - DOKKU_CIDS+=$(< "$DOKKU_CID_FILE") - DOKKU_CIDS+=" " + local DOKKU_CIDS+=" " + local DOKKU_CIDS+=$(< "$DOKKU_CID_FILE") + local DOKKU_CIDS+=" " done shopt -u nullglob echo "$DOKKU_CIDS" @@ -318,8 +319,8 @@ get_cmd_from_procfile() { if [[ -z "$line" ]] || [[ "$line" == "#"* ]]; then continue fi - name="${line%%:*}" - command="${line#*:[[:space:]]}" + local name="${line%%:*}" + local command="${line#*:[[:space:]]}" [[ "$name" == "$PROC_TYPE" ]] && echo "$command" && break done < "$DOKKU_PROCFILE" fi @@ -376,6 +377,8 @@ is_app_running() { release_and_deploy() { local desc="main function for releasing and deploying an app" + source "$PLUGIN_AVAILABLE_PATH/config/functions" + local APP="$1"; local IMAGE_TAG="$2"; local IMAGE=$(get_app_image_name "$APP" "$IMAGE_TAG") verify_app_name "$APP" @@ -386,8 +389,8 @@ release_and_deploy() { local IMAGE_SOURCE_TYPE="dockerfile" fi - 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)" + local DOKKU_APP_SKIP_DEPLOY="$(config_get "$APP" DOKKU_SKIP_DEPLOY || true)" + local DOKKU_GLOBAL_SKIP_DEPLOY="$(config_get --global DOKKU_SKIP_DEPLOY || true)" local DOKKU_SKIP_DEPLOY=${DOKKU_APP_SKIP_DEPLOY:="$DOKKU_GLOBAL_SKIP_DEPLOY"} @@ -398,7 +401,7 @@ release_and_deploy() { dokku_log_info1 "Deploying $APP ($IMAGE)..." dokku deploy "$APP" "$IMAGE_TAG" dokku_log_info2 "Application deployed:" - dokku urls "$APP" | sed "s/^/ /" + get_app_urls urls "$APP" | sed "s/^/ /" else dokku_log_info1 "Skipping deployment" fi @@ -453,18 +456,18 @@ _ipv4_regex() { _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:: - RE_IPV6="${RE_IPV6}([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|" # TEST: 1::8 1:2:3:4:5:6::8 1:2:3:4:5:6::8 - RE_IPV6="${RE_IPV6}([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|" # TEST: 1::7:8 1:2:3:4:5::7:8 1:2:3:4:5::8 - RE_IPV6="${RE_IPV6}([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|" # TEST: 1::6:7:8 1:2:3:4::6:7:8 1:2:3:4::8 - RE_IPV6="${RE_IPV6}([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|" # TEST: 1::5:6:7:8 1:2:3::5:6:7:8 1:2:3::8 - RE_IPV6="${RE_IPV6}([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|" # TEST: 1::4:5:6:7:8 1:2::4:5:6:7:8 1:2::8 - RE_IPV6="${RE_IPV6}[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|" # TEST: 1::3:4:5:6:7:8 1::3:4:5:6:7:8 1::8 - RE_IPV6="${RE_IPV6}:((:[0-9a-fA-F]{1,4}){1,7}|:)|" # TEST: ::2:3:4:5:6:7:8 ::2:3:4:5:6:7:8 ::8 :: - RE_IPV6="${RE_IPV6}fe08:(:[0-9a-fA-F]{1,4}){2,2}%[0-9a-zA-Z]{1,}|" # TEST: fe08::7:8%eth0 fe08::7:8%1 (link-local IPv6 addresses with zone index) - RE_IPV6="${RE_IPV6}::(ffff(:0{1,4}){0,1}:){0,1}${RE_IPV4}|" # TEST: ::255.255.255.255 ::ffff:255.255.255.255 ::ffff:0:255.255.255.255 (IPv4-mapped IPv6 addresses and IPv4-translated addresses) - RE_IPV6="${RE_IPV6}([0-9a-fA-F]{1,4}:){1,4}:${RE_IPV4}" # TEST: 2001:db8:3:4::192.0.2.33 64:ff9b::192.0.2.33 + 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 + local RE_IPV6="${RE_IPV6}([0-9a-fA-F]{1,4}:){1,7}:|" # TEST: 1:: 1:2:3:4:5:6:7:: + local RE_IPV6="${RE_IPV6}([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|" # TEST: 1::8 1:2:3:4:5:6::8 1:2:3:4:5:6::8 + local RE_IPV6="${RE_IPV6}([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|" # TEST: 1::7:8 1:2:3:4:5::7:8 1:2:3:4:5::8 + local RE_IPV6="${RE_IPV6}([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|" # TEST: 1::6:7:8 1:2:3:4::6:7:8 1:2:3:4::8 + local RE_IPV6="${RE_IPV6}([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|" # TEST: 1::5:6:7:8 1:2:3::5:6:7:8 1:2:3::8 + local RE_IPV6="${RE_IPV6}([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|" # TEST: 1::4:5:6:7:8 1:2::4:5:6:7:8 1:2::8 + local RE_IPV6="${RE_IPV6}[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|" # TEST: 1::3:4:5:6:7:8 1::3:4:5:6:7:8 1::8 + local RE_IPV6="${RE_IPV6}:((:[0-9a-fA-F]{1,4}){1,7}|:)|" # TEST: ::2:3:4:5:6:7:8 ::2:3:4:5:6:7:8 ::8 :: + local RE_IPV6="${RE_IPV6}fe08:(:[0-9a-fA-F]{1,4}){2,2}%[0-9a-zA-Z]{1,}|" # TEST: fe08::7:8%eth0 fe08::7:8%1 (link-local IPv6 addresses with zone index) + local RE_IPV6="${RE_IPV6}::(ffff(:0{1,4}){0,1}:){0,1}${RE_IPV4}|" # TEST: ::255.255.255.255 ::ffff:255.255.255.255 ::ffff:0:255.255.255.255 (IPv4-mapped IPv6 addresses and IPv4-translated addresses) + local RE_IPV6="${RE_IPV6}([0-9a-fA-F]{1,4}:){1,4}:${RE_IPV4}" # TEST: 2001:db8:3:4::192.0.2.33 64:ff9b::192.0.2.33 echo "$RE_IPV6" } diff --git a/plugins/config/docker-args-deploy b/plugins/config/docker-args-deploy index c42207da2..4e56133c4 100755 --- a/plugins/config/docker-args-deploy +++ b/plugins/config/docker-args-deploy @@ -3,16 +3,22 @@ set -eo pipefail; [[ $DOKKU_TRACE ]] && set -x source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions" source "$PLUGIN_AVAILABLE_PATH/config/functions" -STDIN=$(cat); APP="$1"; IMAGE_TAG="$2"; IMAGE=$(get_app_image_name "$APP" "$IMAGE_TAG") -DOCKERFILE_ENV_FILE="$DOKKU_ROOT/$APP/DOCKERFILE_ENV_FILE" -verify_app_name "$APP" +config_docker_args() { + local desc="config docker-args plugin trigger" + local trigger="$0 config_docker_args" + local STDIN=$(cat); local APP="$1"; local IMAGE_TAG="$2"; local IMAGE=$(get_app_image_name "$APP" "$IMAGE_TAG") + local DOCKERFILE_ENV_FILE="$DOKKU_ROOT/$APP/DOCKERFILE_ENV_FILE" + verify_app_name "$APP" -if ! is_image_herokuish_based "$IMAGE"; then - > "$DOCKERFILE_ENV_FILE" - config_export global | sed -e "s:^export ::g" -e "s:=':=:g" -e "s:'$::g" > "$DOCKERFILE_ENV_FILE" - config_export app "$APP" | sed -e "s:^export ::g" -e "s:=':=:g" -e "s:'$::g" >> "$DOCKERFILE_ENV_FILE" + if ! is_image_herokuish_based "$IMAGE"; then + > "$DOCKERFILE_ENV_FILE" + config_export global | sed -e "s:^export ::g" -e "s:=':=:g" -e "s:'$::g" > "$DOCKERFILE_ENV_FILE" + config_export app "$APP" | sed -e "s:^export ::g" -e "s:=':=:g" -e "s:'$::g" >> "$DOCKERFILE_ENV_FILE" - echo "$STDIN --env-file=$DOCKERFILE_ENV_FILE" -else - echo "$STDIN" -fi + echo "$STDIN --env-file=$DOCKERFILE_ENV_FILE" + else + echo "$STDIN" + fi +} + +config_docker_args "$@" diff --git a/plugins/docker-options/docker-args-deploy b/plugins/docker-options/docker-args-deploy index 519de709e..b33a9e872 100755 --- a/plugins/docker-options/docker-args-deploy +++ b/plugins/docker-options/docker-args-deploy @@ -1,71 +1,78 @@ #!/usr/bin/env bash set -eo pipefail; [[ $DOKKU_TRACE ]] && set -x -STDIN=$(cat) -APP="$1"; IMAGE_SOURCE_TYPE="$2" +docker_args() { + local desc="docker args plugin trigger" + local trigger="$0" + local STDIN=$(cat) + local APP="$1"; local IMAGE_SOURCE_TYPE="$2" -case "$0" in - *docker-args-build) - PHASE=BUILD - ;; - *docker-args-deploy) - PHASE=DEPLOY - ;; - *docker-args-run) - PHASE=RUN - ;; -esac + case "$0" in + *docker-args-build) + local PHASE=BUILD + ;; + *docker-args-deploy) + local PHASE=DEPLOY + ;; + *docker-args-run) + local PHASE=RUN + ;; + esac -FILE_PREFIX="DOCKER_OPTIONS_" -PHASE_FILE_PATH="${DOKKU_ROOT}/${APP}/${FILE_PREFIX}${PHASE}" + local FILE_PREFIX="DOCKER_OPTIONS_" + local PHASE_FILE_PATH="${DOKKU_ROOT}/${APP}/${FILE_PREFIX}${PHASE}" -output="" + local output="" -if [[ -f "$PHASE_FILE_PATH" ]]; then - DONE=false - until $DONE; do - read -r line || DONE=true + if [[ -f "$PHASE_FILE_PATH" ]]; then + local DONE=false + until $DONE; do + local line + read -r line || local DONE=true - [[ ! -n "$line" ]] && continue + [[ ! -n "$line" ]] && continue - # shellcheck disable=SC1001 - case "$line" in - \#*) - continue - ;; - *) - case "$IMAGE_SOURCE_TYPE" in - dockerfile) - case "$line" in - --link*|-v*) - continue - ;; + # shellcheck disable=SC1001 + case "$line" in + \#*) + continue + ;; + *) + case "$IMAGE_SOURCE_TYPE" in + dockerfile) + case "$line" in + --link*|-v*) + continue + ;; - *) - output="$output $line" - ;; - esac - ;; + *) + local output="$output $line" + ;; + esac + ;; - herokuish) - case "$line" in - --file*|--build-args*) - continue - ;; + herokuish) + case "$line" in + --file*|--build-args*) + continue + ;; - *) - output="$output $line" - ;; - esac - ;; + *) + local output="$output $line" + ;; + esac + ;; - *) - output="$output $line" - ;; - esac - ;; - esac - done < "$PHASE_FILE_PATH" -fi + *) + local output="$output $line" + ;; + esac + ;; + esac + done < "$PHASE_FILE_PATH" + fi -echo "$STDIN$output" + echo "$STDIN$output" +} + +docker_args "$@" diff --git a/plugins/docker-options/functions b/plugins/docker-options/functions index 7450736cb..783af703a 100644 --- a/plugins/docker-options/functions +++ b/plugins/docker-options/functions @@ -49,8 +49,7 @@ 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 - phase_file_path="$(get_phase_file_path "$phase")" + local phase_file_path="$(get_phase_file_path "$phase")" if [[ -s "$phase_file_path" ]]; then display_phase_options "$phase" "$phase_file_path" fi @@ -62,8 +61,7 @@ display_passed_phases_options() { local passed_phases=("${!1}") local phase for phase in "${passed_phases[@]}"; do - local phase_file_path - phase_file_path="$(get_phase_file_path "$phase")" + local phase_file_path="$(get_phase_file_path "$phase")" if [[ ! -s "$phase_file_path" ]]; then echo "${phase^} options: none" else @@ -79,11 +77,10 @@ add_passed_docker_option() { local passed_option_string="$*" local phase for phase in "${passed_phases[@]}"; do - local phase_file_path - phase_file_path="$(get_phase_file_path "$phase")" + local phase_file_path="$(get_phase_file_path "$phase")" create_phase_file_if_required "$phase_file_path" echo "${passed_option_string}" >> "$phase_file_path" - all_phase_options="$(< "$phase_file_path")" + local all_phase_options="$(< "$phase_file_path")" echo -e "${all_phase_options}" | sed '/^$/d' | sort -u > "$phase_file_path" done } @@ -95,11 +92,10 @@ remove_passed_docker_option() { local passed_option_string="$*" local phase for phase in "${passed_phases[@]}"; do - local phase_file_path - phase_file_path="$(get_phase_file_path "$phase")" + local phase_file_path="$(get_phase_file_path "$phase")" [[ ! -s "$phase_file_path" ]] || { - all_phase_options="$(< "$phase_file_path")" - all_phase_options=$(echo -e "${all_phase_options}" | sed "s#^${passed_option_string}\$##") + local all_phase_options="$(< "$phase_file_path")" + local all_phase_options=$(echo -e "${all_phase_options}" | sed "s#^${passed_option_string}\$##") echo -e "${all_phase_options}" | sed '/^$/d' | sort -u > "$phase_file_path" } done diff --git a/plugins/docker-options/subcommands/add b/plugins/docker-options/subcommands/add index 7ac05d6ac..3493a65b8 100755 --- a/plugins/docker-options/subcommands/add +++ b/plugins/docker-options/subcommands/add @@ -10,7 +10,7 @@ docker_options_add_cmd() { 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="$*" + local 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[@]}" } diff --git a/plugins/git/commands b/plugins/git/commands index ee4a5a4da..759b37a81 100755 --- a/plugins/git/commands +++ b/plugins/git/commands @@ -41,78 +41,109 @@ git_build_app_repo() { fi } -case "$1" in - git-hook) - APP=$2 +git_hook_cmd() { + local desc="kick off receive-app trigger from git prereceive hook" + local cmd="git-hook" + local APP="$2" - while read -r oldrev newrev refname; do - # Only run this script for the master branch. You can remove this - # if block if you wish to run it for others as well. - if [[ $refname = "refs/heads/master" ]]; then - # broken out into plugin so we might support other methods to receive an app - # shellcheck disable=SC2086 - plugn trigger receive-app $APP $newrev - else - if test -f "$PLUGIN_PATH"/enabled/*/receive-branch; then - # shellcheck disable=SC2086 - plugn trigger receive-branch $APP $newrev $refname - else - echo $'\e[1G\e[K'"-----> WARNING: deploy did not complete, you must push to master." - echo $'\e[1G\e[K'"-----> for example, try 'git push ${refname/refs\/heads\/}:master'" - fi - fi - done - ;; - - git-upload-pack) - APP="$(echo "$2" | perl -pe 's/(?/dev/null ; echo $?) -ne 0 ]] && echo "$APP_BUILD_LOCK_MSG" - - shift 1 - flock -o "$APP_BUILD_LOCK" dokku git-build-locked "$@" - ;; - - git-build-locked) - APP="$2" - if [[ $# -ge 3 ]]; then - REF="$3" + local oldrev newrev refname + while read -r oldrev newrev refname; do + # Only run this script for the master branch. You can remove this + # if block if you wish to run it for others as well. + if [[ $refname = "refs/heads/master" ]]; then + # broken out into plugin so we might support other methods to receive an app + # shellcheck disable=SC2086 + plugn trigger receive-app $APP $newrev else - REF=$(< "$DOKKU_ROOT/$APP/refs/heads/master") + if test -f "$PLUGIN_PATH"/enabled/*/receive-branch; then + # shellcheck disable=SC2086 + plugn trigger receive-branch $APP $newrev $refname + else + echo $'\e[1G\e[K'"-----> WARNING: deploy did not complete, you must push to master." + echo $'\e[1G\e[K'"-----> for example, try 'git push ${refname/refs\/heads\/}:master'" + fi fi - # shellcheck disable=SC2086 - git_build_app_repo $APP $REF - ;; + done +} - git-*) - APP="$(echo "$2" | perl -pe 's/(? /dev/null - PRERECEIVE_HOOK="$APP_PATH/hooks/pre-receive" - cat > "$PRERECEIVE_HOOK" </dev/null ; echo $?) -ne 0 ]] && echo "$APP_BUILD_LOCK_MSG" + + shift 1 + flock -o "$APP_BUILD_LOCK" dokku git-build-locked "$@" +} + +git_build_locked_cmd() { + local desc="setup and call git_build_app_repo" + local cmd="git-build-locked" + local APP="$2" + if [[ $# -ge 3 ]]; then + local REF="$3" + else + local REF=$(< "$DOKKU_ROOT/$APP/refs/heads/master") + fi + # shellcheck disable=SC2086 + git_build_app_repo $APP $REF +} + +git_glob_cmd() { + local desc="catch-all for any other git-* commands" + local cmd="git-*" + local APP="$(echo "$2" | perl -pe 's/(? /dev/null + local PRERECEIVE_HOOK="$APP_PATH/hooks/pre-receive" + cat > "$PRERECEIVE_HOOK" </dev/null) ]] && exit 0 -for container in "$APP_ROOT"/CONTAINER.*; do - DYNO=$(echo "$container" | sed -r 's/.*CONTAINER\.(.*)/\1/') || true - NAME="$APP.$DYNO" - CURRENT_CONTAINER_ID="$(< "$container")" - PREVIOUS_CIDS=$(docker ps -a -q -f name="^.?$NAME\$" | xargs) || true - if [[ -n $PREVIOUS_CIDS ]]; then - dokku_log_info1_quiet "Found previous container(s) ($PREVIOUS_CIDS) named $NAME" - # in case $PREVIOUS_CIDS has more than one entry - for cid in $PREVIOUS_CIDS; do - PREVIOUS_CONTAINER_STATUS=$(docker inspect -f '{{.State.Status}}' "$cid" || echo "dead") - # dead containers cannot be renamed - if [[ "$PREVIOUS_CONTAINER_STATUS" != "dead" ]]; then - CONTAINER_DATE_NAME="$NAME.$(date +%s)" - dokku_log_info2_quiet "renaming container ($cid) ${NAME} to $CONTAINER_DATE_NAME" - docker rename "$NAME" "$CONTAINER_DATE_NAME" > /dev/null - fi - done - fi - ID=$(cat "$container") - CURRENT_NAME=$(docker inspect -f '{{.Name}}' "$ID" | tr -d /) - dokku_log_info2_quiet "renaming container (${ID:0:12}) $CURRENT_NAME to $NAME" - docker rename "$CURRENT_NAME" "$NAME" > /dev/null -done +named_containers_post_deploy() { + local desc="names deployed app container is consistent manner" + local trigger="named_containers_post_deploy" + local APP="$1"; local APP_ROOT="$DOKKU_ROOT/$APP" + [[ -z $(stat -t "$APP_ROOT"/CONTAINER.* 2>/dev/null) ]] && exit 0 + local container + for container in "$APP_ROOT"/CONTAINER.*; do + local DYNO=$(echo "$container" | sed -r 's/.*CONTAINER\.(.*)/\1/') || true + local NAME="$APP.$DYNO" + local CURRENT_CONTAINER_ID="$(< "$container")" + local PREVIOUS_CIDS=$(docker ps -a -q -f name="^.?$NAME\$" | xargs) || true + if [[ -n $PREVIOUS_CIDS ]]; then + dokku_log_info1_quiet "Found previous container(s) ($PREVIOUS_CIDS) named $NAME" + # in case $PREVIOUS_CIDS has more than one entry + local cid + for cid in $PREVIOUS_CIDS; do + local PREVIOUS_CONTAINER_STATUS=$(docker inspect -f '{{.State.Status}}' "$cid" || echo "dead") + # dead containers cannot be renamed + if [[ "$PREVIOUS_CONTAINER_STATUS" != "dead" ]]; then + local CONTAINER_DATE_NAME="$NAME.$(date +%s)" + dokku_log_info2_quiet "renaming container ($cid) ${NAME} to $CONTAINER_DATE_NAME" + docker rename "$NAME" "$CONTAINER_DATE_NAME" > /dev/null + fi + done + fi + local ID=$(cat "$container") + local CURRENT_NAME=$(docker inspect -f '{{.Name}}' "$ID" | tr -d /) + dokku_log_info2_quiet "renaming container (${ID:0:12}) $CURRENT_NAME to $NAME" + docker rename "$CURRENT_NAME" "$NAME" > /dev/null + done +} + +named_containers_post_deploy "$@" diff --git a/plugins/nginx-vhosts/functions b/plugins/nginx-vhosts/functions index fa47560dc..040e44c76 100755 --- a/plugins/nginx-vhosts/functions +++ b/plugins/nginx-vhosts/functions @@ -47,9 +47,9 @@ nginx_logs() { local NGINX_LOGS_PATH="/var/log/nginx/$APP-$NGINX_LOGS_TYPE.log" if [[ $3 == "-t" ]]; then - NGINX_LOGS_ARGS="-F" + local NGINX_LOGS_ARGS="-F" else - NGINX_LOGS_ARGS="-n 20" + local NGINX_LOGS_ARGS="-n 20" fi tail "$NGINX_LOGS_ARGS" "$NGINX_LOGS_PATH" diff --git a/plugins/nginx-vhosts/post-deploy b/plugins/nginx-vhosts/post-deploy index 02a08a73d..c19804360 100755 --- a/plugins/nginx-vhosts/post-deploy +++ b/plugins/nginx-vhosts/post-deploy @@ -6,6 +6,8 @@ source "$PLUGIN_AVAILABLE_PATH/nginx-vhosts/functions" source "$PLUGIN_AVAILABLE_PATH/proxy/functions" nginx_post_deploy() { + local desc="nginx-vhosts post-deploy plugin trigger" + local trigger="nginx_post_deploy" local APP="$1" if [[ -f "$DOKKU_ROOT/$APP/IP.web.1" ]] && [[ -f "$DOKKU_ROOT/$APP/PORT.web.1" ]]; then if [[ "$(is_app_vhost_enabled "$APP")" == "false" ]]; then diff --git a/plugins/nginx-vhosts/post-domains-update b/plugins/nginx-vhosts/post-domains-update index ae2570122..36cf13ef6 100755 --- a/plugins/nginx-vhosts/post-domains-update +++ b/plugins/nginx-vhosts/post-domains-update @@ -4,6 +4,12 @@ source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions" source "$PLUGIN_AVAILABLE_PATH/nginx-vhosts/functions" source "$PLUGIN_AVAILABLE_PATH/proxy/functions" -if [[ "$(get_app_proxy_type "$1")" == "nginx" ]]; then - nginx_build_config "$1" -fi +nginx_post_domains_update() { + local desc="calls nginx build_config when domains are updated" + local trigger="nginx_post_domains_update" + if [[ "$(get_app_proxy_type "$1")" == "nginx" ]]; then + nginx_build_config "$1" + fi +} + +nginx_post_domains_update "$@" diff --git a/plugins/nginx-vhosts/proxy-disable b/plugins/nginx-vhosts/proxy-disable index c70cd441d..50447e6e9 100755 --- a/plugins/nginx-vhosts/proxy-disable +++ b/plugins/nginx-vhosts/proxy-disable @@ -4,8 +4,9 @@ source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions" source "$PLUGIN_CORE_AVAILABLE_PATH/proxy/functions" source "$PLUGIN_CORE_AVAILABLE_PATH/ps/functions" -nginx_disable() { +nginx_proxy_disable() { local desc="disable nginx proxy" + local trigger="nginx_proxy_disable" local APP="$1"; verify_app_name "$APP" if [[ "$(get_app_proxy_type "$APP")" == "nginx" ]]; then @@ -14,4 +15,4 @@ nginx_disable() { fi } -nginx_disable "$@" +nginx_proxy_disable "$@" diff --git a/plugins/nginx-vhosts/proxy-enable b/plugins/nginx-vhosts/proxy-enable index 23ddb190d..1ceddd952 100755 --- a/plugins/nginx-vhosts/proxy-enable +++ b/plugins/nginx-vhosts/proxy-enable @@ -4,8 +4,9 @@ source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions" source "$PLUGIN_CORE_AVAILABLE_PATH/proxy/functions" source "$PLUGIN_CORE_AVAILABLE_PATH/ps/functions" -nginx_enable() { +nginx_proxy_enable() { local desc="enable nginx proxy" + local trigger="nginx_proxy_enable" local APP="$1"; verify_app_name "$APP" if [[ "$(get_app_proxy_type "$APP")" == "nginx" ]]; then @@ -14,4 +15,4 @@ nginx_enable() { fi } -nginx_enable "$@" +nginx_proxy_enable "$@" diff --git a/plugins/ps/functions b/plugins/ps/functions index a015bbf4e..f5805c854 100755 --- a/plugins/ps/functions +++ b/plugins/ps/functions @@ -44,7 +44,7 @@ generate_scale_file() { if [[ ! -f $DOKKU_SCALE_FILE ]]; then dokku_log_info1_quiet "DOKKU_SCALE file not found in app image. Generating one based on Procfile..." - TMP_WORK_DIR=$(mktemp -d -t "dokku_scale.XXXX") + local TMP_WORK_DIR=$(mktemp -d -t "dokku_scale.XXXX") trap 'rm -rf "$TMP_WORK_DIR" > /dev/null' RETURN if [[ -f $DOKKU_PROCFILE ]]; then @@ -52,8 +52,8 @@ generate_scale_file() { if [[ -z "$line" ]] || [[ "$line" == "#"* ]]; then continue fi - NAME=${line%%:*} - NUM_PROCS=0 + local NAME=${line%%:*} + local NUM_PROCS=0 [[ "$NAME" == "web" ]] && NUM_PROCS=1 [[ -n "$NAME" ]] && echo "$NAME=$NUM_PROCS" >> "$DOKKU_SCALE_FILE" done < "$DOKKU_PROCFILE" @@ -73,8 +73,8 @@ set_scale() { shift 1 local SCALE_SETTINGS=("$@") for procscale in "${SCALE_SETTINGS[@]}"; do - PROC_NAME=${procscale%%=*} - PROC_COUNT=${procscale#*=} + local PROC_NAME=${procscale%%=*} + local PROC_COUNT=${procscale#*=} is_number $PROC_COUNT || dokku_log_fail "ps:scale $PROC_COUNT is not a number" dokku_log_info1_quiet "Scaling $APP:$PROC_NAME to $PROC_COUNT" if (egrep -q ^${PROC_NAME}= "$DOKKU_SCALE_FILE" > /dev/null 2>&1); then @@ -147,8 +147,8 @@ ps_scale() { dokku_col_log_info1_quiet "--------" "---" while read -r line || [[ -n "$line" ]]; do [[ -z "$line" ]] && continue - PROC_NAME=${line%%=*} - PROC_COUNT=${line#*=} + local PROC_NAME=${line%%=*} + local PROC_COUNT=${line#*=} dokku_col_log_info1 "$PROC_NAME" "$PROC_COUNT" done < "$DOKKU_SCALE_FILE" else diff --git a/plugins/ps/post-deploy b/plugins/ps/post-deploy index 07deb0428..6024be3bb 100755 --- a/plugins/ps/post-deploy +++ b/plugins/ps/post-deploy @@ -1,9 +1,16 @@ #!/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/ps/functions" -APP="$1" +ps_post_deploy() { + local desc="ps post-deploy plugin trigger" + local trigger="ps_post_deploy" + local APP="$1" -remove_procfile "$APP" -dokku config:set --no-restart "$APP" DOKKU_APP_RESTORE=1 + remove_procfile "$APP" + config_set --no-restart "$APP" DOKKU_APP_RESTORE=1 +} + +ps_post_deploy "$@" diff --git a/plugins/ps/post-stop b/plugins/ps/post-stop index d2d156c2a..8c0776a1e 100755 --- a/plugins/ps/post-stop +++ b/plugins/ps/post-stop @@ -1,8 +1,13 @@ #!/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/ps/functions" -APP="$1" +ps_post_stop() { + local desc="ps post-stop plugin trigger" + local trigger="ps_post_stop" + local APP="$1" -dokku config:set --no-restart "$APP" DOKKU_APP_RESTORE=0 + config_set --no-restart "$APP" DOKKU_APP_RESTORE=0 +} diff --git a/plugins/ps/pre-deploy b/plugins/ps/pre-deploy index 44ec91a1f..a6f56a493 100755 --- a/plugins/ps/pre-deploy +++ b/plugins/ps/pre-deploy @@ -3,7 +3,13 @@ set -eo pipefail; [[ $DOKKU_TRACE ]] && set -x source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions" source "$PLUGIN_AVAILABLE_PATH/ps/functions" -APP="$1" +ps_pre_deploy() { + local desc="ps pre-deploy plugin trigger" + local trigger="ps_pre_deploy" + local APP="$1" -extract_procfile "$APP" -generate_scale_file "$APP" + extract_procfile "$APP" + generate_scale_file "$APP" +} + +ps_pre_deploy "$@" diff --git a/plugins/ps/subcommands/default b/plugins/ps/subcommands/default index 5852be554..89831e417 100755 --- a/plugins/ps/subcommands/default +++ b/plugins/ps/subcommands/default @@ -12,8 +12,9 @@ ps_main_cmd() { ! (is_deployed "$APP") && echo "App $APP has not been deployed" && exit 0 + local CID for CID in $DOKKU_APP_RUNNING_CONTAINER_IDS; do - has_tty && DOKKU_RUN_OPTS="-i -t" + has_tty && local 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" diff --git a/plugins/ps/subcommands/restore b/plugins/ps/subcommands/restore index f3bfb2353..8ccbba9ad 100755 --- a/plugins/ps/subcommands/restore +++ b/plugins/ps/subcommands/restore @@ -1,13 +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/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) + local DOKKU_APP_RESTORE=$(config_get "$app" DOKKU_APP_RESTORE || true) if [[ $DOKKU_APP_RESTORE != 0 ]]; then echo "Restoring app $app ..." ps_start "$app" diff --git a/plugins/storage/commands b/plugins/storage/commands index 8ef66b861..325a98493 100755 --- a/plugins/storage/commands +++ b/plugins/storage/commands @@ -1,40 +1,8 @@ #!/usr/bin/env bash -[[ " storage storage:list storage:mount storage:unmount storage:help help " == *" $1 "* ]] || exit "$DOKKU_NOT_IMPLEMENTED_EXIT" +[[ " storage:help 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/storage/functions" -source "$PLUGIN_CORE_AVAILABLE_PATH/docker-options/functions" case "$1" in - storage:list) - # List all bound mounts - passed_phases="deploy" - [[ ! $2 ]] && dokku_log_fail "storage:list requires an app to list." - verify_app_name "$2" && APP="$2" - echo "$APP volume bind-mounts:" - get_bind_mounts "$(get_phase_file_path "$passed_phases")" - ;; - - storage:mount) - # Add bind-mount, redeploy app if running - passed_phases=(deploy run) - [[ -z $3 || $4 ]] && dokku_log_fail "storage:mount requires an app and a two paths devided by colon." - verify_app_name "$2" && APP="$2" - verify_paths "$3" && MOUNT_PATH="$3" - check_if_path_exists "$MOUNT_PATH" "$(get_phase_file_path "${passed_phases[@]}")" && dokku_log_fail "Mount path already exists." - add_passed_docker_option passed_phases[@] "-v $MOUNT_PATH" - ;; - - storage:unmount) - # Remove bind-mount, restart app if running - passed_phases=(deploy run) - [[ -z $3 || $4 ]] && dokku_log_fail "storage:unmount requires an app and a two paths devided by colon." - verify_app_name "$2" && APP="$2" - verify_paths "$3" && MOUNT_PATH="$3" - check_if_path_exists "$MOUNT_PATH" "$(get_phase_file_path "${passed_phases[@]}")" || dokku_log_fail "Mount path does not exist." - remove_passed_docker_option passed_phases[@] "-v $MOUNT_PATH" - ;; - help | storage:help) cat<, List bind mounts for app's container(s) (host:container) diff --git a/plugins/storage/functions b/plugins/storage/functions index 56971499c..bd600a208 100755 --- a/plugins/storage/functions +++ b/plugins/storage/functions @@ -3,16 +3,19 @@ set -eo pipefail; [[ $DOKKU_TRACE ]] && set -x source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions" verify_paths() { - echo "$1" | grep -qe '^/.*\:/' || dokku_log_fail "Storage path must be two valid paths devided by colon." + local desc="verifies storage paths" + echo "$1" | grep -qe '^/.*\:/' || dokku_log_fail "Storage path must be two valid paths divided by colon." } check_if_path_exists() { + local desc="checks if path exists" local -r passed_path=$1 local -r phase_file_path=$2 [[ -r "$phase_file_path" ]] && grep -qe "^-v $passed_path" "$phase_file_path" } get_bind_mounts() { + local desc="strips docker options and prints mounts" local -r phase_file_path=$1 [[ -r "$phase_file_path" ]] && sed -e '/^-v/!d' -e 's/^-v/ /' < "$phase_file_path" } diff --git a/plugins/storage/subcommands/list b/plugins/storage/subcommands/list new file mode 100755 index 000000000..7cf67244e --- /dev/null +++ b/plugins/storage/subcommands/list @@ -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/storage/functions" +source "$PLUGIN_CORE_AVAILABLE_PATH/docker-options/functions" + +storage_list_cmd() { + local desc="List all bound mounts" + local cmd="storage:list" + local passed_phases="deploy" + [[ ! $2 ]] && dokku_log_fail "storage:list requires an app to list." + verify_app_name "$2" && local APP="$2" + echo "$APP volume bind-mounts:" + get_bind_mounts "$(get_phase_file_path "$passed_phases")" +} + +storage_list_cmd "$@" diff --git a/plugins/storage/subcommands/mount b/plugins/storage/subcommands/mount new file mode 100755 index 000000000..7eb4645df --- /dev/null +++ b/plugins/storage/subcommands/mount @@ -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/storage/functions" +source "$PLUGIN_CORE_AVAILABLE_PATH/docker-options/functions" + +storage_mount_cmd() { + local desc="Add bind-mount, redeploy app if running" + local cmd="storage:mount" + local passed_phases=(deploy run) + [[ -z $3 || $4 ]] && dokku_log_fail "storage:mount requires an app and a two paths divided by colon." + verify_app_name "$2" && local APP="$2" + verify_paths "$3" && local MOUNT_PATH="$3" + check_if_path_exists "$MOUNT_PATH" "$(get_phase_file_path "${passed_phases[@]}")" && dokku_log_fail "Mount path already exists." + add_passed_docker_option passed_phases[@] "-v $MOUNT_PATH" +} + +storage_mount_cmd "$@" diff --git a/plugins/storage/subcommands/unmount b/plugins/storage/subcommands/unmount new file mode 100755 index 000000000..3007b27a9 --- /dev/null +++ b/plugins/storage/subcommands/unmount @@ -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/storage/functions" +source "$PLUGIN_CORE_AVAILABLE_PATH/docker-options/functions" + +storage_unmount_cmd() { + local desc="Remove bind-mount, restart app if running" + local cmd="storage:unmount" + local passed_phases=(deploy run) + [[ -z $3 || $4 ]] && dokku_log_fail "storage:unmount requires an app and a two paths divided by colon." + verify_app_name "$2" && local APP="$2" + verify_paths "$3" && local MOUNT_PATH="$3" + check_if_path_exists "$MOUNT_PATH" "$(get_phase_file_path "${passed_phases[@]}")" || dokku_log_fail "Mount path does not exist." + remove_passed_docker_option passed_phases[@] "-v $MOUNT_PATH" +} + +storage_unmount_cmd "$@" diff --git a/plugins/tags/subcommands/destroy b/plugins/tags/subcommands/destroy index 46fbfb4e8..6ab3653a5 100755 --- a/plugins/tags/subcommands/destroy +++ b/plugins/tags/subcommands/destroy @@ -7,7 +7,7 @@ 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") + local APP="$2"; local IMAGE_TAG="$3"; local IMAGE_REPO=$(get_app_image_repo "$APP") verify_app_name "$2" case "$IMAGE_TAG" in diff --git a/plugins/tar/receive-app b/plugins/tar/receive-app index 94e33c5fa..0a2348d72 100755 --- a/plugins/tar/receive-app +++ b/plugins/tar/receive-app @@ -3,7 +3,8 @@ set -eo pipefail; [[ $DOKKU_TRACE ]] && set -x source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions" tar_receive_app() { - local desc="receives app tarball and calls tar:build" + local desc="tar receive-app plugin trigger" + local trigger="tar_receive_app" local APP="$1"; local REV="$2" # Don't trigger tar build if there is no tarball. diff --git a/plugins/tar/subcommands/build-locked b/plugins/tar/subcommands/build-locked index 4a13a994f..07bc1e1d7 100755 --- a/plugins/tar/subcommands/build-locked +++ b/plugins/tar/subcommands/build-locked @@ -12,7 +12,7 @@ tar_build_locked_cmd() { # 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 + trap 'rm -rf "$TMP_WORK_DIR" > /dev/null' RETURN INT TERM EXIT # extract tar file chmod 755 "$TMP_WORK_DIR" diff --git a/tests/test_deploy b/tests/test_deploy index 233a17bac..473f65ba6 100755 --- a/tests/test_deploy +++ b/tests/test_deploy @@ -24,7 +24,10 @@ succeeded() { TMP=$(mktemp -d -t "$TARGET.XXXXX") rmdir "$TMP" && cp -r "$(dirname "$SELF")/$APP" "$TMP" -cd "$TMP" + +pushd "$TMP" &> /dev/null || exit 1 +trap 'popd &> /dev/null || true; rm -rf "$TMP"' INT TERM EXIT + git init git config user.email "robot@example.com" git config user.name "Test Robot"