diff --git a/plugins/00_dokku-standard/subcommands/cleanup b/plugins/00_dokku-standard/subcommands/cleanup index 42918a2b4..c73eaebdc 100755 --- a/plugins/00_dokku-standard/subcommands/cleanup +++ b/plugins/00_dokku-standard/subcommands/cleanup @@ -13,6 +13,8 @@ cmd-cleanup() { APP="--global" fi + [[ "$APP" == "--global" ]] || verify_app_name "$APP" + docker_cleanup "$APP" "true" } diff --git a/plugins/caddy-vhosts/subcommands/set b/plugins/caddy-vhosts/subcommands/set index 16238acee..f62fb660a 100755 --- a/plugins/caddy-vhosts/subcommands/set +++ b/plugins/caddy-vhosts/subcommands/set @@ -19,17 +19,16 @@ cmd-caddy-set() { dokku_log_fail "Invalid key specified, valid keys include: image letsencrypt-email letsencrypt-server log-level polling-interval tls-internal" fi - if ! fn-in-array "$KEY" "${GLOBAL_KEYS[@]}"; then - if [[ "$APP" == "--global" ]]; then - dokku_log_fail "The key '$KEY' cannot be set globally" - fi - verify_app_name "$APP" + if ! fn-in-array "$KEY" "${GLOBAL_KEYS[@]}" && [[ "$APP" == "--global" ]]; then + dokku_log_fail "The key '$KEY' cannot be set globally" fi if fn-in-array "$KEY" "${GLOBAL_ONLY_KEYS[@]}" && [[ "$APP" != "--global" ]]; then dokku_log_fail "The key '$KEY' can only be set globally" fi + [[ "$APP" == "--global" ]] || verify_app_name "$APP" + if [[ -n "$VALUE" ]]; then dokku_log_info2_quiet "Setting ${KEY} to ${VALUE}" fn-plugin-property-write "caddy" "$APP" "$KEY" "$VALUE" diff --git a/plugins/domains/subcommands/disable b/plugins/domains/subcommands/disable index 69b14b528..30baf3a32 100755 --- a/plugins/domains/subcommands/disable +++ b/plugins/domains/subcommands/disable @@ -10,7 +10,7 @@ cmd-domains-disable() { [[ "$1" == "$cmd" ]] && shift 1 declare APP="$1" - [[ "$APP" == "--all" ]] && verify_app_name "$APP" + [[ "$APP" == "--all" ]] || verify_app_name "$APP" fn-domains-disable "$APP" } diff --git a/plugins/domains/subcommands/enable b/plugins/domains/subcommands/enable index d996db25a..466d3c58a 100755 --- a/plugins/domains/subcommands/enable +++ b/plugins/domains/subcommands/enable @@ -10,7 +10,7 @@ cmd-domains-enable() { [[ "$1" == "$cmd" ]] && shift 1 declare APP="$1" - [[ "$APP" == "--all" ]] && verify_app_name "$APP" + [[ "$APP" == "--all" ]] || verify_app_name "$APP" fn-domains-enable "$APP" } diff --git a/plugins/haproxy-vhosts/subcommands/set b/plugins/haproxy-vhosts/subcommands/set index 3dafa0dc4..e3a800e74 100755 --- a/plugins/haproxy-vhosts/subcommands/set +++ b/plugins/haproxy-vhosts/subcommands/set @@ -19,17 +19,16 @@ cmd-haproxy-set() { dokku_log_fail "Invalid key specified, valid keys include: image log-level letsencrypt-email letsencrypt-server refresh-conf" fi - if ! fn-in-array "$KEY" "${GLOBAL_KEYS[@]}"; then - if [[ "$APP" == "--global" ]]; then - dokku_log_fail "The key '$KEY' cannot be set globally" - fi - verify_app_name "$APP" + if ! fn-in-array "$KEY" "${GLOBAL_KEYS[@]}" && [[ "$APP" == "--global" ]]; then + dokku_log_fail "The key '$KEY' cannot be set globally" fi if fn-in-array "$KEY" "${GLOBAL_ONLY_KEYS[@]}" && [[ "$APP" != "--global" ]]; then dokku_log_fail "The key '$KEY' can only be set globally" fi + [[ "$APP" == "--global" ]] || verify_app_name "$APP" + if [[ -n "$VALUE" ]]; then dokku_log_info2_quiet "Setting ${KEY} to ${VALUE}" fn-plugin-property-write "haproxy" "$APP" "$KEY" "$VALUE" diff --git a/plugins/network/src/subcommands/subcommands.go b/plugins/network/src/subcommands/subcommands.go index 83fe37f98..278fec0ee 100644 --- a/plugins/network/src/subcommands/subcommands.go +++ b/plugins/network/src/subcommands/subcommands.go @@ -50,7 +50,7 @@ func main() { args := flag.NewFlagSet("network:rebuild", flag.ExitOnError) args.Parse(os.Args[2:]) appName := args.Arg(0) - err = network.BuildConfig(appName) + err = network.CommandRebuild(appName) case "rebuildall": args := flag.NewFlagSet("network:rebuildall", flag.ExitOnError) args.Parse(os.Args[2:]) diff --git a/plugins/network/subcommands.go b/plugins/network/subcommands.go index 3c28e15dd..86545bddc 100644 --- a/plugins/network/subcommands.go +++ b/plugins/network/subcommands.go @@ -148,6 +148,15 @@ func CommandList(format string, dokkuManaged bool) error { return nil } +// CommandRebuild rebuilds network settings for an app +func CommandRebuild(appName string) error { + if err := common.VerifyAppName(appName); err != nil { + return err + } + + return BuildConfig(appName) +} + // CommandRebuildall rebuilds network settings for all apps func CommandRebuildall() error { apps, err := common.DokkuApps() diff --git a/plugins/nginx-vhosts/functions b/plugins/nginx-vhosts/functions index a4e670fc4..abd3da343 100755 --- a/plugins/nginx-vhosts/functions +++ b/plugins/nginx-vhosts/functions @@ -37,7 +37,7 @@ validate_nginx() { verify_app_name "$APP" nginx_vhosts_validate_single_func "$APP" "$FLAG" else - for app in $(dokku_apps "false"); do + for app in $(dokku_apps); do nginx_vhosts_validate_single_func "$app" "$FLAG" done fi diff --git a/plugins/nginx-vhosts/subcommands/set b/plugins/nginx-vhosts/subcommands/set index e3118c4c7..27e85855b 100755 --- a/plugins/nginx-vhosts/subcommands/set +++ b/plugins/nginx-vhosts/subcommands/set @@ -18,13 +18,12 @@ cmd-nginx-set() { dokku_log_fail "Invalid key specified, valid keys include: access-log-format, access-log-path, bind-address-ipv4, bind-address-ipv6, client-body-timeout, client-header-timeout, client-max-body-size, disable-custom-config, error-log-path, hsts, hsts-include-subdomains, hsts-preload, hsts-max-age, keepalive-timeout, lingering-timeout, nginx-conf-sigil-path, nginx-service-command, proxy-buffer-size, proxy-buffering, proxy-buffers, proxy-busy-buffers-size, proxy-connect-timeout, proxy-read-timeout, proxy-send-timeout, proxy-keepalive, send-timeout, underscore-in-headers, x-forwarded-for-value, x-forwarded-port-value, x-forwarded-proto-value, x-forwarded-ssl" fi - if ! fn-in-array "$KEY" "${GLOBAL_KEYS[@]}"; then - if [[ "$APP" == "--global" ]]; then - dokku_log_fail "The key '$KEY' cannot be set globally" - fi - verify_app_name "$APP" + if ! fn-in-array "$KEY" "${GLOBAL_KEYS[@]}" && [[ "$APP" == "--global" ]]; then + dokku_log_fail "The key '$KEY' cannot be set globally" fi + [[ "$APP" == "--global" ]] || verify_app_name "$APP" + if [[ "$KEY" == "proxy-keepalive" ]] && [[ -n "$VALUE" ]]; then if ! is_number "$VALUE"; then dokku_log_fail "Invalid value for proxy-keepalive: must be an integer" diff --git a/plugins/openresty-vhosts/subcommands/set b/plugins/openresty-vhosts/subcommands/set index 8fc21a322..1a9142f4e 100755 --- a/plugins/openresty-vhosts/subcommands/set +++ b/plugins/openresty-vhosts/subcommands/set @@ -19,17 +19,16 @@ cmd-openresty-set() { dokku_log_fail "Invalid key specified, valid keys include: access-log-format, access-log-path, allowed-letsencrypt-domains-func-base64, bind-address-ipv4, bind-address-ipv6, client-body-timeout, client-header-timeout, client-max-body-size, error-log-path, hsts, hsts-include-subdomains, hsts-preload, hsts-max-age, image, keepalive-timeout, log-level, letsencrypt-email, letsencrypt-server, lingering-timeout, proxy-connect-timeout, proxy-connect-timeout, proxy-read-timeout, proxy-send-timeout, send-timeout, underscore-in-headers, x-forwarded-for-value, x-forwarded-port-value, x-forwarded-proto-value, x-forwarded-ssl" fi - if ! fn-in-array "$KEY" "${GLOBAL_KEYS[@]}"; then - if [[ "$APP" == "--global" ]]; then - dokku_log_fail "The key '$KEY' cannot be set globally" - fi - verify_app_name "$APP" + if ! fn-in-array "$KEY" "${GLOBAL_KEYS[@]}" && [[ "$APP" == "--global" ]]; then + dokku_log_fail "The key '$KEY' cannot be set globally" fi if fn-in-array "$KEY" "${GLOBAL_ONLY_KEYS[@]}" && [[ "$APP" != "--global" ]]; then dokku_log_fail "The key '$KEY' can only be set globally" fi + [[ "$APP" == "--global" ]] || verify_app_name "$APP" + if [[ -n "$VALUE" ]]; then dokku_log_info2_quiet "Setting ${KEY} to ${VALUE}" fn-plugin-property-write "openresty" "$APP" "$KEY" "$VALUE" diff --git a/plugins/ps/subcommands.go b/plugins/ps/subcommands.go index 6c726158a..be8d91e41 100644 --- a/plugins/ps/subcommands.go +++ b/plugins/ps/subcommands.go @@ -121,6 +121,9 @@ func CommandRetire(appName string) error { if appName == "" { scheduler = common.GetGlobalScheduler() } else { + if err := common.VerifyAppName(appName); err != nil { + return err + } scheduler = common.GetAppScheduler(appName) } diff --git a/plugins/run/internal-functions b/plugins/run/internal-functions index 2a15e60ef..35c2b81d1 100755 --- a/plugins/run/internal-functions +++ b/plugins/run/internal-functions @@ -269,6 +269,19 @@ cmd-run-stop() { esac done + if [[ -n "$CONTAINER_NAME" ]]; then + local CONTAINER_APP="$(echo "$CONTAINER_NAME" | cut -d'.' -f1)" + if [[ -n "$APP" ]] && [[ "$APP" != "$CONTAINER_APP" ]]; then + dokku_log_fail "Specified app does not match app in container name" + fi + APP="$CONTAINER_APP" + fi + + if [[ -z "$APP" ]]; then + dokku_log_fail "No container or app specified" + fi + + verify_app_name "$APP" local DOKKU_SCHEDULER=$(get_app_scheduler "$APP") plugn trigger scheduler-run-stop "$DOKKU_SCHEDULER" "$APP" "$CONTAINER_NAME" } diff --git a/plugins/scheduler-docker-local/scheduler-run-stop b/plugins/scheduler-docker-local/scheduler-run-stop index 6eb6eb7e9..0fc24d3e8 100755 --- a/plugins/scheduler-docker-local/scheduler-run-stop +++ b/plugins/scheduler-docker-local/scheduler-run-stop @@ -25,6 +25,21 @@ fn-scheduler-docker-local-stop-container() { return 1 } +fn-scheduler-docker-local-stop-app-run-container() { + declare desc="stops a named run container belonging to an app" + declare APP="$1" CONTAINER_NAME="$2" DOCKER_STOP_TIMEOUT="$3" + local NAME + + while IFS= read -r NAME; do + if [[ "$NAME" == "$CONTAINER_NAME" ]]; then + fn-scheduler-docker-local-stop-container "$CONTAINER_NAME" "$DOCKER_STOP_TIMEOUT" + return $? + fi + done < <("$DOCKER_BIN" container ls --filter "label=com.dokku.app-name=$APP" --filter "label=com.dokku.container-type=run" --format '{{ .Names }}') + + dokku_log_warn "Specified container does not exist" +} + trigger-scheduler-docker-local-scheduler-run-stop() { declare desc="stops an app run container" declare trigger="scheduler-run-stop" @@ -34,15 +49,21 @@ trigger-scheduler-docker-local-scheduler-run-stop() { return fi - if [[ -z "$APP" ]]; then - if [[ -z "$CONTAINER_NAME" ]]; then - dokku_log_fail "No container or app specified" - fi + if [[ -z "$APP" ]] && [[ -z "$CONTAINER_NAME" ]]; then + dokku_log_fail "No container or app specified" + fi + + if [[ -n "$CONTAINER_NAME" ]]; then if [[ "$(echo "$CONTAINER_NAME" | grep -o '\.' | wc -l)" -ne 2 ]]; then dokku_log_fail "Invalid container name specified: $CONTAINER_NAME" fi - APP="$(echo "$CONTAINER_NAME" | cut -d'.' -f1)" + local CONTAINER_APP="$(echo "$CONTAINER_NAME" | cut -d'.' -f1)" + if [[ -n "$APP" ]] && [[ "$APP" != "$CONTAINER_APP" ]]; then + dokku_log_fail "Specified app does not match app in container name" + fi + + APP="$CONTAINER_APP" STATE="$(echo "$CONTAINER_NAME" | cut -d'.' -f2)" if [[ "$STATE" != "run" ]]; then dokku_log_fail "Specified container must be a run container" @@ -53,7 +74,7 @@ trigger-scheduler-docker-local-scheduler-run-stop() { DOKKU_DOCKER_STOP_TIMEOUT="$(plugn trigger ps-get-property "$APP" stop-timeout-seconds || true)" if [[ -n "$CONTAINER_NAME" ]]; then - fn-scheduler-docker-local-stop-container "$CONTAINER_NAME" "$DOKKU_DOCKER_STOP_TIMEOUT" + fn-scheduler-docker-local-stop-app-run-container "$APP" "$CONTAINER_NAME" "$DOKKU_DOCKER_STOP_TIMEOUT" return $? fi diff --git a/plugins/traefik-vhosts/subcommands/set b/plugins/traefik-vhosts/subcommands/set index 247ab1222..f1f6513c9 100755 --- a/plugins/traefik-vhosts/subcommands/set +++ b/plugins/traefik-vhosts/subcommands/set @@ -25,11 +25,8 @@ cmd-traefik-set() { dokku_log_fail "Invalid key specified, valid keys include: api-enabled api-entry-point api-entry-point-address api-vhost challenge-mode dashboard-enabled basic-auth-username basic-auth-password dns-provider dns-provider- image letsencrypt-email letsencrypt-server log-level http-entry-point https-entry-point" fi - if ! fn-in-array "$KEY" "${GLOBAL_KEYS[@]}" && [[ "$is_dns_provider_env_var" != "true" ]]; then - if [[ "$APP" == "--global" ]]; then - dokku_log_fail "The key '$KEY' cannot be set globally" - fi - verify_app_name "$APP" + if ! fn-in-array "$KEY" "${GLOBAL_KEYS[@]}" && [[ "$is_dns_provider_env_var" != "true" ]] && [[ "$APP" == "--global" ]]; then + dokku_log_fail "The key '$KEY' cannot be set globally" fi # dns-provider-* keys and GLOBAL_ONLY_KEYS can only be set globally @@ -41,6 +38,8 @@ cmd-traefik-set() { dokku_log_fail "The key '$KEY' can only be set globally" fi + [[ "$APP" == "--global" ]] || verify_app_name "$APP" + if [[ -n "$VALUE" ]]; then dokku_log_info2_quiet "Setting ${KEY} to ${VALUE}" fn-plugin-property-write "traefik" "$APP" "$KEY" "$VALUE" diff --git a/tests/unit/caddy-vhosts.bats b/tests/unit/caddy-vhosts.bats index 1c3180359..f65832d44 100644 --- a/tests/unit/caddy-vhosts.bats +++ b/tests/unit/caddy-vhosts.bats @@ -82,3 +82,16 @@ teardown() { assert_success assert_output "false" } + +@test "(caddy:set) missing app" { + run /bin/bash -c "dokku caddy:set missing-app tls-internal true" + echo "output: $output" + echo "status: $status" + assert_failure + assert_output_contains "App missing-app does not exist" + + run /bin/bash -c "test -e $DOKKU_LIB_ROOT/config/caddy/missing-app" + echo "output: $output" + echo "status: $status" + assert_failure +} diff --git a/tests/unit/core_1.bats b/tests/unit/core_1.bats index 11cacfdca..c27db95c6 100644 --- a/tests/unit/core_1.bats +++ b/tests/unit/core_1.bats @@ -194,3 +194,11 @@ teardown() { assert_success assert_output "--label=a=b" } + +@test "(core) cleanup missing app" { + run /bin/bash -c "dokku cleanup missing-app" + echo "output: $output" + echo "status: $status" + assert_failure + assert_output_contains "App missing-app does not exist" +} diff --git a/tests/unit/domains.bats b/tests/unit/domains.bats index 005973044..bbf965fb2 100644 --- a/tests/unit/domains.bats +++ b/tests/unit/domains.bats @@ -136,6 +136,20 @@ teardown() { assert_failure } +@test "(domains) domains:enable and domains:disable (missing app)" { + run /bin/bash -c "dokku domains:disable missing-app" + echo "output: $output" + echo "status: $status" + assert_failure + assert_output_contains "App missing-app does not exist" + + run /bin/bash -c "dokku domains:enable missing-app" + echo "output: $output" + echo "status: $status" + assert_failure + assert_output_contains "App missing-app does not exist" +} + @test "(domains) domains:remove" { run /bin/bash -c "dokku domains:add $TEST_APP test.app.${DOKKU_DOMAIN}" echo "output: $output" diff --git a/tests/unit/network.bats b/tests/unit/network.bats index 449eefacc..b95576ef7 100644 --- a/tests/unit/network.bats +++ b/tests/unit/network.bats @@ -698,3 +698,16 @@ teardown() { assert_output_contains "Attempting pre-flight checks" 0 assert_output_contains "Application deployed" } + +@test "(network:rebuild) missing app" { + run /bin/bash -c "dokku network:rebuild missing-app" + echo "output: $output" + echo "status: $status" + assert_failure + assert_output_contains "App missing-app does not exist" + + run /bin/bash -c "test -e $DOKKU_LIB_ROOT/config/common/missing-app" + echo "output: $output" + echo "status: $status" + assert_failure +} diff --git a/tests/unit/nginx-vhosts_properties.bats b/tests/unit/nginx-vhosts_properties.bats index 586908eec..db6792b21 100644 --- a/tests/unit/nginx-vhosts_properties.bats +++ b/tests/unit/nginx-vhosts_properties.bats @@ -107,3 +107,16 @@ assert_nginx_property_set_get() { assert_nginx_property_set_get "nginx-conf-sigil-path" "custom.sigil" "global.sigil" assert_nginx_property_set_get "nginx-service-command" "/usr/sbin/nginx-app" "/usr/sbin/nginx-global" } + +@test "(nginx:set) missing app" { + run /bin/bash -c "dokku nginx:set missing-app hsts false" + echo "output: $output" + echo "status: $status" + assert_failure + assert_output_contains "App missing-app does not exist" + + run /bin/bash -c "test -e $DOKKU_LIB_ROOT/config/nginx/missing-app" + echo "output: $output" + echo "status: $status" + assert_failure +} diff --git a/tests/unit/openresty-vhosts.bats b/tests/unit/openresty-vhosts.bats index 916edcf8a..e82ec5fa3 100644 --- a/tests/unit/openresty-vhosts.bats +++ b/tests/unit/openresty-vhosts.bats @@ -82,3 +82,16 @@ teardown() { assert_success assert_output "5m" } + +@test "(openresty:set) missing app" { + run /bin/bash -c "dokku openresty:set missing-app client-max-body-size 5m" + echo "output: $output" + echo "status: $status" + assert_failure + assert_output_contains "App missing-app does not exist" + + run /bin/bash -c "test -e $DOKKU_LIB_ROOT/config/openresty/missing-app" + echo "output: $output" + echo "status: $status" + assert_failure +} diff --git a/tests/unit/ps-general-3.bats b/tests/unit/ps-general-3.bats index 63984274b..475a1d6b5 100644 --- a/tests/unit/ps-general-3.bats +++ b/tests/unit/ps-general-3.bats @@ -92,3 +92,11 @@ teardown() { echo "status: $status" assert_output "console: 0" } + +@test "(ps:retire) missing app" { + run /bin/bash -c "dokku ps:retire missing-app" + echo "output: $output" + echo "status: $status" + assert_failure + assert_output_contains "App missing-app does not exist" +} diff --git a/tests/unit/run_2.bats b/tests/unit/run_2.bats index 0dc6203b9..9d07b6075 100644 --- a/tests/unit/run_2.bats +++ b/tests/unit/run_2.bats @@ -8,6 +8,7 @@ setup() { } teardown() { + docker container rm -f "$TEST_APP.run.9999" >/dev/null 2>&1 || true destroy_app global_teardown } @@ -157,6 +158,58 @@ teardown() { assert_output "2" } +@test "(run:stop) only stops run containers for the app" { + run deploy_app + echo "output: $output" + echo "status: $status" + assert_success + + run /bin/bash -c "dokku run:detached $TEST_APP sleep 300" + echo "output: $output" + echo "status: $status" + assert_success + + run /bin/bash -c "dokku run:list $TEST_APP --format json | jq -r '.[0].name'" + echo "output: $output" + echo "status: $status" + assert_success + local RUN_CONTAINER="$output" + + run /bin/bash -c "docker container run -d --name $TEST_APP.run.9999 --entrypoint sleep dokku/$TEST_APP:latest 300" + echo "output: $output" + echo "status: $status" + assert_success + + run /bin/bash -c "dokku run:stop $TEST_APP --container other-app.run.1" + echo "output: $output" + echo "status: $status" + assert_failure + assert_output_contains "Specified app does not match app in container name" + + run /bin/bash -c "dokku run:stop $TEST_APP --container $TEST_APP.run.9999" + echo "output: $output" + echo "status: $status" + assert_success + assert_output_contains "Specified container does not exist" + + run /bin/bash -c "docker container inspect -f '{{.State.Running}}' $TEST_APP.run.9999" + echo "output: $output" + echo "status: $status" + assert_success + assert_output "true" + + run /bin/bash -c "dokku run:stop $TEST_APP --container $RUN_CONTAINER" + echo "output: $output" + echo "status: $status" + assert_success + + run /bin/bash -c "docker container ls -q --filter name=^/$RUN_CONTAINER\$ | wc -l" + echo "output: $output" + echo "status: $status" + assert_success + assert_output "0" +} + @test "(run) docker-options and -e flags are not eval-injected" { run deploy_app echo "output: $output"