mirror of https://github.com/docker/docs.git
fix soft affinities/constraints
Signed-off-by: Victor Vieux <vieux@docker.com>
This commit is contained in:
parent
40f26856a5
commit
ea5b2290ed
|
@ -19,14 +19,17 @@ func (f *AffinityFilter) Name() string {
|
|||
}
|
||||
|
||||
// Filter is exported
|
||||
func (f *AffinityFilter) Filter(config *cluster.ContainerConfig, nodes []*node.Node) ([]*node.Node, error) {
|
||||
func (f *AffinityFilter) Filter(config *cluster.ContainerConfig, nodes []*node.Node, soft bool) ([]*node.Node, error) {
|
||||
affinities, err := parseExprs(config.Affinities())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for _, affinity := range affinities {
|
||||
log.Debugf("matching affinity: %s%s%s", affinity.key, OPERATORS[affinity.operator], affinity.value)
|
||||
if !soft && affinity.isSoft {
|
||||
continue
|
||||
}
|
||||
log.Debugf("matching affinity: %s%s%s (soft=%t)", affinity.key, OPERATORS[affinity.operator], affinity.value, affinity.isSoft)
|
||||
|
||||
candidates := []*node.Node{}
|
||||
for _, node := range nodes {
|
||||
|
@ -65,12 +68,10 @@ func (f *AffinityFilter) Filter(config *cluster.ContainerConfig, nodes []*node.N
|
|||
}
|
||||
}
|
||||
if len(candidates) == 0 {
|
||||
if affinity.isSoft {
|
||||
continue
|
||||
}
|
||||
return nil, fmt.Errorf("unable to find a node that satisfies %s%s%s", affinity.key, OPERATORS[affinity.operator], affinity.value)
|
||||
}
|
||||
nodes = candidates
|
||||
}
|
||||
|
||||
return nodes, nil
|
||||
}
|
||||
|
|
|
@ -62,137 +62,140 @@ func TestAffinityFilter(t *testing.T) {
|
|||
)
|
||||
|
||||
// Without constraints we should get the unfiltered list of nodes back.
|
||||
result, err = f.Filter(&cluster.ContainerConfig{}, nodes)
|
||||
result, err = f.Filter(&cluster.ContainerConfig{}, nodes, true)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, result, nodes)
|
||||
|
||||
// Set a constraint that cannot be fulfilled and expect an error back.
|
||||
result, err = f.Filter(cluster.BuildContainerConfig(dockerclient.ContainerConfig{Env: []string{"affinity:container==does_not_exsits"}}), nodes)
|
||||
result, err = f.Filter(cluster.BuildContainerConfig(dockerclient.ContainerConfig{Env: []string{"affinity:container==does_not_exsits"}}), nodes, true)
|
||||
assert.Error(t, err)
|
||||
|
||||
// Set a constraint that can only be filled by a single node.
|
||||
result, err = f.Filter(cluster.BuildContainerConfig(dockerclient.ContainerConfig{Env: []string{"affinity:container==container-n0*"}}), nodes)
|
||||
result, err = f.Filter(cluster.BuildContainerConfig(dockerclient.ContainerConfig{Env: []string{"affinity:container==container-n0*"}}), nodes, true)
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, result, 1)
|
||||
assert.Equal(t, result[0], nodes[0])
|
||||
|
||||
// This constraint can only be fulfilled by a subset of nodes.
|
||||
result, err = f.Filter(cluster.BuildContainerConfig(dockerclient.ContainerConfig{Env: []string{"affinity:container==container-*"}}), nodes)
|
||||
result, err = f.Filter(cluster.BuildContainerConfig(dockerclient.ContainerConfig{Env: []string{"affinity:container==container-*"}}), nodes, true)
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, result, 2)
|
||||
assert.NotContains(t, result, nodes[2])
|
||||
|
||||
// Validate by id.
|
||||
result, err = f.Filter(cluster.BuildContainerConfig(dockerclient.ContainerConfig{Env: []string{"affinity:container==container-n0-0-id"}}), nodes)
|
||||
result, err = f.Filter(cluster.BuildContainerConfig(dockerclient.ContainerConfig{Env: []string{"affinity:container==container-n0-0-id"}}), nodes, true)
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, result, 1)
|
||||
assert.Equal(t, result[0], nodes[0])
|
||||
|
||||
// Validate by id.
|
||||
result, err = f.Filter(cluster.BuildContainerConfig(dockerclient.ContainerConfig{Env: []string{"affinity:container!=container-n0-0-id"}}), nodes)
|
||||
result, err = f.Filter(cluster.BuildContainerConfig(dockerclient.ContainerConfig{Env: []string{"affinity:container!=container-n0-0-id"}}), nodes, true)
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, result, 2)
|
||||
assert.NotContains(t, result, nodes[0])
|
||||
|
||||
// Validate by id.
|
||||
result, err = f.Filter(cluster.BuildContainerConfig(dockerclient.ContainerConfig{Env: []string{"affinity:container!=container-n0-1-id"}}), nodes)
|
||||
result, err = f.Filter(cluster.BuildContainerConfig(dockerclient.ContainerConfig{Env: []string{"affinity:container!=container-n0-1-id"}}), nodes, true)
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, result, 2)
|
||||
assert.NotContains(t, result, nodes[0])
|
||||
|
||||
// Validate by name.
|
||||
result, err = f.Filter(cluster.BuildContainerConfig(dockerclient.ContainerConfig{Env: []string{"affinity:container==container-n1-0-name"}}), nodes)
|
||||
result, err = f.Filter(cluster.BuildContainerConfig(dockerclient.ContainerConfig{Env: []string{"affinity:container==container-n1-0-name"}}), nodes, true)
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, result, 1)
|
||||
assert.Equal(t, result[0], nodes[1])
|
||||
|
||||
// Validate by name.
|
||||
result, err = f.Filter(cluster.BuildContainerConfig(dockerclient.ContainerConfig{Env: []string{"affinity:container!=container-n1-0-name"}}), nodes)
|
||||
result, err = f.Filter(cluster.BuildContainerConfig(dockerclient.ContainerConfig{Env: []string{"affinity:container!=container-n1-0-name"}}), nodes, true)
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, result, 2)
|
||||
assert.NotContains(t, result, nodes[1])
|
||||
|
||||
// Validate by name.
|
||||
result, err = f.Filter(cluster.BuildContainerConfig(dockerclient.ContainerConfig{Env: []string{"affinity:container!=container-n1-1-name"}}), nodes)
|
||||
result, err = f.Filter(cluster.BuildContainerConfig(dockerclient.ContainerConfig{Env: []string{"affinity:container!=container-n1-1-name"}}), nodes, true)
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, result, 2)
|
||||
assert.NotContains(t, result, nodes[1])
|
||||
|
||||
// Conflicting Constraint
|
||||
result, err = f.Filter(cluster.BuildContainerConfig(dockerclient.ContainerConfig{Env: []string{"affinity:container!=container-n1-1-name", "affinity:container==container-n1-1-name"}}), nodes)
|
||||
result, err = f.Filter(cluster.BuildContainerConfig(dockerclient.ContainerConfig{Env: []string{"affinity:container!=container-n1-1-name", "affinity:container==container-n1-1-name"}}), nodes, true)
|
||||
assert.Error(t, err)
|
||||
assert.Len(t, result, 0)
|
||||
// Validate images by id
|
||||
result, err = f.Filter(cluster.BuildContainerConfig(dockerclient.ContainerConfig{Env: []string{"affinity:image==image-0-id"}}), nodes)
|
||||
result, err = f.Filter(cluster.BuildContainerConfig(dockerclient.ContainerConfig{Env: []string{"affinity:image==image-0-id"}}), nodes, true)
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, result, 1)
|
||||
assert.Equal(t, result[0], nodes[0])
|
||||
|
||||
// Validate images by name
|
||||
result, err = f.Filter(cluster.BuildContainerConfig(dockerclient.ContainerConfig{Env: []string{"affinity:image==image-0:tag3"}}), nodes)
|
||||
result, err = f.Filter(cluster.BuildContainerConfig(dockerclient.ContainerConfig{Env: []string{"affinity:image==image-0:tag3"}}), nodes, true)
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, result, 1)
|
||||
assert.Equal(t, result[0], nodes[1])
|
||||
|
||||
// Validate images by name
|
||||
result, err = f.Filter(cluster.BuildContainerConfig(dockerclient.ContainerConfig{Env: []string{"affinity:image!=image-0:tag3"}}), nodes)
|
||||
result, err = f.Filter(cluster.BuildContainerConfig(dockerclient.ContainerConfig{Env: []string{"affinity:image!=image-0:tag3"}}), nodes, true)
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, result, 2)
|
||||
|
||||
// Validate images by name
|
||||
result, err = f.Filter(cluster.BuildContainerConfig(dockerclient.ContainerConfig{Env: []string{"affinity:image==image-1"}}), nodes)
|
||||
result, err = f.Filter(cluster.BuildContainerConfig(dockerclient.ContainerConfig{Env: []string{"affinity:image==image-1"}}), nodes, true)
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, result, 1)
|
||||
assert.Equal(t, result[0], nodes[1])
|
||||
|
||||
// Validate images by name
|
||||
result, err = f.Filter(cluster.BuildContainerConfig(dockerclient.ContainerConfig{Env: []string{"affinity:image!=image-1"}}), nodes)
|
||||
result, err = f.Filter(cluster.BuildContainerConfig(dockerclient.ContainerConfig{Env: []string{"affinity:image!=image-1"}}), nodes, true)
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, result, 2)
|
||||
|
||||
// Ensure that constraints can be chained.
|
||||
result, err = f.Filter(cluster.BuildContainerConfig(dockerclient.ContainerConfig{Env: []string{"affinity:container!=container-n0-1-id", "affinity:container!=container-n1-1-id"}}), nodes)
|
||||
result, err = f.Filter(cluster.BuildContainerConfig(dockerclient.ContainerConfig{Env: []string{"affinity:container!=container-n0-1-id", "affinity:container!=container-n1-1-id"}}), nodes, true)
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, result, 1)
|
||||
assert.Equal(t, result[0], nodes[2])
|
||||
|
||||
// Ensure that constraints can be chained.
|
||||
result, err = f.Filter(cluster.BuildContainerConfig(dockerclient.ContainerConfig{Env: []string{"affinity:container==container-n0-1-id", "affinity:container==container-n1-1-id"}}), nodes)
|
||||
result, err = f.Filter(cluster.BuildContainerConfig(dockerclient.ContainerConfig{Env: []string{"affinity:container==container-n0-1-id", "affinity:container==container-n1-1-id"}}), nodes, true)
|
||||
assert.Error(t, err)
|
||||
|
||||
//Tests for Soft affinity
|
||||
result, err = f.Filter(cluster.BuildContainerConfig(dockerclient.ContainerConfig{Env: []string{"affinity:image==~image-0:tag3"}}), nodes)
|
||||
result, err = f.Filter(cluster.BuildContainerConfig(dockerclient.ContainerConfig{Env: []string{"affinity:image==~image-0:tag3"}}), nodes, true)
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, result, 1)
|
||||
|
||||
result, err = f.Filter(cluster.BuildContainerConfig(dockerclient.ContainerConfig{Env: []string{"affinity:image==~ima~ge-0:tag3"}}), nodes)
|
||||
result, err = f.Filter(cluster.BuildContainerConfig(dockerclient.ContainerConfig{Env: []string{"affinity:image==~ima~ge-0:tag3"}}), nodes, true)
|
||||
assert.Error(t, err)
|
||||
assert.Len(t, result, 0)
|
||||
|
||||
result, err = f.Filter(cluster.BuildContainerConfig(dockerclient.ContainerConfig{Env: []string{"affinity:image==~image-1:tag3"}}), nodes)
|
||||
result, err = f.Filter(cluster.BuildContainerConfig(dockerclient.ContainerConfig{Env: []string{"affinity:image==~image-1:tag3"}}), nodes, true)
|
||||
assert.Error(t, err)
|
||||
assert.Len(t, result, 0)
|
||||
result, err = f.Filter(cluster.BuildContainerConfig(dockerclient.ContainerConfig{Env: []string{"affinity:image==~image-1:tag3"}}), nodes, false)
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, result, 3)
|
||||
|
||||
result, err = f.Filter(cluster.BuildContainerConfig(dockerclient.ContainerConfig{Env: []string{"affinity:image==~image-*"}}), nodes)
|
||||
result, err = f.Filter(cluster.BuildContainerConfig(dockerclient.ContainerConfig{Env: []string{"affinity:image==~image-*"}}), nodes, true)
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, result, 2)
|
||||
|
||||
result, err = f.Filter(cluster.BuildContainerConfig(dockerclient.ContainerConfig{Env: []string{"affinity:image!=~image-*"}}), nodes)
|
||||
result, err = f.Filter(cluster.BuildContainerConfig(dockerclient.ContainerConfig{Env: []string{"affinity:image!=~image-*"}}), nodes, true)
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, result, 1)
|
||||
assert.Equal(t, result[0], nodes[2])
|
||||
|
||||
result, err = f.Filter(cluster.BuildContainerConfig(dockerclient.ContainerConfig{Env: []string{"affinity:image==~/image-\\d*/"}}), nodes)
|
||||
result, err = f.Filter(cluster.BuildContainerConfig(dockerclient.ContainerConfig{Env: []string{"affinity:image==~/image-\\d*/"}}), nodes, true)
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, result, 2)
|
||||
|
||||
// Not support = any more
|
||||
result, err = f.Filter(cluster.BuildContainerConfig(dockerclient.ContainerConfig{Env: []string{"affinity:image=image-0:tag3"}}), nodes)
|
||||
result, err = f.Filter(cluster.BuildContainerConfig(dockerclient.ContainerConfig{Env: []string{"affinity:image=image-0:tag3"}}), nodes, true)
|
||||
assert.Error(t, err)
|
||||
assert.Len(t, result, 0)
|
||||
|
||||
// Not support =! any more
|
||||
result, err = f.Filter(cluster.BuildContainerConfig(dockerclient.ContainerConfig{Env: []string{"affinity:image=!image-0:tag3"}}), nodes)
|
||||
result, err = f.Filter(cluster.BuildContainerConfig(dockerclient.ContainerConfig{Env: []string{"affinity:image=!image-0:tag3"}}), nodes, true)
|
||||
assert.Error(t, err)
|
||||
assert.Len(t, result, 0)
|
||||
|
||||
|
@ -237,22 +240,22 @@ func TestAffinityFilterLabels(t *testing.T) {
|
|||
err error
|
||||
)
|
||||
|
||||
result, err = f.Filter(cluster.BuildContainerConfig(dockerclient.ContainerConfig{Env: []string{"affinity:image==image-1"}}), nodes)
|
||||
result, err = f.Filter(cluster.BuildContainerConfig(dockerclient.ContainerConfig{Env: []string{"affinity:image==image-1"}}), nodes, true)
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, result, 1)
|
||||
assert.Equal(t, result[0], nodes[1])
|
||||
|
||||
result, err = f.Filter(cluster.BuildContainerConfig(dockerclient.ContainerConfig{Env: []string{"affinity:image!=image-1"}}), nodes)
|
||||
result, err = f.Filter(cluster.BuildContainerConfig(dockerclient.ContainerConfig{Env: []string{"affinity:image!=image-1"}}), nodes, true)
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, result, 1)
|
||||
assert.Equal(t, result[0], nodes[0])
|
||||
|
||||
result, err = f.Filter(cluster.BuildContainerConfig(dockerclient.ContainerConfig{Labels: map[string]string{"com.docker.swarm.affinities": "[\"image==image-1\"]"}}), nodes)
|
||||
result, err = f.Filter(cluster.BuildContainerConfig(dockerclient.ContainerConfig{Labels: map[string]string{"com.docker.swarm.affinities": "[\"image==image-1\"]"}}), nodes, true)
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, result, 1)
|
||||
assert.Equal(t, result[0], nodes[1])
|
||||
|
||||
result, err = f.Filter(cluster.BuildContainerConfig(dockerclient.ContainerConfig{Labels: map[string]string{"com.docker.swarm.affinities": "[\"image!=image-1\"]"}}), nodes)
|
||||
result, err = f.Filter(cluster.BuildContainerConfig(dockerclient.ContainerConfig{Labels: map[string]string{"com.docker.swarm.affinities": "[\"image!=image-1\"]"}}), nodes, true)
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, result, 1)
|
||||
assert.Equal(t, result[0], nodes[0])
|
||||
|
|
|
@ -18,14 +18,17 @@ func (f *ConstraintFilter) Name() string {
|
|||
}
|
||||
|
||||
// Filter is exported
|
||||
func (f *ConstraintFilter) Filter(config *cluster.ContainerConfig, nodes []*node.Node) ([]*node.Node, error) {
|
||||
func (f *ConstraintFilter) Filter(config *cluster.ContainerConfig, nodes []*node.Node, soft bool) ([]*node.Node, error) {
|
||||
constraints, err := parseExprs(config.Constraints())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for _, constraint := range constraints {
|
||||
log.Debugf("matching constraint: %s %s %s", constraint.key, OPERATORS[constraint.operator], constraint.value)
|
||||
if !soft && constraint.isSoft {
|
||||
continue
|
||||
}
|
||||
log.Debugf("matching constraint: %s%s%s (soft=%t)", constraint.key, OPERATORS[constraint.operator], constraint.value, constraint.isSoft)
|
||||
|
||||
candidates := []*node.Node{}
|
||||
for _, node := range nodes {
|
||||
|
@ -42,9 +45,6 @@ func (f *ConstraintFilter) Filter(config *cluster.ContainerConfig, nodes []*node
|
|||
}
|
||||
}
|
||||
if len(candidates) == 0 {
|
||||
if constraint.isSoft {
|
||||
continue
|
||||
}
|
||||
return nil, fmt.Errorf("unable to find a node that satisfies %s%s%s", constraint.key, OPERATORS[constraint.operator], constraint.value)
|
||||
}
|
||||
nodes = candidates
|
||||
|
|
|
@ -61,54 +61,54 @@ func TestConstrainteFilter(t *testing.T) {
|
|||
)
|
||||
|
||||
// Without constraints we should get the unfiltered list of nodes back.
|
||||
result, err = f.Filter(&cluster.ContainerConfig{}, nodes)
|
||||
result, err = f.Filter(&cluster.ContainerConfig{}, nodes, true)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, result, nodes)
|
||||
|
||||
// Set a constraint that cannot be fulfilled and expect an error back.
|
||||
result, err = f.Filter(cluster.BuildContainerConfig(dockerclient.ContainerConfig{Env: []string{"constraint:does_not_exist==true"}}), nodes)
|
||||
result, err = f.Filter(cluster.BuildContainerConfig(dockerclient.ContainerConfig{Env: []string{"constraint:does_not_exist==true"}}), nodes, true)
|
||||
assert.Error(t, err)
|
||||
|
||||
// Set a contraint that can only be filled by a single node.
|
||||
result, err = f.Filter(cluster.BuildContainerConfig(dockerclient.ContainerConfig{Env: []string{"constraint:name==node1"}}), nodes)
|
||||
result, err = f.Filter(cluster.BuildContainerConfig(dockerclient.ContainerConfig{Env: []string{"constraint:name==node1"}}), nodes, true)
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, result, 1)
|
||||
assert.Equal(t, result[0], nodes[1])
|
||||
|
||||
// This constraint can only be fulfilled by a subset of nodes.
|
||||
result, err = f.Filter(cluster.BuildContainerConfig(dockerclient.ContainerConfig{Env: []string{"constraint:group==1"}}), nodes)
|
||||
result, err = f.Filter(cluster.BuildContainerConfig(dockerclient.ContainerConfig{Env: []string{"constraint:group==1"}}), nodes, true)
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, result, 2)
|
||||
assert.NotContains(t, result, nodes[2])
|
||||
|
||||
// Validate node pinning by id.
|
||||
result, err = f.Filter(cluster.BuildContainerConfig(dockerclient.ContainerConfig{Env: []string{"constraint:node==node-2-id"}}), nodes)
|
||||
result, err = f.Filter(cluster.BuildContainerConfig(dockerclient.ContainerConfig{Env: []string{"constraint:node==node-2-id"}}), nodes, true)
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, result, 1)
|
||||
assert.Equal(t, result[0], nodes[2])
|
||||
|
||||
// Validate node pinning by name.
|
||||
result, err = f.Filter(cluster.BuildContainerConfig(dockerclient.ContainerConfig{Env: []string{"constraint:node==node-1-name"}}), nodes)
|
||||
result, err = f.Filter(cluster.BuildContainerConfig(dockerclient.ContainerConfig{Env: []string{"constraint:node==node-1-name"}}), nodes, true)
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, result, 1)
|
||||
assert.Equal(t, result[0], nodes[1])
|
||||
|
||||
// Make sure constraints are evaluated as logical ANDs.
|
||||
result, err = f.Filter(cluster.BuildContainerConfig(dockerclient.ContainerConfig{Env: []string{"constraint:name==node0", "constraint:group==1"}}), nodes)
|
||||
result, err = f.Filter(cluster.BuildContainerConfig(dockerclient.ContainerConfig{Env: []string{"constraint:name==node0", "constraint:group==1"}}), nodes, true)
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, result, 1)
|
||||
assert.Equal(t, result[0], nodes[0])
|
||||
|
||||
// Check matching
|
||||
result, err = f.Filter(cluster.BuildContainerConfig(dockerclient.ContainerConfig{Env: []string{"constraint:region==us"}}), nodes)
|
||||
result, err = f.Filter(cluster.BuildContainerConfig(dockerclient.ContainerConfig{Env: []string{"constraint:region==us"}}), nodes, true)
|
||||
assert.Error(t, err)
|
||||
assert.Len(t, result, 0)
|
||||
|
||||
result, err = f.Filter(cluster.BuildContainerConfig(dockerclient.ContainerConfig{Env: []string{"constraint:region==us*"}}), nodes)
|
||||
result, err = f.Filter(cluster.BuildContainerConfig(dockerclient.ContainerConfig{Env: []string{"constraint:region==us*"}}), nodes, true)
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, result, 2)
|
||||
|
||||
result, err = f.Filter(cluster.BuildContainerConfig(dockerclient.ContainerConfig{Env: []string{"constraint:region==*us*"}}), nodes)
|
||||
result, err = f.Filter(cluster.BuildContainerConfig(dockerclient.ContainerConfig{Env: []string{"constraint:region==*us*"}}), nodes, true)
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, result, 2)
|
||||
}
|
||||
|
@ -122,22 +122,22 @@ func TestConstraintNotExpr(t *testing.T) {
|
|||
)
|
||||
|
||||
// Check not (!) expression
|
||||
result, err = f.Filter(cluster.BuildContainerConfig(dockerclient.ContainerConfig{Env: []string{"constraint:name!=node0"}}), nodes)
|
||||
result, err = f.Filter(cluster.BuildContainerConfig(dockerclient.ContainerConfig{Env: []string{"constraint:name!=node0"}}), nodes, true)
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, result, 3)
|
||||
|
||||
// Check not does_not_exist. All should be found
|
||||
result, err = f.Filter(cluster.BuildContainerConfig(dockerclient.ContainerConfig{Env: []string{"constraint:name!=does_not_exist"}}), nodes)
|
||||
result, err = f.Filter(cluster.BuildContainerConfig(dockerclient.ContainerConfig{Env: []string{"constraint:name!=does_not_exist"}}), nodes, true)
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, result, 4)
|
||||
|
||||
// Check name must not start with n
|
||||
result, err = f.Filter(cluster.BuildContainerConfig(dockerclient.ContainerConfig{Env: []string{"constraint:name!=n*"}}), nodes)
|
||||
result, err = f.Filter(cluster.BuildContainerConfig(dockerclient.ContainerConfig{Env: []string{"constraint:name!=n*"}}), nodes, true)
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, result, 1)
|
||||
|
||||
// Check not with globber pattern
|
||||
result, err = f.Filter(cluster.BuildContainerConfig(dockerclient.ContainerConfig{Env: []string{"constraint:region!=us*"}}), nodes)
|
||||
result, err = f.Filter(cluster.BuildContainerConfig(dockerclient.ContainerConfig{Env: []string{"constraint:region!=us*"}}), nodes, true)
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, result, 2)
|
||||
}
|
||||
|
@ -151,22 +151,22 @@ func TestConstraintRegExp(t *testing.T) {
|
|||
)
|
||||
|
||||
// Check with regular expression /node\d/ matches node{0..2}
|
||||
result, err = f.Filter(cluster.BuildContainerConfig(dockerclient.ContainerConfig{Env: []string{`constraint:name==/node\d/`}}), nodes)
|
||||
result, err = f.Filter(cluster.BuildContainerConfig(dockerclient.ContainerConfig{Env: []string{`constraint:name==/node\d/`}}), nodes, true)
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, result, 3)
|
||||
|
||||
// Check with regular expression /node\d/ matches node{0..2}
|
||||
result, err = f.Filter(cluster.BuildContainerConfig(dockerclient.ContainerConfig{Env: []string{`constraint:name==/node[12]/`}}), nodes)
|
||||
result, err = f.Filter(cluster.BuildContainerConfig(dockerclient.ContainerConfig{Env: []string{`constraint:name==/node[12]/`}}), nodes, true)
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, result, 2)
|
||||
|
||||
// Check with regular expression ! and regexp /node[12]/ matches node[0] and node[3]
|
||||
result, err = f.Filter(cluster.BuildContainerConfig(dockerclient.ContainerConfig{Env: []string{`constraint:name!=/node[12]/`}}), nodes)
|
||||
result, err = f.Filter(cluster.BuildContainerConfig(dockerclient.ContainerConfig{Env: []string{`constraint:name!=/node[12]/`}}), nodes, true)
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, result, 2)
|
||||
|
||||
// Validate node pinning by ! and regexp.
|
||||
result, err = f.Filter(cluster.BuildContainerConfig(dockerclient.ContainerConfig{Env: []string{"constraint:node!=/node-[01]-id/"}}), nodes)
|
||||
result, err = f.Filter(cluster.BuildContainerConfig(dockerclient.ContainerConfig{Env: []string{"constraint:node!=/node-[01]-id/"}}), nodes, true)
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, result, 2)
|
||||
}
|
||||
|
@ -187,19 +187,19 @@ func TestFilterRegExpCaseInsensitive(t *testing.T) {
|
|||
}
|
||||
|
||||
// Case-sensitive, so not match
|
||||
result, err = f.Filter(cluster.BuildContainerConfig(dockerclient.ContainerConfig{Env: []string{`constraint:name==/abcdef/`}}), nodes)
|
||||
result, err = f.Filter(cluster.BuildContainerConfig(dockerclient.ContainerConfig{Env: []string{`constraint:name==/abcdef/`}}), nodes, true)
|
||||
assert.Error(t, err)
|
||||
assert.Len(t, result, 0)
|
||||
|
||||
// Match with case-insensitive
|
||||
result, err = f.Filter(cluster.BuildContainerConfig(dockerclient.ContainerConfig{Env: []string{`constraint:name==/(?i)abcdef/`}}), nodes)
|
||||
result, err = f.Filter(cluster.BuildContainerConfig(dockerclient.ContainerConfig{Env: []string{`constraint:name==/(?i)abcdef/`}}), nodes, true)
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, result, 1)
|
||||
assert.Equal(t, result[0], nodes[3])
|
||||
assert.Equal(t, result[0].Labels["name"], "aBcDeF")
|
||||
|
||||
// Test ! filter combined with case insensitive
|
||||
result, err = f.Filter(cluster.BuildContainerConfig(dockerclient.ContainerConfig{Env: []string{`constraint:name!=/(?i)abc*/`}}), nodes)
|
||||
result, err = f.Filter(cluster.BuildContainerConfig(dockerclient.ContainerConfig{Env: []string{`constraint:name!=/(?i)abc*/`}}), nodes, true)
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, result, 3)
|
||||
}
|
||||
|
@ -213,17 +213,17 @@ func TestFilterEquals(t *testing.T) {
|
|||
)
|
||||
|
||||
// Check == comparison
|
||||
result, err = f.Filter(cluster.BuildContainerConfig(dockerclient.ContainerConfig{Env: []string{"constraint:name==node0"}}), nodes)
|
||||
result, err = f.Filter(cluster.BuildContainerConfig(dockerclient.ContainerConfig{Env: []string{"constraint:name==node0"}}), nodes, true)
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, result, 1)
|
||||
|
||||
// Test == with glob
|
||||
result, err = f.Filter(cluster.BuildContainerConfig(dockerclient.ContainerConfig{Env: []string{"constraint:region==us*"}}), nodes)
|
||||
result, err = f.Filter(cluster.BuildContainerConfig(dockerclient.ContainerConfig{Env: []string{"constraint:region==us*"}}), nodes, true)
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, result, 2)
|
||||
|
||||
// Validate node name with ==
|
||||
result, err = f.Filter(cluster.BuildContainerConfig(dockerclient.ContainerConfig{Env: []string{"constraint:node==node-1-name"}}), nodes)
|
||||
result, err = f.Filter(cluster.BuildContainerConfig(dockerclient.ContainerConfig{Env: []string{"constraint:node==node-1-name"}}), nodes, true)
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, result, 1)
|
||||
assert.Equal(t, result[0], nodes[1])
|
||||
|
@ -237,11 +237,11 @@ func TestUnsupportedOperators(t *testing.T) {
|
|||
err error
|
||||
)
|
||||
|
||||
result, err = f.Filter(cluster.BuildContainerConfig(dockerclient.ContainerConfig{Env: []string{"constraint:name=node0"}}), nodes)
|
||||
result, err = f.Filter(cluster.BuildContainerConfig(dockerclient.ContainerConfig{Env: []string{"constraint:name=node0"}}), nodes, true)
|
||||
assert.Error(t, err)
|
||||
assert.Len(t, result, 0)
|
||||
|
||||
result, err = f.Filter(cluster.BuildContainerConfig(dockerclient.ContainerConfig{Env: []string{"constraint:name=!node0"}}), nodes)
|
||||
result, err = f.Filter(cluster.BuildContainerConfig(dockerclient.ContainerConfig{Env: []string{"constraint:name=!node0"}}), nodes, true)
|
||||
assert.Error(t, err)
|
||||
assert.Len(t, result, 0)
|
||||
}
|
||||
|
@ -254,26 +254,26 @@ func TestFilterSoftConstraint(t *testing.T) {
|
|||
err error
|
||||
)
|
||||
|
||||
result, err = f.Filter(cluster.BuildContainerConfig(dockerclient.ContainerConfig{Env: []string{"constraint:node==~node-1-name"}}), nodes)
|
||||
result, err = f.Filter(cluster.BuildContainerConfig(dockerclient.ContainerConfig{Env: []string{"constraint:node==~node-1-name"}}), nodes, true)
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, result, 1)
|
||||
assert.Equal(t, result[0], nodes[1])
|
||||
|
||||
result, err = f.Filter(cluster.BuildContainerConfig(dockerclient.ContainerConfig{Env: []string{`constraint:name!=~/(?i)abc*/`}}), nodes)
|
||||
result, err = f.Filter(cluster.BuildContainerConfig(dockerclient.ContainerConfig{Env: []string{`constraint:name!=~/(?i)abc*/`}}), nodes, true)
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, result, 4)
|
||||
|
||||
// Check not with globber pattern
|
||||
result, err = f.Filter(cluster.BuildContainerConfig(dockerclient.ContainerConfig{Env: []string{"constraint:region!=~us*"}}), nodes)
|
||||
result, err = f.Filter(cluster.BuildContainerConfig(dockerclient.ContainerConfig{Env: []string{"constraint:region!=~us*"}}), nodes, true)
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, result, 2)
|
||||
|
||||
result, err = f.Filter(cluster.BuildContainerConfig(dockerclient.ContainerConfig{Env: []string{"constraint:region!=~can*"}}), nodes)
|
||||
result, err = f.Filter(cluster.BuildContainerConfig(dockerclient.ContainerConfig{Env: []string{"constraint:region!=~can*"}}), nodes, true)
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, result, 4)
|
||||
|
||||
// Check matching
|
||||
result, err = f.Filter(cluster.BuildContainerConfig(dockerclient.ContainerConfig{Env: []string{"constraint:region==~us~"}}), nodes)
|
||||
result, err = f.Filter(cluster.BuildContainerConfig(dockerclient.ContainerConfig{Env: []string{"constraint:region==~us~"}}), nodes, true)
|
||||
assert.Error(t, err)
|
||||
assert.Len(t, result, 0)
|
||||
}
|
||||
|
|
|
@ -18,7 +18,7 @@ func (f *DependencyFilter) Name() string {
|
|||
}
|
||||
|
||||
// Filter is exported
|
||||
func (f *DependencyFilter) Filter(config *cluster.ContainerConfig, nodes []*node.Node) ([]*node.Node, error) {
|
||||
func (f *DependencyFilter) Filter(config *cluster.ContainerConfig, nodes []*node.Node, _ bool) ([]*node.Node, error) {
|
||||
if len(nodes) == 0 {
|
||||
return nodes, nil
|
||||
}
|
||||
|
|
|
@ -50,7 +50,7 @@ func TestDependencyFilterSimple(t *testing.T) {
|
|||
|
||||
// No dependencies - make sure we don't filter anything out.
|
||||
config = &cluster.ContainerConfig{}
|
||||
result, err = f.Filter(config, nodes)
|
||||
result, err = f.Filter(config, nodes, true)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, result, nodes)
|
||||
|
||||
|
@ -58,7 +58,7 @@ func TestDependencyFilterSimple(t *testing.T) {
|
|||
config = &cluster.ContainerConfig{dockerclient.ContainerConfig{HostConfig: dockerclient.HostConfig{
|
||||
VolumesFrom: []string{"c0"},
|
||||
}}}
|
||||
result, err = f.Filter(config, nodes)
|
||||
result, err = f.Filter(config, nodes, true)
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, result, 1)
|
||||
assert.Equal(t, result[0], nodes[0])
|
||||
|
@ -67,7 +67,7 @@ func TestDependencyFilterSimple(t *testing.T) {
|
|||
config = &cluster.ContainerConfig{dockerclient.ContainerConfig{HostConfig: dockerclient.HostConfig{
|
||||
VolumesFrom: []string{"c0:rw"},
|
||||
}}}
|
||||
result, err = f.Filter(config, nodes)
|
||||
result, err = f.Filter(config, nodes, true)
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, result, 1)
|
||||
assert.Equal(t, result[0], nodes[0])
|
||||
|
@ -76,7 +76,7 @@ func TestDependencyFilterSimple(t *testing.T) {
|
|||
config = &cluster.ContainerConfig{dockerclient.ContainerConfig{HostConfig: dockerclient.HostConfig{
|
||||
VolumesFrom: []string{"c0:ro"},
|
||||
}}}
|
||||
result, err = f.Filter(config, nodes)
|
||||
result, err = f.Filter(config, nodes, true)
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, result, 1)
|
||||
assert.Equal(t, result[0], nodes[0])
|
||||
|
@ -85,7 +85,7 @@ func TestDependencyFilterSimple(t *testing.T) {
|
|||
config = &cluster.ContainerConfig{dockerclient.ContainerConfig{HostConfig: dockerclient.HostConfig{
|
||||
Links: []string{"c1:foobar"},
|
||||
}}}
|
||||
result, err = f.Filter(config, nodes)
|
||||
result, err = f.Filter(config, nodes, true)
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, result, 1)
|
||||
assert.Equal(t, result[0], nodes[1])
|
||||
|
@ -94,7 +94,7 @@ func TestDependencyFilterSimple(t *testing.T) {
|
|||
config = &cluster.ContainerConfig{dockerclient.ContainerConfig{HostConfig: dockerclient.HostConfig{
|
||||
NetworkMode: "container:c2",
|
||||
}}}
|
||||
result, err = f.Filter(config, nodes)
|
||||
result, err = f.Filter(config, nodes, true)
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, result, 1)
|
||||
assert.Equal(t, result[0], nodes[2])
|
||||
|
@ -103,7 +103,7 @@ func TestDependencyFilterSimple(t *testing.T) {
|
|||
config = &cluster.ContainerConfig{dockerclient.ContainerConfig{HostConfig: dockerclient.HostConfig{
|
||||
NetworkMode: "bridge",
|
||||
}}}
|
||||
result, err = f.Filter(config, nodes)
|
||||
result, err = f.Filter(config, nodes, true)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, result, nodes)
|
||||
}
|
||||
|
@ -158,7 +158,7 @@ func TestDependencyFilterMulti(t *testing.T) {
|
|||
config = &cluster.ContainerConfig{dockerclient.ContainerConfig{HostConfig: dockerclient.HostConfig{
|
||||
VolumesFrom: []string{"c0"},
|
||||
}}}
|
||||
result, err = f.Filter(config, nodes)
|
||||
result, err = f.Filter(config, nodes, true)
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, result, 1)
|
||||
assert.Equal(t, result[0], nodes[0])
|
||||
|
@ -167,7 +167,7 @@ func TestDependencyFilterMulti(t *testing.T) {
|
|||
config = &cluster.ContainerConfig{dockerclient.ContainerConfig{HostConfig: dockerclient.HostConfig{
|
||||
VolumesFrom: []string{"c1"},
|
||||
}}}
|
||||
result, err = f.Filter(config, nodes)
|
||||
result, err = f.Filter(config, nodes, true)
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, result, 1)
|
||||
assert.Equal(t, result[0], nodes[0])
|
||||
|
@ -176,7 +176,7 @@ func TestDependencyFilterMulti(t *testing.T) {
|
|||
config = &cluster.ContainerConfig{dockerclient.ContainerConfig{HostConfig: dockerclient.HostConfig{
|
||||
VolumesFrom: []string{"c0", "c1"},
|
||||
}}}
|
||||
result, err = f.Filter(config, nodes)
|
||||
result, err = f.Filter(config, nodes, true)
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, result, 1)
|
||||
assert.Equal(t, result[0], nodes[0])
|
||||
|
@ -185,7 +185,7 @@ func TestDependencyFilterMulti(t *testing.T) {
|
|||
config = &cluster.ContainerConfig{dockerclient.ContainerConfig{HostConfig: dockerclient.HostConfig{
|
||||
VolumesFrom: []string{"c0", "c2"},
|
||||
}}}
|
||||
result, err = f.Filter(config, nodes)
|
||||
result, err = f.Filter(config, nodes, true)
|
||||
assert.Error(t, err)
|
||||
}
|
||||
|
||||
|
@ -243,7 +243,7 @@ func TestDependencyFilterChaining(t *testing.T) {
|
|||
NetworkMode: "container:c1",
|
||||
},
|
||||
}}
|
||||
result, err = f.Filter(config, nodes)
|
||||
result, err = f.Filter(config, nodes, true)
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, result, 1)
|
||||
assert.Equal(t, result[0], nodes[0])
|
||||
|
@ -256,6 +256,6 @@ func TestDependencyFilterChaining(t *testing.T) {
|
|||
NetworkMode: "container:c1",
|
||||
},
|
||||
}}
|
||||
result, err = f.Filter(config, nodes)
|
||||
result, err = f.Filter(config, nodes, true)
|
||||
assert.Error(t, err)
|
||||
}
|
||||
|
|
|
@ -13,7 +13,7 @@ type Filter interface {
|
|||
Name() string
|
||||
|
||||
// Return a subset of nodes that were accepted by the filtering policy.
|
||||
Filter(*cluster.ContainerConfig, []*node.Node) ([]*node.Node, error)
|
||||
Filter(*cluster.ContainerConfig, []*node.Node, bool) ([]*node.Node, error)
|
||||
}
|
||||
|
||||
var (
|
||||
|
@ -55,15 +55,28 @@ func New(names []string) ([]Filter, error) {
|
|||
|
||||
// ApplyFilters applies a set of filters in batch.
|
||||
func ApplyFilters(filters []Filter, config *cluster.ContainerConfig, nodes []*node.Node) ([]*node.Node, error) {
|
||||
var err error
|
||||
candidates, err := applyFilters(filters, config, nodes, true)
|
||||
|
||||
if err != nil {
|
||||
candidates, err = applyFilters(filters, config, nodes, false)
|
||||
}
|
||||
|
||||
return candidates, err
|
||||
}
|
||||
|
||||
func applyFilters(filters []Filter, config *cluster.ContainerConfig, nodes []*node.Node, soft bool) ([]*node.Node, error) {
|
||||
var (
|
||||
err error
|
||||
candidates = nodes
|
||||
)
|
||||
|
||||
for _, filter := range filters {
|
||||
nodes, err = filter.Filter(config, nodes)
|
||||
candidates, err = filter.Filter(config, candidates, soft)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return nodes, nil
|
||||
return candidates, nil
|
||||
}
|
||||
|
||||
// List returns the names of all the available filters
|
||||
|
|
|
@ -22,7 +22,7 @@ func (f *HealthFilter) Name() string {
|
|||
}
|
||||
|
||||
// Filter is exported
|
||||
func (f *HealthFilter) Filter(_ *cluster.ContainerConfig, nodes []*node.Node) ([]*node.Node, error) {
|
||||
func (f *HealthFilter) Filter(_ *cluster.ContainerConfig, nodes []*node.Node, _ bool) ([]*node.Node, error) {
|
||||
result := []*node.Node{}
|
||||
for _, node := range nodes {
|
||||
if node.IsHealthy {
|
||||
|
|
|
@ -66,16 +66,16 @@ func TestHealthyFilter(t *testing.T) {
|
|||
err error
|
||||
)
|
||||
|
||||
result, err = f.Filter(&cluster.ContainerConfig{}, nodesAllHealth)
|
||||
result, err = f.Filter(&cluster.ContainerConfig{}, nodesAllHealth, true)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, result, nodesAllHealth)
|
||||
|
||||
result, err = f.Filter(&cluster.ContainerConfig{}, nodesPartHealth)
|
||||
result, err = f.Filter(&cluster.ContainerConfig{}, nodesPartHealth, true)
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, result, 1)
|
||||
assert.Equal(t, result[0], nodesPartHealth[1])
|
||||
|
||||
result, err = f.Filter(&cluster.ContainerConfig{}, nodesNoHealth)
|
||||
result, err = f.Filter(&cluster.ContainerConfig{}, nodesNoHealth, true)
|
||||
assert.Equal(t, err, ErrNoHealthyNodeAvailable)
|
||||
assert.Nil(t, result)
|
||||
}
|
||||
|
|
|
@ -20,7 +20,7 @@ func (p *PortFilter) Name() string {
|
|||
}
|
||||
|
||||
// Filter is exported
|
||||
func (p *PortFilter) Filter(config *cluster.ContainerConfig, nodes []*node.Node) ([]*node.Node, error) {
|
||||
func (p *PortFilter) Filter(config *cluster.ContainerConfig, nodes []*node.Node, _ bool) ([]*node.Node, error) {
|
||||
if config.HostConfig.NetworkMode == "host" {
|
||||
return p.filterHost(config, nodes)
|
||||
}
|
||||
|
|
|
@ -50,7 +50,7 @@ func TestPortFilterNoConflicts(t *testing.T) {
|
|||
PortBindings: map[string][]dockerclient.PortBinding{},
|
||||
}}}
|
||||
// Make sure we don't filter anything out.
|
||||
result, err = p.Filter(config, nodes)
|
||||
result, err = p.Filter(config, nodes, true)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, result, nodes)
|
||||
|
||||
|
@ -61,7 +61,7 @@ func TestPortFilterNoConflicts(t *testing.T) {
|
|||
|
||||
// Since there are no other containers in the cluster, this shouldn't
|
||||
// filter anything either.
|
||||
result, err = p.Filter(config, nodes)
|
||||
result, err = p.Filter(config, nodes, true)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, result, nodes)
|
||||
|
||||
|
@ -70,7 +70,7 @@ func TestPortFilterNoConflicts(t *testing.T) {
|
|||
assert.NoError(t, nodes[0].AddContainer(container))
|
||||
|
||||
// Since no node is using port 80, there should be no filter
|
||||
result, err = p.Filter(config, nodes)
|
||||
result, err = p.Filter(config, nodes, true)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, result, nodes)
|
||||
}
|
||||
|
@ -109,7 +109,7 @@ func TestPortFilterSimple(t *testing.T) {
|
|||
}}}
|
||||
|
||||
// nodes[0] should be excluded since port 80 is taken away.
|
||||
result, err = p.Filter(config, nodes)
|
||||
result, err = p.Filter(config, nodes, true)
|
||||
assert.NoError(t, err)
|
||||
assert.NotContains(t, result, nodes[0])
|
||||
}
|
||||
|
@ -149,7 +149,7 @@ func TestPortFilterDifferentInterfaces(t *testing.T) {
|
|||
|
||||
// nodes[0] should be excluded since port 80 is taken away for every
|
||||
// interface.
|
||||
result, err = p.Filter(config, nodes)
|
||||
result, err = p.Filter(config, nodes, true)
|
||||
assert.NoError(t, err)
|
||||
assert.NotContains(t, result, nodes[0])
|
||||
|
||||
|
@ -163,7 +163,7 @@ func TestPortFilterDifferentInterfaces(t *testing.T) {
|
|||
}}}
|
||||
// nodes[1] should be excluded since port 4242 is already taken on that
|
||||
// interface.
|
||||
result, err = p.Filter(config, nodes)
|
||||
result, err = p.Filter(config, nodes, true)
|
||||
assert.NoError(t, err)
|
||||
assert.NotContains(t, result, nodes[1])
|
||||
|
||||
|
@ -172,7 +172,7 @@ func TestPortFilterDifferentInterfaces(t *testing.T) {
|
|||
PortBindings: makeBinding("0.0.0.0", "4242"),
|
||||
}}}
|
||||
// nodes[1] should still be excluded since the port is not available on the same interface.
|
||||
result, err = p.Filter(config, nodes)
|
||||
result, err = p.Filter(config, nodes, true)
|
||||
assert.NoError(t, err)
|
||||
assert.NotContains(t, result, nodes[1])
|
||||
|
||||
|
@ -181,7 +181,7 @@ func TestPortFilterDifferentInterfaces(t *testing.T) {
|
|||
PortBindings: makeBinding("", "4242"),
|
||||
}}}
|
||||
// nodes[1] should still be excluded since the port is not available on the same interface.
|
||||
result, err = p.Filter(config, nodes)
|
||||
result, err = p.Filter(config, nodes, true)
|
||||
assert.NoError(t, err)
|
||||
assert.NotContains(t, result, nodes[1])
|
||||
|
||||
|
@ -191,7 +191,7 @@ func TestPortFilterDifferentInterfaces(t *testing.T) {
|
|||
}}}
|
||||
// nodes[1] should be included this time since the port is available on the
|
||||
// other interface.
|
||||
result, err = p.Filter(config, nodes)
|
||||
result, err = p.Filter(config, nodes, true)
|
||||
assert.NoError(t, err)
|
||||
assert.Contains(t, result, nodes[1])
|
||||
}
|
||||
|
@ -262,7 +262,7 @@ func TestPortFilterRandomAssignment(t *testing.T) {
|
|||
}}}
|
||||
|
||||
// Since port "80" has been mapped to "1234", we should be able to request "80".
|
||||
result, err = p.Filter(config, nodes)
|
||||
result, err = p.Filter(config, nodes, true)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, result, nodes)
|
||||
|
||||
|
@ -270,7 +270,7 @@ func TestPortFilterRandomAssignment(t *testing.T) {
|
|||
config = &cluster.ContainerConfig{dockerclient.ContainerConfig{HostConfig: dockerclient.HostConfig{
|
||||
PortBindings: makeBinding("", "1234"),
|
||||
}}}
|
||||
result, err = p.Filter(config, nodes)
|
||||
result, err = p.Filter(config, nodes, true)
|
||||
assert.NoError(t, err)
|
||||
assert.NotContains(t, result, nodes[0])
|
||||
}
|
||||
|
@ -323,7 +323,7 @@ func TestPortFilterForHostMode(t *testing.T) {
|
|||
}}
|
||||
|
||||
// nodes[0] should be excluded since port 80 is taken away
|
||||
result, err = p.Filter(config, nodes)
|
||||
result, err = p.Filter(config, nodes, true)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, 2, len(result))
|
||||
assert.NotContains(t, result, nodes[0])
|
||||
|
|
|
@ -145,6 +145,26 @@ function teardown() {
|
|||
[[ "${output}" == *"not found"* ]]
|
||||
}
|
||||
|
||||
@test "docker run - constraint and soft affinities" {
|
||||
start_docker_with_busybox 1 --label group=A
|
||||
start_docker_with_busybox 1 --label group=B
|
||||
swarm_manage
|
||||
|
||||
# start c0 on a node in group=A
|
||||
docker_swarm run -d --name c0 -e constraint:group==A -e affinity:container==~c0 busybox sleep 100
|
||||
|
||||
# check container running on node-0
|
||||
run docker_swarm ps
|
||||
[[ "${output}" == *"node-0/c0"* ]]
|
||||
|
||||
# start c2 on a node in group==B (soft affinity shouldn't matter here)
|
||||
docker_swarm run -d --name c2 -e constraint:group==B -e affinity:container==~c0 busybox sleep 100
|
||||
|
||||
# check container running on a node in group=B
|
||||
run docker_swarm ps
|
||||
[[ "${output}" == *"node-1/c2"* ]]
|
||||
}
|
||||
|
||||
@test "docker run - with not exist volume driver" {
|
||||
start_docker_with_busybox 2
|
||||
swarm_manage
|
||||
|
|
Loading…
Reference in New Issue