Skip to content

Commit

Permalink
Merge pull request #3321 from jedevc/fixup-attestation-platforms
Browse files Browse the repository at this point in the history
Fixup attestation platforms for the local exporter
  • Loading branch information
tonistiigi authored Dec 8, 2022
2 parents e798d29 + 6f21d6b commit 01c0d67
Show file tree
Hide file tree
Showing 11 changed files with 154 additions and 21 deletions.
2 changes: 0 additions & 2 deletions client/build.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import (
"context"

"github.com/moby/buildkit/client/buildid"
"github.com/moby/buildkit/frontend/attestations"
gateway "github.com/moby/buildkit/frontend/gateway/client"
"github.com/moby/buildkit/frontend/gateway/grpcclient"
gatewayapi "github.com/moby/buildkit/frontend/gateway/pb"
Expand All @@ -24,7 +23,6 @@ func (c *Client) Build(ctx context.Context, opt SolveOpt, product string, buildF
feOpts := opt.FrontendAttrs

opt.Frontend = ""
opt.FrontendAttrs = attestations.Filter(opt.FrontendAttrs)

if product == "" {
product = apicaps.ExportedProduct
Expand Down
13 changes: 7 additions & 6 deletions client/solve.go
Original file line number Diff line number Diff line change
Expand Up @@ -210,11 +210,12 @@ func (c *Client) solve(ctx context.Context, def *llb.Definition, runGateway runG
})
}

frontendAttrs := map[string]string{}
for k, v := range opt.FrontendAttrs {
frontendAttrs[k] = v
}
for k, v := range cacheOpt.frontendAttrs {
if opt.FrontendAttrs == nil {
opt.FrontendAttrs = map[string]string{}
}
opt.FrontendAttrs[k] = v
frontendAttrs[k] = v
}

solveCtx, cancelSolve := context.WithCancel(ctx)
Expand Down Expand Up @@ -254,7 +255,7 @@ func (c *Client) solve(ctx context.Context, def *llb.Definition, runGateway runG
ExporterAttrs: ex.Attrs,
Session: s.ID(),
Frontend: opt.Frontend,
FrontendAttrs: opt.FrontendAttrs,
FrontendAttrs: frontendAttrs,
FrontendInputs: frontendInputs,
Cache: cacheOpt.options,
Entitlements: opt.AllowedEntitlements,
Expand All @@ -270,7 +271,7 @@ func (c *Client) solve(ctx context.Context, def *llb.Definition, runGateway runG

if runGateway != nil {
eg.Go(func() error {
err := runGateway(ref, s, opt.FrontendAttrs)
err := runGateway(ref, s, frontendAttrs)
if err == nil {
return nil
}
Expand Down
15 changes: 13 additions & 2 deletions control/control.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import (
controlgateway "github.com/moby/buildkit/control/gateway"
"github.com/moby/buildkit/exporter"
"github.com/moby/buildkit/exporter/util/epoch"
"github.com/moby/buildkit/exporter/util/multiplatform"
"github.com/moby/buildkit/frontend"
"github.com/moby/buildkit/frontend/attestations"
"github.com/moby/buildkit/session"
Expand Down Expand Up @@ -295,12 +296,22 @@ func (c *Controller) Solve(ctx context.Context, req *controlapi.SolveRequest) (*
}

// if SOURCE_DATE_EPOCH is set, enable it for the exporter
if epochVal, ok := req.FrontendAttrs["build-arg:SOURCE_DATE_EPOCH"]; ok {
if v, ok := epoch.ParseBuildArgs(req.FrontendAttrs); ok {
if _, ok := req.ExporterAttrs[epoch.KeySourceDateEpoch]; !ok {
if req.ExporterAttrs == nil {
req.ExporterAttrs = make(map[string]string)
}
req.ExporterAttrs[epoch.KeySourceDateEpoch] = epochVal
req.ExporterAttrs[epoch.KeySourceDateEpoch] = v
}
}

// if multi-platform is set, enable it for the exporter
if v, ok := multiplatform.ParseBuildArgs(req.FrontendAttrs); ok {
if _, ok := req.ExporterAttrs[multiplatform.KeyMultiPlatform]; !ok {
if req.ExporterAttrs == nil {
req.ExporterAttrs = make(map[string]string)
}
req.ExporterAttrs[multiplatform.KeyMultiPlatform] = v
}
}

Expand Down
9 changes: 8 additions & 1 deletion exporter/containerimage/opts.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (

cacheconfig "github.com/moby/buildkit/cache/config"
"github.com/moby/buildkit/exporter/util/epoch"
"github.com/moby/buildkit/exporter/util/multiplatform"
"github.com/moby/buildkit/util/compression"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
Expand Down Expand Up @@ -34,6 +35,7 @@ type ImageCommitOpts struct {
BuildInfoAttrs bool
Annotations AnnotationsGroup
Epoch *time.Time
MultiPlatform *bool
}

func (c *ImageCommitOpts) Load(opt map[string]string) (map[string]string, error) {
Expand All @@ -45,7 +47,12 @@ func (c *ImageCommitOpts) Load(opt map[string]string) (map[string]string, error)
}
opt = toStringMap(optb)

c.Epoch, opt, err = epoch.ParseAttr(opt)
c.Epoch, opt, err = epoch.ParseExporterAttrs(opt)
if err != nil {
return nil, err
}

c.MultiPlatform, opt, err = multiplatform.ParseExporterAttrs(opt)
if err != nil {
return nil, err
}
Expand Down
33 changes: 30 additions & 3 deletions exporter/containerimage/writer.go
Original file line number Diff line number Diff line change
Expand Up @@ -63,11 +63,20 @@ func (ic *ImageWriter) Commit(ctx context.Context, inp *exporter.Source, session
return nil, errors.Errorf("unable to export multiple refs, missing platforms mapping")
}

multiPlatform := len(inp.Refs) > 0

var p exptypes.Platforms
if ok && len(platformsBytes) > 0 {
if err := json.Unmarshal(platformsBytes, &p); err != nil {
return nil, errors.Wrapf(err, "failed to parse platforms passed to exporter")
}
if len(p.Platforms) > 1 {
multiPlatform = true
}
}

if opts.MultiPlatform != nil {
multiPlatform = *opts.MultiPlatform
}

if opts.Epoch == nil {
Expand All @@ -92,8 +101,26 @@ func (ic *ImageWriter) Commit(ctx context.Context, inp *exporter.Source, session
}
}

if len(inp.Refs) == 0 {
remotes, err := ic.exportLayers(ctx, opts.RefCfg, session.NewGroup(sessionID), inp.Ref)
if !multiPlatform {
if len(p.Platforms) > 1 {
return nil, errors.Errorf("cannot export multiple platforms without multi-platform enabled")
}

var ref cache.ImmutableRef
if inp.Ref != nil {
ref = inp.Ref
} else if len(p.Platforms) > 0 {
p := p.Platforms[0]
if _, ok := inp.Attestations[p.ID]; ok {
return nil, errors.Errorf("cannot export attestations without multi-platform enabled")
}
ref = inp.Refs[p.ID]
} else if len(inp.Refs) == 1 {
for _, ref = range inp.Refs {
}
}

remotes, err := ic.exportLayers(ctx, opts.RefCfg, session.NewGroup(sessionID), ref)
if err != nil {
return nil, err
}
Expand All @@ -112,7 +139,7 @@ func (ic *ImageWriter) Commit(ctx context.Context, inp *exporter.Source, session
return nil, errors.Errorf("index annotations not supported for single platform export")
}

mfstDesc, configDesc, err := ic.commitDistributionManifest(ctx, opts, inp.Ref, inp.Metadata[exptypes.ExporterImageConfigKey], &remotes[0], annotations, inp.Metadata[exptypes.ExporterInlineCache], dtbi, opts.Epoch, session.NewGroup(sessionID))
mfstDesc, configDesc, err := ic.commitDistributionManifest(ctx, opts, ref, inp.Metadata[exptypes.ExporterImageConfigKey], &remotes[0], annotations, inp.Metadata[exptypes.ExporterInlineCache], dtbi, opts.Epoch, session.NewGroup(sessionID))
if err != nil {
return nil, err
}
Expand Down
24 changes: 21 additions & 3 deletions exporter/local/export.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (
"github.com/moby/buildkit/exporter"
"github.com/moby/buildkit/exporter/containerimage/exptypes"
"github.com/moby/buildkit/exporter/util/epoch"
"github.com/moby/buildkit/exporter/util/multiplatform"
"github.com/moby/buildkit/session"
"github.com/moby/buildkit/session/filesync"
"github.com/moby/buildkit/solver/result"
Expand Down Expand Up @@ -41,15 +42,21 @@ func New(opt Opt) (exporter.Exporter, error) {
}

func (e *localExporter) Resolve(ctx context.Context, opt map[string]string) (exporter.ExporterInstance, error) {
tm, _, err := epoch.ParseAttr(opt)
tm, _, err := epoch.ParseExporterAttrs(opt)
if err != nil {
return nil, err
}

multiPlatform, _, err := multiplatform.ParseExporterAttrs(opt)
if err != nil {
return nil, err
}

i := &localExporterInstance{
localExporter: e,
opts: CreateFSOpts{
Epoch: tm,
Epoch: tm,
MultiPlatform: multiPlatform,
},
}

Expand Down Expand Up @@ -93,6 +100,8 @@ func (e *localExporterInstance) Export(ctx context.Context, inp *exporter.Source
return nil, err
}

isMap := len(inp.Refs) > 0

platformsBytes, ok := inp.Metadata[exptypes.ExporterPlatformsKey]
if len(inp.Refs) > 0 && !ok {
return nil, errors.Errorf("unable to export multiple refs, missing platforms mapping")
Expand All @@ -103,8 +112,17 @@ func (e *localExporterInstance) Export(ctx context.Context, inp *exporter.Source
if err := json.Unmarshal(platformsBytes, &p); err != nil {
return nil, errors.Wrapf(err, "failed to parse platforms passed to exporter")
}
if len(p.Platforms) > 1 {
isMap = true
}
}

if e.opts.MultiPlatform != nil {
isMap = *e.opts.MultiPlatform
}
if !isMap && len(p.Platforms) > 1 {
return nil, errors.Errorf("unable to export multiple platforms without map")
}
isMap := len(p.Platforms) > 1

now := time.Now().Truncate(time.Second)

Expand Down
1 change: 1 addition & 0 deletions exporter/local/fs.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import (
type CreateFSOpts struct {
Epoch *time.Time
AttestationPrefix string
MultiPlatform *bool
}

func CreateFS(ctx context.Context, sessionID string, k string, ref cache.ImmutableRef, refs map[string]cache.ImmutableRef, attestations []result.Attestation, defaultTime time.Time, opt CreateFSOpts) (fsutil.FS, func() error, error) {
Expand Down
22 changes: 20 additions & 2 deletions exporter/tar/export.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import (
"github.com/moby/buildkit/exporter/containerimage/exptypes"
"github.com/moby/buildkit/exporter/local"
"github.com/moby/buildkit/exporter/util/epoch"
"github.com/moby/buildkit/exporter/util/multiplatform"
"github.com/moby/buildkit/session"
"github.com/moby/buildkit/session/filesync"
"github.com/moby/buildkit/solver/result"
Expand Down Expand Up @@ -48,12 +49,18 @@ func New(opt Opt) (exporter.Exporter, error) {
func (e *localExporter) Resolve(ctx context.Context, opt map[string]string) (exporter.ExporterInstance, error) {
li := &localExporterInstance{localExporter: e}

tm, _, err := epoch.ParseAttr(opt)
tm, opt, err := epoch.ParseExporterAttrs(opt)
if err != nil {
return nil, err
}
li.opts.Epoch = tm

multiPlatform, opt, err := multiplatform.ParseExporterAttrs(opt)
if err != nil {
return nil, err
}
li.opts.MultiPlatform = multiPlatform

for k, v := range opt {
switch k {
case preferNondistLayersKey:
Expand Down Expand Up @@ -126,6 +133,8 @@ func (e *localExporterInstance) Export(ctx context.Context, inp *exporter.Source
}, nil
}

isMap := len(inp.Refs) > 0

platformsBytes, ok := inp.Metadata[exptypes.ExporterPlatformsKey]
if len(inp.Refs) > 0 && !ok {
return nil, errors.Errorf("unable to export multiple refs, missing platforms mapping")
Expand All @@ -136,8 +145,17 @@ func (e *localExporterInstance) Export(ctx context.Context, inp *exporter.Source
if err := json.Unmarshal(platformsBytes, &p); err != nil {
return nil, errors.Wrapf(err, "failed to parse platforms passed to exporter")
}
if len(p.Platforms) > 1 {
isMap = true
}
}

if e.opts.MultiPlatform != nil {
isMap = *e.opts.MultiPlatform
}
if !isMap && len(p.Platforms) > 1 {
return nil, errors.Errorf("unable to export multiple platforms without map")
}
isMap := len(p.Platforms) > 1

var fs fsutil.FS

Expand Down
9 changes: 8 additions & 1 deletion exporter/util/epoch/parse.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,17 @@ import (
)

const (
frontendSourceDateEpochArg = "build-arg:SOURCE_DATE_EPOCH"

KeySourceDateEpoch = "source-date-epoch"
)

func ParseAttr(opt map[string]string) (*time.Time, map[string]string, error) {
func ParseBuildArgs(opt map[string]string) (string, bool) {
v, ok := opt[frontendSourceDateEpochArg]
return v, ok
}

func ParseExporterAttrs(opt map[string]string) (*time.Time, map[string]string, error) {
rest := make(map[string]string, len(opt))

var tm *time.Time
Expand Down
45 changes: 45 additions & 0 deletions exporter/util/multiplatform/parse.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package multiplatform

import (
"strconv"

"github.com/pkg/errors"
)

const (
frontendMultiPlatform = "multi-platform"
frontendMultiPlatformArg = "build-arg:BUILDKIT_MULTI_PLATFORM"

KeyMultiPlatform = "multi-platform"
)

func ParseBuildArgs(opt map[string]string) (string, bool) {
if v, ok := opt[frontendMultiPlatform]; ok {
return v, true
}
if v, ok := opt[frontendMultiPlatformArg]; ok {
return v, true
}
return "", false
}

func ParseExporterAttrs(opt map[string]string) (*bool, map[string]string, error) {
rest := make(map[string]string, len(opt))

var multiPlatform *bool

for k, v := range opt {
switch k {
case KeyMultiPlatform:
b, err := strconv.ParseBool(v)
if err != nil {
return nil, nil, errors.Errorf("invalid boolean value %s", v)
}
multiPlatform = &b
default:
rest[k] = v
}
}

return multiPlatform, rest, nil
}
2 changes: 1 addition & 1 deletion frontend/dockerfile/builder/build.go
Original file line number Diff line number Diff line change
Expand Up @@ -414,7 +414,7 @@ func Build(ctx context.Context, c client.Client) (_ *client.Result, err error) {
return nil, errors.Errorf("invalid boolean value %s", v)
}
if !b && exportMap {
return nil, errors.Errorf("returning multiple target plaforms is not allowed")
return nil, errors.Errorf("returning multiple target platforms is not allowed")
}
exportMap = b
}
Expand Down

0 comments on commit 01c0d67

Please sign in to comment.