diff --git a/glide.yaml b/glide.yaml index 50467459e2e4..86b079e001c0 100644 --- a/glide.yaml +++ b/glide.yaml @@ -75,6 +75,10 @@ import: - package: github.com/opencontainers/runc repo: git@github.com:openshift/opencontainers-runc version: openshift-3.9 +# cli +- package: github.com/docker/distribution + repo: git@github.com:openshift/docker-distribution + version: release-2.6.0 # ours: shared with kube, but forced by openshift # master diff --git a/pkg/oc/cli/cmd/image/mirror/mirror.go b/pkg/oc/cli/cmd/image/mirror/mirror.go index c986624b5cdc..2029ba4418d4 100644 --- a/pkg/oc/cli/cmd/image/mirror/mirror.go +++ b/pkg/oc/cli/cmd/image/mirror/mirror.go @@ -101,6 +101,12 @@ type pushOptions struct { AttemptS3BucketCopy []string } +// schema2ManifestOnly specifically requests a manifest list first +var schema2ManifestOnly = distribution.WithManifestMediaTypes([]string{ + manifestlist.MediaTypeManifestList, + schema2.MediaTypeManifest, +}) + // NewCommandMirrorImage copies images from one location to another. func NewCmdMirrorImage(name string, out, errOut io.Writer) *cobra.Command { o := &pushOptions{} @@ -398,8 +404,7 @@ func (o *pushOptions) Run() error { for srcDigestString, pushTargets := range src.digests { // load the manifest srcDigest := godigest.Digest(srcDigestString) - // var contentDigest godigest.Digest / client.ReturnContentDigest(&contentDigest), - srcManifest, err := manifests.Get(ctx, godigest.Digest(srcDigest), distribution.WithTag(manifestlist.MediaTypeManifestList), distribution.WithTag(schema2.MediaTypeManifest)) + srcManifest, err := manifests.Get(ctx, godigest.Digest(srcDigest), schema2ManifestOnly) if err != nil { digestErrs = append(digestErrs, retrieverError{src: src.ref, err: fmt.Errorf("unable to retrieve source image %s manifest: %v", src.ref, err)}) continue diff --git a/vendor/github.com/docker/distribution/registry.go b/vendor/github.com/docker/distribution/registry.go index 1da1d533ff75..dd5509adc5de 100644 --- a/vendor/github.com/docker/distribution/registry.go +++ b/vendor/github.com/docker/distribution/registry.go @@ -72,6 +72,21 @@ func (o WithTagOption) Apply(m ManifestService) error { return nil } +// WithManifestMediaTypes lists the media types the client wishes +// the server to provide. +func WithManifestMediaTypes(mediaTypes []string) ManifestServiceOption { + return WithManifestMediaTypesOption{mediaTypes} +} + +// WithManifestMediaTypesOption holds a list of accepted media types +type WithManifestMediaTypesOption struct{ MediaTypes []string } + +// Apply conforms to the ManifestServiceOption interface +func (o WithManifestMediaTypesOption) Apply(m ManifestService) error { + // no implementation + return nil +} + // Repository is a named collection of manifests and layers. type Repository interface { // Named returns the name of the repository. diff --git a/vendor/github.com/docker/distribution/registry/client/repository.go b/vendor/github.com/docker/distribution/registry/client/repository.go index b82a968e28ac..d783e3df055e 100644 --- a/vendor/github.com/docker/distribution/registry/client/repository.go +++ b/vendor/github.com/docker/distribution/registry/client/repository.go @@ -421,18 +421,22 @@ func (ms *manifests) Get(ctx context.Context, dgst digest.Digest, options ...dis ref reference.Named err error contentDgst *digest.Digest + mediaTypes []string ) for _, option := range options { - if opt, ok := option.(distribution.WithTagOption); ok { + switch opt := option.(type) { + case distribution.WithTagOption: digestOrTag = opt.Tag ref, err = reference.WithTag(ms.name, opt.Tag) if err != nil { return nil, err } - } else if opt, ok := option.(contentDigestOption); ok { + case contentDigestOption: contentDgst = opt.digest - } else { + case distribution.WithManifestMediaTypesOption: + mediaTypes = opt.MediaTypes + default: err := option.Apply(ms) if err != nil { return nil, err @@ -448,6 +452,10 @@ func (ms *manifests) Get(ctx context.Context, dgst digest.Digest, options ...dis } } + if len(mediaTypes) == 0 { + mediaTypes = distribution.ManifestMediaTypes() + } + u, err := ms.ub.BuildManifestURL(ref) if err != nil { return nil, err @@ -458,7 +466,7 @@ func (ms *manifests) Get(ctx context.Context, dgst digest.Digest, options ...dis return nil, err } - for _, t := range distribution.ManifestMediaTypes() { + for _, t := range mediaTypes { req.Header.Add("Accept", t) } diff --git a/vendor/github.com/docker/distribution/registry/client/repository_test.go b/vendor/github.com/docker/distribution/registry/client/repository_test.go index f22fa33d4154..ef53397564e3 100644 --- a/vendor/github.com/docker/distribution/registry/client/repository_test.go +++ b/vendor/github.com/docker/distribution/registry/client/repository_test.go @@ -9,6 +9,8 @@ import ( "log" "net/http" "net/http/httptest" + "reflect" + "sort" "strconv" "strings" "testing" @@ -784,6 +786,65 @@ func TestManifestFetchWithEtag(t *testing.T) { } } +func TestManifestFetchWithAccept(t *testing.T) { + ctx := context.Background() + repo, _ := reference.WithName("test.example.com/repo") + _, dgst, _ := newRandomSchemaV1Manifest(repo, "latest", 6) + headers := make(chan []string, 1) + s := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { + headers <- req.Header["Accept"] + })) + defer close(headers) + defer s.Close() + + r, err := NewRepository(context.Background(), repo, s.URL, nil) + if err != nil { + t.Fatal(err) + } + ms, err := r.Manifests(ctx) + if err != nil { + t.Fatal(err) + } + + testCases := []struct { + // the media types we send + mediaTypes []string + // the expected Accept headers the server should receive + expect []string + // whether to sort the request and response values for comparison + sort bool + }{ + { + mediaTypes: []string{}, + expect: distribution.ManifestMediaTypes(), + sort: true, + }, + { + mediaTypes: []string{"test1", "test2"}, + expect: []string{"test1", "test2"}, + }, + { + mediaTypes: []string{"test1"}, + expect: []string{"test1"}, + }, + { + mediaTypes: []string{""}, + expect: []string{""}, + }, + } + for _, testCase := range testCases { + ms.Get(ctx, dgst, distribution.WithManifestMediaTypes(testCase.mediaTypes)) + actual := <-headers + if testCase.sort { + sort.Strings(actual) + sort.Strings(testCase.expect) + } + if !reflect.DeepEqual(actual, testCase.expect) { + t.Fatalf("unexpected Accept header values: %v", actual) + } + } +} + func TestManifestDelete(t *testing.T) { repo, _ := reference.WithName("test.example.com/repo/delete") _, dgst1, _ := newRandomSchemaV1Manifest(repo, "latest", 6)