Files
moby/daemon/migration.go
Sebastiaan van Stijn 15bef6ff1a daemon/server: move GetImageOpts, ImageInspectOpts to imagebackend
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-10-05 13:41:22 +02:00

141 lines
4.0 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package daemon
import (
"context"
"encoding/json"
"github.com/containerd/containerd/v2/core/content"
"github.com/containerd/log"
"github.com/containerd/platforms"
"github.com/moby/moby/v2/daemon/container"
"github.com/moby/moby/v2/daemon/internal/image"
"github.com/moby/moby/v2/daemon/internal/multierror"
"github.com/moby/moby/v2/daemon/server/imagebackend"
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
"github.com/pkg/errors"
)
func migrateContainerOS(ctx context.Context,
migration platformReader,
ctr *container.Container,
) {
deduced, err := deduceContainerPlatform(ctx, migration, ctr)
if err != nil {
log.G(ctx).WithFields(log.Fields{
"container": ctr.ID,
"error": err,
}).Warn("failed to deduce the container architecture")
ctr.ImagePlatform.OS = ctr.OS //nolint:staticcheck // ignore SA1019
return
}
ctr.ImagePlatform = deduced
}
type platformReader interface {
ReadPlatformFromConfigByImageManifest(ctx context.Context, desc ocispec.Descriptor) (ocispec.Platform, error)
ReadPlatformFromImage(ctx context.Context, id image.ID) (ocispec.Platform, error)
}
// deduceContainerPlatform tries to deduce `ctr`'s platform.
// If both `ctr.OS` and `ctr.ImageManifest` are empty, assume the image comes
// from a pre-OS times and use the host platform to match the behavior of
// [container.FromDisk].
// Otherwise:
// - `ctr.ImageManifest.Platform` is used, if it exists and is not empty.
// - The platform from the manifest's config is used, if `ctr.ImageManifest` exists
// and we're able to load its config from the content store.
// - The platform found by loading the image from the image service by ID (using
// `ctr.ImageID`) is used this looks for the best *present* matching manifest in
// the store.
func deduceContainerPlatform(
ctx context.Context,
migration platformReader,
ctr *container.Container,
) (ocispec.Platform, error) {
if ctr.OS == "" && ctr.ImageManifest == nil { //nolint:staticcheck // ignore SA1019 because we are testing deprecated field migration
return platforms.DefaultSpec(), nil
}
var errs []error
isValidPlatform := func(p ocispec.Platform) bool {
return p.OS != "" && p.Architecture != ""
}
if ctr.ImageManifest != nil {
if ctr.ImageManifest.Platform != nil {
return *ctr.ImageManifest.Platform, nil
}
if ctr.ImageManifest != nil {
p, err := migration.ReadPlatformFromConfigByImageManifest(ctx, *ctr.ImageManifest)
if err != nil {
errs = append(errs, err)
} else {
if isValidPlatform(p) {
return p, nil
}
errs = append(errs, errors.New("malformed image config obtained by ImageManifestDescriptor"))
}
}
}
if ctr.ImageID != "" {
p, err := migration.ReadPlatformFromImage(ctx, ctr.ImageID)
if err != nil {
errs = append(errs, err)
} else {
if isValidPlatform(p) {
return p, nil
}
errs = append(errs, errors.New("malformed image config obtained by image id"))
}
}
return ocispec.Platform{}, errors.Wrap(multierror.Join(errs...), "cannot deduce the container platform")
}
type daemonPlatformReader struct {
imageService ImageService
content content.Provider
}
func (r daemonPlatformReader) ReadPlatformFromConfigByImageManifest(
ctx context.Context,
desc ocispec.Descriptor,
) (ocispec.Platform, error) {
if r.content == nil {
return ocispec.Platform{}, errors.New("not an containerd image store")
}
b, err := content.ReadBlob(ctx, r.content, desc)
if err != nil {
return ocispec.Platform{}, err
}
var mfst ocispec.Manifest
if err := json.Unmarshal(b, &mfst); err != nil {
return ocispec.Platform{}, err
}
b, err = content.ReadBlob(ctx, r.content, mfst.Config)
if err != nil {
return ocispec.Platform{}, err
}
var plat ocispec.Platform
if err := json.Unmarshal(b, &plat); err != nil {
return ocispec.Platform{}, err
}
return plat, nil
}
func (r daemonPlatformReader) ReadPlatformFromImage(ctx context.Context, id image.ID) (ocispec.Platform, error) {
img, err := r.imageService.GetImage(ctx, id.String(), imagebackend.GetImageOpts{})
if err != nil {
return ocispec.Platform{}, err
}
return img.Platform(), nil
}