github.com/vieux/docker@v0.6.3-0.20161004191708-e097c2a938c7/cli/command/container/utils.go (about) 1 package container 2 3 import ( 4 "strconv" 5 6 "golang.org/x/net/context" 7 8 "github.com/Sirupsen/logrus" 9 "github.com/docker/docker/api/types" 10 "github.com/docker/docker/api/types/events" 11 "github.com/docker/docker/api/types/filters" 12 "github.com/docker/docker/cli/command" 13 clientapi "github.com/docker/docker/client" 14 ) 15 16 func waitExitOrRemoved(dockerCli *command.DockerCli, ctx context.Context, containerID string, waitRemove bool) chan int { 17 if len(containerID) == 0 { 18 // containerID can never be empty 19 panic("Internal Error: waitExitOrRemoved needs a containerID as parameter") 20 } 21 22 statusChan := make(chan int) 23 exitCode := 125 24 25 eventProcessor := func(e events.Message) bool { 26 27 stopProcessing := false 28 switch e.Status { 29 case "die": 30 if v, ok := e.Actor.Attributes["exitCode"]; ok { 31 code, cerr := strconv.Atoi(v) 32 if cerr != nil { 33 logrus.Errorf("failed to convert exitcode '%q' to int: %v", v, cerr) 34 } else { 35 exitCode = code 36 } 37 } 38 if !waitRemove { 39 stopProcessing = true 40 } 41 case "detach": 42 exitCode = 0 43 stopProcessing = true 44 case "destroy": 45 stopProcessing = true 46 } 47 48 if stopProcessing { 49 statusChan <- exitCode 50 return true 51 } 52 53 return false 54 } 55 56 // Get events via Events API 57 f := filters.NewArgs() 58 f.Add("type", "container") 59 f.Add("container", containerID) 60 options := types.EventsOptions{ 61 Filters: f, 62 } 63 64 eventCtx, cancel := context.WithCancel(ctx) 65 eventq, errq := dockerCli.Client().Events(eventCtx, options) 66 67 go func() { 68 defer cancel() 69 70 for { 71 select { 72 case evt := <-eventq: 73 if eventProcessor(evt) { 74 return 75 } 76 77 case err := <-errq: 78 logrus.Errorf("error getting events from daemon: %v", err) 79 statusChan <- exitCode 80 return 81 } 82 } 83 }() 84 85 return statusChan 86 } 87 88 // getExitCode performs an inspect on the container. It returns 89 // the running state and the exit code. 90 func getExitCode(dockerCli *command.DockerCli, ctx context.Context, containerID string) (bool, int, error) { 91 c, err := dockerCli.Client().ContainerInspect(ctx, containerID) 92 if err != nil { 93 // If we can't connect, then the daemon probably died. 94 if err != clientapi.ErrConnectionFailed { 95 return false, -1, err 96 } 97 return false, -1, nil 98 } 99 return c.State.Running, c.State.ExitCode, nil 100 } 101 102 func parallelOperation(ctx context.Context, cids []string, op func(ctx context.Context, id string) error) chan error { 103 if len(cids) == 0 { 104 return nil 105 } 106 const defaultParallel int = 50 107 sem := make(chan struct{}, defaultParallel) 108 errChan := make(chan error) 109 110 // make sure result is printed in correct order 111 output := map[string]chan error{} 112 for _, c := range cids { 113 output[c] = make(chan error, 1) 114 } 115 go func() { 116 for _, c := range cids { 117 err := <-output[c] 118 errChan <- err 119 } 120 }() 121 122 go func() { 123 for _, c := range cids { 124 sem <- struct{}{} // Wait for active queue sem to drain. 125 go func(container string) { 126 output[container] <- op(ctx, container) 127 <-sem 128 }(c) 129 } 130 }() 131 return errChan 132 }