From 8eeafa058c762b303436422a4682c364fe469985 Mon Sep 17 00:00:00 2001 From: Tonis Tiigi Date: Mon, 17 Aug 2015 14:11:40 -0700 Subject: [PATCH] Fix pull on client disconnect Fixes #15589 Signed-off-by: Tonis Tiigi --- graph/pull_v2.go | 5 +++- integration-cli/docker_cli_pull_test.go | 37 +++++++++++++++++++++++++ 2 files changed, 41 insertions(+), 1 deletion(-) diff --git a/graph/pull_v2.go b/graph/pull_v2.go index daf906b98a..034f6dc9a8 100644 --- a/graph/pull_v2.go +++ b/graph/pull_v2.go @@ -77,7 +77,7 @@ func (p *v2Puller) pullV2Repository(tag string) (err error) { if err != nil { if c != nil { // Another pull of the same repository is already taking place; just wait for it to finish - p.sf.FormatStatus("", "Repository %s already being pulled by another client. Waiting.", p.repoInfo.CanonicalName) + p.config.OutStream.Write(p.sf.FormatStatus("", "Repository %s already being pulled by another client. Waiting.", p.repoInfo.CanonicalName)) <-c return nil } @@ -223,6 +223,9 @@ func (p *v2Puller) pullV2Tag(tag, taggedName string) (verified bool, err error) go func() { if _, err := io.Copy(out, pipeReader); err != nil { logrus.Errorf("error copying from layer download progress reader: %s", err) + if err := pipeReader.CloseWithError(err); err != nil { + logrus.Errorf("error closing the progress reader: %s", err) + } } }() defer func() { diff --git a/integration-cli/docker_cli_pull_test.go b/integration-cli/docker_cli_pull_test.go index e1419b12e5..fdafe7c984 100644 --- a/integration-cli/docker_cli_pull_test.go +++ b/integration-cli/docker_cli_pull_test.go @@ -369,3 +369,40 @@ func (s *DockerTrustSuite) TestTrustedPullWithExpiredSnapshot(c *check.C) { } }) } + +// Test that pull continues after client has disconnected. #15589 +func (s *DockerTrustSuite) TestPullClientDisconnect(c *check.C) { + testRequires(c, Network) + + repoName := "hello-world:latest" + + dockerCmdWithError("rmi", repoName) // clean just in case + + pullCmd := exec.Command(dockerBinary, "pull", repoName) + + stdout, err := pullCmd.StdoutPipe() + c.Assert(err, check.IsNil) + + err = pullCmd.Start() + c.Assert(err, check.IsNil) + + // cancel as soon as we get some output + buf := make([]byte, 10) + _, err = stdout.Read(buf) + c.Assert(err, check.IsNil) + + err = pullCmd.Process.Kill() + c.Assert(err, check.IsNil) + + maxAttempts := 20 + for i := 0; ; i++ { + if _, _, err := dockerCmdWithError("inspect", repoName); err == nil { + break + } + if i >= maxAttempts { + c.Fatal("Timeout reached. Image was not pulled after client disconnected.") + } + time.Sleep(500 * time.Millisecond) + } + +}