diff --git a/plugins/builder-herokuish/builder-build b/plugins/builder-herokuish/builder-build index b3b67465f..74d989cc7 100755 --- a/plugins/builder-herokuish/builder-build +++ b/plugins/builder-herokuish/builder-build @@ -47,14 +47,14 @@ trigger-builder-herokuish-builder-build() { plugn trigger pre-build-buildpack "$APP" "$SOURCECODE_WORK_DIR" local DOCKER_ARGS=$(: | plugn trigger docker-args-build "$APP" "$BUILDER_TYPE") - [[ "$DOKKU_TRACE" ]] && DOCKER_ARGS+=" -e TRACE=true " + [[ "$DOKKU_TRACE" ]] && DOCKER_ARGS+=" --env=TRACE=true " DOCKER_ARGS+=$(: | plugn trigger docker-args-process-build "$APP" "$BUILDER_TYPE") declare -a ARG_ARRAY eval "ARG_ARRAY=($DOCKER_ARGS)" local DOKKU_CONTAINER_EXIT_CODE=0 - local CID=$("$DOCKER_BIN" container create "${DOCKER_RUN_LABEL_ARGS[@]}" $DOKKU_GLOBAL_RUN_ARGS -v $DOKKU_APP_HOST_CACHE_DIR:/cache -e CACHE_PATH=/cache "${ARG_ARRAY[@]}" $IMAGE /build) + local CID=$("$DOCKER_BIN" container create "${DOCKER_RUN_LABEL_ARGS[@]}" $DOKKU_GLOBAL_RUN_ARGS -v $DOKKU_APP_HOST_CACHE_DIR:/cache --env=CACHE_PATH=/cache "${ARG_ARRAY[@]}" $IMAGE /build) plugn trigger post-container-create "app" "$CID" "$APP" "build" "$DOCKER_BIN" container start "$CID" >/dev/null || DOKKU_CONTAINER_EXIT_CODE=$? "$DOCKER_BIN" container attach "$CID" diff --git a/plugins/config/docker-args-deploy b/plugins/config/docker-args-deploy index 1f1e53579..c429e3a83 100755 --- a/plugins/config/docker-args-deploy +++ b/plugins/config/docker-args-deploy @@ -14,6 +14,12 @@ trigger-config-docker-args() { STDIN=$(cat) trigger="$0 config_docker_args" + if is_image_cnb_based "$IMAGE"; then + ENV_ARGS="$(config_export app "$APP" --format docker-args-keys --merged)" + echo -n "$STDIN $ENV_ARGS" + return + fi + if ! is_image_herokuish_based "$IMAGE" "$APP"; then ENV_ARGS="$(config_export app "$APP" --format docker-args --merged)" echo -n "$STDIN $ENV_ARGS" diff --git a/plugins/config/environment.go b/plugins/config/environment.go index 23e639eda..2b4602f0b 100644 --- a/plugins/config/environment.go +++ b/plugins/config/environment.go @@ -24,8 +24,10 @@ const ( ExportFormatExports ExportFormat = iota //ExportFormatEnvfile format: dotenv file ExportFormatEnvfile - //ExportFormatDockerArgs format: --env args for docker + //ExportFormatDockerArgs format: --env KEY=VALUE args for docker ExportFormatDockerArgs + //ExportFormatDockerArgsKeys format: --env KEY args for docker + ExportFormatDockerArgsKeys //ExportFormatShell format: env arguments for shell ExportFormatShell //ExportFormatPretty format: pretty-printed in columns @@ -171,6 +173,8 @@ func (e *Env) Export(format ExportFormat) string { return e.EnvfileString() case ExportFormatDockerArgs: return e.DockerArgsString() + case ExportFormatDockerArgsKeys: + return e.DockerArgsKeysString() case ExportFormatShell: return e.ShellString() case ExportFormatPretty: @@ -201,6 +205,16 @@ func (e *Env) DockerArgsString() string { return e.stringWithPrefixAndSeparator("--env=", " ") } +//DockerArgsKeysString gets the contents of this Env in the form -env=KEY --env... +func (e *Env) DockerArgsKeysString() string { + keys := e.Keys() + entries := make([]string, len(keys)) + for i, k := range keys { + entries[i] = fmt.Sprintf("%s%s", "--env=", k) + } + return strings.Join(entries, " ") +} + //JSONString returns the contents of this Env as a key/value json object func (e *Env) JSONString() string { data, err := json.Marshal(e.Map()) diff --git a/plugins/config/environment_test.go b/plugins/config/environment_test.go index 8f87a4a3b..dbe0bf744 100644 --- a/plugins/config/environment_test.go +++ b/plugins/config/environment_test.go @@ -54,6 +54,7 @@ func TestExport(t *testing.T) { e, _ := newEnvFromString("BAR='BAZ'\nFOO='b'ar '\nBAZ='a\\nb'") Expect(e.Export(ExportFormatEnvfile)).To(Equal("BAR=\"BAZ\"\nBAZ=\"a\\nb\"\nFOO=\"b'ar \"")) Expect(e.Export(ExportFormatDockerArgs)).To(Equal("--env=BAR='BAZ' --env=BAZ='a\nb' --env=FOO='b'\\''ar '")) + Expect(e.Export(ExportFormatDockerArgsKeys)).To(Equal("--env=BAR --env=BAZ --env=FOO")) Expect(e.Export(ExportFormatShell)).To(Equal("BAR='BAZ' BAZ='a\nb' FOO='b'\\''ar '")) Expect(e.Export(ExportFormatExports)).To(Equal("export BAR='BAZ'\nexport BAZ='a\nb'\nexport FOO='b'\\''ar '")) Expect(e.Export(ExportFormatPretty)).To(Equal("BAR: BAZ\nBAZ: a\nb\nFOO: b'ar")) diff --git a/plugins/config/src/subcommands/subcommands.go b/plugins/config/src/subcommands/subcommands.go index 0ad64a674..ae543e1ab 100644 --- a/plugins/config/src/subcommands/subcommands.go +++ b/plugins/config/src/subcommands/subcommands.go @@ -49,7 +49,7 @@ func main() { args := flag.NewFlagSet("config:export", flag.ExitOnError) global := args.Bool("global", false, "--global: use the global environment") merged := args.Bool("merged", false, "--merged: merge app environment and global environment") - format := args.String("format", "exports", "--format: [ exports | envfile | docker-args | shell | pretty | json | json-list ] which format to export as)") + format := args.String("format", "exports", "--format: [ exports | envfile | docker-args | docker-args-keys | shell | pretty | json | json-list ] which format to export as)") args.Parse(os.Args[2:]) if !*global { appName = args.Arg(0) diff --git a/plugins/config/subcommands.go b/plugins/config/subcommands.go index 331deb165..fdf30af52 100644 --- a/plugins/config/subcommands.go +++ b/plugins/config/subcommands.go @@ -43,13 +43,14 @@ func CommandExport(appName string, global bool, merged bool, format string) erro suffix := "\n" exportTypes := map[string]ExportFormat{ - "exports": ExportFormatExports, - "envfile": ExportFormatEnvfile, - "docker-args": ExportFormatDockerArgs, - "shell": ExportFormatShell, - "pretty": ExportFormatPretty, - "json": ExportFormatJSON, - "json-list": ExportFormatJSONList, + "exports": ExportFormatExports, + "envfile": ExportFormatEnvfile, + "docker-args": ExportFormatDockerArgs, + "docker-args-keys": ExportFormatDockerArgsKeys, + "shell": ExportFormatShell, + "pretty": ExportFormatPretty, + "json": ExportFormatJSON, + "json-list": ExportFormatJSONList, } exportType, ok := exportTypes[format] diff --git a/plugins/logs/triggers.go b/plugins/logs/triggers.go index fdadb55b7..31c829b50 100644 --- a/plugins/logs/triggers.go +++ b/plugins/logs/triggers.go @@ -49,7 +49,7 @@ func TriggerDockerArgsProcessDeploy(appName string) error { } if maxSize != "unlimited" { - fmt.Printf(" --log-opt max-size=%s ", maxSize) + fmt.Printf(" --log-opt=max-size=%s ", maxSize) } } diff --git a/plugins/scheduler-docker-local/scheduler-deploy b/plugins/scheduler-docker-local/scheduler-deploy index f7dfc6d94..521afc1a8 100755 --- a/plugins/scheduler-docker-local/scheduler-deploy +++ b/plugins/scheduler-docker-local/scheduler-deploy @@ -17,7 +17,7 @@ trigger-scheduler-docker-local-scheduler-deploy() { rm -f "${DOKKU_LIB_ROOT}/data/scheduler-docker-local/$APP/failed-containers" - local DOCKER_RUN_LABEL_ARGS="--label=com.dokku.app-name=$APP" + local DOCKER_RUN_LABEL_ARGS="--label=com.dokku.app-name=$APP --label=com.dokku.container-type=deploy" local DOKKU_DOCKER_STOP_TIMEOUT DOKKU_HEROKUISH DOKKU_NETWORK_BIND_ALL IMAGE DOKKU_HEROKUISH=false IMAGE=$(get_deploying_app_image_name "$APP" "$IMAGE_TAG") @@ -72,43 +72,40 @@ trigger-scheduler-docker-local-scheduler-deploy() { # start the app local DOCKER_ARGS DOCKER_ARGS=$(: | plugn trigger docker-args-deploy "$APP" "$IMAGE_TAG" "$PROC_TYPE" "$CONTAINER_INDEX") - DOCKER_ARGS+=" -e DYNO=$DYNO " + DOCKER_ARGS+=" --label=com.dokku.process-type=$PROC_TYPE --label=com.dokku.dyno=$DYNO " + DOCKER_ARGS+=" --env=DYNO=$DYNO " + DOCKER_ARGS+=" --init " + DOCKER_ARGS+=" $DOCKER_RUN_LABEL_ARGS $DOKKU_GLOBAL_RUN_ARGS " DOCKER_ARGS+=$(: | plugn trigger docker-args-process-deploy "$APP" "$IMAGE_SOURCE_TYPE" "$IMAGE_TAG" "$PROC_TYPE" "$CONTAINER_INDEX") - [[ "$DOKKU_TRACE" ]] && DOCKER_ARGS+=" -e TRACE=true " - - declare -a ARG_ARRAY - eval "ARG_ARRAY=($DOCKER_ARGS)" + [[ "$DOKKU_TRACE" ]] && DOCKER_ARGS+=" --env=TRACE=true " local START_CMD [[ "$DOKKU_HEROKUISH" == "true" ]] && START_CMD="/start $PROC_TYPE" [[ -n "$DOKKU_START_CMD" ]] && START_CMD="$DOKKU_START_CMD" + local DOKKU_PORT="" if [[ "$PROC_TYPE" == "web" ]]; then ports=($(plugn trigger network-compute-ports "$APP" "$PROC_TYPE" "$DOKKU_HEROKUISH" "$CONTAINER_INDEX")) local DOKKU_DOCKER_PORT_ARGS="" - local DOKKU_PORT="" for p in "${ports[@]}"; do if [[ ! "$p" =~ .*udp.* ]]; then DOKKU_PORT=${DOKKU_PORT:="$p"} fi - DOKKU_DOCKER_PORT_ARGS+=" -p $p " + + if [[ "$DOKKU_NETWORK_BIND_ALL" == "true" ]]; then + DOCKER_ARGS+=" -p $p " + fi done - - START_CMD=$(fn-scheduler-docker-local-extract-start-cmd "$APP" "$PROC_TYPE" "$START_CMD" "$DOKKU_HEROKUISH" "$DOKKU_PORT") - if [[ "$DOKKU_NETWORK_BIND_ALL" == "false" ]]; then - # shellcheck disable=SC2086 - cid=$("$DOCKER_BIN" container create --label=com.dokku.container-type=deploy --label=com.dokku.process-type=$PROC_TYPE --label=com.dokku.dyno=$DYNO "${DOCKER_RUN_LABEL_ARGS[@]}" $DOKKU_GLOBAL_RUN_ARGS --init --env PORT=$DOKKU_PORT "${ARG_ARRAY[@]}" $IMAGE $START_CMD) - else - # shellcheck disable=SC2086 - cid=$("$DOCKER_BIN" container create --label=com.dokku.container-type=deploy --label=com.dokku.process-type=$PROC_TYPE --label=com.dokku.dyno=$DYNO "${DOCKER_RUN_LABEL_ARGS[@]}" $DOKKU_GLOBAL_RUN_ARGS --init $DOKKU_DOCKER_PORT_ARGS --env PORT=$DOKKU_PORT "${ARG_ARRAY[@]}" $IMAGE $START_CMD) - fi - else - START_CMD=$(fn-scheduler-docker-local-extract-start-cmd "$APP" "$PROC_TYPE" "$START_CMD" "$DOKKU_HEROKUISH") - - # shellcheck disable=SC2086 - cid=$("$DOCKER_BIN" container create --label=com.dokku.container-type=deploy --label=com.dokku.process-type=$PROC_TYPE --label=com.dokku.dyno=$DYNO "${DOCKER_RUN_LABEL_ARGS[@]}" $DOKKU_GLOBAL_RUN_ARGS --init --env PORT=$DOKKU_PORT "${ARG_ARRAY[@]}" $IMAGE $START_CMD) fi + DOCKER_ARGS+=" --env=PORT=$DOKKU_PORT " + + START_CMD=$(fn-scheduler-docker-local-extract-start-cmd "$APP" "$PROC_TYPE" "$START_CMD" "$DOKKU_HEROKUISH" "$DOKKU_PORT") + DOCKER_ARGS+=" $IMAGE " + DOCKER_ARGS+=" $START_CMD " + + cid=$(fn-start-app-container "$DOCKER_ARGS") + plugn trigger post-container-create "app" "$cid" "$APP" "deploy" "$PROC_TYPE" "$DOCKER_BIN" container start "$cid" >/dev/null || true @@ -219,4 +216,14 @@ fn-scheduler-docker-local-extract-start-cmd() { echo "$START_CMD" } +fn-start-app-container() { + declare desc="starts a single app container" + declare DOCKER_ARGS="$1" + + declare -a __DOKKU_DOCKER_ARG_ARRAY + eval "__DOKKU_DOCKER_ARG_ARRAY=($DOCKER_ARGS)" + eval "$(config_export app "$APP")" + "$DOCKER_BIN" container create "${__DOKKU_DOCKER_ARG_ARRAY[@]}" +} + trigger-scheduler-docker-local-scheduler-deploy "$@" diff --git a/tests/apps/python/web.py b/tests/apps/python/web.py index b3e8ef728..c7c3d36a3 100644 --- a/tests/apps/python/web.py +++ b/tests/apps/python/web.py @@ -1,4 +1,5 @@ import http.server +import json import os @@ -7,7 +8,12 @@ class GetHandler(http.server.BaseHTTPRequestHandler): self.send_response(200) self.send_header("Content-Type", "text/plain; charset=utf-8") self.end_headers() - self.wfile.write("python/http.server".encode("utf-8")) + + if self.path == '/': + self.wfile.write("python/http.server".encode("utf-8")) + else: + data = json.dumps(dict(os.environ), sort_keys=True, indent=4) + self.wfile.write(data.encode("utf-8")) if __name__ == "__main__": diff --git a/tests/unit/docker-options.bats b/tests/unit/docker-options.bats index e5b911b18..4ac48686a 100644 --- a/tests/unit/docker-options.bats +++ b/tests/unit/docker-options.bats @@ -303,9 +303,14 @@ teardown() { echo "output: $output" echo "status: $status" assert_success + run /bin/bash -c "dokku docker-options:add $TEST_APP build \"--link postgres\"" echo "output: $output" echo "status: $status" assert_success - deploy_app dockerfile + + run deploy_app dockerfile + echo "output: $output" + echo "status: $status" + assert_success } diff --git a/tests/unit/logs.bats b/tests/unit/logs.bats index f0ec2747e..70677b00e 100644 --- a/tests/unit/logs.bats +++ b/tests/unit/logs.bats @@ -385,7 +385,7 @@ teardown() { echo "output: $output" echo "status: $status" assert_success - assert_output "--log-opt max-size=20m" + assert_output "--log-opt=max-size=20m" run /bin/bash -c "dokku docker-options:add $TEST_APP deploy --log-driver=local" 2>&1 echo "output: $output" @@ -396,7 +396,7 @@ teardown() { echo "output: $output" echo "status: $status" assert_success - assert_output "--log-opt max-size=20m" + assert_output "--log-opt=max-size=20m" run /bin/bash -c "dokku docker-options:add $TEST_APP deploy --log-driver=json-file" 2>&1 echo "output: $output" @@ -407,7 +407,7 @@ teardown() { echo "output: $output" echo "status: $status" assert_success - assert_output "--log-opt max-size=20m" + assert_output "--log-opt=max-size=20m" run /bin/bash -c "dokku docker-options:add $TEST_APP deploy --log-driver=journald" 2>&1 echo "output: $output" diff --git a/tests/unit/ps-cnb.bats b/tests/unit/ps-cnb.bats new file mode 100644 index 000000000..b7045ee9a --- /dev/null +++ b/tests/unit/ps-cnb.bats @@ -0,0 +1,37 @@ +#!/usr/bin/env bats + +load test_helper + +setup_file() { + add-apt-repository --yes ppa:cncf-buildpacks/pack-cli + apt-get update + apt-get --yes install pack-cli +} + +setup() { + global_setup + create_app +} + +teardown() { + destroy_app + global_teardown +} + +@test "(ps) cnb env vars" { + run /bin/bash -c "dokku config:set $TEST_APP DOKKU_CNB_EXPERIMENTAL=1" + echo "output: $output" + echo "status: $status" + assert_success + + run deploy_app python dokku@dokku.me:$TEST_APP add_requirements_txt + echo "output: $output" + echo "status: $status" + assert_success + + run /bin/bash -c "curl $(dokku url $TEST_APP)/env" + echo "output: $output" + echo "status: $status" + assert_success + assert_output_contains '"DOKKU_CNB_EXPERIMENTAL": "1"' +} diff --git a/tests/unit/ps-herokuish-1.bats b/tests/unit/ps-herokuish-1.bats index c6002ef66..10178ca21 100644 --- a/tests/unit/ps-herokuish-1.bats +++ b/tests/unit/ps-herokuish-1.bats @@ -9,7 +9,6 @@ setup() { teardown() { destroy_app - destroy_app 0 "$MYAPP" || true global_teardown } diff --git a/tests/unit/test_helper.bash b/tests/unit/test_helper.bash index 8d693fd9d..816fa98a4 100644 --- a/tests/unit/test_helper.bash +++ b/tests/unit/test_helper.bash @@ -513,6 +513,13 @@ add_release_command() { echo "release: touch /app/release.test" >> "$APP_REPO_DIR/Procfile" } +add_requirements_txt() { + local APP="$1" + local APP_REPO_DIR="$2" + [[ -z "$APP" ]] && local APP="$TEST_APP" + echo "flask" >> "$APP_REPO_DIR/requirements.txt" +} + build_nginx_config() { # simulate nginx post-deploy dokku domains:setup "$TEST_APP"