Browse code

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>

Aaron Lehmann authored on 2017/03/31 10:35:04
Showing 7 changed files
... ...
@@ -30,7 +30,7 @@ func newCreateCommand(dockerCli *command.DockerCli) *cobra.Command {
30 30
 	flags.StringVar(&opts.mode, flagMode, "replicated", "Service mode (replicated or global)")
31 31
 	flags.StringVar(&opts.name, flagName, "", "Service name")
32 32
 
33
-	addServiceFlags(flags, opts)
33
+	addServiceFlags(flags, opts, buildServiceDefaultFlagMapping())
34 34
 
35 35
 	flags.VarP(&opts.labels, flagLabel, "l", "Service labels")
36 36
 	flags.Var(&opts.containerLabels, flagContainerLabel, "Container labels")
... ...
@@ -65,7 +65,7 @@ func runCreate(dockerCli *command.DockerCli, flags *pflag.FlagSet, opts *service
65 65
 
66 66
 	ctx := context.Background()
67 67
 
68
-	service, err := opts.ToService(ctx, apiClient)
68
+	service, err := opts.ToService(ctx, apiClient, flags)
69 69
 	if err != nil {
70 70
 		return err
71 71
 	}
... ...
@@ -12,7 +12,10 @@ import (
12 12
 	"github.com/docker/docker/client"
13 13
 	"github.com/docker/docker/opts"
14 14
 	runconfigopts "github.com/docker/docker/runconfig/opts"
15
+	"github.com/docker/swarmkit/api"
16
+	"github.com/docker/swarmkit/api/defaults"
15 17
 	shlex "github.com/flynn-archive/go-shlex"
18
+	gogotypes "github.com/gogo/protobuf/types"
16 19
 	"github.com/pkg/errors"
17 20
 	"github.com/spf13/pflag"
18 21
 	"golang.org/x/net/context"
... ...
@@ -177,6 +180,9 @@ func (s *ShlexOpt) Type() string {
177 177
 }
178 178
 
179 179
 func (s *ShlexOpt) String() string {
180
+	if len(*s) == 0 {
181
+		return ""
182
+	}
180 183
 	return fmt.Sprint(*s)
181 184
 }
182 185
 
... ...
@@ -194,15 +200,75 @@ type updateOptions struct {
194 194
 	order           string
195 195
 }
196 196
 
197
-func (opts updateOptions) config() *swarm.UpdateConfig {
197
+func updateConfigFromDefaults(defaultUpdateConfig *api.UpdateConfig) *swarm.UpdateConfig {
198
+	defaultFailureAction := strings.ToLower(api.UpdateConfig_FailureAction_name[int32(defaultUpdateConfig.FailureAction)])
199
+	defaultMonitor, _ := gogotypes.DurationFromProto(defaultUpdateConfig.Monitor)
198 200
 	return &swarm.UpdateConfig{
199
-		Parallelism:     opts.parallelism,
200
-		Delay:           opts.delay,
201
-		Monitor:         opts.monitor,
202
-		FailureAction:   opts.onFailure,
203
-		MaxFailureRatio: opts.maxFailureRatio.Value(),
204
-		Order:           opts.order,
201
+		Parallelism:     defaultUpdateConfig.Parallelism,
202
+		Delay:           defaultUpdateConfig.Delay,
203
+		Monitor:         defaultMonitor,
204
+		FailureAction:   defaultFailureAction,
205
+		MaxFailureRatio: defaultUpdateConfig.MaxFailureRatio,
206
+		Order:           defaultOrder(defaultUpdateConfig.Order),
207
+	}
208
+}
209
+
210
+func (opts updateOptions) updateConfig(flags *pflag.FlagSet) *swarm.UpdateConfig {
211
+	if !anyChanged(flags, flagUpdateParallelism, flagUpdateDelay, flagUpdateMonitor, flagUpdateFailureAction, flagUpdateMaxFailureRatio) {
212
+		return nil
213
+	}
214
+
215
+	updateConfig := updateConfigFromDefaults(defaults.Service.Update)
216
+
217
+	if flags.Changed(flagUpdateParallelism) {
218
+		updateConfig.Parallelism = opts.parallelism
219
+	}
220
+	if flags.Changed(flagUpdateDelay) {
221
+		updateConfig.Delay = opts.delay
222
+	}
223
+	if flags.Changed(flagUpdateMonitor) {
224
+		updateConfig.Monitor = opts.monitor
225
+	}
226
+	if flags.Changed(flagUpdateFailureAction) {
227
+		updateConfig.FailureAction = opts.onFailure
228
+	}
229
+	if flags.Changed(flagUpdateMaxFailureRatio) {
230
+		updateConfig.MaxFailureRatio = opts.maxFailureRatio.Value()
231
+	}
232
+	if flags.Changed(flagUpdateOrder) {
233
+		updateConfig.Order = opts.order
234
+	}
235
+
236
+	return updateConfig
237
+}
238
+
239
+func (opts updateOptions) rollbackConfig(flags *pflag.FlagSet) *swarm.UpdateConfig {
240
+	if !anyChanged(flags, flagRollbackParallelism, flagRollbackDelay, flagRollbackMonitor, flagRollbackFailureAction, flagRollbackMaxFailureRatio) {
241
+		return nil
242
+	}
243
+
244
+	updateConfig := updateConfigFromDefaults(defaults.Service.Rollback)
245
+
246
+	if flags.Changed(flagRollbackParallelism) {
247
+		updateConfig.Parallelism = opts.parallelism
248
+	}
249
+	if flags.Changed(flagRollbackDelay) {
250
+		updateConfig.Delay = opts.delay
251
+	}
252
+	if flags.Changed(flagRollbackMonitor) {
253
+		updateConfig.Monitor = opts.monitor
254
+	}
255
+	if flags.Changed(flagRollbackFailureAction) {
256
+		updateConfig.FailureAction = opts.onFailure
205 257
 	}
258
+	if flags.Changed(flagRollbackMaxFailureRatio) {
259
+		updateConfig.MaxFailureRatio = opts.maxFailureRatio.Value()
260
+	}
261
+	if flags.Changed(flagRollbackOrder) {
262
+		updateConfig.Order = opts.order
263
+	}
264
+
265
+	return updateConfig
206 266
 }
207 267
 
208 268
 type resourceOptions struct {
... ...
@@ -232,13 +298,70 @@ type restartPolicyOptions struct {
232 232
 	window      DurationOpt
233 233
 }
234 234
 
235
-func (r *restartPolicyOptions) ToRestartPolicy() *swarm.RestartPolicy {
236
-	return &swarm.RestartPolicy{
237
-		Condition:   swarm.RestartPolicyCondition(r.condition),
238
-		Delay:       r.delay.Value(),
239
-		MaxAttempts: r.maxAttempts.Value(),
240
-		Window:      r.window.Value(),
235
+func defaultRestartPolicy() *swarm.RestartPolicy {
236
+	defaultMaxAttempts := defaults.Service.Task.Restart.MaxAttempts
237
+	rp := &swarm.RestartPolicy{
238
+		MaxAttempts: &defaultMaxAttempts,
239
+	}
240
+
241
+	if defaults.Service.Task.Restart.Delay != nil {
242
+		defaultRestartDelay, _ := gogotypes.DurationFromProto(defaults.Service.Task.Restart.Delay)
243
+		rp.Delay = &defaultRestartDelay
244
+	}
245
+	if defaults.Service.Task.Restart.Window != nil {
246
+		defaultRestartWindow, _ := gogotypes.DurationFromProto(defaults.Service.Task.Restart.Window)
247
+		rp.Window = &defaultRestartWindow
248
+	}
249
+	rp.Condition = defaultRestartCondition()
250
+
251
+	return rp
252
+}
253
+
254
+func defaultRestartCondition() swarm.RestartPolicyCondition {
255
+	switch defaults.Service.Task.Restart.Condition {
256
+	case api.RestartOnNone:
257
+		return "none"
258
+	case api.RestartOnFailure:
259
+		return "on-failure"
260
+	case api.RestartOnAny:
261
+		return "any"
262
+	default:
263
+		return ""
264
+	}
265
+}
266
+
267
+func defaultOrder(order api.UpdateConfig_UpdateOrder) string {
268
+	switch order {
269
+	case api.UpdateConfig_STOP_FIRST:
270
+		return "stop-first"
271
+	case api.UpdateConfig_START_FIRST:
272
+		return "start-first"
273
+	default:
274
+		return ""
275
+	}
276
+}
277
+
278
+func (r *restartPolicyOptions) ToRestartPolicy(flags *pflag.FlagSet) *swarm.RestartPolicy {
279
+	if !anyChanged(flags, flagRestartDelay, flagRestartMaxAttempts, flagRestartWindow, flagRestartCondition) {
280
+		return nil
281
+	}
282
+
283
+	restartPolicy := defaultRestartPolicy()
284
+
285
+	if flags.Changed(flagRestartDelay) {
286
+		restartPolicy.Delay = r.delay.Value()
287
+	}
288
+	if flags.Changed(flagRestartCondition) {
289
+		restartPolicy.Condition = swarm.RestartPolicyCondition(r.condition)
241 290
 	}
291
+	if flags.Changed(flagRestartMaxAttempts) {
292
+		restartPolicy.MaxAttempts = r.maxAttempts.Value()
293
+	}
294
+	if flags.Changed(flagRestartWindow) {
295
+		restartPolicy.Window = r.window.Value()
296
+	}
297
+
298
+	return restartPolicy
242 299
 }
243 300
 
244 301
 type credentialSpecOpt struct {
... ...
@@ -463,7 +586,14 @@ func (opts *serviceOptions) ToServiceMode() (swarm.ServiceMode, error) {
463 463
 	return serviceMode, nil
464 464
 }
465 465
 
466
-func (opts *serviceOptions) ToService(ctx context.Context, apiClient client.APIClient) (swarm.ServiceSpec, error) {
466
+func (opts *serviceOptions) ToStopGracePeriod(flags *pflag.FlagSet) *time.Duration {
467
+	if flags.Changed(flagStopGracePeriod) {
468
+		return opts.stopGrace.Value()
469
+	}
470
+	return nil
471
+}
472
+
473
+func (opts *serviceOptions) ToService(ctx context.Context, apiClient client.APIClient, flags *pflag.FlagSet) (swarm.ServiceSpec, error) {
467 474
 	var service swarm.ServiceSpec
468 475
 
469 476
 	envVariables, err := runconfigopts.ReadKVStrings(opts.envFile.GetAll(), opts.env.GetAll())
... ...
@@ -526,13 +656,13 @@ func (opts *serviceOptions) ToService(ctx context.Context, apiClient client.APIC
526 526
 					Options:     opts.dnsOption.GetAll(),
527 527
 				},
528 528
 				Hosts:           convertExtraHostsToSwarmHosts(opts.hosts.GetAll()),
529
-				StopGracePeriod: opts.stopGrace.Value(),
529
+				StopGracePeriod: opts.ToStopGracePeriod(flags),
530 530
 				Secrets:         nil,
531 531
 				Healthcheck:     healthConfig,
532 532
 			},
533 533
 			Networks:      networks,
534 534
 			Resources:     opts.resources.ToResourceRequirements(),
535
-			RestartPolicy: opts.restartPolicy.ToRestartPolicy(),
535
+			RestartPolicy: opts.restartPolicy.ToRestartPolicy(flags),
536 536
 			Placement: &swarm.Placement{
537 537
 				Constraints: opts.constraints.GetAll(),
538 538
 				Preferences: opts.placementPrefs.prefs,
... ...
@@ -540,8 +670,8 @@ func (opts *serviceOptions) ToService(ctx context.Context, apiClient client.APIC
540 540
 			LogDriver: opts.logDriver.toLogDriver(),
541 541
 		},
542 542
 		Mode:           serviceMode,
543
-		UpdateConfig:   opts.update.config(),
544
-		RollbackConfig: opts.rollback.config(),
543
+		UpdateConfig:   opts.update.updateConfig(flags),
544
+		RollbackConfig: opts.update.rollbackConfig(flags),
545 545
 		EndpointSpec:   opts.endpoint.ToEndpointSpec(),
546 546
 	}
547 547
 
... ...
@@ -554,9 +684,67 @@ func (opts *serviceOptions) ToService(ctx context.Context, apiClient client.APIC
554 554
 	return service, nil
555 555
 }
556 556
 
557
+type flagDefaults map[string]interface{}
558
+
559
+func (fd flagDefaults) getUint64(flagName string) uint64 {
560
+	if val, ok := fd[flagName].(uint64); ok {
561
+		return val
562
+	}
563
+	return 0
564
+}
565
+
566
+func (fd flagDefaults) getString(flagName string) string {
567
+	if val, ok := fd[flagName].(string); ok {
568
+		return val
569
+	}
570
+	return ""
571
+}
572
+
573
+func buildServiceDefaultFlagMapping() flagDefaults {
574
+	defaultFlagValues := make(map[string]interface{})
575
+
576
+	defaultFlagValues[flagStopGracePeriod], _ = gogotypes.DurationFromProto(defaults.Service.Task.GetContainer().StopGracePeriod)
577
+	defaultFlagValues[flagRestartCondition] = `"` + defaultRestartCondition() + `"`
578
+	defaultFlagValues[flagRestartDelay], _ = gogotypes.DurationFromProto(defaults.Service.Task.Restart.Delay)
579
+
580
+	if defaults.Service.Task.Restart.MaxAttempts != 0 {
581
+		defaultFlagValues[flagRestartMaxAttempts] = defaults.Service.Task.Restart.MaxAttempts
582
+	}
583
+
584
+	defaultRestartWindow, _ := gogotypes.DurationFromProto(defaults.Service.Task.Restart.Window)
585
+	if defaultRestartWindow != 0 {
586
+		defaultFlagValues[flagRestartWindow] = defaultRestartWindow
587
+	}
588
+
589
+	defaultFlagValues[flagUpdateParallelism] = defaults.Service.Update.Parallelism
590
+	defaultFlagValues[flagUpdateDelay] = defaults.Service.Update.Delay
591
+	defaultFlagValues[flagUpdateMonitor], _ = gogotypes.DurationFromProto(defaults.Service.Update.Monitor)
592
+	defaultFlagValues[flagUpdateFailureAction] = `"` + strings.ToLower(api.UpdateConfig_FailureAction_name[int32(defaults.Service.Update.FailureAction)]) + `"`
593
+	defaultFlagValues[flagUpdateMaxFailureRatio] = defaults.Service.Update.MaxFailureRatio
594
+	defaultFlagValues[flagUpdateOrder] = `"` + defaultOrder(defaults.Service.Update.Order) + `"`
595
+
596
+	defaultFlagValues[flagRollbackParallelism] = defaults.Service.Rollback.Parallelism
597
+	defaultFlagValues[flagRollbackDelay] = defaults.Service.Rollback.Delay
598
+	defaultFlagValues[flagRollbackMonitor], _ = gogotypes.DurationFromProto(defaults.Service.Rollback.Monitor)
599
+	defaultFlagValues[flagRollbackFailureAction] = `"` + strings.ToLower(api.UpdateConfig_FailureAction_name[int32(defaults.Service.Rollback.FailureAction)]) + `"`
600
+	defaultFlagValues[flagRollbackMaxFailureRatio] = defaults.Service.Rollback.MaxFailureRatio
601
+	defaultFlagValues[flagRollbackOrder] = `"` + defaultOrder(defaults.Service.Rollback.Order) + `"`
602
+
603
+	defaultFlagValues[flagEndpointMode] = "vip"
604
+
605
+	return defaultFlagValues
606
+}
607
+
557 608
 // addServiceFlags adds all flags that are common to both `create` and `update`.
558 609
 // Any flags that are not common are added separately in the individual command
559
-func addServiceFlags(flags *pflag.FlagSet, opts *serviceOptions) {
610
+func addServiceFlags(flags *pflag.FlagSet, opts *serviceOptions, defaultFlagValues flagDefaults) {
611
+	flagDesc := func(flagName string, desc string) string {
612
+		if defaultValue, ok := defaultFlagValues[flagName]; ok {
613
+			return fmt.Sprintf("%s (default %v)", desc, defaultValue)
614
+		}
615
+		return desc
616
+	}
617
+
560 618
 	flags.BoolVarP(&opts.detach, "detach", "d", true, "Exit immediately instead of waiting for the service to converge")
561 619
 	flags.BoolVarP(&opts.quiet, "quiet", "q", false, "Suppress progress output")
562 620
 
... ...
@@ -572,39 +760,40 @@ func addServiceFlags(flags *pflag.FlagSet, opts *serviceOptions) {
572 572
 	flags.Var(&opts.resources.limitMemBytes, flagLimitMemory, "Limit Memory")
573 573
 	flags.Var(&opts.resources.resCPU, flagReserveCPU, "Reserve CPUs")
574 574
 	flags.Var(&opts.resources.resMemBytes, flagReserveMemory, "Reserve Memory")
575
-	flags.Var(&opts.stopGrace, flagStopGracePeriod, "Time to wait before force killing a container (ns|us|ms|s|m|h)")
576 575
 
576
+	flags.Var(&opts.stopGrace, flagStopGracePeriod, flagDesc(flagStopGracePeriod, "Time to wait before force killing a container (ns|us|ms|s|m|h)"))
577 577
 	flags.Var(&opts.replicas, flagReplicas, "Number of tasks")
578 578
 
579
-	flags.StringVar(&opts.restartPolicy.condition, flagRestartCondition, "", `Restart when condition is met ("none"|"on-failure"|"any")`)
580
-	flags.Var(&opts.restartPolicy.delay, flagRestartDelay, "Delay between restart attempts (ns|us|ms|s|m|h)")
581
-	flags.Var(&opts.restartPolicy.maxAttempts, flagRestartMaxAttempts, "Maximum number of restarts before giving up")
582
-	flags.Var(&opts.restartPolicy.window, flagRestartWindow, "Window used to evaluate the restart policy (ns|us|ms|s|m|h)")
579
+	flags.StringVar(&opts.restartPolicy.condition, flagRestartCondition, "", flagDesc(flagRestartCondition, `Restart when condition is met ("none"|"on-failure"|"any")`))
580
+	flags.Var(&opts.restartPolicy.delay, flagRestartDelay, flagDesc(flagRestartDelay, "Delay between restart attempts (ns|us|ms|s|m|h)"))
581
+	flags.Var(&opts.restartPolicy.maxAttempts, flagRestartMaxAttempts, flagDesc(flagRestartMaxAttempts, "Maximum number of restarts before giving up"))
582
+
583
+	flags.Var(&opts.restartPolicy.window, flagRestartWindow, flagDesc(flagRestartWindow, "Window used to evaluate the restart policy (ns|us|ms|s|m|h)"))
583 584
 
584
-	flags.Uint64Var(&opts.update.parallelism, flagUpdateParallelism, 1, "Maximum number of tasks updated simultaneously (0 to update all at once)")
585
-	flags.DurationVar(&opts.update.delay, flagUpdateDelay, time.Duration(0), "Delay between updates (ns|us|ms|s|m|h) (default 0s)")
586
-	flags.DurationVar(&opts.update.monitor, flagUpdateMonitor, time.Duration(0), "Duration after each task update to monitor for failure (ns|us|ms|s|m|h)")
585
+	flags.Uint64Var(&opts.update.parallelism, flagUpdateParallelism, defaultFlagValues.getUint64(flagUpdateParallelism), "Maximum number of tasks updated simultaneously (0 to update all at once)")
586
+	flags.DurationVar(&opts.update.delay, flagUpdateDelay, 0, flagDesc(flagUpdateDelay, "Delay between updates (ns|us|ms|s|m|h)"))
587
+	flags.DurationVar(&opts.update.monitor, flagUpdateMonitor, 0, flagDesc(flagUpdateMonitor, "Duration after each task update to monitor for failure (ns|us|ms|s|m|h)"))
587 588
 	flags.SetAnnotation(flagUpdateMonitor, "version", []string{"1.25"})
588
-	flags.StringVar(&opts.update.onFailure, flagUpdateFailureAction, "pause", `Action on update failure ("pause"|"continue"|"rollback")`)
589
-	flags.Var(&opts.update.maxFailureRatio, flagUpdateMaxFailureRatio, "Failure rate to tolerate during an update")
589
+	flags.StringVar(&opts.update.onFailure, flagUpdateFailureAction, "", flagDesc(flagUpdateFailureAction, `Action on update failure ("pause"|"continue"|"rollback")`))
590
+	flags.Var(&opts.update.maxFailureRatio, flagUpdateMaxFailureRatio, flagDesc(flagUpdateMaxFailureRatio, "Failure rate to tolerate during an update"))
590 591
 	flags.SetAnnotation(flagUpdateMaxFailureRatio, "version", []string{"1.25"})
591
-	flags.StringVar(&opts.update.order, flagUpdateOrder, "stop-first", `Update order ("start-first"|"stop-first")`)
592
+	flags.StringVar(&opts.update.order, flagUpdateOrder, "", flagDesc(flagUpdateOrder, `Update order ("start-first"|"stop-first")`))
592 593
 	flags.SetAnnotation(flagUpdateOrder, "version", []string{"1.29"})
593 594
 
594
-	flags.Uint64Var(&opts.rollback.parallelism, flagRollbackParallelism, 1, "Maximum number of tasks rolled back simultaneously (0 to roll back all at once)")
595
+	flags.Uint64Var(&opts.rollback.parallelism, flagRollbackParallelism, defaultFlagValues.getUint64(flagRollbackParallelism), "Maximum number of tasks rolled back simultaneously (0 to roll back all at once)")
595 596
 	flags.SetAnnotation(flagRollbackParallelism, "version", []string{"1.28"})
596
-	flags.DurationVar(&opts.rollback.delay, flagRollbackDelay, time.Duration(0), "Delay between task rollbacks (ns|us|ms|s|m|h) (default 0s)")
597
+	flags.DurationVar(&opts.rollback.delay, flagRollbackDelay, 0, flagDesc(flagRollbackDelay, "Delay between task rollbacks (ns|us|ms|s|m|h)"))
597 598
 	flags.SetAnnotation(flagRollbackDelay, "version", []string{"1.28"})
598
-	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)")
599
+	flags.DurationVar(&opts.rollback.monitor, flagRollbackMonitor, 0, flagDesc(flagRollbackMonitor, "Duration after each task rollback to monitor for failure (ns|us|ms|s|m|h)"))
599 600
 	flags.SetAnnotation(flagRollbackMonitor, "version", []string{"1.28"})
600
-	flags.StringVar(&opts.rollback.onFailure, flagRollbackFailureAction, "pause", `Action on rollback failure ("pause"|"continue")`)
601
+	flags.StringVar(&opts.rollback.onFailure, flagRollbackFailureAction, "", flagDesc(flagRollbackFailureAction, `Action on rollback failure ("pause"|"continue")`))
601 602
 	flags.SetAnnotation(flagRollbackFailureAction, "version", []string{"1.28"})
602
-	flags.Var(&opts.rollback.maxFailureRatio, flagRollbackMaxFailureRatio, "Failure rate to tolerate during a rollback")
603
+	flags.Var(&opts.rollback.maxFailureRatio, flagRollbackMaxFailureRatio, flagDesc(flagRollbackMaxFailureRatio, "Failure rate to tolerate during a rollback"))
603 604
 	flags.SetAnnotation(flagRollbackMaxFailureRatio, "version", []string{"1.28"})
604
-	flags.StringVar(&opts.rollback.order, flagRollbackOrder, "stop-first", `Rollback order ("start-first"|"stop-first")`)
605
+	flags.StringVar(&opts.rollback.order, flagRollbackOrder, "", flagDesc(flagRollbackOrder, `Rollback order ("start-first"|"stop-first")`))
605 606
 	flags.SetAnnotation(flagRollbackOrder, "version", []string{"1.29"})
606 607
 
607
-	flags.StringVar(&opts.endpoint.mode, flagEndpointMode, "vip", "Endpoint mode (vip or dnsrr)")
608
+	flags.StringVar(&opts.endpoint.mode, flagEndpointMode, defaultFlagValues.getString(flagEndpointMode), "Endpoint mode (vip or dnsrr)")
608 609
 
609 610
 	flags.BoolVar(&opts.registryAuth, flagRegistryAuth, false, "Send registry authentication details to swarm agents")
610 611
 
... ...
@@ -17,6 +17,7 @@ import (
17 17
 	"github.com/docker/docker/opts"
18 18
 	runconfigopts "github.com/docker/docker/runconfig/opts"
19 19
 	"github.com/docker/go-connections/nat"
20
+	"github.com/docker/swarmkit/api/defaults"
20 21
 	"github.com/pkg/errors"
21 22
 	"github.com/spf13/cobra"
22 23
 	"github.com/spf13/pflag"
... ...
@@ -42,7 +43,7 @@ func newUpdateCommand(dockerCli *command.DockerCli) *cobra.Command {
42 42
 	flags.SetAnnotation("rollback", "version", []string{"1.25"})
43 43
 	flags.Bool("force", false, "Force update even if no changes require it")
44 44
 	flags.SetAnnotation("force", "version", []string{"1.25"})
45
-	addServiceFlags(flags, serviceOpts)
45
+	addServiceFlags(flags, serviceOpts, nil)
46 46
 
47 47
 	flags.Var(newListOptsVar(), flagEnvRemove, "Remove an environment variable")
48 48
 	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
294 294
 
295 295
 	if anyChanged(flags, flagRestartCondition, flagRestartDelay, flagRestartMaxAttempts, flagRestartWindow) {
296 296
 		if task.RestartPolicy == nil {
297
-			task.RestartPolicy = &swarm.RestartPolicy{}
297
+			task.RestartPolicy = defaultRestartPolicy()
298 298
 		}
299
-
300 299
 		if flags.Changed(flagRestartCondition) {
301 300
 			value, _ := flags.GetString(flagRestartCondition)
302 301
 			task.RestartPolicy.Condition = swarm.RestartPolicyCondition(value)
... ...
@@ -332,7 +332,7 @@ func updateService(ctx context.Context, apiClient client.APIClient, flags *pflag
332 332
 
333 333
 	if anyChanged(flags, flagUpdateParallelism, flagUpdateDelay, flagUpdateMonitor, flagUpdateFailureAction, flagUpdateMaxFailureRatio, flagUpdateOrder) {
334 334
 		if spec.UpdateConfig == nil {
335
-			spec.UpdateConfig = &swarm.UpdateConfig{}
335
+			spec.UpdateConfig = updateConfigFromDefaults(defaults.Service.Update)
336 336
 		}
337 337
 		updateUint64(flagUpdateParallelism, &spec.UpdateConfig.Parallelism)
338 338
 		updateDuration(flagUpdateDelay, &spec.UpdateConfig.Delay)
... ...
@@ -344,7 +344,7 @@ func updateService(ctx context.Context, apiClient client.APIClient, flags *pflag
344 344
 
345 345
 	if anyChanged(flags, flagRollbackParallelism, flagRollbackDelay, flagRollbackMonitor, flagRollbackFailureAction, flagRollbackMaxFailureRatio, flagRollbackOrder) {
346 346
 		if spec.RollbackConfig == nil {
347
-			spec.RollbackConfig = &swarm.UpdateConfig{}
347
+			spec.RollbackConfig = updateConfigFromDefaults(defaults.Service.Rollback)
348 348
 		}
349 349
 		updateUint64(flagRollbackParallelism, &spec.RollbackConfig.Parallelism)
350 350
 		updateDuration(flagRollbackDelay, &spec.RollbackConfig.Delay)
... ...
@@ -21,61 +21,60 @@ Usage:  docker service create [OPTIONS] IMAGE [COMMAND] [ARG...]
21 21
 Create a new service
22 22
 
23 23
 Options:
24
-      --constraint list                    Placement constraints (default [])
25
-      --container-label list               Container labels (default [])
26
-  -d, --detach                             Exit immediately instead of waiting for the service to converge
27
-                                           (default true)
28
-      --dns list                           Set custom DNS servers (default [])
29
-      --dns-option list                    Set DNS options (default [])
30
-      --dns-search list                    Set custom DNS search domains (default [])
31
-      --endpoint-mode string               Endpoint mode ("vip"|"dnsrr") (default "vip")
32
-  -e, --env list                           Set environment variables (default [])
33
-      --env-file list                      Read in a file of environment variables (default [])
34
-      --group list                         Set one or more supplementary user groups for the container (default [])
24
+      --constraint list                    Placement constraints
25
+      --container-label list               Container labels
26
+  -d, --detach                             Exit immediately instead of waiting for the service to converge (default true)
27
+      --dns list                           Set custom DNS servers
28
+      --dns-option list                    Set DNS options
29
+      --dns-search list                    Set custom DNS search domains
30
+      --endpoint-mode string               Endpoint mode (vip or dnsrr) (default "vip")
31
+      --entrypoint command                 Overwrite the default ENTRYPOINT of the image
32
+  -e, --env list                           Set environment variables
33
+      --env-file list                      Read in a file of environment variables
34
+      --group list                         Set one or more supplementary user groups for the container
35 35
       --health-cmd string                  Command to run to check health
36 36
       --health-interval duration           Time between running the check (ns|us|ms|s|m|h)
37 37
       --health-retries int                 Consecutive failures needed to report unhealthy
38
+      --health-start-period duration       Start period for the container to initialize before counting retries towards unstable (ns|us|ms|s|m|h)
38 39
       --health-timeout duration            Maximum time to allow one check to run (ns|us|ms|s|m|h)
39
-      --health-start-period duration       Start period for the container to initialize before counting retries towards unstable (ns|us|ms|s|m|h) (default 0s)
40 40
       --help                               Print usage
41
-      --host list                          Set one or more custom host-to-IP mappings (host:ip) (default [])
41
+      --host list                          Set one or more custom host-to-IP mappings (host:ip)
42 42
       --hostname string                    Container hostname
43
-  -l, --label list                         Service labels (default [])
44
-      --limit-cpu decimal                  Limit CPUs (default 0.000)
43
+  -l, --label list                         Service labels
44
+      --limit-cpu decimal                  Limit CPUs
45 45
       --limit-memory bytes                 Limit Memory
46 46
       --log-driver string                  Logging driver for service
47
-      --log-opt list                       Logging driver options (default [])
47
+      --log-opt list                       Logging driver options
48 48
       --mode string                        Service mode (replicated or global) (default "replicated")
49 49
       --mount mount                        Attach a filesystem mount to the service
50 50
       --name string                        Service name
51
-      --network list                       Network attachments (default [])
51
+      --network list                       Network attachments
52 52
       --no-healthcheck                     Disable any container-specified HEALTHCHECK
53 53
       --placement-pref pref                Add a placement preference
54 54
   -p, --publish port                       Publish a port as a node port
55
+  -q, --quiet                              Suppress progress output
55 56
       --read-only                          Mount the container's root filesystem as read only
56 57
       --replicas uint                      Number of tasks
57
-      --reserve-cpu decimal                Reserve CPUs (default 0.000)
58
+      --reserve-cpu decimal                Reserve CPUs
58 59
       --reserve-memory bytes               Reserve Memory
59
-      --restart-condition string           Restart when condition is met ("none"|"on-failure"|"any")
60
-      --restart-delay duration             Delay between restart attempts (ns|us|ms|s|m|h)
60
+      --restart-condition string           Restart when condition is met ("none"|"on-failure"|"any") (default "any")
61
+      --restart-delay duration             Delay between restart attempts (ns|us|ms|s|m|h) (default 5s)
61 62
       --restart-max-attempts uint          Maximum number of restarts before giving up
62 63
       --restart-window duration            Window used to evaluate the restart policy (ns|us|ms|s|m|h)
63 64
       --rollback-delay duration            Delay between task rollbacks (ns|us|ms|s|m|h) (default 0s)
64 65
       --rollback-failure-action string     Action on rollback failure ("pause"|"continue") (default "pause")
65
-      --rollback-max-failure-ratio float   Failure rate to tolerate during a rollback
66
-      --rollback-monitor duration          Duration after each task rollback to monitor for failure
67
-                                           (ns|us|ms|s|m|h) (default 0s)
66
+      --rollback-max-failure-ratio float   Failure rate to tolerate during a rollback (default 0)
67
+      --rollback-monitor duration          Duration after each task rollback to monitor for failure (ns|us|ms|s|m|h) (default 5s)
68 68
       --rollback-order string              Rollback order ("start-first"|"stop-first") (default "stop-first")
69
-      --rollback-parallelism uint          Maximum number of tasks rolled back simultaneously (0 to roll
70
-                                           back all at once) (default 1)
69
+      --rollback-parallelism uint          Maximum number of tasks rolled back simultaneously (0 to roll back all at once) (default 1)
71 70
       --secret secret                      Specify secrets to expose to the service
72
-      --stop-grace-period duration         Time to wait before force killing a container (ns|us|ms|s|m|h)
71
+      --stop-grace-period duration         Time to wait before force killing a container (ns|us|ms|s|m|h) (default 10s)
73 72
       --stop-signal string                 Signal to stop the container
74 73
   -t, --tty                                Allocate a pseudo-TTY
75 74
       --update-delay duration              Delay between updates (ns|us|ms|s|m|h) (default 0s)
76 75
       --update-failure-action string       Action on update failure ("pause"|"continue"|"rollback") (default "pause")
77
-      --update-max-failure-ratio float     Failure rate to tolerate during an update
78
-      --update-monitor duration            Duration after each task update to monitor for failure (ns|us|ms|s|m|h)
76
+      --update-max-failure-ratio float     Failure rate to tolerate during an update (default 0)
77
+      --update-monitor duration            Duration after each task update to monitor for failure (ns|us|ms|s|m|h) (default 5s)
79 78
       --update-order string                Update order ("start-first"|"stop-first") (default "stop-first")
80 79
       --update-parallelism uint            Maximum number of tasks updated simultaneously (0 to update all at once) (default 1)
81 80
   -u, --user string                        Username or UID (format: <name|uid>[:<group|gid>])
... ...
@@ -21,43 +21,43 @@ Usage:  docker service update [OPTIONS] SERVICE
21 21
 Update a service
22 22
 
23 23
 Options:
24
-      --args string                        Service command args
25
-      --constraint-add list                Add or update a placement constraint (default [])
26
-      --constraint-rm list                 Remove a constraint (default [])
27
-      --container-label-add list           Add or update a container label (default [])
28
-      --container-label-rm list            Remove a container label by its key (default [])
29
-  -d, --detach                             Exit immediately instead of waiting for the service to converge
30
-                                           (default true)
31
-      --dns-add list                       Add or update a custom DNS server (default [])
32
-      --dns-option-add list                Add or update a DNS option (default [])
33
-      --dns-option-rm list                 Remove a DNS option (default [])
34
-      --dns-rm list                        Remove a custom DNS server (default [])
35
-      --dns-search-add list                Add or update a custom DNS search domain (default [])
36
-      --dns-search-rm list                 Remove a DNS search domain (default [])
37
-      --endpoint-mode string               Endpoint mode ("vip"|"dnsrr") (default "vip")
38
-      --env-add list                       Add or update an environment variable (default [])
39
-      --env-rm list                        Remove an environment variable (default [])
24
+      --args command                       Service command args
25
+      --constraint-add list                Add or update a placement constraint
26
+      --constraint-rm list                 Remove a constraint
27
+      --container-label-add list           Add or update a container label
28
+      --container-label-rm list            Remove a container label by its key
29
+  -d, --detach                             Exit immediately instead of waiting for the service to converge (default true)
30
+      --dns-add list                       Add or update a custom DNS server
31
+      --dns-option-add list                Add or update a DNS option
32
+      --dns-option-rm list                 Remove a DNS option
33
+      --dns-rm list                        Remove a custom DNS server
34
+      --dns-search-add list                Add or update a custom DNS search domain
35
+      --dns-search-rm list                 Remove a DNS search domain
36
+      --endpoint-mode string               Endpoint mode (vip or dnsrr)
37
+      --entrypoint command                 Overwrite the default ENTRYPOINT of the image
38
+      --env-add list                       Add or update an environment variable
39
+      --env-rm list                        Remove an environment variable
40 40
       --force                              Force update even if no changes require it
41
-      --group-add list                     Add an additional supplementary user group to the container (default [])
42
-      --group-rm list                      Remove a previously added supplementary user group from the container (default [])
41
+      --group-add list                     Add an additional supplementary user group to the container
42
+      --group-rm list                      Remove a previously added supplementary user group from the container
43 43
       --health-cmd string                  Command to run to check health
44 44
       --health-interval duration           Time between running the check (ns|us|ms|s|m|h)
45 45
       --health-retries int                 Consecutive failures needed to report unhealthy
46
+      --health-start-period duration       Start period for the container to initialize before counting retries towards unstable (ns|us|ms|s|m|h)
46 47
       --health-timeout duration            Maximum time to allow one check to run (ns|us|ms|s|m|h)
47
-      --health-start-period duration       Start period for the container to initialize before counting retries towards unstable (ns|us|ms|s|m|h) (default 0s)
48 48
       --help                               Print usage
49
-      --host-add list                      Add or update a custom host-to-IP mapping (host:ip) (default [])
50
-      --host-rm list                       Remove a custom host-to-IP mapping (host:ip) (default [])
49
+      --host-add list                      Add or update a custom host-to-IP mapping (host:ip)
50
+      --host-rm list                       Remove a custom host-to-IP mapping (host:ip)
51 51
       --hostname string                    Container hostname
52 52
       --image string                       Service image tag
53
-      --label-add list                     Add or update a service label (default [])
54
-      --label-rm list                      Remove a label by its key (default [])
55
-      --limit-cpu decimal                  Limit CPUs (default 0.000)
53
+      --label-add list                     Add or update a service label
54
+      --label-rm list                      Remove a label by its key
55
+      --limit-cpu decimal                  Limit CPUs
56 56
       --limit-memory bytes                 Limit Memory
57 57
       --log-driver string                  Logging driver for service
58
-      --log-opt list                       Logging driver options (default [])
58
+      --log-opt list                       Logging driver options
59 59
       --mount-add mount                    Add or update a mount on a service
60
-      --mount-rm list                      Remove a mount by its target path (default [])
60
+      --mount-rm list                      Remove a mount by its target path
61 61
       --network-add list                   Add a network
62 62
       --network-rm list                    Remove a network
63 63
       --no-healthcheck                     Disable any container-specified HEALTHCHECK
... ...
@@ -65,34 +65,33 @@ Options:
65 65
       --placement-pref-rm pref             Remove a placement preference
66 66
       --publish-add port                   Add or update a published port
67 67
       --publish-rm port                    Remove a published port by its target port
68
+  -q, --quiet                              Suppress progress output
68 69
       --read-only                          Mount the container's root filesystem as read only
69 70
       --replicas uint                      Number of tasks
70
-      --reserve-cpu decimal                Reserve CPUs (default 0.000)
71
+      --reserve-cpu decimal                Reserve CPUs
71 72
       --reserve-memory bytes               Reserve Memory
72 73
       --restart-condition string           Restart when condition is met ("none"|"on-failure"|"any")
73 74
       --restart-delay duration             Delay between restart attempts (ns|us|ms|s|m|h)
74 75
       --restart-max-attempts uint          Maximum number of restarts before giving up
75 76
       --restart-window duration            Window used to evaluate the restart policy (ns|us|ms|s|m|h)
76 77
       --rollback                           Rollback to previous specification
77
-      --rollback-delay duration            Delay between task rollbacks (ns|us|ms|s|m|h) (default 0s)
78
-      --rollback-failure-action string     Action on rollback failure ("pause"|"continue") (default "pause")
78
+      --rollback-delay duration            Delay between task rollbacks (ns|us|ms|s|m|h)
79
+      --rollback-failure-action string     Action on rollback failure ("pause"|"continue")
79 80
       --rollback-max-failure-ratio float   Failure rate to tolerate during a rollback
80
-      --rollback-monitor duration          Duration after each task rollback to monitor for failure
81
-                                           (ns|us|ms|s|m|h) (default 0s)
81
+      --rollback-monitor duration          Duration after each task rollback to monitor for failure (ns|us|ms|s|m|h)
82 82
       --rollback-order string              Rollback order ("start-first"|"stop-first") (default "stop-first")
83
-      --rollback-parallelism uint          Maximum number of tasks rolled back simultaneously (0 to roll
84
-                                           back all at once) (default 1)
83
+      --rollback-parallelism uint          Maximum number of tasks rolled back simultaneously (0 to roll back all at once)
85 84
       --secret-add secret                  Add or update a secret on a service
86
-      --secret-rm list                     Remove a secret (default [])
85
+      --secret-rm list                     Remove a secret
87 86
       --stop-grace-period duration         Time to wait before force killing a container (ns|us|ms|s|m|h)
88 87
       --stop-signal string                 Signal to stop the container
89 88
   -t, --tty                                Allocate a pseudo-TTY
90
-      --update-delay duration              Delay between updates (ns|us|ms|s|m|h) (default 0s)
91
-      --update-failure-action string       Action on update failure ("pause"|"continue"|"rollback") (default "pause")
89
+      --update-delay duration              Delay between updates (ns|us|ms|s|m|h)
90
+      --update-failure-action string       Action on update failure ("pause"|"continue"|"rollback")
92 91
       --update-max-failure-ratio float     Failure rate to tolerate during an update
93
-      --update-monitor duration            Duration after each task update to monitor for failure (ns|us|ms|s|m|h) 
94
-      --update-order string                Update order ("start-first"|"stop-first") (default "stop-first")
95
-      --update-parallelism uint            Maximum number of tasks updated simultaneously (0 to update all at once) (default 1)
92
+      --update-monitor duration            Duration after each task update to monitor for failure (ns|us|ms|s|m|h)
93
+      --update-order string                Update order ("start-first"|"stop-first")
94
+      --update-parallelism uint            Maximum number of tasks updated simultaneously (0 to update all at once)
96 95
   -u, --user string                        Username or UID (format: <name|uid>[:<group|gid>])
97 96
       --with-registry-auth                 Send registry authentication details to swarm agents
98 97
   -w, --workdir string                     Working directory inside the container
... ...
@@ -38,7 +38,10 @@ func NewListOptsRef(values *[]string, validator ValidatorFctType) *ListOpts {
38 38
 }
39 39
 
40 40
 func (opts *ListOpts) String() string {
41
-	return fmt.Sprintf("%v", []string((*opts.values)))
41
+	if len(*opts.values) == 0 {
42
+		return ""
43
+	}
44
+	return fmt.Sprintf("%v", *opts.values)
42 45
 }
43 46
 
44 47
 // Set validates if needed the input value and adds it to the
... ...
@@ -343,6 +346,9 @@ type NanoCPUs int64
343 343
 
344 344
 // String returns the string format of the number
345 345
 func (c *NanoCPUs) String() string {
346
+	if *c == 0 {
347
+		return ""
348
+	}
346 349
 	return big.NewRat(c.Value(), 1e9).FloatString(3)
347 350
 }
348 351
 
... ...
@@ -93,12 +93,12 @@ func TestListOptsWithValidator(t *testing.T) {
93 93
 	// Re-using logOptsvalidator (used by MapOpts)
94 94
 	o := NewListOpts(logOptsValidator)
95 95
 	o.Set("foo")
96
-	if o.String() != "[]" {
97
-		t.Errorf("%s != []", o.String())
96
+	if o.String() != "" {
97
+		t.Errorf(`%s != ""`, o.String())
98 98
 	}
99 99
 	o.Set("foo=bar")
100
-	if o.String() != "[]" {
101
-		t.Errorf("%s != []", o.String())
100
+	if o.String() != "" {
101
+		t.Errorf(`%s != ""`, o.String())
102 102
 	}
103 103
 	o.Set("max-file=2")
104 104
 	if o.Len() != 1 {
... ...
@@ -111,8 +111,8 @@ func TestListOptsWithValidator(t *testing.T) {
111 111
 		t.Error("o.Get(\"baz\") == true")
112 112
 	}
113 113
 	o.Delete("max-file=2")
114
-	if o.String() != "[]" {
115
-		t.Errorf("%s != []", o.String())
114
+	if o.String() != "" {
115
+		t.Errorf(`%s != ""`, o.String())
116 116
 	}
117 117
 }
118 118