Skip to content

Commit

Permalink
Return manifest info from remote directly when use digest pull
Browse files Browse the repository at this point in the history
  • Loading branch information
wangqiang committed Oct 18, 2024
1 parent 6471bed commit 3b40e95
Show file tree
Hide file tree
Showing 6 changed files with 59 additions and 1 deletion.
1 change: 1 addition & 0 deletions errors/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -173,4 +173,5 @@ var (
ErrInvalidSearchQuery = errors.New("invalid search query")
ErrImageNotFound = errors.New("image not found")
ErrAmbiguousInput = errors.New("input is not specific enough")
ErrPullByNonOCIDigest = errors.New("pull image with Non OCI digest")
)
9 changes: 9 additions & 0 deletions pkg/api/routes.go
Original file line number Diff line number Diff line change
Expand Up @@ -2023,6 +2023,15 @@ func getImageManifest(ctx context.Context, routeHandler *RouteHandler, imgStore
Msg("trying to get updated image by syncing on demand")

if errSync := routeHandler.c.SyncOnDemand.SyncImage(ctx, name, reference); errSync != nil {
if errors.Is(errSync, zerr.ErrPullByNonOCIDigest) {
routeHandler.c.Log.Err(errSync).Str("repository", name).Str("reference", reference).
Msg("sync failed cause image is not OCI image, return data directly from remote")
details := zerr.GetDetails(errSync)
d, err := godigest.Parse(details["srcDigest"])
if err == nil {
return []byte(details["srcManifest"]), d, details["srcMediaType"], err
}
}
routeHandler.c.Log.Err(errSync).Str("repository", name).Str("reference", reference).
Msg("failed to sync image")
}
Expand Down
2 changes: 1 addition & 1 deletion pkg/extensions/sync/on_demand.go
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ func (onDemand *BaseOnDemand) syncImage(ctx context.Context, repo, reference str
err = service.SyncImage(ctx, repo, reference)
}

if err != nil || isPingErr {
if (err != nil || isPingErr) && !errors.Is(err, zerr.ErrPullByNonOCIDigest) {
if errors.Is(err, zerr.ErrManifestNotFound) ||
errors.Is(err, zerr.ErrSyncImageFilteredOut) ||
errors.Is(err, zerr.ErrSyncImageNotSigned) {
Expand Down
18 changes: 18 additions & 0 deletions pkg/extensions/sync/remote.go
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,24 @@ func (registry *RemoteRegistry) GetImageReference(repo, reference string) (types
return imageRef, nil
}

func (registry *RemoteRegistry) GetSrcManifestContent(imageReference types.ImageReference) (
[]byte, string, digest.Digest, error,
) {
imageSource, err := imageReference.NewImageSource(context.Background(), registry.GetContext())
if err != nil {
return []byte{}, "", "", err
}

defer imageSource.Close()

manifestBuf, mediaType, err := imageSource.GetManifest(context.Background(), nil)
if err != nil {
return []byte{}, "", "", err
}

return manifestBuf, mediaType, digest.FromBytes(manifestBuf), nil
}

func (registry *RemoteRegistry) GetManifestContent(imageReference types.ImageReference) (
[]byte, string, digest.Digest, error,
) {
Expand Down
28 changes: 28 additions & 0 deletions pkg/extensions/sync/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -453,6 +453,34 @@ func (service *BaseService) syncTag(ctx context.Context, destinationRepo, remote
}

if !skipImage {
_, err = digest.Parse(tag)
if err == nil {
if tag != manifestDigest.String() {
// its a digest pull. we add details to err and let upper level handling this
buf, mt, md, err := service.remote.GetSrcManifestContent(remoteImageRef)
if err != nil {
service.log.Error().Err(err).Str("errortype", common.TypeOf(err)).
Str("remote", remoteImageRef.DockerReference().String()).
Str("reference", tag).
Msg("get manifest info from remote error")
return "", err
}

if md.String() != tag {
return "", zerr.NewError(zerr.ErrManifestNotFound)
}

return manifestDigest, zerr.NewError(zerr.ErrPullByNonOCIDigest).AddDetail(
"srcDigest", tag,
).AddDetail(
"srcMediaType", mt,
).AddDetail(
"srcManifest", string(buf),
).AddDetail(
"srcRepo", remoteRepo,
)
}
}
localImageRef, err := service.destination.GetImageReference(destinationRepo, tag)
if err != nil {
service.log.Error().Err(err).Str("errortype", common.TypeOf(err)).
Expand Down
2 changes: 2 additions & 0 deletions pkg/extensions/sync/sync.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,8 @@ type Remote interface {
GetRepoTags(repo string) ([]string, error)
// Get manifest content, mediaType, digest given an ImageReference
GetManifestContent(imageReference types.ImageReference) ([]byte, string, digest.Digest, error)
// Get manifest from remote without convert to OCI
GetSrcManifestContent(imageReference types.ImageReference) ([]byte, string, digest.Digest, error)
// In the case of public dockerhub images 'library' namespace is added to the repo names of images
// eg: alpine -> library/alpine
GetDockerRemoteRepo(repo string) string
Expand Down

0 comments on commit 3b40e95

Please sign in to comment.