Skip to content

Commit 919f351

Browse files
committed
Fix bind mounts when in project volumes definition
Signed-off-by: Ulysses Souza <[email protected]>
1 parent 6756732 commit 919f351

File tree

4 files changed

+77
-5
lines changed

4 files changed

+77
-5
lines changed

pkg/compose/create.go

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -718,9 +718,15 @@ MOUNTS:
718718
// so `Bind` API is used here with raw volume string
719719
// see https://github.com/moby/moby/issues/43483
720720
for _, v := range service.Volumes {
721-
if v.Target == m.Target && v.Bind != nil && v.Bind.CreateHostPath {
722-
binds = append(binds, v.String())
723-
continue MOUNTS
721+
if v.Target == m.Target {
722+
switch {
723+
case string(m.Type) != v.Type:
724+
v.Source = m.Source
725+
fallthrough
726+
case v.Bind != nil && v.Bind.CreateHostPath:
727+
binds = append(binds, v.String())
728+
continue MOUNTS
729+
}
724730
}
725731
}
726732
}
@@ -911,10 +917,14 @@ func buildMount(project types.Project, volume types.ServiceVolumeConfig) (mount.
911917
}
912918
}
913919

914-
bind, vol, tmpfs := buildMountOptions(volume)
920+
bind, vol, tmpfs := buildMountOptions(project, volume)
915921

916922
volume.Target = path.Clean(volume.Target)
917923

924+
if bind != nil {
925+
volume.Type = types.VolumeTypeBind
926+
}
927+
918928
return mount.Mount{
919929
Type: mount.Type(volume.Type),
920930
Source: source,
@@ -927,7 +937,7 @@ func buildMount(project types.Project, volume types.ServiceVolumeConfig) (mount.
927937
}, nil
928938
}
929939

930-
func buildMountOptions(volume types.ServiceVolumeConfig) (*mount.BindOptions, *mount.VolumeOptions, *mount.TmpfsOptions) {
940+
func buildMountOptions(project types.Project, volume types.ServiceVolumeConfig) (*mount.BindOptions, *mount.VolumeOptions, *mount.TmpfsOptions) {
931941
switch volume.Type {
932942
case "bind":
933943
if volume.Volume != nil {
@@ -944,6 +954,11 @@ func buildMountOptions(volume types.ServiceVolumeConfig) (*mount.BindOptions, *m
944954
if volume.Tmpfs != nil {
945955
logrus.Warnf("mount of type `volume` should not define `tmpfs` option")
946956
}
957+
if v, ok := project.Volumes[volume.Source]; ok && v.DriverOpts["o"] == types.VolumeTypeBind {
958+
return buildBindOption(&types.ServiceVolumeBind{
959+
CreateHostPath: true,
960+
}), nil, nil
961+
}
947962
return nil, buildVolumeOptions(volume.Volume), nil
948963
case "tmpfs":
949964
if volume.Bind != nil {
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
services:
2+
frontend:
3+
image: nginx
4+
container_name: frontend
5+
volumes:
6+
- project_data:/data
7+
8+
volumes:
9+
project_data:
10+
driver: local
11+
driver_opts:
12+
type: none
13+
o: bind
14+
device: "${TEST_DIR}"

pkg/e2e/framework.go

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,19 @@ func (c *E2eCLI) NewCmd(command string, args ...string) icmd.Cmd {
167167
}
168168
}
169169

170+
// NewCmdWithEnv creates a cmd object configured with the test environment set with additional env vars
171+
func (c *E2eCLI) NewCmdWithEnv(envvars []string, command string, args ...string) icmd.Cmd {
172+
env := append(os.Environ(),
173+
append(envvars,
174+
"DOCKER_CONFIG="+c.ConfigDir,
175+
"KUBECONFIG=invalid")...,
176+
)
177+
return icmd.Cmd{
178+
Command: append([]string{command}, args...),
179+
Env: env,
180+
}
181+
}
182+
170183
// MetricsSocket get the path where test metrics will be sent
171184
func (c *E2eCLI) MetricsSocket() string {
172185
return filepath.Join(c.ConfigDir, "./docker-cli.sock")

pkg/e2e/volumes_test.go

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,14 @@ package e2e
1818

1919
import (
2020
"net/http"
21+
"os"
22+
"path/filepath"
2123
"strings"
2224
"testing"
2325
"time"
2426

2527
"gotest.tools/v3/assert"
28+
"gotest.tools/v3/icmd"
2629
)
2730

2831
func TestLocalComposeVolume(t *testing.T) {
@@ -88,3 +91,30 @@ func TestLocalComposeVolume(t *testing.T) {
8891
assert.Assert(t, !strings.Contains(ls, "myvolume"))
8992
})
9093
}
94+
95+
func TestProjectVolumeBind(t *testing.T) {
96+
if composeStandaloneMode {
97+
t.Skip()
98+
}
99+
c := NewParallelE2eCLI(t, binDir)
100+
const projectName = "compose-e2e-project-volume-bind"
101+
102+
t.Run("up on project volume with bind specification", func(t *testing.T) {
103+
tmpDir, err := os.MkdirTemp("", projectName)
104+
assert.NilError(t, err)
105+
defer os.RemoveAll(tmpDir) // nolint
106+
107+
c.RunDockerComposeCmd("--project-name", projectName, "down")
108+
109+
c.RunDockerOrExitError("volume", "rm", "-f", projectName+"_project_data").Assert(t, icmd.Success)
110+
cmd := c.NewCmdWithEnv([]string{"TEST_DIR=" + tmpDir},
111+
"docker", "compose", "--project-directory", "fixtures/project-volume-bind-test", "--project-name", projectName, "up", "-d")
112+
icmd.RunCmd(cmd).Assert(t, icmd.Success)
113+
defer c.RunDockerComposeCmd("--project-name", projectName, "down")
114+
115+
c.RunCmd("sh", "-c", "echo SUCCESS > "+filepath.Join(tmpDir, "resultfile")).Assert(t, icmd.Success)
116+
117+
ret := c.RunDockerOrExitError("exec", "frontend", "bash", "-c", "cat /data/resultfile").Assert(t, icmd.Success)
118+
assert.Assert(t, strings.Contains(ret.Stdout(), "SUCCESS"))
119+
})
120+
}

0 commit comments

Comments
 (0)