diff --git a/daemon/containerd/image_children.go b/daemon/containerd/image_children.go index 488b5b158c..ced4637aeb 100644 --- a/daemon/containerd/image_children.go +++ b/daemon/containerd/image_children.go @@ -7,46 +7,49 @@ import ( cerrdefs "github.com/containerd/containerd/errdefs" containerdimages "github.com/containerd/containerd/images" "github.com/containerd/containerd/platforms" + "github.com/docker/docker/errdefs" "github.com/docker/docker/image" ocispec "github.com/opencontainers/image-spec/specs-go/v1" + "github.com/pkg/errors" "github.com/sirupsen/logrus" ) // Children returns a slice of image ID which rootfs is a superset of the // rootfs of the given image ID, excluding images with exactly the same rootfs. // Called from list.go to filter containers. -func (i *ImageService) Children(ctx context.Context, id image.ID) []image.ID { +func (i *ImageService) Children(ctx context.Context, id image.ID) ([]image.ID, error) { target, err := i.resolveDescriptor(ctx, id.String()) if err != nil { - logrus.WithError(err).Error("failed to get parent image") - return []image.ID{} + return []image.ID{}, errors.Wrap(err, "failed to get parent image") } - is := i.client.ImageService() cs := i.client.ContentStore() - log := logrus.WithField("id", id) - allPlatforms, err := containerdimages.Platforms(ctx, cs, target) if err != nil { - log.WithError(err).Error("failed to list supported platorms of image") - return []image.ID{} + return []image.ID{}, errdefs.System(errors.Wrap(err, "failed to list platforms supported by image")) } parentRootFS := []ocispec.RootFS{} for _, platform := range allPlatforms { rootfs, err := platformRootfs(ctx, cs, target, platform) if err != nil { + if !cerrdefs.IsNotFound(err) { + logrus.WithFields(logrus.Fields{ + logrus.ErrorKey: err, + "image": target.Digest, + "platform": platform, + }).Warning("failed to get platform-specific rootfs") + } continue } parentRootFS = append(parentRootFS, rootfs) } - imgs, err := is.List(ctx) + imgs, err := i.client.ImageService().List(ctx) if err != nil { - log.WithError(err).Error("failed to list all images") - return []image.ID{} + return []image.ID{}, errdefs.System(errors.Wrap(err, "failed to list all images")) } children := []image.ID{} @@ -55,6 +58,13 @@ func (i *ImageService) Children(ctx context.Context, id image.ID) []image.ID { for _, platform := range allPlatforms { rootfs, err := platformRootfs(ctx, cs, img.Target, platform) if err != nil { + if !cerrdefs.IsNotFound(err) { + logrus.WithFields(logrus.Fields{ + logrus.ErrorKey: err, + "image": img.Target.Digest, + "platform": platform, + }).Warning("failed to get platform-specific rootfs") + } continue } @@ -68,29 +78,21 @@ func (i *ImageService) Children(ctx context.Context, id image.ID) []image.ID { } - return children + return children, nil } // platformRootfs returns a rootfs for a specified platform. func platformRootfs(ctx context.Context, store content.Store, desc ocispec.Descriptor, platform ocispec.Platform) (ocispec.RootFS, error) { empty := ocispec.RootFS{} - log := logrus.WithField("desc", desc.Digest).WithField("platform", platforms.Format(platform)) configDesc, err := containerdimages.Config(ctx, store, desc, platforms.OnlyStrict(platform)) if err != nil { - if !cerrdefs.IsNotFound(err) { - log.WithError(err).Warning("failed to get parent image config") - } - return empty, err + return empty, errors.Wrapf(err, "failed to get config for platform %s", platforms.Format(platform)) } - log = log.WithField("configDesc", configDesc) diffs, err := containerdimages.RootFS(ctx, store, configDesc) if err != nil { - if !cerrdefs.IsNotFound(err) { - log.WithError(err).Warning("failed to get parent image rootfs") - } - return empty, err + return empty, errors.Wrapf(err, "failed to obtain rootfs") } return ocispec.RootFS{ diff --git a/daemon/image_service.go b/daemon/image_service.go index 2da49c1c9e..b47575b6db 100644 --- a/daemon/image_service.go +++ b/daemon/image_service.go @@ -73,7 +73,7 @@ type ImageService interface { // Other DistributionServices() images.DistributionServices - Children(ctx context.Context, id image.ID) []image.ID + Children(ctx context.Context, id image.ID) ([]image.ID, error) Cleanup() error StorageDriver() string UpdateConfig(maxDownloads, maxUploads int) diff --git a/daemon/images/service.go b/daemon/images/service.go index 19cbfa0263..0cddfd052c 100644 --- a/daemon/images/service.go +++ b/daemon/images/service.go @@ -109,8 +109,8 @@ func (i *ImageService) CountImages() int { // Children returns the children image.IDs for a parent image. // called from list.go to filter containers // TODO: refactor to expose an ancestry for image.ID? -func (i *ImageService) Children(_ context.Context, id image.ID) []image.ID { - return i.imageStore.Children(id) +func (i *ImageService) Children(_ context.Context, id image.ID) ([]image.ID, error) { + return i.imageStore.Children(id), nil } // CreateLayer creates a filesystem layer for a container. diff --git a/daemon/list.go b/daemon/list.go index cefb06395b..676de6f222 100644 --- a/daemon/list.go +++ b/daemon/list.go @@ -317,7 +317,7 @@ func (daemon *Daemon) foldFilter(ctx context.Context, view *container.View, conf var ancestorFilter bool if psFilters.Contains("ancestor") { ancestorFilter = true - psFilters.WalkValues("ancestor", func(ancestor string) error { + err := psFilters.WalkValues("ancestor", func(ancestor string) error { img, err := daemon.imageService.GetImage(ctx, ancestor, imagetypes.GetImageOpts{}) if err != nil { logrus.Warnf("Error while looking up for image %v", ancestor) @@ -328,9 +328,12 @@ func (daemon *Daemon) foldFilter(ctx context.Context, view *container.View, conf return nil } // Then walk down the graph and put the imageIds in imagesFilter - populateImageFilterByParents(ctx, imagesFilter, img.ID(), daemon.imageService.Children) - return nil + return populateImageFilterByParents(ctx, imagesFilter, img.ID(), daemon.imageService.Children) }) + + if err != nil { + return nil, err + } } publishFilter := map[nat.Port]bool{} @@ -594,11 +597,18 @@ func (daemon *Daemon) refreshImage(ctx context.Context, s *container.Snapshot, f return &c, nil } -func populateImageFilterByParents(ctx context.Context, ancestorMap map[image.ID]bool, imageID image.ID, getChildren func(context.Context, image.ID) []image.ID) { +func populateImageFilterByParents(ctx context.Context, ancestorMap map[image.ID]bool, imageID image.ID, getChildren func(context.Context, image.ID) ([]image.ID, error)) error { if !ancestorMap[imageID] { - for _, id := range getChildren(ctx, imageID) { - populateImageFilterByParents(ctx, ancestorMap, id, getChildren) + children, err := getChildren(ctx, imageID) + if err != nil { + return err + } + for _, id := range children { + if err := populateImageFilterByParents(ctx, ancestorMap, id, getChildren); err != nil { + return err + } } ancestorMap[imageID] = true } + return nil }