From aa7c08679ea8bb667722352a4efbd6aac2e80f76 Mon Sep 17 00:00:00 2001 From: Nick Ethier Date: Fri, 3 May 2019 10:26:26 -0400 Subject: [PATCH] structs: Add validations for task group networks --- nomad/structs/structs.go | 65 ++++++++++++++++++++++++++++++----- nomad/structs/structs_test.go | 22 ++++++++++++ 2 files changed, 78 insertions(+), 9 deletions(-) diff --git a/nomad/structs/structs.go b/nomad/structs/structs.go index d78a580e3..9d4cc162a 100644 --- a/nomad/structs/structs.go +++ b/nomad/structs/structs.go @@ -4818,10 +4818,42 @@ func (tg *TaskGroup) Validate(j *Job) error { } } - // Check for duplicate tasks, that there is only leader task if any, - // and no duplicated static ports - tasks := make(map[string]int) + portLabels := make(map[string]string) staticPorts := make(map[int]string) + mappedPorts := make(map[int]string) + + for _, net := range tg.Networks { + for _, port := range append(net.ReservedPorts, net.DynamicPorts...) { + if other, ok := portLabels[port.Label]; ok { + mErr.Errors = append(mErr.Errors, fmt.Errorf("Port label %s already in use by %s", port.Label, other)) + } else { + portLabels[port.Label] = "taskgroup network" + } + + if port.Value != 0 { + // static port + if other, ok := staticPorts[port.Value]; ok { + err := fmt.Errorf("Static port %d already reserved by %s", port.Value, other) + mErr.Errors = append(mErr.Errors, err) + } else { + staticPorts[port.Value] = fmt.Sprintf("taskgroup network:%s", port.Label) + } + } + + if port.To != 0 { + if other, ok := mappedPorts[port.To]; ok { + err := fmt.Errorf("Port mapped to %d already in use by %s", port.To, other) + mErr.Errors = append(mErr.Errors, err) + } else { + mappedPorts[port.To] = fmt.Sprintf("taskgroup network:%s", port.Label) + } + } + } + } + + // Check for duplicate tasks or port labels, that there is only leader task if any, + // and no duplicated static or mapped ports + tasks := make(map[string]int) leaderTasks := 0 for idx, task := range tg.Tasks { if task.Name == "" { @@ -4841,12 +4873,27 @@ func (tg *TaskGroup) Validate(j *Job) error { } for _, net := range task.Resources.Networks { - for _, port := range net.ReservedPorts { - if other, ok := staticPorts[port.Value]; ok { - err := fmt.Errorf("Static port %d already reserved by %s", port.Value, other) - mErr.Errors = append(mErr.Errors, err) - } else { - staticPorts[port.Value] = fmt.Sprintf("%s:%s", task.Name, port.Label) + for _, port := range append(net.ReservedPorts, net.DynamicPorts...) { + if other, ok := portLabels[port.Label]; ok { + mErr.Errors = append(mErr.Errors, fmt.Errorf("Port label %s already in use by %s", port.Label, other)) + } + + if port.Value != 0 { + if other, ok := staticPorts[port.Value]; ok { + err := fmt.Errorf("Static port %d already reserved by %s", port.Value, other) + mErr.Errors = append(mErr.Errors, err) + } else { + staticPorts[port.Value] = fmt.Sprintf("%s:%s", task.Name, port.Label) + } + } + + if port.To != 0 { + if other, ok := mappedPorts[port.To]; ok { + err := fmt.Errorf("Port mapped to %d already in use by %s", port.To, other) + mErr.Errors = append(mErr.Errors, err) + } else { + mappedPorts[port.To] = fmt.Sprintf("taskgroup network:%s", port.Label) + } } } } diff --git a/nomad/structs/structs_test.go b/nomad/structs/structs_test.go index 3b6b54150..6f1fc03f6 100644 --- a/nomad/structs/structs_test.go +++ b/nomad/structs/structs_test.go @@ -846,6 +846,28 @@ 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{ + Networks: []*NetworkResource{ + { + DynamicPorts: []Port{{"http", 0, 80}}, + }, + }, + Tasks: []*Task{ + { + Resources: &Resources{ + Networks: []*NetworkResource{ + { + DynamicPorts: []Port{{"http", 0, 80}}, + }, + }, + }, + }, + }, + } + err = tg.Validate(j) + require.Contains(t, err.Error(), "Port label http already in use") + require.Contains(t, err.Error(), "Port mapped to 80 already in use") } func TestTask_Validate(t *testing.T) {