c8d: Handle nil container.ImageManifest

Don't panic when processing containers created under fork containerd
integration (this field was added in the upstream and didn't exist in
fork).

Co-authored-by: Djordje Lukic <djordje.lukic@docker.com>
Signed-off-by: Paweł Gronowski <pawel.gronowski@docker.com>
This commit is contained in:
Paweł Gronowski 2023-04-25 15:10:55 +02:00
parent a343ed13e5
commit 9fe5ac6614
No known key found for this signature in database
GPG key ID: B85EFCFE26DEF92A
3 changed files with 52 additions and 9 deletions

View file

@ -17,7 +17,12 @@ import (
func (i *ImageService) Changes(ctx context.Context, container *container.Container) ([]archive.Change, error) {
cs := i.client.ContentStore()
imageManifestBytes, err := content.ReadBlob(ctx, cs, *container.ImageManifest)
imageManifest, err := getContainerImageManifest(container)
if err != nil {
return nil, err
}
imageManifestBytes, err := content.ReadBlob(ctx, cs, imageManifest)
if err != nil {
return nil, err
}

View file

@ -40,7 +40,12 @@ func (i *ImageService) CommitImage(ctx context.Context, cc backend.CommitConfig)
container := i.containers.Get(cc.ContainerID)
cs := i.client.ContentStore()
imageManifestBytes, err := content.ReadBlob(ctx, cs, *container.ImageManifest)
imageManifest, err := getContainerImageManifest(container)
if err != nil {
return "", err
}
imageManifestBytes, err := content.ReadBlob(ctx, cs, imageManifest)
if err != nil {
return "", err
}

View file

@ -10,6 +10,7 @@ import (
"github.com/containerd/containerd/plugin"
"github.com/containerd/containerd/remotes/docker"
"github.com/containerd/containerd/snapshots"
imagetypes "github.com/docker/docker/api/types/image"
"github.com/docker/docker/container"
daemonevents "github.com/docker/docker/daemon/events"
"github.com/docker/docker/daemon/images"
@ -20,6 +21,7 @@ import (
"github.com/opencontainers/image-spec/identity"
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
)
// ImageService implements daemon.ImageService
@ -154,9 +156,35 @@ func (i *ImageService) GetContainerLayerSize(ctx context.Context, containerID st
if ctr == nil {
return 0, 0, nil
}
snapshotter := i.client.SnapshotService(ctr.Driver)
usage, err := snapshotter.Usage(ctx, containerID)
if err != nil {
return 0, 0, err
}
imageManifest, err := getContainerImageManifest(ctr)
if err != nil {
// Best efforts attempt to pick an image.
// We don't have platform information at this point, so we can only
// assume that the platform matches host.
// Otherwise this will give a wrong base image size (different
// platform), but should be close enough.
mfst, err := i.GetImageManifest(ctx, ctr.Config.Image, imagetypes.GetImageOpts{})
if err != nil {
// Log error, don't error out whole operation.
logrus.WithFields(logrus.Fields{
logrus.ErrorKey: err,
"container": containerID,
}).Warn("empty ImageManifest, can't calculate base image size")
return usage.Size, 0, nil
}
imageManifest = *mfst
}
cs := i.client.ContentStore()
imageManifestBytes, err := content.ReadBlob(ctx, cs, *ctr.ImageManifest)
imageManifestBytes, err := content.ReadBlob(ctx, cs, imageManifest)
if err != nil {
return 0, 0, err
}
@ -175,12 +203,6 @@ func (i *ImageService) GetContainerLayerSize(ctx context.Context, containerID st
return 0, 0, err
}
snapshotter := i.client.SnapshotService(ctr.Driver)
usage, err := snapshotter.Usage(ctx, containerID)
if err != nil {
return 0, 0, err
}
sizeCache := make(map[digest.Digest]int64)
snapshotSizeFn := func(d digest.Digest) (int64, error) {
if s, ok := sizeCache[d]; ok {
@ -203,3 +225,14 @@ func (i *ImageService) GetContainerLayerSize(ctx context.Context, containerID st
// TODO(thaJeztah): include content-store size for the image (similar to "GET /images/json")
return usage.Size, usage.Size + snapShotSize, nil
}
// getContainerImageManifest safely dereferences ImageManifest.
// ImageManifest can be nil for containers created with Docker Desktop with old
// containerd image store integration enabled which didn't set this field.
func getContainerImageManifest(ctr *container.Container) (ocispec.Descriptor, error) {
if ctr.ImageManifest == nil {
return ocispec.Descriptor{}, errdefs.InvalidParameter(errors.New("container is missing ImageManifest (probably created on old version), please recreate it"))
}
return *ctr.ImageManifest, nil
}