diff --git a/internal/image/docker_schema2.go b/internal/image/docker_schema2.go index 23a21999aa..a36e26006a 100644 --- a/internal/image/docker_schema2.go +++ b/internal/image/docker_schema2.go @@ -326,7 +326,7 @@ func (m *manifestSchema2) convertToManifestSchema1(ctx context.Context, options ID: v1ID, Parent: parentV1ID, Comment: historyEntry.Comment, - Created: historyEntry.Created, + Created: *historyEntry.Created, Author: historyEntry.Author, ThrowAway: historyEntry.EmptyLayer, } diff --git a/manifest/docker_schema1.go b/manifest/docker_schema1.go index e1f1fb9d98..f1895b4331 100644 --- a/manifest/docker_schema1.go +++ b/manifest/docker_schema1.go @@ -228,10 +228,24 @@ func (m *Schema1) Inspect(_ func(types.BlobInfo) ([]byte, error)) (*types.ImageI Architecture: s1.Architecture, Os: s1.OS, Layers: layerInfosToStrings(m.LayerInfos()), + LayersDetail: imgInspectLayersFromLayerInfos(m.LayerInfos()), + History: nil, + Author: s1.Author, + Size: s1.Size, } 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 } diff --git a/manifest/docker_schema2.go b/manifest/docker_schema2.go index e79d0851f2..c84c7bcac0 100644 --- a/manifest/docker_schema2.go +++ b/manifest/docker_schema2.go @@ -9,6 +9,7 @@ import ( "github.com/containers/image/v5/pkg/strslice" "github.com/containers/image/v5/types" "github.com/opencontainers/go-digest" + imgspecv1 "github.com/opencontainers/image-spec/specs-go/v1" ) // Schema2Descriptor is a “descriptor” in docker/distribution schema 2. @@ -151,11 +152,11 @@ type Schema2History struct { // Schema2Image is an Image in docker/docker/image. 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"` + Parent digest.Digest `json:"parent,omitempty"` + RootFS *Schema2RootFS `json:"rootfs,omitempty"` + History []imgspecv1.History `json:"history,omitempty"` + OSVersion string `json:"os.version,omitempty"` + OSFeatures []string `json:"os.features,omitempty"` } // Schema2FromManifest creates a Schema2 manifest instance from a manifest blob. @@ -215,6 +216,19 @@ func (m *Schema2) LayerInfos() []LayerInfo { return blobs } +// 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 +} + var schema2CompressionMIMETypeSets = []compressionMIMETypeSet{ { mtsUncompressed: DockerV2Schema2ForeignLayerMediaType, @@ -279,10 +293,24 @@ func (m *Schema2) Inspect(configGetter func(types.BlobInfo) ([]byte, error)) (*t Variant: s2.Variant, Os: s2.OS, Layers: layerInfosToStrings(m.LayerInfos()), + LayersDetail: imgInspectLayersFromLayerInfos(m.LayerInfos()), + History: 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 } return i, nil } diff --git a/manifest/oci.go b/manifest/oci.go index fc325009ce..63a7439f7e 100644 --- a/manifest/oci.go +++ b/manifest/oci.go @@ -220,7 +220,12 @@ func (m *OCI1) Inspect(configGetter func(types.BlobInfo) ([]byte, error)) (*type Architecture: v1.Architecture, Os: v1.OS, Layers: layerInfosToStrings(m.LayerInfos()), + LayersDetail: imgInspectLayersFromLayerInfos(m.LayerInfos()), Env: v1.Config.Env, + History: v1.History, + Author: v1.Author, + Size: d1.Size, + Config: v1.Config, } return i, nil } diff --git a/types/types.go b/types/types.go index dcff8caf76..6503328a2c 100644 --- a/types/types.go +++ b/types/types.go @@ -466,6 +466,18 @@ type ImageInspectInfo struct { Os string Layers []string Env []string + LayersDetail []LayerDetail + History []v1.History + Author string + Size int64 + Config v1.ImageConfig +} + +type LayerDetail struct { + MIMEType string + Digest digest.Digest + Size int64 + Annotations map[string]string } // DockerAuthConfig contains authorization information for connecting to a registry.