Skip to content

Commit 45da9cf

Browse files
committed
Introduce CommitResults(), which returns a results struct
Add a CommitResults() method which returns a structure on success, changing Commit() into a wrapper for it which returns a subset of the data to keep its signature stable. Signed-off-by: Nalin Dahyabhai <[email protected]>
1 parent 91bc3aa commit 45da9cf

File tree

2 files changed

+64
-24
lines changed

2 files changed

+64
-24
lines changed

commit.go

Lines changed: 56 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -304,11 +304,35 @@ func (b *Builder) addManifest(ctx context.Context, manifestName string, imageSpe
304304
return imageID, err
305305
}
306306

307+
// CommitResults is a structure returned when CommitResults() succeeds.
308+
type CommitResults struct {
309+
ImageID string // a local image ID, or part of the digest of the image's config blob
310+
Canonical reference.Canonical // set if destination included a DockerReference
311+
MediaType string // always returned
312+
ImageManifest []byte // always returned
313+
Digest digest.Digest // always returned
314+
}
315+
307316
// Commit writes the contents of the container, along with its updated
308317
// configuration, to a new image in the specified location, and if we know how,
309318
// add any additional tags that were specified. Returns the ID of the new image
310-
// if commit was successful and the image destination was local.
319+
// if commit was successful and the image destination was local, a canonical
320+
// reference if the destination ImageReference include a DockerReference, and
321+
// the digest of the written image's manifest.
322+
// Commit() is implemented as a wrapper around CommitResults().
311323
func (b *Builder) Commit(ctx context.Context, dest types.ImageReference, options CommitOptions) (string, reference.Canonical, digest.Digest, error) {
324+
results, err := b.CommitResults(ctx, dest, options)
325+
if err != nil {
326+
return "", nil, "", err
327+
}
328+
return results.ImageID, results.Canonical, results.Digest, nil
329+
}
330+
331+
// CommitResults writes the contents of the container, along with its updated
332+
// configuration, to a new image in the specified location, and if we know how,
333+
// add any additional tags that were specified. Returns a CommitResults
334+
// structure.
335+
func (b *Builder) CommitResults(ctx context.Context, dest types.ImageReference, options CommitOptions) (*CommitResults, error) {
312336
var (
313337
imgID string
314338
src types.ImageReference
@@ -325,7 +349,7 @@ func (b *Builder) Commit(ctx context.Context, dest types.ImageReference, options
325349
// work twice.
326350
if options.OmitTimestamp {
327351
if options.HistoryTimestamp != nil {
328-
return imgID, nil, "", fmt.Errorf("OmitTimestamp and HistoryTimestamp can not be used together")
352+
return nil, fmt.Errorf("OmitTimestamp and HistoryTimestamp can not be used together")
329353
}
330354
timestamp := time.Unix(0, 0).UTC()
331355
options.HistoryTimestamp = &timestamp
@@ -339,7 +363,7 @@ func (b *Builder) Commit(ctx context.Context, dest types.ImageReference, options
339363
nameToRemove = stringid.GenerateRandomID() + "-tmp"
340364
dest2, err := is.Transport.ParseStoreReference(b.store, nameToRemove)
341365
if err != nil {
342-
return imgID, nil, "", fmt.Errorf("creating temporary destination reference for image: %w", err)
366+
return nil, fmt.Errorf("creating temporary destination reference for image: %w", err)
343367
}
344368
dest = dest2
345369
}
@@ -348,23 +372,23 @@ func (b *Builder) Commit(ctx context.Context, dest types.ImageReference, options
348372

349373
blocked, err := isReferenceBlocked(dest, systemContext)
350374
if err != nil {
351-
return "", nil, "", fmt.Errorf("checking if committing to registry for %q is blocked: %w", transports.ImageName(dest), err)
375+
return nil, fmt.Errorf("checking if committing to registry for %q is blocked: %w", transports.ImageName(dest), err)
352376
}
353377
if blocked {
354-
return "", nil, "", fmt.Errorf("commit access to registry for %q is blocked by configuration", transports.ImageName(dest))
378+
return nil, fmt.Errorf("commit access to registry for %q is blocked by configuration", transports.ImageName(dest))
355379
}
356380

357381
// Load the system signing policy.
358382
commitPolicy, err := signature.DefaultPolicy(systemContext)
359383
if err != nil {
360-
return "", nil, "", fmt.Errorf("obtaining default signature policy: %w", err)
384+
return nil, fmt.Errorf("obtaining default signature policy: %w", err)
361385
}
362386
// Override the settings for local storage to make sure that we can always read the source "image".
363387
commitPolicy.Transports[is.Transport.Name()] = storageAllowedPolicyScopes
364388

365389
policyContext, err := signature.NewPolicyContext(commitPolicy)
366390
if err != nil {
367-
return imgID, nil, "", fmt.Errorf("creating new signature policy context: %w", err)
391+
return nil, fmt.Errorf("creating new signature policy context: %w", err)
368392
}
369393
defer func() {
370394
if err2 := policyContext.Destroy(); err2 != nil {
@@ -375,11 +399,11 @@ func (b *Builder) Commit(ctx context.Context, dest types.ImageReference, options
375399
// Check if the commit is blocked by $BUILDER_REGISTRY_SOURCES.
376400
insecure, err := checkRegistrySourcesAllows("commit to", dest)
377401
if err != nil {
378-
return imgID, nil, "", err
402+
return nil, err
379403
}
380404
if insecure {
381405
if systemContext.DockerInsecureSkipTLSVerify == types.OptionalBoolFalse {
382-
return imgID, nil, "", fmt.Errorf("can't require tls verification on an insecured registry")
406+
return nil, fmt.Errorf("can't require tls verification on an insecured registry")
383407
}
384408
systemContext.DockerInsecureSkipTLSVerify = types.OptionalBoolTrue
385409
systemContext.OCIInsecureSkipTLSVerify = true
@@ -393,7 +417,7 @@ func (b *Builder) Commit(ctx context.Context, dest types.ImageReference, options
393417
if len(options.SBOMScanOptions) != 0 {
394418
var scansDirectory string
395419
if extraImageContent, extraLocalContent, scansDirectory, err = b.sbomScan(ctx, options); err != nil {
396-
return imgID, nil, "", fmt.Errorf("scanning rootfs to generate SBOM for container %q: %w", b.ContainerID, err)
420+
return nil, fmt.Errorf("scanning rootfs to generate SBOM for container %q: %w", b.ContainerID, err)
397421
}
398422
if scansDirectory != "" {
399423
defer func() {
@@ -418,7 +442,7 @@ func (b *Builder) Commit(ctx context.Context, dest types.ImageReference, options
418442
// Build an image reference from which we can copy the finished image.
419443
src, err = b.makeContainerImageRef(options)
420444
if err != nil {
421-
return imgID, nil, "", fmt.Errorf("computing layer digests and building metadata for container %q: %w", b.ContainerID, err)
445+
return nil, fmt.Errorf("computing layer digests and building metadata for container %q: %w", b.ContainerID, err)
422446
}
423447
// In case we're using caching, decide how to handle compression for a cache.
424448
// If we're using blob caching, set it up for the source.
@@ -431,12 +455,12 @@ func (b *Builder) Commit(ctx context.Context, dest types.ImageReference, options
431455
}
432456
cache, err := blobcache.NewBlobCache(src, options.BlobDirectory, compress)
433457
if err != nil {
434-
return imgID, nil, "", fmt.Errorf("wrapping image reference %q in blob cache at %q: %w", transports.ImageName(src), options.BlobDirectory, err)
458+
return nil, fmt.Errorf("wrapping image reference %q in blob cache at %q: %w", transports.ImageName(src), options.BlobDirectory, err)
435459
}
436460
maybeCachedSrc = cache
437461
cache, err = blobcache.NewBlobCache(dest, options.BlobDirectory, compress)
438462
if err != nil {
439-
return imgID, nil, "", fmt.Errorf("wrapping image reference %q in blob cache at %q: %w", transports.ImageName(dest), options.BlobDirectory, err)
463+
return nil, fmt.Errorf("wrapping image reference %q in blob cache at %q: %w", transports.ImageName(dest), options.BlobDirectory, err)
440464
}
441465
maybeCachedDest = cache
442466
}
@@ -457,7 +481,7 @@ func (b *Builder) Commit(ctx context.Context, dest types.ImageReference, options
457481

458482
var manifestBytes []byte
459483
if manifestBytes, err = retryCopyImage(ctx, policyContext, maybeCachedDest, maybeCachedSrc, dest, getCopyOptions(b.store, options.ReportWriter, nil, systemContext, "", false, options.SignBy, options.OciEncryptLayers, options.OciEncryptConfig, nil, destinationTimestamp), options.MaxRetries, options.RetryDelay); err != nil {
460-
return imgID, nil, "", fmt.Errorf("copying layers and metadata for container %q: %w", b.ContainerID, err)
484+
return nil, fmt.Errorf("copying layers and metadata for container %q: %w", b.ContainerID, err)
461485
}
462486
// If we've got more names to attach, and we know how to do that for
463487
// the transport that we're writing the new image to, add them now.
@@ -466,10 +490,10 @@ func (b *Builder) Commit(ctx context.Context, dest types.ImageReference, options
466490
case is.Transport.Name():
467491
_, img, err := is.ResolveReference(dest)
468492
if err != nil {
469-
return imgID, nil, "", fmt.Errorf("locating just-written image %q: %w", transports.ImageName(dest), err)
493+
return nil, fmt.Errorf("locating just-written image %q: %w", transports.ImageName(dest), err)
470494
}
471495
if err = util.AddImageNames(b.store, "", systemContext, img, options.AdditionalTags); err != nil {
472-
return imgID, nil, "", fmt.Errorf("setting image names to %v: %w", append(img.Names, options.AdditionalTags...), err)
496+
return nil, fmt.Errorf("setting image names to %v: %w", append(img.Names, options.AdditionalTags...), err)
473497
}
474498
logrus.Debugf("assigned names %v to image %q", img.Names, img.ID)
475499
default:
@@ -480,7 +504,7 @@ func (b *Builder) Commit(ctx context.Context, dest types.ImageReference, options
480504
if dest.Transport().Name() == is.Transport.Name() {
481505
dest2, img, err := is.ResolveReference(dest)
482506
if err != nil {
483-
return imgID, nil, "", fmt.Errorf("locating image %q in local storage: %w", transports.ImageName(dest), err)
507+
return nil, fmt.Errorf("locating image %q in local storage: %w", transports.ImageName(dest), err)
484508
}
485509
dest = dest2
486510
imgID = img.ID
@@ -492,13 +516,13 @@ func (b *Builder) Commit(ctx context.Context, dest types.ImageReference, options
492516
}
493517
if len(toPruneNames) > 0 {
494518
if err = b.store.RemoveNames(imgID, toPruneNames); err != nil {
495-
return imgID, nil, "", fmt.Errorf("failed to remove temporary name from image %q: %w", imgID, err)
519+
return nil, fmt.Errorf("failed to remove temporary name from image %q: %w", imgID, err)
496520
}
497521
logrus.Debugf("removing %v from assigned names to image %q", nameToRemove, img.ID)
498522
}
499523
if options.IIDFile != "" {
500524
if err = os.WriteFile(options.IIDFile, []byte("sha256:"+img.ID), 0o644); err != nil {
501-
return imgID, nil, "", err
525+
return nil, err
502526
}
503527
}
504528
}
@@ -521,20 +545,20 @@ func (b *Builder) Commit(ctx context.Context, dest types.ImageReference, options
521545
return nil
522546
}()
523547
if err != nil {
524-
return imgID, nil, "", err
548+
return nil, err
525549
}
526550
}
527551

528552
// Calculate the as-written digest of the image's manifest and build the digested
529553
// reference for the image.
530554
manifestDigest, err := manifest.Digest(manifestBytes)
531555
if err != nil {
532-
return imgID, nil, "", fmt.Errorf("computing digest of manifest of new image %q: %w", transports.ImageName(dest), err)
556+
return nil, fmt.Errorf("computing digest of manifest of new image %q: %w", transports.ImageName(dest), err)
533557
}
534558
if imgID == "" {
535559
parsedManifest, err := manifest.FromBlob(manifestBytes, manifest.GuessMIMEType(manifestBytes))
536560
if err != nil {
537-
return imgID, nil, "", fmt.Errorf("parsing written manifest to determine the image's ID: %w", err)
561+
return nil, fmt.Errorf("parsing written manifest to determine the image's ID: %w", err)
538562
}
539563
configInfo := parsedManifest.ConfigInfo()
540564
if configInfo.Size > 2 && configInfo.Digest.Validate() == nil { // don't be returning a digest of "" or "{}"
@@ -553,9 +577,17 @@ func (b *Builder) Commit(ctx context.Context, dest types.ImageReference, options
553577
if options.Manifest != "" {
554578
manifestID, err := b.addManifest(ctx, options.Manifest, imgID)
555579
if err != nil {
556-
return imgID, nil, "", err
580+
return nil, err
557581
}
558582
logrus.Debugf("added imgID %s to manifestID %s", imgID, manifestID)
559583
}
560-
return imgID, ref, manifestDigest, nil
584+
585+
results := CommitResults{
586+
ImageID: imgID,
587+
Canonical: ref,
588+
MediaType: manifest.GuessMIMEType(manifestBytes),
589+
ImageManifest: manifestBytes,
590+
Digest: manifestDigest,
591+
}
592+
return &results, nil
561593
}

tests/commit.bats

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,14 @@ load helpers
127127
expect_output ""
128128
}
129129

130+
@test "commit iidfile" {
131+
_prefetch busybox
132+
run_buildah from --quiet --pull=false $WITH_POLICY_JSON busybox
133+
cid=$output
134+
run_buildah commit --iidfile ${TEST_SCRATCH_DIR}/iidfile.txt $cid
135+
test -s ${TEST_SCRATCH_DIR}/iidfile.txt
136+
}
137+
130138
@test "commit rm test" {
131139
_prefetch alpine
132140
run_buildah from --quiet --pull=false $WITH_POLICY_JSON alpine

0 commit comments

Comments
 (0)