api/client/service: mount option defaults and aliases
Simplifies the mount option usage by providing common aliases for `source` and `target`. The default mount type is now volume. Signed-off-by: Stephen J Day <stephen.day@docker.com>
This commit is contained in:
parent
0a8a6f2dd7
commit
634f54a047
2 changed files with 43 additions and 25 deletions
|
@ -176,32 +176,37 @@ func (m *MountOpt) Set(value string) error {
|
|||
}
|
||||
}
|
||||
|
||||
mount.Type = swarm.MountTypeVolume // default to volume mounts
|
||||
// Set writable as the default
|
||||
for _, field := range fields {
|
||||
parts := strings.SplitN(field, "=", 2)
|
||||
if len(parts) == 1 && strings.ToLower(parts[0]) == "readonly" {
|
||||
mount.ReadOnly = true
|
||||
continue
|
||||
}
|
||||
key := strings.ToLower(parts[0])
|
||||
|
||||
if len(parts) == 1 && strings.ToLower(parts[0]) == "volume-nocopy" {
|
||||
volumeOptions().NoCopy = true
|
||||
continue
|
||||
if len(parts) == 1 {
|
||||
if key == "readonly" || key == "ro" {
|
||||
mount.ReadOnly = true
|
||||
continue
|
||||
}
|
||||
|
||||
if key == "volume-nocopy" {
|
||||
volumeOptions().NoCopy = true
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
if len(parts) != 2 {
|
||||
return fmt.Errorf("invalid field '%s' must be a key=value pair", field)
|
||||
}
|
||||
|
||||
key, value := parts[0], parts[1]
|
||||
switch strings.ToLower(key) {
|
||||
value := parts[1]
|
||||
switch key {
|
||||
case "type":
|
||||
mount.Type = swarm.MountType(strings.ToLower(value))
|
||||
case "source":
|
||||
case "source", "name", "src":
|
||||
mount.Source = value
|
||||
case "target":
|
||||
case "target", "dst", "dest", "destination", "path":
|
||||
mount.Target = value
|
||||
case "readonly":
|
||||
case "readonly", "ro":
|
||||
ro, err := strconv.ParseBool(value)
|
||||
if err != nil {
|
||||
return fmt.Errorf("invalid value for readonly: %s", value)
|
||||
|
|
|
@ -77,21 +77,33 @@ func TestMountOptString(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestMountOptSetNoError(t *testing.T) {
|
||||
var mount MountOpt
|
||||
assert.NilError(t, mount.Set("type=bind,target=/target,source=/foo"))
|
||||
for _, testcase := range []string{
|
||||
// tests several aliases that should have same result.
|
||||
"type=bind,target=/target,source=/source",
|
||||
"type=bind,src=/source,dst=/target",
|
||||
"type=bind,name=/source,dst=/target",
|
||||
"type=bind,name=/source,path=/target",
|
||||
} {
|
||||
var mount MountOpt
|
||||
|
||||
mounts := mount.Value()
|
||||
assert.Equal(t, len(mounts), 1)
|
||||
assert.Equal(t, mounts[0], swarm.Mount{
|
||||
Type: swarm.MountTypeBind,
|
||||
Source: "/foo",
|
||||
Target: "/target",
|
||||
})
|
||||
assert.NilError(t, mount.Set(testcase))
|
||||
|
||||
mounts := mount.Value()
|
||||
assert.Equal(t, len(mounts), 1)
|
||||
assert.Equal(t, mounts[0], swarm.Mount{
|
||||
Type: swarm.MountTypeBind,
|
||||
Source: "/source",
|
||||
Target: "/target",
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestMountOptSetErrorNoType(t *testing.T) {
|
||||
// TestMountOptDefaultType ensures that a mount without the type defaults to a
|
||||
// volume mount.
|
||||
func TestMountOptDefaultType(t *testing.T) {
|
||||
var mount MountOpt
|
||||
assert.Error(t, mount.Set("target=/target,source=/foo"), "type is required")
|
||||
assert.NilError(t, mount.Set("target=/target,source=/foo"))
|
||||
assert.Equal(t, mount.values[0].Type, swarm.MountTypeVolume)
|
||||
}
|
||||
|
||||
func TestMountOptSetErrorNoTarget(t *testing.T) {
|
||||
|
@ -109,12 +121,13 @@ func TestMountOptSetErrorInvalidField(t *testing.T) {
|
|||
assert.Error(t, mount.Set("type=volume,bogus"), "invalid field 'bogus'")
|
||||
}
|
||||
|
||||
func TestMountOptSetErrorInvalidWritable(t *testing.T) {
|
||||
func TestMountOptSetErrorInvalidReadOnly(t *testing.T) {
|
||||
var mount MountOpt
|
||||
assert.Error(t, mount.Set("type=volume,readonly=no"), "invalid value for readonly: no")
|
||||
assert.Error(t, mount.Set("type=volume,readonly=invalid"), "invalid value for readonly: invalid")
|
||||
}
|
||||
|
||||
func TestMountOptDefaultEnableWritable(t *testing.T) {
|
||||
func TestMountOptDefaultEnableReadOnly(t *testing.T) {
|
||||
var m MountOpt
|
||||
assert.NilError(t, m.Set("type=bind,target=/foo,source=/foo"))
|
||||
assert.Equal(t, m.values[0].ReadOnly, false)
|
||||
|
|
Loading…
Reference in a new issue