Do not re-tag non-distributable blob descriptors

Before this change buildkit was changing the media type for
non-distributable layers to normal layers.
It was also clearing out the urls to get those blobs.

Now the layer mediatype and URL's are preserved.
If a layer blob is seen more than once, if it has extra URL's they will
be appended to the stored value.

On export there is now a new exporter option to preserve the
non-distributable data values.
All URL's seen by buildkit will be added to the exported content.

Signed-off-by: Brian Goff <cpuguy83@gmail.com>
master
Brian Goff 2022-01-14 22:15:50 +00:00
parent 2f996517bc
commit 78bb7137ee
13 changed files with 245 additions and 43 deletions

1
cache/blobs.go vendored
View File

@ -306,6 +306,7 @@ func (sr *immutableRef) setBlob(ctx context.Context, compressionType compression
sr.queueBlob(desc.Digest) sr.queueBlob(desc.Digest)
sr.queueMediaType(desc.MediaType) sr.queueMediaType(desc.MediaType)
sr.queueBlobSize(desc.Size) sr.queueBlobSize(desc.Size)
sr.appendURLs(desc.URLs)
if err := sr.commitMetadata(); err != nil { if err := sr.commitMetadata(); err != nil {
return err return err
} }

1
cache/manager.go vendored
View File

@ -283,6 +283,7 @@ func (cm *cacheManager) GetByBlob(ctx context.Context, desc ocispecs.Descriptor,
rec.queueBlobOnly(blobOnly) rec.queueBlobOnly(blobOnly)
rec.queueMediaType(desc.MediaType) rec.queueMediaType(desc.MediaType)
rec.queueBlobSize(desc.Size) rec.queueBlobSize(desc.Size)
rec.appendURLs(desc.URLs)
rec.queueCommitted(true) rec.queueCommitted(true)
if err := rec.commitMetadata(); err != nil { if err := rec.commitMetadata(); err != nil {

59
cache/manager_test.go vendored
View File

@ -1508,6 +1508,65 @@ func checkVariantsCoverage(ctx context.Context, t *testing.T, variants idxToVari
require.Equal(t, 0, len(got)) require.Equal(t, 0, len(got))
} }
// Make sure that media type and urls are persisted for non-distributable blobs.
func TestNondistributableBlobs(t *testing.T) {
t.Parallel()
ctx := namespaces.WithNamespace(context.Background(), "buildkit-test")
tmpdir, err := ioutil.TempDir("", "cachemanager")
require.NoError(t, err)
defer os.RemoveAll(tmpdir)
snapshotter, err := native.NewSnapshotter(filepath.Join(tmpdir, "snapshots"))
require.NoError(t, err)
co, cleanup, err := newCacheManager(ctx, cmOpt{
snapshotter: snapshotter,
snapshotterName: "native",
})
require.NoError(t, err)
defer cleanup()
cm := co.manager
ctx, done, err := leaseutil.WithLease(ctx, co.lm, leaseutil.MakeTemporary)
require.NoError(t, err)
defer done(context.TODO())
contentBuffer := contentutil.NewBuffer()
descHandlers := DescHandlers(map[digest.Digest]*DescHandler{})
data, desc, err := mapToBlob(map[string]string{"foo": "bar"}, false)
require.NoError(t, err)
// Pretend like this is non-distributable
desc.MediaType = ocispecs.MediaTypeImageLayerNonDistributable
desc.URLs = []string{"https://buildkit.moby.dev/foo"}
cw, err := contentBuffer.Writer(ctx)
require.NoError(t, err)
_, err = cw.Write(data)
require.NoError(t, err)
err = cw.Commit(ctx, 0, cw.Digest())
require.NoError(t, err)
descHandlers[desc.Digest] = &DescHandler{
Provider: func(_ session.Group) content.Provider { return contentBuffer },
}
ref, err := cm.GetByBlob(ctx, desc, nil, descHandlers)
require.NoError(t, err)
remotes, err := ref.GetRemotes(ctx, true, compression.Config{}, false, nil)
require.NoError(t, err)
desc2 := remotes[0].Descriptors[0]
require.Equal(t, desc.MediaType, desc2.MediaType)
require.Equal(t, desc.URLs, desc2.URLs)
}
func checkInfo(ctx context.Context, t *testing.T, cs content.Store, info content.Info) { func checkInfo(ctx context.Context, t *testing.T, cs content.Store, info content.Info) {
if info.Labels == nil { if info.Labels == nil {
return return

45
cache/metadata.go vendored
View File

@ -37,6 +37,7 @@ const keyMediaType = "cache.mediatype"
const keyImageRefs = "cache.imageRefs" const keyImageRefs = "cache.imageRefs"
const keyDeleted = "cache.deleted" const keyDeleted = "cache.deleted"
const keyBlobSize = "cache.blobsize" // the packed blob size as specified in the oci descriptor const keyBlobSize = "cache.blobsize" // the packed blob size as specified in the oci descriptor
const keyURLs = "cache.layer.urls"
// Indexes // Indexes
const blobchainIndex = "blobchainid:" const blobchainIndex = "blobchainid:"
@ -281,6 +282,17 @@ func (md *cacheMetadata) queueBlob(str digest.Digest) error {
return md.queueValue(keyBlob, str, "") return md.queueValue(keyBlob, str, "")
} }
func (md *cacheMetadata) appendURLs(urls []string) error {
if len(urls) == 0 {
return nil
}
return md.appendStringSlice(keyURLs, urls...)
}
func (md *cacheMetadata) getURLs() []string {
return md.GetStringSlice(keyURLs)
}
func (md *cacheMetadata) getBlob() digest.Digest { func (md *cacheMetadata) getBlob() digest.Digest {
return digest.Digest(md.GetString(keyBlob)) return digest.Digest(md.GetString(keyBlob))
} }
@ -468,6 +480,18 @@ func (md *cacheMetadata) GetString(key string) string {
return str return str
} }
func (md *cacheMetadata) GetStringSlice(key string) []string {
v := md.si.Get(key)
if v == nil {
return nil
}
var val []string
if err := v.Unmarshal(&val); err != nil {
return nil
}
return val
}
func (md *cacheMetadata) setTime(key string, value time.Time, index string) error { func (md *cacheMetadata) setTime(key string, value time.Time, index string) error {
return md.setValue(key, value.UnixNano(), index) return md.setValue(key, value.UnixNano(), index)
} }
@ -512,7 +536,7 @@ func (md *cacheMetadata) getInt64(key string) (int64, bool) {
return i, true return i, true
} }
func (md *cacheMetadata) appendStringSlice(key string, value string) error { func (md *cacheMetadata) appendStringSlice(key string, values ...string) error {
return md.si.GetAndSetValue(key, func(v *metadata.Value) (*metadata.Value, error) { return md.si.GetAndSetValue(key, func(v *metadata.Value) (*metadata.Value, error) {
var slice []string var slice []string
if v != nil { if v != nil {
@ -520,12 +544,25 @@ func (md *cacheMetadata) appendStringSlice(key string, value string) error {
return nil, err return nil, err
} }
} }
idx := make(map[string]struct{}, len(values))
for _, v := range values {
idx[v] = struct{}{}
}
for _, existing := range slice { for _, existing := range slice {
if existing == value { if _, ok := idx[existing]; ok {
return nil, metadata.ErrSkipSetValue delete(idx, existing)
} }
} }
slice = append(slice, value)
if len(idx) == 0 {
return nil, metadata.ErrSkipSetValue
}
for value := range idx {
slice = append(slice, value)
}
v, err := metadata.NewValue(slice) v, err := metadata.NewValue(slice)
if err != nil { if err != nil {
return nil, err return nil, err

2
cache/refs.go vendored
View File

@ -600,6 +600,7 @@ func (sr *immutableRef) ociDesc(ctx context.Context, dhs DescHandlers) (ocispecs
Size: sr.getBlobSize(), Size: sr.getBlobSize(),
MediaType: sr.getMediaType(), MediaType: sr.getMediaType(),
Annotations: make(map[string]string), Annotations: make(map[string]string),
URLs: sr.getURLs(),
} }
if blobDesc, err := getBlobDesc(ctx, sr.cm.ContentStore, desc.Digest); err == nil { if blobDesc, err := getBlobDesc(ctx, sr.cm.ContentStore, desc.Digest); err == nil {
@ -748,6 +749,7 @@ func getBlobDesc(ctx context.Context, cs content.Store, dgst digest.Digest) (oci
if !ok { if !ok {
return ocispecs.Descriptor{}, fmt.Errorf("no media type is stored for %q", info.Digest) return ocispecs.Descriptor{}, fmt.Errorf("no media type is stored for %q", info.Digest)
} }
desc := ocispecs.Descriptor{ desc := ocispecs.Descriptor{
Digest: info.Digest, Digest: info.Digest,
Size: info.Size, Size: info.Size,

1
cache/remote.go vendored
View File

@ -224,6 +224,7 @@ func (sr *immutableRef) getRemote(ctx context.Context, createIfNeeded bool, comp
newDesc.MediaType = blobDesc.MediaType newDesc.MediaType = blobDesc.MediaType
newDesc.Digest = blobDesc.Digest newDesc.Digest = blobDesc.Digest
newDesc.Size = blobDesc.Size newDesc.Size = blobDesc.Size
newDesc.URLs = blobDesc.URLs
newDesc.Annotations = nil newDesc.Annotations = nil
for _, k := range addAnnotations { for _, k := range addAnnotations {
newDesc.Annotations[k] = desc.Annotations[k] newDesc.Annotations[k] = desc.Annotations[k]

View File

@ -44,6 +44,10 @@ const (
keyCompressionLevel = "compression-level" keyCompressionLevel = "compression-level"
keyBuildInfo = "buildinfo" keyBuildInfo = "buildinfo"
ociTypes = "oci-mediatypes" ociTypes = "oci-mediatypes"
// propagateNondistLayersKey is an exporter option which can be used to mark a layer as non-distributable if the layer reference was
// already found to use a non-distributable media type.
// When this option is not set, the exporter will change the media type of the layer to a distributable one.
propagateNondistLayersKey = "propagate-nondist-layers"
) )
type Opt struct { type Opt struct {
@ -181,6 +185,12 @@ func (e *imageExporter) Resolve(ctx context.Context, opt map[string]string) (exp
return nil, err return nil, err
} }
i.buildInfoMode = bimode i.buildInfoMode = bimode
case propagateNondistLayersKey:
b, err := strconv.ParseBool(v)
if err != nil {
return nil, errors.Wrapf(err, "non-bool value %s specified for %s", v, k)
}
i.propagateNondistLayers = b
default: default:
if i.meta == nil { if i.meta == nil {
i.meta = make(map[string][]byte) i.meta = make(map[string][]byte)
@ -197,19 +207,20 @@ func (e *imageExporter) Resolve(ctx context.Context, opt map[string]string) (exp
type imageExporterInstance struct { type imageExporterInstance struct {
*imageExporter *imageExporter
targetName string targetName string
push bool push bool
pushByDigest bool pushByDigest bool
unpack bool unpack bool
insecure bool insecure bool
ociTypes bool ociTypes bool
nameCanonical bool nameCanonical bool
danglingPrefix string danglingPrefix string
layerCompression compression.Type layerCompression compression.Type
forceCompression bool forceCompression bool
compressionLevel *int compressionLevel *int
buildInfoMode buildinfo.ExportMode buildInfoMode buildinfo.ExportMode
meta map[string][]byte meta map[string][]byte
propagateNondistLayers bool
} }
func (e *imageExporterInstance) Name() string { func (e *imageExporterInstance) Name() string {
@ -244,7 +255,7 @@ func (e *imageExporterInstance) Export(ctx context.Context, src exporter.Source,
} }
defer done(context.TODO()) defer done(context.TODO())
desc, err := e.opt.ImageWriter.Commit(ctx, src, e.ociTypes, e.compression(), e.buildInfoMode, sessionID) desc, err := e.opt.ImageWriter.Commit(ctx, src, e.ociTypes, e.compression(), e.buildInfoMode, e.propagateNondistLayers, sessionID)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@ -21,6 +21,7 @@ import (
"github.com/moby/buildkit/util/bklog" "github.com/moby/buildkit/util/bklog"
"github.com/moby/buildkit/util/buildinfo" "github.com/moby/buildkit/util/buildinfo"
"github.com/moby/buildkit/util/compression" "github.com/moby/buildkit/util/compression"
"github.com/moby/buildkit/util/convert"
"github.com/moby/buildkit/util/progress" "github.com/moby/buildkit/util/progress"
"github.com/moby/buildkit/util/system" "github.com/moby/buildkit/util/system"
"github.com/moby/buildkit/util/tracing" "github.com/moby/buildkit/util/tracing"
@ -48,7 +49,7 @@ type ImageWriter struct {
opt WriterOpt opt WriterOpt
} }
func (ic *ImageWriter) Commit(ctx context.Context, inp exporter.Source, oci bool, comp compression.Config, buildInfoMode buildinfo.ExportMode, sessionID string) (*ocispecs.Descriptor, error) { func (ic *ImageWriter) Commit(ctx context.Context, inp exporter.Source, oci bool, comp compression.Config, buildInfoMode buildinfo.ExportMode, propagateNonDist bool, sessionID string) (*ocispecs.Descriptor, error) {
platformsBytes, ok := inp.Metadata[exptypes.ExporterPlatformsKey] platformsBytes, ok := inp.Metadata[exptypes.ExporterPlatformsKey]
if len(inp.Refs) > 0 && !ok { if len(inp.Refs) > 0 && !ok {
@ -56,6 +57,7 @@ func (ic *ImageWriter) Commit(ctx context.Context, inp exporter.Source, oci bool
} }
if len(inp.Refs) == 0 { if len(inp.Refs) == 0 {
// TODO: pass through non-dist layers?
remotes, err := ic.exportLayers(ctx, comp, session.NewGroup(sessionID), inp.Ref) remotes, err := ic.exportLayers(ctx, comp, session.NewGroup(sessionID), inp.Ref)
if err != nil { if err != nil {
return nil, err return nil, err
@ -66,7 +68,7 @@ func (ic *ImageWriter) Commit(ctx context.Context, inp exporter.Source, oci bool
buildInfo = inp.Metadata[exptypes.ExporterBuildInfo] buildInfo = inp.Metadata[exptypes.ExporterBuildInfo]
} }
mfstDesc, configDesc, err := ic.commitDistributionManifest(ctx, inp.Ref, inp.Metadata[exptypes.ExporterImageConfigKey], &remotes[0], oci, inp.Metadata[exptypes.ExporterInlineCache], buildInfo) mfstDesc, configDesc, err := ic.commitDistributionManifest(ctx, inp.Ref, inp.Metadata[exptypes.ExporterImageConfigKey], &remotes[0], oci, inp.Metadata[exptypes.ExporterInlineCache], buildInfo, propagateNonDist)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -94,6 +96,7 @@ func (ic *ImageWriter) Commit(ctx context.Context, inp exporter.Source, oci bool
refs = append(refs, r) refs = append(refs, r)
} }
// TODO: Pass through non-distributable layers
remotes, err := ic.exportLayers(ctx, comp, session.NewGroup(sessionID), refs...) remotes, err := ic.exportLayers(ctx, comp, session.NewGroup(sessionID), refs...)
if err != nil { if err != nil {
return nil, err return nil, err
@ -133,7 +136,7 @@ func (ic *ImageWriter) Commit(ctx context.Context, inp exporter.Source, oci bool
buildInfo = inp.Metadata[fmt.Sprintf("%s/%s", exptypes.ExporterBuildInfo, p.ID)] buildInfo = inp.Metadata[fmt.Sprintf("%s/%s", exptypes.ExporterBuildInfo, p.ID)]
} }
desc, _, err := ic.commitDistributionManifest(ctx, r, config, &remotes[remotesMap[p.ID]], oci, inlineCache, buildInfo) desc, _, err := ic.commitDistributionManifest(ctx, r, config, &remotes[remotesMap[p.ID]], oci, inlineCache, buildInfo, propagateNonDist)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -202,7 +205,7 @@ func (ic *ImageWriter) exportLayers(ctx context.Context, comp compression.Config
return out, err return out, err
} }
func (ic *ImageWriter) commitDistributionManifest(ctx context.Context, ref cache.ImmutableRef, config []byte, remote *solver.Remote, oci bool, inlineCache []byte, buildInfo []byte) (*ocispecs.Descriptor, *ocispecs.Descriptor, error) { func (ic *ImageWriter) commitDistributionManifest(ctx context.Context, ref cache.ImmutableRef, config []byte, remote *solver.Remote, oci bool, inlineCache []byte, buildInfo []byte, propagateNonDist bool) (*ocispecs.Descriptor, *ocispecs.Descriptor, error) {
if len(config) == 0 { if len(config) == 0 {
var err error var err error
config, err = emptyImageConfig() config, err = emptyImageConfig()
@ -278,6 +281,10 @@ func (ic *ImageWriter) commitDistributionManifest(ctx context.Context, ref cache
} else { } else {
desc.Annotations = nil desc.Annotations = nil
} }
if !propagateNonDist {
desc.MediaType = convert.LayerToDistributable(oci, desc.MediaType)
desc.URLs = nil
}
mfst.Layers = append(mfst.Layers, desc) mfst.Layers = append(mfst.Layers, desc)
labels[fmt.Sprintf("containerd.io/gc.ref.content.%d", i+1)] = desc.Digest.String() labels[fmt.Sprintf("containerd.io/gc.ref.content.%d", i+1)] = desc.Digest.String()
} }

View File

@ -38,6 +38,10 @@ const (
keyForceCompression = "force-compression" keyForceCompression = "force-compression"
keyCompressionLevel = "compression-level" keyCompressionLevel = "compression-level"
keyBuildInfo = "buildinfo" keyBuildInfo = "buildinfo"
// propagateNondistLayersKey is an exporter option which can be used to mark a layer as non-distributable if the layer reference was
// already found to use a non-distributable media type.
// When this option is not set, the exporter will change the media type of the layer to a distributable one.
propagateNondistLayersKey = "propagate-nondist-layers"
) )
type Opt struct { type Opt struct {
@ -119,6 +123,12 @@ func (e *imageExporter) Resolve(ctx context.Context, opt map[string]string) (exp
return nil, err return nil, err
} }
i.buildInfoMode = bimode i.buildInfoMode = bimode
case propagateNondistLayersKey:
b, err := strconv.ParseBool(v)
if err != nil {
return nil, errors.Wrapf(err, "non-bool value specified for %s", k)
}
i.propagateNonDist = b
default: default:
if i.meta == nil { if i.meta == nil {
i.meta = make(map[string][]byte) i.meta = make(map[string][]byte)
@ -147,6 +157,7 @@ type imageExporterInstance struct {
forceCompression bool forceCompression bool
compressionLevel *int compressionLevel *int
buildInfoMode buildinfo.ExportMode buildInfoMode buildinfo.ExportMode
propagateNonDist bool
} }
func (e *imageExporterInstance) Name() string { func (e *imageExporterInstance) Name() string {
@ -185,7 +196,7 @@ func (e *imageExporterInstance) Export(ctx context.Context, src exporter.Source,
} }
defer done(context.TODO()) defer done(context.TODO())
desc, err := e.opt.ImageWriter.Commit(ctx, src, e.ociTypes, e.compression(), e.buildInfoMode, sessionID) desc, err := e.opt.ImageWriter.Commit(ctx, src, e.ociTypes, e.compression(), e.buildInfoMode, e.propagateNonDist, sessionID)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@ -4,6 +4,7 @@ import (
"context" "context"
"io/ioutil" "io/ioutil"
"os" "os"
"strconv"
"strings" "strings"
"time" "time"
@ -14,10 +15,18 @@ import (
"github.com/moby/buildkit/session/filesync" "github.com/moby/buildkit/session/filesync"
"github.com/moby/buildkit/snapshot" "github.com/moby/buildkit/snapshot"
"github.com/moby/buildkit/util/progress" "github.com/moby/buildkit/util/progress"
"github.com/pkg/errors"
"github.com/tonistiigi/fsutil" "github.com/tonistiigi/fsutil"
fstypes "github.com/tonistiigi/fsutil/types" fstypes "github.com/tonistiigi/fsutil/types"
) )
const (
// propagateNondistLayersKey is an exporter option which can be used to mark a layer as non-distributable if the layer reference was
// already found to use a non-distributable media type.
// When this option is not set, the exporter will change the media type of the layer to a distributable one.
propagateNondistLayersKey = "propagate-nondist-layers"
)
type Opt struct { type Opt struct {
SessionManager *session.Manager SessionManager *session.Manager
} }
@ -34,11 +43,22 @@ func New(opt Opt) (exporter.Exporter, error) {
func (e *localExporter) Resolve(ctx context.Context, opt map[string]string) (exporter.ExporterInstance, error) { func (e *localExporter) Resolve(ctx context.Context, opt map[string]string) (exporter.ExporterInstance, error) {
li := &localExporterInstance{localExporter: e} li := &localExporterInstance{localExporter: e}
v, ok := opt[propagateNondistLayersKey]
if ok {
b, err := strconv.ParseBool(v)
if err != nil {
return nil, errors.Wrapf(err, "non-bool value for %s: %s", propagateNondistLayersKey, v)
}
li.propagateNonDist = b
}
return li, nil return li, nil
} }
type localExporterInstance struct { type localExporterInstance struct {
*localExporter *localExporter
propagateNonDist bool
} }
func (e *localExporterInstance) Name() string { func (e *localExporterInstance) Name() string {

View File

@ -116,11 +116,11 @@ func (ct Type) IsMediaType(mt string) bool {
func FromMediaType(mediaType string) Type { func FromMediaType(mediaType string) Type {
switch toOCILayerType[mediaType] { switch toOCILayerType[mediaType] {
case ocispecs.MediaTypeImageLayer: case ocispecs.MediaTypeImageLayer, ocispecs.MediaTypeImageLayerNonDistributable:
return Uncompressed return Uncompressed
case ocispecs.MediaTypeImageLayerGzip: case ocispecs.MediaTypeImageLayerGzip, ocispecs.MediaTypeImageLayerNonDistributableGzip:
return Gzip return Gzip
case mediaTypeImageLayerZstd: case mediaTypeImageLayerZstd, ocispecs.MediaTypeImageLayerNonDistributableZstd:
return Zstd return Zstd
default: default:
return UnknownCompression return UnknownCompression
@ -193,25 +193,30 @@ func detectCompressionType(cr *io.SectionReader) (Type, error) {
} }
var toDockerLayerType = map[string]string{ var toDockerLayerType = map[string]string{
ocispecs.MediaTypeImageLayer: images.MediaTypeDockerSchema2Layer, ocispecs.MediaTypeImageLayer: images.MediaTypeDockerSchema2Layer,
images.MediaTypeDockerSchema2Layer: images.MediaTypeDockerSchema2Layer, images.MediaTypeDockerSchema2Layer: images.MediaTypeDockerSchema2Layer,
ocispecs.MediaTypeImageLayerGzip: images.MediaTypeDockerSchema2LayerGzip, ocispecs.MediaTypeImageLayerGzip: images.MediaTypeDockerSchema2LayerGzip,
images.MediaTypeDockerSchema2LayerGzip: images.MediaTypeDockerSchema2LayerGzip, images.MediaTypeDockerSchema2LayerGzip: images.MediaTypeDockerSchema2LayerGzip,
images.MediaTypeDockerSchema2LayerForeign: images.MediaTypeDockerSchema2Layer, images.MediaTypeDockerSchema2LayerForeign: images.MediaTypeDockerSchema2LayerForeign,
images.MediaTypeDockerSchema2LayerForeignGzip: images.MediaTypeDockerSchema2LayerGzip, images.MediaTypeDockerSchema2LayerForeignGzip: images.MediaTypeDockerSchema2LayerForeignGzip,
mediaTypeImageLayerZstd: mediaTypeDockerSchema2LayerZstd, ocispecs.MediaTypeImageLayerNonDistributable: images.MediaTypeDockerSchema2LayerForeign,
mediaTypeDockerSchema2LayerZstd: mediaTypeDockerSchema2LayerZstd, ocispecs.MediaTypeImageLayerNonDistributableGzip: images.MediaTypeDockerSchema2LayerForeignGzip,
mediaTypeImageLayerZstd: mediaTypeDockerSchema2LayerZstd,
mediaTypeDockerSchema2LayerZstd: mediaTypeDockerSchema2LayerZstd,
} }
var toOCILayerType = map[string]string{ var toOCILayerType = map[string]string{
ocispecs.MediaTypeImageLayer: ocispecs.MediaTypeImageLayer, ocispecs.MediaTypeImageLayer: ocispecs.MediaTypeImageLayer,
images.MediaTypeDockerSchema2Layer: ocispecs.MediaTypeImageLayer, ocispecs.MediaTypeImageLayerNonDistributable: ocispecs.MediaTypeImageLayerNonDistributable,
ocispecs.MediaTypeImageLayerGzip: ocispecs.MediaTypeImageLayerGzip, ocispecs.MediaTypeImageLayerNonDistributableGzip: ocispecs.MediaTypeImageLayerNonDistributableGzip,
images.MediaTypeDockerSchema2LayerGzip: ocispecs.MediaTypeImageLayerGzip, ocispecs.MediaTypeImageLayerNonDistributableZstd: ocispecs.MediaTypeImageLayerNonDistributableZstd,
images.MediaTypeDockerSchema2LayerForeign: ocispecs.MediaTypeImageLayer, images.MediaTypeDockerSchema2Layer: ocispecs.MediaTypeImageLayer,
images.MediaTypeDockerSchema2LayerForeignGzip: ocispecs.MediaTypeImageLayerGzip, ocispecs.MediaTypeImageLayerGzip: ocispecs.MediaTypeImageLayerGzip,
mediaTypeImageLayerZstd: mediaTypeImageLayerZstd, images.MediaTypeDockerSchema2LayerGzip: ocispecs.MediaTypeImageLayerGzip,
mediaTypeDockerSchema2LayerZstd: mediaTypeImageLayerZstd, images.MediaTypeDockerSchema2LayerForeign: ocispecs.MediaTypeImageLayerNonDistributable,
images.MediaTypeDockerSchema2LayerForeignGzip: ocispecs.MediaTypeImageLayerNonDistributableGzip,
mediaTypeImageLayerZstd: mediaTypeImageLayerZstd,
mediaTypeDockerSchema2LayerZstd: mediaTypeImageLayerZstd,
} }
func convertLayerMediaType(mediaType string, oci bool) string { func convertLayerMediaType(mediaType string, oci bool) string {

37
util/convert/layer.go Normal file
View File

@ -0,0 +1,37 @@
package convert
import (
"github.com/containerd/containerd/images"
ocispecs "github.com/opencontainers/image-spec/specs-go/v1"
)
// LayertoDistributable changes the passed in media type to the "distributable" version of the media type.
func LayerToDistributable(oci bool, mt string) string {
if !images.IsNonDistributable(mt) {
// Layer is already a distributable media type (or this is not even a layer).
// No conversion needed
return mt
}
if oci {
switch mt {
case ocispecs.MediaTypeImageLayerNonDistributable:
return ocispecs.MediaTypeImageLayer
case ocispecs.MediaTypeImageLayerNonDistributableGzip:
return ocispecs.MediaTypeImageLayerGzip
case ocispecs.MediaTypeImageLayerNonDistributableZstd:
return ocispecs.MediaTypeImageLayerZstd
default:
return mt
}
}
switch mt {
case images.MediaTypeDockerSchema2LayerForeign:
return images.MediaTypeDockerSchema2Layer
case images.MediaTypeDockerSchema2LayerForeignGzip:
return images.MediaTypeDockerSchema2LayerGzip
default:
return mt
}
}

View File

@ -225,7 +225,17 @@ func (p *provider) ReaderAt(ctx context.Context, desc ocispecs.Descriptor) (cont
func filterLayerBlobs(metadata map[digest.Digest]ocispecs.Descriptor, mu sync.Locker) images.HandlerFunc { func filterLayerBlobs(metadata map[digest.Digest]ocispecs.Descriptor, mu sync.Locker) images.HandlerFunc {
return func(ctx context.Context, desc ocispecs.Descriptor) ([]ocispecs.Descriptor, error) { return func(ctx context.Context, desc ocispecs.Descriptor) ([]ocispecs.Descriptor, error) {
switch desc.MediaType { switch desc.MediaType {
case ocispecs.MediaTypeImageLayer, images.MediaTypeDockerSchema2Layer, ocispecs.MediaTypeImageLayerGzip, images.MediaTypeDockerSchema2LayerGzip, images.MediaTypeDockerSchema2LayerForeign, images.MediaTypeDockerSchema2LayerForeignGzip: case
ocispecs.MediaTypeImageLayer,
ocispecs.MediaTypeImageLayerNonDistributable,
images.MediaTypeDockerSchema2Layer,
images.MediaTypeDockerSchema2LayerForeign,
ocispecs.MediaTypeImageLayerGzip,
images.MediaTypeDockerSchema2LayerGzip,
ocispecs.MediaTypeImageLayerNonDistributableGzip,
images.MediaTypeDockerSchema2LayerForeignGzip,
ocispecs.MediaTypeImageLayerZstd,
ocispecs.MediaTypeImageLayerNonDistributableZstd:
return nil, images.ErrSkipDesc return nil, images.ErrSkipDesc
default: default:
if metadata != nil { if metadata != nil {