github.com/sameo/containerd@v0.2.8/integration-test/start_linux_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  	ctrs := make([]*ContainerProcess, totalCtr)
   383  
   384  	for i := 0; i < totalCtr; i++ {
   385  		containerID := fmt.Sprintf("top%d", i)
   386  		c, err := cs.StartContainer(containerID, bundleName)
   387  		if err != nil {
   388  			t.Fatal(err)
   389  		}
   390  
   391  		e := c.GetNextEvent()
   392  
   393  		t.Assert(*e, checker.Equals, types.Event{
   394  			Type:      "start-container",
   395  			Id:        containerID,
   396  			Status:    0,
   397  			Pid:       "",
   398  			Timestamp: e.Timestamp,
   399  		})
   400  		ctrs[i] = c
   401  	}
   402  
   403  	// restart daemon gracefully (SIGINT)
   404  	cs.RestartDaemon(false)
   405  
   406  	// check that status is running
   407  	containers, err := cs.ListRunningContainers()
   408  	if err != nil {
   409  		t.Fatal(err)
   410  	}
   411  	sortContainers(containers)
   412  	t.Assert(len(containers), checker.Equals, totalCtr)
   413  	for i := 0; i < totalCtr; i++ {
   414  		t.Assert(containers[i].Id, checker.Equals, fmt.Sprintf("top%d", i))
   415  		t.Assert(containers[i].Status, checker.Equals, "running")
   416  	}
   417  
   418  	// Check that we can exec see docker/docker#
   419  	execTarget := "top1"
   420  	echop, err := cs.AddProcessToContainer(ctrs[1], "echo", "/", []string{"PATH=/bin"}, []string{"sh", "-c", "echo -n Success!"}, 0, 0)
   421  	t.Assert(err, checker.Equals, nil)
   422  	for _, evt := range []types.Event{
   423  		{
   424  			Type:   "start-process",
   425  			Id:     execTarget,
   426  			Status: 0,
   427  			Pid:    "echo",
   428  		},
   429  		{
   430  			Type:   "exit",
   431  			Id:     execTarget,
   432  			Status: 0,
   433  			Pid:    "echo",
   434  		},
   435  	} {
   436  		ch := ctrs[1].GetEventsChannel()
   437  		e := <-ch
   438  		evt.Timestamp = e.Timestamp
   439  
   440  		t.Assert(*e, checker.Equals, evt)
   441  	}
   442  	t.Assert(echop.io.stdoutBuffer.String(), checker.Equals, "Success!")
   443  
   444  	// Now kill daemon (SIGKILL)
   445  	cs.StopDaemon(true)
   446  
   447  	// Sleep a second to allow the timestamp to change since
   448  	// it's second based
   449  	<-time.After(3 * time.Second)
   450  
   451  	// Kill a couple of containers
   452  	killedCtr := map[int]bool{4: true, 2: true}
   453  
   454  	var f func(*types.Event)
   455  	deathChans := make([]chan error, len(killedCtr))
   456  	deathChansIdx := 0
   457  
   458  	for i := range killedCtr {
   459  		ch := make(chan error, 1)
   460  		deathChans[deathChansIdx] = ch
   461  		deathChansIdx++
   462  		syscall.Kill(int(containers[i].Pids[0]), syscall.SIGKILL)
   463  
   464  		// Filter to be notified of their death
   465  		containerID := fmt.Sprintf("top%d", i)
   466  		f = func(event *types.Event) {
   467  			expectedEvent := types.Event{
   468  				Type:   "exit",
   469  				Id:     containerID,
   470  				Status: 137,
   471  				Pid:    "init",
   472  			}
   473  			expectedEvent.Timestamp = event.Timestamp
   474  			if ok := t.Check(*event, checker.Equals, expectedEvent); !ok {
   475  				ch <- fmt.Errorf("Unexpected event: %#v", *event)
   476  			} else {
   477  				ch <- nil
   478  			}
   479  		}
   480  		cs.SetContainerEventFilter(containerID, f)
   481  	}
   482  
   483  	cs.RestartDaemon(true)
   484  
   485  	// Ensure we got our events
   486  	for i := range deathChans {
   487  		done := false
   488  		for done == false {
   489  			select {
   490  			case err := <-deathChans[i]:
   491  				t.Assert(err, checker.Equals, nil)
   492  				done = true
   493  			case <-time.After(3 * time.Second):
   494  				t.Fatal("Exit event for container not received after 3 seconds")
   495  			}
   496  		}
   497  	}
   498  
   499  	// check that status is running
   500  	containers, err = cs.ListRunningContainers()
   501  	if err != nil {
   502  		t.Fatal(err)
   503  	}
   504  	sortContainers(containers)
   505  	t.Assert(len(containers), checker.Equals, totalCtr-len(killedCtr))
   506  	idShift := 0
   507  	for i := 0; i < totalCtr-len(killedCtr); i++ {
   508  		if _, ok := killedCtr[i+idShift]; ok {
   509  			idShift++
   510  		}
   511  		t.Assert(containers[i].Id, checker.Equals, fmt.Sprintf("top%d", i+idShift))
   512  		t.Assert(containers[i].Status, checker.Equals, "running")
   513  	}
   514  }
   515  
   516  func swapEnabled() bool {
   517  	_, err := os.Stat("/sys/fs/cgroup/memory/memory.memsw.limit_in_bytes")
   518  	return err == nil
   519  }
   520  
   521  func (cs *ContainerdSuite) TestSigkillShimReuseName(t *check.C) {
   522  	bundleName := "busybox-top"
   523  	if err := CreateBusyboxBundle(bundleName, []string{"top"}); err != nil {
   524  		t.Fatal(err)
   525  	}
   526  	containerID := "top"
   527  	c, err := cs.StartContainer(containerID, bundleName)
   528  	if err != nil {
   529  		t.Fatal(err)
   530  	}
   531  
   532  	// Sigkill the shim
   533  	exec.Command("pkill", "-9", "containerd-shim").Run()
   534  
   535  	// Wait for it to be reaped
   536  	for _, evt := range []types.Event{
   537  		{
   538  			Type:   "start-container",
   539  			Id:     containerID,
   540  			Status: 0,
   541  			Pid:    "",
   542  		},
   543  		{
   544  			Type:   "exit",
   545  			Id:     containerID,
   546  			Status: 128 + 9,
   547  			Pid:    "init",
   548  		},
   549  	} {
   550  		ch := c.GetEventsChannel()
   551  		select {
   552  		case e := <-ch:
   553  			evt.Timestamp = e.Timestamp
   554  
   555  			t.Assert(*e, checker.Equals, evt)
   556  		case <-time.After(2 * time.Second):
   557  			t.Fatal("Container took more than 2 seconds to terminate")
   558  		}
   559  	}
   560  
   561  	// Start a new continer with the same name
   562  	c, err = cs.StartContainer(containerID, bundleName)
   563  	if err != nil {
   564  		t.Fatal(err)
   565  	}
   566  }