From 2b6550bb2e4d462d8afa687b59766bb13783ef1f Mon Sep 17 00:00:00 2001 From: Sebastiaan van Stijn Date: Mon, 16 Sep 2024 09:57:39 +0200 Subject: [PATCH 1/5] man: fix duplicate word in --feature flag description Signed-off-by: Sebastiaan van Stijn --- man/dockerd.8.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/man/dockerd.8.md b/man/dockerd.8.md index 47391497c4c16..ebcb3691be7aa 100644 --- a/man/dockerd.8.md +++ b/man/dockerd.8.md @@ -224,7 +224,7 @@ $ sudo dockerd --add-runtime runc=runc --add-runtime custom=/usr/local/bin/my-ru Enable the daemon experimental features. **--feature**=*NAME*=**true**|**false** - Enable or disable feature feature in the daemon. This option corresponds + Enable or disable a feature in the daemon. This option corresponds with the "features" field in the daemon.json configuration file. Using both the command-line option and the "features" field in the configuration file produces an error. The feature option can be specified multiple times From 50e83a0713b750d7d63e25482b4df3deefb5827d Mon Sep 17 00:00:00 2001 From: Sebastiaan van Stijn Date: Mon, 16 Sep 2024 10:26:20 +0200 Subject: [PATCH 2/5] man: dockerd: value is optional for --feature flag The --feature flag allows the boolean value to be omitted. If only a name is provided, the default is "true". Signed-off-by: Sebastiaan van Stijn --- man/dockerd.8.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/man/dockerd.8.md b/man/dockerd.8.md index ebcb3691be7aa..c93f809991db4 100644 --- a/man/dockerd.8.md +++ b/man/dockerd.8.md @@ -31,7 +31,7 @@ dockerd - Enable daemon mode [**--exec-opt**[=*[]*]] [**--exec-root**[=*/var/run/docker*]] [**--experimental**[=**false**]] -[**--feature**[=*NAME*=**true**|**false**] +[**--feature**[=*NAME*[=**true**|**false**]] [**--fixed-cidr**[=*FIXED-CIDR*]] [**--fixed-cidr-v6**[=*FIXED-CIDR-V6*]] [**-G**|**--group**[=*docker*]] @@ -223,13 +223,13 @@ $ sudo dockerd --add-runtime runc=runc --add-runtime custom=/usr/local/bin/my-ru **--experimental**="" Enable the daemon experimental features. -**--feature**=*NAME*=**true**|**false** +**--feature**=*NAME*[=**true**|**false**] Enable or disable a feature in the daemon. This option corresponds with the "features" field in the daemon.json configuration file. Using both the command-line option and the "features" field in the configuration file produces an error. The feature option can be specified multiple times to configure multiple features. - Usage example: `--feature containerd-snapshotter=true` + Usage example: `--feature containerd-snapshotter` or `--feature containerd-snapshotter=true`. **--fixed-cidr**="" IPv4 subnet for fixed IPs (e.g., 10.20.0.0/16); this subnet must be nested in From 758cca60367672e745e9c82d82dcdc6408129ccd Mon Sep 17 00:00:00 2001 From: Sebastiaan van Stijn Date: Mon, 16 Sep 2024 10:22:30 +0200 Subject: [PATCH 3/5] internal/opts: SetOpts,NamedSetOpts: test for optional value The value is optional for SetOpts (and NamedSetOpts), and implied "true" when omitted. This patch adds a test-case for this. Signed-off-by: Sebastiaan van Stijn --- internal/opts/opts_test.go | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/internal/opts/opts_test.go b/internal/opts/opts_test.go index 954c5baab3b5e..17edeb5f98f38 100644 --- a/internal/opts/opts_test.go +++ b/internal/opts/opts_test.go @@ -14,11 +14,12 @@ func TestSetOpts(t *testing.T) { assert.NilError(t, o.Set("feature-b=true")) assert.NilError(t, o.Set("feature-c=0")) assert.NilError(t, o.Set("feature-d=false")) + assert.NilError(t, o.Set("feature-e")) - expected := "map[feature-a:true feature-b:true feature-c:false feature-d:false]" + expected := "map[feature-a:true feature-b:true feature-c:false feature-d:false feature-e:true]" assert.Check(t, is.Equal(expected, o.String())) - expectedValue := map[string]bool{"feature-a": true, "feature-b": true, "feature-c": false, "feature-d": false} + expectedValue := map[string]bool{"feature-a": true, "feature-b": true, "feature-c": false, "feature-d": false, "feature-e": true} assert.Check(t, is.DeepEqual(expectedValue, o.GetAll())) err := o.Set("feature=not-a-bool") @@ -34,11 +35,12 @@ func TestNamedSetOpts(t *testing.T) { assert.NilError(t, o.Set("feature-b=true")) assert.NilError(t, o.Set("feature-c=0")) assert.NilError(t, o.Set("feature-d=false")) + assert.NilError(t, o.Set("feature-e")) - expected := "map[feature-a:true feature-b:true feature-c:false feature-d:false]" + expected := "map[feature-a:true feature-b:true feature-c:false feature-d:false feature-e:true]" assert.Check(t, is.Equal(expected, o.String())) - expectedValue := map[string]bool{"feature-a": true, "feature-b": true, "feature-c": false, "feature-d": false} + expectedValue := map[string]bool{"feature-a": true, "feature-b": true, "feature-c": false, "feature-d": false, "feature-e": true} assert.Check(t, is.DeepEqual(expectedValue, o.GetAll())) err := o.Set("feature=not-a-bool") From 908bb959e794f0c794c062415315b5af4fd13246 Mon Sep 17 00:00:00 2001 From: Sebastiaan van Stijn Date: Mon, 16 Sep 2024 10:39:20 +0200 Subject: [PATCH 4/5] internal/opts: SetOpts.Set: remove redundant var assignment Signed-off-by: Sebastiaan van Stijn --- internal/opts/opts.go | 1 - 1 file changed, 1 deletion(-) diff --git a/internal/opts/opts.go b/internal/opts/opts.go index 71a01731201ae..5c9c1d03688a3 100644 --- a/internal/opts/opts.go +++ b/internal/opts/opts.go @@ -20,7 +20,6 @@ func (opts *SetOpts) Set(value string) error { var isSet bool if !found { isSet = true - k = value } else { var err error isSet, err = strconv.ParseBool(v) From c2fc1f4a409c583ec74f874a1268bff22953555d Mon Sep 17 00:00:00 2001 From: Sebastiaan van Stijn Date: Mon, 16 Sep 2024 11:00:06 +0200 Subject: [PATCH 5/5] internal/opts: SetOpts: invalidate empty option-names Signed-off-by: Sebastiaan van Stijn --- internal/opts/opts.go | 4 ++++ internal/opts/opts_test.go | 8 ++++++++ 2 files changed, 12 insertions(+) diff --git a/internal/opts/opts.go b/internal/opts/opts.go index 5c9c1d03688a3..d518fbb690106 100644 --- a/internal/opts/opts.go +++ b/internal/opts/opts.go @@ -1,6 +1,7 @@ package opts import ( + "errors" "fmt" "strconv" "strings" @@ -17,6 +18,9 @@ type SetOpts struct { // internal map, by splitting on '='. func (opts *SetOpts) Set(value string) error { k, v, found := strings.Cut(value, "=") + if k == "" { + return errors.New("invalid option name: " + value) + } var isSet bool if !found { isSet = true diff --git a/internal/opts/opts_test.go b/internal/opts/opts_test.go index 17edeb5f98f38..70263d75aef16 100644 --- a/internal/opts/opts_test.go +++ b/internal/opts/opts_test.go @@ -24,6 +24,10 @@ func TestSetOpts(t *testing.T) { err := o.Set("feature=not-a-bool") assert.Check(t, is.Error(err, `strconv.ParseBool: parsing "not-a-bool": invalid syntax`)) + err = o.Set("feature=") + assert.Check(t, is.Error(err, `strconv.ParseBool: parsing "": invalid syntax`)) + err = o.Set("=true") + assert.Check(t, is.Error(err, `invalid option name: =true`)) } func TestNamedSetOpts(t *testing.T) { @@ -45,4 +49,8 @@ func TestNamedSetOpts(t *testing.T) { err := o.Set("feature=not-a-bool") assert.Check(t, is.Error(err, `strconv.ParseBool: parsing "not-a-bool": invalid syntax`)) + err = o.Set("feature=") + assert.Check(t, is.Error(err, `strconv.ParseBool: parsing "": invalid syntax`)) + err = o.Set("=true") + assert.Check(t, is.Error(err, `invalid option name: =true`)) }