github.com/anth0d/nomad@v0.0.0-20221214183521-ae3a0a2cad06/e2e/oversubscription/oversubscription.go (about)

     1  package oversubscription
     2  
     3  import (
     4  	"fmt"
     5  	"strings"
     6  	"time"
     7  
     8  	"github.com/hashicorp/nomad/api"
     9  	"github.com/hashicorp/nomad/e2e/e2eutil"
    10  	"github.com/hashicorp/nomad/e2e/framework"
    11  	"github.com/hashicorp/nomad/helper/uuid"
    12  )
    13  
    14  type OversubscriptionTest struct {
    15  	framework.TC
    16  	jobIDs                 []string
    17  	initialSchedulerConfig *api.SchedulerConfiguration
    18  }
    19  
    20  func init() {
    21  	framework.AddSuites(&framework.TestSuite{
    22  		Component:   "oversubscription",
    23  		CanRunLocal: true,
    24  		Cases: []framework.TestCase{
    25  			new(OversubscriptionTest),
    26  		},
    27  	})
    28  }
    29  
    30  func (tc *OversubscriptionTest) BeforeAll(f *framework.F) {
    31  	// Ensure cluster has leader before running tests
    32  	e2eutil.WaitForLeader(f.T(), tc.Nomad())
    33  	e2eutil.WaitForNodesReady(f.T(), tc.Nomad(), 1)
    34  
    35  	tc.enableMemoryOversubscription(f)
    36  }
    37  
    38  func (tc *OversubscriptionTest) AfterAll(f *framework.F) {
    39  	tc.restoreSchedulerConfig(f)
    40  }
    41  
    42  func (tc *OversubscriptionTest) enableMemoryOversubscription(f *framework.F) {
    43  	resp, _, err := tc.Nomad().Operator().SchedulerGetConfiguration(nil)
    44  	f.NoError(err)
    45  
    46  	tc.initialSchedulerConfig = resp.SchedulerConfig
    47  
    48  	conf := *resp.SchedulerConfig
    49  	conf.MemoryOversubscriptionEnabled = true
    50  	_, _, err = tc.Nomad().Operator().SchedulerSetConfiguration(&conf, nil)
    51  	f.NoError(err)
    52  }
    53  
    54  func (tc *OversubscriptionTest) restoreSchedulerConfig(f *framework.F) {
    55  	if tc.initialSchedulerConfig != nil {
    56  		_, _, err := tc.Nomad().Operator().SchedulerSetConfiguration(tc.initialSchedulerConfig, nil)
    57  		f.NoError(err)
    58  	}
    59  }
    60  
    61  func (tc *OversubscriptionTest) AfterEach(f *framework.F) {
    62  	nomadClient := tc.Nomad()
    63  	j := nomadClient.Jobs()
    64  
    65  	for _, id := range tc.jobIDs {
    66  		j.Deregister(id, true, nil)
    67  	}
    68  	tc.Nomad().System().GarbageCollect()
    69  }
    70  
    71  func (tc *OversubscriptionTest) TestDocker(f *framework.F) {
    72  	alloc := tc.runTest(f, "oversubscription-docker-", "docker.nomad")
    73  
    74  	// check that cgroup reports the memoryMaxMB as the limit within he container
    75  	stdout, err := e2eutil.AllocLogs(alloc.ID, e2eutil.LogsStdOut)
    76  	f.NoError(err)
    77  	f.Equal(fmt.Sprintf("%d\n", 30*1024*1024), stdout)
    78  }
    79  
    80  func (tc *OversubscriptionTest) TestExec(f *framework.F) {
    81  	alloc := tc.runTest(f, "oversubscription-exec-", "exec.nomad")
    82  
    83  	// check the the cgroup is configured with the memoryMaxMB
    84  	var err error
    85  	expected := fmt.Sprintf("%d\n", 30*1024*1024)
    86  	e2eutil.WaitForAllocFile(alloc.ID, "/alloc/tmp/memory.limit_in_bytes", func(s string) bool {
    87  		if s != expected {
    88  			err = fmt.Errorf("expected %v got %v", expected, s)
    89  			return false
    90  		}
    91  		err = nil
    92  		return true
    93  	}, nil)
    94  	f.NoError(err)
    95  }
    96  
    97  func (tc *OversubscriptionTest) runTest(f *framework.F, jobPrefix, jobfile string) *api.Allocation {
    98  	// register a job
    99  	jobID := jobPrefix + uuid.Generate()[:8]
   100  	tc.jobIDs = append(tc.jobIDs, jobID)
   101  
   102  	allocs := e2eutil.RegisterAndWaitForAllocs(f.T(), tc.Nomad(), "oversubscription/testdata/"+jobfile, jobID, "")
   103  	f.Len(allocs, 1)
   104  
   105  	e2eutil.WaitForAllocRunning(f.T(), tc.Nomad(), allocs[0].ID)
   106  
   107  	alloc, _, err := tc.Nomad().Allocations().Info(allocs[0].ID, nil)
   108  	f.NoError(err)
   109  
   110  	// assert the resources info
   111  	resources := alloc.AllocatedResources.Tasks["task"]
   112  	f.Equal(int64(20), resources.Memory.MemoryMB)
   113  	f.Equal(int64(30), resources.Memory.MemoryMaxMB)
   114  
   115  	// assert the status API reports memory, we need to wait for the
   116  	// for metrics to be written before we can assert the entire
   117  	// command line
   118  	var allocInfo string
   119  	f.Eventually(func() bool {
   120  		allocInfo, err = e2eutil.Command("nomad", "alloc", "status", alloc.ID)
   121  		if err != nil {
   122  			return false
   123  		}
   124  		return strings.Contains(allocInfo, "/20 MiB") && // memory reserve
   125  			strings.Contains(allocInfo, "Max: 30 MiB") // memory max
   126  	}, 10*time.Second, 200*time.Millisecond, "unexpected memory output")
   127  
   128  	return alloc
   129  }