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:
parent
69efb4652c
commit
3e3d3c8086
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
@ -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:
|
||||||
|
|
|
@ -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.
|
||||||
|
|
||||||
|
|
|
@ -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)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue