github.com/hernad/nomad@v1.6.112/e2e/oversubscription/oversubscription.go (about)

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