Browse code

builder: implement PullParent option with buildkit

Signed-off-by: Tibor Vass <tibor@docker.com>

Tibor Vass authored on 2018/08/09 07:53:19
Showing 2 changed files
... ...
@@ -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