2023-04-10 15:36:59 +00:00
|
|
|
// Copyright (c) HashiCorp, Inc.
|
|
|
|
// SPDX-License-Identifier: MPL-2.0
|
|
|
|
|
2018-12-19 00:39:45 +00:00
|
|
|
package affinities
|
|
|
|
|
|
|
|
import (
|
|
|
|
"github.com/hashicorp/nomad/e2e/framework"
|
|
|
|
"github.com/stretchr/testify/require"
|
|
|
|
|
2018-12-20 03:25:32 +00:00
|
|
|
"github.com/hashicorp/nomad/e2e/e2eutil"
|
2019-01-03 22:16:20 +00:00
|
|
|
"github.com/hashicorp/nomad/helper/uuid"
|
2018-12-19 00:39:45 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
type BasicAffinityTest struct {
|
|
|
|
framework.TC
|
|
|
|
jobIds []string
|
|
|
|
}
|
|
|
|
|
|
|
|
func init() {
|
|
|
|
framework.AddSuites(&framework.TestSuite{
|
|
|
|
Component: "Affinity",
|
|
|
|
CanRunLocal: true,
|
|
|
|
Cases: []framework.TestCase{
|
|
|
|
new(BasicAffinityTest),
|
|
|
|
},
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2018-12-19 15:56:44 +00:00
|
|
|
func (tc *BasicAffinityTest) BeforeAll(f *framework.F) {
|
|
|
|
// Ensure cluster has leader before running tests
|
2018-12-20 03:25:32 +00:00
|
|
|
e2eutil.WaitForLeader(f.T(), tc.Nomad())
|
2019-01-03 22:16:20 +00:00
|
|
|
// Ensure that we have four client nodes in ready state
|
|
|
|
e2eutil.WaitForNodesReady(f.T(), tc.Nomad(), 4)
|
2018-12-19 15:05:01 +00:00
|
|
|
}
|
2018-12-19 00:39:45 +00:00
|
|
|
|
2018-12-19 15:05:01 +00:00
|
|
|
func (tc *BasicAffinityTest) TestSingleAffinities(f *framework.F) {
|
|
|
|
nomadClient := tc.Nomad()
|
2019-01-03 22:16:20 +00:00
|
|
|
uuid := uuid.Generate()
|
|
|
|
jobId := "aff" + uuid[0:8]
|
|
|
|
tc.jobIds = append(tc.jobIds, jobId)
|
2020-01-28 22:33:59 +00:00
|
|
|
allocs := e2eutil.RegisterAndWaitForAllocs(f.T(), nomadClient, "affinities/input/single_affinity.nomad", jobId, "")
|
2018-12-20 03:25:32 +00:00
|
|
|
|
2018-12-19 15:05:01 +00:00
|
|
|
jobAllocs := nomadClient.Allocations()
|
|
|
|
require := require.New(f.T())
|
2018-12-19 00:39:45 +00:00
|
|
|
// Verify affinity score metadata
|
|
|
|
for _, allocStub := range allocs {
|
|
|
|
alloc, _, err := jobAllocs.Info(allocStub.ID, nil)
|
|
|
|
require.Nil(err)
|
|
|
|
require.NotEmpty(alloc.Metrics.ScoreMetaData)
|
|
|
|
for _, sm := range alloc.Metrics.ScoreMetaData {
|
|
|
|
score, ok := sm.Scores["node-affinity"]
|
|
|
|
if ok {
|
|
|
|
require.Equal(1.0, score)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
func (tc *BasicAffinityTest) TestMultipleAffinities(f *framework.F) {
|
2018-12-19 15:05:01 +00:00
|
|
|
nomadClient := tc.Nomad()
|
2019-01-03 22:16:20 +00:00
|
|
|
uuid := uuid.Generate()
|
|
|
|
jobId := "multiaff" + uuid[0:8]
|
|
|
|
tc.jobIds = append(tc.jobIds, jobId)
|
2020-01-28 22:33:59 +00:00
|
|
|
allocs := e2eutil.RegisterAndWaitForAllocs(f.T(), nomadClient, "affinities/input/multiple_affinities.nomad", jobId, "")
|
2018-12-20 03:25:32 +00:00
|
|
|
|
2018-12-19 00:39:45 +00:00
|
|
|
jobAllocs := nomadClient.Allocations()
|
2018-12-19 15:05:01 +00:00
|
|
|
require := require.New(f.T())
|
2018-12-19 00:39:45 +00:00
|
|
|
|
|
|
|
// Verify affinity score metadata
|
|
|
|
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)
|
|
|
|
|
|
|
|
dcMatch := node.Datacenter == "dc1"
|
|
|
|
rackMatch := node.Meta != nil && node.Meta["rack"] == "r1"
|
|
|
|
|
|
|
|
// Figure out expected node affinity score based on whether both affinities match or just one does
|
|
|
|
expectedNodeAffinityScore := 0.0
|
|
|
|
if dcMatch && rackMatch {
|
|
|
|
expectedNodeAffinityScore = 1.0
|
|
|
|
} else if dcMatch || rackMatch {
|
|
|
|
expectedNodeAffinityScore = 0.5
|
|
|
|
}
|
|
|
|
|
|
|
|
nodeScore := 0.0
|
|
|
|
// Find the node's score for this alloc
|
|
|
|
for _, sm := range alloc.Metrics.ScoreMetaData {
|
|
|
|
score, ok := sm.Scores["node-affinity"]
|
|
|
|
if ok && sm.NodeID == alloc.NodeID {
|
|
|
|
nodeScore = score
|
|
|
|
}
|
|
|
|
}
|
|
|
|
require.Equal(nodeScore, expectedNodeAffinityScore)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (tc *BasicAffinityTest) TestAntiAffinities(f *framework.F) {
|
2018-12-19 15:05:01 +00:00
|
|
|
nomadClient := tc.Nomad()
|
2019-01-03 22:16:20 +00:00
|
|
|
uuid := uuid.Generate()
|
|
|
|
jobId := "antiaff" + uuid[0:8]
|
|
|
|
tc.jobIds = append(tc.jobIds, jobId)
|
2020-01-28 22:33:59 +00:00
|
|
|
allocs := e2eutil.RegisterAndWaitForAllocs(f.T(), nomadClient, "affinities/input/anti_affinities.nomad", jobId, "")
|
2018-12-20 03:25:32 +00:00
|
|
|
|
2018-12-19 00:39:45 +00:00
|
|
|
jobAllocs := nomadClient.Allocations()
|
2018-12-19 15:05:01 +00:00
|
|
|
require := require.New(f.T())
|
2018-12-19 00:39:45 +00:00
|
|
|
|
|
|
|
// Verify affinity score metadata
|
|
|
|
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)
|
|
|
|
|
|
|
|
dcMatch := node.Datacenter == "dc1"
|
|
|
|
rackMatch := node.Meta != nil && node.Meta["rack"] == "r1"
|
|
|
|
|
|
|
|
// Figure out expected node affinity score based on whether both affinities match or just one does
|
|
|
|
expectedAntiAffinityScore := 0.0
|
|
|
|
if dcMatch && rackMatch {
|
|
|
|
expectedAntiAffinityScore = -1.0
|
|
|
|
} else if dcMatch || rackMatch {
|
|
|
|
expectedAntiAffinityScore = -0.5
|
|
|
|
}
|
|
|
|
|
|
|
|
nodeScore := 0.0
|
|
|
|
|
|
|
|
// Find the node's score for this alloc
|
|
|
|
for _, sm := range alloc.Metrics.ScoreMetaData {
|
|
|
|
score, ok := sm.Scores["node-affinity"]
|
|
|
|
if ok && sm.NodeID == alloc.NodeID {
|
|
|
|
nodeScore = score
|
|
|
|
}
|
|
|
|
}
|
|
|
|
require.Equal(nodeScore, expectedAntiAffinityScore)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (tc *BasicAffinityTest) AfterEach(f *framework.F) {
|
|
|
|
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()
|
|
|
|
}
|