github.com/sameo/containerd@v0.2.8/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/docker/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 name, path := range map[string]*string{
   203  		"stdin":  &c.io.stdin,
   204  		"stdout": &c.io.stdout,
   205  		"stderr": &c.io.stderr,
   206  	} {
   207  		*path = filepath.Join(bundle.Path, "io", cid+"-"+pid+"-"+name)
   208  		if err = unix.Mkfifo(*path, 0755); err != nil && !os.IsExist(err) {
   209  			return nil, err
   210  		}
   211  	}
   212  
   213  	if err = c.openIo(); err != nil {
   214  		return nil, err
   215  	}
   216  
   217  	return c, nil
   218  }
   219  
   220  func (cs *ContainerdSuite) StartContainerWithEventFilter(id, bundleName string, filter func(*types.Event)) (c *ContainerProcess, err error) {
   221  	bundle := GetBundle(bundleName)
   222  	if bundle == nil {
   223  		return nil, fmt.Errorf("No such bundle '%s'", bundleName)
   224  	}
   225  
   226  	c, err = NewContainerProcess(cs, bundle, id, "init")
   227  	if err != nil {
   228  		return nil, err
   229  	}
   230  
   231  	r := &types.CreateContainerRequest{
   232  		Id:         id,
   233  		BundlePath: filepath.Join(cs.cwd, bundle.Path),
   234  		Stdin:      filepath.Join(cs.cwd, c.io.stdin),
   235  		Stdout:     filepath.Join(cs.cwd, c.io.stdout),
   236  		Stderr:     filepath.Join(cs.cwd, c.io.stderr),
   237  	}
   238  
   239  	if filter == nil {
   240  		filter = func(event *types.Event) {
   241  			c.eventsCh <- event
   242  		}
   243  	}
   244  
   245  	cs.SetContainerEventFilter(id, filter)
   246  
   247  	if _, err := cs.grpcClient.CreateContainer(context.Background(), r); err != nil {
   248  		c.Cleanup()
   249  		return nil, err
   250  	}
   251  
   252  	return c, nil
   253  }
   254  
   255  func (cs *ContainerdSuite) StartContainer(id, bundleName string) (c *ContainerProcess, err error) {
   256  	return cs.StartContainerWithEventFilter(id, bundleName, nil)
   257  }
   258  
   259  func (cs *ContainerdSuite) RunContainer(id, bundleName string) (c *ContainerProcess, err error) {
   260  	c, err = cs.StartContainer(id, bundleName)
   261  	if err != nil {
   262  		return nil, err
   263  	}
   264  
   265  	for {
   266  		e := c.GetNextEvent()
   267  		if e.Type == "exit" && e.Pid == "init" {
   268  			break
   269  		}
   270  	}
   271  
   272  	return c, err
   273  }
   274  
   275  func (cs *ContainerdSuite) AddProcessToContainer(init *ContainerProcess, pid, cwd string, env, args []string, uid, gid uint32) (c *ContainerProcess, err error) {
   276  	c, err = NewContainerProcess(cs, init.bundle, init.containerID, pid)
   277  	if err != nil {
   278  		return nil, err
   279  	}
   280  
   281  	pr := &types.AddProcessRequest{
   282  		Id:   init.containerID,
   283  		Pid:  pid,
   284  		Args: args,
   285  		Cwd:  cwd,
   286  		Env:  env,
   287  		User: &types.User{
   288  			Uid: uid,
   289  			Gid: gid,
   290  		},
   291  		Stdin:  filepath.Join(cs.cwd, c.io.stdin),
   292  		Stdout: filepath.Join(cs.cwd, c.io.stdout),
   293  		Stderr: filepath.Join(cs.cwd, c.io.stderr),
   294  	}
   295  
   296  	apr, err := cs.grpcClient.AddProcess(context.Background(), pr)
   297  	if err != nil {
   298  		c.Cleanup()
   299  		return nil, err
   300  	}
   301  
   302  	c.systemPid = apr.SystemPid
   303  
   304  	return c, nil
   305  }
   306  
   307  type containerSorter struct {
   308  	c []*types.Container
   309  }
   310  
   311  func (s *containerSorter) Len() int {
   312  	return len(s.c)
   313  }
   314  
   315  func (s *containerSorter) Swap(i, j int) {
   316  	s.c[i], s.c[j] = s.c[j], s.c[i]
   317  }
   318  
   319  func (s *containerSorter) Less(i, j int) bool {
   320  	return s.c[i].Id < s.c[j].Id
   321  }
   322  
   323  func sortContainers(c []*types.Container) {
   324  	sort.Sort(&containerSorter{c})
   325  }