Improve default handling for "service create"
| ... | ... |
@@ -17,7 +17,7 @@ type Backend interface {
|
| 17 | 17 |
GetUnlockKey() (string, error) |
| 18 | 18 |
UnlockSwarm(req types.UnlockRequest) error |
| 19 | 19 |
GetServices(basictypes.ServiceListOptions) ([]types.Service, error) |
| 20 |
- GetService(string) (types.Service, error) |
|
| 20 |
+ GetService(idOrName string, insertDefaults bool) (types.Service, error) |
|
| 21 | 21 |
CreateService(types.ServiceSpec, string) (*basictypes.ServiceCreateResponse, error) |
| 22 | 22 |
UpdateService(string, uint64, types.ServiceSpec, basictypes.ServiceUpdateOptions) (*basictypes.ServiceUpdateResponse, error) |
| 23 | 23 |
RemoveService(string) error |
| ... | ... |
@@ -30,7 +30,7 @@ type Backend interface {
|
| 30 | 30 |
GetTask(string) (types.Task, error) |
| 31 | 31 |
GetSecrets(opts basictypes.SecretListOptions) ([]types.Secret, error) |
| 32 | 32 |
CreateSecret(s types.SecretSpec) (string, error) |
| 33 |
- RemoveSecret(id string) error |
|
| 33 |
+ RemoveSecret(idOrName string) error |
|
| 34 | 34 |
GetSecret(id string) (types.Secret, error) |
| 35 |
- UpdateSecret(id string, version uint64, spec types.SecretSpec) error |
|
| 35 |
+ UpdateSecret(idOrName string, version uint64, spec types.SecretSpec) error |
|
| 36 | 36 |
} |
| ... | ... |
@@ -151,7 +151,17 @@ func (sr *swarmRouter) getServices(ctx context.Context, w http.ResponseWriter, r |
| 151 | 151 |
} |
| 152 | 152 |
|
| 153 | 153 |
func (sr *swarmRouter) getService(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
| 154 |
- service, err := sr.backend.GetService(vars["id"]) |
|
| 154 |
+ var insertDefaults bool |
|
| 155 |
+ if value := r.URL.Query().Get("insertDefaults"); value != "" {
|
|
| 156 |
+ var err error |
|
| 157 |
+ insertDefaults, err = strconv.ParseBool(value) |
|
| 158 |
+ if err != nil {
|
|
| 159 |
+ err := fmt.Errorf("invalid value for insertDefaults: %s", value)
|
|
| 160 |
+ return errors.NewBadRequestError(err) |
|
| 161 |
+ } |
|
| 162 |
+ } |
|
| 163 |
+ |
|
| 164 |
+ service, err := sr.backend.GetService(vars["id"], insertDefaults) |
|
| 155 | 165 |
if err != nil {
|
| 156 | 166 |
logrus.Errorf("Error getting service %s: %v", vars["id"], err)
|
| 157 | 167 |
return err |
| ... | ... |
@@ -39,7 +39,7 @@ func (sr *swarmRouter) swarmLogs(ctx context.Context, w http.ResponseWriter, r * |
| 39 | 39 |
// checking for whether logs are TTY involves iterating over every service |
| 40 | 40 |
// and task. idk if there is a better way |
| 41 | 41 |
for _, service := range selector.Services {
|
| 42 |
- s, err := sr.backend.GetService(service) |
|
| 42 |
+ s, err := sr.backend.GetService(service, false) |
|
| 43 | 43 |
if err != nil {
|
| 44 | 44 |
// maybe should return some context with this error? |
| 45 | 45 |
return err |
| ... | ... |
@@ -7584,6 +7584,11 @@ paths: |
| 7584 | 7584 |
description: "ID or name of service." |
| 7585 | 7585 |
required: true |
| 7586 | 7586 |
type: "string" |
| 7587 |
+ - name: "insertDefaults" |
|
| 7588 |
+ in: "query" |
|
| 7589 |
+ description: "Fill empty fields with default values." |
|
| 7590 |
+ type: "boolean" |
|
| 7591 |
+ default: false |
|
| 7587 | 7592 |
tags: ["Service"] |
| 7588 | 7593 |
delete: |
| 7589 | 7594 |
summary: "Delete a service" |
| ... | ... |
@@ -316,12 +316,18 @@ type ServiceUpdateOptions struct {
|
| 316 | 316 |
Rollback string |
| 317 | 317 |
} |
| 318 | 318 |
|
| 319 |
-// ServiceListOptions holds parameters to list services with. |
|
| 319 |
+// ServiceListOptions holds parameters to list services with. |
|
| 320 | 320 |
type ServiceListOptions struct {
|
| 321 | 321 |
Filters filters.Args |
| 322 | 322 |
} |
| 323 | 323 |
|
| 324 |
-// TaskListOptions holds parameters to list tasks with. |
|
| 324 |
+// ServiceInspectOptions holds parameters related to the "service inspect" |
|
| 325 |
+// operation. |
|
| 326 |
+type ServiceInspectOptions struct {
|
|
| 327 |
+ InsertDefaults bool |
|
| 328 |
+} |
|
| 329 |
+ |
|
| 330 |
+// TaskListOptions holds parameters to list tasks with. |
|
| 325 | 331 |
type TaskListOptions struct {
|
| 326 | 332 |
Filters filters.Args |
| 327 | 333 |
} |
| ... | ... |
@@ -1,6 +1,7 @@ |
| 1 | 1 |
package idresolver |
| 2 | 2 |
|
| 3 | 3 |
import ( |
| 4 |
+ "github.com/docker/docker/api/types" |
|
| 4 | 5 |
"github.com/docker/docker/api/types/swarm" |
| 5 | 6 |
"github.com/docker/docker/client" |
| 6 | 7 |
"golang.org/x/net/context" |
| ... | ... |
@@ -19,7 +20,7 @@ func (cli *fakeClient) NodeInspectWithRaw(ctx context.Context, nodeID string) (s |
| 19 | 19 |
return swarm.Node{}, []byte{}, nil
|
| 20 | 20 |
} |
| 21 | 21 |
|
| 22 |
-func (cli *fakeClient) ServiceInspectWithRaw(ctx context.Context, serviceID string) (swarm.Service, []byte, error) {
|
|
| 22 |
+func (cli *fakeClient) ServiceInspectWithRaw(ctx context.Context, serviceID string, options types.ServiceInspectOptions) (swarm.Service, []byte, error) {
|
|
| 23 | 23 |
if cli.serviceInspectFunc != nil {
|
| 24 | 24 |
return cli.serviceInspectFunc(serviceID) |
| 25 | 25 |
} |
| ... | ... |
@@ -3,6 +3,7 @@ package idresolver |
| 3 | 3 |
import ( |
| 4 | 4 |
"golang.org/x/net/context" |
| 5 | 5 |
|
| 6 |
+ "github.com/docker/docker/api/types" |
|
| 6 | 7 |
"github.com/docker/docker/api/types/swarm" |
| 7 | 8 |
"github.com/docker/docker/client" |
| 8 | 9 |
"github.com/pkg/errors" |
| ... | ... |
@@ -39,7 +40,7 @@ func (r *IDResolver) get(ctx context.Context, t interface{}, id string) (string,
|
| 39 | 39 |
} |
| 40 | 40 |
return id, nil |
| 41 | 41 |
case swarm.Service: |
| 42 |
- service, _, err := r.client.ServiceInspectWithRaw(ctx, id) |
|
| 42 |
+ service, _, err := r.client.ServiceInspectWithRaw(ctx, id, types.ServiceInspectOptions{})
|
|
| 43 | 43 |
if err != nil {
|
| 44 | 44 |
return id, nil |
| 45 | 45 |
} |
| ... | ... |
@@ -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 |
} |
| ... | ... |
@@ -5,6 +5,7 @@ import ( |
| 5 | 5 |
|
| 6 | 6 |
"golang.org/x/net/context" |
| 7 | 7 |
|
| 8 |
+ "github.com/docker/docker/api/types" |
|
| 8 | 9 |
"github.com/docker/docker/cli" |
| 9 | 10 |
"github.com/docker/docker/cli/command" |
| 10 | 11 |
"github.com/docker/docker/cli/command/formatter" |
| ... | ... |
@@ -51,7 +52,8 @@ func runInspect(dockerCli *command.DockerCli, opts inspectOptions) error {
|
| 51 | 51 |
} |
| 52 | 52 |
|
| 53 | 53 |
getRef := func(ref string) (interface{}, []byte, error) {
|
| 54 |
- service, _, err := client.ServiceInspectWithRaw(ctx, ref) |
|
| 54 |
+ // Service inspect shows defaults values in empty fields. |
|
| 55 |
+ service, _, err := client.ServiceInspectWithRaw(ctx, ref, types.ServiceInspectOptions{InsertDefaults: true})
|
|
| 55 | 56 |
if err == nil || !apiclient.IsErrServiceNotFound(err) {
|
| 56 | 57 |
return service, nil, err |
| 57 | 58 |
} |
| ... | ... |
@@ -86,7 +86,7 @@ func runLogs(dockerCli *command.DockerCli, opts *logsOptions) error {
|
| 86 | 86 |
tty bool |
| 87 | 87 |
) |
| 88 | 88 |
|
| 89 |
- service, _, err := cli.ServiceInspectWithRaw(ctx, opts.target) |
|
| 89 |
+ service, _, err := cli.ServiceInspectWithRaw(ctx, opts.target, types.ServiceInspectOptions{})
|
|
| 90 | 90 |
if err != nil {
|
| 91 | 91 |
// if it's any error other than service not found, it's Real |
| 92 | 92 |
if !client.IsErrServiceNotFound(err) {
|
| ... | ... |
@@ -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 |
|
| ... | ... |
@@ -85,7 +85,7 @@ func ServiceProgress(ctx context.Context, client client.APIClient, serviceID str |
| 85 | 85 |
) |
| 86 | 86 |
|
| 87 | 87 |
for {
|
| 88 |
- service, _, err := client.ServiceInspectWithRaw(ctx, serviceID) |
|
| 88 |
+ service, _, err := client.ServiceInspectWithRaw(ctx, serviceID, types.ServiceInspectOptions{})
|
|
| 89 | 89 |
if err != nil {
|
| 90 | 90 |
return err |
| 91 | 91 |
} |
| ... | ... |
@@ -71,7 +71,7 @@ func runServiceScale(dockerCli *command.DockerCli, serviceID string, scale uint6 |
| 71 | 71 |
client := dockerCli.Client() |
| 72 | 72 |
ctx := context.Background() |
| 73 | 73 |
|
| 74 |
- service, _, err := client.ServiceInspectWithRaw(ctx, serviceID) |
|
| 74 |
+ service, _, err := client.ServiceInspectWithRaw(ctx, serviceID, types.ServiceInspectOptions{})
|
|
| 75 | 75 |
if err != nil {
|
| 76 | 76 |
return err |
| 77 | 77 |
} |
| ... | ... |
@@ -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") |
| ... | ... |
@@ -101,7 +102,7 @@ func runUpdate(dockerCli *command.DockerCli, flags *pflag.FlagSet, opts *service |
| 101 | 101 |
apiClient := dockerCli.Client() |
| 102 | 102 |
ctx := context.Background() |
| 103 | 103 |
|
| 104 |
- service, _, err := apiClient.ServiceInspectWithRaw(ctx, serviceID) |
|
| 104 |
+ service, _, err := apiClient.ServiceInspectWithRaw(ctx, serviceID, types.ServiceInspectOptions{})
|
|
| 105 | 105 |
if err != nil {
|
| 106 | 106 |
return err |
| 107 | 107 |
} |
| ... | ... |
@@ -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) |
| ... | ... |
@@ -4,6 +4,7 @@ import ( |
| 4 | 4 |
"fmt" |
| 5 | 5 |
"strings" |
| 6 | 6 |
|
| 7 |
+ "github.com/docker/docker/api/types" |
|
| 7 | 8 |
"github.com/docker/docker/cli" |
| 8 | 9 |
"github.com/docker/docker/cli/command" |
| 9 | 10 |
"github.com/docker/docker/cli/command/inspect" |
| ... | ... |
@@ -79,7 +80,8 @@ func inspectNode(ctx context.Context, dockerCli *command.DockerCli) inspect.GetR |
| 79 | 79 |
|
| 80 | 80 |
func inspectService(ctx context.Context, dockerCli *command.DockerCli) inspect.GetRefFunc {
|
| 81 | 81 |
return func(ref string) (interface{}, []byte, error) {
|
| 82 |
- return dockerCli.Client().ServiceInspectWithRaw(ctx, ref) |
|
| 82 |
+ // Service inspect shows defaults values in empty fields. |
|
| 83 |
+ return dockerCli.Client().ServiceInspectWithRaw(ctx, ref, types.ServiceInspectOptions{InsertDefaults: true})
|
|
| 83 | 84 |
} |
| 84 | 85 |
} |
| 85 | 86 |
|
| ... | ... |
@@ -123,7 +123,7 @@ type PluginAPIClient interface {
|
| 123 | 123 |
// ServiceAPIClient defines API client methods for the services |
| 124 | 124 |
type ServiceAPIClient interface {
|
| 125 | 125 |
ServiceCreate(ctx context.Context, service swarm.ServiceSpec, options types.ServiceCreateOptions) (types.ServiceCreateResponse, error) |
| 126 |
- ServiceInspectWithRaw(ctx context.Context, serviceID string) (swarm.Service, []byte, error) |
|
| 126 |
+ ServiceInspectWithRaw(ctx context.Context, serviceID string, options types.ServiceInspectOptions) (swarm.Service, []byte, error) |
|
| 127 | 127 |
ServiceList(ctx context.Context, options types.ServiceListOptions) ([]swarm.Service, error) |
| 128 | 128 |
ServiceRemove(ctx context.Context, serviceID string) error |
| 129 | 129 |
ServiceUpdate(ctx context.Context, serviceID string, version swarm.Version, service swarm.ServiceSpec, options types.ServiceUpdateOptions) (types.ServiceUpdateResponse, error) |
| ... | ... |
@@ -3,16 +3,21 @@ package client |
| 3 | 3 |
import ( |
| 4 | 4 |
"bytes" |
| 5 | 5 |
"encoding/json" |
| 6 |
+ "fmt" |
|
| 6 | 7 |
"io/ioutil" |
| 7 | 8 |
"net/http" |
| 9 |
+ "net/url" |
|
| 8 | 10 |
|
| 11 |
+ "github.com/docker/docker/api/types" |
|
| 9 | 12 |
"github.com/docker/docker/api/types/swarm" |
| 10 | 13 |
"golang.org/x/net/context" |
| 11 | 14 |
) |
| 12 | 15 |
|
| 13 | 16 |
// ServiceInspectWithRaw returns the service information and the raw data. |
| 14 |
-func (cli *Client) ServiceInspectWithRaw(ctx context.Context, serviceID string) (swarm.Service, []byte, error) {
|
|
| 15 |
- serverResp, err := cli.get(ctx, "/services/"+serviceID, nil, nil) |
|
| 17 |
+func (cli *Client) ServiceInspectWithRaw(ctx context.Context, serviceID string, opts types.ServiceInspectOptions) (swarm.Service, []byte, error) {
|
|
| 18 |
+ query := url.Values{}
|
|
| 19 |
+ query.Set("insertDefaults", fmt.Sprintf("%v", opts.InsertDefaults))
|
|
| 20 |
+ serverResp, err := cli.get(ctx, "/services/"+serviceID, query, nil) |
|
| 16 | 21 |
if err != nil {
|
| 17 | 22 |
if serverResp.statusCode == http.StatusNotFound {
|
| 18 | 23 |
return swarm.Service{}, nil, serviceNotFoundError{serviceID}
|
| ... | ... |
@@ -9,6 +9,7 @@ import ( |
| 9 | 9 |
"strings" |
| 10 | 10 |
"testing" |
| 11 | 11 |
|
| 12 |
+ "github.com/docker/docker/api/types" |
|
| 12 | 13 |
"github.com/docker/docker/api/types/swarm" |
| 13 | 14 |
"golang.org/x/net/context" |
| 14 | 15 |
) |
| ... | ... |
@@ -18,7 +19,7 @@ func TestServiceInspectError(t *testing.T) {
|
| 18 | 18 |
client: newMockClient(errorMock(http.StatusInternalServerError, "Server error")), |
| 19 | 19 |
} |
| 20 | 20 |
|
| 21 |
- _, _, err := client.ServiceInspectWithRaw(context.Background(), "nothing") |
|
| 21 |
+ _, _, err := client.ServiceInspectWithRaw(context.Background(), "nothing", types.ServiceInspectOptions{})
|
|
| 22 | 22 |
if err == nil || err.Error() != "Error response from daemon: Server error" {
|
| 23 | 23 |
t.Fatalf("expected a Server Error, got %v", err)
|
| 24 | 24 |
} |
| ... | ... |
@@ -29,7 +30,7 @@ func TestServiceInspectServiceNotFound(t *testing.T) {
|
| 29 | 29 |
client: newMockClient(errorMock(http.StatusNotFound, "Server error")), |
| 30 | 30 |
} |
| 31 | 31 |
|
| 32 |
- _, _, err := client.ServiceInspectWithRaw(context.Background(), "unknown") |
|
| 32 |
+ _, _, err := client.ServiceInspectWithRaw(context.Background(), "unknown", types.ServiceInspectOptions{})
|
|
| 33 | 33 |
if err == nil || !IsErrServiceNotFound(err) {
|
| 34 | 34 |
t.Fatalf("expected a serviceNotFoundError error, got %v", err)
|
| 35 | 35 |
} |
| ... | ... |
@@ -55,7 +56,7 @@ func TestServiceInspect(t *testing.T) {
|
| 55 | 55 |
}), |
| 56 | 56 |
} |
| 57 | 57 |
|
| 58 |
- serviceInspect, _, err := client.ServiceInspectWithRaw(context.Background(), "service_id") |
|
| 58 |
+ serviceInspect, _, err := client.ServiceInspectWithRaw(context.Background(), "service_id", types.ServiceInspectOptions{})
|
|
| 59 | 59 |
if err != nil {
|
| 60 | 60 |
t.Fatal(err) |
| 61 | 61 |
} |
| ... | ... |
@@ -58,9 +58,9 @@ func getNode(ctx context.Context, c swarmapi.ControlClient, input string) (*swar |
| 58 | 58 |
return rl.Nodes[0], nil |
| 59 | 59 |
} |
| 60 | 60 |
|
| 61 |
-func getService(ctx context.Context, c swarmapi.ControlClient, input string) (*swarmapi.Service, error) {
|
|
| 61 |
+func getService(ctx context.Context, c swarmapi.ControlClient, input string, insertDefaults bool) (*swarmapi.Service, error) {
|
|
| 62 | 62 |
// GetService to match via full ID. |
| 63 |
- if rg, err := c.GetService(ctx, &swarmapi.GetServiceRequest{ServiceID: input}); err == nil {
|
|
| 63 |
+ if rg, err := c.GetService(ctx, &swarmapi.GetServiceRequest{ServiceID: input, InsertDefaults: insertDefaults}); err == nil {
|
|
| 64 | 64 |
return rg.Service, nil |
| 65 | 65 |
} |
| 66 | 66 |
|
| ... | ... |
@@ -91,7 +91,15 @@ func getService(ctx context.Context, c swarmapi.ControlClient, input string) (*s |
| 91 | 91 |
return nil, fmt.Errorf("service %s is ambiguous (%d matches found)", input, l)
|
| 92 | 92 |
} |
| 93 | 93 |
|
| 94 |
- return rl.Services[0], nil |
|
| 94 |
+ if !insertDefaults {
|
|
| 95 |
+ return rl.Services[0], nil |
|
| 96 |
+ } |
|
| 97 |
+ |
|
| 98 |
+ rg, err := c.GetService(ctx, &swarmapi.GetServiceRequest{ServiceID: rl.Services[0].ID, InsertDefaults: true})
|
|
| 99 |
+ if err == nil {
|
|
| 100 |
+ return rg.Service, nil |
|
| 101 |
+ } |
|
| 102 |
+ return nil, err |
|
| 95 | 103 |
} |
| 96 | 104 |
|
| 97 | 105 |
func getTask(ctx context.Context, c swarmapi.ControlClient, input string) (*swarmapi.Task, error) {
|
| ... | ... |
@@ -87,10 +87,10 @@ func (c *Cluster) GetServices(options apitypes.ServiceListOptions) ([]types.Serv |
| 87 | 87 |
} |
| 88 | 88 |
|
| 89 | 89 |
// GetService returns a service based on an ID or name. |
| 90 |
-func (c *Cluster) GetService(input string) (types.Service, error) {
|
|
| 90 |
+func (c *Cluster) GetService(input string, insertDefaults bool) (types.Service, error) {
|
|
| 91 | 91 |
var service *swarmapi.Service |
| 92 | 92 |
if err := c.lockedManagerAction(func(ctx context.Context, state nodeState) error {
|
| 93 |
- s, err := getService(ctx, state.controlClient, input) |
|
| 93 |
+ s, err := getService(ctx, state.controlClient, input, insertDefaults) |
|
| 94 | 94 |
if err != nil {
|
| 95 | 95 |
return err |
| 96 | 96 |
} |
| ... | ... |
@@ -187,7 +187,7 @@ func (c *Cluster) UpdateService(serviceIDOrName string, version uint64, spec typ |
| 187 | 187 |
return apierrors.NewBadRequestError(err) |
| 188 | 188 |
} |
| 189 | 189 |
|
| 190 |
- currentService, err := getService(ctx, state.controlClient, serviceIDOrName) |
|
| 190 |
+ currentService, err := getService(ctx, state.controlClient, serviceIDOrName, false) |
|
| 191 | 191 |
if err != nil {
|
| 192 | 192 |
return err |
| 193 | 193 |
} |
| ... | ... |
@@ -289,7 +289,7 @@ func (c *Cluster) UpdateService(serviceIDOrName string, version uint64, spec typ |
| 289 | 289 |
// RemoveService removes a service from a managed swarm cluster. |
| 290 | 290 |
func (c *Cluster) RemoveService(input string) error {
|
| 291 | 291 |
return c.lockedManagerAction(func(ctx context.Context, state nodeState) error {
|
| 292 |
- service, err := getService(ctx, state.controlClient, input) |
|
| 292 |
+ service, err := getService(ctx, state.controlClient, input, false) |
|
| 293 | 293 |
if err != nil {
|
| 294 | 294 |
return err |
| 295 | 295 |
} |
| ... | ... |
@@ -442,7 +442,7 @@ func convertSelector(ctx context.Context, cc swarmapi.ControlClient, selector *b |
| 442 | 442 |
// don't rely on swarmkit to resolve IDs, do it ourselves |
| 443 | 443 |
swarmSelector := &swarmapi.LogSelector{}
|
| 444 | 444 |
for _, s := range selector.Services {
|
| 445 |
- service, err := getService(ctx, cc, s) |
|
| 445 |
+ service, err := getService(ctx, cc, s, false) |
|
| 446 | 446 |
if err != nil {
|
| 447 | 447 |
return nil, err |
| 448 | 448 |
} |
| ... | ... |
@@ -23,7 +23,7 @@ func (c *Cluster) GetTasks(options apitypes.TaskListOptions) ([]types.Task, erro |
| 23 | 23 |
if filter.Include("service") {
|
| 24 | 24 |
serviceFilters := filter.Get("service")
|
| 25 | 25 |
for _, serviceFilter := range serviceFilters {
|
| 26 |
- service, err := c.GetService(serviceFilter) |
|
| 26 |
+ service, err := c.GetService(serviceFilter, false) |
|
| 27 | 27 |
if err != nil {
|
| 28 | 28 |
return err |
| 29 | 29 |
} |
| ... | ... |
@@ -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 |
| ... | ... |
@@ -60,6 +60,16 @@ func (s *DockerSwarmSuite) TestAPISwarmServicesCreate(c *check.C) {
|
| 60 | 60 |
id := d.CreateService(c, simpleTestService, setInstances(instances)) |
| 61 | 61 |
waitAndAssert(c, defaultReconciliationTimeout, d.CheckActiveContainerCount, checker.Equals, instances) |
| 62 | 62 |
|
| 63 |
+ // insertDefaults inserts UpdateConfig when service is fetched by ID |
|
| 64 |
+ _, out, err := d.SockRequest("GET", "/services/"+id+"?insertDefaults=true", nil)
|
|
| 65 |
+ c.Assert(err, checker.IsNil, check.Commentf("%s", out))
|
|
| 66 |
+ c.Assert(string(out), checker.Contains, "UpdateConfig") |
|
| 67 |
+ |
|
| 68 |
+ // insertDefaults inserts UpdateConfig when service is fetched by ID |
|
| 69 |
+ _, out, err = d.SockRequest("GET", "/services/top?insertDefaults=true", nil)
|
|
| 70 |
+ c.Assert(err, checker.IsNil, check.Commentf("%s", out))
|
|
| 71 |
+ c.Assert(string(out), checker.Contains, "UpdateConfig") |
|
| 72 |
+ |
|
| 63 | 73 |
service := d.GetService(c, id) |
| 64 | 74 |
instances = 5 |
| 65 | 75 |
d.UpdateService(c, service, setInstances(instances)) |
| ... | ... |
@@ -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 |
|