c8d/list: Use walkImageManifests
Signed-off-by: Paweł Gronowski <pawel.gronowski@docker.com>
This commit is contained in:
parent
fabc1d5bef
commit
5210f48bfc
1 changed files with 27 additions and 91 deletions
|
@ -6,17 +6,14 @@ import (
|
|||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/containerd/containerd"
|
||||
"github.com/containerd/containerd/content"
|
||||
cerrdefs "github.com/containerd/containerd/errdefs"
|
||||
"github.com/containerd/containerd/images"
|
||||
"github.com/containerd/containerd/labels"
|
||||
"github.com/containerd/containerd/platforms"
|
||||
"github.com/docker/distribution/reference"
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/api/types/filters"
|
||||
timetypes "github.com/docker/docker/api/types/time"
|
||||
"github.com/moby/buildkit/util/attestation"
|
||||
"github.com/opencontainers/go-digest"
|
||||
"github.com/opencontainers/image-spec/identity"
|
||||
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
|
||||
|
@ -87,72 +84,41 @@ func (i *ImageService) Images(ctx context.Context, opts types.ImageListOptions)
|
|||
continue
|
||||
}
|
||||
|
||||
err := images.Walk(ctx, images.HandlerFunc(func(ctx context.Context, desc ocispec.Descriptor) ([]ocispec.Descriptor, error) {
|
||||
if images.IsIndexType(desc.MediaType) {
|
||||
return images.Children(ctx, contentStore, desc)
|
||||
err := i.walkImageManifests(ctx, img, func(img *ImageManifest) error {
|
||||
if isPseudo, err := img.IsPseudoImage(ctx); isPseudo || err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if images.IsManifestType(desc.MediaType) {
|
||||
// Ignore buildkit attestation manifests
|
||||
// https://github.com/moby/buildkit/blob/v0.11.4/docs/attestations/attestation-storage.md
|
||||
// This would have also been caught by the isImageManifest call below, but it requires
|
||||
// an additional content read and deserialization of Manifest.
|
||||
if _, has := desc.Annotations[attestation.DockerAnnotationReferenceType]; has {
|
||||
return nil, nil
|
||||
}
|
||||
available, err := img.CheckContentAvailable(ctx)
|
||||
if err != nil {
|
||||
logrus.WithFields(logrus.Fields{
|
||||
logrus.ErrorKey: err,
|
||||
"manifest": img.Target(),
|
||||
"image": img.Name(),
|
||||
}).Warn("checking availability of platform specific manifest failed")
|
||||
return nil
|
||||
}
|
||||
|
||||
mfst, err := images.Manifest(ctx, contentStore, desc, platforms.All)
|
||||
if err != nil {
|
||||
if cerrdefs.IsNotFound(err) {
|
||||
return nil, nil
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
if !available {
|
||||
return nil
|
||||
}
|
||||
|
||||
if !isImageManifest(mfst) {
|
||||
return nil, nil
|
||||
}
|
||||
image, chainIDs, err := i.singlePlatformImage(ctx, contentStore, img)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
platform, err := getManifestPlatform(ctx, contentStore, desc, mfst.Config)
|
||||
if err != nil {
|
||||
if cerrdefs.IsNotFound(err) {
|
||||
return nil, nil
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
summaries = append(summaries, image)
|
||||
|
||||
pm := platforms.OnlyStrict(platform)
|
||||
available, _, _, missing, err := images.Check(ctx, contentStore, img.Target, pm)
|
||||
if err != nil {
|
||||
logrus.WithFields(logrus.Fields{
|
||||
logrus.ErrorKey: err,
|
||||
"platform": platform,
|
||||
"image": img.Target,
|
||||
}).Warn("checking availability of platform content failed")
|
||||
return nil, nil
|
||||
}
|
||||
if !available || len(missing) > 0 {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
c8dImage := containerd.NewImageWithPlatform(i.client, img, pm)
|
||||
image, chainIDs, err := i.singlePlatformImage(ctx, contentStore, c8dImage)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
summaries = append(summaries, image)
|
||||
|
||||
if opts.SharedSize {
|
||||
root = append(root, &chainIDs)
|
||||
for _, id := range chainIDs {
|
||||
layers[id] = layers[id] + 1
|
||||
}
|
||||
if opts.SharedSize {
|
||||
root = append(root, &chainIDs)
|
||||
for _, id := range chainIDs {
|
||||
layers[id] = layers[id] + 1
|
||||
}
|
||||
}
|
||||
|
||||
return nil, nil
|
||||
}), img.Target)
|
||||
return nil
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -173,7 +139,7 @@ func (i *ImageService) Images(ctx context.Context, opts types.ImageListOptions)
|
|||
return summaries, nil
|
||||
}
|
||||
|
||||
func (i *ImageService) singlePlatformImage(ctx context.Context, contentStore content.Store, image containerd.Image) (*types.ImageSummary, []digest.Digest, error) {
|
||||
func (i *ImageService) singlePlatformImage(ctx context.Context, contentStore content.Store, image *ImageManifest) (*types.ImageSummary, []digest.Digest, error) {
|
||||
diffIDs, err := image.RootFS(ctx)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
|
@ -508,36 +474,6 @@ func computeSharedSize(chainIDs []digest.Digest, layers map[digest.Digest]int, s
|
|||
return sharedSize, nil
|
||||
}
|
||||
|
||||
// getManifestPlatform returns a platform specified by the manifest descriptor
|
||||
// or reads it from its config.
|
||||
func getManifestPlatform(ctx context.Context, store content.Provider, manifestDesc, configDesc ocispec.Descriptor) (ocispec.Platform, error) {
|
||||
var platform ocispec.Platform
|
||||
if manifestDesc.Platform != nil {
|
||||
platform = *manifestDesc.Platform
|
||||
} else {
|
||||
// Config is technically a v1.Image, but it has the same member as v1.Platform
|
||||
// which makes the v1.Platform a subset of Image so we can unmarshal directly.
|
||||
if err := readConfig(ctx, store, configDesc, &platform); err != nil {
|
||||
return platform, err
|
||||
}
|
||||
}
|
||||
return platforms.Normalize(platform), nil
|
||||
}
|
||||
|
||||
// isImageManifest returns true if the manifest has no layers or any of its layers is a known image layer.
|
||||
// Some manifests use the image media type for compatibility, even if they are not a real image.
|
||||
func isImageManifest(mfst ocispec.Manifest) bool {
|
||||
if len(mfst.Layers) == 0 {
|
||||
return true
|
||||
}
|
||||
for _, l := range mfst.Layers {
|
||||
if images.IsLayerType(l.MediaType) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// readConfig reads content pointed by the descriptor and unmarshals it into a specified output.
|
||||
func readConfig(ctx context.Context, store content.Provider, desc ocispec.Descriptor, out interface{}) error {
|
||||
data, err := content.ReadBlob(ctx, store, desc)
|
||||
|
|
Loading…
Reference in a new issue