Skip to content

Commit

Permalink
volumes: Validate job configuration for volumes
Browse files Browse the repository at this point in the history
  • Loading branch information
endocrimes committed Jul 23, 2019
1 parent 00b5800 commit 39037d7
Show file tree
Hide file tree
Showing 3 changed files with 119 additions and 2 deletions.
1 change: 0 additions & 1 deletion command/job_validate.go
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,6 @@ func (c *JobValidateCommand) Run(args []string) int {
func (c *JobValidateCommand) validateLocal(aj *api.Job) (*api.JobValidateResponse, error) {
var out api.JobValidateResponse

// TODO: Handle errors from volumes here / move those errors into canonicalize
job := agent.ApiJobToStructJob(aj)
canonicalizeWarnings := job.Canonicalize()

Expand Down
33 changes: 32 additions & 1 deletion nomad/structs/structs.go
Original file line number Diff line number Diff line change
Expand Up @@ -4809,8 +4809,27 @@ func (tg *TaskGroup) Validate(j *Job) error {
}
}

// Validate the Host Volumes
for name, decl := range tg.Volumes {
if decl.Volume.Type != VolumeTypeHost {
// TODO: Remove this error when adding new volume types
mErr.Errors = append(mErr.Errors, fmt.Errorf("Volume %s has unrecognised type %s", name, decl.Volume.Type))
continue
}

cfg, err := ParseHostVolumeConfig(decl.Config)
if err != nil {
mErr.Errors = append(mErr.Errors, fmt.Errorf("Volume %s has unparseable config: %v", name, err))
continue
}

if cfg.Source == "" {
mErr.Errors = append(mErr.Errors, fmt.Errorf("Volume %s has an empty source", name))
}
}

// Check for duplicate tasks, that there is only leader task if any,
// and no duplicated static ports
// and no duplicated static ports, and missing group level volumes
tasks := make(map[string]int)
staticPorts := make(map[int]string)
leaderTasks := 0
Expand Down Expand Up @@ -4841,6 +4860,18 @@ func (tg *TaskGroup) Validate(j *Job) error {
}
}
}

for i, mnt := range task.VolumeMounts {
if mnt.Volume == "" {
mErr.Errors = append(mErr.Errors, fmt.Errorf("Task %s has a volume mount (%d) referencing an empty volume", task.Name, i))
continue
}

if _, ok := tg.Volumes[mnt.Volume]; !ok {
mErr.Errors = append(mErr.Errors, fmt.Errorf("Task %s has a volume mount (%d) referencing undefined volume %s", task.Name, i, mnt.Volume))
continue
}
}
}

if leaderTasks > 1 {
Expand Down
87 changes: 87 additions & 0 deletions nomad/structs/structs_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -846,6 +846,93 @@ func TestTaskGroup_Validate(t *testing.T) {
if !strings.Contains(err.Error(), "System jobs should not have a reschedule policy") {
t.Fatalf("err: %s", err)
}

tg = &TaskGroup{
Volumes: map[string]*VolumeRequest{
"foo": &VolumeRequest{
Volume: &Volume{
Type: "nothost",
},
Config: map[string]interface{}{
"sOuRcE": "foo",
},
},
},
Tasks: []*Task{
{
Name: "task-a",
Resources: &Resources{},
},
},
}
err = tg.Validate(&Job{})
expected = `Volume foo has unrecognised type nothost`
if !strings.Contains(err.Error(), expected) {
t.Errorf("expected %s but found: %v", expected, err)
}

tg = &TaskGroup{
Volumes: map[string]*VolumeRequest{
"foo": &VolumeRequest{
Volume: &Volume{
Type: "host",
},
Config: nil,
},
},
Tasks: []*Task{
{
Name: "task-a",
Resources: &Resources{},
},
},
}
err = tg.Validate(&Job{})
expected = `Volume foo has an empty source`
if !strings.Contains(err.Error(), expected) {
t.Errorf("expected %s but found: %v", expected, err)
}

tg = &TaskGroup{
Volumes: map[string]*VolumeRequest{
"foo": &VolumeRequest{
Volume: &Volume{
Type: "host",
},
Config: nil,
},
},
Tasks: []*Task{
{
Name: "task-a",
Resources: &Resources{},
VolumeMounts: []*VolumeMount{
{
Volume: "",
},
},
},
{
Name: "task-b",
Resources: &Resources{},
VolumeMounts: []*VolumeMount{
{
Volume: "foob",
},
},
},
},
}
err = tg.Validate(&Job{})
expected = `Task task-a has a volume mount (0) referencing an empty volume`
if !strings.Contains(err.Error(), expected) {
t.Errorf("expected %s but found: %v", expected, err)
}

expected = `Task task-b has a volume mount (0) referencing undefined volume foob`
if !strings.Contains(err.Error(), expected) {
t.Errorf("expected %s but found: %v", expected, err)
}
}

func TestTask_Validate(t *testing.T) {
Expand Down

0 comments on commit 39037d7

Please sign in to comment.