remotecache: allow oci mediatypes on exporting to registry

Signed-off-by: Tonis Tiigi <tonistiigi@gmail.com>
v0.8
Tonis Tiigi 2020-10-23 00:20:59 -07:00
parent 212a0b1439
commit 8adf951bc7
3 changed files with 36 additions and 13 deletions

View File

@ -12,6 +12,7 @@ import (
v1 "github.com/moby/buildkit/cache/remotecache/v1" v1 "github.com/moby/buildkit/cache/remotecache/v1"
"github.com/moby/buildkit/session" "github.com/moby/buildkit/session"
"github.com/moby/buildkit/solver" "github.com/moby/buildkit/solver"
"github.com/moby/buildkit/util/compression"
"github.com/moby/buildkit/util/contentutil" "github.com/moby/buildkit/util/contentutil"
"github.com/moby/buildkit/util/progress" "github.com/moby/buildkit/util/progress"
digest "github.com/opencontainers/go-digest" digest "github.com/opencontainers/go-digest"
@ -55,20 +56,17 @@ type contentCacheExporter struct {
solver.CacheExporterTarget solver.CacheExporterTarget
chains *v1.CacheChains chains *v1.CacheChains
ingester content.Ingester ingester content.Ingester
oci bool
} }
func NewExporter(ingester content.Ingester) Exporter { func NewExporter(ingester content.Ingester, oci bool) Exporter {
cc := v1.NewCacheChains() cc := v1.NewCacheChains()
return &contentCacheExporter{CacheExporterTarget: cc, chains: cc, ingester: ingester} return &contentCacheExporter{CacheExporterTarget: cc, chains: cc, ingester: ingester, oci: oci}
} }
func (ce *contentCacheExporter) Finalize(ctx context.Context) (map[string]string, error) { func (ce *contentCacheExporter) Finalize(ctx context.Context) (map[string]string, error) {
return export(ctx, ce.ingester, ce.chains)
}
func export(ctx context.Context, ingester content.Ingester, cc *v1.CacheChains) (map[string]string, error) {
res := make(map[string]string) res := make(map[string]string)
config, descs, err := cc.Marshal() config, descs, err := ce.chains.Marshal()
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -86,6 +84,9 @@ func export(ctx context.Context, ingester content.Ingester, cc *v1.CacheChains)
var mfst manifestList var mfst manifestList
mfst.SchemaVersion = 2 mfst.SchemaVersion = 2
mfst.MediaType = images.MediaTypeDockerSchema2ManifestList mfst.MediaType = images.MediaTypeDockerSchema2ManifestList
if ce.oci {
mfst.MediaType = ocispec.MediaTypeImageIndex
}
for _, l := range config.Layers { for _, l := range config.Layers {
dgstPair, ok := descs[l.Blob] dgstPair, ok := descs[l.Blob]
@ -93,13 +94,15 @@ func export(ctx context.Context, ingester content.Ingester, cc *v1.CacheChains)
return nil, errors.Errorf("missing blob %s", l.Blob) return nil, errors.Errorf("missing blob %s", l.Blob)
} }
layerDone := oneOffProgress(ctx, fmt.Sprintf("writing layer %s", l.Blob)) layerDone := oneOffProgress(ctx, fmt.Sprintf("writing layer %s", l.Blob))
if err := contentutil.Copy(ctx, ingester, dgstPair.Provider, dgstPair.Descriptor); err != nil { if err := contentutil.Copy(ctx, ce.ingester, dgstPair.Provider, dgstPair.Descriptor); err != nil {
return nil, layerDone(errors.Wrap(err, "error writing layer blob")) return nil, layerDone(errors.Wrap(err, "error writing layer blob"))
} }
layerDone(nil) layerDone(nil)
mfst.Manifests = append(mfst.Manifests, dgstPair.Descriptor) mfst.Manifests = append(mfst.Manifests, dgstPair.Descriptor)
} }
mfst.Manifests = compression.ConvertAllLayerMediaTypes(ce.oci, mfst.Manifests...)
dt, err := json.Marshal(config) dt, err := json.Marshal(config)
if err != nil { if err != nil {
return nil, err return nil, err
@ -111,7 +114,7 @@ func export(ctx context.Context, ingester content.Ingester, cc *v1.CacheChains)
MediaType: v1.CacheConfigMediaTypeV0, MediaType: v1.CacheConfigMediaTypeV0,
} }
configDone := oneOffProgress(ctx, fmt.Sprintf("writing config %s", dgst)) configDone := oneOffProgress(ctx, fmt.Sprintf("writing config %s", dgst))
if err := content.WriteBlob(ctx, ingester, dgst.String(), bytes.NewReader(dt), desc); err != nil { if err := content.WriteBlob(ctx, ce.ingester, dgst.String(), bytes.NewReader(dt), desc); err != nil {
return nil, configDone(errors.Wrap(err, "error writing config blob")) return nil, configDone(errors.Wrap(err, "error writing config blob"))
} }
configDone(nil) configDone(nil)
@ -130,7 +133,7 @@ func export(ctx context.Context, ingester content.Ingester, cc *v1.CacheChains)
MediaType: mfst.MediaType, MediaType: mfst.MediaType,
} }
mfstDone := oneOffProgress(ctx, fmt.Sprintf("writing manifest %s", dgst)) mfstDone := oneOffProgress(ctx, fmt.Sprintf("writing manifest %s", dgst))
if err := content.WriteBlob(ctx, ingester, dgst.String(), bytes.NewReader(dt), desc); err != nil { if err := content.WriteBlob(ctx, ce.ingester, dgst.String(), bytes.NewReader(dt), desc); err != nil {
return nil, mfstDone(errors.Wrap(err, "error writing manifest blob")) return nil, mfstDone(errors.Wrap(err, "error writing manifest blob"))
} }
descJSON, err := json.Marshal(desc) descJSON, err := json.Marshal(desc)

View File

@ -2,6 +2,7 @@ package local
import ( import (
"context" "context"
"strconv"
"time" "time"
"github.com/containerd/containerd/content" "github.com/containerd/containerd/content"
@ -17,6 +18,7 @@ const (
attrDigest = "digest" attrDigest = "digest"
attrSrc = "src" attrSrc = "src"
attrDest = "dest" attrDest = "dest"
attrOCIMediatypes = "oci-mediatypes"
contentStoreIDPrefix = "local:" contentStoreIDPrefix = "local:"
) )
@ -27,12 +29,20 @@ func ResolveCacheExporterFunc(sm *session.Manager) remotecache.ResolveCacheExpor
if store == "" { if store == "" {
return nil, errors.New("local cache exporter requires dest") return nil, errors.New("local cache exporter requires dest")
} }
ociMediatypes := true
if v, ok := attrs[attrOCIMediatypes]; ok {
b, err := strconv.ParseBool(v)
if err != nil {
return nil, errors.Wrapf(err, "failed to parse %s", attrOCIMediatypes)
}
ociMediatypes = b
}
csID := contentStoreIDPrefix + store csID := contentStoreIDPrefix + store
cs, err := getContentStore(ctx, sm, g, csID) cs, err := getContentStore(ctx, sm, g, csID)
if err != nil { if err != nil {
return nil, err return nil, err
} }
return remotecache.NewExporter(cs), nil return remotecache.NewExporter(cs, ociMediatypes), nil
} }
} }

View File

@ -2,6 +2,7 @@ package registry
import ( import (
"context" "context"
"strconv"
"github.com/containerd/containerd/content" "github.com/containerd/containerd/content"
"github.com/containerd/containerd/remotes/docker" "github.com/containerd/containerd/remotes/docker"
@ -28,7 +29,8 @@ func canonicalizeRef(rawRef string) (string, error) {
} }
const ( const (
attrRef = "ref" attrRef = "ref"
attrOCIMediatypes = "oci-mediatypes"
) )
func ResolveCacheExporterFunc(sm *session.Manager, hosts docker.RegistryHosts) remotecache.ResolveCacheExporterFunc { func ResolveCacheExporterFunc(sm *session.Manager, hosts docker.RegistryHosts) remotecache.ResolveCacheExporterFunc {
@ -37,12 +39,20 @@ func ResolveCacheExporterFunc(sm *session.Manager, hosts docker.RegistryHosts) r
if err != nil { if err != nil {
return nil, err return nil, err
} }
ociMediatypes := true
if v, ok := attrs[attrOCIMediatypes]; ok {
b, err := strconv.ParseBool(v)
if err != nil {
return nil, errors.Wrapf(err, "failed to parse %s", attrOCIMediatypes)
}
ociMediatypes = b
}
remote := resolver.DefaultPool.GetResolver(hosts, ref, "push", sm, g) remote := resolver.DefaultPool.GetResolver(hosts, ref, "push", sm, g)
pusher, err := remote.Pusher(ctx, ref) pusher, err := remote.Pusher(ctx, ref)
if err != nil { if err != nil {
return nil, err return nil, err
} }
return remotecache.NewExporter(contentutil.FromPusher(pusher)), nil return remotecache.NewExporter(contentutil.FromPusher(pusher), ociMediatypes), nil
} }
} }