Skip to content

Commit

Permalink
Merge pull request moby#21283 from runcom/update-test
Browse files Browse the repository at this point in the history
vendor docker/distribution d06d6d3
  • Loading branch information
LK4D4 committed Mar 21, 2016
2 parents 2a4c970 + 264b5b6 commit a05fdd6
Show file tree
Hide file tree
Showing 12 changed files with 110 additions and 62 deletions.
3 changes: 2 additions & 1 deletion distribution/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,8 @@ func retryOnError(err error) error {
return xfer.DoNotRetry{Err: err}
}
case *url.Error:
if v.Err == auth.ErrNoBasicAuthCredentials {
switch v.Err {
case auth.ErrNoBasicAuthCredentials, auth.ErrNoToken:
return xfer.DoNotRetry{Err: v.Err}
}
return retryOnError(v.Err)
Expand Down
2 changes: 1 addition & 1 deletion hack/vendor.sh
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ clone git github.com/boltdb/bolt v1.1.0
clone git github.com/miekg/dns 75e6e86cc601825c5dbcd4e0c209eab180997cd7

# get graph and distribution packages
clone git github.com/docker/distribution db17a23b961978730892e12a0c6051d43a31aab3
clone git github.com/docker/distribution d06d6d3b093302c02a93153ac7b06ebc0ffd1793
clone git github.com/vbatts/tar-split v0.9.11

# get desired notary commit, might also need to be updated in Dockerfile
Expand Down
65 changes: 54 additions & 11 deletions integration-cli/docker_cli_push_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -546,35 +546,78 @@ func (s *DockerSuite) TestPushToCentralRegistryUnauthorized(c *check.C) {
dockerCmd(c, "tag", "busybox", repoName)
out, _, err := dockerCmdWithError("push", repoName)
c.Assert(err, check.NotNil, check.Commentf(out))
c.Assert(out, check.Not(checker.Contains), "Retrying")
c.Assert(out, checker.Contains, "unauthorized: access to the requested resource is not authorized")
}

func (s *DockerRegistryAuthTokenSuite) TestPushTokenServiceUnauthResponse(c *check.C) {
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusUnauthorized)
func getTestTokenService(status int, body string) *httptest.Server {
return httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(status)
w.Header().Set("Content-Type", "application/json")
w.Write([]byte(`{"errors": [{"Code":"UNAUTHORIZED", "message": "a message", "detail": null}]}`))
w.Write([]byte(body))
}))
}

func (s *DockerRegistryAuthTokenSuite) TestPushTokenServiceUnauthResponse(c *check.C) {
ts := getTestTokenService(http.StatusUnauthorized, `{"errors": [{"Code":"UNAUTHORIZED", "message": "a message", "detail": null}]}`)
defer ts.Close()
s.setupRegistryWithTokenService(c, ts.URL)
repoName := fmt.Sprintf("%s/busybox", privateRegistryURL)
dockerCmd(c, "tag", "busybox", repoName)
out, _, err := dockerCmdWithError("push", repoName)
c.Assert(err, check.NotNil, check.Commentf(out))
c.Assert(out, checker.Not(checker.Contains), "Retrying")
c.Assert(out, checker.Contains, "unauthorized: a message")
}

func (s *DockerRegistryAuthTokenSuite) TestPushMisconfiguredTokenServiceResponse(c *check.C) {
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusUnauthorized)
w.Header().Set("Content-Type", "application/json")
// this will make the daemon panics if no check is performed in retryOnError
w.Write([]byte(`{"error": "unauthorized"}`))
}))
func (s *DockerRegistryAuthTokenSuite) TestPushMisconfiguredTokenServiceResponseUnauthorized(c *check.C) {
ts := getTestTokenService(http.StatusUnauthorized, `{"error": "unauthorized"}`)
defer ts.Close()
s.setupRegistryWithTokenService(c, ts.URL)
repoName := fmt.Sprintf("%s/busybox", privateRegistryURL)
dockerCmd(c, "tag", "busybox", repoName)
out, _, err := dockerCmdWithError("push", repoName)
c.Assert(err, check.NotNil, check.Commentf(out))
c.Assert(out, checker.Not(checker.Contains), "Retrying")
split := strings.Split(out, "\n")
c.Assert(split[len(split)-2], check.Equals, "unauthorized: authentication required")
}

func (s *DockerRegistryAuthTokenSuite) TestPushMisconfiguredTokenServiceResponseError(c *check.C) {
ts := getTestTokenService(http.StatusInternalServerError, `{"error": "unexpected"}`)
defer ts.Close()
s.setupRegistryWithTokenService(c, ts.URL)
repoName := fmt.Sprintf("%s/busybox", privateRegistryURL)
dockerCmd(c, "tag", "busybox", repoName)
out, _, err := dockerCmdWithError("push", repoName)
c.Assert(err, check.NotNil, check.Commentf(out))
c.Assert(out, checker.Contains, "Retrying")
split := strings.Split(out, "\n")
c.Assert(split[len(split)-2], check.Equals, "received unexpected HTTP status: 500 Internal Server Error")
}

func (s *DockerRegistryAuthTokenSuite) TestPushMisconfiguredTokenServiceResponseUnparsable(c *check.C) {
ts := getTestTokenService(http.StatusForbidden, `no way`)
defer ts.Close()
s.setupRegistryWithTokenService(c, ts.URL)
repoName := fmt.Sprintf("%s/busybox", privateRegistryURL)
dockerCmd(c, "tag", "busybox", repoName)
out, _, err := dockerCmdWithError("push", repoName)
c.Assert(err, check.NotNil, check.Commentf(out))
c.Assert(out, checker.Not(checker.Contains), "Retrying")
split := strings.Split(out, "\n")
c.Assert(split[len(split)-2], checker.Contains, "error parsing HTTP 403 response body: ")
}

func (s *DockerRegistryAuthTokenSuite) TestPushMisconfiguredTokenServiceResponseNoToken(c *check.C) {
ts := getTestTokenService(http.StatusOK, `{"something": "wrong"}`)
defer ts.Close()
s.setupRegistryWithTokenService(c, ts.URL)
repoName := fmt.Sprintf("%s/busybox", privateRegistryURL)
dockerCmd(c, "tag", "busybox", repoName)
out, _, err := dockerCmdWithError("push", repoName)
c.Assert(err, check.NotNil, check.Commentf(out))
c.Assert(out, checker.Not(checker.Contains), "Retrying")
split := strings.Split(out, "\n")
c.Assert(split[len(split)-2], check.Equals, "authorization server did not include a token in the response")
}
4 changes: 2 additions & 2 deletions vendor/src/github.com/docker/distribution/CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ Some simple rules to ensure quick merge:
You are heavily encouraged to first discuss what you want to do. You can do so on the irc channel, or by opening an issue that clearly describes the use case you want to fulfill, or the problem you are trying to solve.

If this is a major new feature, you should then submit a proposal that describes your technical solution and reasoning.
If you did discuss it first, this will likely be greenlighted very fast. It's advisable to address all feedback on this proposal before starting actual work.
If you did discuss it first, this will likely be greenlighted very fast. It's advisable to address all feedback on this proposal before starting actual work.

Then you should submit your implementation, clearly linking to the issue (and possible proposal).

Expand All @@ -90,7 +90,7 @@ It's mandatory to:

Complying to these simple rules will greatly accelerate the review process, and will ensure you have a pleasant experience in contributing code to the Registry.

Have a look at a great, successful contribution: the [Ceph driver PR](https://github.com/docker/distribution/pull/443)
Have a look at a great, successful contribution: the [Swift driver PR](https://github.com/docker/distribution/pull/493)

## Coding Style

Expand Down
4 changes: 2 additions & 2 deletions vendor/src/github.com/docker/distribution/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
FROM golang:1.5.3

RUN apt-get update && \
apt-get install -y librados-dev apache2-utils && \
apt-get install -y apache2-utils && \
rm -rf /var/lib/apt/lists/*

ENV DISTRIBUTION_DIR /go/src/github.com/docker/distribution
ENV GOPATH $DISTRIBUTION_DIR/Godeps/_workspace:$GOPATH
ENV DOCKER_BUILDTAGS include_rados include_oss include_gcs
ENV DOCKER_BUILDTAGS include_oss include_gcs

WORKDIR $DISTRIBUTION_DIR
COPY . $DISTRIBUTION_DIR
Expand Down
9 changes: 4 additions & 5 deletions vendor/src/github.com/docker/distribution/blobs.go
Original file line number Diff line number Diff line change
Expand Up @@ -189,9 +189,11 @@ type BlobCreateOption interface {
// BlobWriteService.Resume. If supported by the store, a writer can be
// recovered with the id.
type BlobWriter interface {
io.WriteSeeker
io.WriteCloser
io.ReaderFrom
io.Closer

// Size returns the number of bytes written to this blob.
Size() int64

// ID returns the identifier for this writer. The ID can be used with the
// Blob service to later resume the write.
Expand All @@ -216,9 +218,6 @@ type BlobWriter interface {
// result in a no-op. This allows use of Cancel in a defer statement,
// increasing the assurance that it is correctly called.
Cancel(ctx context.Context) error

// Get a reader to the blob being written by this BlobWriter
Reader() (io.ReadCloser, error)
}

// BlobService combines the operations to access, read and write blobs. This
Expand Down
7 changes: 1 addition & 6 deletions vendor/src/github.com/docker/distribution/circle.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,6 @@ machine:
pre:
# Install gvm
- bash < <(curl -s -S -L https://raw.githubusercontent.com/moovweb/gvm/1.0.22/binscripts/gvm-installer)
# Install ceph to test rados driver & create pool
- sudo -i ~/distribution/contrib/ceph/ci-setup.sh
- ceph osd pool create docker-distribution 1
# Install codecov for coverage
- pip install --user codecov

Expand All @@ -19,11 +16,9 @@ machine:
BASE_DIR: src/github.com/$CIRCLE_PROJECT_USERNAME/$CIRCLE_PROJECT_REPONAME
# Trick circle brainflat "no absolute path" behavior
BASE_STABLE: ../../../$HOME/.gvm/pkgsets/stable/global/$BASE_DIR
DOCKER_BUILDTAGS: "include_rados include_oss include_gcs"
DOCKER_BUILDTAGS: "include_oss include_gcs"
# Workaround Circle parsing dumb bugs and/or YAML wonkyness
CIRCLE_PAIN: "mode: set"
# Ceph config
RADOS_POOL: "docker-distribution"

hosts:
# Not used yet
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ type Challenge struct {
type ChallengeManager interface {
// GetChallenges returns the challenges for the given
// endpoint URL.
GetChallenges(endpoint string) ([]Challenge, error)
GetChallenges(endpoint url.URL) ([]Challenge, error)

// AddResponse adds the response to the challenge
// manager. The challenges will be parsed out of
Expand All @@ -48,8 +48,10 @@ func NewSimpleChallengeManager() ChallengeManager {

type simpleChallengeManager map[string][]Challenge

func (m simpleChallengeManager) GetChallenges(endpoint string) ([]Challenge, error) {
challenges := m[endpoint]
func (m simpleChallengeManager) GetChallenges(endpoint url.URL) ([]Challenge, error) {
endpoint.Host = strings.ToLower(endpoint.Host)

challenges := m[endpoint.String()]
return challenges, nil
}

Expand All @@ -60,11 +62,10 @@ func (m simpleChallengeManager) AddResponse(resp *http.Response) error {
}
urlCopy := url.URL{
Path: resp.Request.URL.Path,
Host: resp.Request.URL.Host,
Host: strings.ToLower(resp.Request.URL.Host),
Scheme: resp.Request.URL.Scheme,
}
m[urlCopy.String()] = challenges

return nil
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,15 @@ import (
"github.com/docker/distribution/registry/client/transport"
)

// ErrNoBasicAuthCredentials is returned if a request can't be authorized with
// basic auth due to lack of credentials.
var ErrNoBasicAuthCredentials = errors.New("no basic auth credentials")
var (
// ErrNoBasicAuthCredentials is returned if a request can't be authorized with
// basic auth due to lack of credentials.
ErrNoBasicAuthCredentials = errors.New("no basic auth credentials")

// ErrNoToken is returned if a request is successful but the body does not
// contain an authorization token.
ErrNoToken = errors.New("authorization server did not include a token in the response")
)

const defaultClientID = "registry-client"

Expand Down Expand Up @@ -77,9 +83,7 @@ func (ea *endpointAuthorizer) ModifyRequest(req *http.Request) error {
Path: req.URL.Path[:v2Root+4],
}

pingEndpoint := ping.String()

challenges, err := ea.challenges.GetChallenges(pingEndpoint)
challenges, err := ea.challenges.GetChallenges(ping)
if err != nil {
return err
}
Expand Down Expand Up @@ -404,7 +408,7 @@ func (th *tokenHandler) fetchTokenWithBasicAuth(realm *url.URL, service string,
}

if tr.Token == "" {
return "", time.Time{}, errors.New("authorization server did not include a token in the response")
return "", time.Time{}, ErrNoToken
}

if tr.ExpiresIn < minimumTokenLifetimeSeconds {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import (
"io"
"io/ioutil"
"net/http"
"os"
"time"

"github.com/docker/distribution"
Expand Down Expand Up @@ -104,21 +103,8 @@ func (hbu *httpBlobUpload) Write(p []byte) (n int, err error) {

}

func (hbu *httpBlobUpload) Seek(offset int64, whence int) (int64, error) {
newOffset := hbu.offset

switch whence {
case os.SEEK_CUR:
newOffset += int64(offset)
case os.SEEK_END:
newOffset += int64(offset)
case os.SEEK_SET:
newOffset = int64(offset)
}

hbu.offset = newOffset

return hbu.offset, nil
func (hbu *httpBlobUpload) Size() int64 {
return hbu.offset
}

func (hbu *httpBlobUpload) ID() string {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package client

import (
"encoding/json"
"errors"
"fmt"
"io"
"io/ioutil"
Expand All @@ -10,25 +11,30 @@ import (
"github.com/docker/distribution/registry/api/errcode"
)

// ErrNoErrorsInBody is returned when a HTTP response body parses to an empty
// errcode.Errors slice.
var ErrNoErrorsInBody = errors.New("no error details found in HTTP response body")

// UnexpectedHTTPStatusError is returned when an unexpected HTTP status is
// returned when making a registry api call.
type UnexpectedHTTPStatusError struct {
Status string
}

func (e *UnexpectedHTTPStatusError) Error() string {
return fmt.Sprintf("Received unexpected HTTP status: %s", e.Status)
return fmt.Sprintf("received unexpected HTTP status: %s", e.Status)
}

// UnexpectedHTTPResponseError is returned when an expected HTTP status code
// is returned, but the content was unexpected and failed to be parsed.
type UnexpectedHTTPResponseError struct {
ParseErr error
Response []byte
ParseErr error
StatusCode int
Response []byte
}

func (e *UnexpectedHTTPResponseError) Error() string {
return fmt.Sprintf("Error parsing HTTP response: %s: %q", e.ParseErr.Error(), string(e.Response))
return fmt.Sprintf("error parsing HTTP %d response body: %s: %q", e.StatusCode, e.ParseErr.Error(), string(e.Response))
}

func parseHTTPErrorResponse(statusCode int, r io.Reader) error {
Expand All @@ -53,10 +59,22 @@ func parseHTTPErrorResponse(statusCode int, r io.Reader) error {

if err := json.Unmarshal(body, &errors); err != nil {
return &UnexpectedHTTPResponseError{
ParseErr: err,
Response: body,
ParseErr: err,
StatusCode: statusCode,
Response: body,
}
}

if len(errors) == 0 {
// If there was no error specified in the body, return
// UnexpectedHTTPResponseError.
return &UnexpectedHTTPResponseError{
ParseErr: ErrNoErrorsInBody,
StatusCode: statusCode,
Response: body,
}
}

return errors
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -308,6 +308,7 @@ check:
if err != nil {
return distribution.Descriptor{}, err
}
defer resp.Body.Close()

switch {
case resp.StatusCode >= 200 && resp.StatusCode < 400:
Expand Down

0 comments on commit a05fdd6

Please sign in to comment.