Skip to content

Commit

Permalink
copy: set media types
Browse files Browse the repository at this point in the history
When copying an image, record the compression in the BlobInfo and use
the information when updating the manifest's layer infos to set the
layers' media types correctly.

Fixes: github.com/containers/podman/issues/2013
Fixes: github.com/containers/buildah/issues/1589

Signed-off-by: Valentin Rothberg <rothberg@redhat.com>
  • Loading branch information
vrothberg committed Jul 29, 2019
1 parent 6d69b60 commit 636e5d2
Show file tree
Hide file tree
Showing 7 changed files with 45 additions and 16 deletions.
5 changes: 5 additions & 0 deletions copy/copy.go
Original file line number Diff line number Diff line change
Expand Up @@ -869,6 +869,11 @@ func (c *copier) copyBlobFromStream(ctx context.Context, srcStream io.Reader, sr
return types.BlobInfo{}, errors.Wrap(err, "Error writing blob")
}

// If we can modify the layer's blob, set the desired compression for it to be set in the manifest.
if canModifyBlob && !isConfig {
uploadedInfo.Compression = c.dest.DesiredLayerCompression()
}

// This is fairly horrible: the writer from getOriginalLayerCopyWriter wants to consumer
// all of the input (to compute DiffIDs), even if dest.PutBlob does not need it.
// So, read everything from originalLayerReader, which will cause the rest to be
Expand Down
1 change: 1 addition & 0 deletions image/sourced.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ package image

import (
"context"

"github.com/containers/image/types"
)

Expand Down
6 changes: 6 additions & 0 deletions manifest/docker_schema1.go
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,12 @@ func (m *Schema1) UpdateLayerInfos(layerInfos []types.BlobInfo) error {
}
m.FSLayers = make([]Schema1FSLayers, len(layerInfos))
for i, info := range layerInfos {
switch info.Compression {
case types.Decompress:
m.FSLayers[(len(layerInfos)-1)-i].MediaType = DockerV2SchemaLayerMediaTypeUncompressed
case types.Compress:
m.FSLayers[(len(layerInfos)-1)-i].MediaType = DockerV2SchemaLayerMediaType
}
// (docker push) sets up m.ExtractedV1Compatibility[].{Id,Parent} based on values of info.Digest,
// but (docker pull) ignores them in favor of computing DiffIDs from uncompressed data, except verifying the child->parent links and uniqueness.
// So, we don't bother recomputing the IDs in m.History.V1Compatibility.
Expand Down
9 changes: 8 additions & 1 deletion manifest/docker_schema2.go
Original file line number Diff line number Diff line change
Expand Up @@ -207,7 +207,14 @@ func (m *Schema2) UpdateLayerInfos(layerInfos []types.BlobInfo) error {
original := m.LayersDescriptors
m.LayersDescriptors = make([]Schema2Descriptor, len(layerInfos))
for i, info := range layerInfos {
m.LayersDescriptors[i].MediaType = original[i].MediaType
switch info.Compression {
case types.PreserveOriginal:
m.LayersDescriptors[i].MediaType = original[i].MediaType
case types.Decompress:
m.LayersDescriptors[i].MediaType = DockerV2SchemaLayerMediaTypeUncompressed
case types.Compress:
m.LayersDescriptors[i].MediaType = DockerV2SchemaLayerMediaType
}
m.LayersDescriptors[i].Digest = info.Digest
m.LayersDescriptors[i].Size = info.Size
m.LayersDescriptors[i].URLs = info.URLs
Expand Down
2 changes: 2 additions & 0 deletions manifest/manifest.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ const (
DockerV2Schema2ConfigMediaType = "application/vnd.docker.container.image.v1+json"
// DockerV2Schema2LayerMediaType is the MIME type used for schema 2 layers.
DockerV2Schema2LayerMediaType = "application/vnd.docker.image.rootfs.diff.tar.gzip"
// DockerV2SchemaLayerMediaTypeUncompressed is the mediaType used for uncompressed layers.
DockerV2SchemaLayerMediaTypeUncompressed = "application/vnd.docker.image.rootfs.diff.tar"
// DockerV2ListMediaType MIME type represents Docker manifest schema 2 list
DockerV2ListMediaType = "application/vnd.docker.distribution.manifest.list.v2+json"
// DockerV2Schema2ForeignLayerMediaType is the MIME type used for schema 2 foreign layers.
Expand Down
9 changes: 8 additions & 1 deletion manifest/oci.go
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,14 @@ func (m *OCI1) UpdateLayerInfos(layerInfos []types.BlobInfo) error {
original := m.Layers
m.Layers = make([]imgspecv1.Descriptor, len(layerInfos))
for i, info := range layerInfos {
m.Layers[i].MediaType = original[i].MediaType
switch info.Compression {
case types.PreserveOriginal:
m.Layers[i].MediaType = original[i].MediaType
case types.Decompress:
m.Layers[i].MediaType = imgspecv1.MediaTypeImageLayer
case types.Compress:
m.Layers[i].MediaType = imgspecv1.MediaTypeImageLayerGzip
}
m.Layers[i].Digest = info.Digest
m.Layers[i].Size = info.Size
m.Layers[i].Annotations = info.Annotations
Expand Down
29 changes: 15 additions & 14 deletions types/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import (

"github.com/containers/image/docker/reference"
"github.com/opencontainers/go-digest"
"github.com/opencontainers/image-spec/specs-go/v1"
v1 "github.com/opencontainers/image-spec/specs-go/v1"
)

// ImageTransport is a top-level namespace for ways to to store/load an image.
Expand Down Expand Up @@ -90,6 +90,19 @@ type ImageReference interface {
DeleteImage(ctx context.Context, sys *SystemContext) error
}

// LayerCompression indicates if layers must be compressed, decompressed or preserved
type LayerCompression int

const (
// PreserveOriginal indicates the layer must be preserved, ie
// no compression or decompression.
PreserveOriginal LayerCompression = iota
// Decompress indicates the layer must be decompressed
Decompress
// Compress indicates the layer must be compressed
Compress
)

// BlobInfo collects known information about a blob (layer/config).
// In some situations, some fields may be unknown, in others they may be mandatory; documenting an “unknown” value here does not override that.
type BlobInfo struct {
Expand All @@ -98,6 +111,7 @@ type BlobInfo struct {
URLs []string
Annotations map[string]string
MediaType string
Compression LayerCompression
}

// BICTransportScope encapsulates transport-dependent representation of a “scope” where blobs are or are not present.
Expand Down Expand Up @@ -211,19 +225,6 @@ type ImageSource interface {
LayerInfosForCopy(ctx context.Context) ([]BlobInfo, error)
}

// LayerCompression indicates if layers must be compressed, decompressed or preserved
type LayerCompression int

const (
// PreserveOriginal indicates the layer must be preserved, ie
// no compression or decompression.
PreserveOriginal LayerCompression = iota
// Decompress indicates the layer must be decompressed
Decompress
// Compress indicates the layer must be compressed
Compress
)

// ImageDestination is a service, possibly remote (= slow), to store components of a single image.
//
// There is a specific required order for some of the calls:
Expand Down

0 comments on commit 636e5d2

Please sign in to comment.