Make the CLI show defaults from the swarmkit defaults package

If no fields related to an update config or restart policy are
specified, these structs should not be created as part of the service,
to avoid hardcoding the current defaults.

Signed-off-by: Aaron Lehmann <aaron.lehmann@docker.com>
This commit is contained in:
Aaron Lehmann 2017-03-30 18:35:04 -07:00
parent 1d274e9acf
commit bbe1202410
7 changed files with 311 additions and 118 deletions

View File

@ -30,7 +30,7 @@ func newCreateCommand(dockerCli *command.DockerCli) *cobra.Command {
flags.StringVar(&opts.mode, flagMode, "replicated", "Service mode (replicated or global)") flags.StringVar(&opts.mode, flagMode, "replicated", "Service mode (replicated or global)")
flags.StringVar(&opts.name, flagName, "", "Service name") flags.StringVar(&opts.name, flagName, "", "Service name")
addServiceFlags(flags, opts) addServiceFlags(flags, opts, buildServiceDefaultFlagMapping())
flags.VarP(&opts.labels, flagLabel, "l", "Service labels") flags.VarP(&opts.labels, flagLabel, "l", "Service labels")
flags.Var(&opts.containerLabels, flagContainerLabel, "Container labels") flags.Var(&opts.containerLabels, flagContainerLabel, "Container labels")
@ -65,7 +65,7 @@ func runCreate(dockerCli *command.DockerCli, flags *pflag.FlagSet, opts *service
ctx := context.Background() ctx := context.Background()
service, err := opts.ToService(ctx, apiClient) service, err := opts.ToService(ctx, apiClient, flags)
if err != nil { if err != nil {
return err return err
} }

View File

@ -12,7 +12,10 @@ import (
"github.com/docker/docker/client" "github.com/docker/docker/client"
"github.com/docker/docker/opts" "github.com/docker/docker/opts"
runconfigopts "github.com/docker/docker/runconfig/opts" runconfigopts "github.com/docker/docker/runconfig/opts"
"github.com/docker/swarmkit/api"
"github.com/docker/swarmkit/api/defaults"
shlex "github.com/flynn-archive/go-shlex" shlex "github.com/flynn-archive/go-shlex"
gogotypes "github.com/gogo/protobuf/types"
"github.com/pkg/errors" "github.com/pkg/errors"
"github.com/spf13/pflag" "github.com/spf13/pflag"
"golang.org/x/net/context" "golang.org/x/net/context"
@ -177,6 +180,9 @@ func (s *ShlexOpt) Type() string {
} }
func (s *ShlexOpt) String() string { func (s *ShlexOpt) String() string {
if len(*s) == 0 {
return ""
}
return fmt.Sprint(*s) return fmt.Sprint(*s)
} }
@ -194,17 +200,77 @@ type updateOptions struct {
order string order string
} }
func (opts updateOptions) config() *swarm.UpdateConfig { func updateConfigFromDefaults(defaultUpdateConfig *api.UpdateConfig) *swarm.UpdateConfig {
defaultFailureAction := strings.ToLower(api.UpdateConfig_FailureAction_name[int32(defaultUpdateConfig.FailureAction)])
defaultMonitor, _ := gogotypes.DurationFromProto(defaultUpdateConfig.Monitor)
return &swarm.UpdateConfig{ return &swarm.UpdateConfig{
Parallelism: opts.parallelism, Parallelism: defaultUpdateConfig.Parallelism,
Delay: opts.delay, Delay: defaultUpdateConfig.Delay,
Monitor: opts.monitor, Monitor: defaultMonitor,
FailureAction: opts.onFailure, FailureAction: defaultFailureAction,
MaxFailureRatio: opts.maxFailureRatio.Value(), MaxFailureRatio: defaultUpdateConfig.MaxFailureRatio,
Order: opts.order, Order: defaultOrder(defaultUpdateConfig.Order),
} }
} }
func (opts updateOptions) updateConfig(flags *pflag.FlagSet) *swarm.UpdateConfig {
if !anyChanged(flags, flagUpdateParallelism, flagUpdateDelay, flagUpdateMonitor, flagUpdateFailureAction, flagUpdateMaxFailureRatio) {
return nil
}
updateConfig := updateConfigFromDefaults(defaults.Service.Update)
if flags.Changed(flagUpdateParallelism) {
updateConfig.Parallelism = opts.parallelism
}
if flags.Changed(flagUpdateDelay) {
updateConfig.Delay = opts.delay
}
if flags.Changed(flagUpdateMonitor) {
updateConfig.Monitor = opts.monitor
}
if flags.Changed(flagUpdateFailureAction) {
updateConfig.FailureAction = opts.onFailure
}
if flags.Changed(flagUpdateMaxFailureRatio) {
updateConfig.MaxFailureRatio = opts.maxFailureRatio.Value()
}
if flags.Changed(flagUpdateOrder) {
updateConfig.Order = opts.order
}
return updateConfig
}
func (opts updateOptions) rollbackConfig(flags *pflag.FlagSet) *swarm.UpdateConfig {
if !anyChanged(flags, flagRollbackParallelism, flagRollbackDelay, flagRollbackMonitor, flagRollbackFailureAction, flagRollbackMaxFailureRatio) {
return nil
}
updateConfig := updateConfigFromDefaults(defaults.Service.Rollback)
if flags.Changed(flagRollbackParallelism) {
updateConfig.Parallelism = opts.parallelism
}
if flags.Changed(flagRollbackDelay) {
updateConfig.Delay = opts.delay
}
if flags.Changed(flagRollbackMonitor) {
updateConfig.Monitor = opts.monitor
}
if flags.Changed(flagRollbackFailureAction) {
updateConfig.FailureAction = opts.onFailure
}
if flags.Changed(flagRollbackMaxFailureRatio) {
updateConfig.MaxFailureRatio = opts.maxFailureRatio.Value()
}
if flags.Changed(flagRollbackOrder) {
updateConfig.Order = opts.order
}
return updateConfig
}
type resourceOptions struct { type resourceOptions struct {
limitCPU opts.NanoCPUs limitCPU opts.NanoCPUs
limitMemBytes opts.MemBytes limitMemBytes opts.MemBytes
@ -232,13 +298,70 @@ type restartPolicyOptions struct {
window DurationOpt window DurationOpt
} }
func (r *restartPolicyOptions) ToRestartPolicy() *swarm.RestartPolicy { func defaultRestartPolicy() *swarm.RestartPolicy {
return &swarm.RestartPolicy{ defaultMaxAttempts := defaults.Service.Task.Restart.MaxAttempts
Condition: swarm.RestartPolicyCondition(r.condition), rp := &swarm.RestartPolicy{
Delay: r.delay.Value(), MaxAttempts: &defaultMaxAttempts,
MaxAttempts: r.maxAttempts.Value(),
Window: r.window.Value(),
} }
if defaults.Service.Task.Restart.Delay != nil {
defaultRestartDelay, _ := gogotypes.DurationFromProto(defaults.Service.Task.Restart.Delay)
rp.Delay = &defaultRestartDelay
}
if defaults.Service.Task.Restart.Window != nil {
defaultRestartWindow, _ := gogotypes.DurationFromProto(defaults.Service.Task.Restart.Window)
rp.Window = &defaultRestartWindow
}
rp.Condition = defaultRestartCondition()
return rp
}
func defaultRestartCondition() swarm.RestartPolicyCondition {
switch defaults.Service.Task.Restart.Condition {
case api.RestartOnNone:
return "none"
case api.RestartOnFailure:
return "on-failure"
case api.RestartOnAny:
return "any"
default:
return ""
}
}
func defaultOrder(order api.UpdateConfig_UpdateOrder) string {
switch order {
case api.UpdateConfig_STOP_FIRST:
return "stop-first"
case api.UpdateConfig_START_FIRST:
return "start-first"
default:
return ""
}
}
func (r *restartPolicyOptions) ToRestartPolicy(flags *pflag.FlagSet) *swarm.RestartPolicy {
if !anyChanged(flags, flagRestartDelay, flagRestartMaxAttempts, flagRestartWindow, flagRestartCondition) {
return nil
}
restartPolicy := defaultRestartPolicy()
if flags.Changed(flagRestartDelay) {
restartPolicy.Delay = r.delay.Value()
}
if flags.Changed(flagRestartCondition) {
restartPolicy.Condition = swarm.RestartPolicyCondition(r.condition)
}
if flags.Changed(flagRestartMaxAttempts) {
restartPolicy.MaxAttempts = r.maxAttempts.Value()
}
if flags.Changed(flagRestartWindow) {
restartPolicy.Window = r.window.Value()
}
return restartPolicy
} }
type credentialSpecOpt struct { type credentialSpecOpt struct {
@ -463,7 +586,14 @@ func (opts *serviceOptions) ToServiceMode() (swarm.ServiceMode, error) {
return serviceMode, nil return serviceMode, nil
} }
func (opts *serviceOptions) ToService(ctx context.Context, apiClient client.APIClient) (swarm.ServiceSpec, error) { func (opts *serviceOptions) ToStopGracePeriod(flags *pflag.FlagSet) *time.Duration {
if flags.Changed(flagStopGracePeriod) {
return opts.stopGrace.Value()
}
return nil
}
func (opts *serviceOptions) ToService(ctx context.Context, apiClient client.APIClient, flags *pflag.FlagSet) (swarm.ServiceSpec, error) {
var service swarm.ServiceSpec var service swarm.ServiceSpec
envVariables, err := runconfigopts.ReadKVStrings(opts.envFile.GetAll(), opts.env.GetAll()) envVariables, err := runconfigopts.ReadKVStrings(opts.envFile.GetAll(), opts.env.GetAll())
@ -526,13 +656,13 @@ func (opts *serviceOptions) ToService(ctx context.Context, apiClient client.APIC
Options: opts.dnsOption.GetAll(), Options: opts.dnsOption.GetAll(),
}, },
Hosts: convertExtraHostsToSwarmHosts(opts.hosts.GetAll()), Hosts: convertExtraHostsToSwarmHosts(opts.hosts.GetAll()),
StopGracePeriod: opts.stopGrace.Value(), StopGracePeriod: opts.ToStopGracePeriod(flags),
Secrets: nil, Secrets: nil,
Healthcheck: healthConfig, Healthcheck: healthConfig,
}, },
Networks: networks, Networks: networks,
Resources: opts.resources.ToResourceRequirements(), Resources: opts.resources.ToResourceRequirements(),
RestartPolicy: opts.restartPolicy.ToRestartPolicy(), RestartPolicy: opts.restartPolicy.ToRestartPolicy(flags),
Placement: &swarm.Placement{ Placement: &swarm.Placement{
Constraints: opts.constraints.GetAll(), Constraints: opts.constraints.GetAll(),
Preferences: opts.placementPrefs.prefs, Preferences: opts.placementPrefs.prefs,
@ -540,8 +670,8 @@ func (opts *serviceOptions) ToService(ctx context.Context, apiClient client.APIC
LogDriver: opts.logDriver.toLogDriver(), LogDriver: opts.logDriver.toLogDriver(),
}, },
Mode: serviceMode, Mode: serviceMode,
UpdateConfig: opts.update.config(), UpdateConfig: opts.update.updateConfig(flags),
RollbackConfig: opts.rollback.config(), RollbackConfig: opts.update.rollbackConfig(flags),
EndpointSpec: opts.endpoint.ToEndpointSpec(), EndpointSpec: opts.endpoint.ToEndpointSpec(),
} }
@ -554,9 +684,67 @@ func (opts *serviceOptions) ToService(ctx context.Context, apiClient client.APIC
return service, nil return service, nil
} }
type flagDefaults map[string]interface{}
func (fd flagDefaults) getUint64(flagName string) uint64 {
if val, ok := fd[flagName].(uint64); ok {
return val
}
return 0
}
func (fd flagDefaults) getString(flagName string) string {
if val, ok := fd[flagName].(string); ok {
return val
}
return ""
}
func buildServiceDefaultFlagMapping() flagDefaults {
defaultFlagValues := make(map[string]interface{})
defaultFlagValues[flagStopGracePeriod], _ = gogotypes.DurationFromProto(defaults.Service.Task.GetContainer().StopGracePeriod)
defaultFlagValues[flagRestartCondition] = `"` + defaultRestartCondition() + `"`
defaultFlagValues[flagRestartDelay], _ = gogotypes.DurationFromProto(defaults.Service.Task.Restart.Delay)
if defaults.Service.Task.Restart.MaxAttempts != 0 {
defaultFlagValues[flagRestartMaxAttempts] = defaults.Service.Task.Restart.MaxAttempts
}
defaultRestartWindow, _ := gogotypes.DurationFromProto(defaults.Service.Task.Restart.Window)
if defaultRestartWindow != 0 {
defaultFlagValues[flagRestartWindow] = defaultRestartWindow
}
defaultFlagValues[flagUpdateParallelism] = defaults.Service.Update.Parallelism
defaultFlagValues[flagUpdateDelay] = defaults.Service.Update.Delay
defaultFlagValues[flagUpdateMonitor], _ = gogotypes.DurationFromProto(defaults.Service.Update.Monitor)
defaultFlagValues[flagUpdateFailureAction] = `"` + strings.ToLower(api.UpdateConfig_FailureAction_name[int32(defaults.Service.Update.FailureAction)]) + `"`
defaultFlagValues[flagUpdateMaxFailureRatio] = defaults.Service.Update.MaxFailureRatio
defaultFlagValues[flagUpdateOrder] = `"` + defaultOrder(defaults.Service.Update.Order) + `"`
defaultFlagValues[flagRollbackParallelism] = defaults.Service.Rollback.Parallelism
defaultFlagValues[flagRollbackDelay] = defaults.Service.Rollback.Delay
defaultFlagValues[flagRollbackMonitor], _ = gogotypes.DurationFromProto(defaults.Service.Rollback.Monitor)
defaultFlagValues[flagRollbackFailureAction] = `"` + strings.ToLower(api.UpdateConfig_FailureAction_name[int32(defaults.Service.Rollback.FailureAction)]) + `"`
defaultFlagValues[flagRollbackMaxFailureRatio] = defaults.Service.Rollback.MaxFailureRatio
defaultFlagValues[flagRollbackOrder] = `"` + defaultOrder(defaults.Service.Rollback.Order) + `"`
defaultFlagValues[flagEndpointMode] = "vip"
return defaultFlagValues
}
// addServiceFlags adds all flags that are common to both `create` and `update`. // addServiceFlags adds all flags that are common to both `create` and `update`.
// Any flags that are not common are added separately in the individual command // Any flags that are not common are added separately in the individual command
func addServiceFlags(flags *pflag.FlagSet, opts *serviceOptions) { func addServiceFlags(flags *pflag.FlagSet, opts *serviceOptions, defaultFlagValues flagDefaults) {
flagDesc := func(flagName string, desc string) string {
if defaultValue, ok := defaultFlagValues[flagName]; ok {
return fmt.Sprintf("%s (default %v)", desc, defaultValue)
}
return desc
}
flags.BoolVarP(&opts.detach, "detach", "d", true, "Exit immediately instead of waiting for the service to converge") flags.BoolVarP(&opts.detach, "detach", "d", true, "Exit immediately instead of waiting for the service to converge")
flags.BoolVarP(&opts.quiet, "quiet", "q", false, "Suppress progress output") flags.BoolVarP(&opts.quiet, "quiet", "q", false, "Suppress progress output")
@ -572,39 +760,40 @@ func addServiceFlags(flags *pflag.FlagSet, opts *serviceOptions) {
flags.Var(&opts.resources.limitMemBytes, flagLimitMemory, "Limit Memory") flags.Var(&opts.resources.limitMemBytes, flagLimitMemory, "Limit Memory")
flags.Var(&opts.resources.resCPU, flagReserveCPU, "Reserve CPUs") flags.Var(&opts.resources.resCPU, flagReserveCPU, "Reserve CPUs")
flags.Var(&opts.resources.resMemBytes, flagReserveMemory, "Reserve Memory") flags.Var(&opts.resources.resMemBytes, flagReserveMemory, "Reserve Memory")
flags.Var(&opts.stopGrace, flagStopGracePeriod, "Time to wait before force killing a container (ns|us|ms|s|m|h)")
flags.Var(&opts.stopGrace, flagStopGracePeriod, flagDesc(flagStopGracePeriod, "Time to wait before force killing a container (ns|us|ms|s|m|h)"))
flags.Var(&opts.replicas, flagReplicas, "Number of tasks") flags.Var(&opts.replicas, flagReplicas, "Number of tasks")
flags.StringVar(&opts.restartPolicy.condition, flagRestartCondition, "", `Restart when condition is met ("none"|"on-failure"|"any")`) flags.StringVar(&opts.restartPolicy.condition, flagRestartCondition, "", flagDesc(flagRestartCondition, `Restart when condition is met ("none"|"on-failure"|"any")`))
flags.Var(&opts.restartPolicy.delay, flagRestartDelay, "Delay between restart attempts (ns|us|ms|s|m|h)") flags.Var(&opts.restartPolicy.delay, flagRestartDelay, flagDesc(flagRestartDelay, "Delay between restart attempts (ns|us|ms|s|m|h)"))
flags.Var(&opts.restartPolicy.maxAttempts, flagRestartMaxAttempts, "Maximum number of restarts before giving up") flags.Var(&opts.restartPolicy.maxAttempts, flagRestartMaxAttempts, flagDesc(flagRestartMaxAttempts, "Maximum number of restarts before giving up"))
flags.Var(&opts.restartPolicy.window, flagRestartWindow, "Window used to evaluate the restart policy (ns|us|ms|s|m|h)")
flags.Uint64Var(&opts.update.parallelism, flagUpdateParallelism, 1, "Maximum number of tasks updated simultaneously (0 to update all at once)") flags.Var(&opts.restartPolicy.window, flagRestartWindow, flagDesc(flagRestartWindow, "Window used to evaluate the restart policy (ns|us|ms|s|m|h)"))
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)") flags.Uint64Var(&opts.update.parallelism, flagUpdateParallelism, defaultFlagValues.getUint64(flagUpdateParallelism), "Maximum number of tasks updated simultaneously (0 to update all at once)")
flags.DurationVar(&opts.update.delay, flagUpdateDelay, 0, flagDesc(flagUpdateDelay, "Delay between updates (ns|us|ms|s|m|h)"))
flags.DurationVar(&opts.update.monitor, flagUpdateMonitor, 0, flagDesc(flagUpdateMonitor, "Duration after each task update to monitor for failure (ns|us|ms|s|m|h)"))
flags.SetAnnotation(flagUpdateMonitor, "version", []string{"1.25"}) flags.SetAnnotation(flagUpdateMonitor, "version", []string{"1.25"})
flags.StringVar(&opts.update.onFailure, flagUpdateFailureAction, "pause", `Action on update failure ("pause"|"continue"|"rollback")`) flags.StringVar(&opts.update.onFailure, flagUpdateFailureAction, "", flagDesc(flagUpdateFailureAction, `Action on update failure ("pause"|"continue"|"rollback")`))
flags.Var(&opts.update.maxFailureRatio, flagUpdateMaxFailureRatio, "Failure rate to tolerate during an update") flags.Var(&opts.update.maxFailureRatio, flagUpdateMaxFailureRatio, flagDesc(flagUpdateMaxFailureRatio, "Failure rate to tolerate during an update"))
flags.SetAnnotation(flagUpdateMaxFailureRatio, "version", []string{"1.25"}) flags.SetAnnotation(flagUpdateMaxFailureRatio, "version", []string{"1.25"})
flags.StringVar(&opts.update.order, flagUpdateOrder, "stop-first", `Update order ("start-first"|"stop-first")`) flags.StringVar(&opts.update.order, flagUpdateOrder, "", flagDesc(flagUpdateOrder, `Update order ("start-first"|"stop-first")`))
flags.SetAnnotation(flagUpdateOrder, "version", []string{"1.29"}) flags.SetAnnotation(flagUpdateOrder, "version", []string{"1.29"})
flags.Uint64Var(&opts.rollback.parallelism, flagRollbackParallelism, 1, "Maximum number of tasks rolled back simultaneously (0 to roll back all at once)") flags.Uint64Var(&opts.rollback.parallelism, flagRollbackParallelism, defaultFlagValues.getUint64(flagRollbackParallelism), "Maximum number of tasks rolled back simultaneously (0 to roll back all at once)")
flags.SetAnnotation(flagRollbackParallelism, "version", []string{"1.28"}) flags.SetAnnotation(flagRollbackParallelism, "version", []string{"1.28"})
flags.DurationVar(&opts.rollback.delay, flagRollbackDelay, time.Duration(0), "Delay between task rollbacks (ns|us|ms|s|m|h) (default 0s)") flags.DurationVar(&opts.rollback.delay, flagRollbackDelay, 0, flagDesc(flagRollbackDelay, "Delay between task rollbacks (ns|us|ms|s|m|h)"))
flags.SetAnnotation(flagRollbackDelay, "version", []string{"1.28"}) flags.SetAnnotation(flagRollbackDelay, "version", []string{"1.28"})
flags.DurationVar(&opts.rollback.monitor, flagRollbackMonitor, time.Duration(0), "Duration after each task rollback to monitor for failure (ns|us|ms|s|m|h) (default 0s)") flags.DurationVar(&opts.rollback.monitor, flagRollbackMonitor, 0, flagDesc(flagRollbackMonitor, "Duration after each task rollback to monitor for failure (ns|us|ms|s|m|h)"))
flags.SetAnnotation(flagRollbackMonitor, "version", []string{"1.28"}) flags.SetAnnotation(flagRollbackMonitor, "version", []string{"1.28"})
flags.StringVar(&opts.rollback.onFailure, flagRollbackFailureAction, "pause", `Action on rollback failure ("pause"|"continue")`) flags.StringVar(&opts.rollback.onFailure, flagRollbackFailureAction, "", flagDesc(flagRollbackFailureAction, `Action on rollback failure ("pause"|"continue")`))
flags.SetAnnotation(flagRollbackFailureAction, "version", []string{"1.28"}) flags.SetAnnotation(flagRollbackFailureAction, "version", []string{"1.28"})
flags.Var(&opts.rollback.maxFailureRatio, flagRollbackMaxFailureRatio, "Failure rate to tolerate during a rollback") flags.Var(&opts.rollback.maxFailureRatio, flagRollbackMaxFailureRatio, flagDesc(flagRollbackMaxFailureRatio, "Failure rate to tolerate during a rollback"))
flags.SetAnnotation(flagRollbackMaxFailureRatio, "version", []string{"1.28"}) flags.SetAnnotation(flagRollbackMaxFailureRatio, "version", []string{"1.28"})
flags.StringVar(&opts.rollback.order, flagRollbackOrder, "stop-first", `Rollback order ("start-first"|"stop-first")`) flags.StringVar(&opts.rollback.order, flagRollbackOrder, "", flagDesc(flagRollbackOrder, `Rollback order ("start-first"|"stop-first")`))
flags.SetAnnotation(flagRollbackOrder, "version", []string{"1.29"}) flags.SetAnnotation(flagRollbackOrder, "version", []string{"1.29"})
flags.StringVar(&opts.endpoint.mode, flagEndpointMode, "vip", "Endpoint mode (vip or dnsrr)") flags.StringVar(&opts.endpoint.mode, flagEndpointMode, defaultFlagValues.getString(flagEndpointMode), "Endpoint mode (vip or dnsrr)")
flags.BoolVar(&opts.registryAuth, flagRegistryAuth, false, "Send registry authentication details to swarm agents") flags.BoolVar(&opts.registryAuth, flagRegistryAuth, false, "Send registry authentication details to swarm agents")

View File

@ -17,6 +17,7 @@ import (
"github.com/docker/docker/opts" "github.com/docker/docker/opts"
runconfigopts "github.com/docker/docker/runconfig/opts" runconfigopts "github.com/docker/docker/runconfig/opts"
"github.com/docker/go-connections/nat" "github.com/docker/go-connections/nat"
"github.com/docker/swarmkit/api/defaults"
"github.com/pkg/errors" "github.com/pkg/errors"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"github.com/spf13/pflag" "github.com/spf13/pflag"
@ -42,7 +43,7 @@ func newUpdateCommand(dockerCli *command.DockerCli) *cobra.Command {
flags.SetAnnotation("rollback", "version", []string{"1.25"}) flags.SetAnnotation("rollback", "version", []string{"1.25"})
flags.Bool("force", false, "Force update even if no changes require it") flags.Bool("force", false, "Force update even if no changes require it")
flags.SetAnnotation("force", "version", []string{"1.25"}) flags.SetAnnotation("force", "version", []string{"1.25"})
addServiceFlags(flags, serviceOpts) addServiceFlags(flags, serviceOpts, nil)
flags.Var(newListOptsVar(), flagEnvRemove, "Remove an environment variable") flags.Var(newListOptsVar(), flagEnvRemove, "Remove an environment variable")
flags.Var(newListOptsVar(), flagGroupRemove, "Remove a previously added supplementary user group from the container") flags.Var(newListOptsVar(), flagGroupRemove, "Remove a previously added supplementary user group from the container")
@ -294,9 +295,8 @@ func updateService(ctx context.Context, apiClient client.APIClient, flags *pflag
if anyChanged(flags, flagRestartCondition, flagRestartDelay, flagRestartMaxAttempts, flagRestartWindow) { if anyChanged(flags, flagRestartCondition, flagRestartDelay, flagRestartMaxAttempts, flagRestartWindow) {
if task.RestartPolicy == nil { if task.RestartPolicy == nil {
task.RestartPolicy = &swarm.RestartPolicy{} task.RestartPolicy = defaultRestartPolicy()
} }
if flags.Changed(flagRestartCondition) { if flags.Changed(flagRestartCondition) {
value, _ := flags.GetString(flagRestartCondition) value, _ := flags.GetString(flagRestartCondition)
task.RestartPolicy.Condition = swarm.RestartPolicyCondition(value) task.RestartPolicy.Condition = swarm.RestartPolicyCondition(value)
@ -332,7 +332,7 @@ func updateService(ctx context.Context, apiClient client.APIClient, flags *pflag
if anyChanged(flags, flagUpdateParallelism, flagUpdateDelay, flagUpdateMonitor, flagUpdateFailureAction, flagUpdateMaxFailureRatio, flagUpdateOrder) { if anyChanged(flags, flagUpdateParallelism, flagUpdateDelay, flagUpdateMonitor, flagUpdateFailureAction, flagUpdateMaxFailureRatio, flagUpdateOrder) {
if spec.UpdateConfig == nil { if spec.UpdateConfig == nil {
spec.UpdateConfig = &swarm.UpdateConfig{} spec.UpdateConfig = updateConfigFromDefaults(defaults.Service.Update)
} }
updateUint64(flagUpdateParallelism, &spec.UpdateConfig.Parallelism) updateUint64(flagUpdateParallelism, &spec.UpdateConfig.Parallelism)
updateDuration(flagUpdateDelay, &spec.UpdateConfig.Delay) updateDuration(flagUpdateDelay, &spec.UpdateConfig.Delay)
@ -344,7 +344,7 @@ func updateService(ctx context.Context, apiClient client.APIClient, flags *pflag
if anyChanged(flags, flagRollbackParallelism, flagRollbackDelay, flagRollbackMonitor, flagRollbackFailureAction, flagRollbackMaxFailureRatio, flagRollbackOrder) { if anyChanged(flags, flagRollbackParallelism, flagRollbackDelay, flagRollbackMonitor, flagRollbackFailureAction, flagRollbackMaxFailureRatio, flagRollbackOrder) {
if spec.RollbackConfig == nil { if spec.RollbackConfig == nil {
spec.RollbackConfig = &swarm.UpdateConfig{} spec.RollbackConfig = updateConfigFromDefaults(defaults.Service.Rollback)
} }
updateUint64(flagRollbackParallelism, &spec.RollbackConfig.Parallelism) updateUint64(flagRollbackParallelism, &spec.RollbackConfig.Parallelism)
updateDuration(flagRollbackDelay, &spec.RollbackConfig.Delay) updateDuration(flagRollbackDelay, &spec.RollbackConfig.Delay)

View File

@ -21,61 +21,60 @@ Usage: docker service create [OPTIONS] IMAGE [COMMAND] [ARG...]
Create a new service Create a new service
Options: Options:
--constraint list Placement constraints (default []) --constraint list Placement constraints
--container-label list Container labels (default []) --container-label list Container labels
-d, --detach Exit immediately instead of waiting for the service to converge -d, --detach Exit immediately instead of waiting for the service to converge (default true)
(default true) --dns list Set custom DNS servers
--dns list Set custom DNS servers (default []) --dns-option list Set DNS options
--dns-option list Set DNS options (default []) --dns-search list Set custom DNS search domains
--dns-search list Set custom DNS search domains (default []) --endpoint-mode string Endpoint mode (vip or dnsrr) (default "vip")
--endpoint-mode string Endpoint mode ("vip"|"dnsrr") (default "vip") --entrypoint command Overwrite the default ENTRYPOINT of the image
-e, --env list Set environment variables (default []) -e, --env list Set environment variables
--env-file list Read in a file of environment variables (default []) --env-file list Read in a file of environment variables
--group list Set one or more supplementary user groups for the container (default []) --group list Set one or more supplementary user groups for the container
--health-cmd string Command to run to check health --health-cmd string Command to run to check health
--health-interval duration Time between running the check (ns|us|ms|s|m|h) --health-interval duration Time between running the check (ns|us|ms|s|m|h)
--health-retries int Consecutive failures needed to report unhealthy --health-retries int Consecutive failures needed to report unhealthy
--health-start-period duration Start period for the container to initialize before counting retries towards unstable (ns|us|ms|s|m|h)
--health-timeout duration Maximum time to allow one check to run (ns|us|ms|s|m|h) --health-timeout duration Maximum time to allow one check to run (ns|us|ms|s|m|h)
--health-start-period duration Start period for the container to initialize before counting retries towards unstable (ns|us|ms|s|m|h) (default 0s)
--help Print usage --help Print usage
--host list Set one or more custom host-to-IP mappings (host:ip) (default []) --host list Set one or more custom host-to-IP mappings (host:ip)
--hostname string Container hostname --hostname string Container hostname
-l, --label list Service labels (default []) -l, --label list Service labels
--limit-cpu decimal Limit CPUs (default 0.000) --limit-cpu decimal Limit CPUs
--limit-memory bytes Limit Memory --limit-memory bytes Limit Memory
--log-driver string Logging driver for service --log-driver string Logging driver for service
--log-opt list Logging driver options (default []) --log-opt list Logging driver options
--mode string Service mode (replicated or global) (default "replicated") --mode string Service mode (replicated or global) (default "replicated")
--mount mount Attach a filesystem mount to the service --mount mount Attach a filesystem mount to the service
--name string Service name --name string Service name
--network list Network attachments (default []) --network list Network attachments
--no-healthcheck Disable any container-specified HEALTHCHECK --no-healthcheck Disable any container-specified HEALTHCHECK
--placement-pref pref Add a placement preference --placement-pref pref Add a placement preference
-p, --publish port Publish a port as a node port -p, --publish port Publish a port as a node port
-q, --quiet Suppress progress output
--read-only Mount the container's root filesystem as read only --read-only Mount the container's root filesystem as read only
--replicas uint Number of tasks --replicas uint Number of tasks
--reserve-cpu decimal Reserve CPUs (default 0.000) --reserve-cpu decimal Reserve CPUs
--reserve-memory bytes Reserve Memory --reserve-memory bytes Reserve Memory
--restart-condition string Restart when condition is met ("none"|"on-failure"|"any") --restart-condition string Restart when condition is met ("none"|"on-failure"|"any") (default "any")
--restart-delay duration Delay between restart attempts (ns|us|ms|s|m|h) --restart-delay duration Delay between restart attempts (ns|us|ms|s|m|h) (default 5s)
--restart-max-attempts uint Maximum number of restarts before giving up --restart-max-attempts uint Maximum number of restarts before giving up
--restart-window duration Window used to evaluate the restart policy (ns|us|ms|s|m|h) --restart-window duration Window used to evaluate the restart policy (ns|us|ms|s|m|h)
--rollback-delay duration Delay between task rollbacks (ns|us|ms|s|m|h) (default 0s) --rollback-delay duration Delay between task rollbacks (ns|us|ms|s|m|h) (default 0s)
--rollback-failure-action string Action on rollback failure ("pause"|"continue") (default "pause") --rollback-failure-action string Action on rollback failure ("pause"|"continue") (default "pause")
--rollback-max-failure-ratio float Failure rate to tolerate during a rollback --rollback-max-failure-ratio float Failure rate to tolerate during a rollback (default 0)
--rollback-monitor duration Duration after each task rollback to monitor for failure --rollback-monitor duration Duration after each task rollback to monitor for failure (ns|us|ms|s|m|h) (default 5s)
(ns|us|ms|s|m|h) (default 0s)
--rollback-order string Rollback order ("start-first"|"stop-first") (default "stop-first") --rollback-order string Rollback order ("start-first"|"stop-first") (default "stop-first")
--rollback-parallelism uint Maximum number of tasks rolled back simultaneously (0 to roll --rollback-parallelism uint Maximum number of tasks rolled back simultaneously (0 to roll back all at once) (default 1)
back all at once) (default 1)
--secret secret Specify secrets to expose to the service --secret secret Specify secrets to expose to the service
--stop-grace-period duration Time to wait before force killing a container (ns|us|ms|s|m|h) --stop-grace-period duration Time to wait before force killing a container (ns|us|ms|s|m|h) (default 10s)
--stop-signal string Signal to stop the container --stop-signal string Signal to stop the container
-t, --tty Allocate a pseudo-TTY -t, --tty Allocate a pseudo-TTY
--update-delay duration Delay between updates (ns|us|ms|s|m|h) (default 0s) --update-delay duration Delay between updates (ns|us|ms|s|m|h) (default 0s)
--update-failure-action string Action on update failure ("pause"|"continue"|"rollback") (default "pause") --update-failure-action string Action on update failure ("pause"|"continue"|"rollback") (default "pause")
--update-max-failure-ratio float Failure rate to tolerate during an update --update-max-failure-ratio float Failure rate to tolerate during an update (default 0)
--update-monitor duration Duration after each task update to monitor for failure (ns|us|ms|s|m|h) --update-monitor duration Duration after each task update to monitor for failure (ns|us|ms|s|m|h) (default 5s)
--update-order string Update order ("start-first"|"stop-first") (default "stop-first") --update-order string Update order ("start-first"|"stop-first") (default "stop-first")
--update-parallelism uint Maximum number of tasks updated simultaneously (0 to update all at once) (default 1) --update-parallelism uint Maximum number of tasks updated simultaneously (0 to update all at once) (default 1)
-u, --user string Username or UID (format: <name|uid>[:<group|gid>]) -u, --user string Username or UID (format: <name|uid>[:<group|gid>])

View File

@ -21,43 +21,43 @@ Usage: docker service update [OPTIONS] SERVICE
Update a service Update a service
Options: Options:
--args string Service command args --args command Service command args
--constraint-add list Add or update a placement constraint (default []) --constraint-add list Add or update a placement constraint
--constraint-rm list Remove a constraint (default []) --constraint-rm list Remove a constraint
--container-label-add list Add or update a container label (default []) --container-label-add list Add or update a container label
--container-label-rm list Remove a container label by its key (default []) --container-label-rm list Remove a container label by its key
-d, --detach Exit immediately instead of waiting for the service to converge -d, --detach Exit immediately instead of waiting for the service to converge (default true)
(default true) --dns-add list Add or update a custom DNS server
--dns-add list Add or update a custom DNS server (default []) --dns-option-add list Add or update a DNS option
--dns-option-add list Add or update a DNS option (default []) --dns-option-rm list Remove a DNS option
--dns-option-rm list Remove a DNS option (default []) --dns-rm list Remove a custom DNS server
--dns-rm list Remove a custom DNS server (default []) --dns-search-add list Add or update a custom DNS search domain
--dns-search-add list Add or update a custom DNS search domain (default []) --dns-search-rm list Remove a DNS search domain
--dns-search-rm list Remove a DNS search domain (default []) --endpoint-mode string Endpoint mode (vip or dnsrr)
--endpoint-mode string Endpoint mode ("vip"|"dnsrr") (default "vip") --entrypoint command Overwrite the default ENTRYPOINT of the image
--env-add list Add or update an environment variable (default []) --env-add list Add or update an environment variable
--env-rm list Remove an environment variable (default []) --env-rm list Remove an environment variable
--force Force update even if no changes require it --force Force update even if no changes require it
--group-add list Add an additional supplementary user group to the container (default []) --group-add list Add an additional supplementary user group to the container
--group-rm list Remove a previously added supplementary user group from the container (default []) --group-rm list Remove a previously added supplementary user group from the container
--health-cmd string Command to run to check health --health-cmd string Command to run to check health
--health-interval duration Time between running the check (ns|us|ms|s|m|h) --health-interval duration Time between running the check (ns|us|ms|s|m|h)
--health-retries int Consecutive failures needed to report unhealthy --health-retries int Consecutive failures needed to report unhealthy
--health-start-period duration Start period for the container to initialize before counting retries towards unstable (ns|us|ms|s|m|h)
--health-timeout duration Maximum time to allow one check to run (ns|us|ms|s|m|h) --health-timeout duration Maximum time to allow one check to run (ns|us|ms|s|m|h)
--health-start-period duration Start period for the container to initialize before counting retries towards unstable (ns|us|ms|s|m|h) (default 0s)
--help Print usage --help Print usage
--host-add list Add or update a custom host-to-IP mapping (host:ip) (default []) --host-add list Add or update a custom host-to-IP mapping (host:ip)
--host-rm list Remove a custom host-to-IP mapping (host:ip) (default []) --host-rm list Remove a custom host-to-IP mapping (host:ip)
--hostname string Container hostname --hostname string Container hostname
--image string Service image tag --image string Service image tag
--label-add list Add or update a service label (default []) --label-add list Add or update a service label
--label-rm list Remove a label by its key (default []) --label-rm list Remove a label by its key
--limit-cpu decimal Limit CPUs (default 0.000) --limit-cpu decimal Limit CPUs
--limit-memory bytes Limit Memory --limit-memory bytes Limit Memory
--log-driver string Logging driver for service --log-driver string Logging driver for service
--log-opt list Logging driver options (default []) --log-opt list Logging driver options
--mount-add mount Add or update a mount on a service --mount-add mount Add or update a mount on a service
--mount-rm list Remove a mount by its target path (default []) --mount-rm list Remove a mount by its target path
--network-add list Add a network --network-add list Add a network
--network-rm list Remove a network --network-rm list Remove a network
--no-healthcheck Disable any container-specified HEALTHCHECK --no-healthcheck Disable any container-specified HEALTHCHECK
@ -65,34 +65,33 @@ Options:
--placement-pref-rm pref Remove a placement preference --placement-pref-rm pref Remove a placement preference
--publish-add port Add or update a published port --publish-add port Add or update a published port
--publish-rm port Remove a published port by its target port --publish-rm port Remove a published port by its target port
-q, --quiet Suppress progress output
--read-only Mount the container's root filesystem as read only --read-only Mount the container's root filesystem as read only
--replicas uint Number of tasks --replicas uint Number of tasks
--reserve-cpu decimal Reserve CPUs (default 0.000) --reserve-cpu decimal Reserve CPUs
--reserve-memory bytes Reserve Memory --reserve-memory bytes Reserve Memory
--restart-condition string Restart when condition is met ("none"|"on-failure"|"any") --restart-condition string Restart when condition is met ("none"|"on-failure"|"any")
--restart-delay duration Delay between restart attempts (ns|us|ms|s|m|h) --restart-delay duration Delay between restart attempts (ns|us|ms|s|m|h)
--restart-max-attempts uint Maximum number of restarts before giving up --restart-max-attempts uint Maximum number of restarts before giving up
--restart-window duration Window used to evaluate the restart policy (ns|us|ms|s|m|h) --restart-window duration Window used to evaluate the restart policy (ns|us|ms|s|m|h)
--rollback Rollback to previous specification --rollback Rollback to previous specification
--rollback-delay duration Delay between task rollbacks (ns|us|ms|s|m|h) (default 0s) --rollback-delay duration Delay between task rollbacks (ns|us|ms|s|m|h)
--rollback-failure-action string Action on rollback failure ("pause"|"continue") (default "pause") --rollback-failure-action string Action on rollback failure ("pause"|"continue")
--rollback-max-failure-ratio float Failure rate to tolerate during a rollback --rollback-max-failure-ratio float Failure rate to tolerate during a rollback
--rollback-monitor duration Duration after each task rollback to monitor for failure --rollback-monitor duration Duration after each task rollback to monitor for failure (ns|us|ms|s|m|h)
(ns|us|ms|s|m|h) (default 0s)
--rollback-order string Rollback order ("start-first"|"stop-first") (default "stop-first") --rollback-order string Rollback order ("start-first"|"stop-first") (default "stop-first")
--rollback-parallelism uint Maximum number of tasks rolled back simultaneously (0 to roll --rollback-parallelism uint Maximum number of tasks rolled back simultaneously (0 to roll back all at once)
back all at once) (default 1)
--secret-add secret Add or update a secret on a service --secret-add secret Add or update a secret on a service
--secret-rm list Remove a secret (default []) --secret-rm list Remove a secret
--stop-grace-period duration Time to wait before force killing a container (ns|us|ms|s|m|h) --stop-grace-period duration Time to wait before force killing a container (ns|us|ms|s|m|h)
--stop-signal string Signal to stop the container --stop-signal string Signal to stop the container
-t, --tty Allocate a pseudo-TTY -t, --tty Allocate a pseudo-TTY
--update-delay duration Delay between updates (ns|us|ms|s|m|h) (default 0s) --update-delay duration Delay between updates (ns|us|ms|s|m|h)
--update-failure-action string Action on update failure ("pause"|"continue"|"rollback") (default "pause") --update-failure-action string Action on update failure ("pause"|"continue"|"rollback")
--update-max-failure-ratio float 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) --update-monitor duration Duration after each task update to monitor for failure (ns|us|ms|s|m|h)
--update-order string Update order ("start-first"|"stop-first") (default "stop-first") --update-order string Update order ("start-first"|"stop-first")
--update-parallelism uint Maximum number of tasks updated simultaneously (0 to update all at once) (default 1) --update-parallelism uint Maximum number of tasks updated simultaneously (0 to update all at once)
-u, --user string Username or UID (format: <name|uid>[:<group|gid>]) -u, --user string Username or UID (format: <name|uid>[:<group|gid>])
--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 -w, --workdir string Working directory inside the container

View File

@ -38,7 +38,10 @@ func NewListOptsRef(values *[]string, validator ValidatorFctType) *ListOpts {
} }
func (opts *ListOpts) String() string { func (opts *ListOpts) String() string {
return fmt.Sprintf("%v", []string((*opts.values))) if len(*opts.values) == 0 {
return ""
}
return fmt.Sprintf("%v", *opts.values)
} }
// Set validates if needed the input value and adds it to the // Set validates if needed the input value and adds it to the
@ -343,6 +346,9 @@ type NanoCPUs int64
// String returns the string format of the number // String returns the string format of the number
func (c *NanoCPUs) String() string { func (c *NanoCPUs) String() string {
if *c == 0 {
return ""
}
return big.NewRat(c.Value(), 1e9).FloatString(3) return big.NewRat(c.Value(), 1e9).FloatString(3)
} }

View File

@ -93,12 +93,12 @@ func TestListOptsWithValidator(t *testing.T) {
// Re-using logOptsvalidator (used by MapOpts) // Re-using logOptsvalidator (used by MapOpts)
o := NewListOpts(logOptsValidator) o := NewListOpts(logOptsValidator)
o.Set("foo") o.Set("foo")
if o.String() != "[]" { if o.String() != "" {
t.Errorf("%s != []", o.String()) t.Errorf(`%s != ""`, o.String())
} }
o.Set("foo=bar") o.Set("foo=bar")
if o.String() != "[]" { if o.String() != "" {
t.Errorf("%s != []", o.String()) t.Errorf(`%s != ""`, o.String())
} }
o.Set("max-file=2") o.Set("max-file=2")
if o.Len() != 1 { if o.Len() != 1 {
@ -111,8 +111,8 @@ func TestListOptsWithValidator(t *testing.T) {
t.Error("o.Get(\"baz\") == true") t.Error("o.Get(\"baz\") == true")
} }
o.Delete("max-file=2") o.Delete("max-file=2")
if o.String() != "[]" { if o.String() != "" {
t.Errorf("%s != []", o.String()) t.Errorf(`%s != ""`, o.String())
} }
} }