nomad: additional constraint validation

This commit is contained in:
Armon Dadgar 2015-10-11 15:50:16 -04:00
parent 4387d3ddb3
commit 369be8e8f4
2 changed files with 77 additions and 0 deletions

View file

@ -4,11 +4,13 @@ import (
"bytes"
"errors"
"fmt"
"regexp"
"strings"
"time"
"github.com/hashicorp/go-msgpack/codec"
"github.com/hashicorp/go-multierror"
"github.com/hashicorp/go-version"
)
var (
@ -809,6 +811,12 @@ func (j *Job) Validate() error {
if len(j.TaskGroups) == 0 {
mErr.Errors = append(mErr.Errors, errors.New("Missing job task groups"))
}
for idx, constr := range j.Constraints {
if err := constr.Validate(); err != nil {
outer := fmt.Errorf("Constraint %d validation failed: %s", idx+1, err)
mErr.Errors = append(mErr.Errors, outer)
}
}
// Check for duplicate task groups
taskGroups := make(map[string]int)
@ -918,6 +926,12 @@ func (tg *TaskGroup) Validate() error {
if len(tg.Tasks) == 0 {
mErr.Errors = append(mErr.Errors, errors.New("Missing tasks for task group"))
}
for idx, constr := range tg.Constraints {
if err := constr.Validate(); err != nil {
outer := fmt.Errorf("Constraint %d validation failed: %s", idx+1, err)
mErr.Errors = append(mErr.Errors, outer)
}
}
// Check for duplicate tasks
tasks := make(map[string]int)
@ -997,6 +1011,12 @@ func (t *Task) Validate() error {
if t.Resources == nil {
mErr.Errors = append(mErr.Errors, errors.New("Missing task resources"))
}
for idx, constr := range t.Constraints {
if err := constr.Validate(); err != nil {
outer := fmt.Errorf("Constraint %d validation failed: %s", idx+1, err)
mErr.Errors = append(mErr.Errors, outer)
}
}
return mErr.ErrorOrNil()
}
@ -1015,6 +1035,26 @@ func (c *Constraint) String() string {
return fmt.Sprintf("%s %s %s", c.LTarget, c.Operand, c.RTarget)
}
func (c *Constraint) Validate() error {
var mErr multierror.Error
if c.Operand == "" {
mErr.Errors = append(mErr.Errors, errors.New("Missing constraint operand"))
}
// Perform additional validation based on operand
switch c.Operand {
case "regexp":
if _, err := regexp.Compile(c.RTarget); err != nil {
mErr.Errors = append(mErr.Errors, fmt.Errorf("Regular expression failed to compile: %v", err))
}
case "version":
if _, err := version.NewConstraint(c.RTarget); err != nil {
mErr.Errors = append(mErr.Errors, fmt.Errorf("Version constraint is invalid: %v", err))
}
}
return mErr.ErrorOrNil()
}
const (
AllocDesiredStatusRun = "run" // Allocation should run
AllocDesiredStatusStop = "stop" // Allocation should stop

View file

@ -125,6 +125,43 @@ func TestTask_Validate(t *testing.T) {
}
}
func TestConstraint_Validate(t *testing.T) {
c := &Constraint{}
err := c.Validate()
mErr := err.(*multierror.Error)
if !strings.Contains(mErr.Errors[0].Error(), "Missing constraint operand") {
t.Fatalf("err: %s", err)
}
c = &Constraint{
LTarget: "$attr.kernel.name",
RTarget: "linux",
Operand: "=",
}
err = c.Validate()
if err != nil {
t.Fatalf("err: %v", err)
}
// Perform additional regexp validation
c.Operand = "regexp"
c.RTarget = "(foo"
err = c.Validate()
mErr = err.(*multierror.Error)
if !strings.Contains(mErr.Errors[0].Error(), "missing closing") {
t.Fatalf("err: %s", err)
}
// Perform version validation
c.Operand = "version"
c.RTarget = "~> foo"
err = c.Validate()
mErr = err.(*multierror.Error)
if !strings.Contains(mErr.Errors[0].Error(), "Malformed constraint") {
t.Fatalf("err: %s", err)
}
}
func TestResource_NetIndex(t *testing.T) {
r := &Resources{
Networks: []*NetworkResource{