From 6ce10b5be65b42ddbb8950a9f137e820809d7fd5 Mon Sep 17 00:00:00 2001 From: Jose Diaz-Gonzalez Date: Sat, 24 May 2025 23:31:34 -0400 Subject: [PATCH] fix: ensure compose projects are spawned from the /tmp directory A recent update to compose executes a stat call in the current working directory, which may have incorrect permissions for execution once the user is changed to the dokku user. This change forces all compose commands to execute in the /tmp directory by using a helper function to execute compose up/down. Closes #7705 --- plugins/caddy-vhosts/command-functions | 8 ++- plugins/common/docker.go | 57 ++++++++++++++++++++++ plugins/common/exec.go | 7 +++ plugins/common/src/common/common.go | 14 ++++++ plugins/haproxy-vhosts/command-functions | 8 ++- plugins/logs/functions.go | 37 +++----------- plugins/openresty-vhosts/command-functions | 8 ++- plugins/traefik-vhosts/command-functions | 8 ++- 8 files changed, 108 insertions(+), 39 deletions(-) diff --git a/plugins/caddy-vhosts/command-functions b/plugins/caddy-vhosts/command-functions index 226ffd300..1f04357ff 100755 --- a/plugins/caddy-vhosts/command-functions +++ b/plugins/caddy-vhosts/command-functions @@ -133,7 +133,9 @@ cmd-caddy-start() { fn-plugin-property-write "caddy" "--global" "proxy-status" "started" fn-caddy-template-compose-file "$TMP_COMPOSE_FILE" - "$DOCKER_BIN" compose -f "$TMP_COMPOSE_FILE" -p caddy up -d --quiet-pull + if ! "$PLUGIN_CORE_AVAILABLE_PATH/common/common" compose-up "caddy" "$TMP_COMPOSE_FILE"; then + return 1 + fi } cmd-caddy-stop() { @@ -150,5 +152,7 @@ cmd-caddy-stop() { fn-plugin-property-write "caddy" "--global" "proxy-status" "stopped" fn-caddy-template-compose-file "$TMP_COMPOSE_FILE" - "$DOCKER_BIN" compose -f "$TMP_COMPOSE_FILE" -p caddy down --remove-orphans + if ! "$PLUGIN_CORE_AVAILABLE_PATH/common/common" compose-down "caddy" "$TMP_COMPOSE_FILE"; then + return 1 + fi } diff --git a/plugins/common/docker.go b/plugins/common/docker.go index 25740a5d1..bf3cef0cd 100644 --- a/plugins/common/docker.go +++ b/plugins/common/docker.go @@ -11,6 +11,63 @@ import ( "time" ) +// ComposeUpInput is the input for the ComposeUp function +type ComposeUpInput struct { + ProjectName string + ComposeFile string +} + +// ComposeUp executes a docker compose up command +func ComposeUp(input ComposeUpInput) error { + result, err := CallExecCommand(ExecCommandInput{ + Command: DockerBin(), + Args: []string{ + "compose", + "--file", input.ComposeFile, + "--project-name", input.ProjectName, + "up", + "--detach", + "--quiet-pull", + }, + StreamStdio: true, + WorkingDirectory: "/tmp", + }) + + if err != nil || result.ExitCode != 0 { + return fmt.Errorf("Unable to start compose project: %s", result.Stderr) + } + + return nil +} + +// ComposeDownInput is the input for the ComposeDown function +type ComposeDownInput struct { + ProjectName string + ComposeFile string +} + +// ComposeDown executes a docker compose down command +func ComposeDown(input ComposeDownInput) error { + result, err := CallExecCommand(ExecCommandInput{ + Command: DockerBin(), + Args: []string{ + "compose", + "--file", input.ComposeFile, + "--project-name", input.ProjectName, + "down", + "--remove-orphans", + }, + StreamStdio: true, + WorkingDirectory: "/tmp", + }) + + if err != nil || result.ExitCode != 0 { + return fmt.Errorf("Unable to stop %s: %s", input.ProjectName, result.Stderr) + } + + return nil +} + // ContainerIsRunning checks to see if a container is running func ContainerIsRunning(containerID string) bool { b, err := DockerInspect(containerID, "'{{.State.Running}}'") diff --git a/plugins/common/exec.go b/plugins/common/exec.go index c8471cc6f..c5790ba6e 100644 --- a/plugins/common/exec.go +++ b/plugins/common/exec.go @@ -50,6 +50,9 @@ type ExecCommandInput struct { // Sudo runs the command with sudo -n -u root Sudo bool + + // WorkingDirectory is the working directory to run the command in + WorkingDirectory string } // ExecCommandResponse is the response for the ExecCommand function @@ -134,6 +137,10 @@ func CallExecCommandWithContext(ctx context.Context, input ExecCommandInput) (Ex DisableStdioBuffer: input.DisableStdioBuffer, } + if input.WorkingDirectory != "" { + cmd.Cwd = input.WorkingDirectory + } + if os.Getenv("DOKKU_TRACE") == "1" { argsSt := "" if len(cmd.Args) > 0 { diff --git a/plugins/common/src/common/common.go b/plugins/common/src/common/common.go index 2862536e9..7d59e39d4 100644 --- a/plugins/common/src/common/common.go +++ b/plugins/common/src/common/common.go @@ -20,6 +20,20 @@ func main() { var err error switch cmd { + case "compose-up": + projectName := flag.Arg(1) + composeFile := flag.Arg(2) + err = common.ComposeUp(common.ComposeUpInput{ + ProjectName: projectName, + ComposeFile: composeFile, + }) + case "compose-down": + projectName := flag.Arg(1) + composeFile := flag.Arg(2) + err = common.ComposeDown(common.ComposeDownInput{ + ProjectName: projectName, + ComposeFile: composeFile, + }) case "copy-from-image": appName := flag.Arg(1) image := flag.Arg(2) diff --git a/plugins/haproxy-vhosts/command-functions b/plugins/haproxy-vhosts/command-functions index a27a31a13..481a6a682 100755 --- a/plugins/haproxy-vhosts/command-functions +++ b/plugins/haproxy-vhosts/command-functions @@ -131,7 +131,9 @@ cmd-haproxy-start() { fn-plugin-property-write "haproxy" "--global" "proxy-status" "started" fn-haproxy-template-compose-file "$TMP_COMPOSE_FILE" - "$DOCKER_BIN" compose -f "$TMP_COMPOSE_FILE" -p haproxy up -d --quiet-pull + if ! "$PLUGIN_CORE_AVAILABLE_PATH/common/common" compose-up "haproxy" "$TMP_COMPOSE_FILE"; then + return 1 + fi } cmd-haproxy-stop() { @@ -148,5 +150,7 @@ cmd-haproxy-stop() { fn-plugin-property-write "haproxy" "--global" "proxy-status" "stopped" fn-haproxy-template-compose-file "$TMP_COMPOSE_FILE" - "$DOCKER_BIN" compose -f "$TMP_COMPOSE_FILE" -p haproxy down --remove-orphans + if ! "$PLUGIN_CORE_AVAILABLE_PATH/common/common" compose-down "haproxy" "$TMP_COMPOSE_FILE"; then + return 1 + fi } diff --git a/plugins/logs/functions.go b/plugins/logs/functions.go index 8908feecc..f091d4939 100644 --- a/plugins/logs/functions.go +++ b/plugins/logs/functions.go @@ -98,23 +98,10 @@ func startVectorContainer(vectorImage string) error { return fmt.Errorf("Unable to execute compose template: %s", err) } - result, err := common.CallExecCommand(common.ExecCommandInput{ - Command: common.DockerBin(), - Args: []string{ - "compose", - "--file", tmpFile.Name(), - "--project-name", "vector", - "up", - "--detach", - "--quiet-pull", - }, - StreamStdio: true, + return common.ComposeUp(common.ComposeUpInput{ + ProjectName: "vector", + ComposeFile: tmpFile.Name(), }) - if err != nil || result.ExitCode != 0 { - return fmt.Errorf("Unable to start vector container: %s", result.Stderr) - } - - return nil } func getComputedVectorImage() string { @@ -173,22 +160,10 @@ func stopVectorContainer() error { return fmt.Errorf("Unable to execute compose template: %s", err) } - result, err := common.CallExecCommand(common.ExecCommandInput{ - Command: common.DockerBin(), - Args: []string{ - "compose", - "--file", tmpFile.Name(), - "--project-name", "vector", - "down", - "--remove-orphans", - }, - StreamStdio: true, + return common.ComposeDown(common.ComposeDownInput{ + ProjectName: "vector", + ComposeFile: tmpFile.Name(), }) - if err != nil || result.ExitCode != 0 { - return fmt.Errorf("Unable to stop vector container: %s", result.Stderr) - } - - return nil } func writeVectorConfig() error { diff --git a/plugins/openresty-vhosts/command-functions b/plugins/openresty-vhosts/command-functions index 86fc56f11..926839ff4 100755 --- a/plugins/openresty-vhosts/command-functions +++ b/plugins/openresty-vhosts/command-functions @@ -160,7 +160,9 @@ cmd-openresty-start() { fn-plugin-property-write "openresty" "--global" "proxy-status" "started" fn-openresty-template-compose-file "$TMP_COMPOSE_FILE" - "$DOCKER_BIN" compose -f "$TMP_COMPOSE_FILE" -p openresty up -d --quiet-pull + if ! "$PLUGIN_CORE_AVAILABLE_PATH/common/common" compose-up "openresty" "$TMP_COMPOSE_FILE"; then + return 1 + fi } cmd-openresty-stop() { @@ -177,5 +179,7 @@ cmd-openresty-stop() { fn-plugin-property-write "openresty" "--global" "proxy-status" "stopped" fn-openresty-template-compose-file "$TMP_COMPOSE_FILE" - "$DOCKER_BIN" compose -f "$TMP_COMPOSE_FILE" -p openresty down --remove-orphans + if ! "$PLUGIN_CORE_AVAILABLE_PATH/common/common" compose-down "openresty" "$TMP_COMPOSE_FILE"; then + return 1 + fi } diff --git a/plugins/traefik-vhosts/command-functions b/plugins/traefik-vhosts/command-functions index dcc522b44..93f5429d5 100755 --- a/plugins/traefik-vhosts/command-functions +++ b/plugins/traefik-vhosts/command-functions @@ -140,7 +140,9 @@ cmd-traefik-start() { touch "${DOKKU_LIB_ROOT}/data/traefik/traefik-acme.json" chmod 600 "${DOKKU_LIB_ROOT}/data/traefik/traefik-acme.json" fn-traefik-template-compose-file "$TMP_COMPOSE_FILE" - "$DOCKER_BIN" compose -f "$TMP_COMPOSE_FILE" -p traefik up -d --quiet-pull + if ! "$PLUGIN_CORE_AVAILABLE_PATH/common/common" compose-up "traefik" "$TMP_COMPOSE_FILE"; then + return 1 + fi } cmd-traefik-stop() { @@ -159,5 +161,7 @@ cmd-traefik-stop() { touch "${DOKKU_LIB_ROOT}/data/traefik/traefik-acme.json" chmod 600 "${DOKKU_LIB_ROOT}/data/traefik/traefik-acme.json" fn-traefik-template-compose-file "$TMP_COMPOSE_FILE" - "$DOCKER_BIN" compose -f "$TMP_COMPOSE_FILE" -p traefik down --remove-orphans + if ! "$PLUGIN_CORE_AVAILABLE_PATH/common/common" compose-down "traefik" "$TMP_COMPOSE_FILE"; then + return 1 + fi }