diff --git a/nomad/structs/network.go b/nomad/structs/network.go index 39292e831..216e51015 100644 --- a/nomad/structs/network.go +++ b/nomad/structs/network.go @@ -1,6 +1,7 @@ package structs import ( + "fmt" "math/rand" "net" ) @@ -134,7 +135,7 @@ func (idx *NetworkIndex) yieldIP(cb func(net *NetworkResource, ip net.IP) bool) // AssignNetwork is used to assign network resources given an ask. // If the ask cannot be satisfied, returns nil -func (idx *NetworkIndex) AssignNetwork(ask *NetworkResource) (out *NetworkResource) { +func (idx *NetworkIndex) AssignNetwork(ask *NetworkResource) (out *NetworkResource, err error) { idx.yieldIP(func(n *NetworkResource, ip net.IP) (stop bool) { // Convert the IP to a string ipStr := ip.String() @@ -143,13 +144,15 @@ func (idx *NetworkIndex) AssignNetwork(ask *NetworkResource) (out *NetworkResour availBandwidth := idx.AvailBandwidth[n.Device] usedBandwidth := idx.UsedBandwidth[n.Device] if usedBandwidth+ask.MBits > availBandwidth { + err = fmt.Errorf("bandwidth exceeded") return } // Check if any of the reserved ports are in use for _, port := range ask.ReservedPorts { if _, ok := idx.UsedPorts[ipStr][port]; ok { - return false + err = fmt.Errorf("reserved port collision") + return } } @@ -166,6 +169,7 @@ func (idx *NetworkIndex) AssignNetwork(ask *NetworkResource) (out *NetworkResour PICK: attempts++ if attempts > maxRandPortAttempts { + err = fmt.Errorf("dynamic port selection failed") return } @@ -181,6 +185,7 @@ func (idx *NetworkIndex) AssignNetwork(ask *NetworkResource) (out *NetworkResour // Stop, we have an offer! out = offer + err = nil return true }) return diff --git a/nomad/structs/network_test.go b/nomad/structs/network_test.go index 802964472..1db783d65 100644 --- a/nomad/structs/network_test.go +++ b/nomad/structs/network_test.go @@ -271,7 +271,10 @@ func TestNetworkIndex_AssignNetwork(t *testing.T) { ask := &NetworkResource{ ReservedPorts: []int{8000}, } - offer := idx.AssignNetwork(ask) + offer, err := idx.AssignNetwork(ask) + if err != nil { + t.Fatalf("err: %v", err) + } if offer == nil { t.Fatalf("bad") } @@ -286,7 +289,10 @@ func TestNetworkIndex_AssignNetwork(t *testing.T) { ask = &NetworkResource{ DynamicPorts: 3, } - offer = idx.AssignNetwork(ask) + offer, err = idx.AssignNetwork(ask) + if err != nil { + t.Fatalf("err: %v", err) + } if offer == nil { t.Fatalf("bad") } @@ -302,7 +308,10 @@ func TestNetworkIndex_AssignNetwork(t *testing.T) { ReservedPorts: []int{12345}, DynamicPorts: 3, } - offer = idx.AssignNetwork(ask) + offer, err = idx.AssignNetwork(ask) + if err != nil { + t.Fatalf("err: %v", err) + } if offer == nil { t.Fatalf("bad") } @@ -317,7 +326,10 @@ func TestNetworkIndex_AssignNetwork(t *testing.T) { ask = &NetworkResource{ MBits: 1000, } - offer = idx.AssignNetwork(ask) + offer, err = idx.AssignNetwork(ask) + if err.Error() != "bandwidth exceeded" { + t.Fatalf("err: %v", err) + } if offer != nil { t.Fatalf("bad") } diff --git a/nomad/structs/structs.go b/nomad/structs/structs.go index f5479c3bc..23633a1af 100644 --- a/nomad/structs/structs.go +++ b/nomad/structs/structs.go @@ -594,7 +594,7 @@ func (r *Resources) Add(delta *Resources) error { // Find the matching interface by IP or CIDR idx := r.NetIndex(n) if idx == -1 { - r.Networks = append(r.Networks, n) + r.Networks = append(r.Networks, n.Copy()) } else { r.Networks[idx].Add(n) }