From f99c4ec7989327597e4fcc118b2dd25c9a75747a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Gronowski?= Date: Wed, 4 Oct 2023 10:32:00 +0200 Subject: [PATCH] c8d/history: Fill ID and Tags for all entries MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Find the parent images by image set by the legacy builder. Signed-off-by: Paweł Gronowski --- daemon/containerd/image_children.go | 22 ++++++++++++++ daemon/containerd/image_history.go | 45 ++++++++++++++++++++--------- 2 files changed, 54 insertions(+), 13 deletions(-) diff --git a/daemon/containerd/image_children.go b/daemon/containerd/image_children.go index 4f39d43f54..0f9d9d0d1b 100644 --- a/daemon/containerd/image_children.go +++ b/daemon/containerd/image_children.go @@ -10,6 +10,7 @@ import ( "github.com/containerd/containerd/platforms" "github.com/docker/docker/errdefs" "github.com/docker/docker/image" + "github.com/opencontainers/go-digest" ocispec "github.com/opencontainers/image-spec/specs-go/v1" "github.com/pkg/errors" ) @@ -190,6 +191,27 @@ func (i *ImageService) parents(ctx context.Context, id image.ID) ([]imageWithRoo return parents, nil } +// getParentsByBuilderLabel finds images that were a base for the given image +// by an image label set by the legacy builder. +// NOTE: This only works for images built with legacy builder (not Buildkit). +func (i *ImageService) getParentsByBuilderLabel(ctx context.Context, img containerdimages.Image) ([]containerdimages.Image, error) { + parent, ok := img.Labels[imageLabelClassicBuilderParent] + if !ok || parent == "" { + return nil, nil + } + + dgst, err := digest.Parse(parent) + if err != nil { + log.G(ctx).WithFields(log.Fields{ + "error": err, + "value": parent, + }).Warnf("invalid %s label value", imageLabelClassicBuilderParent) + return nil, nil + } + + return i.client.ImageService().List(ctx, "target.digest=="+dgst.String()) +} + type imageWithRootfs struct { img containerdimages.Image rootfs ocispec.RootFS diff --git a/daemon/containerd/image_history.go b/daemon/containerd/image_history.go index fc99839796..ada4ce813d 100644 --- a/daemon/containerd/image_history.go +++ b/daemon/containerd/image_history.go @@ -4,6 +4,8 @@ import ( "context" "sort" + "github.com/containerd/containerd/images" + "github.com/containerd/containerd/log" cplatforms "github.com/containerd/containerd/platforms" "github.com/distribution/reference" imagetype "github.com/docker/docker/api/types/image" @@ -17,7 +19,7 @@ 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.resolveImage(ctx, name) + img, err := i.resolveImage(ctx, name) if err != nil { return nil, err } @@ -27,7 +29,7 @@ func (i *ImageService) ImageHistory(ctx context.Context, name string) ([]*imaget platform := platforms.AllPlatformsWithPreference(cplatforms.Default()) var presentImages []ocispec.Image - err = i.walkImageManifests(ctx, desc, func(img *ImageManifest) error { + err = i.walkImageManifests(ctx, img, func(img *ImageManifest) error { conf, err := img.Config(ctx) if err != nil { return err @@ -89,26 +91,43 @@ func (i *ImageService) ImageHistory(ctx context.Context, name string) ([]*imaget }}, history...) } - if len(history) != 0 { - history[0].ID = desc.Target.Digest.String() - - tagged, err := i.client.ImageService().List(ctx, "target.digest=="+desc.Target.Digest.String()) + findParents := func(img images.Image) []images.Image { + imgs, err := i.getParentsByBuilderLabel(ctx, img) if err != nil { - return nil, err + log.G(ctx).WithFields(log.Fields{ + "error": err, + "image": img, + }).Warnf("failed to list parent images") + return nil } + return imgs + } - var tags []string - for _, t := range tagged { - if isDanglingImage(t) { + currentImg := img + for _, h := range history { + h.ID = currentImg.Target.Digest.String() + imgs := findParents(currentImg) + + foundNext := false + for _, img := range imgs { + if _, ok := img.Labels[imageLabelClassicBuilderParent]; ok { + currentImg = img + foundNext = true + } + + if isDanglingImage(img) { continue } - name, err := reference.ParseNamed(t.Name) + name, err := reference.ParseNamed(img.Name) if err != nil { return nil, err } - tags = append(tags, reference.FamiliarString(name)) + h.Tags = append(h.Tags, reference.FamiliarString(name)) + } + + if !foundNext { + break } - history[0].Tags = tags } return history, nil