buildkit/cache/remotecache/registry/registry.go

107 lines
3.2 KiB
Go

package registry
import (
"context"
"strconv"
"github.com/containerd/containerd/content"
"github.com/containerd/containerd/remotes/docker"
"github.com/docker/distribution/reference"
"github.com/moby/buildkit/cache/remotecache"
"github.com/moby/buildkit/session"
"github.com/moby/buildkit/util/contentutil"
"github.com/moby/buildkit/util/resolver"
digest "github.com/opencontainers/go-digest"
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
specs "github.com/opencontainers/image-spec/specs-go/v1"
"github.com/pkg/errors"
)
func canonicalizeRef(rawRef string) (string, error) {
if rawRef == "" {
return "", errors.New("missing ref")
}
parsed, err := reference.ParseNormalizedNamed(rawRef)
if err != nil {
return "", err
}
return reference.TagNameOnly(parsed).String(), nil
}
const (
attrRef = "ref"
attrOCIMediatypes = "oci-mediatypes"
)
func ResolveCacheExporterFunc(sm *session.Manager, hosts docker.RegistryHosts) remotecache.ResolveCacheExporterFunc {
return func(ctx context.Context, g session.Group, attrs map[string]string) (remotecache.Exporter, error) {
ref, err := canonicalizeRef(attrs[attrRef])
if err != nil {
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)
pusher, err := remote.Pusher(ctx, ref)
if err != nil {
return nil, err
}
return remotecache.NewExporter(contentutil.FromPusher(pusher), ociMediatypes), nil
}
}
func ResolveCacheImporterFunc(sm *session.Manager, cs content.Store, hosts docker.RegistryHosts) remotecache.ResolveCacheImporterFunc {
return func(ctx context.Context, g session.Group, attrs map[string]string) (remotecache.Importer, specs.Descriptor, error) {
ref, err := canonicalizeRef(attrs[attrRef])
if err != nil {
return nil, specs.Descriptor{}, err
}
remote := resolver.DefaultPool.GetResolver(hosts, ref, "pull", sm, g)
xref, desc, err := remote.Resolve(ctx, ref)
if err != nil {
return nil, specs.Descriptor{}, err
}
fetcher, err := remote.Fetcher(ctx, xref)
if err != nil {
return nil, specs.Descriptor{}, err
}
src := &withDistributionSourceLabel{
Provider: contentutil.FromFetcher(fetcher),
ref: ref,
source: cs,
}
return remotecache.NewImporter(src), desc, nil
}
}
type withDistributionSourceLabel struct {
content.Provider
ref string
source content.Manager
}
var _ remotecache.DistributionSourceLabelSetter = &withDistributionSourceLabel{}
func (dsl *withDistributionSourceLabel) SetDistributionSourceLabel(ctx context.Context, dgst digest.Digest) error {
hf, err := docker.AppendDistributionSourceLabel(dsl.source, dsl.ref)
if err != nil {
return err
}
_, err = hf(ctx, ocispec.Descriptor{Digest: dgst})
return err
}
func (dsl *withDistributionSourceLabel) SetDistributionSourceAnnotation(desc ocispec.Descriptor) ocispec.Descriptor {
if desc.Annotations == nil {
desc.Annotations = map[string]string{}
}
desc.Annotations["containerd.io/distribution.source.ref"] = dsl.ref
return desc
}