Quellcode durchsuchen

Merge pull request #25524 from WeiZhang555/debug-win2lin

Bugfix: client hangs after run container
Brian Goff vor 9 Jahren
Ursprung
Commit
52286b402e
2 geänderte Dateien mit 44 neuen und 67 gelöschten Zeilen
  1. 8 13
      api/client/container/run.go
  2. 36 54
      api/client/container/utils.go

+ 8 - 13
api/client/container/run.go

@@ -8,7 +8,6 @@ import (
 	"runtime"
 	"runtime"
 	"strings"
 	"strings"
 	"syscall"
 	"syscall"
-	"time"
 
 
 	"golang.org/x/net/context"
 	"golang.org/x/net/context"
 
 
@@ -144,7 +143,6 @@ func runRun(dockerCli *client.DockerCli, flags *pflag.FlagSet, opts *runOptions,
 		hostConfig.ConsoleSize[0], hostConfig.ConsoleSize[1] = dockerCli.GetTtySize()
 		hostConfig.ConsoleSize[0], hostConfig.ConsoleSize[1] = dockerCli.GetTtySize()
 	}
 	}
 
 
-	startTime := time.Now()
 	ctx, cancelFun := context.WithCancel(context.Background())
 	ctx, cancelFun := context.WithCancel(context.Background())
 
 
 	createResponse, err := createContainer(ctx, dockerCli, config, hostConfig, networkingConfig, hostConfig.ContainerIDFile, opts.name)
 	createResponse, err := createContainer(ctx, dockerCli, config, hostConfig, networkingConfig, hostConfig.ContainerIDFile, opts.name)
@@ -221,6 +219,11 @@ func runRun(dockerCli *client.DockerCli, flags *pflag.FlagSet, opts *runOptions,
 		})
 		})
 	}
 	}
 
 
+	statusChan, err := waitExitOrRemoved(dockerCli, context.Background(), createResponse.ID, hostConfig.AutoRemove)
+	if err != nil {
+		return fmt.Errorf("Error waiting container's exit code: %v", err)
+	}
+
 	//start the container
 	//start the container
 	if err := client.ContainerStart(ctx, createResponse.ID, types.ContainerStartOptions{}); err != nil {
 	if err := client.ContainerStart(ctx, createResponse.ID, types.ContainerStartOptions{}); err != nil {
 		// If we have holdHijackedConnection, we should notify
 		// If we have holdHijackedConnection, we should notify
@@ -233,9 +236,8 @@ func runRun(dockerCli *client.DockerCli, flags *pflag.FlagSet, opts *runOptions,
 
 
 		reportError(stderr, cmdPath, err.Error(), false)
 		reportError(stderr, cmdPath, err.Error(), false)
 		if hostConfig.AutoRemove {
 		if hostConfig.AutoRemove {
-			if _, errWait := waitExitOrRemoved(dockerCli, context.Background(), createResponse.ID, hostConfig.AutoRemove, startTime); errWait != nil {
-				logrus.Debugf("Error waiting container's removal: %v", errWait)
-			}
+			// wait container to be removed
+			<-statusChan
 		}
 		}
 		return runStartContainerErr(err)
 		return runStartContainerErr(err)
 	}
 	}
@@ -260,14 +262,7 @@ func runRun(dockerCli *client.DockerCli, flags *pflag.FlagSet, opts *runOptions,
 		return nil
 		return nil
 	}
 	}
 
 
-	var status int
-
-	// Attached mode
-	status, err = waitExitOrRemoved(dockerCli, ctx, createResponse.ID, hostConfig.AutoRemove, startTime)
-	if err != nil {
-		return fmt.Errorf("Error waiting container to exit: %v", err)
-	}
-
+	status := <-statusChan
 	if status != 0 {
 	if status != 0 {
 		return cli.StatusError{StatusCode: status}
 		return cli.StatusError{StatusCode: status}
 	}
 	}

+ 36 - 54
api/client/container/utils.go

@@ -3,7 +3,6 @@ package container
 import (
 import (
 	"fmt"
 	"fmt"
 	"strconv"
 	"strconv"
-	"time"
 
 
 	"golang.org/x/net/context"
 	"golang.org/x/net/context"
 
 
@@ -16,83 +15,66 @@ import (
 	"github.com/docker/engine-api/types/filters"
 	"github.com/docker/engine-api/types/filters"
 )
 )
 
 
-func waitExitOrRemoved(dockerCli *client.DockerCli, ctx context.Context, containerID string, waitRemove bool, since time.Time) (int, error) {
+func waitExitOrRemoved(dockerCli *client.DockerCli, ctx context.Context, containerID string, waitRemove bool) (chan int, error) {
 	if len(containerID) == 0 {
 	if len(containerID) == 0 {
 		// containerID can never be empty
 		// containerID can never be empty
 		panic("Internal Error: waitExitOrRemoved needs a containerID as parameter")
 		panic("Internal Error: waitExitOrRemoved needs a containerID as parameter")
 	}
 	}
 
 
-	var exitCode int
-	exitChan := make(chan struct{})
-	detachChan := make(chan struct{})
-	destroyChan := make(chan struct{})
+	statusChan := make(chan int)
+	exitCode := 125
 
 
-	// 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
+	eventProcessor := func(e events.Message, err error) error {
+		if err != nil {
+			statusChan <- exitCode
+			return fmt.Errorf("failed to decode event: %v", err)
+		}
+
+		stopProcessing := false
+		switch e.Status {
+		case "die":
+			if v, ok := e.Actor.Attributes["exitCode"]; ok {
+				code, cerr := strconv.Atoi(v)
+				if cerr != nil {
+					logrus.Errorf("failed to convert exitcode '%q' to int: %v", v, cerr)
+				} else {
+					exitCode = code
 				}
 				}
 			}
 			}
+			if !waitRemove {
+				stopProcessing = true
+			}
+		case "detach":
+			exitCode = 0
+			stopProcessing = true
+		case "destroy":
+			stopProcessing = true
 		}
 		}
-	})
 
 
-	eh.Handle("detach", func(e events.Message) {
-		exitCode = 0
-		close(detachChan)
-	})
-	eh.Handle("destroy", func(e events.Message) {
-		close(destroyChan)
-	})
+		if stopProcessing {
+			statusChan <- exitCode
+			// stop the loop processing
+			return fmt.Errorf("done")
+		}
 
 
-	eventChan := make(chan events.Message)
-	go eh.Watch(eventChan)
-	defer close(eventChan)
+		return nil
+	}
 
 
 	// Get events via Events API
 	// Get events via Events API
 	f := filters.NewArgs()
 	f := filters.NewArgs()
 	f.Add("type", "container")
 	f.Add("type", "container")
 	f.Add("container", containerID)
 	f.Add("container", containerID)
 	options := types.EventsOptions{
 	options := types.EventsOptions{
-		Since:   fmt.Sprintf("%d", since.Unix()),
 		Filters: f,
 		Filters: f,
 	}
 	}
 	resBody, err := dockerCli.Client().Events(ctx, options)
 	resBody, err := dockerCli.Client().Events(ctx, options)
 	if err != nil {
 	if err != nil {
-		return -1, fmt.Errorf("can't get events from daemon: %v", err)
+		return nil, fmt.Errorf("can't get events from daemon: %v", err)
 	}
 	}
-	defer resBody.Close()
 
 
-	go system.DecodeEvents(resBody, func(event events.Message, err error) error {
-		if err != nil {
-			return nil
-		}
-		eventChan <- event
-		return nil
-	})
+	go system.DecodeEvents(resBody, eventProcessor)
 
 
-	if waitRemove {
-		select {
-		case <-destroyChan:
-			return exitCode, nil
-		case <-detachChan:
-			return 0, nil
-		}
-	} else {
-		select {
-		case <-exitChan:
-			return exitCode, nil
-		case <-detachChan:
-			return 0, nil
-		}
-	}
+	return statusChan, nil
 }
 }
 
 
 // getExitCode performs an inspect on the container. It returns
 // getExitCode performs an inspect on the container. It returns