Skip to content

Commit e5f9959

Browse files
committed
build history: support for image descriptors
Signed-off-by: Tonis Tiigi <tonistiigi@gmail.com>
1 parent 179bed6 commit e5f9959

7 files changed

Lines changed: 181 additions & 106 deletions

File tree

cmd/buildctl/debug/monitor.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,11 +56,17 @@ func monitor(clicontext *cli.Context) error {
5656
}
5757

5858
if ev.Record.Result != nil {
59+
if ev.Record.Result.Result != nil {
60+
fmt.Printf(" descriptor: %s\n", ev.Record.Result.Result)
61+
}
5962
for _, att := range ev.Record.Result.Attestations {
6063
fmt.Printf(" attestation: %s\n", att)
6164
}
6265
}
6366
for k, res := range ev.Record.Results {
67+
if res.Result != nil {
68+
fmt.Printf(" [%s] descriptor: %s\n", k, res.Result)
69+
}
6470
for _, att := range res.Attestations {
6571
fmt.Printf(" [%s] attestation: %s\n", k, att)
6672
}

exporter/containerimage/export.go

Lines changed: 42 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -194,7 +194,7 @@ func (e *imageExporterInstance) Config() *exporter.Config {
194194
return exporter.NewConfigWithCompression(e.opts.RefCfg.Compression)
195195
}
196196

197-
func (e *imageExporterInstance) Export(ctx context.Context, src *exporter.Source, sessionID string) (map[string]string, error) {
197+
func (e *imageExporterInstance) Export(ctx context.Context, src *exporter.Source, sessionID string) (_ map[string]string, descref exporter.DescriptorReference, err error) {
198198
if src.Metadata == nil {
199199
src.Metadata = make(map[string][]byte)
200200
}
@@ -205,23 +205,28 @@ func (e *imageExporterInstance) Export(ctx context.Context, src *exporter.Source
205205
opts := e.opts
206206
as, _, err := ParseAnnotations(src.Metadata)
207207
if err != nil {
208-
return nil, err
208+
return nil, nil, err
209209
}
210210
opts.Annotations = opts.Annotations.Merge(as)
211211

212212
ctx, done, err := leaseutil.WithLease(ctx, e.opt.LeaseManager, leaseutil.MakeTemporary)
213213
if err != nil {
214-
return nil, err
214+
return nil, nil, err
215215
}
216-
defer done(context.TODO())
216+
defer func() {
217+
if descref == nil {
218+
done(context.TODO())
219+
}
220+
}()
217221

218222
desc, err := e.opt.ImageWriter.Commit(ctx, src, sessionID, &opts)
219223
if err != nil {
220-
return nil, err
224+
return nil, nil, err
221225
}
222-
223226
defer func() {
224-
e.opt.ImageWriter.ContentStore().Delete(context.TODO(), desc.Digest)
227+
if err == nil {
228+
descref = NewDescriptorReference(*desc, done)
229+
}
225230
}()
226231

227232
resp := make(map[string]string)
@@ -253,45 +258,45 @@ func (e *imageExporterInstance) Export(ctx context.Context, src *exporter.Source
253258
img.Name = targetName + sfx
254259
if _, err := e.opt.Images.Update(ctx, img); err != nil {
255260
if !errors.Is(err, errdefs.ErrNotFound) {
256-
return nil, tagDone(err)
261+
return nil, nil, tagDone(err)
257262
}
258263

259264
if _, err := e.opt.Images.Create(ctx, img); err != nil {
260-
return nil, tagDone(err)
265+
return nil, nil, tagDone(err)
261266
}
262267
}
263268
}
264269
tagDone(nil)
265270

266271
if src.Ref != nil && e.unpack {
267272
if err := e.unpackImage(ctx, img, src, session.NewGroup(sessionID)); err != nil {
268-
return nil, err
273+
return nil, nil, err
269274
}
270275
}
271276

272277
if !e.storeAllowIncomplete {
273278
if src.Ref != nil {
274279
remotes, err := src.Ref.GetRemotes(ctx, false, e.opts.RefCfg, false, session.NewGroup(sessionID))
275280
if err != nil {
276-
return nil, err
281+
return nil, nil, err
277282
}
278283
remote := remotes[0]
279284
if unlazier, ok := remote.Provider.(cache.Unlazier); ok {
280285
if err := unlazier.Unlazy(ctx); err != nil {
281-
return nil, err
286+
return nil, nil, err
282287
}
283288
}
284289
}
285290
if len(src.Refs) > 0 {
286291
for _, r := range src.Refs {
287292
remotes, err := r.GetRemotes(ctx, false, e.opts.RefCfg, false, session.NewGroup(sessionID))
288293
if err != nil {
289-
return nil, err
294+
return nil, nil, err
290295
}
291296
remote := remotes[0]
292297
if unlazier, ok := remote.Provider.(cache.Unlazier); ok {
293298
if err := unlazier.Unlazy(ctx); err != nil {
294-
return nil, err
299+
return nil, nil, err
295300
}
296301
}
297302
}
@@ -301,7 +306,7 @@ func (e *imageExporterInstance) Export(ctx context.Context, src *exporter.Source
301306
if e.push {
302307
err := e.pushImage(ctx, src, sessionID, targetName, desc.Digest)
303308
if err != nil {
304-
return nil, errors.Wrapf(err, "failed to push %v", targetName)
309+
return nil, nil, errors.Wrapf(err, "failed to push %v", targetName)
305310
}
306311
}
307312
}
@@ -316,11 +321,11 @@ func (e *imageExporterInstance) Export(ctx context.Context, src *exporter.Source
316321

317322
dtdesc, err := json.Marshal(desc)
318323
if err != nil {
319-
return nil, err
324+
return nil, nil, err
320325
}
321326
resp[exptypes.ExporterImageDescriptorKey] = base64.StdEncoding.EncodeToString(dtdesc)
322327

323-
return resp, nil
328+
return resp, nil, nil
324329
}
325330

326331
func (e *imageExporterInstance) pushImage(ctx context.Context, src *exporter.Source, sessionID string, targetName string, dgst digest.Digest) error {
@@ -460,3 +465,23 @@ func defaultPlatform() string {
460465
// are normalized using platforms.Normalize()
461466
return platforms.Format(platforms.Normalize(platforms.DefaultSpec()))
462467
}
468+
469+
func NewDescriptorReference(desc ocispecs.Descriptor, release func(context.Context) error) exporter.DescriptorReference {
470+
return &descriptorReference{
471+
desc: desc,
472+
release: release,
473+
}
474+
}
475+
476+
type descriptorReference struct {
477+
desc ocispecs.Descriptor
478+
release func(context.Context) error
479+
}
480+
481+
func (d *descriptorReference) Descriptor() ocispecs.Descriptor {
482+
return d.desc
483+
}
484+
485+
func (d *descriptorReference) Release() error {
486+
return d.release(context.TODO())
487+
}

exporter/exporter.go

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import (
66
"github.com/moby/buildkit/cache"
77
"github.com/moby/buildkit/solver/result"
88
"github.com/moby/buildkit/util/compression"
9+
ocispecs "github.com/opencontainers/image-spec/specs-go/v1"
910
)
1011

1112
type Source = result.Result[cache.ImmutableRef]
@@ -19,7 +20,12 @@ type Exporter interface {
1920
type ExporterInstance interface {
2021
Name() string
2122
Config() *Config
22-
Export(ctx context.Context, src *Source, sessionID string) (map[string]string, error)
23+
Export(ctx context.Context, src *Source, sessionID string) (map[string]string, DescriptorReference, error)
24+
}
25+
26+
type DescriptorReference interface {
27+
Release() error
28+
Descriptor() ocispecs.Descriptor
2329
}
2430

2531
type Config struct {

exporter/local/export.go

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -74,35 +74,35 @@ func (e *localExporter) Config() *exporter.Config {
7474
return exporter.NewConfig()
7575
}
7676

77-
func (e *localExporterInstance) Export(ctx context.Context, inp *exporter.Source, sessionID string) (map[string]string, error) {
77+
func (e *localExporterInstance) Export(ctx context.Context, inp *exporter.Source, sessionID string) (map[string]string, exporter.DescriptorReference, error) {
7878
timeoutCtx, cancel := context.WithTimeout(ctx, 5*time.Second)
7979
defer cancel()
8080

8181
if e.opts.Epoch == nil {
8282
if tm, ok, err := epoch.ParseSource(inp); err != nil {
83-
return nil, err
83+
return nil, nil, err
8484
} else if ok {
8585
e.opts.Epoch = tm
8686
}
8787
}
8888

8989
caller, err := e.opt.SessionManager.Get(timeoutCtx, sessionID, false)
9090
if err != nil {
91-
return nil, err
91+
return nil, nil, err
9292
}
9393

9494
isMap := len(inp.Refs) > 0
9595

9696
if _, ok := inp.Metadata[exptypes.ExporterPlatformsKey]; isMap && !ok {
97-
return nil, errors.Errorf("unable to export multiple refs, missing platforms mapping")
97+
return nil, nil, errors.Errorf("unable to export multiple refs, missing platforms mapping")
9898
}
9999
p, err := exptypes.ParsePlatforms(inp.Metadata)
100100
if err != nil {
101-
return nil, err
101+
return nil, nil, err
102102
}
103103

104104
if !isMap && len(p.Platforms) > 1 {
105-
return nil, errors.Errorf("unable to export multiple platforms without map")
105+
return nil, nil, errors.Errorf("unable to export multiple platforms without map")
106106
}
107107

108108
now := time.Now().Truncate(time.Second)
@@ -148,7 +148,7 @@ func (e *localExporterInstance) Export(ctx context.Context, inp *exporter.Source
148148
for _, p := range p.Platforms {
149149
r, ok := inp.FindRef(p.ID)
150150
if !ok {
151-
return nil, errors.Errorf("failed to find ref for ID %s", p.ID)
151+
return nil, nil, errors.Errorf("failed to find ref for ID %s", p.ID)
152152
}
153153
eg.Go(export(ctx, p.ID, r, inp.Attestations[p.ID]))
154154
}
@@ -157,9 +157,9 @@ func (e *localExporterInstance) Export(ctx context.Context, inp *exporter.Source
157157
}
158158

159159
if err := eg.Wait(); err != nil {
160-
return nil, err
160+
return nil, nil, err
161161
}
162-
return nil, nil
162+
return nil, nil, nil
163163
}
164164

165165
func NewProgressHandler(ctx context.Context, id string) func(int, bool) {

0 commit comments

Comments
 (0)