diff --git a/jobspec/parse.go b/jobspec/parse.go index b7ca31c54..a7ef01799 100644 --- a/jobspec/parse.go +++ b/jobspec/parse.go @@ -7,6 +7,7 @@ import ( "os" "path/filepath" "regexp" + "strconv" "strings" "time" @@ -256,6 +257,20 @@ func parseConstraints(result *[]*structs.Constraint, obj *hclobj.Object) error { m["RTarget"] = constraint } + if value, ok := m["unique"]; ok { + enabled, err := strconv.ParseBool(value.(string)) + if err != nil { + return err + } + + // If it is not enabled, skip the constraint. + if !enabled { + continue + } + + m["Operand"] = "unique" + } + // Build the constraint var c structs.Constraint if err := mapstructure.WeakDecode(m, &c); err != nil { diff --git a/jobspec/parse_test.go b/jobspec/parse_test.go index 60c5f1f09..979ef6020 100644 --- a/jobspec/parse_test.go +++ b/jobspec/parse_test.go @@ -192,6 +192,24 @@ func TestParse(t *testing.T) { false, }, + { + "unique-constraint.hcl", + &structs.Job{ + ID: "foo", + Name: "foo", + Priority: 50, + Region: "global", + Type: "service", + Constraints: []*structs.Constraint{ + &structs.Constraint{ + Hard: true, + Operand: "unique", + }, + }, + }, + false, + }, + { "specify-job.hcl", &structs.Job{ diff --git a/website/source/docs/jobspec/index.html.md b/website/source/docs/jobspec/index.html.md index c1f463d00..540ca1be2 100644 --- a/website/source/docs/jobspec/index.html.md +++ b/website/source/docs/jobspec/index.html.md @@ -237,6 +237,14 @@ The `constraint` object supports the following keys: the attribute. This sets the operator to "regexp" and the `value` to the regular expression. +* `unique` - Unique accepts a boolean value and can be used to mark a Job or + a Task Group as requiring placement on unique nodes. If the `unique` + constraint is placed on a Job, all of it's Task Groups must be placed on + unique nodes. If the `unique` constraint is placed on a Task Group, then + multiple instances of that Task Group must be placed on unique nodes. This + sets the operator to "unique" if `unique` is set to "true". If set to "false", + the constraint is ignored as this is the default behavior. + Below is a table documenting the variables that can be interpreted: