github.com/runcom/containerd@v0.0.0-20160708090337-9bff9f934c0d/integration-test/start_test.go (about)

     1  package main
     2  
     3  import (
     4  	"fmt"
     5  	"os"
     6  	"path/filepath"
     7  	"syscall"
     8  	"time"
     9  
    10  	"github.com/docker/containerd/api/grpc/types"
    11  	"github.com/docker/docker/pkg/integration/checker"
    12  	"github.com/go-check/check"
    13  	ocs "github.com/opencontainers/runtime-spec/specs-go"
    14  	"google.golang.org/grpc"
    15  )
    16  
    17  func (cs *ContainerdSuite) TestStartBusyboxLsSlash(t *check.C) {
    18  	expectedOutput := `bin
    19  dev
    20  etc
    21  home
    22  lib
    23  lib64
    24  linuxrc
    25  media
    26  mnt
    27  opt
    28  proc
    29  root
    30  run
    31  sbin
    32  sys
    33  tmp
    34  usr
    35  var
    36  `
    37  	if err := CreateBusyboxBundle("busybox-ls-slash", []string{"ls", "/"}); err != nil {
    38  		t.Fatal(err)
    39  	}
    40  
    41  	c, err := cs.RunContainer("myls", "busybox-ls-slash")
    42  	if err != nil {
    43  		t.Fatal(err)
    44  	}
    45  
    46  	t.Assert(c.io.stdoutBuffer.String(), checker.Equals, expectedOutput)
    47  }
    48  
    49  func (cs *ContainerdSuite) TestStartBusyboxNoSuchFile(t *check.C) {
    50  	expectedOutput := `oci runtime error: exec: "NoSuchFile": executable file not found in $PATH`
    51  
    52  	if err := CreateBusyboxBundle("busybox-no-such-file", []string{"NoSuchFile"}); err != nil {
    53  		t.Fatal(err)
    54  	}
    55  
    56  	_, err := cs.RunContainer("NoSuchFile", "busybox-no-such-file")
    57  	t.Assert(grpc.ErrorDesc(err), checker.Contains, expectedOutput)
    58  }
    59  
    60  func (cs *ContainerdSuite) TestStartBusyboxTop(t *check.C) {
    61  	bundleName := "busybox-top"
    62  	if err := CreateBusyboxBundle(bundleName, []string{"top"}); err != nil {
    63  		t.Fatal(err)
    64  	}
    65  
    66  	containerID := "start-busybox-top"
    67  	_, err := cs.StartContainer(containerID, bundleName)
    68  	t.Assert(err, checker.Equals, nil)
    69  
    70  	containers, err := cs.ListRunningContainers()
    71  	if err != nil {
    72  		t.Fatal(err)
    73  	}
    74  	t.Assert(len(containers), checker.Equals, 1)
    75  	t.Assert(containers[0].Id, checker.Equals, containerID)
    76  	t.Assert(containers[0].Status, checker.Equals, "running")
    77  	t.Assert(containers[0].BundlePath, check.Equals, filepath.Join(cs.cwd, GetBundle(bundleName).Path))
    78  }
    79  
    80  func (cs *ContainerdSuite) TestStartBusyboxLsEvents(t *check.C) {
    81  	if err := CreateBusyboxBundle("busybox-ls", []string{"ls"}); err != nil {
    82  		t.Fatal(err)
    83  	}
    84  
    85  	containerID := "ls-events"
    86  	c, err := cs.StartContainer(containerID, "busybox-ls")
    87  	if err != nil {
    88  		t.Fatal(err)
    89  	}
    90  
    91  	for _, evt := range []types.Event{
    92  		{
    93  			Type:   "start-container",
    94  			Id:     containerID,
    95  			Status: 0,
    96  			Pid:    "",
    97  		},
    98  		{
    99  			Type:   "exit",
   100  			Id:     containerID,
   101  			Status: 0,
   102  			Pid:    "init",
   103  		},
   104  	} {
   105  		ch := c.GetEventsChannel()
   106  		select {
   107  		case e := <-ch:
   108  			evt.Timestamp = e.Timestamp
   109  
   110  			t.Assert(*e, checker.Equals, evt)
   111  		case <-time.After(2 * time.Second):
   112  			t.Fatal("Container took more than 2 seconds to terminate")
   113  		}
   114  	}
   115  }
   116  
   117  func (cs *ContainerdSuite) TestStartBusyboxSleep(t *check.C) {
   118  	if err := CreateBusyboxBundle("busybox-sleep-5", []string{"sleep", "5"}); err != nil {
   119  		t.Fatal(err)
   120  	}
   121  
   122  	ch := make(chan interface{})
   123  	filter := func(e *types.Event) {
   124  		if e.Type == "exit" && e.Pid == "init" {
   125  			ch <- nil
   126  		}
   127  	}
   128  
   129  	start := time.Now()
   130  	_, err := cs.StartContainerWithEventFilter("sleep5", "busybox-sleep-5", filter)
   131  	if err != nil {
   132  		t.Fatal(err)
   133  	}
   134  
   135  	// We add a generous 20% marge of error
   136  	select {
   137  	case <-ch:
   138  		t.Assert(uint64(time.Now().Sub(start)), checker.LessOrEqualThan, uint64(6*time.Second))
   139  	case <-time.After(6 * time.Second):
   140  		t.Fatal("Container took more than 6 seconds to exit")
   141  	}
   142  }
   143  
   144  func (cs *ContainerdSuite) TestStartBusyboxTopKill(t *check.C) {
   145  	bundleName := "busybox-top"
   146  	if err := CreateBusyboxBundle(bundleName, []string{"top"}); err != nil {
   147  		t.Fatal(err)
   148  	}
   149  
   150  	containerID := "top-kill"
   151  	c, err := cs.StartContainer(containerID, bundleName)
   152  	if err != nil {
   153  		t.Fatal(err)
   154  	}
   155  
   156  	<-time.After(1 * time.Second)
   157  
   158  	err = cs.KillContainer(containerID)
   159  	if err != nil {
   160  		t.Fatal(err)
   161  	}
   162  
   163  	for _, evt := range []types.Event{
   164  		{
   165  			Type:   "start-container",
   166  			Id:     containerID,
   167  			Status: 0,
   168  			Pid:    "",
   169  		},
   170  		{
   171  			Type:   "exit",
   172  			Id:     containerID,
   173  			Status: 128 + uint32(syscall.SIGKILL),
   174  			Pid:    "init",
   175  		},
   176  	} {
   177  		ch := c.GetEventsChannel()
   178  		select {
   179  		case e := <-ch:
   180  			evt.Timestamp = e.Timestamp
   181  
   182  			t.Assert(*e, checker.Equals, evt)
   183  		case <-time.After(2 * time.Second):
   184  			t.Fatal("Container took more than 2 seconds to terminate")
   185  		}
   186  	}
   187  }
   188  
   189  func (cs *ContainerdSuite) TestStartBusyboxTopSignalSigterm(t *check.C) {
   190  	bundleName := "busybox-top"
   191  	if err := CreateBusyboxBundle(bundleName, []string{"top"}); err != nil {
   192  		t.Fatal(err)
   193  	}
   194  
   195  	containerID := "top-sigterm"
   196  	c, err := cs.StartContainer(containerID, bundleName)
   197  	if err != nil {
   198  		t.Fatal(err)
   199  	}
   200  
   201  	<-time.After(1 * time.Second)
   202  
   203  	err = cs.SignalContainer(containerID, uint32(syscall.SIGTERM))
   204  	if err != nil {
   205  		t.Fatal(err)
   206  	}
   207  
   208  	for _, evt := range []types.Event{
   209  		{
   210  			Type:   "start-container",
   211  			Id:     containerID,
   212  			Status: 0,
   213  			Pid:    "",
   214  		},
   215  		{
   216  			Type:   "exit",
   217  			Id:     containerID,
   218  			Status: 128 + uint32(syscall.SIGTERM),
   219  			Pid:    "init",
   220  		},
   221  	} {
   222  		ch := c.GetEventsChannel()
   223  		select {
   224  		case e := <-ch:
   225  			evt.Timestamp = e.Timestamp
   226  
   227  			t.Assert(*e, checker.Equals, evt)
   228  		case <-time.After(2 * time.Second):
   229  			t.Fatal("Container took more than 2 seconds to terminate")
   230  		}
   231  	}
   232  }
   233  
   234  func (cs *ContainerdSuite) TestStartBusyboxTrapUSR1(t *check.C) {
   235  	if err := CreateBusyboxBundle("busybox-trap-usr1", []string{"sh", "-c", "trap 'echo -n booh!' SIGUSR1 ; sleep 60  &  wait"}); err != nil {
   236  		t.Fatal(err)
   237  	}
   238  
   239  	containerID := "trap-usr1"
   240  	c, err := cs.StartContainer(containerID, "busybox-trap-usr1")
   241  	if err != nil {
   242  		t.Fatal(err)
   243  	}
   244  
   245  	<-time.After(1 * time.Second)
   246  
   247  	if err := cs.SignalContainer(containerID, uint32(syscall.SIGUSR1)); err != nil {
   248  		t.Fatal(err)
   249  	}
   250  
   251  	for {
   252  		e := c.GetNextEvent()
   253  		if e.Type == "exit" && e.Pid == "init" {
   254  			break
   255  		}
   256  	}
   257  
   258  	t.Assert(c.io.stdoutBuffer.String(), checker.Equals, "booh!")
   259  }
   260  
   261  func (cs *ContainerdSuite) TestStartBusyboxTopPauseResume(t *check.C) {
   262  	bundleName := "busybox-top"
   263  	if err := CreateBusyboxBundle(bundleName, []string{"top"}); err != nil {
   264  		t.Fatal(err)
   265  	}
   266  
   267  	containerID := "top-pause-resume"
   268  	c, err := cs.StartContainer(containerID, bundleName)
   269  	if err != nil {
   270  		t.Fatal(err)
   271  	}
   272  
   273  	if err := cs.PauseContainer(containerID); err != nil {
   274  		t.Fatal(err)
   275  	}
   276  
   277  	if err := cs.ResumeContainer(containerID); err != nil {
   278  		t.Fatal(err)
   279  	}
   280  
   281  	for _, evt := range []types.Event{
   282  		{
   283  			Type:   "start-container",
   284  			Id:     containerID,
   285  			Status: 0,
   286  			Pid:    "",
   287  		},
   288  		{
   289  			Type:   "pause",
   290  			Id:     containerID,
   291  			Status: 0,
   292  			Pid:    "",
   293  		},
   294  		{
   295  			Type:   "resume",
   296  			Id:     containerID,
   297  			Status: 0,
   298  			Pid:    "",
   299  		},
   300  	} {
   301  		ch := c.GetEventsChannel()
   302  		select {
   303  		case e := <-ch:
   304  			evt.Timestamp = e.Timestamp
   305  
   306  			t.Assert(*e, checker.Equals, evt)
   307  		case <-time.After(2 * time.Second):
   308  			t.Fatal("Container took more than 2 seconds to terminate")
   309  		}
   310  	}
   311  
   312  	// check that status is running
   313  	containers, err := cs.ListRunningContainers()
   314  	if err != nil {
   315  		t.Fatal(err)
   316  	}
   317  	t.Assert(len(containers), checker.Equals, 1)
   318  	t.Assert(containers[0].Id, checker.Equals, containerID)
   319  	t.Assert(containers[0].Status, checker.Equals, "running")
   320  }
   321  
   322  func (cs *ContainerdSuite) TestOOM(t *check.C) {
   323  	bundleName := "busybox-sh-512k-memlimit"
   324  	if err := CreateBundleWithFilter("busybox", bundleName, []string{"sh", "-c", "x=oom-party-time; while true; do x=$x$x$x$x$x$x$x$x$x$x; done"}, func(spec *ocs.Spec) {
   325  		// Limit to 512k for quick oom
   326  		var limit uint64 = 8 * 1024 * 1024
   327  		spec.Linux.Resources.Memory = &ocs.Memory{
   328  			Limit: &limit,
   329  		}
   330  		if swapEnabled() {
   331  			spec.Linux.Resources.Memory.Swap = &limit
   332  		}
   333  	}); err != nil {
   334  		t.Fatal(err)
   335  	}
   336  
   337  	containerID := "sh-oom"
   338  	c, err := cs.StartContainer(containerID, bundleName)
   339  	if err != nil {
   340  		t.Fatal(err)
   341  	}
   342  
   343  	for _, evt := range []types.Event{
   344  		{
   345  			Type:   "start-container",
   346  			Id:     containerID,
   347  			Status: 0,
   348  			Pid:    "",
   349  		},
   350  		{
   351  			Type:   "oom",
   352  			Id:     containerID,
   353  			Status: 0,
   354  			Pid:    "",
   355  		},
   356  		{
   357  			Type:   "exit",
   358  			Id:     containerID,
   359  			Status: 137,
   360  			Pid:    "init",
   361  		},
   362  	} {
   363  		ch := c.GetEventsChannel()
   364  		select {
   365  		case e := <-ch:
   366  			evt.Timestamp = e.Timestamp
   367  			t.Assert(*e, checker.Equals, evt)
   368  		case <-time.After(60 * time.Second):
   369  			t.Fatalf("Container took more than 60 seconds to %s", evt.Type)
   370  		}
   371  	}
   372  }
   373  
   374  func (cs *ContainerdSuite) TestRestart(t *check.C) {
   375  	bundleName := "busybox-top"
   376  	if err := CreateBusyboxBundle(bundleName, []string{"top"}); err != nil {
   377  		t.Fatal(err)
   378  	}
   379  
   380  	totalCtr := 10
   381  
   382  	for i := 0; i < totalCtr; i++ {
   383  		containerID := fmt.Sprintf("top%d", i)
   384  		c, err := cs.StartContainer(containerID, bundleName)
   385  		if err != nil {
   386  			t.Fatal(err)
   387  		}
   388  
   389  		e := c.GetNextEvent()
   390  
   391  		t.Assert(*e, checker.Equals, types.Event{
   392  			Type:      "start-container",
   393  			Id:        containerID,
   394  			Status:    0,
   395  			Pid:       "",
   396  			Timestamp: e.Timestamp,
   397  		})
   398  	}
   399  
   400  	// restart daemon gracefully (SIGINT)
   401  	cs.RestartDaemon(false)
   402  
   403  	// check that status is running
   404  	containers, err := cs.ListRunningContainers()
   405  	if err != nil {
   406  		t.Fatal(err)
   407  	}
   408  	sortContainers(containers)
   409  	t.Assert(len(containers), checker.Equals, totalCtr)
   410  	for i := 0; i < totalCtr; i++ {
   411  		t.Assert(containers[i].Id, checker.Equals, fmt.Sprintf("top%d", i))
   412  		t.Assert(containers[i].Status, checker.Equals, "running")
   413  	}
   414  
   415  	// Now kill daemon (SIGKILL)
   416  	cs.StopDaemon(true)
   417  
   418  	// Sleep a second to allow thevent e timestamp to change since
   419  	// it's second based
   420  	<-time.After(3 * time.Second)
   421  
   422  	// Kill a couple of containers
   423  	killedCtr := map[int]bool{4: true, 2: true}
   424  
   425  	var f func(*types.Event)
   426  	deathChans := make([]chan error, len(killedCtr))
   427  	deathChansIdx := 0
   428  
   429  	for i := range killedCtr {
   430  		ch := make(chan error, 1)
   431  		deathChans[deathChansIdx] = ch
   432  		deathChansIdx++
   433  		syscall.Kill(int(containers[i].Pids[0]), syscall.SIGKILL)
   434  
   435  		// Filter to be notified of their death
   436  		containerID := fmt.Sprintf("top%d", i)
   437  		f = func(event *types.Event) {
   438  			expectedEvent := types.Event{
   439  				Type:   "exit",
   440  				Id:     containerID,
   441  				Status: 137,
   442  				Pid:    "init",
   443  			}
   444  			expectedEvent.Timestamp = event.Timestamp
   445  			if ok := t.Check(*event, checker.Equals, expectedEvent); !ok {
   446  				ch <- fmt.Errorf("Unexpected event: %#v", *event)
   447  			} else {
   448  				ch <- nil
   449  			}
   450  		}
   451  		cs.SetContainerEventFilter(containerID, f)
   452  	}
   453  
   454  	cs.RestartDaemon(true)
   455  
   456  	// Ensure we got our events
   457  	for i := range deathChans {
   458  		done := false
   459  		for done == false {
   460  			select {
   461  			case err := <-deathChans[i]:
   462  				t.Assert(err, checker.Equals, nil)
   463  				done = true
   464  			case <-time.After(3 * time.Second):
   465  				t.Fatal("Exit event for container not received after 3 seconds")
   466  			}
   467  		}
   468  	}
   469  
   470  	// check that status is running
   471  	containers, err = cs.ListRunningContainers()
   472  	if err != nil {
   473  		t.Fatal(err)
   474  	}
   475  	sortContainers(containers)
   476  	t.Assert(len(containers), checker.Equals, totalCtr-len(killedCtr))
   477  	idShift := 0
   478  	for i := 0; i < totalCtr-len(killedCtr); i++ {
   479  		if _, ok := killedCtr[i+idShift]; ok {
   480  			idShift++
   481  		}
   482  		t.Assert(containers[i].Id, checker.Equals, fmt.Sprintf("top%d", i+idShift))
   483  		t.Assert(containers[i].Status, checker.Equals, "running")
   484  	}
   485  }
   486  
   487  func swapEnabled() bool {
   488  	_, err := os.Stat("/sys/fs/cgroup/memory/memory.memsw.limit_in_bytes")
   489  	return err == nil
   490  }