2021-03-26 20:17:49 +00:00
|
|
|
package oversubscription
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
2022-04-11 15:40:51 +00:00
|
|
|
"strings"
|
|
|
|
"time"
|
2021-03-26 20:17:49 +00:00
|
|
|
|
|
|
|
"github.com/hashicorp/nomad/api"
|
|
|
|
"github.com/hashicorp/nomad/e2e/e2eutil"
|
|
|
|
"github.com/hashicorp/nomad/e2e/framework"
|
|
|
|
"github.com/hashicorp/nomad/helper/uuid"
|
|
|
|
)
|
|
|
|
|
|
|
|
type OversubscriptionTest struct {
|
|
|
|
framework.TC
|
2021-05-10 18:33:47 +00:00
|
|
|
jobIDs []string
|
|
|
|
initialSchedulerConfig *api.SchedulerConfiguration
|
2021-03-26 20:17:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func init() {
|
|
|
|
framework.AddSuites(&framework.TestSuite{
|
|
|
|
Component: "oversubscription",
|
|
|
|
CanRunLocal: true,
|
|
|
|
Cases: []framework.TestCase{
|
|
|
|
new(OversubscriptionTest),
|
|
|
|
},
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
func (tc *OversubscriptionTest) BeforeAll(f *framework.F) {
|
|
|
|
// Ensure cluster has leader before running tests
|
|
|
|
e2eutil.WaitForLeader(f.T(), tc.Nomad())
|
|
|
|
e2eutil.WaitForNodesReady(f.T(), tc.Nomad(), 1)
|
|
|
|
|
2021-05-10 18:33:47 +00:00
|
|
|
tc.enableMemoryOversubscription(f)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (tc *OversubscriptionTest) AfterAll(f *framework.F) {
|
|
|
|
tc.restoreSchedulerConfig(f)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (tc *OversubscriptionTest) enableMemoryOversubscription(f *framework.F) {
|
|
|
|
resp, _, err := tc.Nomad().Operator().SchedulerGetConfiguration(nil)
|
|
|
|
f.NoError(err)
|
|
|
|
|
2021-11-02 21:42:52 +00:00
|
|
|
tc.initialSchedulerConfig = resp.SchedulerConfig
|
2021-05-10 18:33:47 +00:00
|
|
|
|
2021-11-02 21:42:52 +00:00
|
|
|
conf := *resp.SchedulerConfig
|
|
|
|
conf.MemoryOversubscriptionEnabled = true
|
|
|
|
_, _, err = tc.Nomad().Operator().SchedulerSetConfiguration(&conf, nil)
|
2021-05-10 18:33:47 +00:00
|
|
|
f.NoError(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (tc *OversubscriptionTest) restoreSchedulerConfig(f *framework.F) {
|
|
|
|
if tc.initialSchedulerConfig != nil {
|
|
|
|
_, _, err := tc.Nomad().Operator().SchedulerSetConfiguration(tc.initialSchedulerConfig, nil)
|
|
|
|
f.NoError(err)
|
|
|
|
}
|
2021-03-26 20:17:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (tc *OversubscriptionTest) AfterEach(f *framework.F) {
|
|
|
|
nomadClient := tc.Nomad()
|
|
|
|
j := nomadClient.Jobs()
|
|
|
|
|
|
|
|
for _, id := range tc.jobIDs {
|
|
|
|
j.Deregister(id, true, nil)
|
|
|
|
}
|
|
|
|
tc.Nomad().System().GarbageCollect()
|
|
|
|
}
|
|
|
|
|
|
|
|
func (tc *OversubscriptionTest) TestDocker(f *framework.F) {
|
|
|
|
alloc := tc.runTest(f, "oversubscription-docker-", "docker.nomad")
|
|
|
|
|
|
|
|
// check that cgroup reports the memoryMaxMB as the limit within he container
|
|
|
|
stdout, err := e2eutil.AllocLogs(alloc.ID, e2eutil.LogsStdOut)
|
|
|
|
f.NoError(err)
|
|
|
|
f.Equal(fmt.Sprintf("%d\n", 30*1024*1024), stdout)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (tc *OversubscriptionTest) TestExec(f *framework.F) {
|
|
|
|
alloc := tc.runTest(f, "oversubscription-exec-", "exec.nomad")
|
|
|
|
|
|
|
|
// check the the cgroup is configured with the memoryMaxMB
|
|
|
|
var err error
|
|
|
|
expected := fmt.Sprintf("%d\n", 30*1024*1024)
|
|
|
|
e2eutil.WaitForAllocFile(alloc.ID, "/alloc/tmp/memory.limit_in_bytes", func(s string) bool {
|
|
|
|
if s != expected {
|
|
|
|
err = fmt.Errorf("expected %v got %v", expected, s)
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
err = nil
|
|
|
|
return true
|
|
|
|
}, nil)
|
|
|
|
f.NoError(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (tc *OversubscriptionTest) runTest(f *framework.F, jobPrefix, jobfile string) *api.Allocation {
|
|
|
|
// register a job
|
|
|
|
jobID := jobPrefix + uuid.Generate()[:8]
|
|
|
|
tc.jobIDs = append(tc.jobIDs, jobID)
|
|
|
|
|
|
|
|
allocs := e2eutil.RegisterAndWaitForAllocs(f.T(), tc.Nomad(), "oversubscription/testdata/"+jobfile, jobID, "")
|
|
|
|
f.Len(allocs, 1)
|
|
|
|
|
|
|
|
e2eutil.WaitForAllocRunning(f.T(), tc.Nomad(), allocs[0].ID)
|
|
|
|
|
|
|
|
alloc, _, err := tc.Nomad().Allocations().Info(allocs[0].ID, nil)
|
|
|
|
f.NoError(err)
|
|
|
|
|
|
|
|
// assert the resources info
|
|
|
|
resources := alloc.AllocatedResources.Tasks["task"]
|
|
|
|
f.Equal(int64(20), resources.Memory.MemoryMB)
|
|
|
|
f.Equal(int64(30), resources.Memory.MemoryMaxMB)
|
|
|
|
|
2022-04-11 15:40:51 +00:00
|
|
|
// assert the status API reports memory, we need to wait for the
|
|
|
|
// for metrics to be written before we can assert the entire
|
|
|
|
// command line
|
|
|
|
var allocInfo string
|
|
|
|
f.Eventually(func() bool {
|
|
|
|
allocInfo, err = e2eutil.Command("nomad", "alloc", "status", alloc.ID)
|
|
|
|
if err != nil {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
return strings.Contains(allocInfo, "/20 MiB") && // memory reserve
|
|
|
|
strings.Contains(allocInfo, "Max: 30 MiB") // memory max
|
|
|
|
}, 10*time.Second, 200*time.Millisecond, "unexpected memory output")
|
2021-03-26 20:17:49 +00:00
|
|
|
|
|
|
|
return alloc
|
|
|
|
}
|