@@ -2,6 +2,8 @@ package cluster
22
33import (
44 "encoding/json"
5+ "errors"
6+ "fmt"
57 "strings"
68
79 "github.com/samalba/dockerclient"
@@ -63,9 +65,10 @@ func consolidateResourceFields(c *dockerclient.ContainerConfig) {
6365// BuildContainerConfig creates a cluster.ContainerConfig from a dockerclient.ContainerConfig
6466func BuildContainerConfig (c dockerclient.ContainerConfig ) * ContainerConfig {
6567 var (
66- affinities []string
67- constraints []string
68- env []string
68+ affinities []string
69+ constraints []string
70+ reschedulePolicies []string
71+ env []string
6972 )
7073
7174 // only for tests
@@ -83,12 +86,19 @@ func BuildContainerConfig(c dockerclient.ContainerConfig) *ContainerConfig {
8386 json .Unmarshal ([]byte (labels ), & constraints )
8487 }
8588
86- // parse affinities/constraints from env (ex. docker run -e affinity:container==redis -e affinity:image==nginx -e constraint:region==us-east -e constraint:storage==ssd)
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 )
92+ }
93+
94+ // 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)
8795 for _ , e := range c .Env {
8896 if ok , key , value := parseEnv (e ); ok && key == "affinity" {
8997 affinities = append (affinities , value )
9098 } else if ok && key == "constraint" {
9199 constraints = append (constraints , value )
100+ } else if ok && key == "reschedule" {
101+ reschedulePolicies = append (reschedulePolicies , value )
92102 } else {
93103 env = append (env , e )
94104 }
@@ -111,6 +121,13 @@ func BuildContainerConfig(c dockerclient.ContainerConfig) *ContainerConfig {
111121 }
112122 }
113123
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+ }
129+ }
130+
114131 consolidateResourceFields (& c )
115132
116133 return & ContainerConfig {c }
@@ -186,3 +203,33 @@ func (c *ContainerConfig) HaveNodeConstraint() bool {
186203 }
187204 return false
188205}
206+
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+ }
233+ }
234+ return nil
235+ }
0 commit comments