Added support for maximum replicas per node to services

Signed-off-by: Olli Janatuinen <olli.janatuinen@gmail.com>
This commit is contained in:
Olli Janatuinen 2018-09-30 15:28:37 +03:00
parent 7e7ff2a033
commit 153171e9dd
7 changed files with 58 additions and 0 deletions

View file

@ -219,6 +219,12 @@ func (sr *swarmRouter) createService(ctx context.Context, w http.ResponseWriter,
// API version 1.40
service.TaskTemplate.ContainerSpec.Sysctls = nil
}
if service.TaskTemplate.Placement != nil {
// MaxReplicas for docker swarm services weren't supported before
// API version 1.40
service.TaskTemplate.Placement.MaxReplicas = 0
}
}
}
@ -265,6 +271,12 @@ func (sr *swarmRouter) updateService(ctx context.Context, w http.ResponseWriter,
// API version 1.40
service.TaskTemplate.ContainerSpec.Sysctls = nil
}
if service.TaskTemplate.Placement != nil {
// MaxReplicas for docker swarm services weren't supported before
// API version 1.40
service.TaskTemplate.Placement.MaxReplicas = 0
}
}
}

View file

@ -2878,6 +2878,11 @@ definitions:
SpreadDescriptor: "node.labels.datacenter"
- Spread:
SpreadDescriptor: "node.labels.rack"
MaxReplicas:
description: "Maximum number of replicas for per node (default value is 0, which is unlimited)"
type: "integer"
format: "int64"
default: 0
Platforms:
description: |
Platforms stores all the platforms that the service's image can

View file

@ -127,6 +127,7 @@ type ResourceRequirements struct {
type Placement struct {
Constraints []string `json:",omitempty"`
Preferences []PlacementPreference `json:",omitempty"`
MaxReplicas uint64 `json:",omitempty"`
// Platforms stores all the platforms that the image can run on.
// This field is used in the platform filter for scheduling. If empty,

View file

@ -246,6 +246,7 @@ func ServiceSpecToGRPC(s types.ServiceSpec) (swarmapi.ServiceSpec, error) {
spec.Task.Placement = &swarmapi.Placement{
Constraints: s.TaskTemplate.Placement.Constraints,
Preferences: preferences,
MaxReplicas: s.TaskTemplate.Placement.MaxReplicas,
Platforms: platforms,
}
}
@ -472,6 +473,7 @@ func placementFromGRPC(p *swarmapi.Placement) *types.Placement {
}
r := &types.Placement{
Constraints: p.Constraints,
MaxReplicas: p.MaxReplicas,
}
for _, pref := range p.Preferences {

View file

@ -33,6 +33,10 @@ keywords: "API, Docker, rcli, REST, documentation"
* `GET /info` now returns information about `DataPathPort` that is currently used in swarm
* `GET /swarm` endpoint now returns DataPathPort info
* `POST /containers/create` now takes `KernelMemoryTCP` field to set hard limit for kernel TCP buffer memory.
* `GET /service` now returns `MaxReplicas` as part of the `Placement`.
* `GET /service/{id}` now returns `MaxReplicas` as part of the `Placement`.
* `POST /service/create` and `POST /services/(id or name)/update` now take the field `MaxReplicas`
as part of the service `Placement`, allowing to specify maximum replicas per node for the service.
## V1.39 API changes

View file

@ -141,6 +141,14 @@ func ServiceWithReplicas(n uint64) ServiceSpecOpt {
}
}
// ServiceWithMaxReplicas sets the max replicas for the service
func ServiceWithMaxReplicas(n uint64) ServiceSpecOpt {
return func(spec *swarmtypes.ServiceSpec) {
ensurePlacement(spec)
spec.TaskTemplate.Placement.MaxReplicas = n
}
}
// ServiceWithName sets the name of the service
func ServiceWithName(name string) ServiceSpecOpt {
return func(spec *swarmtypes.ServiceSpec) {
@ -210,3 +218,9 @@ func ensureContainerSpec(spec *swarmtypes.ServiceSpec) {
spec.TaskTemplate.ContainerSpec = &swarmtypes.ContainerSpec{}
}
}
func ensurePlacement(spec *swarmtypes.ServiceSpec) {
if spec.TaskTemplate.Placement == nil {
spec.TaskTemplate.Placement = &swarmtypes.Placement{}
}
}

View file

@ -153,6 +153,26 @@ func TestCreateServiceConflict(t *testing.T) {
assert.Check(t, is.Contains(string(buf), "service "+serviceName+" already exists"))
}
func TestCreateServiceMaxReplicas(t *testing.T) {
defer setupTest(t)()
d := swarm.NewSwarm(t, testEnv)
defer d.Stop(t)
client := d.NewClientT(t)
defer client.Close()
var maxReplicas uint64 = 2
serviceSpec := []swarm.ServiceSpecOpt{
swarm.ServiceWithReplicas(maxReplicas),
swarm.ServiceWithMaxReplicas(maxReplicas),
}
serviceID := swarm.CreateService(t, d, serviceSpec...)
poll.WaitOn(t, serviceRunningTasksCount(client, serviceID, maxReplicas), swarm.ServicePoll)
_, _, err := client.ServiceInspectWithRaw(context.Background(), serviceID, types.ServiceInspectOptions{})
assert.NilError(t, err)
}
func TestCreateWithDuplicateNetworkNames(t *testing.T) {
skip.If(t, testEnv.DaemonInfo.OSType == "windows")
defer setupTest(t)()