Skip to content
This repository was archived by the owner on Mar 9, 2022. It is now read-only.

Commit f7fce60

Browse files
authored
Merge pull request #1609 from shahzzzam/add-annotation2
[release/1.4] Add manifest digest annotation for snapshotters
2 parents 500b242 + 1dc3b8a commit f7fce60

2 files changed

Lines changed: 84 additions & 16 deletions

File tree

pkg/server/image_pull.go

Lines changed: 34 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ import (
3131
"github.com/containerd/containerd"
3232
"github.com/containerd/containerd/errdefs"
3333
containerdimages "github.com/containerd/containerd/images"
34+
"github.com/containerd/containerd/labels"
3435
"github.com/containerd/containerd/log"
3536
distribution "github.com/containerd/containerd/reference/docker"
3637
"github.com/containerd/containerd/remotes/docker"
@@ -455,18 +456,21 @@ const (
455456
// targetRefLabel is a label which contains image reference and will be passed
456457
// to snapshotters.
457458
targetRefLabel = "containerd.io/snapshot/cri.image-ref"
458-
// targetDigestLabel is a label which contains layer digest and will be passed
459+
// targetManifestDigestLabel is a label which contains manifest digest and will be passed
459460
// to snapshotters.
460-
targetDigestLabel = "containerd.io/snapshot/cri.layer-digest"
461+
targetManifestDigestLabel = "containerd.io/snapshot/cri.manifest-digest"
462+
// targetLayerDigestLabel is a label which contains layer digest and will be passed
463+
// to snapshotters.
464+
targetLayerDigestLabel = "containerd.io/snapshot/cri.layer-digest"
461465
// targetImageLayersLabel is a label which contains layer digests contained in
462466
// the target image and will be passed to snapshotters for preparing layers in
463-
// parallel.
467+
// parallel. Skipping some layers is allowed and only affects performance.
464468
targetImageLayersLabel = "containerd.io/snapshot/cri.image-layers"
465469
)
466470

467471
// appendInfoHandlerWrapper makes a handler which appends some basic information
468-
// of images to each layer descriptor as annotations during unpack. These
469-
// annotations will be passed to snapshotters as labels. These labels will be
472+
// of images like digests for manifest and their child layers as annotations during unpack.
473+
// These annotations will be passed to snapshotters as labels. These labels will be
470474
// used mainly by stargz-based snapshotters for querying image contents from the
471475
// registry.
472476
func appendInfoHandlerWrapper(ref string) func(f containerdimages.Handler) containerdimages.Handler {
@@ -478,28 +482,42 @@ func appendInfoHandlerWrapper(ref string) func(f containerdimages.Handler) conta
478482
}
479483
switch desc.MediaType {
480484
case imagespec.MediaTypeImageManifest, containerdimages.MediaTypeDockerSchema2Manifest:
481-
var layers string
482-
for _, c := range children {
483-
if containerdimages.IsLayerType(c.MediaType) {
484-
layers += fmt.Sprintf("%s,", c.Digest.String())
485-
}
486-
}
487-
if len(layers) >= 1 {
488-
layers = layers[:len(layers)-1]
489-
}
490485
for i := range children {
491486
c := &children[i]
492487
if containerdimages.IsLayerType(c.MediaType) {
493488
if c.Annotations == nil {
494489
c.Annotations = make(map[string]string)
495490
}
496491
c.Annotations[targetRefLabel] = ref
497-
c.Annotations[targetDigestLabel] = c.Digest.String()
498-
c.Annotations[targetImageLayersLabel] = layers
492+
c.Annotations[targetLayerDigestLabel] = c.Digest.String()
493+
c.Annotations[targetImageLayersLabel] = getLayers(ctx, targetImageLayersLabel, children[i:], labels.Validate)
494+
c.Annotations[targetManifestDigestLabel] = desc.Digest.String()
499495
}
500496
}
501497
}
502498
return children, nil
503499
})
504500
}
505501
}
502+
503+
// getLayers returns comma-separated digests based on the passed list of
504+
// descriptors. The returned list contains as many digests as possible as well
505+
// as meets the label validation.
506+
func getLayers(ctx context.Context, key string, descs []imagespec.Descriptor, validate func(k, v string) error) (layers string) {
507+
var item string
508+
for _, l := range descs {
509+
if containerdimages.IsLayerType(l.MediaType) {
510+
item = l.Digest.String()
511+
if layers != "" {
512+
item = "," + item
513+
}
514+
// This avoids the label hits the size limitation.
515+
if err := validate(key, layers+item); err != nil {
516+
log.G(ctx).WithError(err).WithField("label", key).Debugf("%q is omitted in the layers list", l.Digest.String())
517+
break
518+
}
519+
layers += item
520+
}
521+
}
522+
return
523+
}

pkg/server/image_pull_test.go

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,14 @@
1717
package server
1818

1919
import (
20+
"context"
2021
"encoding/base64"
22+
"fmt"
23+
"strings"
2124
"testing"
2225

26+
digest "github.com/opencontainers/go-digest"
27+
imagespec "github.com/opencontainers/image-spec/specs-go/v1"
2328
"github.com/stretchr/testify/assert"
2429
runtime "k8s.io/cri-api/pkg/apis/runtime/v1alpha2"
2530

@@ -327,3 +332,48 @@ func TestEncryptedImagePullOpts(t *testing.T) {
327332
assert.Equal(t, test.expectedOpts, got)
328333
}
329334
}
335+
336+
func TestImageLayersLabel(t *testing.T) {
337+
sampleKey := "sampleKey"
338+
sampleDigest, err := digest.Parse("sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa")
339+
assert.NoError(t, err)
340+
sampleMaxSize := 300
341+
sampleValidate := func(k, v string) error {
342+
if (len(k) + len(v)) > sampleMaxSize {
343+
return fmt.Errorf("invalid: %q: %q", k, v)
344+
}
345+
return nil
346+
}
347+
348+
tests := []struct {
349+
name string
350+
layersNum int
351+
wantNum int
352+
}{
353+
{
354+
name: "valid number of layers",
355+
layersNum: 2,
356+
wantNum: 2,
357+
},
358+
{
359+
name: "many layers",
360+
layersNum: 5, // hits sampleMaxSize (300 chars).
361+
wantNum: 4, // layers should be ommitted for avoiding invalid label.
362+
},
363+
}
364+
365+
for _, tt := range tests {
366+
t.Run(tt.name, func(t *testing.T) {
367+
var sampleLayers []imagespec.Descriptor
368+
for i := 0; i < tt.layersNum; i++ {
369+
sampleLayers = append(sampleLayers, imagespec.Descriptor{
370+
MediaType: imagespec.MediaTypeImageLayerGzip,
371+
Digest: sampleDigest,
372+
})
373+
}
374+
gotS := getLayers(context.Background(), sampleKey, sampleLayers, sampleValidate)
375+
got := len(strings.Split(gotS, ","))
376+
assert.Equal(t, tt.wantNum, got)
377+
})
378+
}
379+
}

0 commit comments

Comments
 (0)