diff --git a/.gitignore b/.gitignore index 555f976e9d8..ad84db0c732 100644 --- a/.gitignore +++ b/.gitignore @@ -1,7 +1,6 @@ .vagrant .DS_Store stack.tgz -build tmp *.deb .ruby-version diff --git a/Vagrantfile b/Vagrantfile index 2da872a19fc..552a1b7602c 100644 --- a/Vagrantfile +++ b/Vagrantfile @@ -2,6 +2,7 @@ # vi: set ft=ruby : BOX_NAME = ENV["BOX_NAME"] || "bento/ubuntu-14.04" +BOX_CPUS = ENV["BOX_CPUS"] || "1" BOX_MEMORY = ENV["BOX_MEMORY"] || "1024" DOKKU_DOMAIN = ENV["DOKKU_DOMAIN"] || "dokku.me" DOKKU_IP = ENV["DOKKU_IP"] || "10.0.0.2" @@ -24,6 +25,7 @@ Vagrant::configure("2") do |config| # Ubuntu's Raring 64-bit cloud image is set to a 32-bit Ubuntu OS type by # default in Virtualbox and thus will not boot. Manually override that. vb.customize ["modifyvm", :id, "--ostype", "Ubuntu_64"] + vb.customize ["modifyvm", :id, "--cpus", BOX_CPUS] vb.customize ["modifyvm", :id, "--memory", BOX_MEMORY] end diff --git a/contrib/dokku_client.sh b/contrib/dokku_client.sh index 823f5398d95..daac4a19290 100755 --- a/contrib/dokku_client.sh +++ b/contrib/dokku_client.sh @@ -54,80 +54,43 @@ if [[ ! -z $DOKKU_HOST ]]; then echo "This is not a git repository" fi - if [[ "$appname" != "" ]] && [[ -n "$*" ]]; then - case "$1" in - apps|help|plugins*|ps:restartall|trace|version) - true - ;; - apps:destroy) - if [[ -z "$2" ]] || [[ "$2" == "force" ]]; then - donotshift="YES" - fi - ;; - *) - donotshift="YES" - ;; - esac - fi - - if [[ "$1" = "apps:create" ]]; then - if [[ -z "$2" ]]; then - appname=$(random_name) - counter=0 - while ssh -p "$DOKKU_PORT" "dokku@$DOKKU_HOST" apps 2>/dev/null| grep -q "$appname"; do - if [[ $counter -ge 100 ]]; then - echo "Error: could not reasonably generate a new app name. try cleaning up some apps..." - ssh -p "$DOKKU_PORT" "dokku@$DOKKU_HOST" apps - exit 1 - else - appname=$(random_name) - counter=$((counter+1)) - fi - done - else - appname="$2" - fi - if git remote add dokku "dokku@$DOKKU_HOST:$appname"; then - echo "-----> Dokku remote added at $DOKKU_HOST" - echo "-----> Application name is $appname" - else - echo "! Dokku remote not added! Do you already have a dokku remote?" - return - fi - git push dokku master - return $? - fi - - if [[ -z "$donotshift" ]]; then - # shellcheck disable=SC2029 - ssh -o LogLevel=QUIET -p "$DOKKU_PORT" -t "dokku@$DOKKU_HOST" "$@" - exit $? - fi - - if [[ -z "$verb" ]]; then - if [[ ! "$1" =~ --* ]]; then - verb=$1 - shift - - if [[ "$1" == "$appname" ]]; then - shift + case "$1" in + apps:create) + if [[ -z "$2" ]]; then + appname=$(random_name) + counter=0 + while ssh -p "$DOKKU_PORT" "dokku@$DOKKU_HOST" apps 2>/dev/null| grep -q "$appname"; do + if [[ $counter -ge 100 ]]; then + echo "Error: could not reasonably generate a new app name. try cleaning up some apps..." + ssh -p "$DOKKU_PORT" "dokku@$DOKKU_HOST" apps + exit 1 + else + appname=$(random_name) + counter=$((counter+1)) + fi + done + else + appname="$2" fi - - args="$*" - else - long_args="--" - for arg in "$@"; do - if [[ "$arg" =~ --* ]]; then - long_args+=" $arg" - args=("${args[@]/$arg}") - else - verb="$arg" - fi - done - fi - fi - # shellcheck disable=SC2086,SC2029 - ssh -o LogLevel=QUIET -p "$DOKKU_PORT" -t "dokku@$DOKKU_HOST" $long_args "$verb" "$appname" "${args[@]}" + if git remote add dokku "dokku@$DOKKU_HOST:$appname"; then + echo "-----> Dokku remote added at $DOKKU_HOST" + echo "-----> Application name is $appname" + else + echo "! Dokku remote not added! Do you already have a dokku remote?" + return + fi + git push dokku master + return $? + ;; + apps:destroy) + git remote remove dokku + ;; + esac + + [[ -n "$@" ]] && [[ -n "$appname" ]] && app_arg="--app $appname" + # echo "ssh -o LogLevel=QUIET -p $DOKKU_PORT -t dokku@$DOKKU_HOST -- $app_arg $@" + # shellcheck disable=SC2068,SC2086 + ssh -o LogLevel=QUIET -p $DOKKU_PORT -t dokku@$DOKKU_HOST -- $app_arg $@ } if [[ "$0" == "dokku" ]] || [[ "$0" == *dokku_client.sh ]] || [[ "$0" == $(which dokku) ]]; then diff --git a/docs/development/plugin-creation.md b/docs/development/plugin-creation.md index 163ebac7ab2..8e66f37dbbe 100644 --- a/docs/development/plugin-creation.md +++ b/docs/development/plugin-creation.md @@ -8,28 +8,73 @@ 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 +The below plugin is a dummy `dokku hello` plugin. -The below plugin is a dummy `dokku hello` plugin. If your plugin exposes commands, this is a good template for your `commands` file: +hello/subcommands/default ```shell #!/usr/bin/env bash set -eo pipefail; [[ $DOKKU_TRACE ]] && set -x source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions" -case "$1" in - hello) - [[ -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" +hello_main_cmd() { + declare 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 "$@" +``` - echo "Hello $APP" - ;; +hello/subcommands/world - hello:world) - echo "Hello world" - ;; +```shell +#!/usr/bin/env bash +set -eo pipefail; [[ $DOKKU_TRACE ]] && set -x +source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions" +hello_world_cmd() { + declare 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 " diff --git a/dokku b/dokku index dec208114b1..2c7abe1eef9 100755 --- a/dokku +++ b/dokku @@ -40,14 +40,14 @@ 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=("$@") if [[ "${args[0]}" =~ ^--.* ]]; then for arg in "$@"; do - if [[ "$arg" =~ ^--.* ]]; then + if [[ "$arg" == "--app" ]]; then + shift 2 + elif [[ "$arg" =~ ^--.* ]]; then shift 1 else break @@ -86,180 +86,76 @@ if ! dokku_auth "$@" ; then 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 +execute_dokku_cmd() { + declare 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} + ;; + receive|deploy|build|release) + local PLUGIN_NAME="00_dokku-standard" + ;; + trace|delete|ls|run|cleanup) + local PLUGIN_NAME="00_dokku-standard" + ;; + url|urls|report|version) + local PLUGIN_NAME="00_dokku-standard" + ;; + esac + + if [[ "$(readlink -f "$PLUGIN_ENABLED_PATH/${PLUGIN_NAME%%:*}")" == *core-plugins* ]] ; then + [[ ${argv[0]} == "$PLUGIN_CMD" ]] && shift 1 + if [[ ! -z $DOKKU_APP_NAME ]]; then + if [[ "$PLUGIN_CMD" == config* ]] && [[ ${argv[1]} == "--no-restart" ]]; then + shift 1 + set -- "--no-restart" "$DOKKU_APP_NAME" "$@" else - CONTAINER_IDX_OFFSET=$((PROC_COUNT + 1)) + set -- "$DOKKU_APP_NAME" "$@" 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" + fi + set -- "$PLUGIN_CMD" "$@" + fi - # kill the old container - if [[ -n "$oldids" ]]; then + 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/$PLUGIN_CMD ]]; then + "$PLUGIN_ENABLED_PATH/$PLUGIN_NAME/subcommands/$PLUGIN_CMD" "$@" + implemented=1 + elif [[ -x $PLUGIN_ENABLED_PATH/${PLUGIN_NAME%%:*}/subcommands/${1#*:} ]]; then + "$PLUGIN_ENABLED_PATH/${PLUGIN_NAME%%:*}/subcommands/${1#*:}" "$@" + implemented=1 + fi - 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"} + 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 - # 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 "" @@ -271,24 +167,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 e9bef16a25c..679c9e6589d 100755 --- a/plugins/00_dokku-standard/commands +++ b/plugins/00_dokku-standard/commands @@ -1,182 +1,8 @@ #!/usr/bin/env bash -[[ " build release trace delete ls run url urls report version help " == *" $1 "* ]] || exit "$DOKKU_NOT_IMPLEMENTED_EXIT" +[[ " 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" -source "$PLUGIN_CORE_AVAILABLE_PATH/proxy/functions" case "$1" in - 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 - ;; - - 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 - ;; - - 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 - ;; - - delete) - dokku apps:destroy "$2" - ;; - - 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 - ;; - - 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" - - 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 "$@" - ;; - - url | urls) - [[ -z $2 ]] && dokku_log_fail "Please specify an app to run the command on" - get_app_urls "$@" - ;; - - report) - dokku_log_info1 "uname: $(uname -a)" - dokku_log_info1 "memory: " - free -m - dokku_log_info1 "docker version: " - docker version - dokku_log_info1 "docker daemon info: " - docker -D info - dokku_log_info1 "sigil version: $(sigil -v)" - dokku_log_info1 "herokuish version: " - docker run --rm -ti gliderlabs/herokuish:latest herokuish version - dokku_log_info1 "dokku version: $(dokku version)" - dokku_log_info1 "dokku plugins: " - dokku plugin - ;; - - version) - cat "$DOKKU_ROOT/VERSION" || dokku_log_fail "Unable to determine dokku's version" - ;; - help) cat< /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 @@ -34,7 +21,9 @@ get_phase_script() { } execute_script() { - local SCRIPT_CMD=$(get_phase_script "$PHASE_SCRIPT_KEY") + declare desc="executes appropriate phase script key from app.json" + 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 ; " @@ -47,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 @@ -56,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() { + declare 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/00_dokku-standard/subcommands/build b/plugins/00_dokku-standard/subcommands/build new file mode 100755 index 00000000000..1bbdc0fcc5e --- /dev/null +++ b/plugins/00_dokku-standard/subcommands/build @@ -0,0 +1,56 @@ +#!/usr/bin/env bash +set -eo pipefail; [[ $DOKKU_TRACE ]] && set -x +source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions" +source "$PLUGIN_AVAILABLE_PATH/config/functions" + +dokku_build_cmd() { + declare 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" + + local CACHE_DIR="$DOKKU_ROOT/$APP/cache" + + eval "$(config_export app "$APP")" + pushd "$TMP_WORK_DIR" &> /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_build_cmd "$@" diff --git a/plugins/00_dokku-standard/subcommands/cleanup b/plugins/00_dokku-standard/subcommands/cleanup new file mode 100755 index 00000000000..69aa0503f15 --- /dev/null +++ b/plugins/00_dokku-standard/subcommands/cleanup @@ -0,0 +1,13 @@ +#!/usr/bin/env bash +set -eo pipefail; [[ $DOKKU_TRACE ]] && set -x +source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions" + +dokku_cleanup_cmd(){ + declare desc="cleans up old deployment cruft" + local cmd="cleanup" + + docker_cleanup +} + + +dokku_cleanup_cmd "$@" diff --git a/plugins/00_dokku-standard/subcommands/deploy b/plugins/00_dokku-standard/subcommands/deploy new file mode 100755 index 00000000000..77a2929eab7 --- /dev/null +++ b/plugins/00_dokku-standard/subcommands/deploy @@ -0,0 +1,166 @@ +#!/usr/bin/env bash +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_CORE_AVAILABLE_PATH/proxy/functions" + +dokku_deploy_cmd() { + declare 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" + 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=($(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 + + 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() { + declare desc="wrapper function to kill newly started app container" + local id="$1" + 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 $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 + 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=$(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 + + # 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 /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_release_cmd "$@" diff --git a/plugins/00_dokku-standard/subcommands/report b/plugins/00_dokku-standard/subcommands/report new file mode 100755 index 00000000000..1a155e7449b --- /dev/null +++ b/plugins/00_dokku-standard/subcommands/report @@ -0,0 +1,24 @@ +#!/usr/bin/env bash +set -eo pipefail; [[ $DOKKU_TRACE ]] && set -x +source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions" + +dokku_report_cmd() { + declare desc="reports dokku vitals for troubleshooting" + local cmd="report" + + dokku_log_info1 "uname: $(uname -a)" + dokku_log_info1 "memory: " + free -m + dokku_log_info1 "docker version: " + docker version + dokku_log_info1 "docker daemon info: " + docker -D info + dokku_log_info1 "sigil version: $(sigil -v)" + dokku_log_info1 "herokuish version: " + docker run --rm -ti gliderlabs/herokuish:latest herokuish version + dokku_log_info1 "dokku version: $(dokku version)" + dokku_log_info1 "dokku plugins: " + dokku plugin +} + +dokku_report_cmd "$@" diff --git a/plugins/00_dokku-standard/subcommands/run b/plugins/00_dokku-standard/subcommands/run new file mode 100755 index 00000000000..ff2ca1588da --- /dev/null +++ b/plugins/00_dokku-standard/subcommands/run @@ -0,0 +1,30 @@ +#!/usr/bin/env bash +set -eo pipefail; [[ $DOKKU_TRACE ]] && set -x +source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions" +source "$PLUGIN_AVAILABLE_PATH/config/functions" + +dokku_run_cmd() { + declare 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" + + shift 2 + + if [[ -z "$DOKKU_RM_CONTAINER" ]]; then + 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 + + 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" && local EXEC_CMD="/exec" + # shellcheck disable=SC2086 + docker run $DOKKU_GLOBAL_RUN_ARGS $DOKKU_RUN_OPTS $DOCKER_ARGS $IMAGE $EXEC_CMD "$@" +} + +dokku_run_cmd "$@" diff --git a/plugins/00_dokku-standard/subcommands/trace b/plugins/00_dokku-standard/subcommands/trace new file mode 100755 index 00000000000..af9154c4094 --- /dev/null +++ b/plugins/00_dokku-standard/subcommands/trace @@ -0,0 +1,24 @@ +#!/usr/bin/env bash +set -eo pipefail; [[ $DOKKU_TRACE ]] && set -x +source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions" + +dokku_trace_cmd() { + declare 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]" + } + + 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_cmd "$@" diff --git a/plugins/00_dokku-standard/subcommands/url b/plugins/00_dokku-standard/subcommands/url new file mode 120000 index 00000000000..f46456a1f97 --- /dev/null +++ b/plugins/00_dokku-standard/subcommands/url @@ -0,0 +1 @@ +urls \ No newline at end of file diff --git a/plugins/00_dokku-standard/subcommands/urls b/plugins/00_dokku-standard/subcommands/urls new file mode 100755 index 00000000000..8e6f1f30476 --- /dev/null +++ b/plugins/00_dokku-standard/subcommands/urls @@ -0,0 +1,12 @@ +#!/usr/bin/env bash +set -eo pipefail; [[ $DOKKU_TRACE ]] && set -x +source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions" + +dokku_urls_cmd() { + [[ -z $2 ]] && dokku_log_fail "Please specify an app to run the command on" + local APP="$2" + + get_app_urls "$@" +} + +dokku_urls_cmd "$@" diff --git a/plugins/00_dokku-standard/subcommands/version b/plugins/00_dokku-standard/subcommands/version new file mode 100755 index 00000000000..99d2c89d135 --- /dev/null +++ b/plugins/00_dokku-standard/subcommands/version @@ -0,0 +1,15 @@ +#!/usr/bin/env bash +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_version_cmd() { + declare desc="prints dokku version" + local cmd="version" + cat "$DOKKU_ROOT/VERSION" || dokku_log_fail "Unable to determine dokku's version" +} + +dokku_version_cmd "$@" diff --git a/plugins/20_events/commands b/plugins/20_events/commands index d661899bb10..07a975254e1 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 14a57b37996..6a3f21f4768 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" +} diff --git a/plugins/apps/post-delete b/plugins/apps/post-delete index 081f0af17fc..9263b31d8fc 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() { + declare 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 8ace7bca358..086f2714a67 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() { + declare 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/create b/plugins/apps/subcommands/create new file mode 100755 index 00000000000..0f68a1a088d --- /dev/null +++ b/plugins/apps/subcommands/create @@ -0,0 +1,11 @@ +#!/usr/bin/env bash +set -eo pipefail; [[ $DOKKU_TRACE ]] && set -x +source "$PLUGIN_AVAILABLE_PATH/apps/functions" + +apps_create_cmd() { + declare desc="creates app via command line" + local cmd="apps:create" + apps_create "$2" +} + +apps_create_cmd "$@" diff --git a/plugins/apps/subcommands/default b/plugins/apps/subcommands/default new file mode 100755 index 00000000000..47f5973a647 --- /dev/null +++ b/plugins/apps/subcommands/default @@ -0,0 +1,16 @@ +#!/usr/bin/env bash +set -eo pipefail; [[ $DOKKU_TRACE ]] && set -x +source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions" + +apps_main_cmd() { + declare desc="lists all apps" + local cmd="apps" + local app + + dokku_log_info2_quiet "My Apps" + for app in $(dokku_apps); do + echo "$app" + done +} + +apps_main_cmd "$@" diff --git a/plugins/apps/subcommands/destroy b/plugins/apps/subcommands/destroy new file mode 100755 index 00000000000..bfeb438629b --- /dev/null +++ b/plugins/apps/subcommands/destroy @@ -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/apps/functions" + +apps_destroy_cmd() { + declare desc="destroys an app" + local cmd="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" ]] && export DOKKU_APPS_FORCE_DELETE=1 + local APP="$2" + apps_destroy "$APP" +} + +apps_destroy_cmd "$@" diff --git a/plugins/apps/subcommands/rename b/plugins/apps/subcommands/rename new file mode 100755 index 00000000000..fef991daf66 --- /dev/null +++ b/plugins/apps/subcommands/rename @@ -0,0 +1,28 @@ +#!/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() { + declare 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_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" + 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/build-env/pre-build-buildpack b/plugins/build-env/pre-build-buildpack index fac11f26156..ae544b7f428 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() { + declare 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/commands b/plugins/certs/commands index cddc43bff6e..ed188e98b39 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 25200f5bb86..b64a14a566f 100755 --- a/plugins/certs/functions +++ b/plugins/certs/functions @@ -2,11 +2,10 @@ 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() { + declare 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 @@ -16,6 +15,7 @@ is_ssl_enabled() { } get_ssl_hostnames() { + declare 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 00000000000..e31710ea665 --- /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() { + declare 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() { + declare 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() { + declare 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 00000000000..a0fd3426207 --- /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() { + declare 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 00000000000..cfda760d87a --- /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() { + declare 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")" + 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 + local SSL_SELF_SIGNED="verified by a certificate authority." + else + local 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 00000000000..5a9c5a7e8d7 --- /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() { + declare 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 00000000000..d28d40b1882 --- /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 d34bd4a222a..53896ad76f5 100755 --- a/plugins/checks/check-deploy +++ b/plugins/checks/check-deploy @@ -33,188 +33,200 @@ # 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() { - 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() { + declare 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" - ! (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!!" - 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")" - 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 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 + 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 -done -ATTEMPT=0 + # 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}" + + # 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 + + local FILENAME=${TMPDIR}/CHECKS + + cleanup() { + declare desc="cleans up TMPDIR and print container output" + local id="$1" + rm -rf "$TMPDIR" + if [[ $id ]]; then + dokku_log_info2_quiet "$APP $DOKKU_APP_CONTAINER_TYPE container output:" + dokku_container_log_verbose_quiet "$id" + dokku_log_info2_quiet "end $APP $DOKKU_APP_CONTAINER_TYPE container output" + fi + } + 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 -until [[ $SUCCESS == 1 || $ATTEMPT -ge $ATTEMPTS ]] -do - FAILEDCHECKS=0 - ATTEMPT=$(( ATTEMPT + 1 )) - dokku_log_info1 "Attempt $ATTEMPT/$ATTEMPTS Waiting for $WAIT seconds ..." - sleep "$WAIT" + rm -rf "$TMPDIR" + # 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" - # -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" + ! (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 - # 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" + 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 - - if [[ "$CHECK_URL" =~ ^https?: ]]; then - URL_PROTOCOL=${CHECK_URL%:*} - CHECK_URL=${CHECK_URL#*:} - else - URL_PROTOCOL="http" + 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" =~ ^//.+ ]]; 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} - - HEADERS="-H Host:$URL_HOSTNAME" - else - URL_HOSTNAME=localhost - URL_PATHNAME=$CHECK_URL + 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 - # 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 )) + 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 + + 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/checks/commands b/plugins/checks/commands index 54a4d4f1e1b..2f95816d016 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/functions b/plugins/checks/functions index 3ed9e227ae6..e0bca091e9a 100755 --- a/plugins/checks/functions +++ b/plugins/checks/functions @@ -4,7 +4,7 @@ source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions" source "$PLUGIN_AVAILABLE_PATH/config/functions" is_app_checks_enabled() { - local desc="return app zero-downtime checks status" + declare desc="return app zero-downtime checks status" local APP="$1"; verify_app_name "$APP" local DOKKU_CHECKS_ENABLED=$(config_get "$APP" DOKKU_CHECKS_ENABLED) diff --git a/plugins/checks/install b/plugins/checks/install index 7905c13ed70..3d5f6e3da60 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() { + declare 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 00000000000..dd584f08b58 --- /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() { + declare 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 00000000000..0c5188dc6ef --- /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() { + declare 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 00000000000..98be76bf092 --- /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() { + declare 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 d32c5f8ade2..28379bacc4c 100755 --- a/plugins/common/functions +++ b/plugins/common/functions @@ -2,6 +2,7 @@ set -eo pipefail; [[ $DOKKU_TRACE ]] && set -x has_tty() { + declare 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() { + declare 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() { + declare desc="log info1 formatter" echo "-----> $*" } dokku_log_info2() { + declare desc="log info2 formatter" echo "=====> $*" } dokku_log_info1_quiet() { + declare 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() { + declare 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() { + declare desc="columnar log info1 formatter" printf "%-6s %-18s %-25s %-25s %-25s\n" "----->" "$@" } dokku_col_log_info1_quiet() { + declare 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() { + declare desc="columnar log info2 formatter" printf "%-6s %-18s %-25s %-25s %-25s\n" "=====>" "$@" } dokku_col_log_info2_quiet() { + declare 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() { + declare desc="columnar log formatter" printf "%-25s %-25s %-25s %-25s\n" "$@" } dokku_col_log_msg_quiet() { + declare 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() { + declare desc="log verbose formatter (with quiet option)" if [[ -z "$DOKKU_QUIET_OUTPUT" ]]; then echo " $*" else @@ -83,35 +96,41 @@ dokku_log_verbose_quiet() { } dokku_log_verbose() { + declare desc="log verbose formatter" echo " $*" } dokku_log_warn() { + declare desc="log warning formatter" echo " ! $*" } dokku_log_fail() { + declare desc="log fail formatter" echo "$@" 1>&2 exit 1 } dokku_log_event() { + declare desc="log dokku events" logger -t dokku -i -- "$@" } dokku_log_plugn_trigger_call() { - local l_hook + declare desc="log plugn trigger calls" - l_hook="$1" ; shift + local l_hook="$1" ; shift dokku_log_event "INVOKED: ${l_hook}( $* ) NAME=$NAME FINGERPRINT=$FINGERPRINT" } dokku_container_log_verbose_quiet() { + declare desc="log verbose container output (with quiet option)" local CID=$1; shift OIFS=$IFS IFS=$'\n' + local line for line in $(docker logs "$CID" 2>&1); do dokku_log_verbose_quiet "$line" done @@ -119,6 +138,7 @@ dokku_container_log_verbose_quiet() { } verify_app_name() { + declare 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() { + declare desc="verify image existence" local IMAGE="$1" if (docker inspect "$IMAGE" &>/dev/null); then return 0 @@ -140,44 +161,46 @@ verify_image() { } get_app_image_repo() { - # central definition of our image repo pattern + declare 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 + declare 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" 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" } get_running_image_tag() { - # retrieve current image tag for a given app. returns empty string if no deployed containers are found + declare 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" - 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" } is_image_herokuish_based() { + declare 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() { + declare desc="returns 0 if input is a number" local NUMBER=$1; local NUM_RE='^[0-9]+$' if [[ $NUMBER =~ $NUM_RE ]]; then return 0 @@ -187,8 +210,9 @@ is_number() { } is_abs_path() { + declare 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 @@ -196,7 +220,10 @@ is_abs_path() { } parse_args() { + declare desc="top-level cli arg parser" + local next_index=1; local skip=false; local args=("$@") for arg in "$@"; do + $skip && skip=false && continue case "$arg" in --quiet) export DOKKU_QUIET_OUTPUT=1 @@ -210,22 +237,27 @@ parse_args() { --force) export DOKKU_APPS_FORCE_DELETE=1 ;; + --app) + export DOKKU_APP_NAME=${args[$next_index]}; skip=true + ;; esac + local next_index=$(( next_index + 1 )) done return 0 } copy_from_image() { + declare desc="copy file from named image to destination" local IMAGE="$1"; local SRC_FILE="$2"; local DST_DIR="$3" verify_app_name "$APP" 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 @@ -234,31 +266,34 @@ copy_from_image() { } get_app_container_ids() { + declare 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") 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" } get_app_running_container_ids() { + declare desc="return list of running docker container ids for given apps" local APP=$1 verify_app_name "$APP" @@ -274,6 +309,7 @@ get_app_running_container_ids() { } get_cmd_from_procfile() { + declare 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" @@ -283,14 +319,15 @@ 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 } is_deployed() { + declare 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 @@ -300,6 +337,7 @@ is_deployed() { } is_container_running () { + declare 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) @@ -311,6 +349,7 @@ is_container_running () { } is_container_status () { + declare 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) @@ -323,6 +362,7 @@ is_container_status () { } is_app_running() { + declare desc="return 0 if given app has a running container" local APP="$1" verify_app_name "$APP" @@ -336,20 +376,23 @@ is_app_running() { } release_and_deploy() { + declare 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" 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="$(config_get "$APP" DOKKU_SKIP_DEPLOY || true)" + local DOKKU_GLOBAL_SKIP_DEPLOY="$(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" @@ -358,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 @@ -368,6 +411,7 @@ release_and_deploy() { } docker_cleanup() { + declare 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 @@ -382,6 +426,7 @@ docker_cleanup() { } get_available_port() { + declare 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 @@ -394,6 +439,7 @@ get_available_port() { } dokku_auth() { + declare 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 @@ -403,27 +449,30 @@ dokku_auth() { } _ipv4_regex() { + declare desc="ipv4 regex" echo "([0-9]{1,3}[\.]){3}[0-9]{1,3}" } _ipv6_regex() { + declare 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" } get_ipv4_regex() { + declare 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 @@ -431,6 +480,7 @@ get_ipv4_regex() { } get_ipv6_regex() { + declare 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 @@ -438,13 +488,14 @@ 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" + declare 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() { - local desc="returns true if we have a valid global vhost set; otherwise returns false" + declare desc="returns true if we have a valid global vhost set; otherwise returns false" local GLOBAL_VHOST=$(get_global_vhost) local GLOBAL_VHOST_ENABLED=true local RE_IPV4="$(get_ipv4_regex)" @@ -457,9 +508,10 @@ 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" + declare desc="returns true or false if vhost support is enabled for a given application" + 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 @@ -471,7 +523,9 @@ is_app_vhost_enabled() { } disable_app_vhost() { - local desc="disable vhost support for given application" + declare 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" @@ -499,7 +553,9 @@ disable_app_vhost() { } enable_app_vhost() { - local desc="enable vhost support for given application" + declare 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 @@ -509,11 +565,15 @@ enable_app_vhost() { } get_dockerfile_exposed_ports() { + declare 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() { + declare 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 @@ -522,11 +582,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() { + declare desc="returns published ports from app containers" local APP="$1"; verify_app_name "$APP" local APP_CIDS="$(get_app_container_ids "$APP")" local cid @@ -539,6 +600,10 @@ get_container_ports() { } get_app_urls() { + declare desc="print an app's available urls" + source "$PLUGIN_AVAILABLE_PATH/config/functions" + source "$PLUGIN_AVAILABLE_PATH/proxy/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" @@ -603,7 +668,7 @@ get_app_urls() { } get_json_value() { - # return value of provided json key from a json stream on stdin + declare 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" @@ -613,7 +678,7 @@ get_json_value() { } get_json_keys() { - # return space-separated list of json keys from json provided on stdin + declare 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 36b1c013b58..ddd9c069922 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/docker-args-deploy b/plugins/config/docker-args-deploy index c42207da2f3..b6d0bf53422 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() { + declare 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/config/functions b/plugins/config/functions index b63dd2ac10d..ec515096d45 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() { + declare 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() { + declare 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 () { + declare desc="create config env file" local ENV_FILE=$1 [[ -f $ENV_FILE ]] || touch "$ENV_FILE" } config_styled_hash () { + declare desc="internal config hash" local vars="$1" local prefix="$2" local longest="" @@ -79,6 +83,7 @@ config_styled_hash () { } config_write() { + declare 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() { + declare 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() { + declare desc="print or export config vars" [[ "$1" == "config" ]] || set -- "config" "$@" config_parse_args "$@" @@ -123,6 +130,7 @@ config_all() { } config_get() { + declare desc="get value of given config var" [[ "$1" == "config:get" ]] || set -- "config:get" "$@" config_parse_args "$@" @@ -143,6 +151,7 @@ config_get() { } config_set() { + declare 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() { + declare 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 00000000000..2a266cc814d --- /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() { + declare 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 00000000000..6a0822ab471 --- /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() { + declare 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 00000000000..54253d3aa49 --- /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() { + declare 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 00000000000..abb864d0347 --- /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() { + declare 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 2dadcbd0a9f..5c934c8d5fe 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/docker-args-deploy b/plugins/docker-options/docker-args-deploy index 519de709ea6..7d71f39eb69 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() { + declare 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 07ae08b64b7..d49ba305d1f 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() { + declare 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() { + declare 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() { + declare 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() { + declare desc="print docker-options for specified phase" local phase="$1" local phase_file_path="$2" echo "${phase^} options:" @@ -42,10 +46,10 @@ display_phase_options() { } display_all_phases_options() { + declare 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 @@ -53,11 +57,11 @@ display_all_phases_options() { } display_passed_phases_options() { + declare desc="print docker options for list of specified phases" 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 @@ -67,31 +71,31 @@ display_passed_phases_options() { } add_passed_docker_option() { + declare desc="adds docker option to specified phases" local passed_phases=("${!1}") shift 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 } remove_passed_docker_option() { + declare desc="removes docker option from specified phases" local passed_phases=("${!1}") shift 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 new file mode 100755 index 00000000000..b66576539b0 --- /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() { + declare 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 + 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[@]}" +} + +docker_options_add_cmd "$@" diff --git a/plugins/docker-options/subcommands/default b/plugins/docker-options/subcommands/default new file mode 100755 index 00000000000..25d4580d567 --- /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() { + declare 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 00000000000..f232083ef21 --- /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() { + declare 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 b860ba70f87..72e869845d1 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 334eff5694d..1326d82417f 100755 --- a/plugins/domains/functions +++ b/plugins/domains/functions @@ -3,7 +3,7 @@ set -eo pipefail; [[ $DOKKU_TRACE ]] && set -x source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions" get_app_domains() { - local desc="return app domains" + declare desc="return app domains" verify_app_name "$1" local APP=$1; local APP_VHOST_FILE="$DOKKU_ROOT/$APP/VHOST" local GLOBAL_VHOST_PATH="$DOKKU_ROOT/VHOST" @@ -21,7 +21,7 @@ get_app_domains() { } get_default_vhost() { - local desc="return default vhost" + declare desc="return default vhost" verify_app_name "$1" local APP="$1"; local RE_IPV4="$(get_ipv4_regex)"; local RE_IPV6="$(get_ipv6_regex)" @@ -44,7 +44,7 @@ get_default_vhost() { } domains_setup() { - local desc="setup domains to default state" + declare desc="setup domains to default state" verify_app_name "$1" local APP="$1"; local APP_VHOST_PATH="$DOKKU_ROOT/$APP/VHOST"; local GLOBAL_VHOST_PATH="$DOKKU_ROOT/VHOST" local RE_IPV4="$(get_ipv4_regex)"; local RE_IPV6="$(get_ipv6_regex)" @@ -61,27 +61,8 @@ 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" + declare desc="add list of domains to app" verify_app_name "$1" local APP="$1"; local APP_VHOST_PATH="$DOKKU_ROOT/$APP/VHOST" @@ -103,19 +84,8 @@ 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" + declare desc="remove list of app domains" verify_app_name "$1" local APP="$1"; local APP_VHOST_PATH="$DOKKU_ROOT/$APP/VHOST" local DEFAULT_VHOST="$(get_default_vhost "$APP")" @@ -129,7 +99,7 @@ domains_remove() { } domains_disable() { - local desc="disable domains/VHOST support" + declare desc="disable domains/VHOST support" verify_app_name "$1" local APP="$1"; local APP_VHOST_PATH="$DOKKU_ROOT/$APP/VHOST" @@ -141,7 +111,7 @@ domains_disable() { } domains_enable() { - local desc="enable domains/VHOST support" + declare desc="enable domains/VHOST support" verify_app_name "$1" local APP="$1"; local APP_VHOST_PATH="$DOKKU_ROOT/$APP/VHOST" local DEFAULT_VHOST="$(get_default_vhost "$APP")" @@ -158,7 +128,7 @@ domains_enable() { } domains_set_global() { - local desc="set global domain name" + declare desc="set global domain name" local NEW_GLOBAL_VHOST="$1"; local GLOBAL_VHOST_PATH="$DOKKU_ROOT/VHOST" if [[ -n "$NEW_GLOBAL_VHOST" ]]; then diff --git a/plugins/domains/install b/plugins/domains/install index ca32d9a947d..6fd5a2a5809 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 00000000000..b58d45a205b --- /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() { + declare 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 00000000000..ca4a19be453 --- /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() { + declare 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 00000000000..7bf731c040c --- /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() { + declare 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 00000000000..c32f3ab789d --- /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() { + declare 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 00000000000..195b1d4d85e --- /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() { + declare 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 00000000000..1d0e44695c7 --- /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() { + declare 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 00000000000..18ae15a118e --- /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() { + declare 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 00000000000..0c0bd345f6f --- /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() { + declare 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 df0997a3819..94709c05ee1 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 00000000000..ab6634142a1 --- /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() { + declare 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 8cc9fec8b1f..8ace412eeb2 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() { + declare 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 @@ -40,78 +41,109 @@ git_build_app_repo() { fi } -case "$1" in - git-hook) - 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 +git_hook_cmd() { + declare desc="kick off receive-app trigger from git prereceive hook" + local cmd="git-hook" + local APP="$2" + + 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 + if test -f "$PLUGIN_PATH"/enabled/*/receive-branch; then # shellcheck disable=SC2086 - plugn trigger receive-app $APP $newrev + plugn trigger receive-branch $APP $newrev $refname 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 + 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 - done - ;; + fi + done +} - git-upload-pack) - APP="$(echo "$2" | perl -pe 's/(?/dev/null ; echo $?) -ne 0 ]] && echo "$APP_BUILD_LOCK_MSG" +git_build_cmd() { + declare desc="lock git-build" + local cmd="git-build" + 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 git-build-locked "$@" - ;; + shift 1 + flock -o "$APP_BUILD_LOCK" dokku git-build-locked "$@" +} - git-build-locked) - APP="$2" - if [[ $# -ge 3 ]]; then - REF="$3" - else - REF=$(< "$DOKKU_ROOT/$APP/refs/heads/master") - fi - # shellcheck disable=SC2086 - git_build_app_repo $APP $REF - ;; +git_build_locked_cmd() { + declare 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-*) - APP="$(echo "$2" | perl -pe 's/(? /dev/null - PRERECEIVE_HOOK="$APP_PATH/hooks/pre-receive" - cat > "$PRERECEIVE_HOOK" < /dev/null + local PRERECEIVE_HOOK="$APP_PATH/hooks/pre-receive" + cat > "$PRERECEIVE_HOOK" <&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)" - ;; +usage() { + declare 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:help) usage ;; diff --git a/plugins/logs/functions b/plugins/logs/functions deleted file mode 100755 index 71ad638f862..00000000000 --- 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 00000000000..e97480c6a99 --- /dev/null +++ b/plugins/logs/subcommands/default @@ -0,0 +1,63 @@ +#!/usr/bin/env bash +set -eo pipefail; [[ $DOKKU_TRACE ]] && set -x +source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions" + +logs_default_cmd() { + declare 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/named-containers/post-deploy b/plugins/named-containers/post-deploy index f69508e402f..4fbc60c7c2c 100755 --- a/plugins/named-containers/post-deploy +++ b/plugins/named-containers/post-deploy @@ -2,28 +2,36 @@ set -eo pipefail; [[ $DOKKU_TRACE ]] && set -x source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions" -APP="$1"; APP_ROOT="$DOKKU_ROOT/$APP" -[[ -z $(stat -t "$APP_ROOT"/CONTAINER.* 2>/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() { + declare 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/commands b/plugins/nginx-vhosts/commands index 190a25a10a0..ef0100b7795 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 ada62cfcfa5..ae5f9ed9b74 100755 --- a/plugins/nginx-vhosts/functions +++ b/plugins/nginx-vhosts/functions @@ -7,7 +7,7 @@ source "$PLUGIN_AVAILABLE_PATH/domains/functions" source "$PLUGIN_AVAILABLE_PATH/ps/functions" validate_nginx() { - local desc="validate entire nginx config" + declare desc="validate entire nginx config" set +e sudo /usr/sbin/nginx -t > /dev/null 2>&1 local exit_code=$? @@ -19,7 +19,7 @@ validate_nginx() { } restart_nginx() { - local desc="restart nginx for given distros" + declare desc="restart nginx for given distros" case "$DOKKU_DISTRO" in debian) sudo /usr/sbin/invoke-rc.d nginx reload > /dev/null @@ -40,23 +40,23 @@ restart_nginx() { } nginx_logs() { - local desc="display app nginx logs" + declare desc="display app nginx logs" local APP="$2"; verify_app_name "$APP" local NGINX_LOGS_TYPE=${1#nginx:} local NGINX_LOGS_TYPE=${NGINX_LOGS_TYPE%-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" } configure_nginx_ports() { - local desc="configure nginx listening ports" + declare desc="configure nginx listening ports" local APP=$1; verify_app_name "$APP" local RAW_TCP_PORTS="$(get_app_raw_tcp_ports "$APP")" local DOKKU_NGINX_PORT=$(config_get "$APP" DOKKU_NGINX_PORT) @@ -89,7 +89,7 @@ configure_nginx_ports() { } validate_ssl_domains() { - local desc="check configured domains against SSL cert contents and show warning if mismatched" + declare desc="check configured domains against SSL cert contents and show warning if mismatched" local APP=$1; verify_app_name "$APP" local SSL_HOSTNAME=$(get_ssl_hostnames "$APP") local SSL_HOSTNAME_REGEX=$(echo "$SSL_HOSTNAME" | xargs | sed 's|\.|\\.|g' | sed 's/\*/\[^\.\]\*/g' | sed 's/ /|/g') @@ -110,6 +110,7 @@ validate_ssl_domains() { } get_custom_nginx_template() { + declare 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")" @@ -120,7 +121,7 @@ get_custom_nginx_template() { } nginx_build_config() { - local desc="build nginx config to proxy app containers using sigil" + declare desc="build nginx config to proxy app containers using sigil" local APP="$1"; verify_app_name "$APP" local DOKKU_APP_LISTEN_PORT="$2"; local DOKKU_APP_LISTEN_IP="$3" local VHOST_PATH="$DOKKU_ROOT/$APP/VHOST"; local URLS_PATH="$DOKKU_ROOT/$APP/URLS" diff --git a/plugins/nginx-vhosts/post-deploy b/plugins/nginx-vhosts/post-deploy index 02a08a73dda..f716b0715a6 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() { + declare 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 ae25701220d..6201175b700 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() { + declare 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 c70cd441d4b..512863078e3 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() { - local desc="disable nginx proxy" +nginx_proxy_disable() { + declare 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 23ddb190d8b..a4fe26eddb3 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() { - local desc="enable nginx proxy" +nginx_proxy_enable() { + declare 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/nginx-vhosts/subcommands/access-logs b/plugins/nginx-vhosts/subcommands/access-logs new file mode 100755 index 00000000000..5b8fa8990c7 --- /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() { + declare 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 00000000000..212c8ef15ad --- /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() { + declare 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 00000000000..8069b30c1d2 --- /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 6916719e788..d331361df4f 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 ad6935a466b..5f3dce1b6cc 100755 --- a/plugins/proxy/functions +++ b/plugins/proxy/functions @@ -4,7 +4,7 @@ source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions" source "$PLUGIN_AVAILABLE_PATH/config/functions" is_app_proxy_enabled() { - local desc="return true if proxy is enabled; otherwise return false" + declare desc="return true if proxy is enabled; otherwise return false" local APP="$1"; verify_app_name "$APP" local APP_PROXY_ENABLED=true @@ -16,61 +16,9 @@ is_app_proxy_enabled() { } get_app_proxy_type() { - local desc="return app proxy type" + declare desc="return app proxy type" local APP="$1"; verify_app_name "$APP" local APP_PROXY_TYPE="nginx" 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 00000000000..cd913904c75 --- /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() { + declare 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 00000000000..504b6f6af3f --- /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() { + declare 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 00000000000..0aa20f2b44b --- /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() { + declare 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 00000000000..ac08a58ec4f --- /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() { + declare 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 71472b8a199..a445b22fd6e 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 7bf9d6bee69..930ba5ea374 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() { + declare 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() { + declare 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() { + declare 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() { + declare 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" @@ -40,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 @@ -48,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" @@ -64,12 +68,13 @@ generate_scale_file() { } set_scale() { + declare desc="sets app proc type scaling" local APP="$1"; local DOKKU_SCALE_FILE="$DOKKU_ROOT/$APP/DOKKU_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 @@ -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() { + declare 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() { + declare 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() { + declare desc="rebuilds app from base image" local APP="$1"; verify_app_name "$APP" plugn trigger receive-app "$APP" } ps_restart() { + declare 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() { + declare 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" @@ -151,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 07deb042896..f66170f6fcd 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() { + declare 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 d2d156c2acf..e3e22f695d8 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() { + declare 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 44ec91a1f06..92112d8ec2a 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() { + declare 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 new file mode 100755 index 00000000000..46dec800a3d --- /dev/null +++ b/plugins/ps/subcommands/default @@ -0,0 +1,24 @@ +#!/usr/bin/env bash +set -eo pipefail; [[ $DOKKU_TRACE ]] && set -x +source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions" + +ps_main_cmd() { + declare 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 + + local CID + for CID in $DOKKU_APP_RUNNING_CONTAINER_IDS; do + 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" + done +} + +ps_main_cmd "$@" diff --git a/plugins/ps/subcommands/rebuild b/plugins/ps/subcommands/rebuild new file mode 100755 index 00000000000..e564be45a8f --- /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() { + declare 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 00000000000..7a903b3f0df --- /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() { + declare 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 00000000000..cf41a64b41b --- /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() { + declare 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 00000000000..bfdeed29a43 --- /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() { + declare 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 00000000000..0b7b8372981 --- /dev/null +++ b/plugins/ps/subcommands/restore @@ -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/config/functions" +source "$PLUGIN_AVAILABLE_PATH/ps/functions" + +ps_restore_cmd() { + declare 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=$(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 00000000000..3e4993200f5 --- /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() { + declare 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 00000000000..4f3e298d719 --- /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() { + declare 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 00000000000..a24b7555929 --- /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() { + declare 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 182c33b95ce..361a41d561f 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/storage/commands b/plugins/storage/commands index 8ef66b86174..325a9849372 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 56971499cad..767059f1300 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." + declare 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() { + declare 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() { + declare 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 00000000000..ecaab29b0cc --- /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() { + declare 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 00000000000..b82a550cbb7 --- /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() { + declare 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 00000000000..d460386d560 --- /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() { + declare 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/commands b/plugins/tags/commands index 5d76164a807..8dc78b2be4c 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 df1721dfdfa..cd244c1052c 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() { + declare 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 00000000000..00adbea586a --- /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() { + declare 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 00000000000..de16fb92616 --- /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() { + declare 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 00000000000..ebd6ec1ac1f --- /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() { + declare 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 00000000000..4fec517ab13 --- /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() { + declare 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" + local APP="$2"; local IMAGE_TAG="$3"; local 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 4d6eaa4887b..c83149ba575 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 99ab6201702..16f6dd5cafc 100755 --- a/plugins/tar/receive-app +++ b/plugins/tar/receive-app @@ -2,11 +2,17 @@ set -eo pipefail; [[ $DOKKU_TRACE ]] && set -x source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions" -APP="$1"; REV="$2" +tar_receive_app() { + declare 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. -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 00000000000..ecb0b96e083 --- /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() { + declare 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 00000000000..63b366b8f4c --- /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() { + declare 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' RETURN 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 00000000000..c51b74fbf16 --- /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() { + declare 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 00000000000..7bbdb5f87c3 --- /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() { + declare 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/ci/parallel_runner.sh b/tests/ci/parallel_runner.sh index c78b07f252d..823ac13e5e0 100755 --- a/tests/ci/parallel_runner.sh +++ b/tests/ci/parallel_runner.sh @@ -46,26 +46,55 @@ if [[ -n "$CIRCLE_NODE_INDEX" ]] && [[ "$MODE" == "setup" ]]; then # esac fi +start=$(date +%s) case "$CIRCLE_NODE_INDEX" in 0) echo "=====> make unit-tests (1/4) on CIRCLE_NODE_INDEX: $CIRCLE_NODE_INDEX" sudo -E UNIT_TEST_BATCH=1 make -e unit-tests + RC=$? + if [[ $RC -ne 0 ]]; then + echo "exit status: $RC" + exit $RC + fi ;; 1) echo "=====> make unit-tests (2/4) on CIRCLE_NODE_INDEX: $CIRCLE_NODE_INDEX" sudo -E UNIT_TEST_BATCH=2 make -e unit-tests + RC=$? + if [[ $RC -ne 0 ]]; then + echo "exit status: $RC" + exit $RC + fi ;; 2) echo "=====> make unit-tests (3/4) on CIRCLE_NODE_INDEX: $CIRCLE_NODE_INDEX" sudo -E UNIT_TEST_BATCH=3 make -e unit-tests + RC=$? + if [[ $RC -ne 0 ]]; then + echo "exit status: $RC" + exit $RC + fi echo "=====> make deploy tests" sudo -E make -e deploy-test-checks-root deploy-test-config deploy-test-multi + RC=$? + if [[ $RC -ne 0 ]]; then + echo "exit status: $RC" + exit $RC + fi ;; 3) echo "=====> make unit-tests (4/4) on CIRCLE_NODE_INDEX: $CIRCLE_NODE_INDEX" sudo -E UNIT_TEST_BATCH=4 make -e unit-tests + RC=$? + if [[ $RC -ne 0 ]]; then + echo "exit status: $RC" + exit $RC + fi ;; esac +end=$(date +%s) +runtime=$((end-start)) +echo "suite runtime: $(date -u -d @${runtime} +"%T")" diff --git a/tests/ci/unit_test_runner.sh b/tests/ci/unit_test_runner.sh index d3f632bd94c..189bf497fa3 100755 --- a/tests/ci/unit_test_runner.sh +++ b/tests/ci/unit_test_runner.sh @@ -19,5 +19,20 @@ is_number "$BATCH_NUM" || usage TESTS=$(find "$(dirname "$0")/../unit" -maxdepth 1 -name "${BATCH_NUM}0*.bats" | sort -n | xargs) echo "running the following tests $TESTS" + # shellcheck disable=SC2086 -bats $TESTS +for test in $TESTS; do + echo $test + starttest=$(date +%s) + + bats $test + RC=$? + if [[ $RC -ne 0 ]]; then + echo "exit status: $RC" + exit $RC + fi + + endtest=$(date +%s) + testruntime=$((endtest-starttest)) + echo "individual runtime: $(date -u -d @${testruntime} +"%T")" +done diff --git a/tests/test_deploy b/tests/test_deploy index 233a17bac00..473f65ba693 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" diff --git a/tests/unit/10_apps.bats b/tests/unit/10_apps.bats index 118bf95610e..cf82872379d 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/30_ps-herokuish.bats b/tests/unit/10_ps-herokuish.bats similarity index 100% rename from tests/unit/30_ps-herokuish.bats rename to tests/unit/10_ps-herokuish.bats diff --git a/tests/unit/10_build-env.bats b/tests/unit/20_build-env.bats similarity index 100% rename from tests/unit/10_build-env.bats rename to tests/unit/20_build-env.bats diff --git a/tests/unit/20_config.bats b/tests/unit/20_config.bats index fed7612d51a..e4afc432b85 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 diff --git a/tests/unit/20_client.bats b/tests/unit/30_client.bats similarity index 99% rename from tests/unit/20_client.bats rename to tests/unit/30_client.bats index 190fb1f4416..c62f1b6a8cb 100644 --- a/tests/unit/20_client.bats +++ b/tests/unit/30_client.bats @@ -34,7 +34,7 @@ teardown() { echo "status: "$status assert_success git remote | grep dokku - run bash -c "${BATS_TEST_DIRNAME}/../../contrib/dokku_client.sh --force apps:destroy" + run bash -c "${BATS_TEST_DIRNAME}/../../contrib/dokku_client.sh apps:destroy --force" echo "output: "$output echo "status: "$status assert_success @@ -49,7 +49,7 @@ teardown() { assert_success git remote | grep dokku git remote -v | grep $test_app_name - run bash -c "${BATS_TEST_DIRNAME}/../../contrib/dokku_client.sh --force apps:destroy" + run bash -c "${BATS_TEST_DIRNAME}/../../contrib/dokku_client.sh apps:destroy --force" echo "output: "$output echo "status: "$status assert_success diff --git a/tests/unit/10_core_1.bats b/tests/unit/30_core_1.bats similarity index 81% rename from tests/unit/10_core_1.bats rename to tests/unit/30_core_1.bats index a1eeef9a7f8..c9eded32876 100644 --- a/tests/unit/10_core_1.bats +++ b/tests/unit/30_core_1.bats @@ -30,12 +30,13 @@ build_nginx_config() { @test "(core) remove exited containers" { deploy_app + # make sure we have many exited containers of the same 'type' - run bash -c "for cnt in 1 2 3; do dokku run $TEST_APP hostname; done" + run bash -c "for cnt in 1 2 3; do dokku run $TEST_APP echo $TEST_APP; done" echo "output: "$output echo "status: "$status assert_success - run bash -c "docker ps -a -f 'status=exited' --no-trunc=false | grep '/exec hostname'" + run bash -c "docker ps -a -f 'status=exited' --no-trunc=true | grep \"/exec echo $TEST_APP\"" echo "output: "$output echo "status: "$status assert_success @@ -45,24 +46,20 @@ build_nginx_config() { assert_success sleep 5 # wait for dokku cleanup to happen in the background - run bash -c "docker ps -a -f 'status=exited' --no-trunc=false | grep '/exec hostname'" + run bash -c "docker ps -a -f 'status=exited' --no-trunc=true | grep \"/exec echo $TEST_APP\"" echo "output: "$output echo "status: "$status assert_failure - run bash -c "docker ps -a -f 'status=exited' -q --no-trunc=false" - echo "output: "$output - echo "status: "$status - assert_output "" } @test "(core) run (with DOKKU_RM_CONTAINER/--rm-container)" { deploy_app - run bash -c "dokku --rm-container run $TEST_APP hostname" + run bash -c "dokku --rm-container run $TEST_APP echo $TEST_APP" echo "output: "$output echo "status: "$status assert_success - run bash -c "docker ps -a -f 'status=exited' --no-trunc=false | grep '/exec hostname'" + run bash -c "docker ps -a -f 'status=exited' --no-trunc=true | grep \"/exec echo $TEST_APP\"" echo "output: "$output echo "status: "$status assert_failure @@ -72,11 +69,11 @@ build_nginx_config() { echo "status: "$status assert_success - run bash -c "dokku --rm-container run $TEST_APP hostname" + run bash -c "dokku --rm-container run $TEST_APP echo $TEST_APP" echo "output: "$output echo "status: "$status assert_success - run bash -c "docker ps -a -f 'status=exited' --no-trunc=false | grep '/exec hostname'" + run bash -c "docker ps -a -f 'status=exited' --no-trunc=true | grep \"/exec echo $TEST_APP\"" echo "output: "$output echo "status: "$status assert_failure @@ -91,11 +88,11 @@ build_nginx_config() { echo "status: "$status assert_success - run bash -c "dokku --rm-container run $TEST_APP hostname" + run bash -c "dokku --rm-container run $TEST_APP echo $TEST_APP" echo "output: "$output echo "status: "$status assert_success - run bash -c "docker ps -a -f 'status=exited' --no-trunc=false | grep '/exec hostname'" + run bash -c "docker ps -a -f 'status=exited' --no-trunc=true | grep \"/exec echo $TEST_APP\"" echo "output: "$output echo "status: "$status assert_failure diff --git a/tests/unit/40_core_2.bats b/tests/unit/40_core_2.bats index 3c0a2ee8fe3..5a6f0f88db4 100644 --- a/tests/unit/40_core_2.bats +++ b/tests/unit/40_core_2.bats @@ -16,8 +16,8 @@ assert_urls() { run dokku urls $TEST_APP echo "output: "$output echo "status: "$status - echo "urls:" $(tr ' ' '\n' <<< "${urls}") - assert_output < <(tr ' ' '\n' <<< "${urls}") + echo "urls:" $(tr ' ' '\n' <<< "${urls}" | sort) + assert_output < <(tr ' ' '\n' <<< "${urls}" | sort) } build_nginx_config() { diff --git a/tests/unit/test_helper.bash b/tests/unit/test_helper.bash index ca61fdc20bf..3fb4bc5cfcc 100644 --- a/tests/unit/test_helper.bash +++ b/tests/unit/test_helper.bash @@ -8,8 +8,9 @@ PLUGIN_AVAILABLE_PATH=${PLUGIN_AVAILABLE_PATH:="$PLUGIN_PATH/available"} PLUGIN_ENABLED_PATH=${PLUGIN_ENABLED_PATH:="$PLUGIN_PATH/enabled"} PLUGIN_CORE_PATH=${PLUGIN_CORE_PATH:="$DOKKU_LIB_ROOT/core-plugins"} PLUGIN_CORE_AVAILABLE_PATH=${PLUGIN_CORE_AVAILABLE_PATH:="$PLUGIN_CORE_PATH/available"} -TEST_APP=testsuiteapp CUSTOM_TEMPLATE_SSL_DOMAIN=customssltemplate.dokku.me +UUID=$(tr -dc 'a-z0-9' < /dev/urandom | fold -w 32 | head -n 1) +TEST_APP="rdmtestapp-${UUID}" # test functions flunk() { @@ -112,17 +113,17 @@ assert_exit_status() { # dokku functions create_app() { - dokku apps:create $TEST_APP + dokku apps:create "$TEST_APP" } destroy_app() { local RC="$1"; local RC=${RC:=0} - dokku --force apps:destroy $TEST_APP + dokku --force apps:destroy "$TEST_APP" return "$RC" } add_domain() { - dokku domains:add $TEST_APP "$1" + dokku domains:add "$TEST_APP" "$1" } # shellcheck disable=SC2119 @@ -213,7 +214,7 @@ setup_client_repo() { setup_test_tls() { local TLS_TYPE="$1"; local TLS="/home/dokku/$TEST_APP/tls" - mkdir -p $TLS + mkdir -p "$TLS" case "$TLS_TYPE" in wildcard) @@ -226,8 +227,8 @@ setup_test_tls() { local TLS_ARCHIVE=server_ssl.tar ;; esac - tar xf "$BATS_TEST_DIRNAME/$TLS_ARCHIVE" -C $TLS - sudo chown -R dokku:dokku ${TLS}/.. + tar xf "$BATS_TEST_DIRNAME/$TLS_ARCHIVE" -C "$TLS" + sudo chown -R dokku:dokku "${TLS}/.." } custom_ssl_nginx_template() {