瀏覽代碼

Merge pull request #1496 from xdissent/1351-volumes-from-before-volumes

* Runtime: Apply volumes-from before creating volumes
Guillaume J. Charmes 12 年之前
父節點
當前提交
631c449183
共有 2 個文件被更改,包括 99 次插入30 次删除
  1. 34 30
      container.go
  2. 65 0
      container_test.go

+ 34 - 30
container.go

@@ -577,40 +577,12 @@ func (container *Container) Start(hostConfig *HostConfig) error {
 		binds[path.Clean(dst)] = bindMap
 	}
 
-	// FIXME: evaluate volumes-from before individual volumes, so that the latter can override the former.
-	// Create the requested volumes volumes
 	if container.Volumes == nil || len(container.Volumes) == 0 {
 		container.Volumes = make(map[string]string)
 		container.VolumesRW = make(map[string]bool)
-
-		for volPath := range container.Config.Volumes {
-			volPath = path.Clean(volPath)
-			// If an external bind is defined for this volume, use that as a source
-			if bindMap, exists := binds[volPath]; exists {
-				container.Volumes[volPath] = bindMap.SrcPath
-				if strings.ToLower(bindMap.Mode) == "rw" {
-					container.VolumesRW[volPath] = true
-				}
-				// Otherwise create an directory in $ROOT/volumes/ and use that
-			} else {
-				c, err := container.runtime.volumes.Create(nil, container, "", "", nil)
-				if err != nil {
-					return err
-				}
-				srcPath, err := c.layer()
-				if err != nil {
-					return err
-				}
-				container.Volumes[volPath] = srcPath
-				container.VolumesRW[volPath] = true // RW by default
-			}
-			// Create the mountpoint
-			if err := os.MkdirAll(path.Join(container.RootfsPath(), volPath), 0755); err != nil {
-				return nil
-			}
-		}
 	}
 
+	// Apply volumes from another container if requested
 	if container.Config.VolumesFrom != "" {
 		c := container.runtime.Get(container.Config.VolumesFrom)
 		if c == nil {
@@ -618,7 +590,7 @@ func (container *Container) Start(hostConfig *HostConfig) error {
 		}
 		for volPath, id := range c.Volumes {
 			if _, exists := container.Volumes[volPath]; exists {
-				return fmt.Errorf("The requested volume %s overlap one of the volume of the container %s", volPath, c.ID)
+				continue
 			}
 			if err := os.MkdirAll(path.Join(container.RootfsPath(), volPath), 0755); err != nil {
 				return nil
@@ -630,6 +602,38 @@ func (container *Container) Start(hostConfig *HostConfig) error {
 		}
 	}
 
+	// Create the requested volumes if they don't exist
+	for volPath := range container.Config.Volumes {
+		volPath = path.Clean(volPath)
+		// Skip existing volumes
+		if _, exists := container.Volumes[volPath]; exists {
+			continue
+		}
+		// If an external bind is defined for this volume, use that as a source
+		if bindMap, exists := binds[volPath]; exists {
+			container.Volumes[volPath] = bindMap.SrcPath
+			if strings.ToLower(bindMap.Mode) == "rw" {
+				container.VolumesRW[volPath] = true
+			}
+			// Otherwise create an directory in $ROOT/volumes/ and use that
+		} else {
+			c, err := container.runtime.volumes.Create(nil, container, "", "", nil)
+			if err != nil {
+				return err
+			}
+			srcPath, err := c.layer()
+			if err != nil {
+				return err
+			}
+			container.Volumes[volPath] = srcPath
+			container.VolumesRW[volPath] = true // RW by default
+		}
+		// Create the mountpoint
+		if err := os.MkdirAll(path.Join(container.RootfsPath(), volPath), 0755); err != nil {
+			return nil
+		}
+	}
+
 	if err := container.generateLXCConfig(); err != nil {
 		return err
 	}

+ 65 - 0
container_test.go

@@ -1283,6 +1283,71 @@ func TestRestartWithVolumes(t *testing.T) {
 	}
 }
 
+// Test for #1351
+func TestVolumesFromWithVolumes(t *testing.T) {
+	runtime := mkRuntime(t)
+	defer nuke(runtime)
+
+	container, err := NewBuilder(runtime).Create(&Config{
+		Image:   GetTestImage(runtime).ID,
+		Cmd:     []string{"sh", "-c", "echo -n bar > /test/foo"},
+		Volumes: map[string]struct{}{"/test": {}},
+	},
+	)
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer runtime.Destroy(container)
+
+	for key := range container.Config.Volumes {
+		if key != "/test" {
+			t.Fail()
+		}
+	}
+
+	_, err = container.Output()
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	expected := container.Volumes["/test"]
+	if expected == "" {
+		t.Fail()
+	}
+
+	container2, err := NewBuilder(runtime).Create(
+		&Config{
+			Image:       GetTestImage(runtime).ID,
+			Cmd:         []string{"cat", "/test/foo"},
+			VolumesFrom: container.ID,
+			Volumes:     map[string]struct{}{"/test": {}},
+		},
+	)
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer runtime.Destroy(container2)
+
+	output, err := container2.Output()
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	if string(output) != "bar" {
+		t.Fail()
+	}
+
+	if container.Volumes["/test"] != container2.Volumes["/test"] {
+		t.Fail()
+	}
+
+	// Ensure it restarts successfully
+	_, err = container2.Output()
+	if err != nil {
+		t.Fatal(err)
+	}
+}
+
 func TestOnlyLoopbackExistsWhenUsingDisableNetworkOption(t *testing.T) {
 	runtime := mkRuntime(t)
 	defer nuke(runtime)