...

Source file src/github.com/opencontainers/runc/libcontainer/container_linux_test.go

Documentation: github.com/opencontainers/runc/libcontainer

     1  package libcontainer
     2  
     3  import (
     4  	"fmt"
     5  	"os"
     6  	"testing"
     7  
     8  	"github.com/opencontainers/runc/libcontainer/cgroups"
     9  	"github.com/opencontainers/runc/libcontainer/configs"
    10  	"github.com/opencontainers/runc/libcontainer/system"
    11  )
    12  
    13  type mockCgroupManager struct {
    14  	pids    []int
    15  	allPids []int
    16  	paths   map[string]string
    17  }
    18  
    19  func (m *mockCgroupManager) GetPids() ([]int, error) {
    20  	return m.pids, nil
    21  }
    22  
    23  func (m *mockCgroupManager) GetAllPids() ([]int, error) {
    24  	return m.allPids, nil
    25  }
    26  
    27  func (m *mockCgroupManager) GetStats() (*cgroups.Stats, error) {
    28  	return nil, nil
    29  }
    30  
    31  func (m *mockCgroupManager) Apply(pid int) error {
    32  	return nil
    33  }
    34  
    35  func (m *mockCgroupManager) Set(_ *configs.Resources) error {
    36  	return nil
    37  }
    38  
    39  func (m *mockCgroupManager) Destroy() error {
    40  	return nil
    41  }
    42  
    43  func (m *mockCgroupManager) Exists() bool {
    44  	_, err := os.Lstat(m.Path("devices"))
    45  	return err == nil
    46  }
    47  
    48  func (m *mockCgroupManager) OOMKillCount() (uint64, error) {
    49  	return 0, nil
    50  }
    51  
    52  func (m *mockCgroupManager) GetPaths() map[string]string {
    53  	return m.paths
    54  }
    55  
    56  func (m *mockCgroupManager) Path(subsys string) string {
    57  	return m.paths[subsys]
    58  }
    59  
    60  func (m *mockCgroupManager) Freeze(state configs.FreezerState) error {
    61  	return nil
    62  }
    63  
    64  func (m *mockCgroupManager) GetCgroups() (*configs.Cgroup, error) {
    65  	return nil, nil
    66  }
    67  
    68  func (m *mockCgroupManager) GetFreezerState() (configs.FreezerState, error) {
    69  	return configs.Thawed, nil
    70  }
    71  
    72  type mockProcess struct {
    73  	_pid    int
    74  	started uint64
    75  }
    76  
    77  func (m *mockProcess) terminate() error {
    78  	return nil
    79  }
    80  
    81  func (m *mockProcess) pid() int {
    82  	return m._pid
    83  }
    84  
    85  func (m *mockProcess) startTime() (uint64, error) {
    86  	return m.started, nil
    87  }
    88  
    89  func (m *mockProcess) start() error {
    90  	return nil
    91  }
    92  
    93  func (m *mockProcess) wait() (*os.ProcessState, error) {
    94  	return nil, nil
    95  }
    96  
    97  func (m *mockProcess) signal(_ os.Signal) error {
    98  	return nil
    99  }
   100  
   101  func (m *mockProcess) externalDescriptors() []string {
   102  	return []string{}
   103  }
   104  
   105  func (m *mockProcess) setExternalDescriptors(newFds []string) {
   106  }
   107  
   108  func (m *mockProcess) forwardChildLogs() chan error {
   109  	return nil
   110  }
   111  
   112  func TestGetContainerPids(t *testing.T) {
   113  	pid := 1
   114  	stat, err := system.Stat(pid)
   115  	if err != nil {
   116  		t.Fatalf("can't stat pid %d, got %v", pid, err)
   117  	}
   118  	container := &linuxContainer{
   119  		id:     "myid",
   120  		config: &configs.Config{},
   121  		cgroupManager: &mockCgroupManager{
   122  			allPids: []int{1, 2, 3},
   123  			paths: map[string]string{
   124  				"device": "/proc/self/cgroups",
   125  			},
   126  		},
   127  		initProcess: &mockProcess{
   128  			_pid:    1,
   129  			started: 10,
   130  		},
   131  		initProcessStartTime: stat.StartTime,
   132  	}
   133  	container.state = &runningState{c: container}
   134  	pids, err := container.Processes()
   135  	if err != nil {
   136  		t.Fatal(err)
   137  	}
   138  	for i, expected := range []int{1, 2, 3} {
   139  		if pids[i] != expected {
   140  			t.Fatalf("expected pid %d but received %d", expected, pids[i])
   141  		}
   142  	}
   143  }
   144  
   145  func TestGetContainerState(t *testing.T) {
   146  	var (
   147  		pid                 = os.Getpid()
   148  		expectedMemoryPath  = "/sys/fs/cgroup/memory/myid"
   149  		expectedNetworkPath = fmt.Sprintf("/proc/%d/ns/net", pid)
   150  	)
   151  	container := &linuxContainer{
   152  		id: "myid",
   153  		config: &configs.Config{
   154  			Namespaces: []configs.Namespace{
   155  				{Type: configs.NEWPID},
   156  				{Type: configs.NEWNS},
   157  				{Type: configs.NEWNET, Path: expectedNetworkPath},
   158  				{Type: configs.NEWUTS},
   159  				// emulate host for IPC
   160  				//{Type: configs.NEWIPC},
   161  				{Type: configs.NEWCGROUP},
   162  			},
   163  		},
   164  		initProcess: &mockProcess{
   165  			_pid:    pid,
   166  			started: 10,
   167  		},
   168  		cgroupManager: &mockCgroupManager{
   169  			pids: []int{1, 2, 3},
   170  			paths: map[string]string{
   171  				"memory": expectedMemoryPath,
   172  			},
   173  		},
   174  	}
   175  	container.state = &createdState{c: container}
   176  	state, err := container.State()
   177  	if err != nil {
   178  		t.Fatal(err)
   179  	}
   180  	if state.InitProcessPid != pid {
   181  		t.Fatalf("expected pid %d but received %d", pid, state.InitProcessPid)
   182  	}
   183  	if state.InitProcessStartTime != 10 {
   184  		t.Fatalf("expected process start time 10 but received %d", state.InitProcessStartTime)
   185  	}
   186  	paths := state.CgroupPaths
   187  	if paths == nil {
   188  		t.Fatal("cgroup paths should not be nil")
   189  	}
   190  	if memPath := paths["memory"]; memPath != expectedMemoryPath {
   191  		t.Fatalf("expected memory path %q but received %q", expectedMemoryPath, memPath)
   192  	}
   193  	for _, ns := range container.config.Namespaces {
   194  		path := state.NamespacePaths[ns.Type]
   195  		if path == "" {
   196  			t.Fatalf("expected non nil namespace path for %s", ns.Type)
   197  		}
   198  		if ns.Type == configs.NEWNET {
   199  			if path != expectedNetworkPath {
   200  				t.Fatalf("expected path %q but received %q", expectedNetworkPath, path)
   201  			}
   202  		} else {
   203  			file := ""
   204  			switch ns.Type {
   205  			case configs.NEWNET:
   206  				file = "net"
   207  			case configs.NEWNS:
   208  				file = "mnt"
   209  			case configs.NEWPID:
   210  				file = "pid"
   211  			case configs.NEWIPC:
   212  				file = "ipc"
   213  			case configs.NEWUSER:
   214  				file = "user"
   215  			case configs.NEWUTS:
   216  				file = "uts"
   217  			case configs.NEWCGROUP:
   218  				file = "cgroup"
   219  			}
   220  			expected := fmt.Sprintf("/proc/%d/ns/%s", pid, file)
   221  			if expected != path {
   222  				t.Fatalf("expected path %q but received %q", expected, path)
   223  			}
   224  		}
   225  	}
   226  }
   227  
   228  func TestGetContainerStateAfterUpdate(t *testing.T) {
   229  	pid := os.Getpid()
   230  	stat, err := system.Stat(pid)
   231  	if err != nil {
   232  		t.Fatal(err)
   233  	}
   234  
   235  	container := &linuxContainer{
   236  		root: t.TempDir(),
   237  		id:   "myid",
   238  		config: &configs.Config{
   239  			Namespaces: []configs.Namespace{
   240  				{Type: configs.NEWPID},
   241  				{Type: configs.NEWNS},
   242  				{Type: configs.NEWNET},
   243  				{Type: configs.NEWUTS},
   244  				{Type: configs.NEWIPC},
   245  			},
   246  			Cgroups: &configs.Cgroup{
   247  				Resources: &configs.Resources{
   248  					Memory: 1024,
   249  				},
   250  			},
   251  		},
   252  		initProcess: &mockProcess{
   253  			_pid:    pid,
   254  			started: stat.StartTime,
   255  		},
   256  		cgroupManager: &mockCgroupManager{},
   257  	}
   258  	container.state = &createdState{c: container}
   259  	state, err := container.State()
   260  	if err != nil {
   261  		t.Fatal(err)
   262  	}
   263  	if state.InitProcessPid != pid {
   264  		t.Fatalf("expected pid %d but received %d", pid, state.InitProcessPid)
   265  	}
   266  	if state.InitProcessStartTime != stat.StartTime {
   267  		t.Fatalf("expected process start time %d but received %d", stat.StartTime, state.InitProcessStartTime)
   268  	}
   269  	if state.Config.Cgroups.Resources.Memory != 1024 {
   270  		t.Fatalf("expected Memory to be 1024 but received %q", state.Config.Cgroups.Memory)
   271  	}
   272  
   273  	// Set initProcessStartTime so we fake to be running
   274  	container.initProcessStartTime = state.InitProcessStartTime
   275  	container.state = &runningState{c: container}
   276  	newConfig := container.Config()
   277  	newConfig.Cgroups.Resources.Memory = 2048
   278  	if err := container.Set(newConfig); err != nil {
   279  		t.Fatal(err)
   280  	}
   281  	state, err = container.State()
   282  	if err != nil {
   283  		t.Fatal(err)
   284  	}
   285  	if state.Config.Cgroups.Resources.Memory != 2048 {
   286  		t.Fatalf("expected Memory to be 2048 but received %q", state.Config.Cgroups.Memory)
   287  	}
   288  }
   289  

View as plain text