Skip to content
This repository was archived by the owner on Feb 1, 2021. It is now read-only.

Commit b72d27f

Browse files
committed
explicit failure
Signed-off-by: Victor Vieux <vieux@docker.com>
1 parent adc087c commit b72d27f

File tree

5 files changed

+64
-36
lines changed

5 files changed

+64
-36
lines changed

api/handlers.go

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -438,8 +438,14 @@ func postContainersCreate(c *context, w http.ResponseWriter, r *http.Request) {
438438
authConfig = &dockerclient.AuthConfig{}
439439
json.Unmarshal(buf, authConfig)
440440
}
441+
containerConfig := cluster.BuildContainerConfig(config)
441442

442-
container, err := c.cluster.CreateContainer(cluster.BuildContainerConfig(config), name, authConfig)
443+
if err := containerConfig.Validate(); err != nil {
444+
httpError(w, err.Error(), http.StatusInternalServerError)
445+
return
446+
}
447+
448+
container, err := c.cluster.CreateContainer(containerConfig, name, authConfig)
443449
if err != nil {
444450
if strings.HasPrefix(err.Error(), "Conflict") {
445451
httpError(w, err.Error(), http.StatusConflict)

cluster/config.go

Lines changed: 42 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ package cluster
22

33
import (
44
"encoding/json"
5+
"errors"
6+
"fmt"
57
"strings"
68

79
"github.com/samalba/dockerclient"
@@ -63,10 +65,10 @@ func consolidateResourceFields(c *dockerclient.ContainerConfig) {
6365
// BuildContainerConfig creates a cluster.ContainerConfig from a dockerclient.ContainerConfig
6466
func BuildContainerConfig(c dockerclient.ContainerConfig) *ContainerConfig {
6567
var (
66-
affinities []string
67-
constraints []string
68-
reschedulePolicy string
69-
env []string
68+
affinities []string
69+
constraints []string
70+
reschedulePolicies []string
71+
env []string
7072
)
7173

7274
// only for tests
@@ -84,9 +86,9 @@ func BuildContainerConfig(c dockerclient.ContainerConfig) *ContainerConfig {
8486
json.Unmarshal([]byte(labels), &constraints)
8587
}
8688

87-
// parse reschedule policy from labels (ex. docker run --label 'com.docker.swarm.reschedule-policy=on-node-failure')
88-
if label, ok := c.Labels[SwarmLabelNamespace+".reschedule-policy"]; ok {
89-
reschedulePolicy = label
89+
// parse reschedule policy from labels (ex. docker run --label 'com.docker.swarm.reschedule-policies=on-node-failure')
90+
if labels, ok := c.Labels[SwarmLabelNamespace+".reschedule-policies"]; ok {
91+
json.Unmarshal([]byte(labels), &reschedulePolicies)
9092
}
9193

9294
// parse affinities/constraints/reschedule policies from env (ex. docker run -e affinity:container==redis -e affinity:image==nginx -e constraint:region==us-east -e constraint:storage==ssd -e reschedule:off)
@@ -96,12 +98,7 @@ func BuildContainerConfig(c dockerclient.ContainerConfig) *ContainerConfig {
9698
} else if ok && key == "constraint" {
9799
constraints = append(constraints, value)
98100
} else if ok && key == "reschedule" {
99-
if reschedulePolicy == "" {
100-
reschedulePolicy = value
101-
} else if reschedulePolicy != value {
102-
// for off on conflict
103-
reschedulePolicy = "off"
104-
}
101+
reschedulePolicies = append(reschedulePolicies, value)
105102
} else {
106103
env = append(env, e)
107104
}
@@ -124,9 +121,11 @@ func BuildContainerConfig(c dockerclient.ContainerConfig) *ContainerConfig {
124121
}
125122
}
126123

127-
// store reschedule policy in labels
128-
if reschedulePolicy != "" {
129-
c.Labels[SwarmLabelNamespace+".reschedule-policy"] = reschedulePolicy
124+
// store reschedule policies in labels
125+
if len(reschedulePolicies) > 0 {
126+
if labels, err := json.Marshal(reschedulePolicies); err == nil {
127+
c.Labels[SwarmLabelNamespace+".reschedule-policies"] = string(labels)
128+
}
130129
}
131130

132131
consolidateResourceFields(&c)
@@ -205,11 +204,32 @@ func (c *ContainerConfig) HaveNodeConstraint() bool {
205204
return false
206205
}
207206

208-
// ReschedulePolicy returns the current rescheduling policy
209-
func (c *ContainerConfig) ReschedulePolicy() string {
210-
policy, ok := c.Labels[SwarmLabelNamespace+".reschedule-policy"]
211-
if !ok {
212-
return "off"
207+
// HasReschedulePolicy returns true if the specified policy is part of the config
208+
func (c *ContainerConfig) HasReschedulePolicy(p string) bool {
209+
for _, reschedulePolicy := range c.extractExprs("reschedule-policies") {
210+
if reschedulePolicy == p {
211+
return true
212+
}
213+
}
214+
return false
215+
}
216+
217+
// Validate returns an error if the config isn't valid
218+
func (c *ContainerConfig) Validate() error {
219+
//TODO: add validation for affinities and constraints
220+
reschedulePolicies := c.extractExprs("reschedule-policies")
221+
if len(reschedulePolicies) > 1 {
222+
return errors.New("too many reschedule policies")
223+
} else if len(reschedulePolicies) == 1 {
224+
valid := false
225+
for _, validReschedulePolicy := range []string{"off", "on-node-failure"} {
226+
if reschedulePolicies[0] == validReschedulePolicy {
227+
valid = true
228+
}
229+
}
230+
if !valid {
231+
return fmt.Errorf("invalid reschedule policy: %s", reschedulePolicies[0])
232+
}
213233
}
214-
return policy
234+
return nil
215235
}

cluster/watchdog.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -74,8 +74,8 @@ func (w *Watchdog) rescheduleContainers(e *Engine) {
7474

7575
func (w *Watchdog) rescheduleContainer(c *Container) {
7676
// Skip containers which don't have an "on-node-failure" reschedule policy.
77-
if c.Config.ReschedulePolicy() != "on-node-failure" {
78-
log.Debugf("Skipping rescheduling of %s based on rescheduling policy", c.Id)
77+
if !c.Config.HasReschedulePolicy("on-node-failure") {
78+
log.Debugf("Skipping rescheduling of %s based on rescheduling policies", c.Id)
7979
return
8080
}
8181

docs/scheduler/rescheduling.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,14 +30,14 @@ apply to the container.
3030
# do not reschedule (default)
3131
$ docker run -d -e reschedule:off redis
3232
# or
33-
$ docker run -d -l com.docker.swarm.reschedule-policy=off redis
33+
$ docker run -d -l 'com.docker.swarm.reschedule-policy=["off"]' redis
3434
```
3535

3636
```
3737
# reschedule on node failure
3838
$ docker run -d -e reschedule:on-node-failure redis
3939
# or
40-
$ docker run -d -l com.docker.swarm.reschedule-policy=on-node-failure redis
40+
$ docker run -d -l 'com.docker.swarm.reschedule-policy=["on-node-failure"]' redis
4141
```
4242

4343
- [Docker Swarm overview](../index.md)

test/integration/rescheduling.bats

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,13 @@ function teardown() {
1212
swarm_manage --engine-refresh-min-interval=1s --engine-refresh-max-interval=1s --engine-failure-retry=1 ${HOSTS[0]},${HOSTS[1]}
1313

1414
# c1 on node-0 with reschedule=on-node-failure
15-
run docker_swarm run -dit --name c1 -e constraint:node==~node-0 --label com.docker.swarm.reschedule-policy=on-node-failure busybox sh
15+
run docker_swarm run -dit --name c1 -e constraint:node==~node-0 --label 'com.docker.swarm.reschedule-policies=["on-node-failure"]' busybox sh
1616
[ "$status" -eq 0 ]
1717
# c2 on node-0 with reschedule=off
18-
run docker_swarm run -dit --name c2 -e constraint:node==~node-0 --label com.docker.swarm.reschedule-policy=off busybox sh
18+
run docker_swarm run -dit --name c2 -e constraint:node==~node-0 --label 'com.docker.swarm.reschedule-policies=["off"]' busybox sh
1919
[ "$status" -eq 0 ]
2020
# c3 on node-1
21-
run docker_swarm run -dit --name c3 -e constraint:node==~node-1 --label com.docker.swarm.reschedule-policy=on-node-failure busybox sh
21+
run docker_swarm run -dit --name c3 -e constraint:node==~node-1 --label 'com.docker.swarm.reschedule-policies=["on-node-failure"]' busybox sh
2222
[ "$status" -eq 0 ]
2323

2424
run docker_swarm ps -q
@@ -119,11 +119,13 @@ function teardown() {
119119
start_docker_with_busybox 2
120120
swarm_manage
121121

122-
docker_swarm run --name c1 -dit -e reschedule:on-node-failure --label com.docker.swarm.reschedule-policy=off busybox sh
123-
[[ $(docker_swarm inspect -f '{{ index .Config.Labels "com.docker.swarm.reschedule-policy" }}' c1) == "off" ]]
122+
run docker_swarm run --name c1 -dit --label 'com.docker.swarm.reschedule-policies=["false"]' busybox sh
123+
[ "$status" -ne 0 ]
124+
[[ "${output}" == *'invalid reschedule policy: false'* ]]
124125

125-
docker_swarm run --name c2 -dit -e reschedule:off --label com.docker.swarm.reschedule-policy=on-node-failure busybox sh
126-
[[ $(docker_swarm inspect -f '{{ index .Config.Labels "com.docker.swarm.reschedule-policy" }}' c2) == "off" ]]
126+
run docker_swarm run --name c2 -dit -e reschedule:off --label 'com.docker.swarm.reschedule-policies=["on-node-failure"]' -e reschedule:off busybox sh
127+
[ "$status" -ne 0 ]
128+
[[ "${output}" == *'too many reschedule policies'* ]]
127129
}
128130

129131
@test "rescheduling pending" {
@@ -185,10 +187,10 @@ function teardown() {
185187
swarm_manage --engine-refresh-min-interval=1s --engine-refresh-max-interval=1s --engine-failure-retry=1 ${HOSTS[0]},${HOSTS[1]}
186188

187189
# c1 on node-0 with reschedule=on-node-failure
188-
run docker_swarm run -dit --name c1 -e constraint:node==~node-0 --label com.docker.swarm.reschedule-policy=on-node-failure busybox sh
190+
run docker_swarm run -dit --name c1 -e constraint:node==~node-0 --label com.docker.swarm.reschedule-policies=["on-node-failure"] busybox sh
189191
[ "$status" -eq 0 ]
190192
# c2 on node-1
191-
run docker_swarm run -dit --name c2 -e constraint:node==~node-1 --label com.docker.swarm.reschedule-policy=on-node-failure busybox sh
193+
run docker_swarm run -dit --name c2 -e constraint:node==~node-1 --label com.docker.swarm.reschedule-policies=["on-node-failure"] busybox sh
192194
[ "$status" -eq 0 ]
193195

194196
run docker_swarm ps -q

0 commit comments

Comments
 (0)