Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

enhance skopeo inspect #1608

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open

Conversation

ningmingxiao
Copy link
Contributor

Signed-off-by: ningmingxiao ning.mingxiao@zte.com.cn

@ningmingxiao
Copy link
Contributor Author

skopeo inspect can't see whether an image's MediaType,I want to use MediaType to check whether it is enctryed.

Copy link
Collaborator

@mtrmac mtrmac left a comment

Choose a reason for hiding this comment

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

Thanks for the PR.

c/image is following the Go semantic versioning rules, so we must not incompatibly change the externally-visible API like this (and we have no appetite for increasing the major version number either).

This needs to be done by adding new fields, without modifying any of the existing ones.

manifest/common.go Outdated Show resolved Hide resolved
types/types.go Outdated Show resolved Hide resolved
types/types.go Outdated Show resolved Hide resolved
types/types.go Outdated Show resolved Hide resolved
types/types.go Outdated Show resolved Hide resolved
manifest/oci.go Outdated Show resolved Hide resolved
Copy link
Collaborator

@mtrmac mtrmac left a comment

Choose a reason for hiding this comment

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

This PR keeps growing…

While the additions are certainly valuable, perhaps it might be better to get one feature done, and then add others similarly, in one or more smaller PRs.

types/types.go Outdated
History []v1.History
Author string
Size int64
Config v1.ImageConfig
Copy link
Collaborator

Choose a reason for hiding this comment

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

Adding a full config here is redundant with Image.OCIConfig, and probably unwanted for the Inspect caller, who is calling Inspect exactly not to deal with the details of the config format.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I use podman or docker inspect an image, they will show config, so I think we should stay the same with docker or podman

Copy link
Collaborator

Choose a reason for hiding this comment

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

But then are other callers like skopeo inspect, or automation that just wants a single element (like looking up a single label) that don’t need both at the same time. Paying the cost of the full conversion and JSON formatting is not all that great for them.

As a maintainer, I’d also much prefer not to have to maintain logic to convert to OCI format in two separate implementations for each format.

Config v1.ImageConfig
}

type LayerDetail struct {
Copy link
Collaborator

Choose a reason for hiding this comment

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

ImageInspectLayer?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I think ImageInspectLayer and Layers are same meaning, at ImageInspectInfo struct

Copy link
Collaborator

Choose a reason for hiding this comment

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

The types subpackage contains quite a few types … and it’s useful to make it clear that the purpose of this struct is only as an inspect output.

We already have types.BlobInfo (and manifest.LayerInfo); being clear about the purposes of each (especially when there is no written documentation) is helpful to users of the API.

(Especially when may users are just going to use Inspect().LayersDetail… without having to name the type, we need the type name more to be unambiguous than we need it to be short.)

types/types.go Outdated
@@ -466,6 +466,18 @@ type ImageInspectInfo struct {
Os string
Layers []string
Env []string
LayersDetail []LayerDetail
History []v1.History
Copy link
Collaborator

Choose a reason for hiding this comment

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

As this very PR shows, it’s valuable to be able to add extra fields — so a separate ImageInspectHistory where we can add fields to would be better than forever tying this to OCIv1, and potentially having to add a HistoryDetail.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

you means I should use another func ImageInspectHistory to show history? When I use podman inspect an image, I can see history

Copy link
Collaborator

Choose a reason for hiding this comment

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

I mean that the type of the field should be History []ImageInpectHistory.

manifest/oci.go Outdated
Env: v1.Config.Env,
History: v1.History,
Author: v1.Author,
Size: d1.Size,
Copy link
Collaborator

Choose a reason for hiding this comment

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

Size is not defined in OCI — so the ImageInspectInfo documentation for the field must document how “unknown” is represented, and this code needs to set that value.

(0 is not a good “unknown” value for a size field, in principle… We typically use -1.)

Copy link
Collaborator

Choose a reason for hiding this comment

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

Still outstanding: The -1 value needs documenting.

manifest/docker_schema2.go Outdated Show resolved Hide resolved
internal/image/docker_schema2.go Outdated Show resolved Hide resolved
manifest/docker_schema1.go Outdated Show resolved Hide resolved
manifest/oci.go Outdated Show resolved Hide resolved
types/types.go Outdated
@@ -466,6 +466,18 @@ type ImageInspectInfo struct {
Os string
Layers []string
Env []string
LayersDetail []LayerDetail
History []v1.History
Copy link
Collaborator

Choose a reason for hiding this comment

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

For History, we need to worry about promised semantics, if any; e.g. is the number of entries supposed to match the number of layers? (That needs to be very careful about the EmptyLayer bit in OCI — so the number of non-empty layers?) Is “unknown” a possible value?

Copy link
Collaborator

Choose a reason for hiding this comment

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

Outstanding.

types/types.go Outdated
LayersDetail []LayerDetail
History []v1.History
Author string
Size int64
Copy link
Collaborator

Choose a reason for hiding this comment

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

Size of what? The compressed representation? Uncompressed representation? Either, depending on circumstances?

In OCI this can apparently be unknown.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Still outstanding; the added comment doesn’t answer this question.

@mtrmac
Copy link
Collaborator

mtrmac commented Jul 19, 2022

Unit test coverage, to make sure this does not accidentally break, would also be nice. (And, looking at how the existing tests fail, it’s in a sense unavoidable at least to that little extent.)

Signed-off-by: ningmingxiao <ning.mingxiao@zte.com.cn>
assert.Equal(t, Env, ii.Env)
assert.NotEqual(t, nil, ii.Config)
assert.Equal(t, int64(0), ii.Size)
assert.Equal(t, "", ii.Author)
Copy link
Collaborator

@mtrmac mtrmac Jul 20, 2022

Choose a reason for hiding this comment

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

Please maintain the original whole-structure comparison.

A single Equal over the whole structure is more useful because it ensures that nothing was left out in the tests. Doing this item by item requires much more manual inspection and maintenance.

(In all three formats.)

assert.Equal(t, int64(0), ii.Size)
assert.Equal(t, "", ii.Author)
for _, layer := range ii.LayersDetail {
assert.NotEqual(t, nil, layer)
Copy link
Collaborator

@mtrmac mtrmac Jul 20, 2022

Choose a reason for hiding this comment

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

AFAICS that’s always true (members of the slice are not pointers at all), and does not test the created contents at all. That’s not useful.

Same for the other loop.

types/types.go Outdated
History []v1.History
Author string
Size int64
Config v1.ImageConfig
Copy link
Collaborator

Choose a reason for hiding this comment

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

But then are other callers like skopeo inspect, or automation that just wants a single element (like looking up a single label) that don’t need both at the same time. Paying the cost of the full conversion and JSON formatting is not all that great for them.

As a maintainer, I’d also much prefer not to have to maintain logic to convert to OCI format in two separate implementations for each format.

func schema2HistoryToV1History(history []Schema2History) []v1.History {
v1History := make([]v1.History, len(history))
for index, value := range history {
v1History[index].Created = &value.Created
Copy link
Collaborator

Choose a reason for hiding this comment

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

created := value.Created
v1History[index].Created = &created

would be more obviously safe, because the pointer points at an individually-allocated value that will never be modified by whatever owns the input history value.

i := &types.ImageInspectInfo{
Tag: "",
Created: v1.Created,
DockerVersion: d1.DockerVersion,
Labels: v1.Config.Labels,
Architecture: v1.Architecture,
Os: v1.OS,
Layers: layerInfosToStrings(m.LayerInfos()),
Layers: layerInfosToStrings(layerInfos),
Copy link
Collaborator

Choose a reason for hiding this comment

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

Please keep the order of fields in the initializer the same as in the type definition, to make it easier to tell which fields were / were not set. (Everywhere.)

}

diffIDs := []digest.Digest{digest.FromString(s1.ID)}
Copy link
Collaborator

Choose a reason for hiding this comment

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

s1.ID is not a diffID, and the single-value array would frequently not even have the right number of elements.

Passing an empty value would at least be consistent with the existing OCIConfig call.

(This is another reason not to include all of OCIv1 config in the inspect output: the value is not fully valid, and the OCIConfig API is focused enough on this single thing that it can document that at least a bit more effectively.)


Actually the best thing to do is not to involve the schema2 JSON format at all: refactor the convertedHistory computation out from ToSchema2Config into a separate function, and call it here. Then

  • We don’t need to invent fake DiffID values
  • ToSchema2Config avoids a whole lot of JSON manipulation
  • This code can just consume convenient Go values instead of having to unmarshal again.

if err != nil {
return nil, err
}
imageConfig := &schema2Image{}
Copy link
Collaborator

Choose a reason for hiding this comment

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

(Why is this using a custom type and not the existing schema2 manifest.Schema2Image? But see elsewhere, we shouldn’t need to involve JSON for this.)

@@ -466,6 +466,19 @@ type ImageInspectInfo struct {
Os string
Layers []string
Env []string
LayersDetail []LayerDetail
Copy link
Collaborator

Choose a reason for hiding this comment

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

I think we can keep LayersDetail right next to Layers.

@TomSweeneyRedHat
Copy link
Member

@ningmingxiao needs a rebase

@mtrmac
Copy link
Collaborator

mtrmac commented Aug 8, 2022

#1626 follows up on this PR (with a subset of the functionality).

@mtrmac mtrmac added the kind/feature A request for, or a PR adding, new functionality label Dec 7, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
invalid kind/feature A request for, or a PR adding, new functionality
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants