mirror of https://github.com/docker/cli.git
service: Add --cap-add & --cap-drop to service cmds
Signed-off-by: Albin Kerouanton <albin@akerouanton.name>
This commit is contained in:
parent
0db61ff6da
commit
c6ec4e081e
|
@ -97,6 +97,15 @@ ContainerSpec:
|
|||
{{- if .ContainerUser }}
|
||||
User: {{ .ContainerUser }}
|
||||
{{- end }}
|
||||
{{- if .HasCapabilities }}
|
||||
Capabilities:
|
||||
{{- if .HasCapabilityAdd }}
|
||||
Add: {{ .CapabilityAdd }}
|
||||
{{- end }}
|
||||
{{- if .HasCapabilityDrop }}
|
||||
Drop: {{ .CapabilityDrop }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- if .ContainerSysCtls }}
|
||||
SysCtls:
|
||||
{{- range $k, $v := .ContainerSysCtls }}
|
||||
|
@ -532,6 +541,26 @@ func (ctx *serviceInspectContext) Ports() []swarm.PortConfig {
|
|||
return ctx.Service.Endpoint.Ports
|
||||
}
|
||||
|
||||
func (ctx *serviceInspectContext) HasCapabilities() bool {
|
||||
return len(ctx.Service.Spec.TaskTemplate.ContainerSpec.CapabilityAdd) > 0 || len(ctx.Service.Spec.TaskTemplate.ContainerSpec.CapabilityDrop) > 0
|
||||
}
|
||||
|
||||
func (ctx *serviceInspectContext) HasCapabilityAdd() bool {
|
||||
return len(ctx.Service.Spec.TaskTemplate.ContainerSpec.CapabilityAdd) > 0
|
||||
}
|
||||
|
||||
func (ctx *serviceInspectContext) HasCapabilityDrop() bool {
|
||||
return len(ctx.Service.Spec.TaskTemplate.ContainerSpec.CapabilityDrop) > 0
|
||||
}
|
||||
|
||||
func (ctx *serviceInspectContext) CapabilityAdd() string {
|
||||
return strings.Join(ctx.Service.Spec.TaskTemplate.ContainerSpec.CapabilityAdd, ", ")
|
||||
}
|
||||
|
||||
func (ctx *serviceInspectContext) CapabilityDrop() string {
|
||||
return strings.Join(ctx.Service.Spec.TaskTemplate.ContainerSpec.CapabilityDrop, ", ")
|
||||
}
|
||||
|
||||
const (
|
||||
defaultServiceTableFormat = "table {{.ID}}\t{{.Name}}\t{{.Mode}}\t{{.Replicas}}\t{{.Image}}\t{{.Ports}}"
|
||||
|
||||
|
|
|
@ -506,6 +506,8 @@ type serviceOptions struct {
|
|||
dnsOption opts.ListOpts
|
||||
hosts opts.ListOpts
|
||||
sysctls opts.ListOpts
|
||||
capAdd opts.ListOpts
|
||||
capDrop opts.ListOpts
|
||||
|
||||
resources resourceOptions
|
||||
stopGrace opts.DurationOpt
|
||||
|
@ -549,6 +551,8 @@ func newServiceOptions() *serviceOptions {
|
|||
dnsSearch: opts.NewListOpts(opts.ValidateDNSSearch),
|
||||
hosts: opts.NewListOpts(opts.ValidateExtraHost),
|
||||
sysctls: opts.NewListOpts(nil),
|
||||
capAdd: opts.NewListOpts(nil),
|
||||
capDrop: opts.NewListOpts(nil),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -716,6 +720,8 @@ func (options *serviceOptions) ToService(ctx context.Context, apiClient client.N
|
|||
Healthcheck: healthConfig,
|
||||
Isolation: container.Isolation(options.isolation),
|
||||
Sysctls: opts.ConvertKVStringsToMap(options.sysctls.GetAll()),
|
||||
CapabilityAdd: options.capAdd.GetAll(),
|
||||
CapabilityDrop: options.capDrop.GetAll(),
|
||||
},
|
||||
Networks: networks,
|
||||
Resources: resources,
|
||||
|
@ -818,6 +824,10 @@ func addServiceFlags(flags *pflag.FlagSet, opts *serviceOptions, defaultFlagValu
|
|||
flags.StringVar(&opts.hostname, flagHostname, "", "Container hostname")
|
||||
flags.SetAnnotation(flagHostname, "version", []string{"1.25"})
|
||||
flags.Var(&opts.entrypoint, flagEntrypoint, "Overwrite the default ENTRYPOINT of the image")
|
||||
flags.Var(&opts.capAdd, flagCapAdd, "Add Linux capabilities")
|
||||
flags.SetAnnotation(flagCapAdd, "version", []string{"1.41"})
|
||||
flags.Var(&opts.capDrop, flagCapDrop, "Drop Linux capabilities")
|
||||
flags.SetAnnotation(flagCapDrop, "version", []string{"1.41"})
|
||||
|
||||
flags.Var(&opts.resources.limitCPU, flagLimitCPU, "Limit CPUs")
|
||||
flags.Var(&opts.resources.limitMemBytes, flagLimitMemory, "Limit Memory")
|
||||
|
@ -1001,6 +1011,8 @@ const (
|
|||
flagConfigAdd = "config-add"
|
||||
flagConfigRemove = "config-rm"
|
||||
flagIsolation = "isolation"
|
||||
flagCapAdd = "cap-add"
|
||||
flagCapDrop = "cap-drop"
|
||||
)
|
||||
|
||||
func validateAPIVersion(c swarm.ServiceSpec, serverAPIVersion string) error {
|
||||
|
|
|
@ -505,6 +505,7 @@ func updateService(ctx context.Context, apiClient client.NetworkAPIClient, flags
|
|||
}
|
||||
|
||||
updateString(flagStopSignal, &cspec.StopSignal)
|
||||
updateCapabilities(flags, cspec)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
@ -1349,3 +1350,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 {
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1342,3 +1342,74 @@ func TestUpdateCredSpec(t *testing.T) {
|
|||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestUpdateCaps(t *testing.T) {
|
||||
tests := []struct {
|
||||
// name is the name of the testcase
|
||||
name string
|
||||
// flagAdd is the value passed to --cap-add
|
||||
flagAdd []string
|
||||
// flagDrop is the value passed to --cap-drop
|
||||
flagDrop []string
|
||||
// spec is the original ContainerSpec, before being updated
|
||||
spec *swarm.ContainerSpec
|
||||
// expectedAdd is the set of requested caps the ContainerSpec should have once updated
|
||||
expectedAdd []string
|
||||
// expectedDrop is the set of dropped caps the ContainerSpec should have once updated
|
||||
expectedDrop []string
|
||||
}{
|
||||
{
|
||||
name: "Add new caps",
|
||||
flagAdd: []string{"NET_ADMIN"},
|
||||
flagDrop: []string{},
|
||||
spec: &swarm.ContainerSpec{},
|
||||
expectedAdd: []string{"NET_ADMIN"},
|
||||
expectedDrop: []string{},
|
||||
},
|
||||
{
|
||||
name: "Drop new caps",
|
||||
flagAdd: []string{},
|
||||
flagDrop: []string{"CAP_MKNOD"},
|
||||
spec: &swarm.ContainerSpec{},
|
||||
expectedAdd: []string{},
|
||||
expectedDrop: []string{"CAP_MKNOD"},
|
||||
},
|
||||
{
|
||||
name: "Add a previously dropped cap",
|
||||
flagAdd: []string{"NET_ADMIN"},
|
||||
flagDrop: []string{},
|
||||
spec: &swarm.ContainerSpec{
|
||||
CapabilityDrop: []string{"NET_ADMIN"},
|
||||
},
|
||||
expectedAdd: []string{"NET_ADMIN"},
|
||||
expectedDrop: []string{},
|
||||
},
|
||||
{
|
||||
name: "Drop a previously requested cap",
|
||||
flagAdd: []string{},
|
||||
flagDrop: []string{"CAP_MKNOD"},
|
||||
spec: &swarm.ContainerSpec{
|
||||
CapabilityAdd: []string{"CAP_MKNOD"},
|
||||
},
|
||||
expectedAdd: []string{},
|
||||
expectedDrop: []string{"CAP_MKNOD"},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range tests {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
flags := newUpdateCommand(nil).Flags()
|
||||
for _, cap := range tc.flagAdd {
|
||||
flags.Set(flagCapAdd, cap)
|
||||
}
|
||||
for _, cap := range tc.flagDrop {
|
||||
flags.Set(flagCapDrop, cap)
|
||||
}
|
||||
|
||||
updateCapabilities(flags, tc.spec)
|
||||
|
||||
assert.DeepEqual(t, tc.spec.CapabilityAdd, tc.expectedAdd)
|
||||
assert.DeepEqual(t, tc.spec.CapabilityDrop, tc.expectedDrop)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue