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  }