From 634f54a047bfcd2ac95bdcdfe04da7eabe02cbec Mon Sep 17 00:00:00 2001 From: Stephen J Day Date: Wed, 20 Jul 2016 16:34:45 -0700 Subject: [PATCH] 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 --- api/client/service/opts.go | 29 ++++++++++++++---------- api/client/service/opts_test.go | 39 ++++++++++++++++++++++----------- 2 files changed, 43 insertions(+), 25 deletions(-) diff --git a/api/client/service/opts.go b/api/client/service/opts.go index fe39a0f832..76e0c03fff 100644 --- a/api/client/service/opts.go +++ b/api/client/service/opts.go @@ -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) diff --git a/api/client/service/opts_test.go b/api/client/service/opts_test.go index bdd7751e9a..48f6acc921 100644 --- a/api/client/service/opts_test.go +++ b/api/client/service/opts_test.go @@ -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)