2018-12-17 18:29:56 +00:00
|
|
|
package spread
|
|
|
|
|
|
|
|
import (
|
2020-10-16 15:01:07 +00:00
|
|
|
"fmt"
|
|
|
|
"strings"
|
|
|
|
|
2018-12-17 18:29:56 +00:00
|
|
|
"github.com/stretchr/testify/require"
|
|
|
|
|
2020-10-16 15:01:07 +00:00
|
|
|
"github.com/hashicorp/nomad/api"
|
2018-12-20 03:25:32 +00:00
|
|
|
"github.com/hashicorp/nomad/e2e/e2eutil"
|
2020-10-16 15:01:07 +00:00
|
|
|
"github.com/hashicorp/nomad/e2e/framework"
|
2019-01-03 22:16:20 +00:00
|
|
|
"github.com/hashicorp/nomad/helper/uuid"
|
2018-12-17 18:29:56 +00:00
|
|
|
)
|
|
|
|
|
2018-12-20 03:25:32 +00:00
|
|
|
type SpreadTest struct {
|
2018-12-17 18:29:56 +00:00
|
|
|
framework.TC
|
|
|
|
jobIds []string
|
|
|
|
}
|
|
|
|
|
|
|
|
func init() {
|
|
|
|
framework.AddSuites(&framework.TestSuite{
|
|
|
|
Component: "Spread",
|
|
|
|
CanRunLocal: true,
|
|
|
|
Cases: []framework.TestCase{
|
2018-12-20 03:25:32 +00:00
|
|
|
new(SpreadTest),
|
2018-12-17 18:29:56 +00:00
|
|
|
},
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2018-12-20 03:25:32 +00:00
|
|
|
func (tc *SpreadTest) BeforeAll(f *framework.F) {
|
|
|
|
// Ensure cluster has leader before running tests
|
|
|
|
e2eutil.WaitForLeader(f.T(), tc.Nomad())
|
2019-01-03 22:16:20 +00:00
|
|
|
e2eutil.WaitForNodesReady(f.T(), tc.Nomad(), 4)
|
2018-12-20 03:25:32 +00:00
|
|
|
}
|
2018-12-17 18:29:56 +00:00
|
|
|
|
2018-12-20 03:25:32 +00:00
|
|
|
func (tc *SpreadTest) TestEvenSpread(f *framework.F) {
|
|
|
|
nomadClient := tc.Nomad()
|
2019-01-03 22:16:20 +00:00
|
|
|
uuid := uuid.Generate()
|
|
|
|
jobId := "spread" + uuid[0:8]
|
|
|
|
tc.jobIds = append(tc.jobIds, jobId)
|
2020-01-28 22:33:59 +00:00
|
|
|
allocs := e2eutil.RegisterAndWaitForAllocs(f.T(), nomadClient, "spread/input/even_spread.nomad", jobId, "")
|
2018-12-17 18:29:56 +00:00
|
|
|
|
|
|
|
jobAllocs := nomadClient.Allocations()
|
|
|
|
dcToAllocs := make(map[string]int)
|
2018-12-20 03:25:32 +00:00
|
|
|
require := require.New(f.T())
|
2018-12-17 18:29:56 +00:00
|
|
|
// Verify spread score and alloc distribution
|
|
|
|
for _, allocStub := range allocs {
|
|
|
|
alloc, _, err := jobAllocs.Info(allocStub.ID, nil)
|
|
|
|
require.Nil(err)
|
|
|
|
require.NotEmpty(alloc.Metrics.ScoreMetaData)
|
|
|
|
|
|
|
|
node, _, err := nomadClient.Nodes().Info(alloc.NodeID, nil)
|
|
|
|
require.Nil(err)
|
2018-12-20 21:12:48 +00:00
|
|
|
dcToAllocs[node.Datacenter]++
|
2018-12-17 18:29:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
expectedDcToAllocs := make(map[string]int)
|
|
|
|
expectedDcToAllocs["dc1"] = 3
|
|
|
|
expectedDcToAllocs["dc2"] = 3
|
|
|
|
require.Equal(expectedDcToAllocs, dcToAllocs)
|
|
|
|
}
|
|
|
|
|
2018-12-20 03:25:32 +00:00
|
|
|
func (tc *SpreadTest) TestMultipleSpreads(f *framework.F) {
|
2018-12-17 18:29:56 +00:00
|
|
|
nomadClient := tc.Nomad()
|
2019-01-03 22:16:20 +00:00
|
|
|
uuid := uuid.Generate()
|
|
|
|
jobId := "spread" + uuid[0:8]
|
|
|
|
tc.jobIds = append(tc.jobIds, jobId)
|
2020-01-28 22:33:59 +00:00
|
|
|
allocs := e2eutil.RegisterAndWaitForAllocs(f.T(), nomadClient, "spread/input/multiple_spread.nomad", jobId, "")
|
2018-12-17 18:29:56 +00:00
|
|
|
|
|
|
|
jobAllocs := nomadClient.Allocations()
|
|
|
|
dcToAllocs := make(map[string]int)
|
|
|
|
rackToAllocs := make(map[string]int)
|
2020-10-16 15:01:07 +00:00
|
|
|
allocMetrics := make(map[string]*api.AllocationMetric)
|
2018-12-17 18:29:56 +00:00
|
|
|
|
2018-12-20 03:25:32 +00:00
|
|
|
require := require.New(f.T())
|
2018-12-17 18:29:56 +00:00
|
|
|
// Verify spread score and alloc distribution
|
|
|
|
for _, allocStub := range allocs {
|
|
|
|
alloc, _, err := jobAllocs.Info(allocStub.ID, nil)
|
2019-01-03 22:16:20 +00:00
|
|
|
|
2018-12-17 18:29:56 +00:00
|
|
|
require.Nil(err)
|
|
|
|
require.NotEmpty(alloc.Metrics.ScoreMetaData)
|
2020-10-16 15:01:07 +00:00
|
|
|
allocMetrics[allocStub.ID] = alloc.Metrics
|
2018-12-17 18:29:56 +00:00
|
|
|
|
|
|
|
node, _, err := nomadClient.Nodes().Info(alloc.NodeID, nil)
|
|
|
|
require.Nil(err)
|
2018-12-20 21:12:48 +00:00
|
|
|
dcToAllocs[node.Datacenter]++
|
2018-12-17 18:29:56 +00:00
|
|
|
rack := node.Meta["rack"]
|
|
|
|
if rack != "" {
|
2018-12-20 21:12:48 +00:00
|
|
|
rackToAllocs[rack]++
|
2018-12-17 18:29:56 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
expectedDcToAllocs := make(map[string]int)
|
|
|
|
expectedDcToAllocs["dc1"] = 5
|
|
|
|
expectedDcToAllocs["dc2"] = 5
|
2020-10-16 15:01:07 +00:00
|
|
|
require.Equal(expectedDcToAllocs, dcToAllocs, report(allocMetrics))
|
2018-12-17 18:29:56 +00:00
|
|
|
|
2018-12-17 20:39:14 +00:00
|
|
|
expectedRackToAllocs := make(map[string]int)
|
|
|
|
expectedRackToAllocs["r1"] = 7
|
|
|
|
expectedRackToAllocs["r2"] = 3
|
2020-10-16 15:01:07 +00:00
|
|
|
require.Equal(expectedRackToAllocs, rackToAllocs, report(allocMetrics))
|
2018-12-17 18:29:56 +00:00
|
|
|
|
|
|
|
}
|
|
|
|
|
2020-10-16 15:01:07 +00:00
|
|
|
func report(metrics map[string]*api.AllocationMetric) string {
|
|
|
|
var s strings.Builder
|
|
|
|
for allocID, m := range metrics {
|
|
|
|
s.WriteString("Alloc ID: " + allocID + "\n")
|
|
|
|
s.WriteString(fmt.Sprintf(" NodesEvaluated: %d\n", m.NodesEvaluated))
|
|
|
|
s.WriteString(fmt.Sprintf(" NodesAvailable: %#v\n", m.NodesAvailable))
|
|
|
|
s.WriteString(fmt.Sprintf(" ClassFiltered: %#v\n", m.ClassFiltered))
|
|
|
|
s.WriteString(fmt.Sprintf(" ConstraintFiltered: %#v\n", m.ConstraintFiltered))
|
|
|
|
s.WriteString(fmt.Sprintf(" NodesExhausted: %d\n", m.NodesExhausted))
|
|
|
|
s.WriteString(fmt.Sprintf(" ClassExhausted: %#v\n", m.ClassExhausted))
|
|
|
|
s.WriteString(fmt.Sprintf(" DimensionExhausted: %#v\n", m.DimensionExhausted))
|
|
|
|
s.WriteString(fmt.Sprintf(" QuotaExhausted: %#v\n", m.QuotaExhausted))
|
|
|
|
for _, nodeMeta := range m.ScoreMetaData {
|
|
|
|
s.WriteString(fmt.Sprintf(" NodeID: %s, NormScore: %f, Scores: %#v\n",
|
|
|
|
nodeMeta.NodeID, nodeMeta.NormScore, nodeMeta.Scores))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return s.String()
|
|
|
|
}
|
|
|
|
|
2018-12-20 03:25:32 +00:00
|
|
|
func (tc *SpreadTest) AfterEach(f *framework.F) {
|
2018-12-17 18:29:56 +00:00
|
|
|
nomadClient := tc.Nomad()
|
|
|
|
jobs := nomadClient.Jobs()
|
|
|
|
// Stop all jobs in test
|
|
|
|
for _, id := range tc.jobIds {
|
|
|
|
jobs.Deregister(id, true, nil)
|
|
|
|
}
|
|
|
|
// Garbage collect
|
|
|
|
nomadClient.System().GarbageCollect()
|
|
|
|
}
|