Ver Fonte

Merge pull request #15646 from tonistiigi/15589-pull-cancellation

Fix pull on client disconnect
David Calavera há 9 anos atrás
pai
commit
0634c653d5
2 ficheiros alterados com 41 adições e 1 exclusões
  1. 4 1
      graph/pull_v2.go
  2. 37 0
      integration-cli/docker_cli_pull_test.go

+ 4 - 1
graph/pull_v2.go

@@ -77,7 +77,7 @@ func (p *v2Puller) pullV2Repository(tag string) (err error) {
 	if err != nil {
 	if err != nil {
 		if c != nil {
 		if c != nil {
 			// Another pull of the same repository is already taking place; just wait for it to finish
 			// 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
 			<-c
 			return nil
 			return nil
 		}
 		}
@@ -223,6 +223,9 @@ func (p *v2Puller) pullV2Tag(tag, taggedName string) (verified bool, err error)
 	go func() {
 	go func() {
 		if _, err := io.Copy(out, pipeReader); err != nil {
 		if _, err := io.Copy(out, pipeReader); err != nil {
 			logrus.Errorf("error copying from layer download progress reader: %s", err)
 			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() {
 	defer func() {

+ 37 - 0
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)
+	}
+
+}