github.com/brahmaroutu/docker@v1.2.1-0.20160809185609-eb28dde01f16/api/client/container/utils.go (about) 1 package container 2 3 import ( 4 "fmt" 5 "strconv" 6 "time" 7 8 "golang.org/x/net/context" 9 10 "github.com/Sirupsen/logrus" 11 "github.com/docker/docker/api/client" 12 "github.com/docker/docker/api/client/system" 13 clientapi "github.com/docker/engine-api/client" 14 "github.com/docker/engine-api/types" 15 "github.com/docker/engine-api/types/events" 16 "github.com/docker/engine-api/types/filters" 17 ) 18 19 func waitExitOrRemoved(dockerCli *client.DockerCli, ctx context.Context, containerID string, waitRemove bool, since time.Time) (int, error) { 20 if len(containerID) == 0 { 21 // containerID can never be empty 22 panic("Internal Error: waitExitOrRemoved needs a containerID as parameter") 23 } 24 25 var exitCode int 26 exitChan := make(chan struct{}) 27 detachChan := make(chan struct{}) 28 destroyChan := make(chan struct{}) 29 30 // Start watch events 31 eh := system.InitEventHandler() 32 eh.Handle("die", func(e events.Message) { 33 if len(e.Actor.Attributes) > 0 { 34 for k, v := range e.Actor.Attributes { 35 if k == "exitCode" { 36 var err error 37 if exitCode, err = strconv.Atoi(v); err != nil { 38 logrus.Errorf("Can't convert %q to int: %v", v, err) 39 } 40 close(exitChan) 41 break 42 } 43 } 44 } 45 }) 46 47 eh.Handle("detach", func(e events.Message) { 48 exitCode = 0 49 close(detachChan) 50 }) 51 eh.Handle("destroy", func(e events.Message) { 52 close(destroyChan) 53 }) 54 55 eventChan := make(chan events.Message) 56 go eh.Watch(eventChan) 57 defer close(eventChan) 58 59 // Get events via Events API 60 f := filters.NewArgs() 61 f.Add("type", "container") 62 f.Add("container", containerID) 63 options := types.EventsOptions{ 64 Since: fmt.Sprintf("%d", since.Unix()), 65 Filters: f, 66 } 67 resBody, err := dockerCli.Client().Events(ctx, options) 68 if err != nil { 69 return -1, fmt.Errorf("can't get events from daemon: %v", err) 70 } 71 defer resBody.Close() 72 73 go system.DecodeEvents(resBody, func(event events.Message, err error) error { 74 if err != nil { 75 return nil 76 } 77 eventChan <- event 78 return nil 79 }) 80 81 if waitRemove { 82 select { 83 case <-destroyChan: 84 return exitCode, nil 85 case <-detachChan: 86 return 0, nil 87 } 88 } else { 89 select { 90 case <-exitChan: 91 return exitCode, nil 92 case <-detachChan: 93 return 0, nil 94 } 95 } 96 } 97 98 // getExitCode performs an inspect on the container. It returns 99 // the running state and the exit code. 100 func getExitCode(dockerCli *client.DockerCli, ctx context.Context, containerID string) (bool, int, error) { 101 c, err := dockerCli.Client().ContainerInspect(ctx, containerID) 102 if err != nil { 103 // If we can't connect, then the daemon probably died. 104 if err != clientapi.ErrConnectionFailed { 105 return false, -1, err 106 } 107 return false, -1, nil 108 } 109 return c.State.Running, c.State.ExitCode, nil 110 }