CommitWithOptions marks the process of storing the image as successful and asks for the image to be persisted. WARNING: This does not have any transactional semantics: - Uploaded data MAY be visible to others before CommitWithOptions() is called - Uploaded data MAY be removed or MAY remain around if
(ctx context.Context, options private.CommitOptions)
| 1417 | // - Uploaded data MAY be visible to others before CommitWithOptions() is called |
| 1418 | // - Uploaded data MAY be removed or MAY remain around if Close() is called without CommitWithOptions() (i.e. rollback is allowed but not guaranteed) |
| 1419 | func (s *storageImageDestination) CommitWithOptions(ctx context.Context, options private.CommitOptions) error { |
| 1420 | // This function is outside of the scope of HasThreadSafePutBlob, so we don’t need to hold s.lock. |
| 1421 | |
| 1422 | if s.manifest == nil { |
| 1423 | return errors.New("Internal error: storageImageDestination.CommitWithOptions() called without PutManifest()") |
| 1424 | } |
| 1425 | toplevelManifest, _, err := options.UnparsedToplevel.Manifest(ctx) |
| 1426 | if err != nil { |
| 1427 | return fmt.Errorf("retrieving top-level manifest: %w", err) |
| 1428 | } |
| 1429 | // If the name we're saving to includes a digest, then check that the |
| 1430 | // manifests that we're about to save all either match the one from the |
| 1431 | // options.UnparsedToplevel, or match the digest in the name that we're using. |
| 1432 | if s.imageRef.named != nil { |
| 1433 | if digested, ok := s.imageRef.named.(reference.Digested); ok { |
| 1434 | matches, err := manifest.MatchesDigest(s.manifest, digested.Digest()) |
| 1435 | if err != nil { |
| 1436 | return err |
| 1437 | } |
| 1438 | if !matches { |
| 1439 | matches, err = manifest.MatchesDigest(toplevelManifest, digested.Digest()) |
| 1440 | if err != nil { |
| 1441 | return err |
| 1442 | } |
| 1443 | } |
| 1444 | if !matches { |
| 1445 | return fmt.Errorf("Manifest to be saved does not match expected digest %s", digested.Digest()) |
| 1446 | } |
| 1447 | } |
| 1448 | } |
| 1449 | // Find the list of layer blobs. |
| 1450 | man, err := manifest.FromBlob(s.manifest, s.manifestMIMEType) |
| 1451 | if err != nil { |
| 1452 | return fmt.Errorf("parsing manifest: %w", err) |
| 1453 | } |
| 1454 | layerBlobs := man.LayerInfos() |
| 1455 | |
| 1456 | // Extract, commit, or find the layers. |
| 1457 | for i, blob := range layerBlobs { |
| 1458 | if stopQueue, err := s.commitLayer(i, addedLayerInfo{ |
| 1459 | digest: blob.Digest, |
| 1460 | emptyLayer: blob.EmptyLayer, |
| 1461 | }, blob.Size); err != nil { |
| 1462 | return err |
| 1463 | } else if stopQueue { |
| 1464 | return fmt.Errorf("Internal error: storageImageDestination.CommitWithOptions(): commitLayer() not ready to commit for layer %q", blob.Digest) |
| 1465 | } |
| 1466 | } |
| 1467 | var lastLayer string |
| 1468 | if len(layerBlobs) > 0 { // Zero-layer images rarely make sense, but it is technically possible, and may happen for non-image artifacts. |
| 1469 | prev, ok := s.indexToStorageID[len(layerBlobs)-1] |
| 1470 | if !ok { |
| 1471 | return fmt.Errorf("Internal error: storageImageDestination.CommitWithOptions(): previous layer %d hasn't been committed (lastLayer == nil)", len(layerBlobs)-1) |
| 1472 | } |
| 1473 | lastLayer = prev |
| 1474 | } |
| 1475 | |
| 1476 | // If one of those blobs was a configuration blob, then we can try to dig out the date when the image |
nothing calls this directly
no test coverage detected