mirror of
https://github.com/moby/moby.git
synced 2022-11-09 12:21:53 -05:00
Merge pull request #32284 from aaronlehmann/fix-service-defaults
Improve default handling for "service create"
This commit is contained in:
commit
a258ef58d8
26 changed files with 392 additions and 148 deletions
|
@ -17,7 +17,7 @@ type Backend interface {
|
|||
GetUnlockKey() (string, error)
|
||||
UnlockSwarm(req types.UnlockRequest) error
|
||||
GetServices(basictypes.ServiceListOptions) ([]types.Service, error)
|
||||
GetService(string) (types.Service, error)
|
||||
GetService(idOrName string, insertDefaults bool) (types.Service, error)
|
||||
CreateService(types.ServiceSpec, string) (*basictypes.ServiceCreateResponse, error)
|
||||
UpdateService(string, uint64, types.ServiceSpec, basictypes.ServiceUpdateOptions) (*basictypes.ServiceUpdateResponse, error)
|
||||
RemoveService(string) error
|
||||
|
@ -30,7 +30,7 @@ type Backend interface {
|
|||
GetTask(string) (types.Task, error)
|
||||
GetSecrets(opts basictypes.SecretListOptions) ([]types.Secret, error)
|
||||
CreateSecret(s types.SecretSpec) (string, error)
|
||||
RemoveSecret(id string) error
|
||||
RemoveSecret(idOrName string) error
|
||||
GetSecret(id string) (types.Secret, error)
|
||||
UpdateSecret(id string, version uint64, spec types.SecretSpec) error
|
||||
UpdateSecret(idOrName string, version uint64, spec types.SecretSpec) error
|
||||
}
|
||||
|
|
|
@ -151,7 +151,17 @@ func (sr *swarmRouter) getServices(ctx context.Context, w http.ResponseWriter, r
|
|||
}
|
||||
|
||||
func (sr *swarmRouter) getService(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
service, err := sr.backend.GetService(vars["id"])
|
||||
var insertDefaults bool
|
||||
if value := r.URL.Query().Get("insertDefaults"); value != "" {
|
||||
var err error
|
||||
insertDefaults, err = strconv.ParseBool(value)
|
||||
if err != nil {
|
||||
err := fmt.Errorf("invalid value for insertDefaults: %s", value)
|
||||
return errors.NewBadRequestError(err)
|
||||
}
|
||||
}
|
||||
|
||||
service, err := sr.backend.GetService(vars["id"], insertDefaults)
|
||||
if err != nil {
|
||||
logrus.Errorf("Error getting service %s: %v", vars["id"], err)
|
||||
return err
|
||||
|
|
|
@ -39,7 +39,7 @@ func (sr *swarmRouter) swarmLogs(ctx context.Context, w http.ResponseWriter, r *
|
|||
// checking for whether logs are TTY involves iterating over every service
|
||||
// and task. idk if there is a better way
|
||||
for _, service := range selector.Services {
|
||||
s, err := sr.backend.GetService(service)
|
||||
s, err := sr.backend.GetService(service, false)
|
||||
if err != nil {
|
||||
// maybe should return some context with this error?
|
||||
return err
|
||||
|
|
|
@ -7584,6 +7584,11 @@ paths:
|
|||
description: "ID or name of service."
|
||||
required: true
|
||||
type: "string"
|
||||
- name: "insertDefaults"
|
||||
in: "query"
|
||||
description: "Fill empty fields with default values."
|
||||
type: "boolean"
|
||||
default: false
|
||||
tags: ["Service"]
|
||||
delete:
|
||||
summary: "Delete a service"
|
||||
|
|
|
@ -316,12 +316,18 @@ type ServiceUpdateOptions struct {
|
|||
Rollback string
|
||||
}
|
||||
|
||||
// ServiceListOptions holds parameters to list services with.
|
||||
// ServiceListOptions holds parameters to list services with.
|
||||
type ServiceListOptions struct {
|
||||
Filters filters.Args
|
||||
}
|
||||
|
||||
// TaskListOptions holds parameters to list tasks with.
|
||||
// ServiceInspectOptions holds parameters related to the "service inspect"
|
||||
// operation.
|
||||
type ServiceInspectOptions struct {
|
||||
InsertDefaults bool
|
||||
}
|
||||
|
||||
// TaskListOptions holds parameters to list tasks with.
|
||||
type TaskListOptions struct {
|
||||
Filters filters.Args
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package idresolver
|
||||
|
||||
import (
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/api/types/swarm"
|
||||
"github.com/docker/docker/client"
|
||||
"golang.org/x/net/context"
|
||||
|
@ -19,7 +20,7 @@ func (cli *fakeClient) NodeInspectWithRaw(ctx context.Context, nodeID string) (s
|
|||
return swarm.Node{}, []byte{}, nil
|
||||
}
|
||||
|
||||
func (cli *fakeClient) ServiceInspectWithRaw(ctx context.Context, serviceID string) (swarm.Service, []byte, error) {
|
||||
func (cli *fakeClient) ServiceInspectWithRaw(ctx context.Context, serviceID string, options types.ServiceInspectOptions) (swarm.Service, []byte, error) {
|
||||
if cli.serviceInspectFunc != nil {
|
||||
return cli.serviceInspectFunc(serviceID)
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@ package idresolver
|
|||
import (
|
||||
"golang.org/x/net/context"
|
||||
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/api/types/swarm"
|
||||
"github.com/docker/docker/client"
|
||||
"github.com/pkg/errors"
|
||||
|
@ -39,7 +40,7 @@ func (r *IDResolver) get(ctx context.Context, t interface{}, id string) (string,
|
|||
}
|
||||
return id, nil
|
||||
case swarm.Service:
|
||||
service, _, err := r.client.ServiceInspectWithRaw(ctx, id)
|
||||
service, _, err := r.client.ServiceInspectWithRaw(ctx, id, types.ServiceInspectOptions{})
|
||||
if err != nil {
|
||||
return id, nil
|
||||
}
|
||||
|
|
|
@ -30,7 +30,7 @@ func newCreateCommand(dockerCli *command.DockerCli) *cobra.Command {
|
|||
flags.StringVar(&opts.mode, flagMode, "replicated", "Service mode (replicated or global)")
|
||||
flags.StringVar(&opts.name, flagName, "", "Service name")
|
||||
|
||||
addServiceFlags(flags, opts)
|
||||
addServiceFlags(flags, opts, buildServiceDefaultFlagMapping())
|
||||
|
||||
flags.VarP(&opts.labels, flagLabel, "l", "Service labels")
|
||||
flags.Var(&opts.containerLabels, flagContainerLabel, "Container labels")
|
||||
|
@ -65,7 +65,7 @@ func runCreate(dockerCli *command.DockerCli, flags *pflag.FlagSet, opts *service
|
|||
|
||||
ctx := context.Background()
|
||||
|
||||
service, err := opts.ToService(ctx, apiClient)
|
||||
service, err := opts.ToService(ctx, apiClient, flags)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -5,6 +5,7 @@ import (
|
|||
|
||||
"golang.org/x/net/context"
|
||||
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/cli"
|
||||
"github.com/docker/docker/cli/command"
|
||||
"github.com/docker/docker/cli/command/formatter"
|
||||
|
@ -51,7 +52,8 @@ func runInspect(dockerCli *command.DockerCli, opts inspectOptions) error {
|
|||
}
|
||||
|
||||
getRef := func(ref string) (interface{}, []byte, error) {
|
||||
service, _, err := client.ServiceInspectWithRaw(ctx, ref)
|
||||
// Service inspect shows defaults values in empty fields.
|
||||
service, _, err := client.ServiceInspectWithRaw(ctx, ref, types.ServiceInspectOptions{InsertDefaults: true})
|
||||
if err == nil || !apiclient.IsErrServiceNotFound(err) {
|
||||
return service, nil, err
|
||||
}
|
||||
|
|
|
@ -86,7 +86,7 @@ func runLogs(dockerCli *command.DockerCli, opts *logsOptions) error {
|
|||
tty bool
|
||||
)
|
||||
|
||||
service, _, err := cli.ServiceInspectWithRaw(ctx, opts.target)
|
||||
service, _, err := cli.ServiceInspectWithRaw(ctx, opts.target, types.ServiceInspectOptions{})
|
||||
if err != nil {
|
||||
// if it's any error other than service not found, it's Real
|
||||
if !client.IsErrServiceNotFound(err) {
|
||||
|
|
|
@ -12,7 +12,10 @@ import (
|
|||
"github.com/docker/docker/client"
|
||||
"github.com/docker/docker/opts"
|
||||
runconfigopts "github.com/docker/docker/runconfig/opts"
|
||||
"github.com/docker/swarmkit/api"
|
||||
"github.com/docker/swarmkit/api/defaults"
|
||||
shlex "github.com/flynn-archive/go-shlex"
|
||||
gogotypes "github.com/gogo/protobuf/types"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/spf13/pflag"
|
||||
"golang.org/x/net/context"
|
||||
|
@ -177,6 +180,9 @@ func (s *ShlexOpt) Type() string {
|
|||
}
|
||||
|
||||
func (s *ShlexOpt) String() string {
|
||||
if len(*s) == 0 {
|
||||
return ""
|
||||
}
|
||||
return fmt.Sprint(*s)
|
||||
}
|
||||
|
||||
|
@ -194,17 +200,77 @@ type updateOptions struct {
|
|||
order string
|
||||
}
|
||||
|
||||
func (opts updateOptions) config() *swarm.UpdateConfig {
|
||||
func updateConfigFromDefaults(defaultUpdateConfig *api.UpdateConfig) *swarm.UpdateConfig {
|
||||
defaultFailureAction := strings.ToLower(api.UpdateConfig_FailureAction_name[int32(defaultUpdateConfig.FailureAction)])
|
||||
defaultMonitor, _ := gogotypes.DurationFromProto(defaultUpdateConfig.Monitor)
|
||||
return &swarm.UpdateConfig{
|
||||
Parallelism: opts.parallelism,
|
||||
Delay: opts.delay,
|
||||
Monitor: opts.monitor,
|
||||
FailureAction: opts.onFailure,
|
||||
MaxFailureRatio: opts.maxFailureRatio.Value(),
|
||||
Order: opts.order,
|
||||
Parallelism: defaultUpdateConfig.Parallelism,
|
||||
Delay: defaultUpdateConfig.Delay,
|
||||
Monitor: defaultMonitor,
|
||||
FailureAction: defaultFailureAction,
|
||||
MaxFailureRatio: defaultUpdateConfig.MaxFailureRatio,
|
||||
Order: defaultOrder(defaultUpdateConfig.Order),
|
||||
}
|
||||
}
|
||||
|
||||
func (opts updateOptions) updateConfig(flags *pflag.FlagSet) *swarm.UpdateConfig {
|
||||
if !anyChanged(flags, flagUpdateParallelism, flagUpdateDelay, flagUpdateMonitor, flagUpdateFailureAction, flagUpdateMaxFailureRatio) {
|
||||
return nil
|
||||
}
|
||||
|
||||
updateConfig := updateConfigFromDefaults(defaults.Service.Update)
|
||||
|
||||
if flags.Changed(flagUpdateParallelism) {
|
||||
updateConfig.Parallelism = opts.parallelism
|
||||
}
|
||||
if flags.Changed(flagUpdateDelay) {
|
||||
updateConfig.Delay = opts.delay
|
||||
}
|
||||
if flags.Changed(flagUpdateMonitor) {
|
||||
updateConfig.Monitor = opts.monitor
|
||||
}
|
||||
if flags.Changed(flagUpdateFailureAction) {
|
||||
updateConfig.FailureAction = opts.onFailure
|
||||
}
|
||||
if flags.Changed(flagUpdateMaxFailureRatio) {
|
||||
updateConfig.MaxFailureRatio = opts.maxFailureRatio.Value()
|
||||
}
|
||||
if flags.Changed(flagUpdateOrder) {
|
||||
updateConfig.Order = opts.order
|
||||
}
|
||||
|
||||
return updateConfig
|
||||
}
|
||||
|
||||
func (opts updateOptions) rollbackConfig(flags *pflag.FlagSet) *swarm.UpdateConfig {
|
||||
if !anyChanged(flags, flagRollbackParallelism, flagRollbackDelay, flagRollbackMonitor, flagRollbackFailureAction, flagRollbackMaxFailureRatio) {
|
||||
return nil
|
||||
}
|
||||
|
||||
updateConfig := updateConfigFromDefaults(defaults.Service.Rollback)
|
||||
|
||||
if flags.Changed(flagRollbackParallelism) {
|
||||
updateConfig.Parallelism = opts.parallelism
|
||||
}
|
||||
if flags.Changed(flagRollbackDelay) {
|
||||
updateConfig.Delay = opts.delay
|
||||
}
|
||||
if flags.Changed(flagRollbackMonitor) {
|
||||
updateConfig.Monitor = opts.monitor
|
||||
}
|
||||
if flags.Changed(flagRollbackFailureAction) {
|
||||
updateConfig.FailureAction = opts.onFailure
|
||||
}
|
||||
if flags.Changed(flagRollbackMaxFailureRatio) {
|
||||
updateConfig.MaxFailureRatio = opts.maxFailureRatio.Value()
|
||||
}
|
||||
if flags.Changed(flagRollbackOrder) {
|
||||
updateConfig.Order = opts.order
|
||||
}
|
||||
|
||||
return updateConfig
|
||||
}
|
||||
|
||||
type resourceOptions struct {
|
||||
limitCPU opts.NanoCPUs
|
||||
limitMemBytes opts.MemBytes
|
||||
|
@ -232,13 +298,70 @@ type restartPolicyOptions struct {
|
|||
window DurationOpt
|
||||
}
|
||||
|
||||
func (r *restartPolicyOptions) ToRestartPolicy() *swarm.RestartPolicy {
|
||||
return &swarm.RestartPolicy{
|
||||
Condition: swarm.RestartPolicyCondition(r.condition),
|
||||
Delay: r.delay.Value(),
|
||||
MaxAttempts: r.maxAttempts.Value(),
|
||||
Window: r.window.Value(),
|
||||
func defaultRestartPolicy() *swarm.RestartPolicy {
|
||||
defaultMaxAttempts := defaults.Service.Task.Restart.MaxAttempts
|
||||
rp := &swarm.RestartPolicy{
|
||||
MaxAttempts: &defaultMaxAttempts,
|
||||
}
|
||||
|
||||
if defaults.Service.Task.Restart.Delay != nil {
|
||||
defaultRestartDelay, _ := gogotypes.DurationFromProto(defaults.Service.Task.Restart.Delay)
|
||||
rp.Delay = &defaultRestartDelay
|
||||
}
|
||||
if defaults.Service.Task.Restart.Window != nil {
|
||||
defaultRestartWindow, _ := gogotypes.DurationFromProto(defaults.Service.Task.Restart.Window)
|
||||
rp.Window = &defaultRestartWindow
|
||||
}
|
||||
rp.Condition = defaultRestartCondition()
|
||||
|
||||
return rp
|
||||
}
|
||||
|
||||
func defaultRestartCondition() swarm.RestartPolicyCondition {
|
||||
switch defaults.Service.Task.Restart.Condition {
|
||||
case api.RestartOnNone:
|
||||
return "none"
|
||||
case api.RestartOnFailure:
|
||||
return "on-failure"
|
||||
case api.RestartOnAny:
|
||||
return "any"
|
||||
default:
|
||||
return ""
|
||||
}
|
||||
}
|
||||
|
||||
func defaultOrder(order api.UpdateConfig_UpdateOrder) string {
|
||||
switch order {
|
||||
case api.UpdateConfig_STOP_FIRST:
|
||||
return "stop-first"
|
||||
case api.UpdateConfig_START_FIRST:
|
||||
return "start-first"
|
||||
default:
|
||||
return ""
|
||||
}
|
||||
}
|
||||
|
||||
func (r *restartPolicyOptions) ToRestartPolicy(flags *pflag.FlagSet) *swarm.RestartPolicy {
|
||||
if !anyChanged(flags, flagRestartDelay, flagRestartMaxAttempts, flagRestartWindow, flagRestartCondition) {
|
||||
return nil
|
||||
}
|
||||
|
||||
restartPolicy := defaultRestartPolicy()
|
||||
|
||||
if flags.Changed(flagRestartDelay) {
|
||||
restartPolicy.Delay = r.delay.Value()
|
||||
}
|
||||
if flags.Changed(flagRestartCondition) {
|
||||
restartPolicy.Condition = swarm.RestartPolicyCondition(r.condition)
|
||||
}
|
||||
if flags.Changed(flagRestartMaxAttempts) {
|
||||
restartPolicy.MaxAttempts = r.maxAttempts.Value()
|
||||
}
|
||||
if flags.Changed(flagRestartWindow) {
|
||||
restartPolicy.Window = r.window.Value()
|
||||
}
|
||||
|
||||
return restartPolicy
|
||||
}
|
||||
|
||||
type credentialSpecOpt struct {
|
||||
|
@ -463,7 +586,14 @@ func (opts *serviceOptions) ToServiceMode() (swarm.ServiceMode, error) {
|
|||
return serviceMode, nil
|
||||
}
|
||||
|
||||
func (opts *serviceOptions) ToService(ctx context.Context, apiClient client.APIClient) (swarm.ServiceSpec, error) {
|
||||
func (opts *serviceOptions) ToStopGracePeriod(flags *pflag.FlagSet) *time.Duration {
|
||||
if flags.Changed(flagStopGracePeriod) {
|
||||
return opts.stopGrace.Value()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (opts *serviceOptions) ToService(ctx context.Context, apiClient client.APIClient, flags *pflag.FlagSet) (swarm.ServiceSpec, error) {
|
||||
var service swarm.ServiceSpec
|
||||
|
||||
envVariables, err := runconfigopts.ReadKVStrings(opts.envFile.GetAll(), opts.env.GetAll())
|
||||
|
@ -526,13 +656,13 @@ func (opts *serviceOptions) ToService(ctx context.Context, apiClient client.APIC
|
|||
Options: opts.dnsOption.GetAll(),
|
||||
},
|
||||
Hosts: convertExtraHostsToSwarmHosts(opts.hosts.GetAll()),
|
||||
StopGracePeriod: opts.stopGrace.Value(),
|
||||
StopGracePeriod: opts.ToStopGracePeriod(flags),
|
||||
Secrets: nil,
|
||||
Healthcheck: healthConfig,
|
||||
},
|
||||
Networks: networks,
|
||||
Resources: opts.resources.ToResourceRequirements(),
|
||||
RestartPolicy: opts.restartPolicy.ToRestartPolicy(),
|
||||
RestartPolicy: opts.restartPolicy.ToRestartPolicy(flags),
|
||||
Placement: &swarm.Placement{
|
||||
Constraints: opts.constraints.GetAll(),
|
||||
Preferences: opts.placementPrefs.prefs,
|
||||
|
@ -540,8 +670,8 @@ func (opts *serviceOptions) ToService(ctx context.Context, apiClient client.APIC
|
|||
LogDriver: opts.logDriver.toLogDriver(),
|
||||
},
|
||||
Mode: serviceMode,
|
||||
UpdateConfig: opts.update.config(),
|
||||
RollbackConfig: opts.rollback.config(),
|
||||
UpdateConfig: opts.update.updateConfig(flags),
|
||||
RollbackConfig: opts.update.rollbackConfig(flags),
|
||||
EndpointSpec: opts.endpoint.ToEndpointSpec(),
|
||||
}
|
||||
|
||||
|
@ -554,9 +684,67 @@ func (opts *serviceOptions) ToService(ctx context.Context, apiClient client.APIC
|
|||
return service, nil
|
||||
}
|
||||
|
||||
type flagDefaults map[string]interface{}
|
||||
|
||||
func (fd flagDefaults) getUint64(flagName string) uint64 {
|
||||
if val, ok := fd[flagName].(uint64); ok {
|
||||
return val
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (fd flagDefaults) getString(flagName string) string {
|
||||
if val, ok := fd[flagName].(string); ok {
|
||||
return val
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func buildServiceDefaultFlagMapping() flagDefaults {
|
||||
defaultFlagValues := make(map[string]interface{})
|
||||
|
||||
defaultFlagValues[flagStopGracePeriod], _ = gogotypes.DurationFromProto(defaults.Service.Task.GetContainer().StopGracePeriod)
|
||||
defaultFlagValues[flagRestartCondition] = `"` + defaultRestartCondition() + `"`
|
||||
defaultFlagValues[flagRestartDelay], _ = gogotypes.DurationFromProto(defaults.Service.Task.Restart.Delay)
|
||||
|
||||
if defaults.Service.Task.Restart.MaxAttempts != 0 {
|
||||
defaultFlagValues[flagRestartMaxAttempts] = defaults.Service.Task.Restart.MaxAttempts
|
||||
}
|
||||
|
||||
defaultRestartWindow, _ := gogotypes.DurationFromProto(defaults.Service.Task.Restart.Window)
|
||||
if defaultRestartWindow != 0 {
|
||||
defaultFlagValues[flagRestartWindow] = defaultRestartWindow
|
||||
}
|
||||
|
||||
defaultFlagValues[flagUpdateParallelism] = defaults.Service.Update.Parallelism
|
||||
defaultFlagValues[flagUpdateDelay] = defaults.Service.Update.Delay
|
||||
defaultFlagValues[flagUpdateMonitor], _ = gogotypes.DurationFromProto(defaults.Service.Update.Monitor)
|
||||
defaultFlagValues[flagUpdateFailureAction] = `"` + strings.ToLower(api.UpdateConfig_FailureAction_name[int32(defaults.Service.Update.FailureAction)]) + `"`
|
||||
defaultFlagValues[flagUpdateMaxFailureRatio] = defaults.Service.Update.MaxFailureRatio
|
||||
defaultFlagValues[flagUpdateOrder] = `"` + defaultOrder(defaults.Service.Update.Order) + `"`
|
||||
|
||||
defaultFlagValues[flagRollbackParallelism] = defaults.Service.Rollback.Parallelism
|
||||
defaultFlagValues[flagRollbackDelay] = defaults.Service.Rollback.Delay
|
||||
defaultFlagValues[flagRollbackMonitor], _ = gogotypes.DurationFromProto(defaults.Service.Rollback.Monitor)
|
||||
defaultFlagValues[flagRollbackFailureAction] = `"` + strings.ToLower(api.UpdateConfig_FailureAction_name[int32(defaults.Service.Rollback.FailureAction)]) + `"`
|
||||
defaultFlagValues[flagRollbackMaxFailureRatio] = defaults.Service.Rollback.MaxFailureRatio
|
||||
defaultFlagValues[flagRollbackOrder] = `"` + defaultOrder(defaults.Service.Rollback.Order) + `"`
|
||||
|
||||
defaultFlagValues[flagEndpointMode] = "vip"
|
||||
|
||||
return defaultFlagValues
|
||||
}
|
||||
|
||||
// addServiceFlags adds all flags that are common to both `create` and `update`.
|
||||
// Any flags that are not common are added separately in the individual command
|
||||
func addServiceFlags(flags *pflag.FlagSet, opts *serviceOptions) {
|
||||
func addServiceFlags(flags *pflag.FlagSet, opts *serviceOptions, defaultFlagValues flagDefaults) {
|
||||
flagDesc := func(flagName string, desc string) string {
|
||||
if defaultValue, ok := defaultFlagValues[flagName]; ok {
|
||||
return fmt.Sprintf("%s (default %v)", desc, defaultValue)
|
||||
}
|
||||
return desc
|
||||
}
|
||||
|
||||
flags.BoolVarP(&opts.detach, "detach", "d", true, "Exit immediately instead of waiting for the service to converge")
|
||||
flags.BoolVarP(&opts.quiet, "quiet", "q", false, "Suppress progress output")
|
||||
|
||||
|
@ -572,39 +760,40 @@ func addServiceFlags(flags *pflag.FlagSet, opts *serviceOptions) {
|
|||
flags.Var(&opts.resources.limitMemBytes, flagLimitMemory, "Limit Memory")
|
||||
flags.Var(&opts.resources.resCPU, flagReserveCPU, "Reserve CPUs")
|
||||
flags.Var(&opts.resources.resMemBytes, flagReserveMemory, "Reserve Memory")
|
||||
flags.Var(&opts.stopGrace, flagStopGracePeriod, "Time to wait before force killing a container (ns|us|ms|s|m|h)")
|
||||
|
||||
flags.Var(&opts.stopGrace, flagStopGracePeriod, flagDesc(flagStopGracePeriod, "Time to wait before force killing a container (ns|us|ms|s|m|h)"))
|
||||
flags.Var(&opts.replicas, flagReplicas, "Number of tasks")
|
||||
|
||||
flags.StringVar(&opts.restartPolicy.condition, flagRestartCondition, "", `Restart when condition is met ("none"|"on-failure"|"any")`)
|
||||
flags.Var(&opts.restartPolicy.delay, flagRestartDelay, "Delay between restart attempts (ns|us|ms|s|m|h)")
|
||||
flags.Var(&opts.restartPolicy.maxAttempts, flagRestartMaxAttempts, "Maximum number of restarts before giving up")
|
||||
flags.Var(&opts.restartPolicy.window, flagRestartWindow, "Window used to evaluate the restart policy (ns|us|ms|s|m|h)")
|
||||
flags.StringVar(&opts.restartPolicy.condition, flagRestartCondition, "", flagDesc(flagRestartCondition, `Restart when condition is met ("none"|"on-failure"|"any")`))
|
||||
flags.Var(&opts.restartPolicy.delay, flagRestartDelay, flagDesc(flagRestartDelay, "Delay between restart attempts (ns|us|ms|s|m|h)"))
|
||||
flags.Var(&opts.restartPolicy.maxAttempts, flagRestartMaxAttempts, flagDesc(flagRestartMaxAttempts, "Maximum number of restarts before giving up"))
|
||||
|
||||
flags.Uint64Var(&opts.update.parallelism, flagUpdateParallelism, 1, "Maximum number of tasks updated simultaneously (0 to update all at once)")
|
||||
flags.DurationVar(&opts.update.delay, flagUpdateDelay, time.Duration(0), "Delay between updates (ns|us|ms|s|m|h) (default 0s)")
|
||||
flags.DurationVar(&opts.update.monitor, flagUpdateMonitor, time.Duration(0), "Duration after each task update to monitor for failure (ns|us|ms|s|m|h)")
|
||||
flags.Var(&opts.restartPolicy.window, flagRestartWindow, flagDesc(flagRestartWindow, "Window used to evaluate the restart policy (ns|us|ms|s|m|h)"))
|
||||
|
||||
flags.Uint64Var(&opts.update.parallelism, flagUpdateParallelism, defaultFlagValues.getUint64(flagUpdateParallelism), "Maximum number of tasks updated simultaneously (0 to update all at once)")
|
||||
flags.DurationVar(&opts.update.delay, flagUpdateDelay, 0, flagDesc(flagUpdateDelay, "Delay between updates (ns|us|ms|s|m|h)"))
|
||||
flags.DurationVar(&opts.update.monitor, flagUpdateMonitor, 0, flagDesc(flagUpdateMonitor, "Duration after each task update to monitor for failure (ns|us|ms|s|m|h)"))
|
||||
flags.SetAnnotation(flagUpdateMonitor, "version", []string{"1.25"})
|
||||
flags.StringVar(&opts.update.onFailure, flagUpdateFailureAction, "pause", `Action on update failure ("pause"|"continue"|"rollback")`)
|
||||
flags.Var(&opts.update.maxFailureRatio, flagUpdateMaxFailureRatio, "Failure rate to tolerate during an update")
|
||||
flags.StringVar(&opts.update.onFailure, flagUpdateFailureAction, "", flagDesc(flagUpdateFailureAction, `Action on update failure ("pause"|"continue"|"rollback")`))
|
||||
flags.Var(&opts.update.maxFailureRatio, flagUpdateMaxFailureRatio, flagDesc(flagUpdateMaxFailureRatio, "Failure rate to tolerate during an update"))
|
||||
flags.SetAnnotation(flagUpdateMaxFailureRatio, "version", []string{"1.25"})
|
||||
flags.StringVar(&opts.update.order, flagUpdateOrder, "stop-first", `Update order ("start-first"|"stop-first")`)
|
||||
flags.StringVar(&opts.update.order, flagUpdateOrder, "", flagDesc(flagUpdateOrder, `Update order ("start-first"|"stop-first")`))
|
||||
flags.SetAnnotation(flagUpdateOrder, "version", []string{"1.29"})
|
||||
|
||||
flags.Uint64Var(&opts.rollback.parallelism, flagRollbackParallelism, 1, "Maximum number of tasks rolled back simultaneously (0 to roll back all at once)")
|
||||
flags.Uint64Var(&opts.rollback.parallelism, flagRollbackParallelism, defaultFlagValues.getUint64(flagRollbackParallelism), "Maximum number of tasks rolled back simultaneously (0 to roll back all at once)")
|
||||
flags.SetAnnotation(flagRollbackParallelism, "version", []string{"1.28"})
|
||||
flags.DurationVar(&opts.rollback.delay, flagRollbackDelay, time.Duration(0), "Delay between task rollbacks (ns|us|ms|s|m|h) (default 0s)")
|
||||
flags.DurationVar(&opts.rollback.delay, flagRollbackDelay, 0, flagDesc(flagRollbackDelay, "Delay between task rollbacks (ns|us|ms|s|m|h)"))
|
||||
flags.SetAnnotation(flagRollbackDelay, "version", []string{"1.28"})
|
||||
flags.DurationVar(&opts.rollback.monitor, flagRollbackMonitor, time.Duration(0), "Duration after each task rollback to monitor for failure (ns|us|ms|s|m|h) (default 0s)")
|
||||
flags.DurationVar(&opts.rollback.monitor, flagRollbackMonitor, 0, flagDesc(flagRollbackMonitor, "Duration after each task rollback to monitor for failure (ns|us|ms|s|m|h)"))
|
||||
flags.SetAnnotation(flagRollbackMonitor, "version", []string{"1.28"})
|
||||
flags.StringVar(&opts.rollback.onFailure, flagRollbackFailureAction, "pause", `Action on rollback failure ("pause"|"continue")`)
|
||||
flags.StringVar(&opts.rollback.onFailure, flagRollbackFailureAction, "", flagDesc(flagRollbackFailureAction, `Action on rollback failure ("pause"|"continue")`))
|
||||
flags.SetAnnotation(flagRollbackFailureAction, "version", []string{"1.28"})
|
||||
flags.Var(&opts.rollback.maxFailureRatio, flagRollbackMaxFailureRatio, "Failure rate to tolerate during a rollback")
|
||||
flags.Var(&opts.rollback.maxFailureRatio, flagRollbackMaxFailureRatio, flagDesc(flagRollbackMaxFailureRatio, "Failure rate to tolerate during a rollback"))
|
||||
flags.SetAnnotation(flagRollbackMaxFailureRatio, "version", []string{"1.28"})
|
||||
flags.StringVar(&opts.rollback.order, flagRollbackOrder, "stop-first", `Rollback order ("start-first"|"stop-first")`)
|
||||
flags.StringVar(&opts.rollback.order, flagRollbackOrder, "", flagDesc(flagRollbackOrder, `Rollback order ("start-first"|"stop-first")`))
|
||||
flags.SetAnnotation(flagRollbackOrder, "version", []string{"1.29"})
|
||||
|
||||
flags.StringVar(&opts.endpoint.mode, flagEndpointMode, "vip", "Endpoint mode (vip or dnsrr)")
|
||||
flags.StringVar(&opts.endpoint.mode, flagEndpointMode, defaultFlagValues.getString(flagEndpointMode), "Endpoint mode (vip or dnsrr)")
|
||||
|
||||
flags.BoolVar(&opts.registryAuth, flagRegistryAuth, false, "Send registry authentication details to swarm agents")
|
||||
|
||||
|
|
|
@ -85,7 +85,7 @@ func ServiceProgress(ctx context.Context, client client.APIClient, serviceID str
|
|||
)
|
||||
|
||||
for {
|
||||
service, _, err := client.ServiceInspectWithRaw(ctx, serviceID)
|
||||
service, _, err := client.ServiceInspectWithRaw(ctx, serviceID, types.ServiceInspectOptions{})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -71,7 +71,7 @@ func runServiceScale(dockerCli *command.DockerCli, serviceID string, scale uint6
|
|||
client := dockerCli.Client()
|
||||
ctx := context.Background()
|
||||
|
||||
service, _, err := client.ServiceInspectWithRaw(ctx, serviceID)
|
||||
service, _, err := client.ServiceInspectWithRaw(ctx, serviceID, types.ServiceInspectOptions{})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -17,6 +17,7 @@ import (
|
|||
"github.com/docker/docker/opts"
|
||||
runconfigopts "github.com/docker/docker/runconfig/opts"
|
||||
"github.com/docker/go-connections/nat"
|
||||
"github.com/docker/swarmkit/api/defaults"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/pflag"
|
||||
|
@ -42,7 +43,7 @@ func newUpdateCommand(dockerCli *command.DockerCli) *cobra.Command {
|
|||
flags.SetAnnotation("rollback", "version", []string{"1.25"})
|
||||
flags.Bool("force", false, "Force update even if no changes require it")
|
||||
flags.SetAnnotation("force", "version", []string{"1.25"})
|
||||
addServiceFlags(flags, serviceOpts)
|
||||
addServiceFlags(flags, serviceOpts, nil)
|
||||
|
||||
flags.Var(newListOptsVar(), flagEnvRemove, "Remove an environment variable")
|
||||
flags.Var(newListOptsVar(), 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
|
|||
apiClient := dockerCli.Client()
|
||||
ctx := context.Background()
|
||||
|
||||
service, _, err := apiClient.ServiceInspectWithRaw(ctx, serviceID)
|
||||
service, _, err := apiClient.ServiceInspectWithRaw(ctx, serviceID, types.ServiceInspectOptions{})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -294,9 +295,8 @@ func updateService(ctx context.Context, apiClient client.APIClient, flags *pflag
|
|||
|
||||
if anyChanged(flags, flagRestartCondition, flagRestartDelay, flagRestartMaxAttempts, flagRestartWindow) {
|
||||
if task.RestartPolicy == nil {
|
||||
task.RestartPolicy = &swarm.RestartPolicy{}
|
||||
task.RestartPolicy = defaultRestartPolicy()
|
||||
}
|
||||
|
||||
if flags.Changed(flagRestartCondition) {
|
||||
value, _ := flags.GetString(flagRestartCondition)
|
||||
task.RestartPolicy.Condition = swarm.RestartPolicyCondition(value)
|
||||
|
@ -332,7 +332,7 @@ func updateService(ctx context.Context, apiClient client.APIClient, flags *pflag
|
|||
|
||||
if anyChanged(flags, flagUpdateParallelism, flagUpdateDelay, flagUpdateMonitor, flagUpdateFailureAction, flagUpdateMaxFailureRatio, flagUpdateOrder) {
|
||||
if spec.UpdateConfig == nil {
|
||||
spec.UpdateConfig = &swarm.UpdateConfig{}
|
||||
spec.UpdateConfig = updateConfigFromDefaults(defaults.Service.Update)
|
||||
}
|
||||
updateUint64(flagUpdateParallelism, &spec.UpdateConfig.Parallelism)
|
||||
updateDuration(flagUpdateDelay, &spec.UpdateConfig.Delay)
|
||||
|
@ -344,7 +344,7 @@ func updateService(ctx context.Context, apiClient client.APIClient, flags *pflag
|
|||
|
||||
if anyChanged(flags, flagRollbackParallelism, flagRollbackDelay, flagRollbackMonitor, flagRollbackFailureAction, flagRollbackMaxFailureRatio, flagRollbackOrder) {
|
||||
if spec.RollbackConfig == nil {
|
||||
spec.RollbackConfig = &swarm.UpdateConfig{}
|
||||
spec.RollbackConfig = updateConfigFromDefaults(defaults.Service.Rollback)
|
||||
}
|
||||
updateUint64(flagRollbackParallelism, &spec.RollbackConfig.Parallelism)
|
||||
updateDuration(flagRollbackDelay, &spec.RollbackConfig.Delay)
|
||||
|
|
|
@ -4,6 +4,7 @@ import (
|
|||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/cli"
|
||||
"github.com/docker/docker/cli/command"
|
||||
"github.com/docker/docker/cli/command/inspect"
|
||||
|
@ -79,7 +80,8 @@ func inspectNode(ctx context.Context, dockerCli *command.DockerCli) inspect.GetR
|
|||
|
||||
func inspectService(ctx context.Context, dockerCli *command.DockerCli) inspect.GetRefFunc {
|
||||
return func(ref string) (interface{}, []byte, error) {
|
||||
return dockerCli.Client().ServiceInspectWithRaw(ctx, ref)
|
||||
// Service inspect shows defaults values in empty fields.
|
||||
return dockerCli.Client().ServiceInspectWithRaw(ctx, ref, types.ServiceInspectOptions{InsertDefaults: true})
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -123,7 +123,7 @@ type PluginAPIClient interface {
|
|||
// ServiceAPIClient defines API client methods for the services
|
||||
type ServiceAPIClient interface {
|
||||
ServiceCreate(ctx context.Context, service swarm.ServiceSpec, options types.ServiceCreateOptions) (types.ServiceCreateResponse, error)
|
||||
ServiceInspectWithRaw(ctx context.Context, serviceID string) (swarm.Service, []byte, error)
|
||||
ServiceInspectWithRaw(ctx context.Context, serviceID string, options types.ServiceInspectOptions) (swarm.Service, []byte, error)
|
||||
ServiceList(ctx context.Context, options types.ServiceListOptions) ([]swarm.Service, error)
|
||||
ServiceRemove(ctx context.Context, serviceID string) error
|
||||
ServiceUpdate(ctx context.Context, serviceID string, version swarm.Version, service swarm.ServiceSpec, options types.ServiceUpdateOptions) (types.ServiceUpdateResponse, error)
|
||||
|
|
|
@ -3,16 +3,21 @@ package client
|
|||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/url"
|
||||
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/api/types/swarm"
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
||||
// ServiceInspectWithRaw returns the service information and the raw data.
|
||||
func (cli *Client) ServiceInspectWithRaw(ctx context.Context, serviceID string) (swarm.Service, []byte, error) {
|
||||
serverResp, err := cli.get(ctx, "/services/"+serviceID, nil, nil)
|
||||
func (cli *Client) ServiceInspectWithRaw(ctx context.Context, serviceID string, opts types.ServiceInspectOptions) (swarm.Service, []byte, error) {
|
||||
query := url.Values{}
|
||||
query.Set("insertDefaults", fmt.Sprintf("%v", opts.InsertDefaults))
|
||||
serverResp, err := cli.get(ctx, "/services/"+serviceID, query, nil)
|
||||
if err != nil {
|
||||
if serverResp.statusCode == http.StatusNotFound {
|
||||
return swarm.Service{}, nil, serviceNotFoundError{serviceID}
|
||||
|
|
|
@ -9,6 +9,7 @@ import (
|
|||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/api/types/swarm"
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
@ -18,7 +19,7 @@ func TestServiceInspectError(t *testing.T) {
|
|||
client: newMockClient(errorMock(http.StatusInternalServerError, "Server error")),
|
||||
}
|
||||
|
||||
_, _, err := client.ServiceInspectWithRaw(context.Background(), "nothing")
|
||||
_, _, err := client.ServiceInspectWithRaw(context.Background(), "nothing", types.ServiceInspectOptions{})
|
||||
if err == nil || err.Error() != "Error response from daemon: Server error" {
|
||||
t.Fatalf("expected a Server Error, got %v", err)
|
||||
}
|
||||
|
@ -29,7 +30,7 @@ func TestServiceInspectServiceNotFound(t *testing.T) {
|
|||
client: newMockClient(errorMock(http.StatusNotFound, "Server error")),
|
||||
}
|
||||
|
||||
_, _, err := client.ServiceInspectWithRaw(context.Background(), "unknown")
|
||||
_, _, err := client.ServiceInspectWithRaw(context.Background(), "unknown", types.ServiceInspectOptions{})
|
||||
if err == nil || !IsErrServiceNotFound(err) {
|
||||
t.Fatalf("expected a serviceNotFoundError error, got %v", err)
|
||||
}
|
||||
|
@ -55,7 +56,7 @@ func TestServiceInspect(t *testing.T) {
|
|||
}),
|
||||
}
|
||||
|
||||
serviceInspect, _, err := client.ServiceInspectWithRaw(context.Background(), "service_id")
|
||||
serviceInspect, _, err := client.ServiceInspectWithRaw(context.Background(), "service_id", types.ServiceInspectOptions{})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
|
|
@ -58,9 +58,9 @@ func getNode(ctx context.Context, c swarmapi.ControlClient, input string) (*swar
|
|||
return rl.Nodes[0], nil
|
||||
}
|
||||
|
||||
func getService(ctx context.Context, c swarmapi.ControlClient, input string) (*swarmapi.Service, error) {
|
||||
func getService(ctx context.Context, c swarmapi.ControlClient, input string, insertDefaults bool) (*swarmapi.Service, error) {
|
||||
// GetService to match via full ID.
|
||||
if rg, err := c.GetService(ctx, &swarmapi.GetServiceRequest{ServiceID: input}); err == nil {
|
||||
if rg, err := c.GetService(ctx, &swarmapi.GetServiceRequest{ServiceID: input, InsertDefaults: insertDefaults}); err == nil {
|
||||
return rg.Service, nil
|
||||
}
|
||||
|
||||
|
@ -91,7 +91,15 @@ func getService(ctx context.Context, c swarmapi.ControlClient, input string) (*s
|
|||
return nil, fmt.Errorf("service %s is ambiguous (%d matches found)", input, l)
|
||||
}
|
||||
|
||||
return rl.Services[0], nil
|
||||
if !insertDefaults {
|
||||
return rl.Services[0], nil
|
||||
}
|
||||
|
||||
rg, err := c.GetService(ctx, &swarmapi.GetServiceRequest{ServiceID: rl.Services[0].ID, InsertDefaults: true})
|
||||
if err == nil {
|
||||
return rg.Service, nil
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
|
||||
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
|
|||
}
|
||||
|
||||
// GetService returns a service based on an ID or name.
|
||||
func (c *Cluster) GetService(input string) (types.Service, error) {
|
||||
func (c *Cluster) GetService(input string, insertDefaults bool) (types.Service, error) {
|
||||
var service *swarmapi.Service
|
||||
if err := c.lockedManagerAction(func(ctx context.Context, state nodeState) error {
|
||||
s, err := getService(ctx, state.controlClient, input)
|
||||
s, err := getService(ctx, state.controlClient, input, insertDefaults)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -187,7 +187,7 @@ func (c *Cluster) UpdateService(serviceIDOrName string, version uint64, spec typ
|
|||
return apierrors.NewBadRequestError(err)
|
||||
}
|
||||
|
||||
currentService, err := getService(ctx, state.controlClient, serviceIDOrName)
|
||||
currentService, err := getService(ctx, state.controlClient, serviceIDOrName, false)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -289,7 +289,7 @@ func (c *Cluster) UpdateService(serviceIDOrName string, version uint64, spec typ
|
|||
// RemoveService removes a service from a managed swarm cluster.
|
||||
func (c *Cluster) RemoveService(input string) error {
|
||||
return c.lockedManagerAction(func(ctx context.Context, state nodeState) error {
|
||||
service, err := getService(ctx, state.controlClient, input)
|
||||
service, err := getService(ctx, state.controlClient, input, false)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -442,7 +442,7 @@ func convertSelector(ctx context.Context, cc swarmapi.ControlClient, selector *b
|
|||
// don't rely on swarmkit to resolve IDs, do it ourselves
|
||||
swarmSelector := &swarmapi.LogSelector{}
|
||||
for _, s := range selector.Services {
|
||||
service, err := getService(ctx, cc, s)
|
||||
service, err := getService(ctx, cc, s, false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
@ -23,7 +23,7 @@ func (c *Cluster) GetTasks(options apitypes.TaskListOptions) ([]types.Task, erro
|
|||
if filter.Include("service") {
|
||||
serviceFilters := filter.Get("service")
|
||||
for _, serviceFilter := range serviceFilters {
|
||||
service, err := c.GetService(serviceFilter)
|
||||
service, err := c.GetService(serviceFilter, false)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -21,61 +21,60 @@ Usage: docker service create [OPTIONS] IMAGE [COMMAND] [ARG...]
|
|||
Create a new service
|
||||
|
||||
Options:
|
||||
--constraint list Placement constraints (default [])
|
||||
--container-label list Container labels (default [])
|
||||
-d, --detach Exit immediately instead of waiting for the service to converge
|
||||
(default true)
|
||||
--dns list Set custom DNS servers (default [])
|
||||
--dns-option list Set DNS options (default [])
|
||||
--dns-search list Set custom DNS search domains (default [])
|
||||
--endpoint-mode string Endpoint mode ("vip"|"dnsrr") (default "vip")
|
||||
-e, --env list Set environment variables (default [])
|
||||
--env-file list Read in a file of environment variables (default [])
|
||||
--group list Set one or more supplementary user groups for the container (default [])
|
||||
--constraint list Placement constraints
|
||||
--container-label list Container labels
|
||||
-d, --detach Exit immediately instead of waiting for the service to converge (default true)
|
||||
--dns list Set custom DNS servers
|
||||
--dns-option list Set DNS options
|
||||
--dns-search list Set custom DNS search domains
|
||||
--endpoint-mode string Endpoint mode (vip or dnsrr) (default "vip")
|
||||
--entrypoint command Overwrite the default ENTRYPOINT of the image
|
||||
-e, --env list Set environment variables
|
||||
--env-file list Read in a file of environment variables
|
||||
--group list Set one or more supplementary user groups for the container
|
||||
--health-cmd string Command to run to check health
|
||||
--health-interval duration Time between running the check (ns|us|ms|s|m|h)
|
||||
--health-retries int Consecutive failures needed to report unhealthy
|
||||
--health-start-period duration Start period for the container to initialize before counting retries towards unstable (ns|us|ms|s|m|h)
|
||||
--health-timeout duration Maximum time to allow one check to run (ns|us|ms|s|m|h)
|
||||
--health-start-period duration Start period for the container to initialize before counting retries towards unstable (ns|us|ms|s|m|h) (default 0s)
|
||||
--help Print usage
|
||||
--host list Set one or more custom host-to-IP mappings (host:ip) (default [])
|
||||
--host list Set one or more custom host-to-IP mappings (host:ip)
|
||||
--hostname string Container hostname
|
||||
-l, --label list Service labels (default [])
|
||||
--limit-cpu decimal Limit CPUs (default 0.000)
|
||||
-l, --label list Service labels
|
||||
--limit-cpu decimal Limit CPUs
|
||||
--limit-memory bytes Limit Memory
|
||||
--log-driver string Logging driver for service
|
||||
--log-opt list Logging driver options (default [])
|
||||
--log-opt list Logging driver options
|
||||
--mode string Service mode (replicated or global) (default "replicated")
|
||||
--mount mount Attach a filesystem mount to the service
|
||||
--name string Service name
|
||||
--network list Network attachments (default [])
|
||||
--network list Network attachments
|
||||
--no-healthcheck Disable any container-specified HEALTHCHECK
|
||||
--placement-pref pref Add a placement preference
|
||||
-p, --publish port Publish a port as a node port
|
||||
-q, --quiet Suppress progress output
|
||||
--read-only Mount the container's root filesystem as read only
|
||||
--replicas uint Number of tasks
|
||||
--reserve-cpu decimal Reserve CPUs (default 0.000)
|
||||
--reserve-cpu decimal Reserve CPUs
|
||||
--reserve-memory bytes Reserve Memory
|
||||
--restart-condition string Restart when condition is met ("none"|"on-failure"|"any")
|
||||
--restart-delay duration Delay between restart attempts (ns|us|ms|s|m|h)
|
||||
--restart-condition string Restart when condition is met ("none"|"on-failure"|"any") (default "any")
|
||||
--restart-delay duration Delay between restart attempts (ns|us|ms|s|m|h) (default 5s)
|
||||
--restart-max-attempts uint Maximum number of restarts before giving up
|
||||
--restart-window duration Window used to evaluate the restart policy (ns|us|ms|s|m|h)
|
||||
--rollback-delay duration Delay between task rollbacks (ns|us|ms|s|m|h) (default 0s)
|
||||
--rollback-failure-action string Action on rollback failure ("pause"|"continue") (default "pause")
|
||||
--rollback-max-failure-ratio float Failure rate to tolerate during a rollback
|
||||
--rollback-monitor duration Duration after each task rollback to monitor for failure
|
||||
(ns|us|ms|s|m|h) (default 0s)
|
||||
--rollback-max-failure-ratio float Failure rate to tolerate during a rollback (default 0)
|
||||
--rollback-monitor duration Duration after each task rollback to monitor for failure (ns|us|ms|s|m|h) (default 5s)
|
||||
--rollback-order string Rollback order ("start-first"|"stop-first") (default "stop-first")
|
||||
--rollback-parallelism uint Maximum number of tasks rolled back simultaneously (0 to roll
|
||||
back all at once) (default 1)
|
||||
--rollback-parallelism uint Maximum number of tasks rolled back simultaneously (0 to roll back all at once) (default 1)
|
||||
--secret secret Specify secrets to expose to the service
|
||||
--stop-grace-period duration Time to wait before force killing a container (ns|us|ms|s|m|h)
|
||||
--stop-grace-period duration Time to wait before force killing a container (ns|us|ms|s|m|h) (default 10s)
|
||||
--stop-signal string Signal to stop the container
|
||||
-t, --tty Allocate a pseudo-TTY
|
||||
--update-delay duration Delay between updates (ns|us|ms|s|m|h) (default 0s)
|
||||
--update-failure-action string Action on update failure ("pause"|"continue"|"rollback") (default "pause")
|
||||
--update-max-failure-ratio float Failure rate to tolerate during an update
|
||||
--update-monitor duration Duration after each task update to monitor for failure (ns|us|ms|s|m|h)
|
||||
--update-max-failure-ratio float Failure rate to tolerate during an update (default 0)
|
||||
--update-monitor duration Duration after each task update to monitor for failure (ns|us|ms|s|m|h) (default 5s)
|
||||
--update-order string Update order ("start-first"|"stop-first") (default "stop-first")
|
||||
--update-parallelism uint Maximum number of tasks updated simultaneously (0 to update all at once) (default 1)
|
||||
-u, --user string Username or UID (format: <name|uid>[:<group|gid>])
|
||||
|
|
|
@ -21,43 +21,43 @@ Usage: docker service update [OPTIONS] SERVICE
|
|||
Update a service
|
||||
|
||||
Options:
|
||||
--args string Service command args
|
||||
--constraint-add list Add or update a placement constraint (default [])
|
||||
--constraint-rm list Remove a constraint (default [])
|
||||
--container-label-add list Add or update a container label (default [])
|
||||
--container-label-rm list Remove a container label by its key (default [])
|
||||
-d, --detach Exit immediately instead of waiting for the service to converge
|
||||
(default true)
|
||||
--dns-add list Add or update a custom DNS server (default [])
|
||||
--dns-option-add list Add or update a DNS option (default [])
|
||||
--dns-option-rm list Remove a DNS option (default [])
|
||||
--dns-rm list Remove a custom DNS server (default [])
|
||||
--dns-search-add list Add or update a custom DNS search domain (default [])
|
||||
--dns-search-rm list Remove a DNS search domain (default [])
|
||||
--endpoint-mode string Endpoint mode ("vip"|"dnsrr") (default "vip")
|
||||
--env-add list Add or update an environment variable (default [])
|
||||
--env-rm list Remove an environment variable (default [])
|
||||
--args command Service command args
|
||||
--constraint-add list Add or update a placement constraint
|
||||
--constraint-rm list Remove a constraint
|
||||
--container-label-add list Add or update a container label
|
||||
--container-label-rm list Remove a container label by its key
|
||||
-d, --detach Exit immediately instead of waiting for the service to converge (default true)
|
||||
--dns-add list Add or update a custom DNS server
|
||||
--dns-option-add list Add or update a DNS option
|
||||
--dns-option-rm list Remove a DNS option
|
||||
--dns-rm list Remove a custom DNS server
|
||||
--dns-search-add list Add or update a custom DNS search domain
|
||||
--dns-search-rm list Remove a DNS search domain
|
||||
--endpoint-mode string Endpoint mode (vip or dnsrr)
|
||||
--entrypoint command Overwrite the default ENTRYPOINT of the image
|
||||
--env-add list Add or update an environment variable
|
||||
--env-rm list Remove an environment variable
|
||||
--force Force update even if no changes require it
|
||||
--group-add list Add an additional supplementary user group to the container (default [])
|
||||
--group-rm list Remove a previously added supplementary user group from the container (default [])
|
||||
--group-add list Add an additional supplementary user group to the container
|
||||
--group-rm list Remove a previously added supplementary user group from the container
|
||||
--health-cmd string Command to run to check health
|
||||
--health-interval duration Time between running the check (ns|us|ms|s|m|h)
|
||||
--health-retries int Consecutive failures needed to report unhealthy
|
||||
--health-start-period duration Start period for the container to initialize before counting retries towards unstable (ns|us|ms|s|m|h)
|
||||
--health-timeout duration Maximum time to allow one check to run (ns|us|ms|s|m|h)
|
||||
--health-start-period duration Start period for the container to initialize before counting retries towards unstable (ns|us|ms|s|m|h) (default 0s)
|
||||
--help Print usage
|
||||
--host-add list Add or update a custom host-to-IP mapping (host:ip) (default [])
|
||||
--host-rm list Remove a custom host-to-IP mapping (host:ip) (default [])
|
||||
--host-add list Add or update a custom host-to-IP mapping (host:ip)
|
||||
--host-rm list Remove a custom host-to-IP mapping (host:ip)
|
||||
--hostname string Container hostname
|
||||
--image string Service image tag
|
||||
--label-add list Add or update a service label (default [])
|
||||
--label-rm list Remove a label by its key (default [])
|
||||
--limit-cpu decimal Limit CPUs (default 0.000)
|
||||
--label-add list Add or update a service label
|
||||
--label-rm list Remove a label by its key
|
||||
--limit-cpu decimal Limit CPUs
|
||||
--limit-memory bytes Limit Memory
|
||||
--log-driver string Logging driver for service
|
||||
--log-opt list Logging driver options (default [])
|
||||
--log-opt list Logging driver options
|
||||
--mount-add mount Add or update a mount on a service
|
||||
--mount-rm list Remove a mount by its target path (default [])
|
||||
--mount-rm list Remove a mount by its target path
|
||||
--network-add list Add a network
|
||||
--network-rm list Remove a network
|
||||
--no-healthcheck Disable any container-specified HEALTHCHECK
|
||||
|
@ -65,34 +65,33 @@ Options:
|
|||
--placement-pref-rm pref Remove a placement preference
|
||||
--publish-add port Add or update a published port
|
||||
--publish-rm port Remove a published port by its target port
|
||||
-q, --quiet Suppress progress output
|
||||
--read-only Mount the container's root filesystem as read only
|
||||
--replicas uint Number of tasks
|
||||
--reserve-cpu decimal Reserve CPUs (default 0.000)
|
||||
--reserve-cpu decimal Reserve CPUs
|
||||
--reserve-memory bytes Reserve Memory
|
||||
--restart-condition string Restart when condition is met ("none"|"on-failure"|"any")
|
||||
--restart-delay duration Delay between restart attempts (ns|us|ms|s|m|h)
|
||||
--restart-max-attempts uint Maximum number of restarts before giving up
|
||||
--restart-window duration Window used to evaluate the restart policy (ns|us|ms|s|m|h)
|
||||
--rollback Rollback to previous specification
|
||||
--rollback-delay duration Delay between task rollbacks (ns|us|ms|s|m|h) (default 0s)
|
||||
--rollback-failure-action string Action on rollback failure ("pause"|"continue") (default "pause")
|
||||
--rollback-delay duration Delay between task rollbacks (ns|us|ms|s|m|h)
|
||||
--rollback-failure-action string Action on rollback failure ("pause"|"continue")
|
||||
--rollback-max-failure-ratio float Failure rate to tolerate during a rollback
|
||||
--rollback-monitor duration Duration after each task rollback to monitor for failure
|
||||
(ns|us|ms|s|m|h) (default 0s)
|
||||
--rollback-monitor duration Duration after each task rollback to monitor for failure (ns|us|ms|s|m|h)
|
||||
--rollback-order string Rollback order ("start-first"|"stop-first") (default "stop-first")
|
||||
--rollback-parallelism uint Maximum number of tasks rolled back simultaneously (0 to roll
|
||||
back all at once) (default 1)
|
||||
--rollback-parallelism uint Maximum number of tasks rolled back simultaneously (0 to roll back all at once)
|
||||
--secret-add secret Add or update a secret on a service
|
||||
--secret-rm list Remove a secret (default [])
|
||||
--secret-rm list Remove a secret
|
||||
--stop-grace-period duration Time to wait before force killing a container (ns|us|ms|s|m|h)
|
||||
--stop-signal string Signal to stop the container
|
||||
-t, --tty Allocate a pseudo-TTY
|
||||
--update-delay duration Delay between updates (ns|us|ms|s|m|h) (default 0s)
|
||||
--update-failure-action string Action on update failure ("pause"|"continue"|"rollback") (default "pause")
|
||||
--update-delay duration Delay between updates (ns|us|ms|s|m|h)
|
||||
--update-failure-action string Action on update failure ("pause"|"continue"|"rollback")
|
||||
--update-max-failure-ratio float Failure rate to tolerate during an update
|
||||
--update-monitor duration Duration after each task update to monitor for failure (ns|us|ms|s|m|h)
|
||||
--update-order string Update order ("start-first"|"stop-first") (default "stop-first")
|
||||
--update-parallelism uint Maximum number of tasks updated simultaneously (0 to update all at once) (default 1)
|
||||
--update-monitor duration Duration after each task update to monitor for failure (ns|us|ms|s|m|h)
|
||||
--update-order string Update order ("start-first"|"stop-first")
|
||||
--update-parallelism uint Maximum number of tasks updated simultaneously (0 to update all at once)
|
||||
-u, --user string Username or UID (format: <name|uid>[:<group|gid>])
|
||||
--with-registry-auth Send registry authentication details to swarm agents
|
||||
-w, --workdir string Working directory inside the container
|
||||
|
|
|
@ -60,6 +60,16 @@ func (s *DockerSwarmSuite) TestAPISwarmServicesCreate(c *check.C) {
|
|||
id := d.CreateService(c, simpleTestService, setInstances(instances))
|
||||
waitAndAssert(c, defaultReconciliationTimeout, d.CheckActiveContainerCount, checker.Equals, instances)
|
||||
|
||||
// insertDefaults inserts UpdateConfig when service is fetched by ID
|
||||
_, out, err := d.SockRequest("GET", "/services/"+id+"?insertDefaults=true", nil)
|
||||
c.Assert(err, checker.IsNil, check.Commentf("%s", out))
|
||||
c.Assert(string(out), checker.Contains, "UpdateConfig")
|
||||
|
||||
// insertDefaults inserts UpdateConfig when service is fetched by ID
|
||||
_, out, err = d.SockRequest("GET", "/services/top?insertDefaults=true", nil)
|
||||
c.Assert(err, checker.IsNil, check.Commentf("%s", out))
|
||||
c.Assert(string(out), checker.Contains, "UpdateConfig")
|
||||
|
||||
service := d.GetService(c, id)
|
||||
instances = 5
|
||||
d.UpdateService(c, service, setInstances(instances))
|
||||
|
|
|
@ -38,7 +38,10 @@ func NewListOptsRef(values *[]string, validator ValidatorFctType) *ListOpts {
|
|||
}
|
||||
|
||||
func (opts *ListOpts) String() string {
|
||||
return fmt.Sprintf("%v", []string((*opts.values)))
|
||||
if len(*opts.values) == 0 {
|
||||
return ""
|
||||
}
|
||||
return fmt.Sprintf("%v", *opts.values)
|
||||
}
|
||||
|
||||
// Set validates if needed the input value and adds it to the
|
||||
|
@ -343,6 +346,9 @@ type NanoCPUs int64
|
|||
|
||||
// String returns the string format of the number
|
||||
func (c *NanoCPUs) String() string {
|
||||
if *c == 0 {
|
||||
return ""
|
||||
}
|
||||
return big.NewRat(c.Value(), 1e9).FloatString(3)
|
||||
}
|
||||
|
||||
|
|
|
@ -93,12 +93,12 @@ func TestListOptsWithValidator(t *testing.T) {
|
|||
// Re-using logOptsvalidator (used by MapOpts)
|
||||
o := NewListOpts(logOptsValidator)
|
||||
o.Set("foo")
|
||||
if o.String() != "[]" {
|
||||
t.Errorf("%s != []", o.String())
|
||||
if o.String() != "" {
|
||||
t.Errorf(`%s != ""`, o.String())
|
||||
}
|
||||
o.Set("foo=bar")
|
||||
if o.String() != "[]" {
|
||||
t.Errorf("%s != []", o.String())
|
||||
if o.String() != "" {
|
||||
t.Errorf(`%s != ""`, o.String())
|
||||
}
|
||||
o.Set("max-file=2")
|
||||
if o.Len() != 1 {
|
||||
|
@ -111,8 +111,8 @@ func TestListOptsWithValidator(t *testing.T) {
|
|||
t.Error("o.Get(\"baz\") == true")
|
||||
}
|
||||
o.Delete("max-file=2")
|
||||
if o.String() != "[]" {
|
||||
t.Errorf("%s != []", o.String())
|
||||
if o.String() != "" {
|
||||
t.Errorf(`%s != ""`, o.String())
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue