Browse code

Merge branch '1887-allow_ro_volumes-from' of https://github.com/daniel-garcia/docker into daniel-garcia-1887-allow_ro_volumes-from

Victor Vieux authored on 2013/11/08 10:46:22
Showing 3 changed files
... ...
@@ -199,7 +199,7 @@ func ParseRun(args []string, capabilities *Capabilities) (*Config, *HostConfig,
199 199
 	cmd.Var(flVolumes, "v", "Bind mount a volume (e.g. from the host: -v /host:/container, from docker: -v /container)")
200 200
 
201 201
 	var flVolumesFrom utils.ListOpts
202
-	cmd.Var(&flVolumesFrom, "volumes-from", "Mount volumes from the specified container")
202
+	cmd.Var(&flVolumesFrom, "volumes-from", "Mount volumes from the specified container(s)")
203 203
 
204 204
 	flEntrypoint := cmd.String("entrypoint", "", "Overwrite the default entrypoint of the image")
205 205
 
... ...
@@ -763,9 +763,23 @@ func (container *Container) Start() (err error) {
763 763
 
764 764
 	// Apply volumes from another container if requested
765 765
 	if container.Config.VolumesFrom != "" {
766
-		volumes := strings.Split(container.Config.VolumesFrom, ",")
767
-		for _, v := range volumes {
768
-			c := container.runtime.Get(v)
766
+		containerSpecs := strings.Split(container.Config.VolumesFrom, ",")
767
+		for _, containerSpec := range containerSpecs {
768
+			mountRW := true
769
+			specParts := strings.SplitN(containerSpec, ":", 2)
770
+			switch len(specParts) {
771
+			case 0:
772
+				return fmt.Errorf("Malformed volumes-from specification: %s", container.Config.VolumesFrom)
773
+			case 2:
774
+				switch specParts[1] {
775
+				case "ro":
776
+					mountRW = false
777
+				case "rw": // mountRW is already true
778
+				default:
779
+					return fmt.Errorf("Malformed volumes-from speficication: %s", containerSpec)
780
+				}
781
+			}
782
+			c := container.runtime.Get(specParts[0])
769 783
 			if c == nil {
770 784
 				return fmt.Errorf("Container %s not found. Impossible to mount its volumes", container.ID)
771 785
 			}
... ...
@@ -778,7 +792,7 @@ func (container *Container) Start() (err error) {
778 778
 				}
779 779
 				container.Volumes[volPath] = id
780 780
 				if isRW, exists := c.VolumesRW[volPath]; exists {
781
-					container.VolumesRW[volPath] = isRW
781
+					container.VolumesRW[volPath] = isRW && mountRW
782 782
 				}
783 783
 			}
784 784
 
... ...
@@ -1338,6 +1338,67 @@ func TestBindMounts(t *testing.T) {
1338 1338
 	}
1339 1339
 }
1340 1340
 
1341
+// Test that -volumes-from supports both read-only mounts
1342
+func TestFromVolumesInReadonlyMode(t *testing.T) {
1343
+	runtime := mkRuntime(t)
1344
+	defer nuke(runtime)
1345
+	container, _, err := runtime.Create(
1346
+		&Config{
1347
+			Image:   GetTestImage(runtime).ID,
1348
+			Cmd:     []string{"/bin/echo", "-n", "foobar"},
1349
+			Volumes: map[string]struct{}{"/test": {}},
1350
+		},
1351
+		"",
1352
+	)
1353
+	if err != nil {
1354
+		t.Fatal(err)
1355
+	}
1356
+	defer runtime.Destroy(container)
1357
+	_, err = container.Output()
1358
+	if err != nil {
1359
+		t.Fatal(err)
1360
+	}
1361
+	if !container.VolumesRW["/test"] {
1362
+		t.Fail()
1363
+	}
1364
+
1365
+	container2, _, err := runtime.Create(
1366
+		&Config{
1367
+			Image:       GetTestImage(runtime).ID,
1368
+			Cmd:         []string{"/bin/echo", "-n", "foobar"},
1369
+			VolumesFrom: container.ID + ":ro",
1370
+		},
1371
+		"",
1372
+	)
1373
+	if err != nil {
1374
+		t.Fatal(err)
1375
+	}
1376
+	defer runtime.Destroy(container2)
1377
+
1378
+	_, err = container2.Output()
1379
+	if err != nil {
1380
+		t.Fatal(err)
1381
+	}
1382
+
1383
+	if container.Volumes["/test"] != container2.Volumes["/test"] {
1384
+		t.Logf("container volumes do not match: %s | %s ",
1385
+			container.Volumes["/test"],
1386
+			container2.Volumes["/test"])
1387
+		t.Fail()
1388
+	}
1389
+
1390
+	_, exists := container2.VolumesRW["/test"]
1391
+	if !exists {
1392
+		t.Logf("container2 is missing '/test' volume: %s", container2.VolumesRW)
1393
+		t.Fail()
1394
+	}
1395
+
1396
+	if container2.VolumesRW["/test"] != false {
1397
+		t.Log("'/test' volume mounted in read-write mode, expected read-only")
1398
+		t.Fail()
1399
+	}
1400
+}
1401
+
1341 1402
 // Test that VolumesRW values are copied to the new container.  Regression test for #1201
1342 1403
 func TestVolumesFromReadonlyMount(t *testing.T) {
1343 1404
 	runtime := mkRuntime(t)
... ...
@@ -648,7 +648,7 @@ network communication.
648 648
       -u="": Username or UID
649 649
       -dns=[]: Set custom dns servers for the container
650 650
       -v=[]: Create a bind mount with: [host-dir]:[container-dir]:[rw|ro]. If "container-dir" is missing, then docker creates a new volume.
651
-      -volumes-from="": Mount all volumes from the given container
651
+      -volumes-from="": Mount all volumes from the given container(s)
652 652
       -entrypoint="": Overwrite the default entrypoint set by the image
653 653
       -w="": Working directory inside the container
654 654
       -lxc-conf=[]: Add custom lxc options -lxc-conf="lxc.cgroup.cpuset.cpus = 0,1"
... ...
@@ -740,6 +740,17 @@ can access the network and environment of the redis container via
740 740
 environment variables.  The ``-name`` flag will assign the name ``console``
741 741
 to the newly created container.
742 742
 
743
+.. code-block:: bash
744
+
745
+   docker run -volumes-from 777f7dc92da7,ba8c0c54f0f2:ro -i -t ubuntu pwd
746
+
747
+The ``-volumes-from`` flag mounts all the defined volumes from the
748
+refrence containers. Containers can be specified by a comma seperated
749
+list or by repetitions of the ``-volumes-from`` argument. The container
750
+id may be optionally suffixed with ``:ro`` or ``:rw`` to mount the volumes in
751
+read-only or read-write mode, respectively. By default, the volumes are mounted
752
+in the same mode (rw or ro) as the reference container.
753
+
743 754
 .. _cli_search:
744 755
 
745 756
 ``search``