| package daemon |
| |
| import ( |
| "context" |
| "errors" |
| "testing" |
| |
| "github.com/containerd/platforms" |
| "github.com/moby/moby/v2/daemon/container" |
| "github.com/moby/moby/v2/daemon/internal/image" |
| ocispec "github.com/opencontainers/image-spec/specs-go/v1" |
| "gotest.tools/v3/assert" |
| ) |
| |
| type mockPlatformReader struct{} |
| |
| func (m mockPlatformReader) ReadPlatformFromImage(ctx context.Context, id image.ID) (ocispec.Platform, error) { |
| switch id { |
| case "multiplatform": |
| // This image has multiple platforms, but GetImage will prefer the first one |
| // because the ID points to the full image index, not a specific platform. |
| return platforms.DefaultSpec(), nil |
| case "linux/arm64/v8": |
| return ocispec.Platform{ |
| OS: "linux", |
| Architecture: "arm64", |
| Variant: "v8", |
| }, nil |
| case "linux/amd64": |
| return ocispec.Platform{ |
| OS: "linux", |
| Architecture: "amd64", |
| }, nil |
| case "windows/amd64": |
| return ocispec.Platform{ |
| OS: "windows", |
| Architecture: "amd64", |
| }, nil |
| default: |
| return ocispec.Platform{}, errors.New("image not found") |
| } |
| } |
| |
| func (m mockPlatformReader) ReadPlatformFromConfigByImageManifest(ctx context.Context, desc ocispec.Descriptor) (ocispec.Platform, error) { |
| return m.ReadPlatformFromImage(ctx, image.ID(desc.Digest)) |
| } |
| |
| //nolint:staticcheck // ignore SA1019 because we are testing deprecated field migration |
| func TestContainerMigrateOS(t *testing.T) { |
| type Container = container.Container |
| |
| var mock mockPlatformReader |
| |
| // ImageManifest is nil for containers created with graphdrivers image store |
| var graphdrivers *ocispec.Descriptor |
| |
| for _, tc := range []struct { |
| name string |
| ctr Container |
| expected ocispec.Platform |
| }{ |
| { |
| name: "gd pre-OS container", |
| ctr: Container{ |
| ImageManifest: graphdrivers, |
| OS: "", |
| }, |
| expected: platforms.DefaultSpec(), |
| }, |
| { |
| name: "gd with linux arm64 image", |
| ctr: Container{ |
| ImageManifest: graphdrivers, |
| ImageID: "linux/arm64/v8", |
| OS: "linux", |
| }, |
| expected: ocispec.Platform{ |
| OS: "linux", |
| Architecture: "arm64", |
| Variant: "v8", |
| }, |
| }, |
| { |
| name: "gd with windows image", |
| ctr: Container{ |
| ImageManifest: graphdrivers, |
| ImageID: "windows/amd64", |
| OS: "windows", |
| }, |
| expected: ocispec.Platform{ |
| OS: "windows", |
| Architecture: "amd64", |
| }, |
| }, |
| { |
| name: "gd with an image thats no longer available", |
| ctr: Container{ |
| ImageManifest: graphdrivers, |
| ImageID: "notfound", |
| OS: "linux", |
| }, |
| expected: platforms.Platform{ |
| OS: "linux", |
| }, |
| }, |
| { |
| name: "c8d with linux arm64 image", |
| ctr: Container{ |
| ImageManifest: &ocispec.Descriptor{ |
| Digest: "linux/arm64/v8", |
| }, |
| OS: "linux", |
| ImageID: "linux/arm64/v8", |
| }, |
| expected: ocispec.Platform{ |
| OS: "linux", |
| Architecture: "arm64", |
| Variant: "v8", |
| }, |
| }, |
| { |
| name: "c8d with an image thats no longer available", |
| ctr: Container{ |
| ImageManifest: &ocispec.Descriptor{ |
| Digest: "notfound", |
| }, |
| OS: "linux", |
| ImageID: "notfound", |
| }, |
| expected: platforms.Platform{ |
| OS: "linux", |
| }, |
| }, |
| { |
| name: "c8d with ImageManifest that is no longer available", |
| ctr: Container{ |
| ImageManifest: &ocispec.Descriptor{ |
| Digest: "notfound", |
| }, |
| OS: "linux", |
| ImageID: "multiplatform", |
| }, |
| // Note: This might produce unexpected results, because if the platform-specific manifest |
| // is not available, and the ImageID points to a multi-platform image, then GetImage will |
| // return any available platform with host platform being the priority. |
| // So it will just use whatever platform is returned by GetImage (docker image inspect). |
| expected: platforms.DefaultSpec(), |
| }, |
| { |
| name: "ImageManifest has priority over ImageID migration", |
| ctr: Container{ |
| ImageManifest: &ocispec.Descriptor{ |
| Digest: "linux/arm64/v8", |
| }, |
| OS: "linux", |
| ImageID: "linux/amd64", |
| }, |
| expected: ocispec.Platform{ |
| OS: "linux", |
| Architecture: "arm64", |
| Variant: "v8", |
| }, |
| }, |
| } { |
| ctr := tc.ctr |
| t.Run(tc.name, func(t *testing.T) { |
| migrateContainerOS(context.Background(), mock, &ctr) |
| |
| assert.DeepEqual(t, tc.expected, ctr.ImagePlatform) |
| }) |
| } |
| } |