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 }