Skip to content

Commit

Permalink
fixup: Add support to constraint attributes
Browse files Browse the repository at this point in the history
  • Loading branch information
endocrimes committed Nov 15, 2018
1 parent 2faab61 commit f450b28
Show file tree
Hide file tree
Showing 2 changed files with 90 additions and 16 deletions.
66 changes: 51 additions & 15 deletions scheduler/feasible.go
Original file line number Diff line number Diff line change
Expand Up @@ -486,7 +486,7 @@ func checkAffinity(ctx Context, operand string, lVal, rVal interface{}) bool {

// checkAttributeAffinity checks if an affinity is satisfied
func checkAttributeAffinity(ctx Context, operand string, lVal, rVal *psstructs.Attribute) bool {
return checkAttributeConstraint(ctx, operand, lVal, rVal)
return checkAttributeConstraint(ctx, operand, lVal, rVal, true, true)
}

// checkLexicalOrder is used to check for lexical ordering
Expand Down Expand Up @@ -932,17 +932,11 @@ func nodeDeviceMatches(ctx Context, d *structs.NodeDeviceResource, req *structs.

for _, c := range req.Constraints {
// Resolve the targets
lVal, ok := resolveDeviceTarget(c.LTarget, d)
if !ok {
return false
}
rVal, ok := resolveDeviceTarget(c.RTarget, d)
if !ok {
return false
}
lVal, lOk := resolveDeviceTarget(c.LTarget, d)
rVal, rOk := resolveDeviceTarget(c.RTarget, d)

// Check if satisfied
if !checkAttributeConstraint(ctx, c.Operand, lVal, rVal) {
if !checkAttributeConstraint(ctx, c.Operand, lVal, rVal, lOk, rOk) {
return false
}
}
Expand Down Expand Up @@ -980,8 +974,9 @@ func resolveDeviceTarget(target string, d *structs.NodeDeviceResource) (*psstruc
}
}

// checkAttributeConstraint checks if a constraint is satisfied
func checkAttributeConstraint(ctx Context, operand string, lVal, rVal *psstructs.Attribute) bool {
// checkAttributeConstraint checks if a constraint is satisfied. nil equality
// comparisons are considered to be false.
func checkAttributeConstraint(ctx Context, operand string, lVal, rVal *psstructs.Attribute, lFound, rFound bool) bool {
// Check for constraints not handled by this checker.
switch operand {
case structs.ConstraintDistinctHosts, structs.ConstraintDistinctProperty:
Expand All @@ -991,15 +986,36 @@ func checkAttributeConstraint(ctx Context, operand string, lVal, rVal *psstructs
}

switch operand {
case "<", "<=", ">", ">=", "=", "==", "is", "!=", "not":
case "!=", "not":
// Neither value was provided, nil != nil == false
if !(lFound || rFound) {
return false
}

// Only 1 value was provided, therefore nil != some == true
if lFound != rFound {
return true
}

// Both values were provided, so actually compare them
v, ok := lVal.Compare(rVal)
if !ok {
return false
}

return v != 0

case "<", "<=", ">", ">=", "=", "==", "is":
if !(lFound && rFound) {
return false
}

v, ok := lVal.Compare(rVal)
if !ok {
return false
}

switch operand {
case "not", "!=":
return v != 0
case "is", "==", "=":
return v == 0
case "<":
Expand All @@ -1015,15 +1031,27 @@ func checkAttributeConstraint(ctx Context, operand string, lVal, rVal *psstructs
}

case structs.ConstraintVersion:
if !(lFound && rFound) {
return false
}

return checkAttributeVersionMatch(ctx, lVal, rVal)
case structs.ConstraintRegex:
if !(lFound && rFound) {
return false
}

ls, ok := lVal.GetString()
rs, ok2 := rVal.GetString()
if !ok || !ok2 {
return false
}
return checkRegexpMatch(ctx, ls, rs)
case structs.ConstraintSetContains, structs.ConstraintSetContainsAll:
if !(lFound && rFound) {
return false
}

ls, ok := lVal.GetString()
rs, ok2 := rVal.GetString()
if !ok || !ok2 {
Expand All @@ -1032,13 +1060,21 @@ func checkAttributeConstraint(ctx Context, operand string, lVal, rVal *psstructs

return checkSetContainsAll(ctx, ls, rs)
case structs.ConstraintSetContainsAny:
if !(lFound && rFound) {
return false
}

ls, ok := lVal.GetString()
rs, ok2 := rVal.GetString()
if !ok || !ok2 {
return false
}

return checkSetContainsAny(ls, rs)
case structs.ConstraintAttributeIsSet:
return lFound
case structs.ConstraintAttributeIsNotSet:
return !lFound
default:
return false
}
Expand Down
40 changes: 39 additions & 1 deletion scheduler/feasible_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2033,6 +2033,12 @@ func TestCheckAttributeConstraint(t *testing.T) {
rVal: psstructs.NewStringAttribute("foo"),
result: true,
},
{
op: "=",
lVal: nil,
rVal: nil,
result: false,
},
{
op: "is",
lVal: psstructs.NewStringAttribute("foo"),
Expand All @@ -2051,6 +2057,18 @@ func TestCheckAttributeConstraint(t *testing.T) {
rVal: psstructs.NewStringAttribute("foo"),
result: false,
},
{
op: "!=",
lVal: nil,
rVal: psstructs.NewStringAttribute("foo"),
result: true,
},
{
op: "!=",
lVal: psstructs.NewStringAttribute("foo"),
rVal: nil,
result: true,
},
{
op: "!=",
lVal: psstructs.NewStringAttribute("foo"),
Expand Down Expand Up @@ -2105,11 +2123,31 @@ func TestCheckAttributeConstraint(t *testing.T) {
rVal: psstructs.NewStringAttribute("foo,bam"),
result: true,
},
{
op: structs.ConstraintAttributeIsSet,
lVal: psstructs.NewStringAttribute("foo,bar,baz"),
result: true,
},
{
op: structs.ConstraintAttributeIsSet,
lVal: nil,
result: false,
},
{
op: structs.ConstraintAttributeIsNotSet,
lVal: psstructs.NewStringAttribute("foo,bar,baz"),
result: false,
},
{
op: structs.ConstraintAttributeIsNotSet,
lVal: nil,
result: true,
},
}

for _, tc := range cases {
_, ctx := testContext(t)
if res := checkAttributeConstraint(ctx, tc.op, tc.lVal, tc.rVal); res != tc.result {
if res := checkAttributeConstraint(ctx, tc.op, tc.lVal, tc.rVal, tc.lVal != nil, tc.rVal != nil); res != tc.result {
t.Fatalf("TC: %#v, Result: %v", tc, res)
}
}
Expand Down

0 comments on commit f450b28

Please sign in to comment.