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