From 2b65def1236fc95095cd305713b6b2389b4c1a13 Mon Sep 17 00:00:00 2001 From: Jose Diaz-Gonzalez Date: Mon, 31 Aug 2020 18:36:07 -0400 Subject: [PATCH] fix: pass command directly to entrypoint Closes #3706 --- docs/advanced-usage/deployment-tasks.md | 2 + plugins/app-json/appjson.go | 53 ++++++++++++++------- tests/apps/dockerfile-entrypoint/entrypoint | 9 +++- tests/unit/app-json.bats | 14 ++++++ 4 files changed, 59 insertions(+), 19 deletions(-) diff --git a/docs/advanced-usage/deployment-tasks.md b/docs/advanced-usage/deployment-tasks.md index 5536689cb..44de27596 100644 --- a/docs/advanced-usage/deployment-tasks.md +++ b/docs/advanced-usage/deployment-tasks.md @@ -32,6 +32,8 @@ Each "phase" has different expectations and limitations: - Priming or invalidating cache stores - Running database migrations +Additionally, if using a Dockerfile with an `ENTRYPOINT`, the deployment task is passed to that entrypoint as is. + Please keep the above in mind when utilizing deployment tasks. > To execute commands on the host during a release phase, see the [plugin creation documentation](/docs/development/plugin-creation.md) docs for more information on building your own custom plugin. diff --git a/plugins/app-json/appjson.go b/plugins/app-json/appjson.go index cc5109695..af9174995 100644 --- a/plugins/app-json/appjson.go +++ b/plugins/app-json/appjson.go @@ -22,7 +22,11 @@ type AppJson struct { } `json:"scripts"` } -func constructScript(command string, isHerokuishImage bool) string { +func constructScript(command string, shell string, isHerokuishImage bool, hasEntrypoint bool) []string { + if hasEntrypoint { + return []string{command} + } + script := []string{"set -eo pipefail;"} if os.Getenv("DOKKU_TRACE") == "1" { script = append(script, "set -x;") @@ -65,7 +69,7 @@ func constructScript(command string, isHerokuishImage bool) string { }...) } - return strings.Join(script, " ") + return []string{shell, "-c", strings.Join(script, " ")} } // getPhaseScript extracts app.json from app image and returns the appropriate json key/value @@ -106,7 +110,12 @@ func getPhaseScript(appName string, image string, phase string) (string, error) // getReleaseCommand extracts the release command from a given app's procfile func getReleaseCommand(appName string, image string) string { forceExtract := "true" - if err := common.PlugnTrigger("procfile-extract", []string{appName, image, forceExtract}...); err != nil { + + err := common.SuppressOutput(func() error { + return common.PlugnTrigger("procfile-extract", []string{appName, image, forceExtract}...) + }) + + if err != nil { return "" } @@ -116,6 +125,19 @@ func getReleaseCommand(appName string, image string) string { return strings.TrimSpace(string(b[:])) } +func getDokkuAppShell(appName string) string { + dokkuAppShell := "/bin/bash" + if b, _ := common.PlugnTriggerOutput("config-get-global", []string{"DOKKU_APP_SHELL"}...); strings.TrimSpace(string(b[:])) != "" { + dokkuAppShell = strings.TrimSpace(string(b[:])) + } + + if b, _ := common.PlugnTriggerOutput("config-get", []string{appName, "DOKKU_APP_SHELL"}...); strings.TrimSpace(string(b[:])) != "" { + dokkuAppShell = strings.TrimSpace(string(b[:])) + } + + return dokkuAppShell +} + func executeScript(appName string, imageTag string, phase string) error { image := common.GetDeployingAppImageName(appName, imageTag, "") command := "" @@ -137,7 +159,16 @@ func executeScript(appName string, imageTag string, phase string) error { common.LogInfo1(fmt.Sprintf("Executing %s task from %s: %s", phase, phaseSource, command)) isHerokuishImage := common.IsImageHerokuishBased(image, appName) - script := constructScript(command, isHerokuishImage) + dockerfileEntrypoint := "" + dockerfileCommand := "" + if !isHerokuishImage { + dockerfileEntrypoint, _ = getEntrypointFromImage(image) + dockerfileCommand, _ = getCommandFromImage(image) + } + + hasEntrypoint := dockerfileEntrypoint != "" + dokkuAppShell := getDokkuAppShell(appName) + script := constructScript(command, dokkuAppShell, isHerokuishImage, hasEntrypoint) imageSourceType := "dockerfile" if isHerokuishImage { @@ -189,17 +220,7 @@ func executeScript(appName string, imageTag string, phase string) error { dockerArgs = append(dockerArgs, "--env", "DOKKU_TRACE="+os.Getenv("DOKKU_TRACE")) } - dokkuAppShell := "/bin/bash" - if b, _ := common.PlugnTriggerOutput("config-get-global", []string{"DOKKU_APP_SHELL"}...); strings.TrimSpace(string(b[:])) != "" { - dokkuAppShell = strings.TrimSpace(string(b[:])) - } - - if b, _ := common.PlugnTriggerOutput("config-get", []string{appName, "DOKKU_APP_SHELL"}...); strings.TrimSpace(string(b[:])) != "" { - dokkuAppShell = strings.TrimSpace(string(b[:])) - } - - containerCommand := []string{dokkuAppShell, "-c", script} - containerID, err := createdContainerID(appName, dockerArgs, image, containerCommand, phase) + containerID, err := createdContainerID(appName, dockerArgs, image, script, phase) if err != nil { common.LogFail(fmt.Sprintf("Failed to create %s execution container: %s", phase, err.Error())) } @@ -221,12 +242,10 @@ func executeScript(appName string, imageTag string, phase string) error { commitArgs := []string{"container", "commit"} if !isHerokuishImage { - dockerfileEntrypoint, _ := getEntrypointFromImage(image) if dockerfileEntrypoint != "" { commitArgs = append(commitArgs, "--change", dockerfileEntrypoint) } - dockerfileCommand, _ := getCommandFromImage(image) if dockerfileCommand != "" { commitArgs = append(commitArgs, "--change", dockerfileCommand) } diff --git a/tests/apps/dockerfile-entrypoint/entrypoint b/tests/apps/dockerfile-entrypoint/entrypoint index 9c2c70694..1b4625f4f 100755 --- a/tests/apps/dockerfile-entrypoint/entrypoint +++ b/tests/apps/dockerfile-entrypoint/entrypoint @@ -1,4 +1,9 @@ #!/bin/bash +set -o pipefail -echo "entrypoint script started with arguments $@" -exec "$@" +if [[ "$1" == touch* ]]; then + echo "entrypoint script started with arguments $@" + touch "$(echo $@ | awk '{print $2}')" +else + exec "$@" +fi diff --git a/tests/unit/app-json.bats b/tests/unit/app-json.bats index 5fe2f1a36..1bd0d2f03 100644 --- a/tests/unit/app-json.bats +++ b/tests/unit/app-json.bats @@ -101,3 +101,17 @@ teardown() { assert_output_contains "SECRET_KEY: fjdkslafjdk" assert_success } + +@test "(app-json) app.json dockerfile entrypoint" { + run deploy_app dockerfile-entrypoint + echo "output: $output" + echo "status: $status" + assert_output_contains "Executing predeploy task from app.json" + assert_output_contains "entrypoint script started with arguments touch /app/predeploy.test" + assert_success + + run /bin/bash -c "dokku --rm run $TEST_APP ls /app/predeploy.test" + echo "output: $output" + echo "status: $status" + assert_success +}