123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125 |
- package container
- import (
- "fmt"
- "strconv"
- "golang.org/x/net/context"
- "github.com/Sirupsen/logrus"
- "github.com/docker/docker/api/client"
- "github.com/docker/docker/api/client/system"
- clientapi "github.com/docker/engine-api/client"
- "github.com/docker/engine-api/types"
- "github.com/docker/engine-api/types/events"
- "github.com/docker/engine-api/types/filters"
- )
- func waitExitOrRemoved(dockerCli *client.DockerCli, ctx context.Context, containerID string, waitRemove bool) (chan int, error) {
- if len(containerID) == 0 {
- // containerID can never be empty
- panic("Internal Error: waitExitOrRemoved needs a containerID as parameter")
- }
- var exitCode int
- statusChan := make(chan int)
- exitChan := make(chan struct{})
- detachChan := make(chan struct{})
- destroyChan := make(chan struct{})
- eventsErr := make(chan error)
- // Start watch events
- eh := system.InitEventHandler()
- eh.Handle("die", func(e events.Message) {
- if len(e.Actor.Attributes) > 0 {
- for k, v := range e.Actor.Attributes {
- if k == "exitCode" {
- var err error
- if exitCode, err = strconv.Atoi(v); err != nil {
- logrus.Errorf("Can't convert %q to int: %v", v, err)
- }
- close(exitChan)
- break
- }
- }
- }
- })
- eh.Handle("detach", func(e events.Message) {
- exitCode = 0
- close(detachChan)
- })
- eh.Handle("destroy", func(e events.Message) {
- close(destroyChan)
- })
- eventChan := make(chan events.Message)
- go eh.Watch(eventChan)
- // Get events via Events API
- f := filters.NewArgs()
- f.Add("type", "container")
- f.Add("container", containerID)
- options := types.EventsOptions{
- Filters: f,
- }
- resBody, err := dockerCli.Client().Events(ctx, options)
- if err != nil {
- return nil, fmt.Errorf("can't get events from daemon: %v", err)
- }
- go func() {
- eventsErr <- system.DecodeEvents(resBody, func(event events.Message, err error) error {
- if err != nil {
- return fmt.Errorf("decode events error: %v", err)
- }
- eventChan <- event
- return nil
- })
- close(eventChan)
- }()
- go func() {
- var waitErr error
- if waitRemove {
- select {
- case <-destroyChan:
- // keep exitcode and return
- case <-detachChan:
- exitCode = 0
- case waitErr = <-eventsErr:
- exitCode = 125
- }
- } else {
- select {
- case <-exitChan:
- // keep exitcode and return
- case <-detachChan:
- exitCode = 0
- case waitErr = <-eventsErr:
- exitCode = 125
- }
- }
- if waitErr != nil {
- logrus.Errorf("%v", waitErr)
- }
- statusChan <- exitCode
- resBody.Close()
- }()
- return statusChan, nil
- }
- // getExitCode performs an inspect on the container. It returns
- // the running state and the exit code.
- func getExitCode(dockerCli *client.DockerCli, ctx context.Context, containerID string) (bool, int, error) {
- c, err := dockerCli.Client().ContainerInspect(ctx, containerID)
- if err != nil {
- // If we can't connect, then the daemon probably died.
- if err != clientapi.ErrConnectionFailed {
- return false, -1, err
- }
- return false, -1, nil
- }
- return c.State.Running, c.State.ExitCode, nil
- }
|