diff --git a/api/client/container/run.go b/api/client/container/run.go index 8261120bf4..7c2a90fd1f 100644 --- a/api/client/container/run.go +++ b/api/client/container/run.go @@ -288,7 +288,7 @@ func runRun(dockerCli *client.DockerCli, flags *pflag.FlagSet, opts *runOptions, } } else { // No Autoremove: Simply retrieve the exit code - if !config.Tty { + if !config.Tty && hostConfig.RestartPolicy.IsNone() { // In non-TTY mode, we can't detach, so we must wait for container exit if status, err = client.ContainerWait(ctx, createResponse.ID); err != nil { return err diff --git a/daemon/attach.go b/daemon/attach.go index 06eb2be3d4..3d4a51eead 100644 --- a/daemon/attach.go +++ b/daemon/attach.go @@ -119,6 +119,15 @@ func (daemon *Daemon) containerAttach(c *container.Container, stdin io.ReadClose }() stdinPipe = r } + + waitChan := make(chan struct{}) + if c.Config.StdinOnce && !c.Config.Tty { + go func() { + c.WaitStop(-1 * time.Second) + close(waitChan) + }() + } + err := <-c.Attach(stdinPipe, stdout, stderr, keys) if err != nil { if _, ok := err.(container.DetachError); ok { @@ -131,7 +140,7 @@ func (daemon *Daemon) containerAttach(c *container.Container, stdin io.ReadClose // If we are in stdinonce mode, wait for the process to end // otherwise, simply return if c.Config.StdinOnce && !c.Config.Tty { - c.WaitStop(-1 * time.Second) + <-waitChan } } return nil diff --git a/integration-cli/docker_cli_run_test.go b/integration-cli/docker_cli_run_test.go index 224d2c51f4..1f631acdcd 100644 --- a/integration-cli/docker_cli_run_test.go +++ b/integration-cli/docker_cli_run_test.go @@ -1833,6 +1833,37 @@ func (s *DockerSuite) TestRunExitOnStdinClose(c *check.C) { } } +// Test run -i --restart xxx doesn't hang +func (s *DockerSuite) TestRunInteractiveWithRestartPolicy(c *check.C) { + name := "test-inter-restart" + runCmd := exec.Command(dockerBinary, "run", "-i", "--name", name, "--restart=always", "busybox", "sh") + + stdin, err := runCmd.StdinPipe() + c.Assert(err, checker.IsNil) + + err = runCmd.Start() + c.Assert(err, checker.IsNil) + c.Assert(waitRun(name), check.IsNil) + + _, err = stdin.Write([]byte("exit 11\n")) + c.Assert(err, checker.IsNil) + + finish := make(chan error) + go func() { + finish <- runCmd.Wait() + close(finish) + }() + delay := 10 * time.Second + select { + case <-finish: + case <-time.After(delay): + c.Fatal("run -i --restart hangs") + } + + c.Assert(waitRun(name), check.IsNil) + dockerCmd(c, "stop", name) +} + // Test for #2267 func (s *DockerSuite) TestRunWriteHostsFileAndNotCommit(c *check.C) { // Cannot run on Windows as Windows does not support diff.