open-nomad/client/lib/cgutil/cgutil_linux_test.go
Seth Hoenig 5138c5b99e
client: do not disable memory swappiness if kernel does not support it (#17625)
* 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>
2023-06-22 09:36:31 -05:00

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)
}