Skip to content

Commit eac151b

Browse files
committed
Add support for maximum replicas per node
Signed-off-by: Olli Janatuinen <olli.janatuinen@gmail.com>
1 parent 0ac5c15 commit eac151b

File tree

9 files changed

+702
-3
lines changed

9 files changed

+702
-3
lines changed

cli/command/service/formatter.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,9 @@ Placement:
4949
{{- if .TaskPlacementPreferences }}
5050
Preferences: {{ .TaskPlacementPreferences }}
5151
{{- end }}
52+
{{- if .MaxReplicas }}
53+
Max Replicas Per Node: {{ .MaxReplicas }}
54+
{{- end }}
5255
{{- if .HasUpdateConfig }}
5356
UpdateConfig:
5457
Parallelism: {{ .UpdateParallelism }}
@@ -284,6 +287,13 @@ func (ctx *serviceInspectContext) TaskPlacementPreferences() []string {
284287
return strings
285288
}
286289

290+
func (ctx *serviceInspectContext) MaxReplicas() uint64 {
291+
if ctx.Service.Spec.TaskTemplate.Placement != nil {
292+
return ctx.Service.Spec.TaskTemplate.Placement.MaxReplicas
293+
}
294+
return 0
295+
}
296+
287297
func (ctx *serviceInspectContext) HasUpdateConfig() bool {
288298
return ctx.Service.Spec.UpdateConfig != nil
289299
}

cli/command/service/list.go

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -120,9 +120,16 @@ func GetServicesStatus(services []swarm.Service, nodes []swarm.Node, tasks []swa
120120
for _, service := range services {
121121
info[service.ID] = ListInfo{}
122122
if service.Spec.Mode.Replicated != nil && service.Spec.Mode.Replicated.Replicas != nil {
123-
info[service.ID] = ListInfo{
124-
Mode: "replicated",
125-
Replicas: fmt.Sprintf("%d/%d", running[service.ID], *service.Spec.Mode.Replicated.Replicas),
123+
if service.Spec.TaskTemplate.Placement != nil && service.Spec.TaskTemplate.Placement.MaxReplicas > 0 {
124+
info[service.ID] = ListInfo{
125+
Mode: "replicated",
126+
Replicas: fmt.Sprintf("%d/%d (max %d per node)", running[service.ID], *service.Spec.Mode.Replicated.Replicas, service.Spec.TaskTemplate.Placement.MaxReplicas),
127+
}
128+
} else {
129+
info[service.ID] = ListInfo{
130+
Mode: "replicated",
131+
Replicas: fmt.Sprintf("%d/%d", running[service.ID], *service.Spec.Mode.Replicated.Replicas),
132+
}
126133
}
127134
} else if service.Spec.Mode.Global != nil {
128135
info[service.ID] = ListInfo{

cli/command/service/opts.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -499,6 +499,7 @@ type serviceOptions struct {
499499
restartPolicy restartPolicyOptions
500500
constraints opts.ListOpts
501501
placementPrefs placementPrefOpts
502+
maxReplicas uint64
502503
update updateOptions
503504
rollback updateOptions
504505
networks opts.NetworkOpt
@@ -540,6 +541,10 @@ func (options *serviceOptions) ToServiceMode() (swarm.ServiceMode, error) {
540541
return serviceMode, errors.Errorf("replicas can only be used with replicated mode")
541542
}
542543

544+
if options.maxReplicas > 0 {
545+
return serviceMode, errors.Errorf("replicas-max-per-node can only be used with replicated mode")
546+
}
547+
543548
serviceMode.Global = &swarm.GlobalService{}
544549
case "replicated":
545550
serviceMode.Replicated = &swarm.ReplicatedService{
@@ -644,6 +649,7 @@ func (options *serviceOptions) ToService(ctx context.Context, apiClient client.N
644649
Placement: &swarm.Placement{
645650
Constraints: options.constraints.GetAll(),
646651
Preferences: options.placementPrefs.prefs,
652+
MaxReplicas: options.maxReplicas,
647653
},
648654
LogDriver: options.logDriver.toLogDriver(),
649655
},
@@ -746,6 +752,7 @@ func addServiceFlags(flags *pflag.FlagSet, opts *serviceOptions, defaultFlagValu
746752

747753
flags.Var(&opts.stopGrace, flagStopGracePeriod, flagDesc(flagStopGracePeriod, "Time to wait before force killing a container (ns|us|ms|s|m|h)"))
748754
flags.Var(&opts.replicas, flagReplicas, "Number of tasks")
755+
flags.Uint64Var(&opts.maxReplicas, flagMaxReplicas, defaultFlagValues.getUint64(flagMaxReplicas), "Maximum number of tasks per node (default 0 = unlimited)")
749756

750757
flags.StringVar(&opts.restartPolicy.condition, flagRestartCondition, "", flagDesc(flagRestartCondition, `Restart when condition is met ("none"|"on-failure"|"any")`))
751758
flags.Var(&opts.restartPolicy.delay, flagRestartDelay, flagDesc(flagRestartDelay, "Delay between restart attempts (ns|us|ms|s|m|h)"))
@@ -852,6 +859,7 @@ const (
852859
flagLabelAdd = "label-add"
853860
flagLimitCPU = "limit-cpu"
854861
flagLimitMemory = "limit-memory"
862+
flagMaxReplicas = "replicas-max-per-node"
855863
flagMode = "mode"
856864
flagMount = "mount"
857865
flagMountRemove = "mount-rm"

cli/command/service/update.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -387,6 +387,10 @@ func updateService(ctx context.Context, apiClient client.NetworkAPIClient, flags
387387
return err
388388
}
389389

390+
if anyChanged(flags, flagMaxReplicas) {
391+
updateUint64(flagMaxReplicas, &task.Placement.MaxReplicas)
392+
}
393+
390394
if anyChanged(flags, flagUpdateParallelism, flagUpdateDelay, flagUpdateMonitor, flagUpdateFailureAction, flagUpdateMaxFailureRatio, flagUpdateOrder) {
391395
if spec.UpdateConfig == nil {
392396
spec.UpdateConfig = updateConfigFromDefaults(defaults.Service.Update)

cli/compose/convert/service.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,7 @@ func Service(
158158
Placement: &swarm.Placement{
159159
Constraints: service.Deploy.Placement.Constraints,
160160
Preferences: getPlacementPreference(service.Deploy.Placement.Preferences),
161+
MaxReplicas: service.Deploy.Placement.MaxReplicas,
161162
},
162163
},
163164
EndpointSpec: endpoint,

cli/compose/schema/bindata.go

Lines changed: 44 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)