diff --git a/builder/builder-next/adapters/containerimage/pull.go b/builder/builder-next/adapters/containerimage/pull.go index 2b6c214b8b..b701669fe3 100644 --- a/builder/builder-next/adapters/containerimage/pull.go +++ b/builder/builder-next/adapters/containerimage/pull.go @@ -27,6 +27,7 @@ import ( pkgprogress "github.com/docker/docker/pkg/progress" "github.com/docker/docker/reference" "github.com/moby/buildkit/cache" + gw "github.com/moby/buildkit/frontend/gateway/client" "github.com/moby/buildkit/session" "github.com/moby/buildkit/session/auth" "github.com/moby/buildkit/source" @@ -113,7 +114,7 @@ func (is *imageSource) resolveLocal(refStr string) ([]byte, error) { return img.RawJSON(), nil } -func (is *imageSource) ResolveImageConfig(ctx context.Context, ref string, platform *ocispec.Platform) (digest.Digest, []byte, error) { +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 { @@ -126,7 +127,7 @@ func (is *imageSource) ResolveImageConfig(ctx context.Context, ref string, platf 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, platform) + dgst, dt, err := imageutil.Config(ctx, ref, is.getResolver(ctx), is.ContentStore, opt.Platform) if err != nil { return nil, err } @@ -257,7 +258,7 @@ func (p *puller) resolve(ctx context.Context) error { return } - _, dt, err := p.is.ResolveImageConfig(ctx, ref.String(), &p.platform) + _, dt, err := p.is.ResolveImageConfig(ctx, ref.String(), gw.ResolveImageConfigOpt{Platform: &p.platform}) if err != nil { p.resolveErr = err resolveProgressDone(err) diff --git a/builder/builder-next/exporter/export.go b/builder/builder-next/exporter/export.go index 70e7d6ece1..e0c7db563c 100644 --- a/builder/builder-next/exporter/export.go +++ b/builder/builder-next/exporter/export.go @@ -2,6 +2,7 @@ package containerimage import ( "context" + "encoding/json" "fmt" "strings" @@ -9,15 +10,15 @@ import ( "github.com/docker/docker/image" "github.com/docker/docker/layer" "github.com/docker/docker/reference" - "github.com/moby/buildkit/cache" "github.com/moby/buildkit/exporter" + "github.com/moby/buildkit/exporter/containerimage/exptypes" digest "github.com/opencontainers/go-digest" + "github.com/pkg/errors" "github.com/sirupsen/logrus" ) const ( - keyImageName = "name" - exporterImageConfig = "containerimage.config" + keyImageName = "name" ) // Differ can make a moby layer from a snapshot @@ -54,8 +55,11 @@ func (e *imageExporter) Resolve(ctx context.Context, opt map[string]string) (exp } i.targetNames = append(i.targetNames, ref) } - case exporterImageConfig: - i.config = []byte(v) + case exptypes.ExporterImageConfigKey: + if i.meta == nil { + i.meta = make(map[string][]byte) + } + i.meta[k] = []byte(v) default: logrus.Warnf("image exporter: unknown option %s", k) } @@ -66,18 +70,47 @@ func (e *imageExporter) Resolve(ctx context.Context, opt map[string]string) (exp type imageExporterInstance struct { *imageExporter targetNames []distref.Named - config []byte + meta map[string][]byte } func (e *imageExporterInstance) Name() string { return "exporting to image" } -func (e *imageExporterInstance) Export(ctx context.Context, ref cache.ImmutableRef, opt map[string][]byte) (map[string]string, error) { - if config, ok := opt[exporterImageConfig]; ok { - e.config = config +func (e *imageExporterInstance) Export(ctx context.Context, inp exporter.Source) (map[string]string, error) { + + if len(inp.Refs) > 1 { + return nil, fmt.Errorf("exporting multiple references to image store is currently unsupported") + } + + ref := inp.Ref + if ref != nil && len(inp.Refs) == 1 { + return nil, fmt.Errorf("invalid exporter input: Ref and Refs are mutually exclusive") + } + + // only one loop + for _, v := range inp.Refs { + ref = v + } + + var config []byte + switch len(inp.Refs) { + case 0: + config = inp.Metadata[exptypes.ExporterImageConfigKey] + case 1: + platformsBytes, ok := inp.Metadata[exptypes.ExporterPlatformsKey] + if !ok { + return nil, fmt.Errorf("cannot export image, missing platforms mapping") + } + var p exptypes.Platforms + if err := json.Unmarshal(platformsBytes, &p); err != nil { + return nil, errors.Wrapf(err, "failed to parse platforms passed to exporter") + } + if len(p.Platforms) != len(inp.Refs) { + return nil, errors.Errorf("number of platforms does not match references %d %d", len(p.Platforms), len(inp.Refs)) + } + config = inp.Metadata[fmt.Sprintf("%s/%s", exptypes.ExporterImageConfigKey, p.Platforms[0].ID)] } - config := e.config var diffs []digest.Digest if ref != nil { diff --git a/builder/builder-next/worker/worker.go b/builder/builder-next/worker/worker.go index 29e8095c32..f288466e47 100644 --- a/builder/builder-next/worker/worker.go +++ b/builder/builder-next/worker/worker.go @@ -24,6 +24,7 @@ import ( "github.com/moby/buildkit/executor" "github.com/moby/buildkit/exporter" "github.com/moby/buildkit/frontend" + gw "github.com/moby/buildkit/frontend/gateway/client" "github.com/moby/buildkit/session" "github.com/moby/buildkit/snapshot" "github.com/moby/buildkit/solver" @@ -141,7 +142,7 @@ func (w *Worker) ResolveOp(v solver.Vertex, s frontend.FrontendLLBBridge) (solve case *pb.Op_Source: return ops.NewSourceOp(v, op, baseOp.Platform, w.SourceManager, w) case *pb.Op_Exec: - return ops.NewExecOp(v, op, w.CacheManager, w.MetadataStore, w.Executor, w) + return ops.NewExecOp(v, op, w.CacheManager, w.Opt.SessionManager, w.MetadataStore, w.Executor, w) case *pb.Op_Build: return ops.NewBuildOp(v, op, s, w) } @@ -150,13 +151,13 @@ func (w *Worker) ResolveOp(v solver.Vertex, s frontend.FrontendLLBBridge) (solve } // ResolveImageConfig returns image config for an image -func (w *Worker) ResolveImageConfig(ctx context.Context, ref string, platform *ocispec.Platform) (digest.Digest, []byte, error) { +func (w *Worker) ResolveImageConfig(ctx context.Context, ref string, opt gw.ResolveImageConfigOpt) (digest.Digest, []byte, error) { // ImageSource is typically source/containerimage resolveImageConfig, ok := w.ImageSource.(resolveImageConfig) if !ok { return "", nil, errors.Errorf("worker %q does not implement ResolveImageConfig", w.ID()) } - return resolveImageConfig.ResolveImageConfig(ctx, ref, platform) + return resolveImageConfig.ResolveImageConfig(ctx, ref, opt) } // Exec executes a process directly on a worker @@ -175,8 +176,8 @@ func (w *Worker) DiskUsage(ctx context.Context, opt client.DiskUsageInfo) ([]*cl } // Prune deletes reclaimable build cache -func (w *Worker) Prune(ctx context.Context, ch chan client.UsageInfo) error { - return w.CacheManager.Prune(ctx, ch) +func (w *Worker) Prune(ctx context.Context, ch chan client.UsageInfo, info client.PruneInfo) error { + return w.CacheManager.Prune(ctx, ch, info) } // Exporter returns exporter by name @@ -327,5 +328,5 @@ func oneOffProgress(ctx context.Context, id string) func(err error) error { } type resolveImageConfig interface { - ResolveImageConfig(ctx context.Context, ref string, platform *ocispec.Platform) (digest.Digest, []byte, error) + ResolveImageConfig(ctx context.Context, ref string, opt gw.ResolveImageConfigOpt) (digest.Digest, []byte, error) }