Skip to content

Commit 3d62be8

Browse files
committed
Update SOCI index manifest V2 db references
When we convert images to SOCI index manifest v2, we first create SOCI indexes, then add the annotations to the image manifests. In the process of creating the SOCI indexes, we create an artifacts DB reference to the SOCI index using the original manifest and image ids. This change goes back after everything is done and updates the artifacts DB so the index is associated with the new manifest and image. Signed-off-by: Kern Walster <walster@amazon.com>
1 parent e1958bc commit 3d62be8

File tree

3 files changed

+67
-22
lines changed

3 files changed

+67
-22
lines changed

integration/pull_modes_test.go

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -34,17 +34,20 @@ var (
3434

3535
func createAndPushV2Index(t *testing.T, sh *dockershell.Shell, srcInfo imageInfo, dstInfo imageInfo) string {
3636
sh.X("nerdctl", "pull", "--all-platforms", srcInfo.ref)
37-
sh.X("soci", "convert", "--min-layer-size", "0", srcInfo.ref, dstInfo.ref)
37+
sh.X("soci", "convert", "--all-platforms", "--min-layer-size", "0", srcInfo.ref, dstInfo.ref)
3838
sh.X("nerdctl", "push", "--all-platforms", dstInfo.ref)
3939

4040
indexDigest, err := sh.OLog("soci",
4141
"index", "list",
42-
"-q", "--ref", srcInfo.ref,
42+
"-q", "--ref", dstInfo.ref,
4343
"--platform", platforms.Format(platforms.DefaultSpec()),
4444
)
4545
if err != nil {
4646
t.Fatal(err)
4747
}
48+
if len(indexDigest) == 0 {
49+
t.Fatal("index digest is empty")
50+
}
4851

4952
return strings.Trim(string(indexDigest), "\n")
5053
}
@@ -264,7 +267,7 @@ func testDanglingV2Annotation(t *testing.T, imgName string) {
264267
dstInfo := regConfig.mirror(imgName)
265268

266269
sh.X("nerdctl", "pull", "--all-platforms", srcInfo.ref)
267-
sh.X("soci", "convert", "--min-layer-size", "0", srcInfo.ref, dstInfo.ref)
270+
sh.X("soci", "convert", "--all-platforms", "--min-layer-size", "0", srcInfo.ref, dstInfo.ref)
268271

269272
manifest, err := getManifestDigest(sh, dstInfo.ref, platforms.DefaultSpec())
270273
if err != nil {
@@ -273,14 +276,17 @@ func testDanglingV2Annotation(t *testing.T, imgName string) {
273276

274277
v2IndexDigest, err := sh.OLog("soci",
275278
"index", "list",
276-
"-q", "--ref", srcInfo.ref,
279+
"-q", "--ref", dstInfo.ref,
277280
"--platform", platforms.Format(platforms.DefaultSpec()),
278281
)
279282
if err != nil {
280283
t.Fatal(err)
281284
}
285+
if len(v2IndexDigest) == 0 {
286+
t.Fatal("index digest is empty")
287+
}
282288

283-
// Nither nerdctl nor ctr expose a way to "elevate" a platform-specific
289+
// Neither nerdctl nor ctr expose a way to "elevate" a platform-specific
284290
// manifest to a top level image directly, so we do a little registry dance:
285291
// push image:tag
286292
// pull image@sha256:... (the specific manifest we want to elevate)

soci/artifacts.go

Lines changed: 32 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -323,24 +323,22 @@ func (db *ArtifactsDb) addNewArtifacts(ctx context.Context, blobStorePath string
323323

324324
// GetArtifactEntry loads a single ArtifactEntry from the ArtifactsDB by digest
325325
func (db *ArtifactsDb) GetArtifactEntry(digest string) (*ArtifactEntry, error) {
326-
entry := ArtifactEntry{}
326+
var entry *ArtifactEntry
327327
err := db.db.View(func(tx *bolt.Tx) error {
328-
bucket, err := getArtifactsBucket(tx)
329-
if err != nil {
330-
return err
331-
}
332-
e, err := getArtifactEntryByDigest(bucket, digest)
333-
if err != nil {
334-
return err
335-
}
336-
entry = *e
337-
return nil
328+
var err error
329+
entry, err = db.getArtifactEntry(tx, digest)
330+
return err
338331
})
339332

333+
return entry, err
334+
}
335+
336+
func (db *ArtifactsDb) getArtifactEntry(tx *bolt.Tx, digest string) (*ArtifactEntry, error) {
337+
bucket, err := getArtifactsBucket(tx)
340338
if err != nil {
341339
return nil, err
342340
}
343-
return &entry, nil
341+
return getArtifactEntryByDigest(bucket, digest)
344342
}
345343

346344
// GetArtifactType gets Type of an ArtifactEntry from the ArtifactsDB by digest
@@ -411,15 +409,32 @@ func (db *ArtifactsDb) WriteArtifactEntry(entry *ArtifactEntry) error {
411409
if entry == nil {
412410
return fmt.Errorf("no entry to write")
413411
}
414-
err := db.db.Update(func(tx *bolt.Tx) error {
415-
bucket, err := tx.CreateBucketIfNotExists(bucketKeySociArtifacts)
412+
return db.db.Update(func(tx *bolt.Tx) error {
413+
return db.writeArtifactEntry(tx, entry)
414+
})
415+
}
416+
417+
func (db *ArtifactsDb) writeArtifactEntry(tx *bolt.Tx, entry *ArtifactEntry) error {
418+
bucket, err := tx.CreateBucketIfNotExists(bucketKeySociArtifacts)
419+
if err != nil {
420+
return err
421+
}
422+
return putArtifactEntry(bucket, entry)
423+
}
424+
425+
// updateSociV2ArtifactReference updates the image and manifest digests associated with the SOCI index digest in the artifacts db.
426+
// the indexDigest is the SOCI index to updated, the manifestDigest is the specific image manifest that the SOCI index is bound to,
427+
// and the imageDigest is the target of the image (this is the same as the manifestDigest for single platform images, but different for mult-platform)
428+
func (db *ArtifactsDb) updateSociV2ArtifactReference(indexDigest string, manifestDigest string, imageDigest string) error {
429+
return db.db.Update(func(tx *bolt.Tx) error {
430+
ae, err := db.getArtifactEntry(tx, indexDigest)
416431
if err != nil {
417432
return err
418433
}
419-
err = putArtifactEntry(bucket, entry)
420-
return err
434+
ae.ImageDigest = imageDigest
435+
ae.OriginalDigest = manifestDigest
436+
return db.writeArtifactEntry(tx, ae)
421437
})
422-
return err
423438
}
424439

425440
func getArtifactsBucket(tx *bolt.Tx) (*bolt.Bucket, error) {

soci/soci_convert.go

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,12 @@ func (b *IndexBuilder) Convert(ctx context.Context, img images.Image, opts ...Co
146146
return nil, err
147147
}
148148

149+
// Update artifacts DB references to the new image/index digests
150+
err = b.updateSociV2ArtifactReferences(&ociIndex, ociIndexDesc.Digest.String())
151+
if err != nil {
152+
return nil, err
153+
}
154+
149155
// Apply GC Labels
150156
for i, desc := range ociIndex.Manifests {
151157
err := store.LabelGCRefContent(ctx, b.blobStore, ociIndexDesc, fmt.Sprintf("m.%d", i), desc.Digest.String())
@@ -352,3 +358,21 @@ func (b *IndexBuilder) pushOCIObject(ctx context.Context, obj any) (ocispec.Desc
352358
}
353359
return desc, nil
354360
}
361+
362+
// updateSociV2ArtifactReferences adjusts the artifacts DB so that the SOCI indexes contained in the OCI index
363+
// reference the correct digests.
364+
//
365+
// When we create the SOCI index manifest v2, we add it to the artifacts DB with the original image manifest digest
366+
// and image digest. When we add the annotations, we change the manifest digest and create a new image with a new
367+
// digest. This function goes back and fixes the artifacts DB so that the index is associated with the new manifest and image digests.
368+
func (b *IndexBuilder) updateSociV2ArtifactReferences(index *ocispec.Index, indexDigest string) error {
369+
for _, manifestDesc := range index.Manifests {
370+
if manifestDesc.ArtifactType == SociIndexArtifactTypeV2 {
371+
err := b.config.artifactsDb.updateSociV2ArtifactReference(manifestDesc.Digest.String(), manifestDesc.Annotations[IndexAnnotationImageManifestDigest], indexDigest)
372+
if err != nil {
373+
return err
374+
}
375+
}
376+
}
377+
return nil
378+
}

0 commit comments

Comments
 (0)