mirror of
https://github.com/kemko/nomad.git
synced 2026-01-04 09:25:46 +03:00
Add set contains
This commit is contained in:
@@ -407,6 +407,7 @@ func parseConstraints(result *[]*structs.Constraint, list *ast.ObjectList) error
|
||||
"version",
|
||||
"regexp",
|
||||
"distinct_hosts",
|
||||
"set_contains",
|
||||
}
|
||||
if err := checkHCLKeys(o.Val, valid); err != nil {
|
||||
return err
|
||||
@@ -435,6 +436,13 @@ func parseConstraints(result *[]*structs.Constraint, list *ast.ObjectList) error
|
||||
m["RTarget"] = constraint
|
||||
}
|
||||
|
||||
// If "set_contains" is provided, set the operand
|
||||
// to "set_contains" and the value to the "RTarget"
|
||||
if constraint, ok := m[structs.ConstraintSetContains]; ok {
|
||||
m["Operand"] = structs.ConstraintSetContains
|
||||
m["RTarget"] = constraint
|
||||
}
|
||||
|
||||
if value, ok := m[structs.ConstraintDistinctHosts]; ok {
|
||||
enabled, err := parseBool(value)
|
||||
if err != nil {
|
||||
|
||||
@@ -282,6 +282,25 @@ func TestParse(t *testing.T) {
|
||||
false,
|
||||
},
|
||||
|
||||
{
|
||||
"set-contains-constraint.hcl",
|
||||
&structs.Job{
|
||||
ID: "foo",
|
||||
Name: "foo",
|
||||
Priority: 50,
|
||||
Region: "global",
|
||||
Type: "service",
|
||||
Constraints: []*structs.Constraint{
|
||||
&structs.Constraint{
|
||||
LTarget: "$meta.data",
|
||||
RTarget: "foo,bar,baz",
|
||||
Operand: structs.ConstraintSetContains,
|
||||
},
|
||||
},
|
||||
},
|
||||
false,
|
||||
},
|
||||
|
||||
{
|
||||
"distinctHosts-constraint.hcl",
|
||||
&structs.Job{
|
||||
|
||||
6
jobspec/test-fixtures/set-contains-constraint.hcl
Normal file
6
jobspec/test-fixtures/set-contains-constraint.hcl
Normal file
@@ -0,0 +1,6 @@
|
||||
job "foo" {
|
||||
constraint {
|
||||
attribute = "$meta.data"
|
||||
set_contains = "foo,bar,baz"
|
||||
}
|
||||
}
|
||||
@@ -2729,6 +2729,7 @@ const (
|
||||
ConstraintDistinctHosts = "distinct_hosts"
|
||||
ConstraintRegex = "regexp"
|
||||
ConstraintVersion = "version"
|
||||
ConstraintSetContains = "set_contains"
|
||||
)
|
||||
|
||||
// Constraints are used to restrict placement options.
|
||||
|
||||
@@ -344,6 +344,8 @@ func checkConstraint(ctx Context, operand string, lVal, rVal interface{}) bool {
|
||||
return checkVersionConstraint(ctx, lVal, rVal)
|
||||
case structs.ConstraintRegex:
|
||||
return checkRegexpConstraint(ctx, lVal, rVal)
|
||||
case structs.ConstraintSetContains:
|
||||
return checkSetContainsConstraint(ctx, lVal, rVal)
|
||||
default:
|
||||
return false
|
||||
}
|
||||
@@ -451,6 +453,38 @@ func checkRegexpConstraint(ctx Context, lVal, rVal interface{}) bool {
|
||||
return re.MatchString(lStr)
|
||||
}
|
||||
|
||||
// checkSetContainsConstraint is used to see if the left hand side contains the
|
||||
// string on the right hand side
|
||||
func checkSetContainsConstraint(ctx Context, lVal, rVal interface{}) bool {
|
||||
// Ensure left-hand is string
|
||||
lStr, ok := lVal.(string)
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
|
||||
// Regexp must be a string
|
||||
rStr, ok := rVal.(string)
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
|
||||
input := strings.Split(lStr, ",")
|
||||
lookup := make(map[string]struct{}, len(input))
|
||||
for _, in := range input {
|
||||
cleaned := strings.TrimSpace(in)
|
||||
lookup[cleaned] = struct{}{}
|
||||
}
|
||||
|
||||
for _, r := range strings.Split(rStr, ",") {
|
||||
cleaned := strings.TrimSpace(r)
|
||||
if _, ok := lookup[cleaned]; !ok {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
// FeasibilityWrapper is a FeasibleIterator which wraps both job and task group
|
||||
// FeasibilityCheckers in which feasibility checking can be skipped if the
|
||||
// computed node class has previously been marked as eligible or ineligible.
|
||||
|
||||
@@ -304,6 +304,16 @@ func TestCheckConstraint(t *testing.T) {
|
||||
lVal: "foo", rVal: "bar",
|
||||
result: false,
|
||||
},
|
||||
{
|
||||
op: structs.ConstraintSetContains,
|
||||
lVal: "foo,bar,baz", rVal: "foo, bar ",
|
||||
result: true,
|
||||
},
|
||||
{
|
||||
op: structs.ConstraintSetContains,
|
||||
lVal: "foo,bar,baz", rVal: "foo,bam",
|
||||
result: false,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
|
||||
@@ -419,6 +419,12 @@ The `constraint` object supports the following keys:
|
||||
the attribute. This sets the operator to "regexp" and the `value`
|
||||
to the regular expression.
|
||||
|
||||
* `set_contains` - Specifies a set contains constraint against
|
||||
the attribute. This sets the operator to "set_contains" and the `value`
|
||||
to the what is specified. This will check that the given attribute contains
|
||||
each of the specified elements. The attribute and the list being checked are
|
||||
split using commas.
|
||||
|
||||
* `distinct_hosts` - `distinct_hosts` accepts a boolean value and defaults to
|
||||
`false`. If set, the scheduler will not co-locate any task groups on the same
|
||||
machine. This can be specified as a job constraint which applies the
|
||||
|
||||
@@ -443,6 +443,9 @@ The `Constraint` object supports the following keys:
|
||||
|
||||
* `regexp` - Allows the `RTarget` to be a regular expression to be matched.
|
||||
|
||||
* `set_contains` - Allows the `RTarget` to be a comma separated list of values
|
||||
that should be contained in the LTarget's value.
|
||||
|
||||
* `distinct_host` - If set, the scheduler will not co-locate any task groups on the same
|
||||
machine. This can be specified as a job constraint which applies the
|
||||
constraint to all task groups in the job, or as a task group constraint which
|
||||
|
||||
Reference in New Issue
Block a user