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  }