Browse Source

Do Docker edits so we can use the new distribution code

Signed-off-by: Doug Davis <dug@us.ibm.com>
Doug Davis 10 years ago
parent
commit
b874ef8f43

+ 15 - 3
graph/pull_v2.go

@@ -18,6 +18,7 @@ import (
 	"github.com/docker/docker/trust"
 	"github.com/docker/docker/trust"
 	"github.com/docker/docker/utils"
 	"github.com/docker/docker/utils"
 	"github.com/docker/libtrust"
 	"github.com/docker/libtrust"
+	"golang.org/x/net/context"
 )
 )
 
 
 type v2Puller struct {
 type v2Puller struct {
@@ -58,7 +59,13 @@ func (p *v2Puller) pullV2Repository(tag string) (err error) {
 		taggedName = utils.ImageReference(p.repoInfo.LocalName, tag)
 		taggedName = utils.ImageReference(p.repoInfo.LocalName, tag)
 	} else {
 	} else {
 		var err error
 		var err error
-		tags, err = p.repo.Manifests().Tags()
+
+		manSvc, err := p.repo.Manifests(context.Background())
+		if err != nil {
+			return err
+		}
+
+		tags, err = manSvc.Tags()
 		if err != nil {
 		if err != nil {
 			return err
 			return err
 		}
 		}
@@ -140,7 +147,7 @@ func (p *v2Puller) download(di *downloadInfo) {
 		di.err <- err
 		di.err <- err
 		return
 		return
 	}
 	}
-	di.size = desc.Length
+	di.size = desc.Size
 
 
 	layerDownload, err := blobs.Open(nil, di.digest)
 	layerDownload, err := blobs.Open(nil, di.digest)
 	if err != nil {
 	if err != nil {
@@ -187,7 +194,12 @@ func (p *v2Puller) pullV2Tag(tag, taggedName string) (bool, error) {
 	logrus.Debugf("Pulling tag from V2 registry: %q", tag)
 	logrus.Debugf("Pulling tag from V2 registry: %q", tag)
 	out := p.config.OutStream
 	out := p.config.OutStream
 
 
-	manifest, err := p.repo.Manifests().GetByTag(tag)
+	manSvc, err := p.repo.Manifests(context.Background())
+	if err != nil {
+		return false, err
+	}
+
+	manifest, err := manSvc.GetByTag(tag)
 	if err != nil {
 	if err != nil {
 		return false, err
 		return false, err
 	}
 	}

+ 6 - 1
graph/push_v2.go

@@ -16,6 +16,7 @@ import (
 	"github.com/docker/docker/registry"
 	"github.com/docker/docker/registry"
 	"github.com/docker/docker/runconfig"
 	"github.com/docker/docker/runconfig"
 	"github.com/docker/docker/utils"
 	"github.com/docker/docker/utils"
+	"golang.org/x/net/context"
 )
 )
 
 
 type v2Pusher struct {
 type v2Pusher struct {
@@ -191,7 +192,11 @@ func (p *v2Pusher) pushV2Tag(tag string) error {
 		out.Write(p.sf.FormatStatus("", "Digest: %s", manifestDigest))
 		out.Write(p.sf.FormatStatus("", "Digest: %s", manifestDigest))
 	}
 	}
 
 
-	return p.repo.Manifests().Put(signed)
+	manSvc, err := p.repo.Manifests(context.Background())
+	if err != nil {
+		return err
+	}
+	return manSvc.Put(signed)
 }
 }
 
 
 func (p *v2Pusher) pushV2Image(bs distribution.BlobService, img *image.Image) (digest.Digest, error) {
 func (p *v2Pusher) pushV2Image(bs distribution.BlobService, img *image.Image) (digest.Digest, error) {

+ 1 - 1
hack/vendor.sh

@@ -35,7 +35,7 @@ clone git github.com/coreos/go-etcd v2.0.0
 clone git github.com/hashicorp/consul v0.5.2
 clone git github.com/hashicorp/consul v0.5.2
 
 
 # get graph and distribution packages
 # get graph and distribution packages
-clone git github.com/docker/distribution 856638e299eddf01964fa918ac1552d8aa2e22b3
+clone git github.com/docker/distribution cd8ff553b6b1911be23dfeabb73e33108bcbf147
 clone git github.com/vbatts/tar-split v0.9.4
 clone git github.com/vbatts/tar-split v0.9.4
 
 
 clone git github.com/opencontainers/runc v0.0.2 # libcontainer
 clone git github.com/opencontainers/runc v0.0.2 # libcontainer

+ 19 - 8
vendor/src/github.com/docker/distribution/CONTRIBUTING.md

@@ -97,32 +97,43 @@ Unless explicitly stated, we follow all coding guidelines from the Go
 community. While some of these standards may seem arbitrary, they somehow seem
 community. While some of these standards may seem arbitrary, they somehow seem
 to result in a solid, consistent codebase.
 to result in a solid, consistent codebase.
 
 
+It is possible that the code base does not currently comply with these
+guidelines. We are not looking for a massive PR that fixes this, since that
+goes against the spirit of the guidelines. All new contributions should make a
+best effort to clean up and make the code base better than they left it.
+Obviously, apply your best judgement. Remember, the goal here is to make the
+code base easier for humans to navigate and understand. Always keep that in
+mind when nudging others to comply.
+
 The rules:
 The rules:
 
 
 1. All code should be formatted with `gofmt -s`.
 1. All code should be formatted with `gofmt -s`.
 2. All code should pass the default levels of
 2. All code should pass the default levels of
    [`golint`](https://github.com/golang/lint).
    [`golint`](https://github.com/golang/lint).
-3. All code should follow the guidelines covered at
-   https://github.com/golang/go/wiki/CodeReviewComments.
+3. All code should follow the guidelines covered in [Effective
+   Go](http://golang.org/doc/effective_go.html) and [Go Code Review
+   Comments](https://github.com/golang/go/wiki/CodeReviewComments).
 4. Comment the code. Tell us the why, the history and the context.
 4. Comment the code. Tell us the why, the history and the context.
 5. Document _all_ declarations and methods, even private ones. Declare
 5. Document _all_ declarations and methods, even private ones. Declare
    expectations, caveats and anything else that may be important. If a type
    expectations, caveats and anything else that may be important. If a type
    gets exported, having the comments already there will ensure it's ready.
    gets exported, having the comments already there will ensure it's ready.
-6. Variable name length should be proportional to it's context and no longer.
-   noALongVariableNameLikeThisIsNotMoreClearWhenASimpleCommentWouldDo. In
-   practice, short methods will have short variable names and globals will
+6. Variable name length should be proportional to its context and no longer.
+   `noCommaALongVariableNameLikeThisIsNotMoreClearWhenASimpleCommentWouldDo`.
+   In practice, short methods will have short variable names and globals will
    have longer names.
    have longer names.
 7. No underscores in package names. If you need a compound name, step back,
 7. No underscores in package names. If you need a compound name, step back,
    and re-examine why you need a compound name. If you still think you need a
    and re-examine why you need a compound name. If you still think you need a
    compound name, lose the underscore.
    compound name, lose the underscore.
 8. No utils or helpers packages. If a function is not general enough to
 8. No utils or helpers packages. If a function is not general enough to
-   warrant it's own package, it has not been written generally enough to be a
+   warrant its own package, it has not been written generally enough to be a
    part of a util package. Just leave it unexported and well-documented.
    part of a util package. Just leave it unexported and well-documented.
-9. No, we don't need another unit testing framework.
+9. All tests should run with `go test` and outside tooling should not be
+   required. No, we don't need another unit testing framework. Assertion
+   packages are acceptable if they provide _real_ incremental value.
 10. Even though we call these "rules" above, they are actually just
 10. Even though we call these "rules" above, they are actually just
     guidelines. Since you've read all the rules, you now know that.
     guidelines. Since you've read all the rules, you now know that.
 
 
 If you are having trouble getting into the mood of idiomatic Go, we recommend
 If you are having trouble getting into the mood of idiomatic Go, we recommend
-reading through [`Effective Go`](http://golang.org/doc/effective_go.html). The
+reading through [Effective Go](http://golang.org/doc/effective_go.html). The
 [Go Blog](http://blog.golang.org/) is also a great resource. Drinking the
 [Go Blog](http://blog.golang.org/) is also a great resource. Drinking the
 kool-aid is a lot easier than going thirsty.
 kool-aid is a lot easier than going thirsty.

+ 2 - 0
vendor/src/github.com/docker/distribution/README.md

@@ -7,6 +7,8 @@ for storing and distributing Docker images. It supersedes the [docker/docker-
 registry](https://github.com/docker/docker-registry) project with a new API
 registry](https://github.com/docker/docker-registry) project with a new API
 design, focused around security and performance.
 design, focused around security and performance.
 
 
+<img src="https://www.docker.com/sites/default/files/oyster-registry-3.png" width=200px/>
+
 This repository contains the following components:
 This repository contains the following components:
 
 
 |**Component**       |Description                                                                                                                                                                                         |
 |**Component**       |Description                                                                                                                                                                                         |

+ 6 - 0
vendor/src/github.com/docker/distribution/registry.go

@@ -35,6 +35,12 @@ type Namespace interface {
 	// registry may or may not have the repository but should always return a
 	// registry may or may not have the repository but should always return a
 	// reference.
 	// reference.
 	Repository(ctx context.Context, name string) (Repository, error)
 	Repository(ctx context.Context, name string) (Repository, error)
+
+	// Repositories fills 'repos' with a lexigraphically sorted catalog of repositories
+	// up to the size of 'repos' and returns the value 'n' for the number of entries
+	// which were filled.  'last' contains an offset in the catalog, and 'err' will be
+	// set to io.EOF if there are no more entries to obtain.
+	Repositories(ctx context.Context, repos []string, last string) (n int, err error)
 }
 }
 
 
 // ManifestServiceOption is a function argument for Manifest Service methods
 // ManifestServiceOption is a function argument for Manifest Service methods

+ 1 - 1
vendor/src/github.com/docker/distribution/registry/api/errcode/errors.go

@@ -106,7 +106,7 @@ func (e Error) ErrorCode() ErrorCode {
 func (e Error) Error() string {
 func (e Error) Error() string {
 	return fmt.Sprintf("%s: %s",
 	return fmt.Sprintf("%s: %s",
 		strings.ToLower(strings.Replace(e.Code.String(), "_", " ", -1)),
 		strings.ToLower(strings.Replace(e.Code.String(), "_", " ", -1)),
-		e.Code.Message())
+		e.Message)
 }
 }
 
 
 // WithDetail will return a new Error, based on the current one, but with
 // WithDetail will return a new Error, based on the current one, but with

+ 127 - 0
vendor/src/github.com/docker/distribution/registry/api/v2/descriptors.go

@@ -87,6 +87,30 @@ var (
 		Format:      "<digest>",
 		Format:      "<digest>",
 	}
 	}
 
 
+	linkHeader = ParameterDescriptor{
+		Name:        "Link",
+		Type:        "link",
+		Description: "RFC5988 compliant rel='next' with URL to next result set, if available",
+		Format:      `<<url>?n=<last n value>&last=<last entry from response>>; rel="next"`,
+	}
+
+	paginationParameters = []ParameterDescriptor{
+		{
+			Name:        "n",
+			Type:        "integer",
+			Description: "Limit the number of entries in each response. It not present, all entries will be returned.",
+			Format:      "<integer>",
+			Required:    false,
+		},
+		{
+			Name:        "last",
+			Type:        "string",
+			Description: "Result set will include values lexically after last.",
+			Format:      "<integer>",
+			Required:    false,
+		},
+	}
+
 	unauthorizedResponse = ResponseDescriptor{
 	unauthorizedResponse = ResponseDescriptor{
 		Description: "The client does not have access to the repository.",
 		Description: "The client does not have access to the repository.",
 		StatusCode:  http.StatusUnauthorized,
 		StatusCode:  http.StatusUnauthorized,
@@ -269,6 +293,9 @@ type ResponseDescriptor struct {
 	// Headers covers any headers that may be returned from the response.
 	// Headers covers any headers that may be returned from the response.
 	Headers []ParameterDescriptor
 	Headers []ParameterDescriptor
 
 
+	// Fields describes any fields that may be present in the response.
+	Fields []ParameterDescriptor
+
 	// ErrorCodes enumerates the error codes that may be returned along with
 	// ErrorCodes enumerates the error codes that may be returned along with
 	// the response.
 	// the response.
 	ErrorCodes []errcode.ErrorCode
 	ErrorCodes []errcode.ErrorCode
@@ -427,6 +454,36 @@ var routeDescriptors = []RouteDescriptor{
 							},
 							},
 						},
 						},
 					},
 					},
+					{
+						Description:     "Return a portion of the tags for the specified repository.",
+						PathParameters:  []ParameterDescriptor{nameParameterDescriptor},
+						QueryParameters: paginationParameters,
+						Successes: []ResponseDescriptor{
+							{
+								StatusCode:  http.StatusOK,
+								Description: "A list of tags for the named repository.",
+								Headers: []ParameterDescriptor{
+									{
+										Name:        "Content-Length",
+										Type:        "integer",
+										Description: "Length of the JSON response body.",
+										Format:      "<length>",
+									},
+									linkHeader,
+								},
+								Body: BodyDescriptor{
+									ContentType: "application/json; charset=utf-8",
+									Format: `{
+    "name": <name>,
+    "tags": [
+        <tag>,
+        ...
+    ],
+}`,
+								},
+							},
+						},
+					},
 				},
 				},
 			},
 			},
 		},
 		},
@@ -1320,6 +1377,76 @@ var routeDescriptors = []RouteDescriptor{
 			},
 			},
 		},
 		},
 	},
 	},
+	{
+		Name:        RouteNameCatalog,
+		Path:        "/v2/_catalog",
+		Entity:      "Catalog",
+		Description: "List a set of available repositories in the local registry cluster. Does not provide any indication of what may be available upstream. Applications can only determine if a repository is available but not if it is not available.",
+		Methods: []MethodDescriptor{
+			{
+				Method:      "GET",
+				Description: "Retrieve a sorted, json list of repositories available in the registry.",
+				Requests: []RequestDescriptor{
+					{
+						Name:        "Catalog Fetch Complete",
+						Description: "Request an unabridged list of repositories available.",
+						Successes: []ResponseDescriptor{
+							{
+								Description: "Returns the unabridged list of repositories as a json response.",
+								StatusCode:  http.StatusOK,
+								Headers: []ParameterDescriptor{
+									{
+										Name:        "Content-Length",
+										Type:        "integer",
+										Description: "Length of the JSON response body.",
+										Format:      "<length>",
+									},
+								},
+								Body: BodyDescriptor{
+									ContentType: "application/json; charset=utf-8",
+									Format: `{
+	"repositories": [
+		<name>,
+		...
+	]
+}`,
+								},
+							},
+						},
+					},
+					{
+						Name:            "Catalog Fetch Paginated",
+						Description:     "Return the specified portion of repositories.",
+						QueryParameters: paginationParameters,
+						Successes: []ResponseDescriptor{
+							{
+								StatusCode: http.StatusOK,
+								Body: BodyDescriptor{
+									ContentType: "application/json; charset=utf-8",
+									Format: `{
+	"repositories": [
+		<name>,
+		...
+	]
+	"next": "<url>?last=<name>&n=<last value of n>"
+}`,
+								},
+								Headers: []ParameterDescriptor{
+									{
+										Name:        "Content-Length",
+										Type:        "integer",
+										Description: "Length of the JSON response body.",
+										Format:      "<length>",
+									},
+									linkHeader,
+								},
+							},
+						},
+					},
+				},
+			},
+		},
+	},
 }
 }
 
 
 var routeDescriptorsMap map[string]RouteDescriptor
 var routeDescriptorsMap map[string]RouteDescriptor

+ 2 - 0
vendor/src/github.com/docker/distribution/registry/api/v2/routes.go

@@ -11,10 +11,12 @@ const (
 	RouteNameBlob            = "blob"
 	RouteNameBlob            = "blob"
 	RouteNameBlobUpload      = "blob-upload"
 	RouteNameBlobUpload      = "blob-upload"
 	RouteNameBlobUploadChunk = "blob-upload-chunk"
 	RouteNameBlobUploadChunk = "blob-upload-chunk"
+	RouteNameCatalog         = "catalog"
 )
 )
 
 
 var allEndpoints = []string{
 var allEndpoints = []string{
 	RouteNameManifest,
 	RouteNameManifest,
+	RouteNameCatalog,
 	RouteNameTags,
 	RouteNameTags,
 	RouteNameBlob,
 	RouteNameBlob,
 	RouteNameBlobUpload,
 	RouteNameBlobUpload,

+ 12 - 0
vendor/src/github.com/docker/distribution/registry/api/v2/urls.go

@@ -100,6 +100,18 @@ func (ub *URLBuilder) BuildBaseURL() (string, error) {
 	return baseURL.String(), nil
 	return baseURL.String(), nil
 }
 }
 
 
+// BuildCatalogURL constructs a url get a catalog of repositories
+func (ub *URLBuilder) BuildCatalogURL(values ...url.Values) (string, error) {
+	route := ub.cloneRoute(RouteNameCatalog)
+
+	catalogURL, err := route.URL()
+	if err != nil {
+		return "", err
+	}
+
+	return appendValuesURL(catalogURL, values...).String(), nil
+}
+
 // BuildTagsURL constructs a url to list the tags in the named repository.
 // BuildTagsURL constructs a url to list the tags in the named repository.
 func (ub *URLBuilder) BuildTagsURL(name string) (string, error) {
 func (ub *URLBuilder) BuildTagsURL(name string) (string, error) {
 	route := ub.cloneRoute(RouteNameTags)
 	route := ub.cloneRoute(RouteNameTags)

+ 0 - 7
vendor/src/github.com/docker/distribution/registry/client/errors.go

@@ -53,13 +53,6 @@ func handleErrorResponse(resp *http.Response) error {
 		err := parseHTTPErrorResponse(resp.Body)
 		err := parseHTTPErrorResponse(resp.Body)
 		if uErr, ok := err.(*UnexpectedHTTPResponseError); ok {
 		if uErr, ok := err.(*UnexpectedHTTPResponseError); ok {
 			return v2.ErrorCodeUnauthorized.WithDetail(uErr.Response)
 			return v2.ErrorCodeUnauthorized.WithDetail(uErr.Response)
-			/*
-				return &errcode.Error{
-					Code:    v2.ErrorCodeUnauthorized,
-					Message: v2.ErrorCodeUnauthorized.Message(),
-					Detail:  uErr.Response,
-				}
-			*/
 		}
 		}
 		return err
 		return err
 	}
 	}

+ 91 - 0
vendor/src/github.com/docker/distribution/registry/client/repository.go

@@ -21,6 +21,83 @@ import (
 	"github.com/docker/distribution/registry/storage/cache/memory"
 	"github.com/docker/distribution/registry/storage/cache/memory"
 )
 )
 
 
+// Registry provides an interface for calling Repositories, which returns a catalog of repositories.
+type Registry interface {
+	Repositories(ctx context.Context, repos []string, last string) (n int, err error)
+}
+
+// NewRegistry creates a registry namespace which can be used to get a listing of repositories
+func NewRegistry(ctx context.Context, baseURL string, transport http.RoundTripper) (Registry, error) {
+	ub, err := v2.NewURLBuilderFromString(baseURL)
+	if err != nil {
+		return nil, err
+	}
+
+	client := &http.Client{
+		Transport: transport,
+		Timeout:   1 * time.Minute,
+	}
+
+	return &registry{
+		client:  client,
+		ub:      ub,
+		context: ctx,
+	}, nil
+}
+
+type registry struct {
+	client  *http.Client
+	ub      *v2.URLBuilder
+	context context.Context
+}
+
+// Repositories returns a lexigraphically sorted catalog given a base URL.  The 'entries' slice will be filled up to the size
+// of the slice, starting at the value provided in 'last'.  The number of entries will be returned along with io.EOF if there
+// are no more entries
+func (r *registry) Repositories(ctx context.Context, entries []string, last string) (int, error) {
+	var numFilled int
+	var returnErr error
+
+	values := buildCatalogValues(len(entries), last)
+	u, err := r.ub.BuildCatalogURL(values)
+	if err != nil {
+		return 0, err
+	}
+
+	resp, err := r.client.Get(u)
+	if err != nil {
+		return 0, err
+	}
+	defer resp.Body.Close()
+
+	switch resp.StatusCode {
+	case http.StatusOK:
+		var ctlg struct {
+			Repositories []string `json:"repositories"`
+		}
+		decoder := json.NewDecoder(resp.Body)
+
+		if err := decoder.Decode(&ctlg); err != nil {
+			return 0, err
+		}
+
+		for cnt := range ctlg.Repositories {
+			entries[cnt] = ctlg.Repositories[cnt]
+		}
+		numFilled = len(ctlg.Repositories)
+
+		link := resp.Header.Get("Link")
+		if link == "" {
+			returnErr = io.EOF
+		}
+
+	default:
+		return 0, handleErrorResponse(resp)
+	}
+
+	return numFilled, returnErr
+}
+
 // NewRepository creates a new Repository for the given repository name and base URL
 // NewRepository creates a new Repository for the given repository name and base URL
 func NewRepository(ctx context.Context, name, baseURL string, transport http.RoundTripper) (distribution.Repository, error) {
 func NewRepository(ctx context.Context, name, baseURL string, transport http.RoundTripper) (distribution.Repository, error) {
 	if err := v2.ValidateRepositoryName(name); err != nil {
 	if err := v2.ValidateRepositoryName(name); err != nil {
@@ -444,3 +521,17 @@ func (bs *blobStatter) Stat(ctx context.Context, dgst digest.Digest) (distributi
 		return distribution.Descriptor{}, handleErrorResponse(resp)
 		return distribution.Descriptor{}, handleErrorResponse(resp)
 	}
 	}
 }
 }
+
+func buildCatalogValues(maxEntries int, last string) url.Values {
+	values := url.Values{}
+
+	if maxEntries > 0 {
+		values.Add("n", strconv.Itoa(maxEntries))
+	}
+
+	if last != "" {
+		values.Add("last", last)
+	}
+
+	return values
+}