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
This commit is contained in:
Jose Diaz-Gonzalez
2025-05-24 23:31:34 -04:00
parent 41ac56e54b
commit 6ce10b5be6
8 changed files with 108 additions and 39 deletions

View File

@@ -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
}

View File

@@ -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}}'")

View File

@@ -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 {

View File

@@ -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)

View File

@@ -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
}

View File

@@ -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 {

View File

@@ -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
}

View File

@@ -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
}