diff --git a/cli/command/service/create.go b/cli/command/service/create.go index 6aca4635ae..d6c3ebdb9c 100644 --- a/cli/command/service/create.go +++ b/cli/command/service/create.go @@ -37,10 +37,10 @@ func newCreateCommand(dockerCli *command.DockerCli) *cobra.Command { flags.VarP(&opts.env, flagEnv, "e", "Set environment variables") flags.Var(&opts.envFile, flagEnvFile, "Read in a file of environment variables") flags.Var(&opts.mounts, flagMount, "Attach a filesystem mount to the service") - flags.StringSliceVar(&opts.constraints, flagConstraint, []string{}, "Placement constraints") - flags.StringSliceVar(&opts.networks, flagNetwork, []string{}, "Network attachments") + flags.Var(&opts.constraints, flagConstraint, "Placement constraints") + flags.Var(&opts.networks, flagNetwork, "Network attachments") flags.VarP(&opts.endpoint.ports, flagPublish, "p", "Publish a port as a node port") - flags.StringSliceVar(&opts.groups, flagGroup, []string{}, "Set one or more supplementary user groups for the container") + flags.Var(&opts.groups, flagGroup, "Set one or more supplementary user groups for the container") flags.Var(&opts.dns, flagDNS, "Set custom DNS servers") flags.Var(&opts.dnsOptions, flagDNSOptions, "Set DNS options") flags.Var(&opts.dnsSearch, flagDNSSearch, "Set custom DNS search domains") diff --git a/cli/command/service/opts.go b/cli/command/service/opts.go index 8de8b173ef..827c4e5cdc 100644 --- a/cli/command/service/opts.go +++ b/cli/command/service/opts.go @@ -32,7 +32,7 @@ func (m *memBytes) Set(value string) error { } func (m *memBytes) Type() string { - return "MemoryBytes" + return "bytes" } func (m *memBytes) Value() int64 { @@ -71,9 +71,9 @@ func (d *DurationOpt) Set(s string) error { return err } -// Type returns the type of this option +// Type returns the type of this option, which will be displayed in `--help` output func (d *DurationOpt) Type() string { - return "duration-ptr" + return "duration" } // String returns a string repr of this option @@ -101,9 +101,9 @@ func (i *Uint64Opt) Set(s string) error { return err } -// Type returns the type of this option +// Type returns the type of this option, which will be displayed in `--help` output func (i *Uint64Opt) Type() string { - return "uint64-ptr" + return "uint" } // String returns a string repr of this option @@ -119,12 +119,32 @@ func (i *Uint64Opt) Value() *uint64 { return i.value } +type floatValue float32 + +func (f *floatValue) Set(s string) error { + v, err := strconv.ParseFloat(s, 32) + *f = floatValue(v) + return err +} + +func (f *floatValue) Type() string { + return "float" +} + +func (f *floatValue) String() string { + return strconv.FormatFloat(float64(*f), 'g', -1, 32) +} + +func (f *floatValue) Value() float32 { + return float32(*f) +} + type updateOptions struct { parallelism uint64 delay time.Duration monitor time.Duration onFailure string - maxFailureRatio float32 + maxFailureRatio floatValue } type resourceOptions struct { @@ -293,7 +313,7 @@ type serviceOptions struct { envFile opts.ListOpts workdir string user string - groups []string + groups opts.ListOpts tty bool mounts opts.MountOpt dns opts.ListOpts @@ -307,9 +327,9 @@ type serviceOptions struct { mode string restartPolicy restartPolicyOptions - constraints []string + constraints opts.ListOpts update updateOptions - networks []string + networks opts.ListOpts endpoint endpointOptions registryAuth bool @@ -322,16 +342,19 @@ type serviceOptions struct { func newServiceOptions() *serviceOptions { return &serviceOptions{ labels: opts.NewListOpts(runconfigopts.ValidateEnv), + constraints: opts.NewListOpts(nil), containerLabels: opts.NewListOpts(runconfigopts.ValidateEnv), env: opts.NewListOpts(runconfigopts.ValidateEnv), envFile: opts.NewListOpts(nil), endpoint: endpointOptions{ ports: opts.NewListOpts(ValidatePort), }, + groups: opts.NewListOpts(nil), logDriver: newLogDriverOptions(), dns: opts.NewListOpts(opts.ValidateIPAddress), dnsOptions: opts.NewListOpts(nil), dnsSearch: opts.NewListOpts(opts.ValidateDNSSearch), + networks: opts.NewListOpts(nil), } } @@ -371,7 +394,7 @@ func (opts *serviceOptions) ToService() (swarm.ServiceSpec, error) { Labels: runconfigopts.ConvertKVStringsToMap(opts.containerLabels.GetAll()), Dir: opts.workdir, User: opts.user, - Groups: opts.groups, + Groups: opts.groups.GetAll(), TTY: opts.tty, Mounts: opts.mounts.Value(), DNSConfig: &swarm.DNSConfig{ @@ -381,22 +404,22 @@ func (opts *serviceOptions) ToService() (swarm.ServiceSpec, error) { }, StopGracePeriod: opts.stopGrace.Value(), }, - Networks: convertNetworks(opts.networks), + Networks: convertNetworks(opts.networks.GetAll()), Resources: opts.resources.ToResourceRequirements(), RestartPolicy: opts.restartPolicy.ToRestartPolicy(), Placement: &swarm.Placement{ - Constraints: opts.constraints, + Constraints: opts.constraints.GetAll(), }, LogDriver: opts.logDriver.toLogDriver(), }, - Networks: convertNetworks(opts.networks), + Networks: convertNetworks(opts.networks.GetAll()), Mode: swarm.ServiceMode{}, UpdateConfig: &swarm.UpdateConfig{ Parallelism: opts.update.parallelism, Delay: opts.update.delay, Monitor: opts.update.monitor, FailureAction: opts.update.onFailure, - MaxFailureRatio: opts.update.maxFailureRatio, + MaxFailureRatio: opts.update.maxFailureRatio.Value(), }, EndpointSpec: opts.endpoint.ToEndpointSpec(), } @@ -449,7 +472,7 @@ func addServiceFlags(cmd *cobra.Command, opts *serviceOptions) { flags.DurationVar(&opts.update.delay, flagUpdateDelay, time.Duration(0), "Delay between updates (ns|us|ms|s|m|h) (default 0s)") flags.DurationVar(&opts.update.monitor, flagUpdateMonitor, time.Duration(0), "Duration after each task update to monitor for failure (ns|us|ms|s|m|h) (default 0s)") flags.StringVar(&opts.update.onFailure, flagUpdateFailureAction, "pause", "Action on update failure (pause|continue)") - flags.Float32Var(&opts.update.maxFailureRatio, flagUpdateMaxFailureRatio, 0, "Failure rate to tolerate during an update") + flags.Var(&opts.update.maxFailureRatio, flagUpdateMaxFailureRatio, "Failure rate to tolerate during an update") flags.StringVar(&opts.endpoint.mode, flagEndpointMode, "", "Endpoint mode (vip or dnsrr)") diff --git a/cli/command/service/update.go b/cli/command/service/update.go index d3088720a0..4a77229497 100644 --- a/cli/command/service/update.go +++ b/cli/command/service/update.go @@ -55,9 +55,9 @@ func newUpdateCommand(dockerCli *command.DockerCli) *cobra.Command { flags.Var(&opts.containerLabels, flagContainerLabelAdd, "Add or update a container label") flags.Var(&opts.env, flagEnvAdd, "Add or update an environment variable") flags.Var(&opts.mounts, flagMountAdd, "Add or update a mount on a service") - flags.StringSliceVar(&opts.constraints, flagConstraintAdd, []string{}, "Add or update a placement constraint") + flags.Var(&opts.constraints, flagConstraintAdd, "Add or update a placement constraint") flags.Var(&opts.endpoint.ports, flagPublishAdd, "Add or update a published port") - flags.StringSliceVar(&opts.groups, flagGroupAdd, []string{}, "Add an additional supplementary user group to the container") + flags.Var(&opts.groups, flagGroupAdd, "Add an additional supplementary user group to the container") flags.Var(&opts.dns, flagDNSAdd, "Add or update custom DNS servers") flags.Var(&opts.dnsOptions, flagDNSOptionsAdd, "Add or update DNS options") flags.Var(&opts.dnsSearch, flagDNSSearchAdd, "Add or update custom DNS search domains") @@ -139,9 +139,9 @@ func updateService(flags *pflag.FlagSet, spec *swarm.ServiceSpec) error { } } - updateFloat32 := func(flag string, field *float32) { + updateFloatValue := func(flag string, field *float32) { if flags.Changed(flag) { - *field, _ = flags.GetFloat32(flag) + *field = flags.Lookup(flag).Value.(*floatValue).Value() } } @@ -238,7 +238,7 @@ func updateService(flags *pflag.FlagSet, spec *swarm.ServiceSpec) error { updateDuration(flagUpdateDelay, &spec.UpdateConfig.Delay) updateDuration(flagUpdateMonitor, &spec.UpdateConfig.Monitor) updateString(flagUpdateFailureAction, &spec.UpdateConfig.FailureAction) - updateFloat32(flagUpdateMaxFailureRatio, &spec.UpdateConfig.MaxFailureRatio) + updateFloatValue(flagUpdateMaxFailureRatio, &spec.UpdateConfig.MaxFailureRatio) } if flags.Changed(flagEndpointMode) { @@ -322,11 +322,22 @@ func anyChanged(flags *pflag.FlagSet, fields ...string) bool { } func updatePlacement(flags *pflag.FlagSet, placement *swarm.Placement) { - field, _ := flags.GetStringSlice(flagConstraintAdd) - placement.Constraints = append(placement.Constraints, field...) - + if flags.Changed(flagConstraintAdd) { + values := flags.Lookup(flagConstraintAdd).Value.(*opts.ListOpts).GetAll() + placement.Constraints = append(placement.Constraints, values...) + } toRemove := buildToRemoveSet(flags, flagConstraintRemove) - placement.Constraints = removeItems(placement.Constraints, toRemove, itemKey) + + newConstraints := []string{} + for _, constraint := range placement.Constraints { + if _, exists := toRemove[constraint]; !exists { + newConstraints = append(newConstraints, constraint) + } + } + // Sort so that result is predictable. + sort.Strings(newConstraints) + + placement.Constraints = newConstraints } func updateContainerLabels(flags *pflag.FlagSet, field *map[string]string) { @@ -479,10 +490,7 @@ func updateMounts(flags *pflag.FlagSet, mounts *[]mounttypes.Mount) error { func updateGroups(flags *pflag.FlagSet, groups *[]string) error { if flags.Changed(flagGroupAdd) { - values, err := flags.GetStringSlice(flagGroupAdd) - if err != nil { - return err - } + values := flags.Lookup(flagGroupAdd).Value.(*opts.ListOpts).GetAll() *groups = append(*groups, values...) } toRemove := buildToRemoveSet(flags, flagGroupRemove) diff --git a/docs/reference/commandline/service_create.md b/docs/reference/commandline/service_create.md index c058616a07..d659a60d19 100644 --- a/docs/reference/commandline/service_create.md +++ b/docs/reference/commandline/service_create.md @@ -21,48 +21,48 @@ Usage: docker service create [OPTIONS] IMAGE [COMMAND] [ARG...] Create a new service Options: - --constraint value Placement constraints (default []) - --container-label value Service container labels (default []) + --constraint list Placement constraints (default []) + --container-label list Container labels (default []) --dns list Set custom DNS servers (default []) --dns-options list Set DNS options (default []) --dns-search list Set custom DNS search domains (default []) --endpoint-mode string Endpoint mode (vip or dnsrr) - -e, --env value Set environment variables (default []) - --env-file value Read in a file of environment variables (default []) - --group value Set one or more supplementary user groups for the container (default []) + -e, --env list Set environment variables (default []) + --env-file list Read in a file of environment variables (default []) + --group list Set one or more supplementary user groups for the container (default []) --health-cmd string Command to run to check health - --health-interval duration Time between running the check (ns|us|ms|s|m|h) (default 0s) + --health-interval duration Time between running the check (default none) --health-retries int Consecutive failures needed to report unhealthy - --health-timeout duration Maximum time to allow one check to run (ns|us|ms|s|m|h) (default 0s) + --health-timeout duration Maximum time to allow one check to run (default none) --help Print usage - --hostname Service containers hostname - -l, --label value Service labels (default []) - --limit-cpu value Limit CPUs (default 0.000) - --limit-memory value Limit Memory (default 0 B) + --hostname string Container hostname + -l, --label list Service labels (default []) + --limit-cpu decimal Limit CPUs (default 0.000) + --limit-memory bytes Limit Memory (default 0 B) --log-driver string Logging driver for service - --log-opt value Logging driver options (default []) + --log-opt list Logging driver options (default []) --mode string Service mode (replicated or global) (default "replicated") - --mount value Attach a filesystem mount to the service + --mount mount Attach a filesystem mount to the service --name string Service name - --network value Network attachments (default []) + --network list Network attachments (default []) --no-healthcheck Disable any container-specified HEALTHCHECK - -p, --publish value Publish a port as a node port (default []) - --replicas value Number of tasks (default none) - --reserve-cpu value Reserve CPUs (default 0.000) - --reserve-memory value Reserve Memory (default 0 B) + -p, --publish list Publish a port as a node port (default []) + --replicas uint Number of tasks (default none) + --reserve-cpu decimal Reserve CPUs (default 0.000) + --reserve-memory bytes Reserve Memory (default 0 B) --restart-condition string Restart when condition is met (none, on-failure, or any) - --restart-delay value Delay between restart attempts (default none) - --restart-max-attempts value Maximum number of restarts before giving up (default none) - --restart-window value Window used to evaluate the restart policy (default none) - --stop-grace-period value Time to wait before force killing a container (default none) + --restart-delay duration Delay between restart attempts (default none) + --restart-max-attempts uint Maximum number of restarts before giving up (default none) + --restart-window duration Window used to evaluate the restart policy (default none) + --stop-grace-period duration Time to wait before force killing a container (default none) -t, --tty Allocate a pseudo-TTY --update-delay duration Delay between updates (ns|us|ms|s|m|h) (default 0s) --update-failure-action string Action on update failure (pause|continue) (default "pause") - --update-max-failure-ratio value Failure rate to tolerate during an update + --update-max-failure-ratio float Failure rate to tolerate during an update --update-monitor duration Duration after each task update to monitor for failure (ns|us|ms|s|m|h) (default 0s) --update-parallelism uint Maximum number of tasks updated simultaneously (0 to update all at once) (default 1) -u, --user string Username or UID (format: [:]) - --with-registry-auth Send registry authentication details to Swarm agents + --with-registry-auth Send registry authentication details to swarm agents -w, --workdir string Working directory inside the container ``` diff --git a/docs/reference/commandline/service_update.md b/docs/reference/commandline/service_update.md index bf40aa4446..f321b31ddc 100644 --- a/docs/reference/commandline/service_update.md +++ b/docs/reference/commandline/service_update.md @@ -21,58 +21,58 @@ Usage: docker service update [OPTIONS] SERVICE Update a service Options: - --args string Service command args - --constraint-add stringSlice Add or update a placement constraint - --constraint-rm list Remove a constraint (default []) - --container-label-add list Add or update a container label (default []) - --container-label-rm list Remove a container label by its key (default []) - --dns-add list Add or update custom DNS servers (default []) - --dns-options-add list Add or update DNS options (default []) - --dns-options-rm list Remove DNS options (default []) - --dns-rm list Remove custom DNS servers (default []) - --dns-search-add list Add or update custom DNS search domains (default []) - --dns-search-rm list Remove DNS search domains (default []) - --endpoint-mode string Endpoint mode (vip or dnsrr) - --env-add list Add or update an environment variable (default []) - --env-rm list Remove an environment variable (default []) - --force Force update even if no changes require it - --group-add stringSlice Add an additional supplementary user group to the container - --group-rm list Remove a previously added supplementary user group from the container (default []) - --health-cmd string Command to run to check health - --health-interval duration Time between running the check (ns|us|ms|s|m|h) (default 0s) - --health-retries int Consecutive failures needed to report unhealthy - --health-timeout duration Maximum time to allow one check to run (ns|us|ms|s|m|h) (default 0s) - --help Print usage - --image string Service image tag - --label-add list Add or update a service label (default []) - --label-rm list Remove a label by its key (default []) - --limit-cpu NanoCPUs Limit CPUs (default 0.000) - --limit-memory MemoryBytes Limit Memory (default 0 B) - --log-driver string Logging driver for service - --log-opt list Logging driver options (default []) - --mount-add mount Add or update a mount on a service - --mount-rm list Remove a mount by its target path (default []) - --no-healthcheck Disable any container-specified HEALTHCHECK - --publish-add list Add or update a published port (default []) - --publish-rm list Remove a published port by its target port (default []) - --replicas uint64-ptr Number of tasks (default none) - --reserve-cpu NanoCPUs Reserve CPUs (default 0.000) - --reserve-memory MemoryBytes Reserve Memory (default 0 B) - --restart-condition string Restart when condition is met (none, on-failure, or any) - --restart-delay duration-ptr Delay between restart attempts (default none) - --restart-max-attempts uint64-ptr Maximum number of restarts before giving up (default none) - --restart-window duration-ptr Window used to evaluate the restart policy (default none) - --rollback Rollback to previous specification - --stop-grace-period duration-ptr Time to wait before force killing a container (default none) - -t, --tty Allocate a pseudo-TTY - --update-delay duration Delay between updates (ns|us|ms|s|m|h) (default 0s) - --update-failure-action string Action on update failure (pause|continue) (default "pause") - --update-max-failure-ratio float32 Failure rate to tolerate during an update - --update-monitor duration Duration after each task update to monitor for failure (ns|us|ms|s|m|h) (default 0s) - --update-parallelism uint Maximum number of tasks updated simultaneously (0 to update all at once) (default 1) - -u, --user string Username or UID (format: [:]) - --with-registry-auth Send registry authentication details to swarm agents - -w, --workdir string Working directory inside the container + --args string Service command args + --constraint-add list Add or update a placement constraint (default []) + --constraint-rm list Remove a constraint (default []) + --container-label-add list Add or update a container label (default []) + --container-label-rm list Remove a container label by its key (default []) + --dns-add list Add or update custom DNS servers (default []) + --dns-options-add list Add or update DNS options (default []) + --dns-options-rm list Remove DNS options (default []) + --dns-rm list Remove custom DNS servers (default []) + --dns-search-add list Add or update custom DNS search domains (default []) + --dns-search-rm list Remove DNS search domains (default []) + --endpoint-mode string Endpoint mode (vip or dnsrr) + --env-add list Add or update an environment variable (default []) + --env-rm list Remove an environment variable (default []) + --force Force update even if no changes require it + --group-add list Add an additional supplementary user group to the container (default []) + --group-rm list Remove a previously added supplementary user group from the container (default []) + --health-cmd string Command to run to check health + --health-interval duration Time between running the check (default none) + --health-retries int Consecutive failures needed to report unhealthy + --health-timeout duration Maximum time to allow one check to run (default none) + --help Print usage + --image string Service image tag + --label-add list Add or update a service label (default []) + --label-rm list Remove a label by its key (default []) + --limit-cpu decimal Limit CPUs (default 0.000) + --limit-memory bytes Limit Memory (default 0 B) + --log-driver string Logging driver for service + --log-opt list Logging driver options (default []) + --mount-add mount Add or update a mount on a service + --mount-rm list Remove a mount by its target path (default []) + --no-healthcheck Disable any container-specified HEALTHCHECK + --publish-add list Add or update a published port (default []) + --publish-rm list Remove a published port by its target port (default []) + --replicas uint Number of tasks (default none) + --reserve-cpu decimal Reserve CPUs (default 0.000) + --reserve-memory bytes Reserve Memory (default 0 B) + --restart-condition string Restart when condition is met (none, on-failure, or any) + --restart-delay duration Delay between restart attempts (default none) + --restart-max-attempts uint Maximum number of restarts before giving up (default none) + --restart-window duration Window used to evaluate the restart policy (default none) + --rollback Rollback to previous specification + --stop-grace-period duration Time to wait before force killing a container (default none) + -t, --tty Allocate a pseudo-TTY + --update-delay duration Delay between updates (ns|us|ms|s|m|h) (default 0s) + --update-failure-action string Action on update failure (pause|continue) (default "pause") + --update-max-failure-ratio float Failure rate to tolerate during an update + --update-monitor duration Duration after each task update to monitor for failure (ns|us|ms|s|m|h) (default 0s) + --update-parallelism uint Maximum number of tasks updated simultaneously (0 to update all at once) (default 1) + -u, --user string Username or UID (format: [:]) + --with-registry-auth Send registry authentication details to swarm agents + -w, --workdir string Working directory inside the container ``` Updates a service as described by the specified parameters. This command has to be run targeting a manager node. diff --git a/opts/opts.go b/opts/opts.go index e452943ffc..0ac391add8 100644 --- a/opts/opts.go +++ b/opts/opts.go @@ -345,7 +345,7 @@ func (c *NanoCPUs) Set(value string) error { // Type returns the type func (c *NanoCPUs) Type() string { - return "NanoCPUs" + return "decimal" } // Value returns the value in int64