Skip to content

Commit 19a93a6

Browse files
committed
Update pull error handling
Translate pull errors to provide a more consistent and user friendly error message. Signed-off-by: Derek McGowan <[email protected]> (github: dmcgowan)
1 parent c85eb00 commit 19a93a6

4 files changed

Lines changed: 45 additions & 18 deletions

File tree

distribution/errors.go

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,14 @@ import (
55
"strings"
66
"syscall"
77

8+
"github.com/Sirupsen/logrus"
89
"github.com/docker/distribution/registry/api/errcode"
910
"github.com/docker/distribution/registry/api/v2"
1011
"github.com/docker/distribution/registry/client"
1112
"github.com/docker/distribution/registry/client/auth"
1213
"github.com/docker/docker/distribution/xfer"
14+
"github.com/docker/docker/reference"
15+
"github.com/pkg/errors"
1316
)
1417

1518
// ErrNoSupport is an error type used for errors indicating that an operation
@@ -56,6 +59,37 @@ func shouldV2Fallback(err errcode.Error) bool {
5659
return false
5760
}
5861

62+
func translatePullError(err error, ref reference.Named) error {
63+
switch v := err.(type) {
64+
case errcode.Errors:
65+
if len(v) != 0 {
66+
for _, extra := range v[1:] {
67+
logrus.Infof("Ignoring extra error returned from registry: %v", extra)
68+
}
69+
return translatePullError(v[0], ref)
70+
}
71+
case errcode.Error:
72+
var newErr error
73+
switch v.Code {
74+
case errcode.ErrorCodeDenied:
75+
// ErrorCodeDenied is used when access to the repository was denied
76+
newErr = errors.Errorf("repository %s not found: does not exist or no read access", ref.Name())
77+
case v2.ErrorCodeManifestUnknown:
78+
newErr = errors.Errorf("manifest for %s not found", ref.String())
79+
case v2.ErrorCodeNameUnknown:
80+
newErr = errors.Errorf("repository %s not found", ref.Name())
81+
}
82+
if newErr != nil {
83+
logrus.Infof("Translating %q to %q", err, newErr)
84+
return newErr
85+
}
86+
case xfer.DoNotRetry:
87+
return translatePullError(v.Err, ref)
88+
}
89+
90+
return err
91+
}
92+
5993
// continueOnError returns true if we should fallback to the next endpoint
6094
// as a result of this error.
6195
func continueOnError(err error) bool {

distribution/pull.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -168,7 +168,7 @@ func Pull(ctx context.Context, ref reference.Named, imagePullConfig *ImagePullCo
168168
continue
169169
}
170170
logrus.Errorf("Not continuing with pull after error: %v", err)
171-
return err
171+
return translatePullError(err, ref)
172172
}
173173

174174
imagePullConfig.ImageEventLogger(ref.String(), repoInfo.Name(), "pull")
@@ -179,7 +179,7 @@ func Pull(ctx context.Context, ref reference.Named, imagePullConfig *ImagePullCo
179179
lastErr = fmt.Errorf("no endpoints found for %s", ref.String())
180180
}
181181

182-
return lastErr
182+
return translatePullError(lastErr, ref)
183183
}
184184

185185
// writeStatus writes a status message to out. If layersDownloaded is true, the

integration-cli/docker_cli_by_digest_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,7 @@ func testPullByDigestNoFallback(c *check.C) {
114114
imageReference := fmt.Sprintf("%s@sha256:ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", repoName)
115115
out, _, err := dockerCmdWithError("pull", imageReference)
116116
c.Assert(err, checker.NotNil, check.Commentf("expected non-zero exit status and correct error message when pulling non-existing image"))
117-
c.Assert(out, checker.Contains, "manifest unknown", check.Commentf("expected non-zero exit status and correct error message when pulling non-existing image"))
117+
c.Assert(out, checker.Contains, fmt.Sprintf("manifest for %s not found", imageReference), check.Commentf("expected non-zero exit status and correct error message when pulling non-existing image"))
118118
}
119119

120120
func (s *DockerRegistrySuite) TestPullByDigestNoFallback(c *check.C) {

integration-cli/docker_cli_pull_test.go

Lines changed: 8 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -48,12 +48,12 @@ func (s *DockerHubPullSuite) TestPullNonExistingImage(c *check.C) {
4848
}
4949

5050
entries := []entry{
51-
{"library/asdfasdf", "asdfasdf", "foobar"},
52-
{"library/asdfasdf", "library/asdfasdf", "foobar"},
53-
{"library/asdfasdf", "asdfasdf", ""},
54-
{"library/asdfasdf", "asdfasdf", "latest"},
55-
{"library/asdfasdf", "library/asdfasdf", ""},
56-
{"library/asdfasdf", "library/asdfasdf", "latest"},
51+
{"asdfasdf", "asdfasdf", "foobar"},
52+
{"asdfasdf", "library/asdfasdf", "foobar"},
53+
{"asdfasdf", "asdfasdf", ""},
54+
{"asdfasdf", "asdfasdf", "latest"},
55+
{"asdfasdf", "library/asdfasdf", ""},
56+
{"asdfasdf", "library/asdfasdf", "latest"},
5757
}
5858

5959
// The option field indicates "-a" or not.
@@ -98,18 +98,11 @@ func (s *DockerHubPullSuite) TestPullNonExistingImage(c *check.C) {
9898
for record := range recordChan {
9999
if len(record.option) == 0 {
100100
c.Assert(record.err, checker.NotNil, check.Commentf("expected non-zero exit status when pulling non-existing image: %s", record.out))
101-
// Hub returns 401 rather than 404 for nonexistent repos over
102-
// the v2 protocol - but we should end up falling back to v1,
103-
// which does return a 404.
104-
tag := record.e.tag
105-
if tag == "" {
106-
tag = "latest"
107-
}
108-
c.Assert(record.out, checker.Contains, fmt.Sprintf("Error: image %s:%s not found", record.e.repo, tag), check.Commentf("expected image not found error messages"))
101+
c.Assert(record.out, checker.Contains, fmt.Sprintf("repository %s not found: does not exist or no read access", record.e.repo), check.Commentf("expected image not found error messages"))
109102
} else {
110103
// pull -a on a nonexistent registry should fall back as well
111104
c.Assert(record.err, checker.NotNil, check.Commentf("expected non-zero exit status when pulling non-existing image: %s", record.out))
112-
c.Assert(record.out, checker.Contains, fmt.Sprintf("Error: image %s not found", record.e.repo), check.Commentf("expected image not found error messages"))
105+
c.Assert(record.out, checker.Contains, fmt.Sprintf("repository %s not found", record.e.repo), check.Commentf("expected image not found error messages"))
113106
c.Assert(record.out, checker.Not(checker.Contains), "unauthorized", check.Commentf(`message should not contain "unauthorized"`))
114107
}
115108
}

0 commit comments

Comments
 (0)