Browse Source

c8d/images: handle images without manifests for default platform

Signed-off-by: Laura Brehm <laurabrehm@hey.com>
Laura Brehm 2 years ago
parent
commit
6d3bcd8017
2 changed files with 55 additions and 38 deletions
  1. 27 17
      daemon/containerd/image.go
  2. 28 21
      daemon/containerd/image_history.go

+ 27 - 17
daemon/containerd/image.go

@@ -2,14 +2,13 @@ package containerd
 
 import (
 	"context"
-	"encoding/json"
 	"fmt"
 	"regexp"
+	"sort"
 	"strconv"
 	"sync/atomic"
 	"time"
 
-	"github.com/containerd/containerd/content"
 	cerrdefs "github.com/containerd/containerd/errdefs"
 	containerdimages "github.com/containerd/containerd/images"
 	cplatforms "github.com/containerd/containerd/platforms"
@@ -33,7 +32,7 @@ var truncatedID = regexp.MustCompile(`^([a-f0-9]{4,64})$`)
 
 // GetImage returns an image corresponding to the image referred to by refOrID.
 func (i *ImageService) GetImage(ctx context.Context, refOrID string, options imagetype.GetImageOpts) (*image.Image, error) {
-	desc, err := i.resolveDescriptor(ctx, refOrID)
+	desc, err := i.resolveImage(ctx, refOrID)
 	if err != nil {
 		return nil, err
 	}
@@ -44,21 +43,32 @@ func (i *ImageService) GetImage(ctx context.Context, refOrID string, options ima
 	}
 
 	cs := i.client.ContentStore()
-	conf, err := containerdimages.Config(ctx, cs, desc, platform)
-	if err != nil {
-		return nil, err
-	}
 
-	imageConfigBytes, err := content.ReadBlob(ctx, cs, conf)
+	var presentImages []ocispec.Image
+	err = i.walkImageManifests(ctx, desc, func(img *ImageManifest) error {
+		conf, err := img.Config(ctx)
+		if err != nil {
+			return err
+		}
+		var ociimage ocispec.Image
+		if err := readConfig(ctx, cs, conf, &ociimage); err != nil {
+			return err
+		}
+		presentImages = append(presentImages, ociimage)
+		return nil
+	})
 	if err != nil {
 		return nil, err
 	}
-
-	var ociimage ocispec.Image
-	if err := json.Unmarshal(imageConfigBytes, &ociimage); err != nil {
-		return nil, err
+	if len(presentImages) == 0 {
+		return nil, errdefs.NotFound(errors.New("failed to find image manifest"))
 	}
 
+	sort.SliceStable(presentImages, func(i, j int) bool {
+		return platform.Less(presentImages[i].Platform, presentImages[j].Platform)
+	})
+	ociimage := presentImages[0]
+
 	rootfs := image.NewRootFS()
 	for _, id := range ociimage.RootFS.DiffIDs {
 		rootfs.Append(layer.DiffID(id))
@@ -68,9 +78,9 @@ func (i *ImageService) GetImage(ctx context.Context, refOrID string, options ima
 		exposedPorts[nat.Port(k)] = v
 	}
 
-	img := image.NewImage(image.ID(desc.Digest))
+	img := image.NewImage(image.ID(desc.Target.Digest))
 	img.V1Image = image.V1Image{
-		ID:           string(desc.Digest),
+		ID:           string(desc.Target.Digest),
 		OS:           ociimage.OS,
 		Architecture: ociimage.Architecture,
 		Created:      ociimage.Created,
@@ -92,12 +102,12 @@ func (i *ImageService) GetImage(ctx context.Context, refOrID string, options ima
 
 	if options.Details {
 		lastUpdated := time.Unix(0, 0)
-		size, err := i.size(ctx, desc, platform)
+		size, err := i.size(ctx, desc.Target, platform)
 		if err != nil {
 			return nil, err
 		}
 
-		tagged, err := i.client.ImageService().List(ctx, "target.digest=="+desc.Digest.String())
+		tagged, err := i.client.ImageService().List(ctx, "target.digest=="+desc.Target.Digest.String())
 		if err != nil {
 			return nil, err
 		}
@@ -127,7 +137,7 @@ func (i *ImageService) GetImage(ctx context.Context, refOrID string, options ima
 			}
 			refs = append(refs, name)
 
-			digested, err := reference.WithDigest(reference.TrimNamed(name), desc.Digest)
+			digested, err := reference.WithDigest(reference.TrimNamed(name), desc.Target.Digest)
 			if err != nil {
 				// This could only happen if digest is invalid, but considering that
 				// we get it from the Descriptor it's highly unlikely.

+ 28 - 21
daemon/containerd/image_history.go

@@ -2,13 +2,12 @@ package containerd
 
 import (
 	"context"
-	"encoding/json"
+	"sort"
 
-	"github.com/containerd/containerd/content"
-	containerdimages "github.com/containerd/containerd/images"
 	cplatforms "github.com/containerd/containerd/platforms"
 	"github.com/docker/distribution/reference"
 	imagetype "github.com/docker/docker/api/types/image"
+	"github.com/docker/docker/errdefs"
 	"github.com/docker/docker/pkg/platforms"
 	"github.com/opencontainers/image-spec/identity"
 	ocispec "github.com/opencontainers/image-spec/specs-go/v1"
@@ -18,32 +17,39 @@ import (
 // ImageHistory returns a slice of HistoryResponseItem structures for the
 // specified image name by walking the image lineage.
 func (i *ImageService) ImageHistory(ctx context.Context, name string) ([]*imagetype.HistoryResponseItem, error) {
-	desc, err := i.resolveDescriptor(ctx, name)
+	desc, err := i.resolveImage(ctx, name)
 	if err != nil {
 		return nil, err
 	}
 
 	cs := i.client.ContentStore()
-	// TODO: pass the platform from the cli
-	conf, err := containerdimages.Config(ctx, cs, desc, platforms.AllPlatformsWithPreference(cplatforms.Default()))
-	if err != nil {
-		return nil, err
-	}
+	// TODO: pass platform in from the CLI
+	platform := platforms.AllPlatformsWithPreference(cplatforms.Default())
 
-	diffIDs, err := containerdimages.RootFS(ctx, cs, conf)
+	var presentImages []ocispec.Image
+	err = i.walkImageManifests(ctx, desc, func(img *ImageManifest) error {
+		conf, err := img.Config(ctx)
+		if err != nil {
+			return err
+		}
+		var ociimage ocispec.Image
+		if err := readConfig(ctx, cs, conf, &ociimage); err != nil {
+			return err
+		}
+		presentImages = append(presentImages, ociimage)
+		return nil
+	})
 	if err != nil {
 		return nil, err
 	}
-
-	blob, err := content.ReadBlob(ctx, cs, conf)
-	if err != nil {
-		return nil, err
+	if len(presentImages) == 0 {
+		return nil, errdefs.NotFound(errors.New("failed to find image manifest"))
 	}
 
-	var image ocispec.Image
-	if err := json.Unmarshal(blob, &image); err != nil {
-		return nil, err
-	}
+	sort.SliceStable(presentImages, func(i, j int) bool {
+		return platform.Less(presentImages[i].Platform, presentImages[j].Platform)
+	})
+	ociimage := presentImages[0]
 
 	var (
 		history []*imagetype.HistoryResponseItem
@@ -51,6 +57,7 @@ func (i *ImageService) ImageHistory(ctx context.Context, name string) ([]*imaget
 	)
 	s := i.client.SnapshotService(i.snapshotter)
 
+	diffIDs := ociimage.RootFS.DiffIDs
 	for i := range diffIDs {
 		chainID := identity.ChainID(diffIDs[0 : i+1]).String()
 
@@ -62,7 +69,7 @@ func (i *ImageService) ImageHistory(ctx context.Context, name string) ([]*imaget
 		sizes = append(sizes, use.Size)
 	}
 
-	for _, h := range image.History {
+	for _, h := range ociimage.History {
 		size := int64(0)
 		if !h.EmptyLayer {
 			if len(sizes) == 0 {
@@ -83,9 +90,9 @@ func (i *ImageService) ImageHistory(ctx context.Context, name string) ([]*imaget
 	}
 
 	if len(history) != 0 {
-		history[0].ID = desc.Digest.String()
+		history[0].ID = desc.Target.Digest.String()
 
-		tagged, err := i.client.ImageService().List(ctx, "target.digest=="+desc.Digest.String())
+		tagged, err := i.client.ImageService().List(ctx, "target.digest=="+desc.Target.Digest.String())
 		if err != nil {
 			return nil, err
 		}