Skip to content

Commit 01c0d67

Browse files
authored
Merge pull request moby#3321 from jedevc/fixup-attestation-platforms
Fixup attestation platforms for the local exporter
2 parents e798d29 + 6f21d6b commit 01c0d67

File tree

11 files changed

+154
-21
lines changed

11 files changed

+154
-21
lines changed

client/build.go

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ import (
44
"context"
55

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

2625
opt.Frontend = ""
27-
opt.FrontendAttrs = attestations.Filter(opt.FrontendAttrs)
2826

2927
if product == "" {
3028
product = apicaps.ExportedProduct

client/solve.go

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -210,11 +210,12 @@ func (c *Client) solve(ctx context.Context, def *llb.Definition, runGateway runG
210210
})
211211
}
212212

213+
frontendAttrs := map[string]string{}
214+
for k, v := range opt.FrontendAttrs {
215+
frontendAttrs[k] = v
216+
}
213217
for k, v := range cacheOpt.frontendAttrs {
214-
if opt.FrontendAttrs == nil {
215-
opt.FrontendAttrs = map[string]string{}
216-
}
217-
opt.FrontendAttrs[k] = v
218+
frontendAttrs[k] = v
218219
}
219220

220221
solveCtx, cancelSolve := context.WithCancel(ctx)
@@ -254,7 +255,7 @@ func (c *Client) solve(ctx context.Context, def *llb.Definition, runGateway runG
254255
ExporterAttrs: ex.Attrs,
255256
Session: s.ID(),
256257
Frontend: opt.Frontend,
257-
FrontendAttrs: opt.FrontendAttrs,
258+
FrontendAttrs: frontendAttrs,
258259
FrontendInputs: frontendInputs,
259260
Cache: cacheOpt.options,
260261
Entitlements: opt.AllowedEntitlements,
@@ -270,7 +271,7 @@ func (c *Client) solve(ctx context.Context, def *llb.Definition, runGateway runG
270271

271272
if runGateway != nil {
272273
eg.Go(func() error {
273-
err := runGateway(ref, s, opt.FrontendAttrs)
274+
err := runGateway(ref, s, frontendAttrs)
274275
if err == nil {
275276
return nil
276277
}

control/control.go

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import (
1717
controlgateway "github.com/moby/buildkit/control/gateway"
1818
"github.com/moby/buildkit/exporter"
1919
"github.com/moby/buildkit/exporter/util/epoch"
20+
"github.com/moby/buildkit/exporter/util/multiplatform"
2021
"github.com/moby/buildkit/frontend"
2122
"github.com/moby/buildkit/frontend/attestations"
2223
"github.com/moby/buildkit/session"
@@ -295,12 +296,22 @@ func (c *Controller) Solve(ctx context.Context, req *controlapi.SolveRequest) (*
295296
}
296297

297298
// if SOURCE_DATE_EPOCH is set, enable it for the exporter
298-
if epochVal, ok := req.FrontendAttrs["build-arg:SOURCE_DATE_EPOCH"]; ok {
299+
if v, ok := epoch.ParseBuildArgs(req.FrontendAttrs); ok {
299300
if _, ok := req.ExporterAttrs[epoch.KeySourceDateEpoch]; !ok {
300301
if req.ExporterAttrs == nil {
301302
req.ExporterAttrs = make(map[string]string)
302303
}
303-
req.ExporterAttrs[epoch.KeySourceDateEpoch] = epochVal
304+
req.ExporterAttrs[epoch.KeySourceDateEpoch] = v
305+
}
306+
}
307+
308+
// if multi-platform is set, enable it for the exporter
309+
if v, ok := multiplatform.ParseBuildArgs(req.FrontendAttrs); ok {
310+
if _, ok := req.ExporterAttrs[multiplatform.KeyMultiPlatform]; !ok {
311+
if req.ExporterAttrs == nil {
312+
req.ExporterAttrs = make(map[string]string)
313+
}
314+
req.ExporterAttrs[multiplatform.KeyMultiPlatform] = v
304315
}
305316
}
306317

exporter/containerimage/opts.go

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import (
66

77
cacheconfig "github.com/moby/buildkit/cache/config"
88
"github.com/moby/buildkit/exporter/util/epoch"
9+
"github.com/moby/buildkit/exporter/util/multiplatform"
910
"github.com/moby/buildkit/util/compression"
1011
"github.com/pkg/errors"
1112
"github.com/sirupsen/logrus"
@@ -34,6 +35,7 @@ type ImageCommitOpts struct {
3435
BuildInfoAttrs bool
3536
Annotations AnnotationsGroup
3637
Epoch *time.Time
38+
MultiPlatform *bool
3739
}
3840

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

48-
c.Epoch, opt, err = epoch.ParseAttr(opt)
50+
c.Epoch, opt, err = epoch.ParseExporterAttrs(opt)
51+
if err != nil {
52+
return nil, err
53+
}
54+
55+
c.MultiPlatform, opt, err = multiplatform.ParseExporterAttrs(opt)
4956
if err != nil {
5057
return nil, err
5158
}

exporter/containerimage/writer.go

Lines changed: 30 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -63,11 +63,20 @@ func (ic *ImageWriter) Commit(ctx context.Context, inp *exporter.Source, session
6363
return nil, errors.Errorf("unable to export multiple refs, missing platforms mapping")
6464
}
6565

66+
multiPlatform := len(inp.Refs) > 0
67+
6668
var p exptypes.Platforms
6769
if ok && len(platformsBytes) > 0 {
6870
if err := json.Unmarshal(platformsBytes, &p); err != nil {
6971
return nil, errors.Wrapf(err, "failed to parse platforms passed to exporter")
7072
}
73+
if len(p.Platforms) > 1 {
74+
multiPlatform = true
75+
}
76+
}
77+
78+
if opts.MultiPlatform != nil {
79+
multiPlatform = *opts.MultiPlatform
7180
}
7281

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

95-
if len(inp.Refs) == 0 {
96-
remotes, err := ic.exportLayers(ctx, opts.RefCfg, session.NewGroup(sessionID), inp.Ref)
104+
if !multiPlatform {
105+
if len(p.Platforms) > 1 {
106+
return nil, errors.Errorf("cannot export multiple platforms without multi-platform enabled")
107+
}
108+
109+
var ref cache.ImmutableRef
110+
if inp.Ref != nil {
111+
ref = inp.Ref
112+
} else if len(p.Platforms) > 0 {
113+
p := p.Platforms[0]
114+
if _, ok := inp.Attestations[p.ID]; ok {
115+
return nil, errors.Errorf("cannot export attestations without multi-platform enabled")
116+
}
117+
ref = inp.Refs[p.ID]
118+
} else if len(inp.Refs) == 1 {
119+
for _, ref = range inp.Refs {
120+
}
121+
}
122+
123+
remotes, err := ic.exportLayers(ctx, opts.RefCfg, session.NewGroup(sessionID), ref)
97124
if err != nil {
98125
return nil, err
99126
}
@@ -112,7 +139,7 @@ func (ic *ImageWriter) Commit(ctx context.Context, inp *exporter.Source, session
112139
return nil, errors.Errorf("index annotations not supported for single platform export")
113140
}
114141

115-
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))
142+
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))
116143
if err != nil {
117144
return nil, err
118145
}

exporter/local/export.go

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import (
1111
"github.com/moby/buildkit/exporter"
1212
"github.com/moby/buildkit/exporter/containerimage/exptypes"
1313
"github.com/moby/buildkit/exporter/util/epoch"
14+
"github.com/moby/buildkit/exporter/util/multiplatform"
1415
"github.com/moby/buildkit/session"
1516
"github.com/moby/buildkit/session/filesync"
1617
"github.com/moby/buildkit/solver/result"
@@ -41,15 +42,21 @@ func New(opt Opt) (exporter.Exporter, error) {
4142
}
4243

4344
func (e *localExporter) Resolve(ctx context.Context, opt map[string]string) (exporter.ExporterInstance, error) {
44-
tm, _, err := epoch.ParseAttr(opt)
45+
tm, _, err := epoch.ParseExporterAttrs(opt)
46+
if err != nil {
47+
return nil, err
48+
}
49+
50+
multiPlatform, _, err := multiplatform.ParseExporterAttrs(opt)
4551
if err != nil {
4652
return nil, err
4753
}
4854

4955
i := &localExporterInstance{
5056
localExporter: e,
5157
opts: CreateFSOpts{
52-
Epoch: tm,
58+
Epoch: tm,
59+
MultiPlatform: multiPlatform,
5360
},
5461
}
5562

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

103+
isMap := len(inp.Refs) > 0
104+
96105
platformsBytes, ok := inp.Metadata[exptypes.ExporterPlatformsKey]
97106
if len(inp.Refs) > 0 && !ok {
98107
return nil, errors.Errorf("unable to export multiple refs, missing platforms mapping")
@@ -103,8 +112,17 @@ func (e *localExporterInstance) Export(ctx context.Context, inp *exporter.Source
103112
if err := json.Unmarshal(platformsBytes, &p); err != nil {
104113
return nil, errors.Wrapf(err, "failed to parse platforms passed to exporter")
105114
}
115+
if len(p.Platforms) > 1 {
116+
isMap = true
117+
}
118+
}
119+
120+
if e.opts.MultiPlatform != nil {
121+
isMap = *e.opts.MultiPlatform
122+
}
123+
if !isMap && len(p.Platforms) > 1 {
124+
return nil, errors.Errorf("unable to export multiple platforms without map")
106125
}
107-
isMap := len(p.Platforms) > 1
108126

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

exporter/local/fs.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ import (
2727
type CreateFSOpts struct {
2828
Epoch *time.Time
2929
AttestationPrefix string
30+
MultiPlatform *bool
3031
}
3132

3233
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) {

exporter/tar/export.go

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import (
1313
"github.com/moby/buildkit/exporter/containerimage/exptypes"
1414
"github.com/moby/buildkit/exporter/local"
1515
"github.com/moby/buildkit/exporter/util/epoch"
16+
"github.com/moby/buildkit/exporter/util/multiplatform"
1617
"github.com/moby/buildkit/session"
1718
"github.com/moby/buildkit/session/filesync"
1819
"github.com/moby/buildkit/solver/result"
@@ -48,12 +49,18 @@ func New(opt Opt) (exporter.Exporter, error) {
4849
func (e *localExporter) Resolve(ctx context.Context, opt map[string]string) (exporter.ExporterInstance, error) {
4950
li := &localExporterInstance{localExporter: e}
5051

51-
tm, _, err := epoch.ParseAttr(opt)
52+
tm, opt, err := epoch.ParseExporterAttrs(opt)
5253
if err != nil {
5354
return nil, err
5455
}
5556
li.opts.Epoch = tm
5657

58+
multiPlatform, opt, err := multiplatform.ParseExporterAttrs(opt)
59+
if err != nil {
60+
return nil, err
61+
}
62+
li.opts.MultiPlatform = multiPlatform
63+
5764
for k, v := range opt {
5865
switch k {
5966
case preferNondistLayersKey:
@@ -126,6 +133,8 @@ func (e *localExporterInstance) Export(ctx context.Context, inp *exporter.Source
126133
}, nil
127134
}
128135

136+
isMap := len(inp.Refs) > 0
137+
129138
platformsBytes, ok := inp.Metadata[exptypes.ExporterPlatformsKey]
130139
if len(inp.Refs) > 0 && !ok {
131140
return nil, errors.Errorf("unable to export multiple refs, missing platforms mapping")
@@ -136,8 +145,17 @@ func (e *localExporterInstance) Export(ctx context.Context, inp *exporter.Source
136145
if err := json.Unmarshal(platformsBytes, &p); err != nil {
137146
return nil, errors.Wrapf(err, "failed to parse platforms passed to exporter")
138147
}
148+
if len(p.Platforms) > 1 {
149+
isMap = true
150+
}
151+
}
152+
153+
if e.opts.MultiPlatform != nil {
154+
isMap = *e.opts.MultiPlatform
155+
}
156+
if !isMap && len(p.Platforms) > 1 {
157+
return nil, errors.Errorf("unable to export multiple platforms without map")
139158
}
140-
isMap := len(p.Platforms) > 1
141159

142160
var fs fsutil.FS
143161

exporter/util/epoch/parse.go

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,17 @@ import (
1010
)
1111

1212
const (
13+
frontendSourceDateEpochArg = "build-arg:SOURCE_DATE_EPOCH"
14+
1315
KeySourceDateEpoch = "source-date-epoch"
1416
)
1517

16-
func ParseAttr(opt map[string]string) (*time.Time, map[string]string, error) {
18+
func ParseBuildArgs(opt map[string]string) (string, bool) {
19+
v, ok := opt[frontendSourceDateEpochArg]
20+
return v, ok
21+
}
22+
23+
func ParseExporterAttrs(opt map[string]string) (*time.Time, map[string]string, error) {
1724
rest := make(map[string]string, len(opt))
1825

1926
var tm *time.Time

exporter/util/multiplatform/parse.go

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
package multiplatform
2+
3+
import (
4+
"strconv"
5+
6+
"github.com/pkg/errors"
7+
)
8+
9+
const (
10+
frontendMultiPlatform = "multi-platform"
11+
frontendMultiPlatformArg = "build-arg:BUILDKIT_MULTI_PLATFORM"
12+
13+
KeyMultiPlatform = "multi-platform"
14+
)
15+
16+
func ParseBuildArgs(opt map[string]string) (string, bool) {
17+
if v, ok := opt[frontendMultiPlatform]; ok {
18+
return v, true
19+
}
20+
if v, ok := opt[frontendMultiPlatformArg]; ok {
21+
return v, true
22+
}
23+
return "", false
24+
}
25+
26+
func ParseExporterAttrs(opt map[string]string) (*bool, map[string]string, error) {
27+
rest := make(map[string]string, len(opt))
28+
29+
var multiPlatform *bool
30+
31+
for k, v := range opt {
32+
switch k {
33+
case KeyMultiPlatform:
34+
b, err := strconv.ParseBool(v)
35+
if err != nil {
36+
return nil, nil, errors.Errorf("invalid boolean value %s", v)
37+
}
38+
multiPlatform = &b
39+
default:
40+
rest[k] = v
41+
}
42+
}
43+
44+
return multiPlatform, rest, nil
45+
}

0 commit comments

Comments
 (0)