Skip to content

Fix several conversions of "ocispec.Image" to "ocispec.Platform"#7376

Merged
samuelkarp merged 1 commit intocontainerd:mainfrom
tianon:oci-platform
May 31, 2023
Merged

Fix several conversions of "ocispec.Image" to "ocispec.Platform"#7376
samuelkarp merged 1 commit intocontainerd:mainfrom
tianon:oci-platform

Conversation

@tianon
Copy link
Copy Markdown
Member

@tianon tianon commented Sep 8, 2022

Several bits of code unmarshal image config JSON into an ocispec.Image, and then immediately create an ocispec.Platform out of it, but then discard the original image and miss several potential platform fields (most notably, variant).

Because ocispec.Platform is a strict subset of ocispec.Image, most of these can be updated to simply unmarshal the image config directly to ocispec.Platform instead, which allows these additional fields to be picked up appropriately.

We can use tianon/raspbian as a concrete reproducer to demonstrate.

Before:

$ ctr content fetch docker.io/tianon/raspbian:bullseye-slim
...

$ ctr image ls
REF                                     TYPE                                                 DIGEST                                                                  SIZE     PLATFORMS    LABELS
docker.io/tianon/raspbian:bullseye-slim application/vnd.docker.distribution.manifest.v2+json sha256:66e96f8af40691b335acc54e5f69711584ef7f926597b339e7d12ab90cc394ce 28.6 MiB linux/arm/v7 -

(Note that the PLATFORMS column lists linux/arm/v7 -- the image itself is actually linux/arm/v6, but one of these bits of code leads to only linux/arm being extracted from the image config, which platforms.Normalize then updates to an explicit v7.)

After:

$ ctr image ls
REF                                     TYPE                                                 DIGEST                                                                  SIZE     PLATFORMS    LABELS
docker.io/tianon/raspbian:bullseye-slim application/vnd.docker.distribution.manifest.v2+json sha256:66e96f8af40691b335acc54e5f69711584ef7f926597b339e7d12ab90cc394ce 28.6 MiB linux/arm/v6 -

(Tianon's back on his BS 😇 ❤️)

There's probably a pretty decent argument to be made for the OCI's Image type to embed Platform directly (which would make this more straightforward) and/or to offer a helper function that appropriately extracts a Platform object from an Image object, but I didn't want the perfect to be the enemy of the good, and this seemed like a good place to start.

@AkihiroSuda
Copy link
Copy Markdown
Member

Can we have an unit test?

@tianon
Copy link
Copy Markdown
Member Author

tianon commented Sep 8, 2022

I'm honestly not exactly sure where I would put unit tests for these changes -- they're all reading blobs from the content store, and each one is pretty deeply nested in other functionality. 😬

With a bit more guidance, I'd be willing to try, though! Any suggestions on a good place to start?

Comment on lines +243 to +250
imgPlatform := platforms.Normalize(ocispec.Platform{
OS: i.OS,
Architecture: i.Architecture,
Variant: i.Variant,

OSVersion: i.OSVersion,
OSFeatures: i.OSFeatures,
})
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should consider updating the ocispec.Image to embed the ocispec.Platform 🤔 ;

// Image is the JSON structure which describes some basic information about the image.
// This provides the `application/vnd.oci.image.config.v1+json` mediatype when marshalled to JSON.
type Image struct {
	// Created is the combined date and time at which the image was created, formatted as defined by RFC 3339, section 5.6.
	Created *time.Time `json:"created,omitempty"`

	// Author defines the name and/or email address of the person or entity which created and is responsible for maintaining the image.
	Author string `json:"author,omitempty"`

	Platform

	// Config defines the execution parameters which should be used as a base when running a container using the image.
	Config ImageConfig `json:"config,omitempty"`

	// RootFS references the layer content addresses used by the image.
	RootFS RootFS `json:"rootfs"`

	// History describes the history of each layer.
	History []History `json:"history,omitempty"`
}

Then all this copying wouldn't be needed, and we could just do

Suggested change
imgPlatform := platforms.Normalize(ocispec.Platform{
OS: i.OS,
Architecture: i.Architecture,
Variant: i.Variant,
OSVersion: i.OSVersion,
OSFeatures: i.OSFeatures,
})
imgPlatform := platforms.Normalize(i.Platform)

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Violent agreement! 😅

There's probably a pretty decent argument to be made for the OCI's Image type to embed Platform directly (which would make this more straightforward) and/or to offer a helper function that appropriately extracts a Platform object from an Image object, but I didn't want the perfect to be the enemy of the good, and this seemed like a good place to start.

👀 ❤️ 😄

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would also be technically correct in that case to swap back to using Image in all these cases, but it feels like a huge amount of overkill to process the entire Image object, extract all the data, and then throw away all but at most five fields of it 😅

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh! Missed your last comments; I was updating my fork of the image-spec; opencontainers/image-spec#949

😂

I agree that just marshaling/unmarshaling the platform makes a lot of sense; but indeed more "correct" if it's actually embedded, which ties them together to be the same thing.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Given opencontainers/image-spec#949 is merged (which further legitimizes this PR's implementation), is this ready for re-review or do we want to do #7382 first and rebase this on top of that? 🙇

var unpack *Platform

imgPlatform := platforms.Normalize(ocispec.Platform{OS: i.OS, Architecture: i.Architecture})
imgPlatform := platforms.Normalize(ocispec.Platform{
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This can just be i.Platform now, I think?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Or is that not imported yet?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, that's #7382 😅

I guess I could import that change and take over from @thaJeztah if you'd like me to? (he seems busy enough that I bet he wouldn't mind 😂)

Copy link
Copy Markdown
Member

@cpuguy83 cpuguy83 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@tianon
Copy link
Copy Markdown
Member Author

tianon commented Dec 16, 2022

Rebased and rolled in #7382 (with an update to the merged version of opencontainers/image-spec#949 and to use i.Platform in the place @cpuguy83 pointed out -- @thaJeztah I put you as the co-author on the commit, but if you'd rather I'm happy to adjust it however you'd like, make you the only author, remove your changes, etc, whatever 👍).

@tianon
Copy link
Copy Markdown
Member Author

tianon commented Mar 27, 2023

(rebased and resolved conflicts)

@estesp
Copy link
Copy Markdown
Member

estesp commented Mar 27, 2023

The project checks want integration/go.mod to match up to the changes in go.mod 😇 Otherwise looks good

@thaJeztah
Copy link
Copy Markdown
Member

make vendor should probably do the trick;

vendor: ## ensure all the go.mod/go.sum files are up-to-date including vendor/ directory

@samuelkarp
Copy link
Copy Markdown
Member

/retest

1 similar comment
@samuelkarp
Copy link
Copy Markdown
Member

/retest

Copy link
Copy Markdown
Member

@thaJeztah thaJeztah left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM (ci is happy now!)

Copy link
Copy Markdown
Member

@thaJeztah thaJeztah left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@tianon could you rebase this one? (also left some suggestions for the comments)

Several bits of code unmarshal image config JSON into an `ocispec.Image`, and then immediately create an `ocispec.Platform` out of it, but then discard the original image *and* miss several potential platform fields (most notably, `variant`).

Because `ocispec.Platform` is a strict subset of `ocispec.Image`, most of these can be updated to simply unmarshal the image config directly to `ocispec.Platform` instead, which allows these additional fields to be picked up appropriately.

We can use `tianon/raspbian` as a concrete reproducer to demonstrate.

Before:

```console
$ ctr content fetch docker.io/tianon/raspbian:bullseye-slim
...

$ ctr image ls
REF                                     TYPE                                                 DIGEST                                                                  SIZE     PLATFORMS    LABELS
docker.io/tianon/raspbian:bullseye-slim application/vnd.docker.distribution.manifest.v2+json sha256:66e96f8af40691b335acc54e5f69711584ef7f926597b339e7d12ab90cc394ce 28.6 MiB linux/arm/v7 -
```

(Note that the `PLATFORMS` column lists `linux/arm/v7` -- the image itself is actually `linux/arm/v6`, but one of these bits of code leads to only `linux/arm` being extracted from the image config, which `platforms.Normalize` then updates to an explicit `v7`.)

After:

```console
$ ctr image ls
REF                                     TYPE                                                 DIGEST                                                                  SIZE     PLATFORMS    LABELS
docker.io/tianon/raspbian:bullseye-slim application/vnd.docker.distribution.manifest.v2+json sha256:66e96f8af40691b335acc54e5f69711584ef7f926597b339e7d12ab90cc394ce 28.6 MiB linux/arm/v6 -
```

Signed-off-by: Tianon Gravi <admwiggin@gmail.com>
Co-authored-by: Sebastiaan van Stijn <github@gone.nl>
@tianon
Copy link
Copy Markdown
Member Author

tianon commented May 30, 2023

Rebased and resolved discussion points 👍

Copy link
Copy Markdown
Member

@thaJeztah thaJeztah left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, thanks!

@samuelkarp samuelkarp merged commit 8b66a75 into containerd:main May 31, 2023
@tianon tianon deleted the oci-platform branch May 31, 2023 01:22
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Archived in project

Development

Successfully merging this pull request may close these issues.

7 participants