-
Notifications
You must be signed in to change notification settings - Fork 379
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
base: main
Are you sure you want to change the base?
enhance skopeo inspect #1608
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -273,56 +273,71 @@ func TestManifestSchema1Inspect(t *testing.T) { | |
manifestSchema1FromFixture(t, "schema1.json"), | ||
manifestSchema1FromComponentsLikeFixture(t), | ||
} { | ||
|
||
labels := map[string]string{ | ||
"Kolla-SHA": "5.0.0-39-g6f1b947b", | ||
"architecture": "x86_64", | ||
"authoritative-source-url": "registry.access.redhat.com", | ||
"build-date": "2018-01-25T00:32:27.807261", | ||
"com.redhat.build-host": "ip-10-29-120-186.ec2.internal", | ||
"com.redhat.component": "openstack-nova-api-docker", | ||
"description": "Red Hat OpenStack Platform 12.0 nova-api", | ||
"distribution-scope": "public", | ||
"io.k8s.description": "Red Hat OpenStack Platform 12.0 nova-api", | ||
"io.k8s.display-name": "Red Hat OpenStack Platform 12.0 nova-api", | ||
"io.openshift.tags": "rhosp osp openstack osp-12.0", | ||
"kolla_version": "stable/pike", | ||
"name": "rhosp12/openstack-nova-api", | ||
"release": "20180124.1", | ||
"summary": "Red Hat OpenStack Platform 12.0 nova-api", | ||
"tripleo-common_version": "7.6.3-23-g4891cfe", | ||
"url": "https://access.redhat.com/containers/#/registry.access.redhat.com/rhosp12/openstack-nova-api/images/12.0-20180124.1", | ||
"vcs-ref": "9b31243b7b448eb2fc3b6e2c96935b948f806e98", | ||
"vcs-type": "git", | ||
"vendor": "Red Hat, Inc.", | ||
"version": "12.0", | ||
"version-release": "12.0-20180124.1", | ||
} | ||
|
||
Layers := []string{ | ||
"sha256:9cadd93b16ff2a0c51ac967ea2abfadfac50cfa3af8b5bf983d89b8f8647f3e4", | ||
"sha256:4aa565ad8b7a87248163ce7dba1dd3894821aac97e846b932ff6b8ef9a8a508a", | ||
"sha256:f576d102e09b9eef0e305aaef705d2d43a11bebc3fd5810a761624bd5e11997e", | ||
"sha256:9e92df2aea7dc0baf5f1f8d509678d6a6306de27ad06513f8e218371938c07a6", | ||
"sha256:62e48e39dc5b30b75a97f05bccc66efbae6058b860ee20a5c9a184b9d5e25788", | ||
"sha256:e623934bca8d1a74f51014256445937714481e49343a31bda2bc5f534748184d", | ||
} | ||
|
||
Env := []string{ | ||
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", | ||
"container=oci", | ||
"KOLLA_BASE_DISTRO=rhel", | ||
"KOLLA_INSTALL_TYPE=binary", | ||
"KOLLA_INSTALL_METATYPE=rhos", | ||
"PS1=$(tput bold)($(printenv KOLLA_SERVICE_NAME))$(tput sgr0)[$(id -un)@$(hostname -s) $(pwd)]$ ", | ||
} | ||
|
||
ii, err := m.Inspect(context.Background()) | ||
require.NoError(t, err) | ||
created := time.Date(2018, 1, 25, 0, 37, 48, 268558000, time.UTC) | ||
assert.Equal(t, types.ImageInspectInfo{ | ||
Tag: "latest", | ||
Created: &created, | ||
DockerVersion: "1.12.6", | ||
Labels: map[string]string{ | ||
"Kolla-SHA": "5.0.0-39-g6f1b947b", | ||
"architecture": "x86_64", | ||
"authoritative-source-url": "registry.access.redhat.com", | ||
"build-date": "2018-01-25T00:32:27.807261", | ||
"com.redhat.build-host": "ip-10-29-120-186.ec2.internal", | ||
"com.redhat.component": "openstack-nova-api-docker", | ||
"description": "Red Hat OpenStack Platform 12.0 nova-api", | ||
"distribution-scope": "public", | ||
"io.k8s.description": "Red Hat OpenStack Platform 12.0 nova-api", | ||
"io.k8s.display-name": "Red Hat OpenStack Platform 12.0 nova-api", | ||
"io.openshift.tags": "rhosp osp openstack osp-12.0", | ||
"kolla_version": "stable/pike", | ||
"name": "rhosp12/openstack-nova-api", | ||
"release": "20180124.1", | ||
"summary": "Red Hat OpenStack Platform 12.0 nova-api", | ||
"tripleo-common_version": "7.6.3-23-g4891cfe", | ||
"url": "https://access.redhat.com/containers/#/registry.access.redhat.com/rhosp12/openstack-nova-api/images/12.0-20180124.1", | ||
"vcs-ref": "9b31243b7b448eb2fc3b6e2c96935b948f806e98", | ||
"vcs-type": "git", | ||
"vendor": "Red Hat, Inc.", | ||
"version": "12.0", | ||
"version-release": "12.0-20180124.1", | ||
}, | ||
Architecture: "amd64", | ||
Os: "linux", | ||
Layers: []string{ | ||
"sha256:9cadd93b16ff2a0c51ac967ea2abfadfac50cfa3af8b5bf983d89b8f8647f3e4", | ||
"sha256:4aa565ad8b7a87248163ce7dba1dd3894821aac97e846b932ff6b8ef9a8a508a", | ||
"sha256:f576d102e09b9eef0e305aaef705d2d43a11bebc3fd5810a761624bd5e11997e", | ||
"sha256:9e92df2aea7dc0baf5f1f8d509678d6a6306de27ad06513f8e218371938c07a6", | ||
"sha256:62e48e39dc5b30b75a97f05bccc66efbae6058b860ee20a5c9a184b9d5e25788", | ||
"sha256:e623934bca8d1a74f51014256445937714481e49343a31bda2bc5f534748184d", | ||
}, | ||
Env: []string{ | ||
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", | ||
"container=oci", | ||
"KOLLA_BASE_DISTRO=rhel", | ||
"KOLLA_INSTALL_TYPE=binary", | ||
"KOLLA_INSTALL_METATYPE=rhos", | ||
"PS1=$(tput bold)($(printenv KOLLA_SERVICE_NAME))$(tput sgr0)[$(id -un)@$(hostname -s) $(pwd)]$ ", | ||
}, | ||
}, *ii) | ||
assert.Equal(t, "latest", ii.Tag) | ||
assert.Equal(t, &created, ii.Created) | ||
assert.Equal(t, "1.12.6", ii.DockerVersion) | ||
assert.Equal(t, labels, ii.Labels) | ||
assert.Equal(t, "amd64", ii.Architecture) | ||
assert.Equal(t, "linux", ii.Os) | ||
assert.Equal(t, Layers, ii.Layers) | ||
assert.Equal(t, Env, ii.Env) | ||
assert.NotEqual(t, nil, ii.Config) | ||
assert.Equal(t, int64(0), ii.Size) | ||
assert.Equal(t, "", ii.Author) | ||
for _, layer := range ii.LayersDetail { | ||
assert.NotEqual(t, nil, layer) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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. |
||
} | ||
assert.Equal(t, "", ii.Author) | ||
for _, history := range ii.History { | ||
assert.NotEqual(t, nil, history) | ||
} | ||
} | ||
} | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -6,6 +6,7 @@ import ( | |
|
||
compressiontypes "github.com/containers/image/v5/pkg/compression/types" | ||
"github.com/containers/image/v5/types" | ||
v1 "github.com/opencontainers/image-spec/specs-go/v1" | ||
"github.com/sirupsen/logrus" | ||
) | ||
|
||
|
@@ -228,3 +229,28 @@ func compressionVariantsRecognizeMIMEType(variantTable []compressionMIMETypeSet, | |
variants := findCompressionMIMETypeSet(variantTable, mimeType) | ||
return variants != nil // Alternatively, this could be len(variants) > 1, but really the caller should ask about a specific algorithm. | ||
} | ||
|
||
// imgInspectLayersFromLayerInfos converts a list of layer infos, presumably obtained from a Manifest.LayerInfos() | ||
// method call, into a format suitable for inclusion in a types.ImageInspectInfo structure. | ||
func imgInspectLayersFromLayerInfos(infos []LayerInfo) []types.LayerDetail { | ||
layers := make([]types.LayerDetail, len(infos)) | ||
for i, info := range infos { | ||
layers[i].MIMEType = info.MediaType | ||
layers[i].Digest = info.Digest | ||
layers[i].Size = info.Size | ||
layers[i].Annotations = info.Annotations | ||
} | ||
return layers | ||
} | ||
|
||
func schema2HistoryToV1History(history []Schema2History) []v1.History { | ||
v1History := make([]v1.History, len(history)) | ||
for index, value := range history { | ||
v1History[index].Created = &value.Created | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 |
||
v1History[index].Author = value.Author | ||
v1History[index].CreatedBy = value.CreatedBy | ||
v1History[index].Comment = value.Comment | ||
v1History[index].EmptyLayer = value.EmptyLayer | ||
} | ||
return v1History | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -215,23 +215,59 @@ func validateV1ID(id string) error { | |
return nil | ||
} | ||
|
||
type schema2Image struct { | ||
Schema2V1Image | ||
Parent digest.Digest `json:"parent,omitempty"` | ||
RootFS *Schema2RootFS `json:"rootfs,omitempty"` | ||
History []Schema2History `json:"history,omitempty"` | ||
OSVersion string `json:"os.version,omitempty"` | ||
OSFeatures []string `json:"os.features,omitempty"` | ||
} | ||
|
||
// Inspect returns various information for (skopeo inspect) parsed from the manifest and configuration. | ||
func (m *Schema1) Inspect(_ func(types.BlobInfo) ([]byte, error)) (*types.ImageInspectInfo, error) { | ||
s1 := &Schema2V1Image{} | ||
if err := json.Unmarshal([]byte(m.History[0].V1Compatibility), s1); err != nil { | ||
return nil, err | ||
} | ||
layerInfos := m.LayerInfos() | ||
i := &types.ImageInspectInfo{ | ||
Tag: m.Tag, | ||
Created: &s1.Created, | ||
DockerVersion: s1.DockerVersion, | ||
Architecture: s1.Architecture, | ||
Os: s1.OS, | ||
Layers: layerInfosToStrings(m.LayerInfos()), | ||
Layers: layerInfosToStrings(layerInfos), | ||
LayersDetail: imgInspectLayersFromLayerInfos(layerInfos), | ||
Author: s1.Author, | ||
Size: s1.Size, | ||
} | ||
|
||
diffIDs := []digest.Digest{digest.FromString(s1.ID)} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Passing an empty value would at least be consistent with the existing (This is another reason not to include all of OCIv1 config in the inspect output: the value is not fully valid, and the Actually the best thing to do is not to involve the schema2 JSON format at all: refactor the
|
||
schema2Config, err := m.ToSchema2Config(diffIDs) | ||
if err != nil { | ||
return nil, err | ||
} | ||
imageConfig := &schema2Image{} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. (Why is this using a custom type and not the existing schema2 |
||
if err := json.Unmarshal(schema2Config, imageConfig); err != nil { | ||
return nil, err | ||
} | ||
i.History = schema2HistoryToV1History(imageConfig.History) | ||
if s1.Config != nil { | ||
i.Labels = s1.Config.Labels | ||
i.Env = s1.Config.Env | ||
i.Config.Env = s1.Config.Env | ||
i.Config.Labels = s1.Config.Labels | ||
i.Config.User = s1.Config.User | ||
i.Config.Volumes = s1.Config.Volumes | ||
i.Config.Entrypoint = s1.Config.Entrypoint | ||
for key, value := range s1.Config.ExposedPorts { | ||
exposedPorts := make(map[string]struct{}) | ||
exposedPorts[string(key)] = value | ||
i.Config.ExposedPorts = exposedPorts | ||
} | ||
i.Config.StopSignal = s1.Config.StopSignal | ||
i.Config.WorkingDir = s1.Config.WorkingDir | ||
} | ||
return i, nil | ||
} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -271,18 +271,35 @@ func (m *Schema2) Inspect(configGetter func(types.BlobInfo) ([]byte, error)) (*t | |
if err := json.Unmarshal(config, s2); err != nil { | ||
return nil, err | ||
} | ||
layerInfos := m.LayerInfos() | ||
i := &types.ImageInspectInfo{ | ||
Tag: "", | ||
Created: &s2.Created, | ||
DockerVersion: s2.DockerVersion, | ||
Architecture: s2.Architecture, | ||
Variant: s2.Variant, | ||
Os: s2.OS, | ||
Layers: layerInfosToStrings(m.LayerInfos()), | ||
Layers: layerInfosToStrings(layerInfos), | ||
LayersDetail: imgInspectLayersFromLayerInfos(layerInfos), | ||
History: schema2HistoryToV1History(s2.History), | ||
Author: s2.Author, | ||
Size: s2.Size, | ||
} | ||
if s2.Config != nil { | ||
i.Labels = s2.Config.Labels | ||
i.Env = s2.Config.Env | ||
i.Config.Env = s2.Config.Env | ||
i.Config.Labels = s2.Config.Labels | ||
i.Config.User = s2.Config.User | ||
i.Config.Volumes = s2.Config.Volumes | ||
i.Config.Entrypoint = s2.Config.Entrypoint | ||
for key, value := range s2.Config.ExposedPorts { | ||
exposedPorts := make(map[string]struct{}) | ||
exposedPorts[string(key)] = value | ||
i.Config.ExposedPorts = exposedPorts | ||
} | ||
i.Config.StopSignal = s2.Config.StopSignal | ||
i.Config.WorkingDir = s2.Config.WorkingDir | ||
Comment on lines
+291
to
+302
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. See the |
||
} | ||
return i, nil | ||
} | ||
|
There was a problem hiding this comment.
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.)