From 071cb1bc2d82866f06c25da467511a53daf45fb2 Mon Sep 17 00:00:00 2001 From: Wenkai Yin Date: Wed, 5 Jun 2019 18:13:33 +0800 Subject: [PATCH] Fix replication bug Fixes #7875, fixes #7968 Signed-off-by: Wenkai Yin --- src/core/api/repository.go | 26 ++++++++++++++++++---- src/replication/transfer/image/transfer.go | 12 +++++----- 2 files changed, 27 insertions(+), 11 deletions(-) diff --git a/src/core/api/repository.go b/src/core/api/repository.go index 12659b48c..be19655c9 100644 --- a/src/core/api/repository.go +++ b/src/core/api/repository.go @@ -25,6 +25,7 @@ import ( "time" "errors" + "github.com/docker/distribution/manifest/schema1" "github.com/docker/distribution/manifest/schema2" "github.com/goharbor/harbor/src/common" @@ -682,14 +683,17 @@ func getTagDetail(client *registry.Repository, tag string) (*tagDetail, error) { Name: tag, } - digest, _, payload, err := client.PullManifest(tag, []string{schema2.MediaTypeManifest}) + digest, mediaType, payload, err := client.PullManifest(tag, []string{schema2.MediaTypeManifest}) if err != nil { return detail, err } detail.Digest = digest - manifest := &schema2.DeserializedManifest{} - if err = manifest.UnmarshalJSON(payload); err != nil { + if strings.Contains(mediaType, "application/json") { + mediaType = schema1.MediaTypeManifest + } + manifest, _, err := registry.UnMarshal(mediaType, payload) + if err != nil { return detail, err } @@ -699,7 +703,21 @@ func getTagDetail(client *registry.Repository, tag string) (*tagDetail, error) { detail.Size += ref.Size } - _, reader, err := client.PullBlob(manifest.Target().Digest.String()) + // if the media type of the manifest isn't v2, doesn't parse image config + // and return directly + // this impacts that some detail information(os, arch, ...) of old images + // cannot be got + if mediaType != schema2.MediaTypeManifest { + log.Debugf("the media type of the manifest is %s, not v2, skip", mediaType) + return detail, nil + } + v2Manifest, ok := manifest.(*schema2.DeserializedManifest) + if !ok { + log.Debug("the manifest cannot be convert to DeserializedManifest, skip") + return detail, nil + } + + _, reader, err := client.PullBlob(v2Manifest.Target().Digest.String()) if err != nil { return detail, err } diff --git a/src/replication/transfer/image/transfer.go b/src/replication/transfer/image/transfer.go index e47526b1b..42064841c 100644 --- a/src/replication/transfer/image/transfer.go +++ b/src/replication/transfer/image/transfer.go @@ -211,18 +211,15 @@ func (t *transfer) copyContent(content distribution.Descriptor, srcRepo, dstRepo case schema2.MediaTypeManifest: // as using digest as the reference, so set the override to true directly return t.copyImage(srcRepo, digest, dstRepo, digest, true) - // copy layer or image config - case schema2.MediaTypeLayer, schema2.MediaTypeImageConfig: - return t.copyBlob(srcRepo, dstRepo, digest) // handle foreign layer case schema2.MediaTypeForeignLayer: t.logger.Infof("the layer %s is a foreign layer, skip", digest) return nil - // others + // copy layer or image config + // the media type of the layer or config can be "application/octet-stream", + // schema1.MediaTypeManifestLayer, schema2.MediaTypeLayer, schema2.MediaTypeImageConfig default: - err := fmt.Errorf("unsupported media type: %s", content.MediaType) - t.logger.Error(err.Error()) - return err + return t.copyBlob(srcRepo, dstRepo, digest) } } @@ -288,6 +285,7 @@ func (t *transfer) handleManifest(manifest distribution.Manifest, repository, di } // manifest if mediaType == schema1.MediaTypeManifest || + mediaType == schema1.MediaTypeSignedManifest || mediaType == schema2.MediaTypeManifest { return manifest, digest, nil }