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 <github@gone.nl>
This commit is contained in:
Sebastiaan van Stijn 2020-08-26 17:50:14 +02:00
parent 60abe967b5
commit 23660be600
No known key found for this signature in database
GPG Key ID: 76698F39D527CE8C
4 changed files with 68 additions and 3 deletions

View File

@ -1409,9 +1409,17 @@ func updateCapabilities(flags *pflag.FlagSet, containerSpec *swarm.ContainerSpec
)
if flags.Changed(flagCapAdd) {
toAdd = opts.CapabilitiesMap(flags.Lookup(flagCapAdd).Value.(*opts.ListOpts).GetAll())
if toAdd[opts.ResetCapabilities] {
capAdd = make(map[string]bool)
delete(toAdd, opts.ResetCapabilities)
}
}
if flags.Changed(flagCapDrop) {
toDrop = opts.CapabilitiesMap(flags.Lookup(flagCapDrop).Value.(*opts.ListOpts).GetAll())
if toDrop[opts.ResetCapabilities] {
capDrop = make(map[string]bool)
delete(toDrop, opts.ResetCapabilities)
}
}
// First remove the capabilities to "drop" from the service's exiting

View File

@ -1522,6 +1522,50 @@ 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"},
},
expectedAdd: nil,
expectedDrop: nil,
},
{
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"},
},
{
name: "Reset capabilities, and add ALL",
flagAdd: []string{"RESET", "ALL"},
flagDrop: []string{"RESET", "ALL"},
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{"ALL"},
expectedDrop: nil,
},
{
name: "Add ALL and RESET",
flagAdd: []string{"ALL", "RESET"},
flagDrop: []string{"ALL", "RESET"},
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{"ALL"},
expectedDrop: nil,
},
}
for _, tc := range tests {

View File

@ -857,6 +857,7 @@ __docker_complete_capabilities_addable() {
CAP_SYS_TIME
CAP_SYS_TTY_CONFIG
CAP_WAKE_ALARM
RESET
)
COMPREPLY=( $( compgen -W "${capabilities[*]} ${capabilities[*]#CAP_}" -- "$cur" ) )
}
@ -881,6 +882,7 @@ __docker_complete_capabilities_droppable() {
CAP_SETPCAP
CAP_SETUID
CAP_SYS_CHROOT
RESET
)
COMPREPLY=( $( compgen -W "${capabilities[*]} ${capabilities[*]#CAP_}" -- "$cur" ) )
}

View File

@ -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_") {
@ -44,6 +48,9 @@ func CapabilitiesMap(caps []string) map[string]bool {
// lists are removed from the list of capabilities to drop. The special "ALL"
// capability is also taken into account.
//
// Note that the special "RESET" value is only used when updating an existing
// service, and will be ignored.
//
// Duplicates are removed, and the resulting lists are sorted.
func EffectiveCapAddCapDrop(add, drop []string) (capAdd, capDrop []string) {
var (
@ -64,11 +71,15 @@ func EffectiveCapAddCapDrop(add, drop []string) (capAdd, capDrop []string) {
// Adding a capability takes precedence, so skip dropping
continue
}
capDrop = append(capDrop, c)
if c != ResetCapabilities {
capDrop = append(capDrop, c)
}
}
for c := range addCaps {
capAdd = append(capAdd, c)
if c != ResetCapabilities {
capAdd = append(capAdd, c)
}
}
sort.Strings(capAdd)