mirror of https://github.com/docker/compose.git
				
				
				
			Fix bind mounts when in project volumes definition
Signed-off-by: Ulysses Souza <ulyssessouza@gmail.com>
This commit is contained in:
		
							parent
							
								
									6756732fe4
								
							
						
					
					
						commit
						919f351b4b
					
				| 
						 | 
					@ -718,9 +718,15 @@ MOUNTS:
 | 
				
			||||||
			// so `Bind` API is used here with raw volume string
 | 
								// so `Bind` API is used here with raw volume string
 | 
				
			||||||
			// see https://github.com/moby/moby/issues/43483
 | 
								// see https://github.com/moby/moby/issues/43483
 | 
				
			||||||
			for _, v := range service.Volumes {
 | 
								for _, v := range service.Volumes {
 | 
				
			||||||
				if v.Target == m.Target && v.Bind != nil && v.Bind.CreateHostPath {
 | 
									if v.Target == m.Target {
 | 
				
			||||||
					binds = append(binds, v.String())
 | 
										switch {
 | 
				
			||||||
					continue MOUNTS
 | 
										case string(m.Type) != v.Type:
 | 
				
			||||||
 | 
											v.Source = m.Source
 | 
				
			||||||
 | 
											fallthrough
 | 
				
			||||||
 | 
										case v.Bind != nil && v.Bind.CreateHostPath:
 | 
				
			||||||
 | 
											binds = append(binds, v.String())
 | 
				
			||||||
 | 
											continue MOUNTS
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
| 
						 | 
					@ -911,10 +917,14 @@ func buildMount(project types.Project, volume types.ServiceVolumeConfig) (mount.
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	bind, vol, tmpfs := buildMountOptions(volume)
 | 
						bind, vol, tmpfs := buildMountOptions(project, volume)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	volume.Target = path.Clean(volume.Target)
 | 
						volume.Target = path.Clean(volume.Target)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if bind != nil {
 | 
				
			||||||
 | 
							volume.Type = types.VolumeTypeBind
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return mount.Mount{
 | 
						return mount.Mount{
 | 
				
			||||||
		Type:          mount.Type(volume.Type),
 | 
							Type:          mount.Type(volume.Type),
 | 
				
			||||||
		Source:        source,
 | 
							Source:        source,
 | 
				
			||||||
| 
						 | 
					@ -927,7 +937,7 @@ func buildMount(project types.Project, volume types.ServiceVolumeConfig) (mount.
 | 
				
			||||||
	}, nil
 | 
						}, nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func buildMountOptions(volume types.ServiceVolumeConfig) (*mount.BindOptions, *mount.VolumeOptions, *mount.TmpfsOptions) {
 | 
					func buildMountOptions(project types.Project, volume types.ServiceVolumeConfig) (*mount.BindOptions, *mount.VolumeOptions, *mount.TmpfsOptions) {
 | 
				
			||||||
	switch volume.Type {
 | 
						switch volume.Type {
 | 
				
			||||||
	case "bind":
 | 
						case "bind":
 | 
				
			||||||
		if volume.Volume != nil {
 | 
							if volume.Volume != nil {
 | 
				
			||||||
| 
						 | 
					@ -944,6 +954,11 @@ func buildMountOptions(volume types.ServiceVolumeConfig) (*mount.BindOptions, *m
 | 
				
			||||||
		if volume.Tmpfs != nil {
 | 
							if volume.Tmpfs != nil {
 | 
				
			||||||
			logrus.Warnf("mount of type `volume` should not define `tmpfs` option")
 | 
								logrus.Warnf("mount of type `volume` should not define `tmpfs` option")
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
							if v, ok := project.Volumes[volume.Source]; ok && v.DriverOpts["o"] == types.VolumeTypeBind {
 | 
				
			||||||
 | 
								return buildBindOption(&types.ServiceVolumeBind{
 | 
				
			||||||
 | 
									CreateHostPath: true,
 | 
				
			||||||
 | 
								}), nil, nil
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
		return nil, buildVolumeOptions(volume.Volume), nil
 | 
							return nil, buildVolumeOptions(volume.Volume), nil
 | 
				
			||||||
	case "tmpfs":
 | 
						case "tmpfs":
 | 
				
			||||||
		if volume.Bind != nil {
 | 
							if volume.Bind != nil {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,14 @@
 | 
				
			||||||
 | 
					services:
 | 
				
			||||||
 | 
					  frontend:
 | 
				
			||||||
 | 
					    image: nginx
 | 
				
			||||||
 | 
					    container_name: frontend
 | 
				
			||||||
 | 
					    volumes:
 | 
				
			||||||
 | 
					      - project_data:/data
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					volumes:
 | 
				
			||||||
 | 
					  project_data:
 | 
				
			||||||
 | 
					    driver: local
 | 
				
			||||||
 | 
					    driver_opts:
 | 
				
			||||||
 | 
					      type: none
 | 
				
			||||||
 | 
					      o: bind
 | 
				
			||||||
 | 
					      device: "${TEST_DIR}"
 | 
				
			||||||
| 
						 | 
					@ -167,6 +167,19 @@ func (c *E2eCLI) NewCmd(command string, args ...string) icmd.Cmd {
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// NewCmdWithEnv creates a cmd object configured with the test environment set with additional env vars
 | 
				
			||||||
 | 
					func (c *E2eCLI) NewCmdWithEnv(envvars []string, command string, args ...string) icmd.Cmd {
 | 
				
			||||||
 | 
						env := append(os.Environ(),
 | 
				
			||||||
 | 
							append(envvars,
 | 
				
			||||||
 | 
								"DOCKER_CONFIG="+c.ConfigDir,
 | 
				
			||||||
 | 
								"KUBECONFIG=invalid")...,
 | 
				
			||||||
 | 
						)
 | 
				
			||||||
 | 
						return icmd.Cmd{
 | 
				
			||||||
 | 
							Command: append([]string{command}, args...),
 | 
				
			||||||
 | 
							Env:     env,
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// MetricsSocket get the path where test metrics will be sent
 | 
					// MetricsSocket get the path where test metrics will be sent
 | 
				
			||||||
func (c *E2eCLI) MetricsSocket() string {
 | 
					func (c *E2eCLI) MetricsSocket() string {
 | 
				
			||||||
	return filepath.Join(c.ConfigDir, "./docker-cli.sock")
 | 
						return filepath.Join(c.ConfigDir, "./docker-cli.sock")
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -18,11 +18,14 @@ package e2e
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	"net/http"
 | 
						"net/http"
 | 
				
			||||||
 | 
						"os"
 | 
				
			||||||
 | 
						"path/filepath"
 | 
				
			||||||
	"strings"
 | 
						"strings"
 | 
				
			||||||
	"testing"
 | 
						"testing"
 | 
				
			||||||
	"time"
 | 
						"time"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"gotest.tools/v3/assert"
 | 
						"gotest.tools/v3/assert"
 | 
				
			||||||
 | 
						"gotest.tools/v3/icmd"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TestLocalComposeVolume(t *testing.T) {
 | 
					func TestLocalComposeVolume(t *testing.T) {
 | 
				
			||||||
| 
						 | 
					@ -88,3 +91,30 @@ func TestLocalComposeVolume(t *testing.T) {
 | 
				
			||||||
		assert.Assert(t, !strings.Contains(ls, "myvolume"))
 | 
							assert.Assert(t, !strings.Contains(ls, "myvolume"))
 | 
				
			||||||
	})
 | 
						})
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestProjectVolumeBind(t *testing.T) {
 | 
				
			||||||
 | 
						if composeStandaloneMode {
 | 
				
			||||||
 | 
							t.Skip()
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						c := NewParallelE2eCLI(t, binDir)
 | 
				
			||||||
 | 
						const projectName = "compose-e2e-project-volume-bind"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						t.Run("up on project volume with bind specification", func(t *testing.T) {
 | 
				
			||||||
 | 
							tmpDir, err := os.MkdirTemp("", projectName)
 | 
				
			||||||
 | 
							assert.NilError(t, err)
 | 
				
			||||||
 | 
							defer os.RemoveAll(tmpDir) // nolint
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							c.RunDockerComposeCmd("--project-name", projectName, "down")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							c.RunDockerOrExitError("volume", "rm", "-f", projectName+"_project_data").Assert(t, icmd.Success)
 | 
				
			||||||
 | 
							cmd := c.NewCmdWithEnv([]string{"TEST_DIR=" + tmpDir},
 | 
				
			||||||
 | 
								"docker", "compose", "--project-directory", "fixtures/project-volume-bind-test", "--project-name", projectName, "up", "-d")
 | 
				
			||||||
 | 
							icmd.RunCmd(cmd).Assert(t, icmd.Success)
 | 
				
			||||||
 | 
							defer c.RunDockerComposeCmd("--project-name", projectName, "down")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							c.RunCmd("sh", "-c", "echo SUCCESS > "+filepath.Join(tmpDir, "resultfile")).Assert(t, icmd.Success)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							ret := c.RunDockerOrExitError("exec", "frontend", "bash", "-c", "cat /data/resultfile").Assert(t, icmd.Success)
 | 
				
			||||||
 | 
							assert.Assert(t, strings.Contains(ret.Stdout(), "SUCCESS"))
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue