Browse code

api: fix ReadOnly support for tmpfs

For `--mount type=tmpfs,target=/foo,readonly`, the `readonly` flag was just ignored.

Signed-off-by: Akihiro Suda <suda.akihiro@lab.ntt.co.jp>

Akihiro Suda authored on 2016/11/08 15:46:23
Showing 5 changed files
... ...
@@ -414,7 +414,7 @@ func (container *Container) TmpfsMounts() ([]Mount, error) {
414 414
 	}
415 415
 	for dest, mnt := range container.MountPoints {
416 416
 		if mnt.Type == mounttypes.TypeTmpfs {
417
-			data, err := volume.ConvertTmpfsOptions(mnt.Spec.TmpfsOptions)
417
+			data, err := volume.ConvertTmpfsOptions(mnt.Spec.TmpfsOptions, mnt.Spec.ReadOnly)
418 418
 			if err != nil {
419 419
 				return nil, err
420 420
 			}
... ...
@@ -91,7 +91,7 @@ func validateMountConfig(mnt *mount.Mount, options ...func(*validateOpts)) error
91 91
 		if len(mnt.Source) != 0 {
92 92
 			return &errMountConfig{mnt, errExtraField("Source")}
93 93
 		}
94
-		if _, err := ConvertTmpfsOptions(mnt.TmpfsOptions); err != nil {
94
+		if _, err := ConvertTmpfsOptions(mnt.TmpfsOptions, mnt.ReadOnly); err != nil {
95 95
 			return &errMountConfig{mnt, err}
96 96
 		}
97 97
 	default:
... ...
@@ -13,16 +13,17 @@ import (
13 13
 // for mount(2).
14 14
 // The logic is copy-pasted from daemon/cluster/executer/container.getMountMask.
15 15
 // It will be deduplicated when we migrated the cluster to the new mount scheme.
16
-func ConvertTmpfsOptions(opt *mounttypes.TmpfsOptions) (string, error) {
17
-	if opt == nil {
18
-		return "", nil
19
-	}
16
+func ConvertTmpfsOptions(opt *mounttypes.TmpfsOptions, readOnly bool) (string, error) {
20 17
 	var rawOpts []string
21
-	if opt.Mode != 0 {
18
+	if readOnly {
19
+		rawOpts = append(rawOpts, "ro")
20
+	}
21
+
22
+	if opt != nil && opt.Mode != 0 {
22 23
 		rawOpts = append(rawOpts, fmt.Sprintf("mode=%o", opt.Mode))
23 24
 	}
24 25
 
25
-	if opt.SizeBytes != 0 {
26
+	if opt != nil && opt.SizeBytes != 0 {
26 27
 		// calculate suffix here, making this linux specific, but that is
27 28
 		// okay, since API is that way anyways.
28 29
 
... ...
@@ -3,6 +3,7 @@
3 3
 package volume
4 4
 
5 5
 import (
6
+	"strings"
6 7
 	"testing"
7 8
 
8 9
 	mounttypes "github.com/docker/docker/api/types/mount"
... ...
@@ -10,14 +11,41 @@ import (
10 10
 
11 11
 func TestConvertTmpfsOptions(t *testing.T) {
12 12
 	type testCase struct {
13
-		opt mounttypes.TmpfsOptions
13
+		opt                  mounttypes.TmpfsOptions
14
+		readOnly             bool
15
+		expectedSubstrings   []string
16
+		unexpectedSubstrings []string
14 17
 	}
15 18
 	cases := []testCase{
16
-		{mounttypes.TmpfsOptions{SizeBytes: 1024 * 1024, Mode: 0700}},
19
+		{
20
+			opt:                  mounttypes.TmpfsOptions{SizeBytes: 1024 * 1024, Mode: 0700},
21
+			readOnly:             false,
22
+			expectedSubstrings:   []string{"size=1m", "mode=700"},
23
+			unexpectedSubstrings: []string{"ro"},
24
+		},
25
+		{
26
+			opt:                  mounttypes.TmpfsOptions{},
27
+			readOnly:             true,
28
+			expectedSubstrings:   []string{"ro"},
29
+			unexpectedSubstrings: []string{},
30
+		},
17 31
 	}
18 32
 	for _, c := range cases {
19
-		if _, err := ConvertTmpfsOptions(&c.opt); err != nil {
20
-			t.Fatalf("could not convert %+v to string: %v", c.opt, err)
33
+		data, err := ConvertTmpfsOptions(&c.opt, c.readOnly)
34
+		if err != nil {
35
+			t.Fatalf("could not convert %+v (readOnly: %v) to string: %v",
36
+				c.opt, c.readOnly, err)
37
+		}
38
+		t.Logf("data=%q", data)
39
+		for _, s := range c.expectedSubstrings {
40
+			if !strings.Contains(data, s) {
41
+				t.Fatalf("expected substring: %s, got %v (case=%+v)", s, data, c)
42
+			}
43
+		}
44
+		for _, s := range c.unexpectedSubstrings {
45
+			if strings.Contains(data, s) {
46
+				t.Fatalf("unexpected substring: %s, got %v (case=%+v)", s, data, c)
47
+			}
21 48
 		}
22 49
 	}
23 50
 }
... ...
@@ -11,6 +11,6 @@ import (
11 11
 
12 12
 // ConvertTmpfsOptions converts *mounttypes.TmpfsOptions to the raw option string
13 13
 // for mount(2).
14
-func ConvertTmpfsOptions(opt *mounttypes.TmpfsOptions) (string, error) {
14
+func ConvertTmpfsOptions(opt *mounttypes.TmpfsOptions, readOnly bool) (string, error) {
15 15
 	return "", fmt.Errorf("%s does not support tmpfs", runtime.GOOS)
16 16
 }