diff --git a/scheduler/feasible.go b/scheduler/feasible.go index 3215e7382..8912c6552 100644 --- a/scheduler/feasible.go +++ b/scheduler/feasible.go @@ -2,7 +2,6 @@ package scheduler import ( "fmt" - "math/rand" "reflect" "strings" @@ -68,11 +67,7 @@ func (iter *StaticIterator) Reset() { // is applied in-place func NewRandomIterator(ctx Context, nodes []*structs.Node) *StaticIterator { // shuffle with the Fisher-Yates algorithm - n := len(nodes) - for i := n - 1; i > 0; i-- { - j := rand.Intn(i + 1) - nodes[i], nodes[j] = nodes[j], nodes[i] - } + shuffleNodes(nodes) // Create a static iterator return NewStaticIterator(ctx, nodes) diff --git a/scheduler/util.go b/scheduler/util.go index 415e2a34b..2911b9503 100644 --- a/scheduler/util.go +++ b/scheduler/util.go @@ -2,6 +2,7 @@ package scheduler import ( "fmt" + "math/rand" "github.com/hashicorp/nomad/nomad/structs" ) @@ -195,3 +196,12 @@ func taintedNodes(state State, allocs []*structs.Allocation) (map[string]bool, e } return out, nil } + +// shuffleNodes randomizes the slice order with the Fisher-Yates algorithm +func shuffleNodes(nodes []*structs.Node) { + n := len(nodes) + for i := n - 1; i > 0; i-- { + j := rand.Intn(i + 1) + nodes[i], nodes[j] = nodes[j], nodes[i] + } +} diff --git a/scheduler/util_test.go b/scheduler/util_test.go index d4d8e9e08..a19186fe2 100644 --- a/scheduler/util_test.go +++ b/scheduler/util_test.go @@ -3,6 +3,7 @@ package scheduler import ( "fmt" "os" + "reflect" "testing" "github.com/hashicorp/nomad/nomad/mock" @@ -210,3 +211,19 @@ func TestTaintedNodes(t *testing.T) { t.Fatalf("Bad: %v", tainted) } } + +func TestShuffleNodes(t *testing.T) { + nodes := []*structs.Node{ + mock.Node(), + mock.Node(), + mock.Node(), + mock.Node(), + mock.Node(), + } + orig := make([]*structs.Node, len(nodes)) + copy(orig, nodes) + shuffleNodes(nodes) + if reflect.DeepEqual(nodes, orig) { + t.Fatalf("shoudl not match") + } +}