|
@@ -10,11 +10,13 @@ import (
|
|
"fmt"
|
|
"fmt"
|
|
"io"
|
|
"io"
|
|
"io/ioutil"
|
|
"io/ioutil"
|
|
|
|
+ "net"
|
|
"os"
|
|
"os"
|
|
"path/filepath"
|
|
"path/filepath"
|
|
"runtime"
|
|
"runtime"
|
|
"strings"
|
|
"strings"
|
|
"sync"
|
|
"sync"
|
|
|
|
+ "syscall"
|
|
"time"
|
|
"time"
|
|
|
|
|
|
"github.com/Sirupsen/logrus"
|
|
"github.com/Sirupsen/logrus"
|
|
@@ -1047,7 +1049,12 @@ func writeDistributionProgress(cancelFunc func(), outStream io.Writer, progressC
|
|
|
|
|
|
for prog := range progressChan {
|
|
for prog := range progressChan {
|
|
if err := progressOutput.WriteProgress(prog); err != nil && !operationCancelled {
|
|
if err := progressOutput.WriteProgress(prog); err != nil && !operationCancelled {
|
|
- logrus.Errorf("error writing progress to client: %v", err)
|
|
|
|
|
|
+ // don't log broken pipe errors as this is the normal case when a client aborts
|
|
|
|
+ if isBrokenPipe(err) {
|
|
|
|
+ logrus.Info("Pull session cancelled")
|
|
|
|
+ } else {
|
|
|
|
+ logrus.Errorf("error writing progress to client: %v", err)
|
|
|
|
+ }
|
|
cancelFunc()
|
|
cancelFunc()
|
|
operationCancelled = true
|
|
operationCancelled = true
|
|
// Don't return, because we need to continue draining
|
|
// Don't return, because we need to continue draining
|
|
@@ -1056,6 +1063,16 @@ func writeDistributionProgress(cancelFunc func(), outStream io.Writer, progressC
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+func isBrokenPipe(e error) bool {
|
|
|
|
+ if netErr, ok := e.(*net.OpError); ok {
|
|
|
|
+ e = netErr.Err
|
|
|
|
+ if sysErr, ok := netErr.Err.(*os.SyscallError); ok {
|
|
|
|
+ e = sysErr.Err
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ return e == syscall.EPIPE
|
|
|
|
+}
|
|
|
|
+
|
|
// PullImage initiates a pull operation. image is the repository name to pull, and
|
|
// PullImage initiates a pull operation. image is the repository name to pull, and
|
|
// tag may be either empty, or indicate a specific tag to pull.
|
|
// tag may be either empty, or indicate a specific tag to pull.
|
|
func (daemon *Daemon) PullImage(ref reference.Named, metaHeaders map[string][]string, authConfig *types.AuthConfig, outStream io.Writer) error {
|
|
func (daemon *Daemon) PullImage(ref reference.Named, metaHeaders map[string][]string, authConfig *types.AuthConfig, outStream io.Writer) error {
|