... | ... |
@@ -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) |