From 0a2e8742451cef5343b1edd2cb367c93fcda50bd Mon Sep 17 00:00:00 2001 From: Armon Dadgar Date: Sun, 11 Oct 2015 15:35:13 -0400 Subject: [PATCH] scheduler: adding regexp constraints --- scheduler/feasible.go | 31 +++++++++++++++++++++++++++--- scheduler/feasible_test.go | 39 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 67 insertions(+), 3 deletions(-) diff --git a/scheduler/feasible.go b/scheduler/feasible.go index b015bd24b..5ecfbedab 100644 --- a/scheduler/feasible.go +++ b/scheduler/feasible.go @@ -3,6 +3,7 @@ package scheduler import ( "fmt" "reflect" + "regexp" "strings" "github.com/hashicorp/go-version" @@ -251,11 +252,10 @@ func checkConstraint(operand string, lVal, rVal interface{}) bool { case "<", "<=", ">", ">=": // TODO: Implement return false - case "contains": - // TODO: Implement - return false case "version": return checkVersionConstraint(lVal, rVal) + case "regexp": + return checkRegexpConstraint(lVal, rVal) default: return false } @@ -296,3 +296,28 @@ func checkVersionConstraint(lVal, rVal interface{}) bool { // Check the constraints against the version return constraints.Check(vers) } + +// checkRegexpConstraint is used to compare a value on the +// left hand side with a regexp on the right hand side +func checkRegexpConstraint(lVal, rVal interface{}) bool { + // Ensure left-hand is string + lStr, ok := lVal.(string) + if !ok { + return false + } + + // Regexp must be a string + regexpStr, ok := rVal.(string) + if !ok { + return false + } + + // Parse the regexp + re, err := regexp.Compile(regexpStr) + if err != nil { + return false + } + + // Look for a match + return re.MatchString(lStr) +} diff --git a/scheduler/feasible_test.go b/scheduler/feasible_test.go index 071df55dd..8ee3c6dc5 100644 --- a/scheduler/feasible_test.go +++ b/scheduler/feasible_test.go @@ -249,6 +249,11 @@ func TestCheckConstraint(t *testing.T) { lVal: "1.2.3", rVal: "~> 1.0", result: true, }, + { + op: "regexp", + lVal: "foobarbaz", rVal: "[\\w]+", + result: true, + }, } for _, tc := range cases { @@ -292,6 +297,40 @@ func TestCheckVersionConstraint(t *testing.T) { } } +func TestCheckRegexpConstraint(t *testing.T) { + type tcase struct { + lVal, rVal interface{} + result bool + } + cases := []tcase{ + { + lVal: "foobar", rVal: "bar", + result: true, + }, + { + lVal: "foobar", rVal: "^foo", + result: true, + }, + { + lVal: "foobar", rVal: "^bar", + result: false, + }, + { + lVal: "zipzap", rVal: "foo", + result: false, + }, + { + lVal: 1, rVal: "foo", + result: false, + }, + } + for _, tc := range cases { + if res := checkRegexpConstraint(tc.lVal, tc.rVal); res != tc.result { + t.Fatalf("TC: %#v, Result: %v", tc, res) + } + } +} + func collectFeasible(iter FeasibleIterator) (out []*structs.Node) { for { next := iter.Next()