Browse code

Copies content from image to volumne if non-empty. Fixes #1582.

Brian Olsen authored on 2013/08/30 09:29:35
Showing 2 changed files
... ...
@@ -642,11 +642,13 @@ func (container *Container) Start(hostConfig *HostConfig) error {
642 642
 		if _, exists := container.Volumes[volPath]; exists {
643 643
 			continue
644 644
 		}
645
+		var srcPath string
646
+		srcRW := false
645 647
 		// If an external bind is defined for this volume, use that as a source
646 648
 		if bindMap, exists := binds[volPath]; exists {
647
-			container.Volumes[volPath] = bindMap.SrcPath
649
+			srcPath = bindMap.SrcPath
648 650
 			if strings.ToLower(bindMap.Mode) == "rw" {
649
-				container.VolumesRW[volPath] = true
651
+				srcRW = true
650 652
 			}
651 653
 			// Otherwise create an directory in $ROOT/volumes/ and use that
652 654
 		} else {
... ...
@@ -654,17 +656,36 @@ func (container *Container) Start(hostConfig *HostConfig) error {
654 654
 			if err != nil {
655 655
 				return err
656 656
 			}
657
-			srcPath, err := c.layer()
657
+			srcPath, err = c.layer()
658 658
 			if err != nil {
659 659
 				return err
660 660
 			}
661
-			container.Volumes[volPath] = srcPath
662
-			container.VolumesRW[volPath] = true // RW by default
661
+			srcRW = true // RW by default
663 662
 		}
663
+		container.Volumes[volPath] = srcPath
664
+		container.VolumesRW[volPath] = srcRW
664 665
 		// Create the mountpoint
665
-		if err := os.MkdirAll(path.Join(container.RootfsPath(), volPath), 0755); err != nil {
666
+		rootVolPath := path.Join(container.RootfsPath(), volPath)
667
+		if err := os.MkdirAll(rootVolPath, 0755); err != nil {
666 668
 			return nil
667 669
 		}
670
+		if srcRW {
671
+			volList, err := ioutil.ReadDir(rootVolPath)
672
+			if err != nil {
673
+				return err
674
+			}
675
+			if len(volList) > 0 {
676
+				srcList, err := ioutil.ReadDir(srcPath)
677
+				if err != nil {
678
+					return err
679
+				}
680
+				if len(srcList) == 0 {
681
+					if err := CopyWithTar(rootVolPath, srcPath); err != nil {
682
+						return err
683
+					}
684
+				}
685
+			}
686
+		}
668 687
 	}
669 688
 
670 689
 	if err := container.generateLXCConfig(hostConfig); err != nil {
... ...
@@ -1193,6 +1193,60 @@ func tempDir(t *testing.T) string {
1193 1193
 	return tmpDir
1194 1194
 }
1195 1195
 
1196
+// Test for #1582
1197
+func TestCopyVolumeContent(t *testing.T) {
1198
+	r := mkRuntime(t)
1199
+	defer nuke(r)
1200
+
1201
+	// Put some content in a directory of a container and commit it
1202
+	container1, _, _ := mkContainer(r, []string{"_", "/bin/sh", "-c", "mkdir -p /hello/local && echo hello > /hello/local/world"}, t)
1203
+	defer r.Destroy(container1)
1204
+
1205
+	if container1.State.Running {
1206
+		t.Errorf("Container shouldn't be running")
1207
+	}
1208
+	if err := container1.Run(); err != nil {
1209
+		t.Fatal(err)
1210
+	}
1211
+	if container1.State.Running {
1212
+		t.Errorf("Container shouldn't be running")
1213
+	}
1214
+
1215
+	rwTar, err := container1.ExportRw()
1216
+	if err != nil {
1217
+		t.Error(err)
1218
+	}
1219
+	img, err := r.graph.Create(rwTar, container1, "unit test commited image", "", nil)
1220
+	if err != nil {
1221
+		t.Error(err)
1222
+	}
1223
+
1224
+	// Test that the content is copied from the image to the volume
1225
+	tmpDir1 := tempDir(t)
1226
+	defer os.RemoveAll(tmpDir1)
1227
+	stdout1, _ := runContainer(r, []string{"-v", fmt.Sprintf("%s:/hello", tmpDir1), img.ID, "find", "/hello"}, t)
1228
+	if !(strings.Contains(stdout1, "/hello/local/world") && strings.Contains(stdout1, "/hello/local")) {
1229
+		t.Fatal("Container failed to transfer content to volume")
1230
+	}
1231
+
1232
+	// Test that the content is not copied when the volume is readonly
1233
+	tmpDir2 := tempDir(t)
1234
+	defer os.RemoveAll(tmpDir2)
1235
+	stdout2, _ := runContainer(r, []string{"-v", fmt.Sprintf("%s:/hello:ro", tmpDir2), img.ID, "find", "/hello"}, t)
1236
+	if strings.Contains(stdout2, "/hello/local/world") || strings.Contains(stdout2, "/hello/local") {
1237
+		t.Fatal("Container transfered content to readonly volume")
1238
+	}
1239
+
1240
+	// Test that the content is not copied when the volume is non-empty
1241
+	tmpDir3 := tempDir(t)
1242
+	defer os.RemoveAll(tmpDir3)
1243
+	writeFile(path.Join(tmpDir3, "touch-me"), "", t)
1244
+	stdout3, _ := runContainer(r, []string{"-v", fmt.Sprintf("%s:/hello:rw", tmpDir3), img.ID, "find", "/hello"}, t)
1245
+	if strings.Contains(stdout3, "/hello/local/world") || strings.Contains(stdout3, "/hello/local") || !strings.Contains(stdout3, "/hello/touch-me") {
1246
+		t.Fatal("Container transfered content to non-empty volume")
1247
+	}
1248
+}
1249
+
1196 1250
 func TestBindMounts(t *testing.T) {
1197 1251
 	r := mkRuntime(t)
1198 1252
 	defer nuke(r)