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 }