From f6561554620019b310a47ec18ee5472e7169b4b0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miloslav=20Trma=C4=8D?= Date: Wed, 7 Feb 2024 23:15:30 +0100 Subject: [PATCH 1/9] Move the definition of storageImageCloser closer to its methods MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Should not change behavior. Signed-off-by: Miloslav Trmač --- storage/storage_image.go | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/storage/storage_image.go b/storage/storage_image.go index ac09f3dbbc..68fa62b709 100644 --- a/storage/storage_image.go +++ b/storage/storage_image.go @@ -18,11 +18,6 @@ var ( ErrNoSuchImage = storage.ErrNotAnImage ) -type storageImageCloser struct { - types.ImageCloser - size int64 -} - // manifestBigDataKey returns a key suitable for recording a manifest with the specified digest using storage.Store.ImageBigData and related functions. // If a specific manifest digest is explicitly requested by the user, the key returned by this function should be used preferably; // for compatibility, if a manifest is not available under this key, check also storage.ImageDigestBigDataKey @@ -36,6 +31,11 @@ func signatureBigDataKey(digest digest.Digest) string { return "signature-" + digest.Encoded() } +type storageImageCloser struct { + types.ImageCloser + size int64 +} + // Size() returns the previously-computed size of the image, with no error. func (s *storageImageCloser) Size() (int64, error) { return s.size, nil From 4cc225e1977c29585db6c62de87cd0837fe31bab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miloslav=20Trma=C4=8D?= Date: Wed, 7 Feb 2024 23:27:42 +0100 Subject: [PATCH 2/9] Define storageImageMetadata for the JSON in Image.Metadata MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This way we: - have a single type, guaranteeing the source and destination don't get out of sync - separate the JSON-encoded data, without having to worry about Marshal/Unmarshal affecting unrelated fields of the source/destination. Should not change behavior. Signed-off-by: Miloslav Trmač --- storage/storage_dest.go | 35 ++++++++++++++++++----------------- storage/storage_image.go | 6 ++++++ storage/storage_src.go | 27 ++++++++++++++------------- 3 files changed, 38 insertions(+), 30 deletions(-) diff --git a/storage/storage_dest.go b/storage/storage_dest.go index 53569793e6..17d821ad6c 100644 --- a/storage/storage_dest.go +++ b/storage/storage_dest.go @@ -55,15 +55,14 @@ type storageImageDestination struct { stubs.ImplementsPutBlobPartial stubs.AlwaysSupportsSignatures - imageRef storageReference - directory string // Temporary directory where we store blobs until Commit() time - nextTempFileID atomic.Int32 // A counter that we use for computing filenames to assign to blobs - manifest []byte // Manifest contents, temporary - manifestDigest digest.Digest // Valid if len(manifest) != 0 - signatures []byte // Signature contents, temporary - signatureses map[digest.Digest][]byte // Instance signature contents, temporary - SignatureSizes []int `json:"signature-sizes,omitempty"` // List of sizes of each signature slice - SignaturesSizes map[digest.Digest][]int `json:"signatures-sizes,omitempty"` // Sizes of each manifest's signature slice + imageRef storageReference + directory string // Temporary directory where we store blobs until Commit() time + nextTempFileID atomic.Int32 // A counter that we use for computing filenames to assign to blobs + manifest []byte // Manifest contents, temporary + manifestDigest digest.Digest // Valid if len(manifest) != 0 + signatures []byte // Signature contents, temporary + signatureses map[digest.Digest][]byte // Instance signature contents, temporary + metadata storageImageMetadata // Metadata contents being built // A storage destination may be used concurrently. Accesses are // serialized via a mutex. Please refer to the individual comments @@ -124,11 +123,13 @@ func newImageDestination(sys *types.SystemContext, imageRef storageReference) (* blobAdditionalLayer: make(map[digest.Digest]storage.AdditionalLayer), fileSizes: make(map[digest.Digest]int64), filenames: make(map[digest.Digest]string), - SignatureSizes: []int{}, - SignaturesSizes: make(map[digest.Digest][]int), - indexToStorageID: make(map[int]*string), - indexToAddedLayerInfo: make(map[int]addedLayerInfo), - diffOutputs: make(map[digest.Digest]*graphdriver.DriverWithDifferOutput), + metadata: storageImageMetadata{ + SignatureSizes: []int{}, + SignaturesSizes: make(map[digest.Digest][]int), + }, + indexToStorageID: make(map[int]*string), + indexToAddedLayerInfo: make(map[int]addedLayerInfo), + diffOutputs: make(map[digest.Digest]*graphdriver.DriverWithDifferOutput), } dest.Compat = impl.AddCompat(dest) return dest, nil @@ -906,7 +907,7 @@ func (s *storageImageDestination) Commit(ctx context.Context, unparsedToplevel t } // Set up to save our metadata. - metadata, err := json.Marshal(s) + metadata, err := json.Marshal(s.metadata) if err != nil { return fmt.Errorf("encoding metadata for image: %w", err) } @@ -1011,7 +1012,7 @@ func (s *storageImageDestination) PutSignaturesWithFormat(ctx context.Context, s } if instanceDigest == nil { s.signatures = sigblob - s.SignatureSizes = sizes + s.metadata.SignatureSizes = sizes if len(s.manifest) > 0 { manifestDigest := s.manifestDigest instanceDigest = &manifestDigest @@ -1019,7 +1020,7 @@ func (s *storageImageDestination) PutSignaturesWithFormat(ctx context.Context, s } if instanceDigest != nil { s.signatureses[*instanceDigest] = sigblob - s.SignaturesSizes[*instanceDigest] = sizes + s.metadata.SignaturesSizes[*instanceDigest] = sizes } return nil } diff --git a/storage/storage_image.go b/storage/storage_image.go index 68fa62b709..eed846eb93 100644 --- a/storage/storage_image.go +++ b/storage/storage_image.go @@ -31,6 +31,12 @@ func signatureBigDataKey(digest digest.Digest) string { return "signature-" + digest.Encoded() } +// storageImageMetadata is stored, as JSON, in storage.Image.Metadata +type storageImageMetadata struct { + SignatureSizes []int `json:"signature-sizes,omitempty"` // List of sizes of each signature slice + SignaturesSizes map[digest.Digest][]int `json:"signatures-sizes,omitempty"` // Sizes of each manifest's signature slice +} + type storageImageCloser struct { types.ImageCloser size int64 diff --git a/storage/storage_src.go b/storage/storage_src.go index 7022d322ea..36f11ef301 100644 --- a/storage/storage_src.go +++ b/storage/storage_src.go @@ -47,11 +47,10 @@ type storageImageSource struct { imageRef storageReference image *storage.Image systemContext *types.SystemContext // SystemContext used in GetBlob() to create temporary files - cachedManifest []byte // A cached copy of the manifest, if already known, or nil - getBlobMutex sync.Mutex // Mutex to sync state for parallel GetBlob executions (it guards layerPosition and digestToLayerID) + metadata storageImageMetadata + cachedManifest []byte // A cached copy of the manifest, if already known, or nil + getBlobMutex sync.Mutex // Mutex to sync state for parallel GetBlob executions (it guards layerPosition and digestToLayerID) getBlobMutexProtected getBlobMutexProtected - SignatureSizes []int `json:"signature-sizes,omitempty"` // List of sizes of each signature slice - SignaturesSizes map[digest.Digest][]int `json:"signatures-sizes,omitempty"` // List of sizes of each signature slice } const expectedLayerDiffIDFlag = "expected-layer-diffid" @@ -71,11 +70,13 @@ func newImageSource(sys *types.SystemContext, imageRef storageReference) (*stora }), NoGetBlobAtInitialize: stubs.NoGetBlobAt(imageRef), - imageRef: imageRef, - systemContext: sys, - image: img, - SignatureSizes: []int{}, - SignaturesSizes: make(map[digest.Digest][]int), + imageRef: imageRef, + systemContext: sys, + image: img, + metadata: storageImageMetadata{ + SignatureSizes: []int{}, + SignaturesSizes: make(map[digest.Digest][]int), + }, getBlobMutexProtected: getBlobMutexProtected{ digestToLayerID: make(map[digest.Digest]string), layerPosition: make(map[digest.Digest]int), @@ -83,7 +84,7 @@ func newImageSource(sys *types.SystemContext, imageRef storageReference) (*stora } image.Compat = impl.AddCompat(image) if img.Metadata != "" { - if err := json.Unmarshal([]byte(img.Metadata), image); err != nil { + if err := json.Unmarshal([]byte(img.Metadata), &image.metadata); err != nil { return nil, fmt.Errorf("decoding metadata for source image: %w", err) } } @@ -375,11 +376,11 @@ func buildLayerInfosForCopy(manifestInfos []manifest.LayerInfo, physicalInfos [] func (s *storageImageSource) GetSignaturesWithFormat(ctx context.Context, instanceDigest *digest.Digest) ([]signature.Signature, error) { var offset int signatureBlobs := []byte{} - signatureSizes := s.SignatureSizes + signatureSizes := s.metadata.SignatureSizes key := "signatures" instance := "default instance" if instanceDigest != nil { - signatureSizes = s.SignaturesSizes[*instanceDigest] + signatureSizes = s.metadata.SignaturesSizes[*instanceDigest] key = signatureBigDataKey(*instanceDigest) instance = instanceDigest.Encoded() } @@ -425,7 +426,7 @@ func (s *storageImageSource) getSize() (int64, error) { sum += bigSize } // Add the signature sizes. - for _, sigSize := range s.SignatureSizes { + for _, sigSize := range s.metadata.SignatureSizes { sum += int64(sigSize) } // Walk the layer list. From ee3bac4434e726d3bba5de7bfa986b05566d9a63 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miloslav=20Trma=C4=8D?= Date: Thu, 8 Feb 2024 01:11:06 +0100 Subject: [PATCH 3/9] Remove an unnecessary pointer in map values MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit First, it is unnecessary. Second, we will no longer need to worry about _allocating_ a variable to point to, or about pointing at a shared/volatile location. Signed-off-by: Miloslav Trmač --- storage/storage_dest.go | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/storage/storage_dest.go b/storage/storage_dest.go index 17d821ad6c..5e59ce4817 100644 --- a/storage/storage_dest.go +++ b/storage/storage_dest.go @@ -73,7 +73,7 @@ type storageImageDestination struct { // time, can only be executed by *one* goroutine. Please refer to // `queueOrCommit()` for further details on how the single-caller // guarantee is implemented. - indexToStorageID map[int]*string + indexToStorageID map[int]string // All accesses to below data are protected by `lock` which is made // *explicit* in the code. uncompressedOrTocDigest map[digest.Digest]digest.Digest // Mapping from layer blobsums to their corresponding DiffIDs or TOC IDs. @@ -127,7 +127,7 @@ func newImageDestination(sys *types.SystemContext, imageRef storageReference) (* SignatureSizes: []int{}, SignaturesSizes: make(map[digest.Digest][]int), }, - indexToStorageID: make(map[int]*string), + indexToStorageID: make(map[int]string), indexToAddedLayerInfo: make(map[int]addedLayerInfo), diffOutputs: make(map[digest.Digest]*graphdriver.DriverWithDifferOutput), } @@ -588,13 +588,13 @@ func (s *storageImageDestination) commitLayer(index int, info addedLayerInfo, si // `s.indexToStorageID` can only be accessed by *one* goroutine at any // given time. Hence, we don't need to lock accesses. var lastLayer string - if prev := s.indexToStorageID[index-1]; prev != nil { - lastLayer = *prev + if prev, ok := s.indexToStorageID[index-1]; ok { + lastLayer = prev } // Carry over the previous ID for empty non-base layers. if info.emptyLayer { - s.indexToStorageID[index] = &lastLayer + s.indexToStorageID[index] = lastLayer return false, nil } @@ -633,7 +633,7 @@ func (s *storageImageDestination) commitLayer(index int, info addedLayerInfo, si if layer, err2 := s.imageRef.transport.store.Layer(id); layer != nil && err2 == nil { // There's already a layer that should have the right contents, just reuse it. lastLayer = layer.ID - s.indexToStorageID[index] = &lastLayer + s.indexToStorageID[index] = lastLayer return false, nil } @@ -683,7 +683,7 @@ func (s *storageImageDestination) commitLayer(index int, info addedLayerInfo, si return false, err } - s.indexToStorageID[index] = &layer.ID + s.indexToStorageID[index] = layer.ID return false, nil } @@ -696,7 +696,7 @@ func (s *storageImageDestination) commitLayer(index int, info addedLayerInfo, si return false, fmt.Errorf("failed to put layer from digest and labels: %w", err) } lastLayer = layer.ID - s.indexToStorageID[index] = &lastLayer + s.indexToStorageID[index] = lastLayer return false, nil } @@ -770,7 +770,7 @@ func (s *storageImageDestination) commitLayer(index int, info addedLayerInfo, si return false, fmt.Errorf("adding layer with blob %q: %w", info.digest, err) } - s.indexToStorageID[index] = &layer.ID + s.indexToStorageID[index] = layer.ID return false, nil } @@ -829,11 +829,11 @@ func (s *storageImageDestination) Commit(ctx context.Context, unparsedToplevel t } var lastLayer string if len(layerBlobs) > 0 { // Can happen when using caches - prev := s.indexToStorageID[len(layerBlobs)-1] - if prev == nil { + prev, ok := s.indexToStorageID[len(layerBlobs)-1] + if !ok { return fmt.Errorf("Internal error: storageImageDestination.Commit(): previous layer %d hasn't been committed (lastLayer == nil)", len(layerBlobs)-1) } - lastLayer = *prev + lastLayer = prev } // If one of those blobs was a configuration blob, then we can try to dig out the date when the image From 9354d6872df635f25df9197a6e2996b0933aef26 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miloslav=20Trma=C4=8D?= Date: Thu, 8 Feb 2024 01:14:34 +0100 Subject: [PATCH 4/9] Fix a comment MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Should not change behavior. Signed-off-by: Miloslav Trmač --- storage/storage_dest.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/storage/storage_dest.go b/storage/storage_dest.go index 5e59ce4817..e70b249d9b 100644 --- a/storage/storage_dest.go +++ b/storage/storage_dest.go @@ -828,7 +828,7 @@ func (s *storageImageDestination) Commit(ctx context.Context, unparsedToplevel t } } var lastLayer string - if len(layerBlobs) > 0 { // Can happen when using caches + if len(layerBlobs) > 0 { // Zero-layer images rarely make sense, but it is technically possible, and may happen for non-image artifacts. prev, ok := s.indexToStorageID[len(layerBlobs)-1] if !ok { return fmt.Errorf("Internal error: storageImageDestination.Commit(): previous layer %d hasn't been committed (lastLayer == nil)", len(layerBlobs)-1) From c5fd4cb0deee2b04f6aa060ac3006237673b3ab5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miloslav=20Trma=C4=8D?= Date: Thu, 8 Feb 2024 01:19:27 +0100 Subject: [PATCH 5/9] Simplify setting indexToStorageID MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Now that we don't need pointer values, assign directly. This means we no longer confusingly use lastLayer _both_ for the parent layer and the currently-created layer. Signed-off-by: Miloslav Trmač --- storage/storage_dest.go | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/storage/storage_dest.go b/storage/storage_dest.go index e70b249d9b..1bb0b05861 100644 --- a/storage/storage_dest.go +++ b/storage/storage_dest.go @@ -632,8 +632,7 @@ func (s *storageImageDestination) commitLayer(index int, info addedLayerInfo, si } if layer, err2 := s.imageRef.transport.store.Layer(id); layer != nil && err2 == nil { // There's already a layer that should have the right contents, just reuse it. - lastLayer = layer.ID - s.indexToStorageID[index] = lastLayer + s.indexToStorageID[index] = layer.ID return false, nil } @@ -695,8 +694,7 @@ func (s *storageImageDestination) commitLayer(index int, info addedLayerInfo, si if err != nil && !errors.Is(err, storage.ErrDuplicateID) { return false, fmt.Errorf("failed to put layer from digest and labels: %w", err) } - lastLayer = layer.ID - s.indexToStorageID[index] = lastLayer + s.indexToStorageID[index] = layer.ID return false, nil } From a2018099ae166e0698d402351b1d397efe9e1b68 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miloslav=20Trma=C4=8D?= Date: Thu, 8 Feb 2024 01:20:26 +0100 Subject: [PATCH 6/9] Fail, instead of silently continuing, if a parent layer is not set yet MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit That should never happen, so make sure we notice. Signed-off-by: Miloslav Trmač --- storage/storage_dest.go | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/storage/storage_dest.go b/storage/storage_dest.go index 1bb0b05861..aab4b85dcd 100644 --- a/storage/storage_dest.go +++ b/storage/storage_dest.go @@ -588,7 +588,11 @@ func (s *storageImageDestination) commitLayer(index int, info addedLayerInfo, si // `s.indexToStorageID` can only be accessed by *one* goroutine at any // given time. Hence, we don't need to lock accesses. var lastLayer string - if prev, ok := s.indexToStorageID[index-1]; ok { + if index != 0 { + prev, ok := s.indexToStorageID[index-1] + if !ok { + return false, fmt.Errorf("Internal error: commitLayer called with previous layer %d not committed yet", index-1) + } lastLayer = prev } From 31f6eebf4d49af4433f06f8233473264c445ab3d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miloslav=20Trma=C4=8D?= Date: Thu, 8 Feb 2024 01:21:34 +0100 Subject: [PATCH 7/9] Rename lastLayer to parentLayer MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ... now that it has that exclusive semantics. Should not change behavior. Signed-off-by: Miloslav Trmač --- storage/storage_dest.go | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/storage/storage_dest.go b/storage/storage_dest.go index aab4b85dcd..ae73da4f55 100644 --- a/storage/storage_dest.go +++ b/storage/storage_dest.go @@ -587,18 +587,18 @@ func (s *storageImageDestination) commitLayer(index int, info addedLayerInfo, si // Start with an empty string or the previous layer ID. Note that // `s.indexToStorageID` can only be accessed by *one* goroutine at any // given time. Hence, we don't need to lock accesses. - var lastLayer string + var parentLayer string if index != 0 { prev, ok := s.indexToStorageID[index-1] if !ok { return false, fmt.Errorf("Internal error: commitLayer called with previous layer %d not committed yet", index-1) } - lastLayer = prev + parentLayer = prev } // Carry over the previous ID for empty non-base layers. if info.emptyLayer { - s.indexToStorageID[index] = lastLayer + s.indexToStorageID[index] = parentLayer return false, nil } @@ -631,8 +631,8 @@ func (s *storageImageDestination) commitLayer(index int, info addedLayerInfo, si } } id := diffIDOrTOCDigest.Hex() - if lastLayer != "" { - id = digest.Canonical.FromBytes([]byte(lastLayer + "+" + diffIDOrTOCDigest.Hex())).Hex() + if parentLayer != "" { + id = digest.Canonical.FromBytes([]byte(parentLayer + "+" + diffIDOrTOCDigest.Hex())).Hex() } if layer, err2 := s.imageRef.transport.store.Layer(id); layer != nil && err2 == nil { // There's already a layer that should have the right contents, just reuse it. @@ -668,7 +668,7 @@ func (s *storageImageDestination) commitLayer(index int, info addedLayerInfo, si return false, fmt.Errorf("index %d out of range for configOCI.RootFS.DiffIDs", index) } - layer, err := s.imageRef.transport.store.CreateLayer(id, lastLayer, nil, "", false, nil) + layer, err := s.imageRef.transport.store.CreateLayer(id, parentLayer, nil, "", false, nil) if err != nil { return false, err } @@ -694,7 +694,7 @@ func (s *storageImageDestination) commitLayer(index int, info addedLayerInfo, si al, ok := s.blobAdditionalLayer[info.digest] s.lock.Unlock() if ok { - layer, err := al.PutAs(id, lastLayer, nil) + layer, err := al.PutAs(id, parentLayer, nil) if err != nil && !errors.Is(err, storage.ErrDuplicateID) { return false, fmt.Errorf("failed to put layer from digest and labels: %w", err) } @@ -764,7 +764,7 @@ func (s *storageImageDestination) commitLayer(index int, info addedLayerInfo, si defer file.Close() // Build the new layer using the diff, regardless of where it came from. // TODO: This can take quite some time, and should ideally be cancellable using ctx.Done(). - layer, _, err := s.imageRef.transport.store.PutLayer(id, lastLayer, nil, "", false, &storage.LayerOptions{ + layer, _, err := s.imageRef.transport.store.PutLayer(id, parentLayer, nil, "", false, &storage.LayerOptions{ OriginalDigest: info.digest, UncompressedDigest: diffIDOrTOCDigest, }, file) From 2029a3b73b661f06fd57caa2d9064e333e48bd90 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miloslav=20Trma=C4=8D?= Date: Thu, 8 Feb 2024 01:43:33 +0100 Subject: [PATCH 8/9] Fix a comment documenting the locking rules MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We only care about concurrency within the scope of HasThreadSafePutBlob. Should not change behavior. Signed-off-by: Miloslav Trmač --- storage/storage_dest.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/storage/storage_dest.go b/storage/storage_dest.go index ae73da4f55..d8b993c9df 100644 --- a/storage/storage_dest.go +++ b/storage/storage_dest.go @@ -74,7 +74,8 @@ type storageImageDestination struct { // `queueOrCommit()` for further details on how the single-caller // guarantee is implemented. indexToStorageID map[int]string - // All accesses to below data are protected by `lock` which is made + // All accesses to below data are, during the concurrent TryReusingBlob/PutBlob/* calls + // (but not necessarily during the final Commit) protected by `lock` which is made // *explicit* in the code. uncompressedOrTocDigest map[digest.Digest]digest.Digest // Mapping from layer blobsums to their corresponding DiffIDs or TOC IDs. fileSizes map[digest.Digest]int64 // Mapping from layer blobsums to their sizes From e0e8045de84fe73709556053357f410372e90d13 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miloslav=20Trma=C4=8D?= Date: Thu, 8 Feb 2024 02:04:26 +0100 Subject: [PATCH 9/9] Use digest.*.FromString where possible MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ... instead of doing the same thing manually. Should not change behavior. Signed-off-by: Miloslav Trmač --- oci/layout/oci_src_test.go | 2 +- storage/storage_dest.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/oci/layout/oci_src_test.go b/oci/layout/oci_src_test.go index 3fe49a2072..08e7b57522 100644 --- a/oci/layout/oci_src_test.go +++ b/oci/layout/oci_src_test.go @@ -49,7 +49,7 @@ func TestGetBlobForRemoteLayers(t *testing.T) { imageSource := createImageSource(t, &types.SystemContext{}) defer imageSource.Close() layerInfo := types.BlobInfo{ - Digest: digest.FromBytes([]byte("Hello world")), + Digest: digest.FromString("Hello world"), Size: -1, URLs: []string{ "brokenurl", diff --git a/storage/storage_dest.go b/storage/storage_dest.go index d8b993c9df..88e492b743 100644 --- a/storage/storage_dest.go +++ b/storage/storage_dest.go @@ -633,7 +633,7 @@ func (s *storageImageDestination) commitLayer(index int, info addedLayerInfo, si } id := diffIDOrTOCDigest.Hex() if parentLayer != "" { - id = digest.Canonical.FromBytes([]byte(parentLayer + "+" + diffIDOrTOCDigest.Hex())).Hex() + id = digest.Canonical.FromString(parentLayer + "+" + diffIDOrTOCDigest.Hex()).Hex() } if layer, err2 := s.imageRef.transport.store.Layer(id); layer != nil && err2 == nil { // There's already a layer that should have the right contents, just reuse it.