github.com/anth0d/nomad@v0.0.0-20221214183521-ae3a0a2cad06/client/lib/cgutil/cpuset_manager_v2_test.go (about)

     1  //go:build linux
     2  
     3  package cgutil
     4  
     5  import (
     6  	"path/filepath"
     7  	"strings"
     8  	"testing"
     9  
    10  	"github.com/hashicorp/nomad/client/testutil"
    11  	"github.com/hashicorp/nomad/helper/testlog"
    12  	"github.com/hashicorp/nomad/helper/uuid"
    13  	"github.com/hashicorp/nomad/lib/cpuset"
    14  	"github.com/hashicorp/nomad/nomad/mock"
    15  	"github.com/opencontainers/runc/libcontainer/cgroups"
    16  	"github.com/stretchr/testify/require"
    17  )
    18  
    19  // Note: these tests need to run on GitHub Actions runners with only 2 cores.
    20  // It is not possible to write more cores to a cpuset than are actually available,
    21  // so make sure tests account for that by setting systemCores as the full set of
    22  // usable cores.
    23  var systemCores = []uint16{0, 1}
    24  
    25  func TestCpusetManager_V2_AddAlloc(t *testing.T) {
    26  	testutil.CgroupsCompatibleV2(t)
    27  	testutil.MinimumCores(t, 2)
    28  
    29  	logger := testlog.HCLogger(t)
    30  	parent := uuid.Short() + ".scope"
    31  	create(t, parent)
    32  	cleanup(t, parent)
    33  
    34  	// setup the cpuset manager
    35  	manager := NewCpusetManagerV2(parent, systemCores, logger)
    36  	manager.Init()
    37  
    38  	// add our first alloc, isolating 1 core
    39  	t.Run("first", func(t *testing.T) {
    40  		alloc := mock.Alloc()
    41  		alloc.AllocatedResources.Tasks["web"].Cpu.ReservedCores = cpuset.New(0).ToSlice()
    42  		manager.AddAlloc(alloc)
    43  		cpusetIs(t, "0-1", parent, alloc.ID, "web")
    44  	})
    45  
    46  	// add second alloc, isolating 1 core
    47  	t.Run("second", func(t *testing.T) {
    48  		alloc := mock.Alloc()
    49  		alloc.AllocatedResources.Tasks["web"].Cpu.ReservedCores = cpuset.New(1).ToSlice()
    50  		manager.AddAlloc(alloc)
    51  		cpusetIs(t, "1", parent, alloc.ID, "web")
    52  	})
    53  
    54  	// note that the scheduler, not the cpuset manager, is what prevents over-subscription
    55  	// and as such no logic exists here to prevent that
    56  }
    57  
    58  func cpusetIs(t *testing.T, exp, parent, allocID, task string) {
    59  	scope := makeScope(makeID(allocID, task))
    60  	value, err := cgroups.ReadFile(filepath.Join(CgroupRoot, parent, scope), "cpuset.cpus")
    61  	require.NoError(t, err)
    62  	require.Equal(t, exp, strings.TrimSpace(value))
    63  }
    64  
    65  func TestCpusetManager_V2_RemoveAlloc(t *testing.T) {
    66  	testutil.CgroupsCompatibleV2(t)
    67  	testutil.MinimumCores(t, 2)
    68  
    69  	logger := testlog.HCLogger(t)
    70  	parent := uuid.Short() + ".scope"
    71  	create(t, parent)
    72  	cleanup(t, parent)
    73  
    74  	// setup the cpuset manager
    75  	manager := NewCpusetManagerV2(parent, systemCores, logger)
    76  	manager.Init()
    77  
    78  	// alloc1 gets core 0
    79  	alloc1 := mock.Alloc()
    80  	alloc1.AllocatedResources.Tasks["web"].Cpu.ReservedCores = cpuset.New(0).ToSlice()
    81  	manager.AddAlloc(alloc1)
    82  
    83  	// alloc2 gets core 1
    84  	alloc2 := mock.Alloc()
    85  	alloc2.AllocatedResources.Tasks["web"].Cpu.ReservedCores = cpuset.New(1).ToSlice()
    86  	manager.AddAlloc(alloc2)
    87  	cpusetIs(t, "1", parent, alloc2.ID, "web")
    88  
    89  	// with alloc1 gone, alloc2 gets the now shared core
    90  	manager.RemoveAlloc(alloc1.ID)
    91  	cpusetIs(t, "0-1", parent, alloc2.ID, "web")
    92  }