mirror of
https://github.com/opencontainers/runc.git
synced 2026-07-10 21:53:57 +08:00
4415446c32
Signed-off-by: Michael Crosby <crosbymichael@gmail.com> Add state status() method Signed-off-by: Michael Crosby <crosbymichael@gmail.com> Allow multiple checkpoint on restore Signed-off-by: Michael Crosby <crosbymichael@gmail.com> Handle leave-running state Signed-off-by: Michael Crosby <crosbymichael@gmail.com> Fix state transitions for inprocess Because the tests use libcontainer in process between the various states we need to ensure that that usecase works as well as the out of process one. Signed-off-by: Michael Crosby <crosbymichael@gmail.com> Remove isDestroyed method Signed-off-by: Michael Crosby <crosbymichael@gmail.com> Handling Pausing from freezer state Signed-off-by: Rajasekaran <rajasec79@gmail.com> freezer status Signed-off-by: Rajasekaran <rajasec79@gmail.com> Fixing review comments Signed-off-by: Rajasekaran <rajasec79@gmail.com> Added comment when freezer not available Signed-off-by: Rajasekaran <rajasec79@gmail.com> Signed-off-by: Michael Crosby <crosbymichael@gmail.com> Conflicts: libcontainer/container_linux.go Change checkFreezer logic to isPaused() Signed-off-by: Michael Crosby <crosbymichael@gmail.com> Remove state base and factor out destroy func Signed-off-by: Michael Crosby <crosbymichael@gmail.com> Add unit test for state transitions Signed-off-by: Michael Crosby <crosbymichael@gmail.com>
214 lines
4.6 KiB
Go
214 lines
4.6 KiB
Go
// +build linux
|
|
|
|
package libcontainer
|
|
|
|
import (
|
|
"fmt"
|
|
"os"
|
|
"testing"
|
|
|
|
"github.com/opencontainers/runc/libcontainer/cgroups"
|
|
"github.com/opencontainers/runc/libcontainer/configs"
|
|
)
|
|
|
|
type mockCgroupManager struct {
|
|
pids []int
|
|
stats *cgroups.Stats
|
|
paths map[string]string
|
|
}
|
|
|
|
func (m *mockCgroupManager) GetPids() ([]int, error) {
|
|
return m.pids, nil
|
|
}
|
|
|
|
func (m *mockCgroupManager) GetStats() (*cgroups.Stats, error) {
|
|
return m.stats, nil
|
|
}
|
|
|
|
func (m *mockCgroupManager) Apply(pid int) error {
|
|
return nil
|
|
}
|
|
|
|
func (m *mockCgroupManager) Set(container *configs.Config) error {
|
|
return nil
|
|
}
|
|
|
|
func (m *mockCgroupManager) Destroy() error {
|
|
return nil
|
|
}
|
|
|
|
func (m *mockCgroupManager) GetPaths() map[string]string {
|
|
return m.paths
|
|
}
|
|
|
|
func (m *mockCgroupManager) Freeze(state configs.FreezerState) error {
|
|
return nil
|
|
}
|
|
|
|
type mockProcess struct {
|
|
_pid int
|
|
started string
|
|
}
|
|
|
|
func (m *mockProcess) terminate() error {
|
|
return nil
|
|
}
|
|
|
|
func (m *mockProcess) pid() int {
|
|
return m._pid
|
|
}
|
|
|
|
func (m *mockProcess) startTime() (string, error) {
|
|
return m.started, nil
|
|
}
|
|
|
|
func (m *mockProcess) start() error {
|
|
return nil
|
|
}
|
|
|
|
func (m *mockProcess) wait() (*os.ProcessState, error) {
|
|
return nil, nil
|
|
}
|
|
|
|
func (m *mockProcess) signal(_ os.Signal) error {
|
|
return nil
|
|
}
|
|
|
|
func (p *mockProcess) externalDescriptors() []string {
|
|
return []string{}
|
|
}
|
|
|
|
func (p *mockProcess) setExternalDescriptors(newFds []string) {
|
|
}
|
|
|
|
func TestGetContainerPids(t *testing.T) {
|
|
container := &linuxContainer{
|
|
id: "myid",
|
|
config: &configs.Config{},
|
|
cgroupManager: &mockCgroupManager{pids: []int{1, 2, 3}},
|
|
}
|
|
pids, err := container.Processes()
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
for i, expected := range []int{1, 2, 3} {
|
|
if pids[i] != expected {
|
|
t.Fatalf("expected pid %d but received %d", expected, pids[i])
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestGetContainerStats(t *testing.T) {
|
|
container := &linuxContainer{
|
|
id: "myid",
|
|
config: &configs.Config{},
|
|
cgroupManager: &mockCgroupManager{
|
|
pids: []int{1, 2, 3},
|
|
stats: &cgroups.Stats{
|
|
MemoryStats: cgroups.MemoryStats{
|
|
Usage: cgroups.MemoryData{
|
|
Usage: 1024,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
stats, err := container.Stats()
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if stats.CgroupStats == nil {
|
|
t.Fatal("cgroup stats are nil")
|
|
}
|
|
if stats.CgroupStats.MemoryStats.Usage.Usage != 1024 {
|
|
t.Fatalf("expected memory usage 1024 but recevied %d", stats.CgroupStats.MemoryStats.Usage.Usage)
|
|
}
|
|
}
|
|
|
|
func TestGetContainerState(t *testing.T) {
|
|
var (
|
|
pid = os.Getpid()
|
|
expectedMemoryPath = "/sys/fs/cgroup/memory/myid"
|
|
expectedNetworkPath = "/networks/fd"
|
|
)
|
|
container := &linuxContainer{
|
|
id: "myid",
|
|
config: &configs.Config{
|
|
Namespaces: []configs.Namespace{
|
|
{Type: configs.NEWPID},
|
|
{Type: configs.NEWNS},
|
|
{Type: configs.NEWNET, Path: expectedNetworkPath},
|
|
{Type: configs.NEWUTS},
|
|
// emulate host for IPC
|
|
//{Type: configs.NEWIPC},
|
|
},
|
|
},
|
|
initProcess: &mockProcess{
|
|
_pid: pid,
|
|
started: "010",
|
|
},
|
|
cgroupManager: &mockCgroupManager{
|
|
pids: []int{1, 2, 3},
|
|
stats: &cgroups.Stats{
|
|
MemoryStats: cgroups.MemoryStats{
|
|
Usage: cgroups.MemoryData{
|
|
Usage: 1024,
|
|
},
|
|
},
|
|
},
|
|
paths: map[string]string{
|
|
"memory": expectedMemoryPath,
|
|
},
|
|
},
|
|
}
|
|
container.state = &nullState{c: container}
|
|
state, err := container.State()
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if state.InitProcessPid != pid {
|
|
t.Fatalf("expected pid %d but received %d", pid, state.InitProcessPid)
|
|
}
|
|
if state.InitProcessStartTime != "010" {
|
|
t.Fatalf("expected process start time 010 but received %s", state.InitProcessStartTime)
|
|
}
|
|
paths := state.CgroupPaths
|
|
if paths == nil {
|
|
t.Fatal("cgroup paths should not be nil")
|
|
}
|
|
if memPath := paths["memory"]; memPath != expectedMemoryPath {
|
|
t.Fatalf("expected memory path %q but received %q", expectedMemoryPath, memPath)
|
|
}
|
|
for _, ns := range container.config.Namespaces {
|
|
path := state.NamespacePaths[ns.Type]
|
|
if path == "" {
|
|
t.Fatalf("expected non nil namespace path for %s", ns.Type)
|
|
}
|
|
if ns.Type == configs.NEWNET {
|
|
if path != expectedNetworkPath {
|
|
t.Fatalf("expected path %q but received %q", expectedNetworkPath, path)
|
|
}
|
|
} else {
|
|
file := ""
|
|
switch ns.Type {
|
|
case configs.NEWNET:
|
|
file = "net"
|
|
case configs.NEWNS:
|
|
file = "mnt"
|
|
case configs.NEWPID:
|
|
file = "pid"
|
|
case configs.NEWIPC:
|
|
file = "ipc"
|
|
case configs.NEWUSER:
|
|
file = "user"
|
|
case configs.NEWUTS:
|
|
file = "uts"
|
|
}
|
|
expected := fmt.Sprintf("/proc/%d/ns/%s", pid, file)
|
|
if expected != path {
|
|
t.Fatalf("expected path %q but received %q", expected, path)
|
|
}
|
|
}
|
|
}
|
|
}
|