2017-12-01 01:29:57 +00:00
|
|
|
package imagemetaresolver
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
"net/http"
|
|
|
|
"sync"
|
|
|
|
|
2018-07-17 23:02:15 +00:00
|
|
|
"github.com/containerd/containerd/platforms"
|
2017-12-01 01:29:57 +00:00
|
|
|
"github.com/containerd/containerd/remotes"
|
|
|
|
"github.com/containerd/containerd/remotes/docker"
|
2018-06-08 18:00:37 +00:00
|
|
|
"github.com/docker/docker/pkg/locker"
|
2017-12-01 01:29:57 +00:00
|
|
|
"github.com/moby/buildkit/client/llb"
|
2018-07-25 06:18:21 +00:00
|
|
|
gw "github.com/moby/buildkit/frontend/gateway/client"
|
2018-03-22 05:01:50 +00:00
|
|
|
"github.com/moby/buildkit/util/contentutil"
|
2017-12-01 01:29:57 +00:00
|
|
|
"github.com/moby/buildkit/util/imageutil"
|
|
|
|
digest "github.com/opencontainers/go-digest"
|
2018-06-24 05:52:19 +00:00
|
|
|
specs "github.com/opencontainers/image-spec/specs-go/v1"
|
2017-12-01 01:29:57 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
var defaultImageMetaResolver llb.ImageMetaResolver
|
|
|
|
var defaultImageMetaResolverOnce sync.Once
|
|
|
|
|
2018-07-25 01:18:53 +00:00
|
|
|
var WithDefault = imageOptionFunc(func(ii *llb.ImageInfo) {
|
2017-12-06 19:36:47 +00:00
|
|
|
llb.WithMetaResolver(Default()).SetImageOption(ii)
|
|
|
|
})
|
2017-12-01 01:29:57 +00:00
|
|
|
|
2018-05-22 16:18:36 +00:00
|
|
|
type imageMetaResolverOpts struct {
|
2018-06-24 05:52:19 +00:00
|
|
|
platform *specs.Platform
|
2018-05-22 16:18:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
type ImageMetaResolverOpt func(o *imageMetaResolverOpts)
|
|
|
|
|
2018-06-24 05:52:19 +00:00
|
|
|
func WithDefaultPlatform(p *specs.Platform) ImageMetaResolverOpt {
|
2018-05-22 16:18:36 +00:00
|
|
|
return func(o *imageMetaResolverOpts) {
|
|
|
|
o.platform = p
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func New(with ...ImageMetaResolverOpt) llb.ImageMetaResolver {
|
|
|
|
var opts imageMetaResolverOpts
|
|
|
|
for _, f := range with {
|
|
|
|
f(&opts)
|
|
|
|
}
|
2017-12-01 01:29:57 +00:00
|
|
|
return &imageMetaResolver{
|
|
|
|
resolver: docker.NewResolver(docker.ResolverOptions{
|
|
|
|
Client: http.DefaultClient,
|
|
|
|
}),
|
2018-05-22 16:18:36 +00:00
|
|
|
platform: opts.platform,
|
|
|
|
buffer: contentutil.NewBuffer(),
|
|
|
|
cache: map[string]resolveResult{},
|
2018-06-08 18:00:37 +00:00
|
|
|
locker: locker.New(),
|
2017-12-01 01:29:57 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func Default() llb.ImageMetaResolver {
|
|
|
|
defaultImageMetaResolverOnce.Do(func() {
|
|
|
|
defaultImageMetaResolver = New()
|
|
|
|
})
|
|
|
|
return defaultImageMetaResolver
|
|
|
|
}
|
|
|
|
|
|
|
|
type imageMetaResolver struct {
|
|
|
|
resolver remotes.Resolver
|
2018-03-22 05:01:50 +00:00
|
|
|
buffer contentutil.Buffer
|
2018-06-24 05:52:19 +00:00
|
|
|
platform *specs.Platform
|
2017-12-01 01:29:57 +00:00
|
|
|
locker *locker.Locker
|
|
|
|
cache map[string]resolveResult
|
|
|
|
}
|
|
|
|
|
|
|
|
type resolveResult struct {
|
|
|
|
config []byte
|
|
|
|
dgst digest.Digest
|
|
|
|
}
|
|
|
|
|
2018-07-25 06:18:21 +00:00
|
|
|
func (imr *imageMetaResolver) ResolveImageConfig(ctx context.Context, ref string, opt gw.ResolveImageConfigOpt) (digest.Digest, []byte, error) {
|
2017-12-01 01:29:57 +00:00
|
|
|
imr.locker.Lock(ref)
|
|
|
|
defer imr.locker.Unlock(ref)
|
|
|
|
|
2018-07-25 06:18:21 +00:00
|
|
|
platform := opt.Platform
|
2018-06-24 05:52:19 +00:00
|
|
|
if platform == nil {
|
|
|
|
platform = imr.platform
|
|
|
|
}
|
|
|
|
|
2018-07-17 23:02:15 +00:00
|
|
|
k := imr.key(ref, platform)
|
|
|
|
|
|
|
|
if res, ok := imr.cache[k]; ok {
|
|
|
|
return res.dgst, res.config, nil
|
|
|
|
}
|
|
|
|
|
2018-06-24 05:52:19 +00:00
|
|
|
dgst, config, err := imageutil.Config(ctx, ref, imr.resolver, imr.buffer, platform)
|
2017-12-01 01:29:57 +00:00
|
|
|
if err != nil {
|
|
|
|
return "", nil, err
|
|
|
|
}
|
|
|
|
|
2018-07-17 23:02:15 +00:00
|
|
|
imr.cache[k] = resolveResult{dgst: dgst, config: config}
|
2017-12-01 01:29:57 +00:00
|
|
|
return dgst, config, nil
|
|
|
|
}
|
2018-07-17 23:02:15 +00:00
|
|
|
|
|
|
|
func (imr *imageMetaResolver) key(ref string, platform *specs.Platform) string {
|
|
|
|
if platform != nil {
|
|
|
|
ref += platforms.Format(*platform)
|
|
|
|
}
|
|
|
|
return ref
|
|
|
|
}
|
2018-07-25 01:18:53 +00:00
|
|
|
|
|
|
|
type imageOptionFunc func(*llb.ImageInfo)
|
|
|
|
|
|
|
|
func (fn imageOptionFunc) SetImageOption(ii *llb.ImageInfo) {
|
|
|
|
fn(ii)
|
|
|
|
}
|