Signed-off-by: Tibor Vass <tibor@docker.com>
| ... | ... |
@@ -42,8 +42,6 @@ import ( |
| 42 | 42 |
"golang.org/x/time/rate" |
| 43 | 43 |
) |
| 44 | 44 |
|
| 45 |
-const preferLocal = true // FIXME: make this optional from the op |
|
| 46 |
- |
|
| 47 | 45 |
// SourceOpt is options for creating the image source |
| 48 | 46 |
type SourceOpt struct {
|
| 49 | 47 |
SessionManager *session.Manager |
| ... | ... |
@@ -114,32 +112,61 @@ func (is *imageSource) resolveLocal(refStr string) ([]byte, error) {
|
| 114 | 114 |
return img.RawJSON(), nil |
| 115 | 115 |
} |
| 116 | 116 |
|
| 117 |
-func (is *imageSource) ResolveImageConfig(ctx context.Context, ref string, opt gw.ResolveImageConfigOpt) (digest.Digest, []byte, error) {
|
|
| 118 |
- if preferLocal {
|
|
| 119 |
- dt, err := is.resolveLocal(ref) |
|
| 120 |
- if err == nil {
|
|
| 121 |
- return "", dt, nil |
|
| 122 |
- } |
|
| 123 |
- } |
|
| 124 |
- |
|
| 117 |
+func (is *imageSource) resolveRemote(ctx context.Context, ref string, platform *ocispec.Platform) (digest.Digest, []byte, error) {
|
|
| 125 | 118 |
type t struct {
|
| 126 | 119 |
dgst digest.Digest |
| 127 | 120 |
dt []byte |
| 128 | 121 |
} |
| 129 | 122 |
res, err := is.g.Do(ctx, ref, func(ctx context.Context) (interface{}, error) {
|
| 130 |
- dgst, dt, err := imageutil.Config(ctx, ref, is.getResolver(ctx), is.ContentStore, opt.Platform) |
|
| 123 |
+ dgst, dt, err := imageutil.Config(ctx, ref, is.getResolver(ctx), is.ContentStore, platform) |
|
| 131 | 124 |
if err != nil {
|
| 132 | 125 |
return nil, err |
| 133 | 126 |
} |
| 134 | 127 |
return &t{dgst: dgst, dt: dt}, nil
|
| 135 | 128 |
}) |
| 129 |
+ var typed *t |
|
| 136 | 130 |
if err != nil {
|
| 137 | 131 |
return "", nil, err |
| 138 | 132 |
} |
| 139 |
- typed := res.(*t) |
|
| 133 |
+ typed = res.(*t) |
|
| 140 | 134 |
return typed.dgst, typed.dt, nil |
| 141 | 135 |
} |
| 142 | 136 |
|
| 137 |
+func (is *imageSource) ResolveImageConfig(ctx context.Context, ref string, opt gw.ResolveImageConfigOpt) (digest.Digest, []byte, error) {
|
|
| 138 |
+ resolveMode, err := source.ParseImageResolveMode(opt.ResolveMode) |
|
| 139 |
+ if err != nil {
|
|
| 140 |
+ return "", nil, err |
|
| 141 |
+ } |
|
| 142 |
+ switch resolveMode {
|
|
| 143 |
+ case source.ResolveModeForcePull: |
|
| 144 |
+ dgst, dt, err := is.resolveRemote(ctx, ref, opt.Platform) |
|
| 145 |
+ // TODO: pull should fallback to local in case of failure to allow offline behavior |
|
| 146 |
+ // the fallback doesn't work currently |
|
| 147 |
+ return dgst, dt, err |
|
| 148 |
+ /* |
|
| 149 |
+ if err == nil {
|
|
| 150 |
+ return dgst, dt, err |
|
| 151 |
+ } |
|
| 152 |
+ // fallback to local |
|
| 153 |
+ dt, err = is.resolveLocal(ref) |
|
| 154 |
+ return "", dt, err |
|
| 155 |
+ */ |
|
| 156 |
+ |
|
| 157 |
+ case source.ResolveModeDefault: |
|
| 158 |
+ // default == prefer local, but in the future could be smarter |
|
| 159 |
+ fallthrough |
|
| 160 |
+ case source.ResolveModePreferLocal: |
|
| 161 |
+ dt, err := is.resolveLocal(ref) |
|
| 162 |
+ if err == nil {
|
|
| 163 |
+ return "", dt, err |
|
| 164 |
+ } |
|
| 165 |
+ // fallback to remote |
|
| 166 |
+ return is.resolveRemote(ctx, ref, opt.Platform) |
|
| 167 |
+ } |
|
| 168 |
+ // should never happen |
|
| 169 |
+ return "", nil, fmt.Errorf("builder cannot resolve image %s: invalid mode %q", ref, opt.ResolveMode)
|
|
| 170 |
+} |
|
| 171 |
+ |
|
| 143 | 172 |
func (is *imageSource) Resolve(ctx context.Context, id source.Identifier) (source.SourceInstance, error) {
|
| 144 | 173 |
imageIdentifier, ok := id.(*source.ImageIdentifier) |
| 145 | 174 |
if !ok {
|
| ... | ... |
@@ -213,7 +240,7 @@ func (p *puller) resolveLocal() {
|
| 213 | 213 |
} |
| 214 | 214 |
} |
| 215 | 215 |
|
| 216 |
- if preferLocal {
|
|
| 216 |
+ if p.src.ResolveMode == source.ResolveModeDefault || p.src.ResolveMode == source.ResolveModePreferLocal {
|
|
| 217 | 217 |
dt, err := p.is.resolveLocal(p.src.Reference.String()) |
| 218 | 218 |
if err == nil {
|
| 219 | 219 |
p.config = dt |
| ... | ... |
@@ -257,8 +284,7 @@ func (p *puller) resolve(ctx context.Context) error {
|
| 257 | 257 |
resolveProgressDone(err) |
| 258 | 258 |
return |
| 259 | 259 |
} |
| 260 |
- |
|
| 261 |
- _, dt, err := p.is.ResolveImageConfig(ctx, ref.String(), gw.ResolveImageConfigOpt{Platform: &p.platform})
|
|
| 260 |
+ _, dt, err := p.is.ResolveImageConfig(ctx, ref.String(), gw.ResolveImageConfigOpt{Platform: &p.platform, ResolveMode: resolveModeToString(p.src.ResolveMode)})
|
|
| 262 | 261 |
if err != nil {
|
| 263 | 262 |
p.resolveErr = err |
| 264 | 263 |
resolveProgressDone(err) |
| ... | ... |
@@ -732,3 +758,17 @@ func cacheKeyFromConfig(dt []byte) digest.Digest {
|
| 732 | 732 |
} |
| 733 | 733 |
return identity.ChainID(img.RootFS.DiffIDs) |
| 734 | 734 |
} |
| 735 |
+ |
|
| 736 |
+// resolveModeToString is the equivalent of github.com/moby/buildkit/solver/llb.ResolveMode.String() |
|
| 737 |
+// FIXME: add String method on source.ResolveMode |
|
| 738 |
+func resolveModeToString(rm source.ResolveMode) string {
|
|
| 739 |
+ switch rm {
|
|
| 740 |
+ case source.ResolveModeDefault: |
|
| 741 |
+ return "default" |
|
| 742 |
+ case source.ResolveModeForcePull: |
|
| 743 |
+ return "pull" |
|
| 744 |
+ case source.ResolveModePreferLocal: |
|
| 745 |
+ return "local" |
|
| 746 |
+ } |
|
| 747 |
+ return "" |
|
| 748 |
+} |
| ... | ... |
@@ -209,6 +209,12 @@ func (b *Builder) Build(ctx context.Context, opt backend.BuildConfig) (*builder. |
| 209 | 209 |
frontendAttrs["no-cache"] = "" |
| 210 | 210 |
} |
| 211 | 211 |
|
| 212 |
+ if opt.Options.PullParent {
|
|
| 213 |
+ frontendAttrs["image-resolve-mode"] = "pull" |
|
| 214 |
+ } else {
|
|
| 215 |
+ frontendAttrs["image-resolve-mode"] = "default" |
|
| 216 |
+ } |
|
| 217 |
+ |
|
| 212 | 218 |
if opt.Options.Platform != "" {
|
| 213 | 219 |
// same as in newBuilder in builder/dockerfile.builder.go |
| 214 | 220 |
// TODO: remove once opt.Options.Platform is of type specs.Platform |