| ... | ... |
@@ -77,7 +77,7 @@ func (p *v2Puller) pullV2Repository(tag string) (err error) {
|
| 77 | 77 |
if err != nil {
|
| 78 | 78 |
if c != nil {
|
| 79 | 79 |
// Another pull of the same repository is already taking place; just wait for it to finish |
| 80 |
- p.sf.FormatStatus("", "Repository %s already being pulled by another client. Waiting.", p.repoInfo.CanonicalName)
|
|
| 80 |
+ p.config.OutStream.Write(p.sf.FormatStatus("", "Repository %s already being pulled by another client. Waiting.", p.repoInfo.CanonicalName))
|
|
| 81 | 81 |
<-c |
| 82 | 82 |
return nil |
| 83 | 83 |
} |
| ... | ... |
@@ -223,6 +223,9 @@ func (p *v2Puller) pullV2Tag(tag, taggedName string) (verified bool, err error) |
| 223 | 223 |
go func() {
|
| 224 | 224 |
if _, err := io.Copy(out, pipeReader); err != nil {
|
| 225 | 225 |
logrus.Errorf("error copying from layer download progress reader: %s", err)
|
| 226 |
+ if err := pipeReader.CloseWithError(err); err != nil {
|
|
| 227 |
+ logrus.Errorf("error closing the progress reader: %s", err)
|
|
| 228 |
+ } |
|
| 226 | 229 |
} |
| 227 | 230 |
}() |
| 228 | 231 |
defer func() {
|
| ... | ... |
@@ -369,3 +369,40 @@ func (s *DockerTrustSuite) TestTrustedPullWithExpiredSnapshot(c *check.C) {
|
| 369 | 369 |
} |
| 370 | 370 |
}) |
| 371 | 371 |
} |
| 372 |
+ |
|
| 373 |
+// Test that pull continues after client has disconnected. #15589 |
|
| 374 |
+func (s *DockerTrustSuite) TestPullClientDisconnect(c *check.C) {
|
|
| 375 |
+ testRequires(c, Network) |
|
| 376 |
+ |
|
| 377 |
+ repoName := "hello-world:latest" |
|
| 378 |
+ |
|
| 379 |
+ dockerCmdWithError("rmi", repoName) // clean just in case
|
|
| 380 |
+ |
|
| 381 |
+ pullCmd := exec.Command(dockerBinary, "pull", repoName) |
|
| 382 |
+ |
|
| 383 |
+ stdout, err := pullCmd.StdoutPipe() |
|
| 384 |
+ c.Assert(err, check.IsNil) |
|
| 385 |
+ |
|
| 386 |
+ err = pullCmd.Start() |
|
| 387 |
+ c.Assert(err, check.IsNil) |
|
| 388 |
+ |
|
| 389 |
+ // cancel as soon as we get some output |
|
| 390 |
+ buf := make([]byte, 10) |
|
| 391 |
+ _, err = stdout.Read(buf) |
|
| 392 |
+ c.Assert(err, check.IsNil) |
|
| 393 |
+ |
|
| 394 |
+ err = pullCmd.Process.Kill() |
|
| 395 |
+ c.Assert(err, check.IsNil) |
|
| 396 |
+ |
|
| 397 |
+ maxAttempts := 20 |
|
| 398 |
+ for i := 0; ; i++ {
|
|
| 399 |
+ if _, _, err := dockerCmdWithError("inspect", repoName); err == nil {
|
|
| 400 |
+ break |
|
| 401 |
+ } |
|
| 402 |
+ if i >= maxAttempts {
|
|
| 403 |
+ c.Fatal("Timeout reached. Image was not pulled after client disconnected.")
|
|
| 404 |
+ } |
|
| 405 |
+ time.Sleep(500 * time.Millisecond) |
|
| 406 |
+ } |
|
| 407 |
+ |
|
| 408 |
+} |