From 7c1c8f1fe29c28ef62017d99a99eb1ec6be4513c Mon Sep 17 00:00:00 2001 From: Tibor Vass Date: Wed, 8 Aug 2018 22:53:19 +0000 Subject: [PATCH] builder: implement PullParent option with buildkit Signed-off-by: Tibor Vass --- .../adapters/containerimage/pull.go | 70 +++++++++++++++---- builder/builder-next/builder.go | 6 ++ 2 files changed, 61 insertions(+), 15 deletions(-) diff --git a/builder/builder-next/adapters/containerimage/pull.go b/builder/builder-next/adapters/containerimage/pull.go index 319a82ecce..e56efd5134 100644 --- a/builder/builder-next/adapters/containerimage/pull.go +++ b/builder/builder-next/adapters/containerimage/pull.go @@ -42,8 +42,6 @@ import ( "golang.org/x/time/rate" ) -const preferLocal = true // FIXME: make this optional from the op - // SourceOpt is options for creating the image source type SourceOpt struct { SessionManager *session.Manager @@ -114,32 +112,61 @@ func (is *imageSource) resolveLocal(refStr string) ([]byte, error) { return img.RawJSON(), nil } -func (is *imageSource) ResolveImageConfig(ctx context.Context, ref string, opt gw.ResolveImageConfigOpt) (digest.Digest, []byte, error) { - if preferLocal { - dt, err := is.resolveLocal(ref) - if err == nil { - return "", dt, nil - } - } - +func (is *imageSource) resolveRemote(ctx context.Context, ref string, platform *ocispec.Platform) (digest.Digest, []byte, error) { type t struct { dgst digest.Digest dt []byte } res, err := is.g.Do(ctx, ref, func(ctx context.Context) (interface{}, error) { - dgst, dt, err := imageutil.Config(ctx, ref, is.getResolver(ctx), is.ContentStore, opt.Platform) + dgst, dt, err := imageutil.Config(ctx, ref, is.getResolver(ctx), is.ContentStore, platform) if err != nil { return nil, err } return &t{dgst: dgst, dt: dt}, nil }) + var typed *t if err != nil { return "", nil, err } - typed := res.(*t) + typed = res.(*t) return typed.dgst, typed.dt, nil } +func (is *imageSource) ResolveImageConfig(ctx context.Context, ref string, opt gw.ResolveImageConfigOpt) (digest.Digest, []byte, error) { + resolveMode, err := source.ParseImageResolveMode(opt.ResolveMode) + if err != nil { + return "", nil, err + } + switch resolveMode { + case source.ResolveModeForcePull: + dgst, dt, err := is.resolveRemote(ctx, ref, opt.Platform) + // TODO: pull should fallback to local in case of failure to allow offline behavior + // the fallback doesn't work currently + return dgst, dt, err + /* + if err == nil { + return dgst, dt, err + } + // fallback to local + dt, err = is.resolveLocal(ref) + return "", dt, err + */ + + case source.ResolveModeDefault: + // default == prefer local, but in the future could be smarter + fallthrough + case source.ResolveModePreferLocal: + dt, err := is.resolveLocal(ref) + if err == nil { + return "", dt, err + } + // fallback to remote + return is.resolveRemote(ctx, ref, opt.Platform) + } + // should never happen + return "", nil, fmt.Errorf("builder cannot resolve image %s: invalid mode %q", ref, opt.ResolveMode) +} + func (is *imageSource) Resolve(ctx context.Context, id source.Identifier) (source.SourceInstance, error) { imageIdentifier, ok := id.(*source.ImageIdentifier) if !ok { @@ -213,7 +240,7 @@ func (p *puller) resolveLocal() { } } - if preferLocal { + if p.src.ResolveMode == source.ResolveModeDefault || p.src.ResolveMode == source.ResolveModePreferLocal { dt, err := p.is.resolveLocal(p.src.Reference.String()) if err == nil { p.config = dt @@ -257,8 +284,7 @@ func (p *puller) resolve(ctx context.Context) error { resolveProgressDone(err) return } - - _, dt, err := p.is.ResolveImageConfig(ctx, ref.String(), gw.ResolveImageConfigOpt{Platform: &p.platform}) + _, dt, err := p.is.ResolveImageConfig(ctx, ref.String(), gw.ResolveImageConfigOpt{Platform: &p.platform, ResolveMode: resolveModeToString(p.src.ResolveMode)}) if err != nil { p.resolveErr = err resolveProgressDone(err) @@ -732,3 +758,17 @@ func cacheKeyFromConfig(dt []byte) digest.Digest { } return identity.ChainID(img.RootFS.DiffIDs) } + +// resolveModeToString is the equivalent of github.com/moby/buildkit/solver/llb.ResolveMode.String() +// FIXME: add String method on source.ResolveMode +func resolveModeToString(rm source.ResolveMode) string { + switch rm { + case source.ResolveModeDefault: + return "default" + case source.ResolveModeForcePull: + return "pull" + case source.ResolveModePreferLocal: + return "local" + } + return "" +} diff --git a/builder/builder-next/builder.go b/builder/builder-next/builder.go index fffac64232..6876f8f0c0 100644 --- a/builder/builder-next/builder.go +++ b/builder/builder-next/builder.go @@ -209,6 +209,12 @@ func (b *Builder) Build(ctx context.Context, opt backend.BuildConfig) (*builder. frontendAttrs["no-cache"] = "" } + if opt.Options.PullParent { + frontendAttrs["image-resolve-mode"] = "pull" + } else { + frontendAttrs["image-resolve-mode"] = "default" + } + if opt.Options.Platform != "" { // same as in newBuilder in builder/dockerfile.builder.go // TODO: remove once opt.Options.Platform is of type specs.Platform