Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

supported numerical comparison in constrains #4729 #4856

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
70 changes: 70 additions & 0 deletions scheduler/feasible.go
Original file line number Diff line number Diff line change
Expand Up @@ -464,6 +464,9 @@ func checkConstraint(ctx Context, operand string, lVal, rVal interface{}) bool {
case "!=", "not":
return !reflect.DeepEqual(lVal, rVal)
case "<", "<=", ">", ">=":
if valIsNumeric(lVal) && valIsNumeric(rVal) {
return checkNumericOrder(operand,lVal,rVal)
}
return checkLexicalOrder(operand, lVal, rVal)
case structs.ConstraintVersion:
return checkVersionMatch(ctx, lVal, rVal)
Expand All @@ -478,6 +481,7 @@ func checkConstraint(ctx Context, operand string, lVal, rVal interface{}) bool {
}
}


// checkAffinity checks if a specific affinity is satisfied
func checkAffinity(ctx Context, operand string, lVal, rVal interface{}) bool {
return checkConstraint(ctx, operand, lVal, rVal)
Expand All @@ -488,6 +492,72 @@ func checkAttributeAffinity(ctx Context, operand string, lVal, rVal *psstructs.A
return checkAttributeConstraint(ctx, operand, lVal, rVal)
}

// valIsNumeric is used to detect if val is number
func valIsNumeric(val interface{}) bool {
re := regexp.MustCompile(`^[0-9]+(\.[0-9]+)?$`)
if str, ok := val.(string); ok {
if re.Match([]byte(str)) {
return true
}
}
return false
}

// checkNumericOrder is used if strings vals can be converted to numeric type
func checkNumericOrder(op string,lVal, rVal interface{}) bool {
// values must be string
lStr, _:= lVal.(string)
rStr, _:= rVal.(string)

// equals on float types are tricky so we check it as strings
if op == "==" {
if lStr == rStr{
return true
}
}
// if at least one of values are float whe must convert both to float
if strings.Contains(lStr,".") || strings.Contains(lStr,".") {
lFloat,_ := strconv.ParseFloat(lStr,64)
rFloat, _ := strconv.ParseFloat(rStr,64)
return checkFloatOrder(op,lFloat,rFloat)
}
lInt,_ := strconv.Atoi(lStr)
rInt, _ := strconv.Atoi(rStr)
return checkIntegerOrder(op,lInt,rInt)
}

// checkIntegerOrder is used when values can be converted to integer type
func checkIntegerOrder(op string,lVal,rVal int) bool {
switch op {
case "<":
return lVal < rVal
case "<=":
return lVal<= rVal
case ">":
return lVal > rVal
case ">=":
return lVal >= rVal
default:
return false
}
}

// checkFloatOrder is used when values can be converted to float type
func checkFloatOrder(op string,lVal,rVal float64) bool {
switch op {
case "<":
return lVal < rVal
case "<=":
return lVal<= rVal
case ">":
return lVal > rVal
case ">=":
return lVal >= rVal
default:
return false
}
}

// checkLexicalOrder is used to check for lexical ordering
func checkLexicalOrder(op string, lVal, rVal interface{}) bool {
// Ensure the values are strings
Expand Down
35 changes: 35 additions & 0 deletions scheduler/feasible_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -372,6 +372,11 @@ func TestCheckConstraint(t *testing.T) {
lVal: "foo", rVal: "bar",
result: false,
},
{
op: ">",
lVal: "8", rVal: "10",
result: false,
},
{
op: structs.ConstraintSetContains,
lVal: "foo,bar,baz", rVal: "foo, bar ",
Expand All @@ -392,6 +397,36 @@ func TestCheckConstraint(t *testing.T) {
}
}

func TestCheckNumericOrder(t *testing.T){
type tcase struct {
op string
lVal, rVal interface{}
result bool
}
cases := []tcase{
{
op: "<",
lVal: "8.21", rVal: "8.14",
result: false,
},
{
op: "==",
lVal: "8.14323", rVal: "8.14323",
result: true,
},
{
op: "<",
lVal: "8", rVal: "12",
result: true,
},
}
for _, tc := range cases {
if res := checkNumericOrder(tc.op, tc.lVal, tc.rVal); res != tc.result {
t.Fatalf("TC: %#v, Result: %v", tc, res)
}
}
}

func TestCheckLexicalOrder(t *testing.T) {
type tcase struct {
op string
Expand Down