mirror of
https://github.com/moby/moby.git
synced 2022-11-09 12:21:53 -05:00
Merge pull request #1281 from dotcloud/505-output_after_pipe-fix
- Runtime: Fixes #505 - Make sure all output is send on the network before closing
This commit is contained in:
commit
594c818d85
4 changed files with 34 additions and 15 deletions
|
@ -895,6 +895,12 @@ func TestPostContainersAttach(t *testing.T) {
|
||||||
stdin, stdinPipe := io.Pipe()
|
stdin, stdinPipe := io.Pipe()
|
||||||
stdout, stdoutPipe := io.Pipe()
|
stdout, stdoutPipe := io.Pipe()
|
||||||
|
|
||||||
|
// Try to avoid the timeoout in destroy. Best effort, don't check error
|
||||||
|
defer func() {
|
||||||
|
closeWrap(stdin, stdinPipe, stdout, stdoutPipe)
|
||||||
|
container.Kill()
|
||||||
|
}()
|
||||||
|
|
||||||
// Attach to it
|
// Attach to it
|
||||||
c1 := make(chan struct{})
|
c1 := make(chan struct{})
|
||||||
go func() {
|
go func() {
|
||||||
|
@ -934,7 +940,7 @@ func TestPostContainersAttach(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Wait for attach to finish, the client disconnected, therefore, Attach finished his job
|
// Wait for attach to finish, the client disconnected, therefore, Attach finished his job
|
||||||
setTimeout(t, "Waiting for CmdAttach timed out", 2*time.Second, func() {
|
setTimeout(t, "Waiting for CmdAttach timed out", 10*time.Second, func() {
|
||||||
<-c1
|
<-c1
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
13
container.go
13
container.go
|
@ -379,14 +379,15 @@ func (container *Container) Attach(stdin io.ReadCloser, stdinCloser io.Closer, s
|
||||||
utils.Debugf("[start] attach stdin\n")
|
utils.Debugf("[start] attach stdin\n")
|
||||||
defer utils.Debugf("[end] attach stdin\n")
|
defer utils.Debugf("[end] attach stdin\n")
|
||||||
// No matter what, when stdin is closed (io.Copy unblock), close stdout and stderr
|
// No matter what, when stdin is closed (io.Copy unblock), close stdout and stderr
|
||||||
if cStdout != nil {
|
|
||||||
defer cStdout.Close()
|
|
||||||
}
|
|
||||||
if cStderr != nil {
|
|
||||||
defer cStderr.Close()
|
|
||||||
}
|
|
||||||
if container.Config.StdinOnce && !container.Config.Tty {
|
if container.Config.StdinOnce && !container.Config.Tty {
|
||||||
defer cStdin.Close()
|
defer cStdin.Close()
|
||||||
|
} else {
|
||||||
|
if cStdout != nil {
|
||||||
|
defer cStdout.Close()
|
||||||
|
}
|
||||||
|
if cStderr != nil {
|
||||||
|
defer cStderr.Close()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if container.Config.Tty {
|
if container.Config.Tty {
|
||||||
_, err = utils.CopyEscapable(cStdin, stdin)
|
_, err = utils.CopyEscapable(cStdin, stdin)
|
||||||
|
|
|
@ -8,6 +8,7 @@ import (
|
||||||
"log"
|
"log"
|
||||||
"net"
|
"net"
|
||||||
"os"
|
"os"
|
||||||
|
"runtime"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
|
@ -25,7 +26,11 @@ const (
|
||||||
testDaemonProto = "tcp"
|
testDaemonProto = "tcp"
|
||||||
)
|
)
|
||||||
|
|
||||||
var globalRuntime *Runtime
|
var (
|
||||||
|
globalRuntime *Runtime
|
||||||
|
startFds int
|
||||||
|
startGoroutines int
|
||||||
|
)
|
||||||
|
|
||||||
func nuke(runtime *Runtime) error {
|
func nuke(runtime *Runtime) error {
|
||||||
var wg sync.WaitGroup
|
var wg sync.WaitGroup
|
||||||
|
@ -80,21 +85,21 @@ func init() {
|
||||||
NetworkBridgeIface = unitTestNetworkBridge
|
NetworkBridgeIface = unitTestNetworkBridge
|
||||||
|
|
||||||
// Make it our Store root
|
// Make it our Store root
|
||||||
runtime, err := NewRuntimeFromDirectory(unitTestStoreBase, false)
|
if runtime, err := NewRuntimeFromDirectory(unitTestStoreBase, false); err != nil {
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
panic(err)
|
||||||
|
} else {
|
||||||
|
globalRuntime = runtime
|
||||||
}
|
}
|
||||||
globalRuntime = runtime
|
|
||||||
|
|
||||||
// Create the "Server"
|
// Create the "Server"
|
||||||
srv := &Server{
|
srv := &Server{
|
||||||
runtime: runtime,
|
runtime: globalRuntime,
|
||||||
enableCors: false,
|
enableCors: false,
|
||||||
pullingPool: make(map[string]struct{}),
|
pullingPool: make(map[string]struct{}),
|
||||||
pushingPool: make(map[string]struct{}),
|
pushingPool: make(map[string]struct{}),
|
||||||
}
|
}
|
||||||
// If the unit test is not found, try to download it.
|
// If the unit test is not found, try to download it.
|
||||||
if img, err := runtime.repositories.LookupImage(unitTestImageName); err != nil || img.ID != unitTestImageID {
|
if img, err := globalRuntime.repositories.LookupImage(unitTestImageName); err != nil || img.ID != unitTestImageID {
|
||||||
// Retrieve the Image
|
// Retrieve the Image
|
||||||
if err := srv.ImagePull(unitTestImageName, "", os.Stdout, utils.NewStreamFormatter(false), nil); err != nil {
|
if err := srv.ImagePull(unitTestImageName, "", os.Stdout, utils.NewStreamFormatter(false), nil); err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
|
@ -109,6 +114,8 @@ func init() {
|
||||||
|
|
||||||
// Give some time to ListenAndServer to actually start
|
// Give some time to ListenAndServer to actually start
|
||||||
time.Sleep(time.Second)
|
time.Sleep(time.Second)
|
||||||
|
|
||||||
|
startFds, startGoroutines = utils.GetTotalUsedFds(), runtime.NumGoroutine()
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME: test that ImagePull(json=true) send correct json output
|
// FIXME: test that ImagePull(json=true) send correct json output
|
||||||
|
|
|
@ -6,7 +6,12 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestFinal(t *testing.T) {
|
func displayFdGoroutines(t *testing.T) {
|
||||||
cleanup(globalRuntime)
|
|
||||||
t.Logf("Fds: %d, Goroutines: %d", utils.GetTotalUsedFds(), runtime.NumGoroutine())
|
t.Logf("Fds: %d, Goroutines: %d", utils.GetTotalUsedFds(), runtime.NumGoroutine())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestFinal(t *testing.T) {
|
||||||
|
cleanup(globalRuntime)
|
||||||
|
t.Logf("Start Fds: %d, Start Goroutines: %d", startFds, startGoroutines)
|
||||||
|
displayFdGoroutines(t)
|
||||||
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue