Jelajahi Sumber

Merge pull request #8055 from cpuguy83/7792_fix_volume_mount_ordering

Fix #7792 - Order mounts
Alexandr Morozov 10 tahun lalu
induk
melakukan
ed957232a1
2 mengubah file dengan 59 tambahan dan 5 penghapusan
  1. 17 5
      daemon/volumes.go
  2. 42 0
      integration-cli/docker_cli_run_test.go

+ 17 - 5
daemon/volumes.go

@@ -5,6 +5,7 @@ import (
 	"io/ioutil"
 	"os"
 	"path/filepath"
+	"sort"
 	"strings"
 	"syscall"
 
@@ -73,19 +74,30 @@ func setupMountsForContainer(container *Container) error {
 	// Note, these are not private because you may want propagation of (un)mounts from host
 	// volumes. For instance if you use -v /usr:/usr and the host later mounts /usr/share you
 	// want this new mount in the container
-	for r, v := range container.Volumes {
+	// These mounts must be ordered based on the length of the path that it is being mounted to (lexicographic)
+	for _, path := range container.sortedVolumeMounts() {
 		mounts = append(mounts, execdriver.Mount{
-			Source:      v,
-			Destination: r,
-			Writable:    container.VolumesRW[r],
+			Source:      container.Volumes[path],
+			Destination: path,
+			Writable:    container.VolumesRW[path],
 		})
 	}
 
 	container.command.Mounts = mounts
-
 	return nil
 }
 
+// sortedVolumeMounts returns the list of container volume mount points sorted in lexicographic order
+func (container *Container) sortedVolumeMounts() []string {
+	var mountPaths []string
+	for path := range container.Volumes {
+		mountPaths = append(mountPaths, path)
+	}
+
+	sort.Strings(mountPaths)
+	return mountPaths
+}
+
 func parseVolumesFromSpec(container *Container, spec string) (map[string]*Volume, error) {
 	specParts := strings.SplitN(spec, ":", 2)
 	if len(specParts) == 0 {

+ 42 - 0
integration-cli/docker_cli_run_test.go

@@ -2069,3 +2069,45 @@ func TestDockerExecInteractive(t *testing.T) {
 
 	logDone("exec - Interactive test")
 }
+
+// Regression test for #7792
+func TestMountOrdering(t *testing.T) {
+	tmpDir, err := ioutil.TempDir("", "docker_nested_mount_test")
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer os.RemoveAll(tmpDir)
+
+	tmpDir2, err := ioutil.TempDir("", "docker_nested_mount_test2")
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer os.RemoveAll(tmpDir2)
+
+	// Create a temporary tmpfs mount.
+	fooDir := filepath.Join(tmpDir, "foo")
+	if err := os.MkdirAll(filepath.Join(tmpDir, "foo"), 0755); err != nil {
+		t.Fatalf("failed to mkdir at %s - %s", fooDir, err)
+	}
+
+	if err := ioutil.WriteFile(fmt.Sprintf("%s/touch-me", fooDir), []byte{}, 0644); err != nil {
+		t.Fatal(err)
+	}
+
+	if err := ioutil.WriteFile(fmt.Sprintf("%s/touch-me", tmpDir), []byte{}, 0644); err != nil {
+		t.Fatal(err)
+	}
+
+	if err := ioutil.WriteFile(fmt.Sprintf("%s/touch-me", tmpDir2), []byte{}, 0644); err != nil {
+		t.Fatal(err)
+	}
+
+	cmd := exec.Command(dockerBinary, "run", "-v", fmt.Sprintf("%s:/tmp", tmpDir), "-v", fmt.Sprintf("%s:/tmp/foo", fooDir), "-v", fmt.Sprintf("%s:/tmp/tmp2", tmpDir2), "-v", fmt.Sprintf("%s:/tmp/tmp2/foo", fooDir), "busybox:latest", "sh", "-c", "ls /tmp/touch-me && ls /tmp/foo/touch-me && ls /tmp/tmp2/touch-me && ls /tmp/tmp2/foo/touch-me")
+	out, _, err := runCommandWithOutput(cmd)
+	if err != nil {
+		t.Fatal(out, err)
+	}
+
+	deleteAllContainers()
+	logDone("run - volumes are mounted in the correct order")
+}