From 782a369f92e02ab47a54bfa25e02e29b6032aef0 Mon Sep 17 00:00:00 2001 From: Bjorn Neergaard Date: Tue, 21 Feb 2023 08:32:00 -0700 Subject: [PATCH] c8d/pull: Add CRI-compatible annotation of pulled content MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Paweł Gronowski Signed-off-by: Bjorn Neergaard --- daemon/containerd/image_pull.go | 6 ++ .../pkg/snapshotters/annotations.go | 97 +++++++++++++++++++ vendor/modules.txt | 1 + 3 files changed, 104 insertions(+) create mode 100644 vendor/github.com/containerd/containerd/pkg/snapshotters/annotations.go diff --git a/daemon/containerd/image_pull.go b/daemon/containerd/image_pull.go index 99352457a9..79bf12f249 100644 --- a/daemon/containerd/image_pull.go +++ b/daemon/containerd/image_pull.go @@ -7,6 +7,7 @@ import ( "github.com/containerd/containerd" "github.com/containerd/containerd/images" + "github.com/containerd/containerd/pkg/snapshotters" "github.com/containerd/containerd/platforms" "github.com/docker/distribution" "github.com/docker/distribution/reference" @@ -63,6 +64,11 @@ func (i *ImageService) PullImage(ctx context.Context, image, tagOrDigest string, opts = append(opts, containerd.WithPullUnpack) opts = append(opts, containerd.WithPullSnapshotter(i.snapshotter)) + // AppendInfoHandlerWrapper will annotate the image with basic information like manifest and layer digests as labels; + // this information is used to enable remote snapshotters like nydus and stargz to query a registry. + infoHandler := snapshotters.AppendInfoHandlerWrapper(ref.String()) + opts = append(opts, containerd.WithImageHandlerWrapper(infoHandler)) + _, err = i.client.Pull(ctx, ref.String(), opts...) return err } diff --git a/vendor/github.com/containerd/containerd/pkg/snapshotters/annotations.go b/vendor/github.com/containerd/containerd/pkg/snapshotters/annotations.go new file mode 100644 index 0000000000..c7ad97c155 --- /dev/null +++ b/vendor/github.com/containerd/containerd/pkg/snapshotters/annotations.go @@ -0,0 +1,97 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package snapshotters + +import ( + "context" + + "github.com/containerd/containerd/images" + "github.com/containerd/containerd/labels" + "github.com/containerd/containerd/log" + ocispec "github.com/opencontainers/image-spec/specs-go/v1" +) + +// NOTE: The following labels contain "cri" prefix but they are not specific to CRI and +// can be used by non-CRI clients as well for enabling remote snapshotters. We need to +// retain that string for keeping compatibility with snapshotter implementations. +const ( + // TargetRefLabel is a label which contains image reference and will be passed + // to snapshotters. + TargetRefLabel = "containerd.io/snapshot/cri.image-ref" + // TargetManifestDigestLabel is a label which contains manifest digest and will be passed + // to snapshotters. + TargetManifestDigestLabel = "containerd.io/snapshot/cri.manifest-digest" + // TargetLayerDigestLabel is a label which contains layer digest and will be passed + // to snapshotters. + TargetLayerDigestLabel = "containerd.io/snapshot/cri.layer-digest" + // TargetImageLayersLabel is a label which contains layer digests contained in + // the target image and will be passed to snapshotters for preparing layers in + // parallel. Skipping some layers is allowed and only affects performance. + TargetImageLayersLabel = "containerd.io/snapshot/cri.image-layers" +) + +// AppendInfoHandlerWrapper makes a handler which appends some basic information +// of images like digests for manifest and their child layers as annotations during unpack. +// These annotations will be passed to snapshotters as labels. These labels will be +// used mainly by remote snapshotters for querying image contents from the remote location. +func AppendInfoHandlerWrapper(ref string) func(f images.Handler) images.Handler { + return func(f images.Handler) images.Handler { + return images.HandlerFunc(func(ctx context.Context, desc ocispec.Descriptor) ([]ocispec.Descriptor, error) { + children, err := f.Handle(ctx, desc) + if err != nil { + return nil, err + } + switch desc.MediaType { + case ocispec.MediaTypeImageManifest, images.MediaTypeDockerSchema2Manifest: + for i := range children { + c := &children[i] + if images.IsLayerType(c.MediaType) { + if c.Annotations == nil { + c.Annotations = make(map[string]string) + } + c.Annotations[TargetRefLabel] = ref + c.Annotations[TargetLayerDigestLabel] = c.Digest.String() + c.Annotations[TargetImageLayersLabel] = getLayers(ctx, TargetImageLayersLabel, children[i:], labels.Validate) + c.Annotations[TargetManifestDigestLabel] = desc.Digest.String() + } + } + } + return children, nil + }) + } +} + +// getLayers returns comma-separated digests based on the passed list of +// descriptors. The returned list contains as many digests as possible as well +// as meets the label validation. +func getLayers(ctx context.Context, key string, descs []ocispec.Descriptor, validate func(k, v string) error) (layers string) { + for _, l := range descs { + if images.IsLayerType(l.MediaType) { + item := l.Digest.String() + if layers != "" { + item = "," + item + } + // This avoids the label hits the size limitation. + if err := validate(key, layers+item); err != nil { + log.G(ctx).WithError(err).WithField("label", key).WithField("digest", l.Digest.String()).Debug("omitting digest in the layers list") + break + } + layers += item + } + } + return +} diff --git a/vendor/modules.txt b/vendor/modules.txt index c38b5efb5b..cda9dc3de1 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -261,6 +261,7 @@ github.com/containerd/containerd/pkg/dialer github.com/containerd/containerd/pkg/kmutex github.com/containerd/containerd/pkg/seccomp github.com/containerd/containerd/pkg/shutdown +github.com/containerd/containerd/pkg/snapshotters github.com/containerd/containerd/pkg/ttrpcutil github.com/containerd/containerd/pkg/userns github.com/containerd/containerd/platforms