diff --git a/storage/storage_dest.go b/storage/storage_dest.go index f494d7d4b..46760ef2b 100644 --- a/storage/storage_dest.go +++ b/storage/storage_dest.go @@ -370,23 +370,22 @@ func (s *storageImageDestination) PutBlobPartial(ctx context.Context, chunkAcces if out.UncompressedDigest != "" { s.lockProtected.indexToDiffID[options.LayerIndex] = out.UncompressedDigest if out.TOCDigest != "" { + s.lockProtected.indexToTOCDigest[options.LayerIndex] = out.TOCDigest options.Cache.RecordTOCUncompressedPair(out.TOCDigest, out.UncompressedDigest) } - // Don’t set indexToTOCDigest on this path: - // - Using UncompressedDigest allows image reuse with non-partially-pulled layers, so we want to set indexToDiffID. - // - If UncompressedDigest has been computed, that means the layer was read completely, and the TOC has been created from scratch. - // That TOC is quite unlikely to match any other TOC value. - // The computation of UncompressedDigest means the whole layer has been consumed; while doing that, chunked.GetDiffer is + // If the whole layer has been consumed, chunked.GetDiffer is // responsible for ensuring blobDigest has been validated. - if out.CompressedDigest != blobDigest { - return private.UploadedBlob{}, fmt.Errorf("internal error: PrepareStagedLayer returned CompressedDigest %q not matching expected %q", - out.CompressedDigest, blobDigest) - } - // So, record also information about blobDigest, that might benefit reuse. - // We trust PrepareStagedLayer to validate or create both values correctly. - s.lockProtected.blobDiffIDs[blobDigest] = out.UncompressedDigest - options.Cache.RecordDigestUncompressedPair(out.CompressedDigest, out.UncompressedDigest) + if out.CompressedDigest != "" { + if out.CompressedDigest != blobDigest { + return private.UploadedBlob{}, fmt.Errorf("internal error: PrepareStagedLayer returned CompressedDigest %q not matching expected %q", + out.CompressedDigest, blobDigest) + } + // So, record also information about blobDigest, that might benefit reuse. + // We trust PrepareStagedLayer to validate or create both values correctly. + s.lockProtected.blobDiffIDs[blobDigest] = out.UncompressedDigest + options.Cache.RecordDigestUncompressedPair(out.CompressedDigest, out.UncompressedDigest) + } } else { // Use diffID for layer identity if it is known. if uncompressedDigest := options.Cache.UncompressedDigestForTOC(out.TOCDigest); uncompressedDigest != "" { @@ -936,12 +935,27 @@ func (s *storageImageDestination) createNewLayer(index int, layerDigest digest.D return nil, nil } + // FIXME: Should we insist on UncompressedDigest being always set, and hard fail otherwise?? untrustedUncompressedDigest = d // While the contents of the digest are untrusted, make sure at least the _format_ is valid, // because we are going to write it to durable storage in expectedLayerDiffIDFlag . if err := untrustedUncompressedDigest.Validate(); err != nil { return nil, err } + } else { + // FIXME: Clean up. Maybe the generic code can provide us the config earlier? + // FIXME: Always enforce this for all layers??! + d, err := s.untrustedLayerDiffID(index) + if err != nil { + return nil, err + } + if d == "" { + logrus.Debugf("Skipping commit for layer %q, manifest not yet available", newLayerID) + return nil, nil + } + if diffOutput.UncompressedDigest != d { + return nil, fmt.Errorf("uncompressed digest inconsistency for layer %d: config %q vs. computed %q", index, d, diffOutput.UncompressedDigest) + } } flags := make(map[string]interface{})