5138c5b99e
* client: do not disable memory swappiness if kernel does not support it This PR adds a workaround for very old Linux kernels which do not support the memory swappiness interface file. Normally we write a "0" to the file to explicitly disable swap. In the case the kernel does not support it, give libcontainer a nil value so it does not write anything. Fixes #17448 * client: detect swappiness by writing to the file * fixup changelog Co-authored-by: James Rasell <jrasell@users.noreply.github.com> --------- Co-authored-by: James Rasell <jrasell@users.noreply.github.com>
142 lines
3.5 KiB
Go
142 lines
3.5 KiB
Go
// Copyright (c) HashiCorp, Inc.
|
|
// SPDX-License-Identifier: MPL-2.0
|
|
|
|
//go:build linux
|
|
|
|
package cgutil
|
|
|
|
import (
|
|
"path/filepath"
|
|
"strings"
|
|
"testing"
|
|
|
|
"github.com/hashicorp/nomad/ci"
|
|
"github.com/hashicorp/nomad/client/testutil"
|
|
"github.com/hashicorp/nomad/helper/testlog"
|
|
"github.com/hashicorp/nomad/helper/uuid"
|
|
"github.com/opencontainers/runc/libcontainer/cgroups"
|
|
"github.com/opencontainers/runc/libcontainer/cgroups/fs2"
|
|
"github.com/shoenig/test/must"
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
func TestUtil_GetCgroupParent(t *testing.T) {
|
|
ci.Parallel(t)
|
|
|
|
t.Run("v1", func(t *testing.T) {
|
|
testutil.CgroupsCompatibleV1(t)
|
|
t.Run("default", func(t *testing.T) {
|
|
exp := "/nomad"
|
|
parent := GetCgroupParent("")
|
|
require.Equal(t, exp, parent)
|
|
})
|
|
|
|
t.Run("configured", func(t *testing.T) {
|
|
exp := "/bar"
|
|
parent := GetCgroupParent("/bar")
|
|
require.Equal(t, exp, parent)
|
|
})
|
|
})
|
|
|
|
t.Run("v2", func(t *testing.T) {
|
|
testutil.CgroupsCompatibleV2(t)
|
|
t.Run("default", func(t *testing.T) {
|
|
exp := "nomad.slice"
|
|
parent := GetCgroupParent("")
|
|
require.Equal(t, exp, parent)
|
|
})
|
|
|
|
t.Run("configured", func(t *testing.T) {
|
|
exp := "abc.slice"
|
|
parent := GetCgroupParent("abc.slice")
|
|
require.Equal(t, exp, parent)
|
|
})
|
|
})
|
|
}
|
|
|
|
func TestUtil_CreateCPUSetManager(t *testing.T) {
|
|
ci.Parallel(t)
|
|
|
|
logger := testlog.HCLogger(t)
|
|
|
|
t.Run("v1", func(t *testing.T) {
|
|
testutil.CgroupsCompatibleV1(t)
|
|
parent := "/" + uuid.Short()
|
|
manager := CreateCPUSetManager(parent, []uint16{0}, logger)
|
|
manager.Init()
|
|
_, ok := manager.(*cpusetManagerV1)
|
|
must.True(t, ok)
|
|
must.NoError(t, cgroups.RemovePath(filepath.Join(CgroupRoot, parent)))
|
|
})
|
|
|
|
t.Run("v2", func(t *testing.T) {
|
|
testutil.CgroupsCompatibleV2(t)
|
|
parent := uuid.Short() + ".slice"
|
|
manager := CreateCPUSetManager(parent, []uint16{0}, logger)
|
|
manager.Init()
|
|
_, ok := manager.(*cpusetManagerV2)
|
|
must.True(t, ok)
|
|
must.NoError(t, cgroups.RemovePath(filepath.Join(CgroupRoot, parent)))
|
|
})
|
|
}
|
|
|
|
func TestUtil_GetCPUsFromCgroup(t *testing.T) {
|
|
ci.Parallel(t)
|
|
|
|
t.Run("v2", func(t *testing.T) {
|
|
testutil.CgroupsCompatibleV2(t)
|
|
cpus, err := GetCPUsFromCgroup("system.slice") // thanks, systemd!
|
|
require.NoError(t, err)
|
|
require.NotEmpty(t, cpus)
|
|
})
|
|
}
|
|
|
|
func create(t *testing.T, name string) {
|
|
mgr, err := fs2.NewManager(nil, filepath.Join(CgroupRoot, name))
|
|
require.NoError(t, err)
|
|
if err = mgr.Apply(CreationPID); err != nil {
|
|
_ = cgroups.RemovePath(name)
|
|
t.Fatal("failed to create cgroup for test")
|
|
}
|
|
}
|
|
|
|
func cleanup(t *testing.T, name string) {
|
|
err := cgroups.RemovePath(name)
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
func TestUtil_CopyCpuset(t *testing.T) {
|
|
ci.Parallel(t)
|
|
|
|
t.Run("v2", func(t *testing.T) {
|
|
testutil.CgroupsCompatibleV2(t)
|
|
source := uuid.Short() + ".scope"
|
|
create(t, source)
|
|
defer cleanup(t, source)
|
|
require.NoError(t, cgroups.WriteFile(filepath.Join(CgroupRoot, source), "cpuset.cpus", "0-1"))
|
|
|
|
destination := uuid.Short() + ".scope"
|
|
create(t, destination)
|
|
defer cleanup(t, destination)
|
|
|
|
err := CopyCpuset(
|
|
filepath.Join(CgroupRoot, source),
|
|
filepath.Join(CgroupRoot, destination),
|
|
)
|
|
require.NoError(t, err)
|
|
|
|
value, readErr := cgroups.ReadFile(filepath.Join(CgroupRoot, destination), "cpuset.cpus")
|
|
require.NoError(t, readErr)
|
|
require.Equal(t, "0-1", strings.TrimSpace(value))
|
|
})
|
|
}
|
|
|
|
func TestUtil_MaybeDisableMemorySwappiness(t *testing.T) {
|
|
ci.Parallel(t)
|
|
|
|
// will return 0 on any reasonable kernel (both cgroups v1 and v2)
|
|
value := MaybeDisableMemorySwappiness()
|
|
must.NotNil(t, value)
|
|
must.Eq(t, 0, *value)
|
|
}
|