github.com/docker/containerd@v0.2.9-0.20170509230648-8ef7df579710/integration-test/container_utils_test.go (about)

     1  package main
     2  
     3  import (
     4  	"bytes"
     5  	"fmt"
     6  	"io"
     7  	"io/ioutil"
     8  	"os"
     9  	"path/filepath"
    10  	"sort"
    11  	"syscall"
    12  	"time"
    13  
    14  	"github.com/containerd/containerd/api/grpc/types"
    15  	"github.com/golang/protobuf/ptypes"
    16  	"github.com/golang/protobuf/ptypes/timestamp"
    17  	"golang.org/x/net/context"
    18  	"golang.org/x/sys/unix"
    19  )
    20  
    21  func (cs *ContainerdSuite) GetLogs() string {
    22  	b, _ := ioutil.ReadFile(cs.logFile.Name())
    23  	return string(b)
    24  }
    25  
    26  func (cs *ContainerdSuite) Events(from time.Time, storedOnly bool, id string) (types.API_EventsClient, error) {
    27  	var (
    28  		ftsp *timestamp.Timestamp
    29  		err  error
    30  	)
    31  	if !from.IsZero() {
    32  		ftsp, err = ptypes.TimestampProto(from)
    33  		if err != nil {
    34  			return nil, err
    35  		}
    36  	}
    37  
    38  	return cs.grpcClient.Events(context.Background(), &types.EventsRequest{Timestamp: ftsp, StoredOnly: storedOnly, Id: id})
    39  }
    40  
    41  func (cs *ContainerdSuite) ListRunningContainers() ([]*types.Container, error) {
    42  	resp, err := cs.grpcClient.State(context.Background(), &types.StateRequest{})
    43  	if err != nil {
    44  		return nil, err
    45  	}
    46  	return resp.Containers, nil
    47  }
    48  
    49  func (cs *ContainerdSuite) SignalContainerProcess(id string, procID string, sig uint32) error {
    50  	_, err := cs.grpcClient.Signal(context.Background(), &types.SignalRequest{
    51  		Id:     id,
    52  		Pid:    procID,
    53  		Signal: sig,
    54  	})
    55  	return err
    56  }
    57  
    58  func (cs *ContainerdSuite) SignalContainer(id string, sig uint32) error {
    59  	return cs.SignalContainerProcess(id, "init", sig)
    60  }
    61  
    62  func (cs *ContainerdSuite) KillContainer(id string) error {
    63  	return cs.SignalContainerProcess(id, "init", uint32(syscall.SIGKILL))
    64  }
    65  
    66  func (cs *ContainerdSuite) UpdateContainerResource(id string, rs *types.UpdateResource) error {
    67  	_, err := cs.grpcClient.UpdateContainer(context.Background(), &types.UpdateContainerRequest{
    68  		Id:        id,
    69  		Pid:       "init",
    70  		Status:    "",
    71  		Resources: rs,
    72  	})
    73  	return err
    74  }
    75  
    76  func (cs *ContainerdSuite) PauseContainer(id string) error {
    77  	_, err := cs.grpcClient.UpdateContainer(context.Background(), &types.UpdateContainerRequest{
    78  		Id:     id,
    79  		Pid:    "init",
    80  		Status: "paused",
    81  	})
    82  	return err
    83  }
    84  
    85  func (cs *ContainerdSuite) ResumeContainer(id string) error {
    86  	_, err := cs.grpcClient.UpdateContainer(context.Background(), &types.UpdateContainerRequest{
    87  		Id:     id,
    88  		Pid:    "init",
    89  		Status: "running",
    90  	})
    91  	return err
    92  }
    93  
    94  func (cs *ContainerdSuite) GetContainerStats(id string) (*types.StatsResponse, error) {
    95  	stats, err := cs.grpcClient.Stats(context.Background(), &types.StatsRequest{
    96  		Id: id,
    97  	})
    98  	return stats, err
    99  }
   100  
   101  type stdio struct {
   102  	stdin        string
   103  	stdout       string
   104  	stderr       string
   105  	stdinf       *os.File
   106  	stdoutf      *os.File
   107  	stderrf      *os.File
   108  	stdoutBuffer bytes.Buffer
   109  	stderrBuffer bytes.Buffer
   110  }
   111  
   112  type ContainerProcess struct {
   113  	containerID string
   114  	pid         string
   115  	bundle      *Bundle
   116  	io          stdio
   117  	eventsCh    chan *types.Event
   118  	cs          *ContainerdSuite
   119  	hasExited   bool
   120  	systemPid   uint32
   121  }
   122  
   123  func (c *ContainerProcess) openIo() (err error) {
   124  	defer func() {
   125  		if err != nil {
   126  			c.Cleanup()
   127  		}
   128  	}()
   129  
   130  	c.io.stdinf, err = os.OpenFile(c.io.stdin, os.O_RDWR, 0)
   131  	if err != nil {
   132  		return err
   133  	}
   134  
   135  	c.io.stdoutf, err = os.OpenFile(c.io.stdout, os.O_RDWR, 0)
   136  	if err != nil {
   137  		return err
   138  	}
   139  	go io.Copy(&c.io.stdoutBuffer, c.io.stdoutf)
   140  
   141  	c.io.stderrf, err = os.OpenFile(c.io.stderr, os.O_RDWR, 0)
   142  	if err != nil {
   143  		return err
   144  	}
   145  	go io.Copy(&c.io.stderrBuffer, c.io.stderrf)
   146  
   147  	return nil
   148  }
   149  
   150  func (c *ContainerProcess) GetEventsChannel() chan *types.Event {
   151  	return c.eventsCh
   152  }
   153  
   154  func (c *ContainerProcess) GetNextEvent() *types.Event {
   155  	if c.hasExited {
   156  		return nil
   157  	}
   158  
   159  	e := <-c.eventsCh
   160  
   161  	if e.Type == "exit" && e.Pid == c.pid {
   162  		c.Cleanup()
   163  		c.hasExited = true
   164  		close(c.eventsCh)
   165  	}
   166  
   167  	return e
   168  }
   169  
   170  func (c *ContainerProcess) CloseStdin() error {
   171  	_, err := c.cs.grpcClient.UpdateProcess(context.Background(), &types.UpdateProcessRequest{
   172  		Id:         c.containerID,
   173  		Pid:        c.pid,
   174  		CloseStdin: true,
   175  	})
   176  	return err
   177  }
   178  
   179  func (c *ContainerProcess) Cleanup() {
   180  	for _, f := range []*os.File{
   181  		c.io.stdinf,
   182  		c.io.stdoutf,
   183  		c.io.stderrf,
   184  	} {
   185  		if f != nil {
   186  			f.Close()
   187  			f = nil
   188  		}
   189  	}
   190  }
   191  
   192  func NewContainerProcess(cs *ContainerdSuite, bundle *Bundle, cid, pid string) (c *ContainerProcess, err error) {
   193  	c = &ContainerProcess{
   194  		containerID: cid,
   195  		pid:         "init",
   196  		bundle:      bundle,
   197  		eventsCh:    make(chan *types.Event, 8),
   198  		cs:          cs,
   199  		hasExited:   false,
   200  	}
   201  
   202  	for _, pair := range []struct {
   203  		name string
   204  		path *string
   205  	}{
   206  		{"stdin", &c.io.stdin},
   207  		{"stdout", &c.io.stdout},
   208  		{"stderr", &c.io.stderr},
   209  	} {
   210  		*pair.path = filepath.Join(bundle.Path, "io", cid+"-"+pid+"-"+pair.name)
   211  		if err = unix.Mkfifo(*pair.path, 0755); err != nil && !os.IsExist(err) {
   212  			return nil, err
   213  		}
   214  	}
   215  
   216  	if err = c.openIo(); err != nil {
   217  		return nil, err
   218  	}
   219  
   220  	return c, nil
   221  }
   222  
   223  func (cs *ContainerdSuite) StartContainerWithEventFilter(id, bundleName string, filter func(*types.Event)) (c *ContainerProcess, err error) {
   224  	bundle := GetBundle(bundleName)
   225  	if bundle == nil {
   226  		return nil, fmt.Errorf("No such bundle '%s'", bundleName)
   227  	}
   228  
   229  	c, err = NewContainerProcess(cs, bundle, id, "init")
   230  	if err != nil {
   231  		return nil, err
   232  	}
   233  
   234  	r := &types.CreateContainerRequest{
   235  		Id:         id,
   236  		BundlePath: filepath.Join(cs.cwd, bundle.Path),
   237  		Stdin:      filepath.Join(cs.cwd, c.io.stdin),
   238  		Stdout:     filepath.Join(cs.cwd, c.io.stdout),
   239  		Stderr:     filepath.Join(cs.cwd, c.io.stderr),
   240  	}
   241  
   242  	if filter == nil {
   243  		filter = func(event *types.Event) {
   244  			c.eventsCh <- event
   245  		}
   246  	}
   247  
   248  	cs.SetContainerEventFilter(id, filter)
   249  
   250  	if _, err := cs.grpcClient.CreateContainer(context.Background(), r); err != nil {
   251  		c.Cleanup()
   252  		return nil, err
   253  	}
   254  
   255  	return c, nil
   256  }
   257  
   258  func (cs *ContainerdSuite) StartContainer(id, bundleName string) (c *ContainerProcess, err error) {
   259  	return cs.StartContainerWithEventFilter(id, bundleName, nil)
   260  }
   261  
   262  func (cs *ContainerdSuite) RunContainer(id, bundleName string) (c *ContainerProcess, err error) {
   263  	c, err = cs.StartContainer(id, bundleName)
   264  	if err != nil {
   265  		return nil, err
   266  	}
   267  
   268  	for {
   269  		e := c.GetNextEvent()
   270  		if e.Type == "exit" && e.Pid == "init" {
   271  			break
   272  		}
   273  	}
   274  
   275  	return c, err
   276  }
   277  
   278  func (cs *ContainerdSuite) AddProcessToContainer(init *ContainerProcess, pid, cwd string, env, args []string, uid, gid uint32) (c *ContainerProcess, err error) {
   279  	c, err = NewContainerProcess(cs, init.bundle, init.containerID, pid)
   280  	if err != nil {
   281  		return nil, err
   282  	}
   283  
   284  	pr := &types.AddProcessRequest{
   285  		Id:   init.containerID,
   286  		Pid:  pid,
   287  		Args: args,
   288  		Cwd:  cwd,
   289  		Env:  env,
   290  		User: &types.User{
   291  			Uid: uid,
   292  			Gid: gid,
   293  		},
   294  		Stdin:  filepath.Join(cs.cwd, c.io.stdin),
   295  		Stdout: filepath.Join(cs.cwd, c.io.stdout),
   296  		Stderr: filepath.Join(cs.cwd, c.io.stderr),
   297  	}
   298  
   299  	apr, err := cs.grpcClient.AddProcess(context.Background(), pr)
   300  	if err != nil {
   301  		c.Cleanup()
   302  		return nil, err
   303  	}
   304  
   305  	c.systemPid = apr.SystemPid
   306  
   307  	return c, nil
   308  }
   309  
   310  type containerSorter struct {
   311  	c []*types.Container
   312  }
   313  
   314  func (s *containerSorter) Len() int {
   315  	return len(s.c)
   316  }
   317  
   318  func (s *containerSorter) Swap(i, j int) {
   319  	s.c[i], s.c[j] = s.c[j], s.c[i]
   320  }
   321  
   322  func (s *containerSorter) Less(i, j int) bool {
   323  	return s.c[i].Id < s.c[j].Id
   324  }
   325  
   326  func sortContainers(c []*types.Container) {
   327  	sort.Sort(&containerSorter{c})
   328  }