зеркало из https://github.com/microsoft/docker.git
Support `--group-add` and `--group-rm` in `docker service create/update`
This fix tries to address the issue raised in 25304 to support `--group-add` and `--group-rm` in `docker service create`. This fix adds `--group-add` to `docker service create` and `docker service update`, adds `--group-rm` to `docker service update`. This fix updates docs for `docker service create` and `docker service update`: 1. Add `--group-add` to `docker service create` and `docker service update` 2. Add `--group-rm` to `docker service update` Signed-off-by: Yong Tang <yong.tang.github@outlook.com>
This commit is contained in:
Родитель
48659599cb
Коммит
b31969ee36
|
@ -399,6 +399,7 @@ type serviceOptions struct {
|
||||||
env opts.ListOpts
|
env opts.ListOpts
|
||||||
workdir string
|
workdir string
|
||||||
user string
|
user string
|
||||||
|
groups []string
|
||||||
mounts MountOpt
|
mounts MountOpt
|
||||||
|
|
||||||
resources resourceOptions
|
resources resourceOptions
|
||||||
|
@ -446,6 +447,7 @@ func (opts *serviceOptions) ToService() (swarm.ServiceSpec, error) {
|
||||||
Labels: runconfigopts.ConvertKVStringsToMap(opts.containerLabels.GetAll()),
|
Labels: runconfigopts.ConvertKVStringsToMap(opts.containerLabels.GetAll()),
|
||||||
Dir: opts.workdir,
|
Dir: opts.workdir,
|
||||||
User: opts.user,
|
User: opts.user,
|
||||||
|
Groups: opts.groups,
|
||||||
Mounts: opts.mounts.Value(),
|
Mounts: opts.mounts.Value(),
|
||||||
StopGracePeriod: opts.stopGrace.Value(),
|
StopGracePeriod: opts.stopGrace.Value(),
|
||||||
},
|
},
|
||||||
|
@ -491,6 +493,7 @@ func addServiceFlags(cmd *cobra.Command, opts *serviceOptions) {
|
||||||
|
|
||||||
flags.StringVarP(&opts.workdir, flagWorkdir, "w", "", "Working directory inside the container")
|
flags.StringVarP(&opts.workdir, flagWorkdir, "w", "", "Working directory inside the container")
|
||||||
flags.StringVarP(&opts.user, flagUser, "u", "", "Username or UID (format: <name|uid>[:<group|gid>])")
|
flags.StringVarP(&opts.user, flagUser, "u", "", "Username or UID (format: <name|uid>[:<group|gid>])")
|
||||||
|
flags.StringSliceVar(&opts.groups, flagGroupAdd, []string{}, "Add additional user groups to the container")
|
||||||
|
|
||||||
flags.Var(&opts.resources.limitCPU, flagLimitCPU, "Limit CPUs")
|
flags.Var(&opts.resources.limitCPU, flagLimitCPU, "Limit CPUs")
|
||||||
flags.Var(&opts.resources.limitMemBytes, flagLimitMemory, "Limit Memory")
|
flags.Var(&opts.resources.limitMemBytes, flagLimitMemory, "Limit Memory")
|
||||||
|
@ -528,6 +531,8 @@ const (
|
||||||
flagEnv = "env"
|
flagEnv = "env"
|
||||||
flagEnvRemove = "env-rm"
|
flagEnvRemove = "env-rm"
|
||||||
flagEnvAdd = "env-add"
|
flagEnvAdd = "env-add"
|
||||||
|
flagGroupAdd = "group-add"
|
||||||
|
flagGroupRemove = "group-rm"
|
||||||
flagLabel = "label"
|
flagLabel = "label"
|
||||||
flagLabelRemove = "label-rm"
|
flagLabelRemove = "label-rm"
|
||||||
flagLabelAdd = "label-add"
|
flagLabelAdd = "label-add"
|
||||||
|
|
|
@ -39,6 +39,7 @@ func newUpdateCommand(dockerCli *client.DockerCli) *cobra.Command {
|
||||||
addServiceFlags(cmd, opts)
|
addServiceFlags(cmd, opts)
|
||||||
|
|
||||||
flags.Var(newListOptsVar(), flagEnvRemove, "Remove an environment variable")
|
flags.Var(newListOptsVar(), flagEnvRemove, "Remove an environment variable")
|
||||||
|
flags.Var(newListOptsVar(), flagGroupRemove, "Remove previously added user groups from the container")
|
||||||
flags.Var(newListOptsVar(), flagLabelRemove, "Remove a label by its key")
|
flags.Var(newListOptsVar(), flagLabelRemove, "Remove a label by its key")
|
||||||
flags.Var(newListOptsVar(), flagContainerLabelRemove, "Remove a container label by its key")
|
flags.Var(newListOptsVar(), flagContainerLabelRemove, "Remove a container label by its key")
|
||||||
flags.Var(newListOptsVar(), flagMountRemove, "Remove a mount by its target path")
|
flags.Var(newListOptsVar(), flagMountRemove, "Remove a mount by its target path")
|
||||||
|
@ -211,6 +212,12 @@ func updateService(flags *pflag.FlagSet, spec *swarm.ServiceSpec) error {
|
||||||
spec.EndpointSpec.Mode = swarm.ResolutionMode(value)
|
spec.EndpointSpec.Mode = swarm.ResolutionMode(value)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if anyChanged(flags, flagGroupAdd, flagGroupRemove) {
|
||||||
|
if err := updateGroups(flags, &cspec.Groups); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if anyChanged(flags, flagPublishAdd, flagPublishRemove) {
|
if anyChanged(flags, flagPublishAdd, flagPublishRemove) {
|
||||||
if spec.EndpointSpec == nil {
|
if spec.EndpointSpec == nil {
|
||||||
spec.EndpointSpec = &swarm.EndpointSpec{}
|
spec.EndpointSpec = &swarm.EndpointSpec{}
|
||||||
|
@ -370,6 +377,29 @@ func updateMounts(flags *pflag.FlagSet, mounts *[]mounttypes.Mount) {
|
||||||
*mounts = newMounts
|
*mounts = newMounts
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func updateGroups(flags *pflag.FlagSet, groups *[]string) error {
|
||||||
|
if flags.Changed(flagGroupAdd) {
|
||||||
|
values, err := flags.GetStringSlice(flagGroupAdd)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
*groups = append(*groups, values...)
|
||||||
|
}
|
||||||
|
toRemove := buildToRemoveSet(flags, flagGroupRemove)
|
||||||
|
|
||||||
|
newGroups := []string{}
|
||||||
|
for _, group := range *groups {
|
||||||
|
if _, exists := toRemove[group]; !exists {
|
||||||
|
newGroups = append(newGroups, group)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Sort so that result is predictable.
|
||||||
|
sort.Strings(newGroups)
|
||||||
|
|
||||||
|
*groups = newGroups
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
type byPortConfig []swarm.PortConfig
|
type byPortConfig []swarm.PortConfig
|
||||||
|
|
||||||
func (r byPortConfig) Len() int { return len(r) }
|
func (r byPortConfig) Len() int { return len(r) }
|
||||||
|
|
|
@ -100,6 +100,23 @@ func TestUpdateEnvironmentWithDuplicateKeys(t *testing.T) {
|
||||||
assert.Equal(t, envs[0], "A=b")
|
assert.Equal(t, envs[0], "A=b")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestUpdateGroups(t *testing.T) {
|
||||||
|
flags := newUpdateCommand(nil).Flags()
|
||||||
|
flags.Set("group-add", "wheel")
|
||||||
|
flags.Set("group-add", "docker")
|
||||||
|
flags.Set("group-rm", "root")
|
||||||
|
flags.Set("group-add", "foo")
|
||||||
|
flags.Set("group-rm", "docker")
|
||||||
|
|
||||||
|
groups := []string{"bar", "root"}
|
||||||
|
|
||||||
|
updateGroups(flags, &groups)
|
||||||
|
assert.Equal(t, len(groups), 3)
|
||||||
|
assert.Equal(t, groups[0], "bar")
|
||||||
|
assert.Equal(t, groups[1], "foo")
|
||||||
|
assert.Equal(t, groups[2], "wheel")
|
||||||
|
}
|
||||||
|
|
||||||
func TestUpdateMounts(t *testing.T) {
|
func TestUpdateMounts(t *testing.T) {
|
||||||
flags := newUpdateCommand(nil).Flags()
|
flags := newUpdateCommand(nil).Flags()
|
||||||
flags.Set("mount-add", "type=volume,target=/toadd")
|
flags.Set("mount-add", "type=volume,target=/toadd")
|
||||||
|
|
|
@ -19,6 +19,7 @@ func containerSpecFromGRPC(c *swarmapi.ContainerSpec) types.ContainerSpec {
|
||||||
Env: c.Env,
|
Env: c.Env,
|
||||||
Dir: c.Dir,
|
Dir: c.Dir,
|
||||||
User: c.User,
|
User: c.User,
|
||||||
|
Groups: c.Groups,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Mounts
|
// Mounts
|
||||||
|
@ -67,6 +68,7 @@ func containerToGRPC(c types.ContainerSpec) (*swarmapi.ContainerSpec, error) {
|
||||||
Env: c.Env,
|
Env: c.Env,
|
||||||
Dir: c.Dir,
|
Dir: c.Dir,
|
||||||
User: c.User,
|
User: c.User,
|
||||||
|
Groups: c.Groups,
|
||||||
}
|
}
|
||||||
|
|
||||||
if c.StopGracePeriod != nil {
|
if c.StopGracePeriod != nil {
|
||||||
|
|
|
@ -20,6 +20,7 @@ Options:
|
||||||
--container-label value Service container labels (default [])
|
--container-label value Service container labels (default [])
|
||||||
--endpoint-mode string Endpoint mode (vip or dnsrr)
|
--endpoint-mode string Endpoint mode (vip or dnsrr)
|
||||||
-e, --env value Set environment variables (default [])
|
-e, --env value Set environment variables (default [])
|
||||||
|
--group-add value Add additional user groups to the container (default [])
|
||||||
--help Print usage
|
--help Print usage
|
||||||
-l, --label value Service labels (default [])
|
-l, --label value Service labels (default [])
|
||||||
--limit-cpu value Limit CPUs (default 0.000)
|
--limit-cpu value Limit CPUs (default 0.000)
|
||||||
|
|
|
@ -24,6 +24,8 @@ Options:
|
||||||
--endpoint-mode string Endpoint mode (vip or dnsrr)
|
--endpoint-mode string Endpoint mode (vip or dnsrr)
|
||||||
--env-add value Add or update environment variables (default [])
|
--env-add value Add or update environment variables (default [])
|
||||||
--env-rm value Remove an environment variable (default [])
|
--env-rm value Remove an environment variable (default [])
|
||||||
|
--group-add value Add additional user groups to the container (default [])
|
||||||
|
--group-rm value Remove previously added user groups from the container (default [])
|
||||||
--help Print usage
|
--help Print usage
|
||||||
--image string Service image tag
|
--image string Service image tag
|
||||||
--label-add value Add or update service labels (default [])
|
--label-add value Add or update service labels (default [])
|
||||||
|
|
|
@ -220,3 +220,25 @@ func (s *DockerSwarmSuite) TestSwarmPublishAdd(c *check.C) {
|
||||||
c.Assert(err, checker.IsNil)
|
c.Assert(err, checker.IsNil)
|
||||||
c.Assert(strings.TrimSpace(out), checker.Equals, "[{ tcp 20 80}]")
|
c.Assert(strings.TrimSpace(out), checker.Equals, "[{ tcp 20 80}]")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *DockerSwarmSuite) TestSwarmServiceWithGroup(c *check.C) {
|
||||||
|
d := s.AddDaemon(c, true, true)
|
||||||
|
|
||||||
|
name := "top"
|
||||||
|
out, err := d.Cmd("service", "create", "--name", name, "--user", "root:root", "--group-add", "wheel", "--group-add", "audio", "--group-add", "staff", "--group-add", "777", "busybox", "sh", "-c", "id > /id && top")
|
||||||
|
c.Assert(err, checker.IsNil)
|
||||||
|
c.Assert(strings.TrimSpace(out), checker.Not(checker.Equals), "")
|
||||||
|
|
||||||
|
// make sure task has been deployed.
|
||||||
|
waitAndAssert(c, defaultReconciliationTimeout, d.checkActiveContainerCount, checker.Equals, 1)
|
||||||
|
|
||||||
|
out, err = d.Cmd("ps", "-q")
|
||||||
|
c.Assert(err, checker.IsNil)
|
||||||
|
c.Assert(strings.TrimSpace(out), checker.Not(checker.Equals), "")
|
||||||
|
|
||||||
|
container := strings.TrimSpace(out)
|
||||||
|
|
||||||
|
out, err = d.Cmd("exec", container, "cat", "/id")
|
||||||
|
c.Assert(err, checker.IsNil)
|
||||||
|
c.Assert(strings.TrimSpace(out), checker.Equals, "uid=0(root) gid=0(root) groups=10(wheel),29(audio),50(staff),777")
|
||||||
|
}
|
||||||
|
|
Загрузка…
Ссылка в новой задаче