From e336b774e57c8daff7e53410d65e13fcf91f6f96 Mon Sep 17 00:00:00 2001 From: Sebastiaan van Stijn Date: Wed, 26 Aug 2020 17:50:14 +0200 Subject: [PATCH] Service cap-add/cap-drop: add special "RESET" value This implements a special "RESET" value that can be used to reset the list of capabilities to add/drop when updating a service. Given the following service; | CapDrop | CapAdd | | -------------- | ------------- | | CAP_SOME_CAP | | When updating the service, and applying `--cap-drop RESET`, the "drop" list is reset to its default: | CapDrop | CapAdd | | -------------- | ------------- | | | | When updating the service, and applying `--cap-drop RESET`, combined with `--cap-add CAP_SOME_CAP` and `--cap-drop CAP_SOME_OTHER_CAP`: | CapDrop | CapAdd | | -------------- | ------------- | | CAP_FOO_CAP | CAP_SOME_CAP | Signed-off-by: Sebastiaan van Stijn --- cli/command/service/update.go | 8 ++++++++ cli/command/service/update_test.go | 20 ++++++++++++++++++++ opts/capabilities.go | 6 +++++- 3 files changed, 33 insertions(+), 1 deletion(-) diff --git a/cli/command/service/update.go b/cli/command/service/update.go index cdda2d161901..73aa32024670 100644 --- a/cli/command/service/update.go +++ b/cli/command/service/update.go @@ -1420,6 +1420,14 @@ func updateCapabilities(flags *pflag.FlagSet, containerSpec *swarm.ContainerSpec if flags.Changed(flagCapDrop) { toDrop = opts.CapabilitiesMap(flags.Lookup(flagCapDrop).Value.(*opts.ListOpts).GetAll()) } + if _, ok := toAdd[opts.ResetCapabilities]; ok { + delete(toAdd, opts.ResetCapabilities) + capAdd = make(map[string]struct{}) + } + if _, ok := toDrop[opts.ResetCapabilities]; ok { + delete(toDrop, opts.ResetCapabilities) + capDrop = make(map[string]struct{}) + } if _, ok := toAdd[opts.AllCapabilities]; ok { // Special case: "adding" capabilities takes precedence over "dropping", // therefore adding "ALL" capabilities resets all dropped capabilities. diff --git a/cli/command/service/update_test.go b/cli/command/service/update_test.go index 19f1abd02a95..33017ea27aad 100644 --- a/cli/command/service/update_test.go +++ b/cli/command/service/update_test.go @@ -1468,6 +1468,26 @@ func TestUpdateCaps(t *testing.T) { expectedAdd: []string{"CAP_AAA", "CAP_BBB", "CAP_CCC", "CAP_DDD"}, expectedDrop: []string{"CAP_WWW", "CAP_XXX", "CAP_YYY", "CAP_ZZZ"}, }, + { + name: "Reset capabilities", + flagAdd: []string{"RESET"}, + flagDrop: []string{"RESET"}, + spec: &swarm.ContainerSpec{ + CapabilityAdd: []string{"CAP_AAA", "CAP_BBB", "CAP_CCC", "CAP_DDD"}, + CapabilityDrop: []string{"CAP_WWW", "CAP_XXX", "CAP_YYY", "CAP_ZZZ"}, + }, + }, + { + name: "Reset capabilities, and update after", + flagAdd: []string{"RESET", "CAP_ADD_ONE", "CAP_FOO"}, + flagDrop: []string{"RESET", "CAP_DROP_ONE", "CAP_FOO"}, + spec: &swarm.ContainerSpec{ + CapabilityAdd: []string{"CAP_AAA", "CAP_BBB", "CAP_CCC", "CAP_DDD"}, + CapabilityDrop: []string{"CAP_WWW", "CAP_XXX", "CAP_YYY", "CAP_ZZZ"}, + }, + expectedAdd: []string{"CAP_ADD_ONE", "CAP_FOO"}, + expectedDrop: []string{"CAP_DROP_ONE"}, + }, } for _, tc := range tests { diff --git a/opts/capabilities.go b/opts/capabilities.go index 96c96b48643f..5d53d2b9c5ab 100644 --- a/opts/capabilities.go +++ b/opts/capabilities.go @@ -8,6 +8,10 @@ import ( const ( // AllCapabilities is a special value to add or drop all capabilities AllCapabilities = "ALL" + + // ResetCapabilities is a special value to reset capabilities when updating. + // This value should only be used when updating, not used on "create". + ResetCapabilities = "RESET" ) // NormalizeCapability normalizes a capability by upper-casing, trimming white space @@ -19,7 +23,7 @@ const ( // handled by the daemon. func NormalizeCapability(cap string) string { cap = strings.ToUpper(strings.TrimSpace(cap)) - if cap == AllCapabilities { + if cap == AllCapabilities || cap == ResetCapabilities { return cap } if !strings.HasPrefix(cap, "CAP_") {