mirror of
https://github.com/aljazceru/kata-containers.git
synced 2025-12-26 10:34:24 +01:00
move `validCgroupPath` to `cgroups.go` since it's cgroups specific. Now `validCgroupPath` supports systemd cgroup path and returns a cgroup path ready to use, calls to `renameCgroupPath` are no longer needed. Signed-off-by: Julio Montes <julio.montes@intel.com>
291 lines
6.1 KiB
Go
291 lines
6.1 KiB
Go
// Copyright (c) 2018 Huawei Corporation
|
|
//
|
|
// SPDX-License-Identifier: Apache-2.0
|
|
//
|
|
|
|
package virtcontainers
|
|
|
|
import (
|
|
"fmt"
|
|
"os"
|
|
"os/exec"
|
|
"path/filepath"
|
|
"strings"
|
|
"testing"
|
|
|
|
"github.com/containerd/cgroups"
|
|
"github.com/kata-containers/runtime/virtcontainers/types"
|
|
specs "github.com/opencontainers/runtime-spec/specs-go"
|
|
"github.com/stretchr/testify/assert"
|
|
)
|
|
|
|
type mockCgroup struct {
|
|
}
|
|
|
|
func (m *mockCgroup) New(string, *specs.LinuxResources) (cgroups.Cgroup, error) {
|
|
return &mockCgroup{}, nil
|
|
}
|
|
func (m *mockCgroup) Add(cgroups.Process) error {
|
|
return nil
|
|
}
|
|
|
|
func (m *mockCgroup) AddTask(cgroups.Process) error {
|
|
return nil
|
|
}
|
|
|
|
func (m *mockCgroup) Delete() error {
|
|
return nil
|
|
}
|
|
|
|
func (m *mockCgroup) MoveTo(cgroups.Cgroup) error {
|
|
return nil
|
|
}
|
|
|
|
func (m *mockCgroup) Stat(...cgroups.ErrorHandler) (*cgroups.Metrics, error) {
|
|
return &cgroups.Metrics{}, nil
|
|
}
|
|
|
|
func (m *mockCgroup) Update(resources *specs.LinuxResources) error {
|
|
return nil
|
|
}
|
|
|
|
func (m *mockCgroup) Processes(cgroups.Name, bool) ([]cgroups.Process, error) {
|
|
return nil, nil
|
|
}
|
|
|
|
func (m *mockCgroup) Freeze() error {
|
|
return nil
|
|
}
|
|
|
|
func (m *mockCgroup) Thaw() error {
|
|
return nil
|
|
}
|
|
|
|
func (m *mockCgroup) OOMEventFD() (uintptr, error) {
|
|
return 0, nil
|
|
}
|
|
|
|
func (m *mockCgroup) State() cgroups.State {
|
|
return ""
|
|
}
|
|
|
|
func (m *mockCgroup) Subsystems() []cgroups.Subsystem {
|
|
return nil
|
|
}
|
|
|
|
func (m *mockCgroup) Tasks(cgroups.Name, bool) ([]cgroups.Task, error) {
|
|
return nil, nil
|
|
}
|
|
|
|
func mockCgroupNew(hierarchy cgroups.Hierarchy, path cgroups.Path, resources *specs.LinuxResources, opts ...cgroups.InitOpts) (cgroups.Cgroup, error) {
|
|
return &mockCgroup{}, nil
|
|
}
|
|
|
|
func mockCgroupLoad(hierarchy cgroups.Hierarchy, path cgroups.Path, opts ...cgroups.InitOpts) (cgroups.Cgroup, error) {
|
|
return &mockCgroup{}, nil
|
|
}
|
|
|
|
func init() {
|
|
cgroupsNewFunc = mockCgroupNew
|
|
cgroupsLoadFunc = mockCgroupLoad
|
|
}
|
|
|
|
func TestV1Constraints(t *testing.T) {
|
|
assert := assert.New(t)
|
|
|
|
systems, err := V1Constraints()
|
|
assert.NoError(err)
|
|
assert.NotEmpty(systems)
|
|
}
|
|
|
|
func TestV1NoConstraints(t *testing.T) {
|
|
assert := assert.New(t)
|
|
|
|
systems, err := V1NoConstraints()
|
|
assert.NoError(err)
|
|
assert.NotEmpty(systems)
|
|
}
|
|
|
|
func TestCgroupNoConstraintsPath(t *testing.T) {
|
|
assert := assert.New(t)
|
|
|
|
cgrouPath := "abc"
|
|
expectedPath := filepath.Join(cgroupKataPath, cgrouPath)
|
|
path := cgroupNoConstraintsPath(cgrouPath)
|
|
assert.Equal(expectedPath, path)
|
|
}
|
|
|
|
func TestUpdateCgroups(t *testing.T) {
|
|
assert := assert.New(t)
|
|
|
|
oldCgroupsNew := cgroupsNewFunc
|
|
oldCgroupsLoad := cgroupsLoadFunc
|
|
cgroupsNewFunc = cgroups.New
|
|
cgroupsLoadFunc = cgroups.Load
|
|
defer func() {
|
|
cgroupsNewFunc = oldCgroupsNew
|
|
cgroupsLoadFunc = oldCgroupsLoad
|
|
}()
|
|
|
|
s := &Sandbox{
|
|
state: types.SandboxState{
|
|
CgroupPath: "",
|
|
},
|
|
config: &SandboxConfig{SandboxCgroupOnly: false},
|
|
}
|
|
|
|
// empty path
|
|
err := s.cgroupsUpdate()
|
|
assert.NoError(err)
|
|
|
|
// path doesn't exist
|
|
s.state.CgroupPath = "/abc/123/rgb"
|
|
err = s.cgroupsUpdate()
|
|
assert.Error(err)
|
|
|
|
if os.Getuid() != 0 {
|
|
return
|
|
}
|
|
|
|
s.state.CgroupPath = fmt.Sprintf("/kata-tests-%d", os.Getpid())
|
|
testCgroup, err := cgroups.New(cgroups.V1, cgroups.StaticPath(s.state.CgroupPath), &specs.LinuxResources{})
|
|
assert.NoError(err)
|
|
defer testCgroup.Delete()
|
|
s.hypervisor = &mockHypervisor{mockPid: 0}
|
|
|
|
// bad pid
|
|
err = s.cgroupsUpdate()
|
|
assert.Error(err)
|
|
|
|
// fake workload
|
|
cmd := exec.Command("tail", "-f", "/dev/null")
|
|
assert.NoError(cmd.Start())
|
|
s.hypervisor = &mockHypervisor{mockPid: cmd.Process.Pid}
|
|
|
|
// no containers
|
|
err = s.cgroupsUpdate()
|
|
assert.NoError(err)
|
|
|
|
s.config = &SandboxConfig{}
|
|
s.config.HypervisorConfig.NumVCPUs = 1
|
|
|
|
s.containers = map[string]*Container{
|
|
"abc": {
|
|
process: Process{
|
|
Pid: cmd.Process.Pid,
|
|
},
|
|
config: &ContainerConfig{
|
|
Annotations: containerAnnotations,
|
|
CustomSpec: newEmptySpec(),
|
|
},
|
|
},
|
|
"xyz": {
|
|
process: Process{
|
|
Pid: cmd.Process.Pid,
|
|
},
|
|
config: &ContainerConfig{
|
|
Annotations: containerAnnotations,
|
|
CustomSpec: newEmptySpec(),
|
|
},
|
|
},
|
|
}
|
|
|
|
err = s.cgroupsUpdate()
|
|
assert.NoError(err)
|
|
|
|
// cleanup
|
|
assert.NoError(cmd.Process.Kill())
|
|
err = s.cgroupsDelete()
|
|
assert.NoError(err)
|
|
}
|
|
|
|
func TestIsSystemdCgroup(t *testing.T) {
|
|
assert := assert.New(t)
|
|
|
|
tests := []struct {
|
|
path string
|
|
expected bool
|
|
}{
|
|
{"slice:kata:afhts2e5d4g5s", true},
|
|
{"slice.system:kata:afhts2e5d4g5s", true},
|
|
{"/kata/afhts2e5d4g5s", false},
|
|
{"a:b:c:d", false},
|
|
{":::", false},
|
|
{"", false},
|
|
{":", false},
|
|
{"::", false},
|
|
{":::", false},
|
|
{"a:b", false},
|
|
{"a:b:", false},
|
|
{":a:b", false},
|
|
{"@:@:@", false},
|
|
}
|
|
|
|
for _, t := range tests {
|
|
assert.Equal(t.expected, isSystemdCgroup(t.path), "invalid systemd cgroup path: %v", t.path)
|
|
}
|
|
}
|
|
|
|
func TestValidCgroupPath(t *testing.T) {
|
|
assert := assert.New(t)
|
|
|
|
for _, t := range []struct {
|
|
path string
|
|
systemdCgroup bool
|
|
error bool
|
|
}{
|
|
// empty paths
|
|
{"../../../", false, false},
|
|
{"../", false, false},
|
|
{".", false, false},
|
|
{"../../../", false, false},
|
|
{"./../", false, false},
|
|
|
|
// valid no-systemd paths
|
|
{"../../../foo", false, false},
|
|
{"/../hi", false, false},
|
|
{"/../hi/foo", false, false},
|
|
{"o / m /../ g", false, false},
|
|
|
|
// invalid systemd paths
|
|
{"o / m /../ g", true, true},
|
|
{"slice:kata", true, true},
|
|
{"/kata/afhts2e5d4g5s", true, true},
|
|
{"a:b:c:d", true, true},
|
|
{":::", true, true},
|
|
{"", true, true},
|
|
{":", true, true},
|
|
{"::", true, true},
|
|
{":::", true, true},
|
|
{"a:b", true, true},
|
|
{"a:b:", true, true},
|
|
{":a:b", true, true},
|
|
{"@:@:@", true, true},
|
|
|
|
// valid system paths
|
|
{"slice:kata:55555", true, false},
|
|
{"slice.system:kata:afhts2e5d4g5s", true, false},
|
|
} {
|
|
path, err := validCgroupPath(t.path, t.systemdCgroup)
|
|
if t.error {
|
|
assert.Error(err)
|
|
continue
|
|
} else {
|
|
assert.NoError(err)
|
|
}
|
|
|
|
if filepath.IsAbs(t.path) {
|
|
cleanPath := filepath.Dir(filepath.Clean(t.path))
|
|
assert.True(strings.HasPrefix(path, cleanPath),
|
|
"%v should have prefix %v", cleanPath)
|
|
} else if t.systemdCgroup {
|
|
assert.Equal(t.path, path)
|
|
} else {
|
|
assert.True(strings.HasPrefix(path, "/"+cgroupKataPrefix) ||
|
|
strings.HasPrefix(path, defaultCgroupPath),
|
|
"%v should have prefix /%v or %v", path, cgroupKataPrefix, defaultCgroupPath)
|
|
}
|
|
}
|
|
|
|
}
|