github.com/georgethebeatle/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 }