github.com/dims/containerd@v0.2.5/integration-test/start_test.go (about)

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