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 }