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