Browse code

Allow named volumes for external drivers.

Signed-off-by: David Calavera <david.calavera@gmail.com>

David Calavera authored on 2015/05/22 02:57:59
Showing 6 changed files
... ...
@@ -70,11 +70,21 @@ func parseBindMount(spec string, config *runconfig.Config) (*mountPoint, error)
70 70
 		return nil, fmt.Errorf("Invalid volume specification: %s", spec)
71 71
 	}
72 72
 
73
-	if !filepath.IsAbs(arr[0]) {
74
-		return nil, fmt.Errorf("cannot bind mount volume: %s volume paths must be absolute.", spec)
73
+	name, source, err := parseVolumeSource(arr[0], config)
74
+	if err != nil {
75
+		return nil, err
76
+	}
77
+
78
+	if len(source) == 0 {
79
+		bind.Driver = config.VolumeDriver
80
+		if len(bind.Driver) == 0 {
81
+			bind.Driver = volume.DefaultDriverName
82
+		}
83
+	} else {
84
+		bind.Source = filepath.Clean(source)
75 85
 	}
76 86
 
77
-	bind.Source = filepath.Clean(arr[0])
87
+	bind.Name = name
78 88
 	bind.Destination = filepath.Clean(bind.Destination)
79 89
 	return bind, nil
80 90
 }
... ...
@@ -245,7 +255,8 @@ func (daemon *Daemon) verifyOldVolumesInfo(container *Container) error {
245 245
 		if strings.HasPrefix(hostPath, vfsPath) {
246 246
 			id := filepath.Base(hostPath)
247 247
 
248
-			container.addLocalMountPoint(id, destination, vols.VolumesRW[destination])
248
+			rw := vols.VolumesRW != nil && vols.VolumesRW[destination]
249
+			container.addLocalMountPoint(id, destination, rw)
249 250
 		}
250 251
 	}
251 252
 
... ...
@@ -254,6 +265,7 @@ func (daemon *Daemon) verifyOldVolumesInfo(container *Container) error {
254 254
 
255 255
 func createVolume(name, driverName string) (volume.Volume, error) {
256 256
 	vd, err := getVolumeDriver(driverName)
257
+
257 258
 	if err != nil {
258 259
 		return nil, err
259 260
 	}
... ...
@@ -3,6 +3,9 @@
3 3
 package daemon
4 4
 
5 5
 import (
6
+	"path/filepath"
7
+
8
+	"github.com/docker/docker/runconfig"
6 9
 	"github.com/docker/docker/volume"
7 10
 	"github.com/docker/docker/volume/drivers"
8 11
 )
... ...
@@ -13,3 +16,11 @@ func getVolumeDriver(name string) (volume.Driver, error) {
13 13
 	}
14 14
 	return volumedrivers.Lookup(name)
15 15
 }
16
+
17
+func parseVolumeSource(spec string, config *runconfig.Config) (string, string, error) {
18
+	if !filepath.IsAbs(spec) {
19
+		return spec, "", nil
20
+	}
21
+
22
+	return "", spec, nil
23
+}
... ...
@@ -5,6 +5,7 @@ package daemon
5 5
 import (
6 6
 	"testing"
7 7
 
8
+	"github.com/docker/docker/runconfig"
8 9
 	"github.com/docker/docker/volume"
9 10
 	"github.com/docker/docker/volume/drivers"
10 11
 )
... ...
@@ -30,3 +31,56 @@ func TestGetVolumeDriver(t *testing.T) {
30 30
 		t.Fatalf("Expected fake driver, got %s\n", d.Name())
31 31
 	}
32 32
 }
33
+
34
+func TestParseBindMount(t *testing.T) {
35
+	cases := []struct {
36
+		bind      string
37
+		driver    string
38
+		expDest   string
39
+		expSource string
40
+		expName   string
41
+		expDriver string
42
+		expRW     bool
43
+		fail      bool
44
+	}{
45
+		{"/tmp:/tmp", "", "/tmp", "/tmp", "", "", true, false},
46
+		{"/tmp:/tmp:ro", "", "/tmp", "/tmp", "", "", false, false},
47
+		{"/tmp:/tmp:rw", "", "/tmp", "/tmp", "", "", true, false},
48
+		{"/tmp:/tmp:foo", "", "/tmp", "/tmp", "", "", false, true},
49
+		{"name:/tmp", "", "/tmp", "", "name", "local", true, false},
50
+		{"name:/tmp", "external", "/tmp", "", "name", "external", true, false},
51
+		{"name:/tmp:ro", "local", "/tmp", "", "name", "local", false, false},
52
+		{"local/name:/tmp:rw", "", "/tmp", "", "local/name", "local", true, false},
53
+	}
54
+
55
+	for _, c := range cases {
56
+		conf := &runconfig.Config{VolumeDriver: c.driver}
57
+		m, err := parseBindMount(c.bind, conf)
58
+		if c.fail {
59
+			if err == nil {
60
+				t.Fatalf("Expected error, was nil, for spec %s\n", c.bind)
61
+			}
62
+			continue
63
+		}
64
+
65
+		if m.Destination != c.expDest {
66
+			t.Fatalf("Expected destination %s, was %s, for spec %s\n", c.expDest, m.Destination, c.bind)
67
+		}
68
+
69
+		if m.Source != c.expSource {
70
+			t.Fatalf("Expected source %s, was %s, for spec %s\n", c.expSource, m.Source, c.bind)
71
+		}
72
+
73
+		if m.Name != c.expName {
74
+			t.Fatalf("Expected name %s, was %s for spec %s\n", c.expName, m.Name, c.bind)
75
+		}
76
+
77
+		if m.Driver != c.expDriver {
78
+			t.Fatalf("Expected driver %s, was %s, for spec %s\n", c.expDriver, m.Driver, c.bind)
79
+		}
80
+
81
+		if m.RW != c.expRW {
82
+			t.Fatalf("Expected RW %v, was %v for spec %s\n", c.expRW, m.RW, c.bind)
83
+		}
84
+	}
85
+}
... ...
@@ -3,6 +3,10 @@
3 3
 package daemon
4 4
 
5 5
 import (
6
+	"fmt"
7
+	"path/filepath"
8
+
9
+	"github.com/docker/docker/runconfig"
6 10
 	"github.com/docker/docker/volume"
7 11
 	"github.com/docker/docker/volume/drivers"
8 12
 )
... ...
@@ -10,3 +14,11 @@ import (
10 10
 func getVolumeDriver(_ string) (volume.Driver, error) {
11 11
 	return volumedrivers.Lookup(volume.DefaultDriverName)
12 12
 }
13
+
14
+func parseVolumeSource(spec string, _ *runconfig.Config) (string, string, error) {
15
+	if !filepath.IsAbs(spec) {
16
+		return "", "", fmt.Errorf("cannot bind mount volume: %s volume paths must be absolute.", spec)
17
+	}
18
+
19
+	return "", spec, nil
20
+}
... ...
@@ -7,6 +7,7 @@ import (
7 7
 	"os"
8 8
 	"testing"
9 9
 
10
+	"github.com/docker/docker/runconfig"
10 11
 	"github.com/docker/docker/volume"
11 12
 	"github.com/docker/docker/volume/drivers"
12 13
 	"github.com/docker/docker/volume/local"
... ...
@@ -33,3 +34,48 @@ func TestGetVolumeDefaultDriver(t *testing.T) {
33 33
 		t.Fatalf("Expected local driver, was %s\n", d.Name)
34 34
 	}
35 35
 }
36
+
37
+func TestParseBindMount(t *testing.T) {
38
+	cases := []struct {
39
+		bind      string
40
+		expDest   string
41
+		expSource string
42
+		expName   string
43
+		expRW     bool
44
+		fail      bool
45
+	}{
46
+		{"/tmp:/tmp", "/tmp", "/tmp", "", true, false},
47
+		{"/tmp:/tmp:ro", "/tmp", "/tmp", "", false, false},
48
+		{"/tmp:/tmp:rw", "/tmp", "/tmp", "", true, false},
49
+		{"/tmp:/tmp:foo", "/tmp", "/tmp", "", false, true},
50
+		{"name:/tmp", "", "", "", false, true},
51
+		{"local/name:/tmp:rw", "", "", "", true, true},
52
+	}
53
+
54
+	for _, c := range cases {
55
+		conf := &runconfig.Config{}
56
+		m, err := parseBindMount(c.bind, conf)
57
+		if c.fail {
58
+			if err == nil {
59
+				t.Fatalf("Expected error, was nil, for spec %s\n", c.bind)
60
+			}
61
+			continue
62
+		}
63
+
64
+		if m.Destination != c.expDest {
65
+			t.Fatalf("Expected destination %s, was %s, for spec %s\n", c.expDest, m.Destination, c.bind)
66
+		}
67
+
68
+		if m.Source != c.expSource {
69
+			t.Fatalf("Expected source %s, was %s, for spec %s\n", c.expSource, m.Source, c.bind)
70
+		}
71
+
72
+		if m.Name != c.expName {
73
+			t.Fatalf("Expected name %s, was %s for spec %s\n", c.expName, m.Name, c.bind)
74
+		}
75
+
76
+		if m.RW != c.expRW {
77
+			t.Fatalf("Expected RW %v, was %v for spec %s\n", c.expRW, m.RW, c.bind)
78
+		}
79
+	}
80
+}
... ...
@@ -1,66 +1,6 @@
1 1
 package daemon
2 2
 
3
-import (
4
-	"testing"
5
-
6
-	"github.com/docker/docker/runconfig"
7
-)
8
-
9
-func TestParseBindMount(t *testing.T) {
10
-	cases := []struct {
11
-		bind      string
12
-		driver    string
13
-		expDest   string
14
-		expSource string
15
-		expName   string
16
-		expDriver string
17
-		expRW     bool
18
-		fail      bool
19
-	}{
20
-		{"/tmp:/tmp", "", "/tmp", "/tmp", "", "", true, false},
21
-		{"/tmp:/tmp:ro", "", "/tmp", "/tmp", "", "", false, false},
22
-		{"/tmp:/tmp:rw", "", "/tmp", "/tmp", "", "", true, false},
23
-		{"/tmp:/tmp:foo", "", "/tmp", "/tmp", "", "", false, true},
24
-		{"name:/tmp", "", "", "", "", "", false, true},
25
-		{"name:/tmp", "external", "/tmp", "", "name", "external", true, true},
26
-		{"external/name:/tmp:rw", "", "/tmp", "", "name", "external", true, true},
27
-		{"external/name:/tmp:ro", "", "/tmp", "", "name", "external", false, true},
28
-		{"external/name:/tmp:foo", "", "/tmp", "", "name", "external", false, true},
29
-		{"name:/tmp", "local", "", "", "", "", false, true},
30
-		{"local/name:/tmp:rw", "", "", "", "", "", true, true},
31
-	}
32
-
33
-	for _, c := range cases {
34
-		conf := &runconfig.Config{VolumeDriver: c.driver}
35
-		m, err := parseBindMount(c.bind, conf)
36
-		if c.fail {
37
-			if err == nil {
38
-				t.Fatalf("Expected error, was nil, for spec %s\n", c.bind)
39
-			}
40
-			continue
41
-		}
42
-
43
-		if m.Destination != c.expDest {
44
-			t.Fatalf("Expected destination %s, was %s, for spec %s\n", c.expDest, m.Destination, c.bind)
45
-		}
46
-
47
-		if m.Source != c.expSource {
48
-			t.Fatalf("Expected source %s, was %s, for spec %s\n", c.expSource, m.Source, c.bind)
49
-		}
50
-
51
-		if m.Name != c.expName {
52
-			t.Fatalf("Expected name %s, was %s for spec %s\n", c.expName, m.Name, c.bind)
53
-		}
54
-
55
-		if m.Driver != c.expDriver {
56
-			t.Fatalf("Expected driver %s, was %s, for spec %s\n", c.expDriver, m.Driver, c.bind)
57
-		}
58
-
59
-		if m.RW != c.expRW {
60
-			t.Fatalf("Expected RW %v, was %v for spec %s\n", c.expRW, m.RW, c.bind)
61
-		}
62
-	}
63
-}
3
+import "testing"
64 4
 
65 5
 func TestParseVolumeFrom(t *testing.T) {
66 6
 	cases := []struct {