Files
kata-containers/virtcontainers/cgroups_test.go
Julio Montes 9949daf4dc virtcontainers: move validCgroupPath
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>
2020-01-15 19:03:36 +00:00

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