-
Notifications
You must be signed in to change notification settings - Fork 2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add capabilities support to stack/service commands #2663
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -505,6 +505,7 @@ func updateService(ctx context.Context, apiClient client.NetworkAPIClient, flags | |
} | ||
|
||
updateString(flagStopSignal, &cspec.StopSignal) | ||
updateCapabilities(flags, cspec) | ||
|
||
return nil | ||
} | ||
|
@@ -1351,3 +1352,41 @@ func updateCredSpecConfig(flags *pflag.FlagSet, containerSpec *swarm.ContainerSp | |
containerSpec.Privileges.CredentialSpec = credSpec | ||
} | ||
} | ||
|
||
func updateCapabilities(flags *pflag.FlagSet, containerSpec *swarm.ContainerSpec) { | ||
var addToRemove, dropToRemove map[string]struct{} | ||
capAdd := containerSpec.CapabilityAdd | ||
capDrop := containerSpec.CapabilityDrop | ||
|
||
// First add the capabilities passed to --cap-add to the list of requested caps | ||
if flags.Changed(flagCapAdd) { | ||
caps := flags.Lookup(flagCapAdd).Value.(*opts.ListOpts).GetAll() | ||
capAdd = append(capAdd, caps...) | ||
|
||
dropToRemove = buildToRemoveSet(flags, flagCapAdd) | ||
} | ||
|
||
// And add the capabilities passed to --cap-drop to the list of dropped caps | ||
if flags.Changed(flagCapDrop) { | ||
caps := flags.Lookup(flagCapDrop).Value.(*opts.ListOpts).GetAll() | ||
capDrop = append(capDrop, caps...) | ||
|
||
addToRemove = buildToRemoveSet(flags, flagCapDrop) | ||
} | ||
|
||
// Then take care of removing caps passed to --cap-drop from the list of requested caps | ||
containerSpec.CapabilityAdd = make([]string, 0, len(capAdd)) | ||
for _, cap := range capAdd { | ||
if _, exists := addToRemove[cap]; !exists { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Looks like this is inconsistent with how # default capabilities
docker run -it --rm busybox sh -c 'touch foo && chown 123:456 foo && echo succesfully chowned'
# succesfully chowned
# dropping CAP_CHOWN
docker run -it --rm --cap-drop CAP_CHOWN busybox sh -c 'touch foo && chown 123:456 foo && echo succesfully chowned'
# chown: foo: Operation not permitted
# dropping *and* adding CAP_CHOWN
docker run -it --rm --cap-add CAP_CHOWN --cap-drop CAP_CHOWN busybox sh -c 'touch foo && chown 123:456 foo && echo succesfully chowned'
# succesfully chowned
docker create --name=test --cap-add CAP_CHOWN --cap-add CAP_CHOWN --cap-drop CAP_CHOWN --cap-drop CAP_CHOWN busybox
docker inspect --format 'CapAdd: {{json .HostConfig.CapAdd}} CapDrop: {{json .HostConfig.CapDrop}}' test
# CapAdd: ["CAP_CHOWN","CAP_CHOWN"] CapDrop: ["CAP_CHOWN","CAP_CHOWN"] Unfortunately, this is all rather involved, but what I think should happen is that;
When deploying a service using a docker-compose file, the docker-compose file is mostly handled as being "declarative". However, many of the issues outlined above also apply to compose-files, so similar handling is applied to compose files as well to prevent service churn. |
||
containerSpec.CapabilityAdd = append(containerSpec.CapabilityAdd, cap) | ||
} | ||
} | ||
|
||
// And remove the caps passed to --cap-add from the list of caps to drop | ||
containerSpec.CapabilityDrop = make([]string, 0, len(capDrop)) | ||
for _, cap := range capDrop { | ||
if _, exists := dropToRemove[cap]; !exists { | ||
containerSpec.CapabilityDrop = append(containerSpec.CapabilityDrop, cap) | ||
} | ||
} | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We may have to sort (Possibly the same will be needed for the For swarm services, we generally want the CLI/client to generate the spec and handle that spec with no (or very little) modifications on the server-side. The SwarmKit reconciliation loop will look for any change in the Service Spec to consider if a service needs updating or not. Currently, it the CLI does not do any normalization or sorting, which will mean that;
To prevent unneeded re-creation of tasks I think we should both normalize capabilities, remove duplicates, and sort them alphabetically. Possibly we could re-use
I noticed this when trying using the following; docker service create --detach --tty --cap-drop cAp_cHoWn --cap-drop CAP_CHOWN --cap-drop ChOwN --cap-drop CHOWN --name foo busybox docker service inspect --format '{{json .Spec.TaskTemplate.ContainerSpec.CapabilityDrop }}' foo | jq .
[
"cAp_cHoWn",
"CAP_CHOWN",
"ChOwN",
"CHOWN"
] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Probably should be checked if any changed to prevent churn;