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>
This commit is contained in:
Akihiro Suda 2016-11-08 06:46:23 +00:00
parent 69efb4652c
commit 3e3d3c8086
5 changed files with 42 additions and 13 deletions

View File

@ -414,7 +414,7 @@ func (container *Container) TmpfsMounts() ([]Mount, error) {
} }
for dest, mnt := range container.MountPoints { for dest, mnt := range container.MountPoints {
if mnt.Type == mounttypes.TypeTmpfs { if mnt.Type == mounttypes.TypeTmpfs {
data, err := volume.ConvertTmpfsOptions(mnt.Spec.TmpfsOptions) data, err := volume.ConvertTmpfsOptions(mnt.Spec.TmpfsOptions, mnt.Spec.ReadOnly)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@ -91,7 +91,7 @@ func validateMountConfig(mnt *mount.Mount, options ...func(*validateOpts)) error
if len(mnt.Source) != 0 { if len(mnt.Source) != 0 {
return &errMountConfig{mnt, errExtraField("Source")} return &errMountConfig{mnt, errExtraField("Source")}
} }
if _, err := ConvertTmpfsOptions(mnt.TmpfsOptions); err != nil { if _, err := ConvertTmpfsOptions(mnt.TmpfsOptions, mnt.ReadOnly); err != nil {
return &errMountConfig{mnt, err} return &errMountConfig{mnt, err}
} }
default: default:

View File

@ -13,16 +13,17 @@ import (
// for mount(2). // for mount(2).
// The logic is copy-pasted from daemon/cluster/executer/container.getMountMask. // The logic is copy-pasted from daemon/cluster/executer/container.getMountMask.
// It will be deduplicated when we migrated the cluster to the new mount scheme. // It will be deduplicated when we migrated the cluster to the new mount scheme.
func ConvertTmpfsOptions(opt *mounttypes.TmpfsOptions) (string, error) { func ConvertTmpfsOptions(opt *mounttypes.TmpfsOptions, readOnly bool) (string, error) {
if opt == nil {
return "", nil
}
var rawOpts []string var rawOpts []string
if opt.Mode != 0 { if readOnly {
rawOpts = append(rawOpts, "ro")
}
if opt != nil && opt.Mode != 0 {
rawOpts = append(rawOpts, fmt.Sprintf("mode=%o", opt.Mode)) rawOpts = append(rawOpts, fmt.Sprintf("mode=%o", opt.Mode))
} }
if opt.SizeBytes != 0 { if opt != nil && opt.SizeBytes != 0 {
// calculate suffix here, making this linux specific, but that is // calculate suffix here, making this linux specific, but that is
// okay, since API is that way anyways. // okay, since API is that way anyways.

View File

@ -3,6 +3,7 @@
package volume package volume
import ( import (
"strings"
"testing" "testing"
mounttypes "github.com/docker/docker/api/types/mount" mounttypes "github.com/docker/docker/api/types/mount"
@ -11,13 +12,40 @@ import (
func TestConvertTmpfsOptions(t *testing.T) { func TestConvertTmpfsOptions(t *testing.T) {
type testCase struct { type testCase struct {
opt mounttypes.TmpfsOptions opt mounttypes.TmpfsOptions
readOnly bool
expectedSubstrings []string
unexpectedSubstrings []string
} }
cases := []testCase{ cases := []testCase{
{mounttypes.TmpfsOptions{SizeBytes: 1024 * 1024, Mode: 0700}}, {
opt: mounttypes.TmpfsOptions{SizeBytes: 1024 * 1024, Mode: 0700},
readOnly: false,
expectedSubstrings: []string{"size=1m", "mode=700"},
unexpectedSubstrings: []string{"ro"},
},
{
opt: mounttypes.TmpfsOptions{},
readOnly: true,
expectedSubstrings: []string{"ro"},
unexpectedSubstrings: []string{},
},
} }
for _, c := range cases { for _, c := range cases {
if _, err := ConvertTmpfsOptions(&c.opt); err != nil { data, err := ConvertTmpfsOptions(&c.opt, c.readOnly)
t.Fatalf("could not convert %+v to string: %v", c.opt, err) if err != nil {
t.Fatalf("could not convert %+v (readOnly: %v) to string: %v",
c.opt, c.readOnly, err)
}
t.Logf("data=%q", data)
for _, s := range c.expectedSubstrings {
if !strings.Contains(data, s) {
t.Fatalf("expected substring: %s, got %v (case=%+v)", s, data, c)
}
}
for _, s := range c.unexpectedSubstrings {
if strings.Contains(data, s) {
t.Fatalf("unexpected substring: %s, got %v (case=%+v)", s, data, c)
}
} }
} }
} }

View File

@ -11,6 +11,6 @@ import (
// ConvertTmpfsOptions converts *mounttypes.TmpfsOptions to the raw option string // ConvertTmpfsOptions converts *mounttypes.TmpfsOptions to the raw option string
// for mount(2). // for mount(2).
func ConvertTmpfsOptions(opt *mounttypes.TmpfsOptions) (string, error) { func ConvertTmpfsOptions(opt *mounttypes.TmpfsOptions, readOnly bool) (string, error) {
return "", fmt.Errorf("%s does not support tmpfs", runtime.GOOS) return "", fmt.Errorf("%s does not support tmpfs", runtime.GOOS)
} }