remotecache: allow oci mediatypes on exporting to registry
Signed-off-by: Tonis Tiigi <tonistiigi@gmail.com>v0.8
parent
212a0b1439
commit
8adf951bc7
|
@ -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)
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue