From b9af453f0ccc68d9ae37202712f1a9726d9cf5de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Gronowski?= Date: Fri, 15 Dec 2023 17:34:15 +0100 Subject: [PATCH] export: Copy distribution source labels to manifest annotations MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Persist manifest/indexes distribution source labels as annotations in the index.json. This could allow the importer to fetch the missing blobs from the external repository. These can't really be persisted directly in blob descriptors because that would alter the digests. Signed-off-by: Paweł Gronowski --- images/archive/exporter.go | 35 +++++++++++++++++++++++++++++++++-- 1 file changed, 33 insertions(+), 2 deletions(-) diff --git a/images/archive/exporter.go b/images/archive/exporter.go index 87fac79e8..f343912a4 100644 --- a/images/archive/exporter.go +++ b/images/archive/exporter.go @@ -24,11 +24,14 @@ import ( "io" "path" "sort" + "strings" "github.com/containerd/containerd/v2/content" "github.com/containerd/containerd/v2/errdefs" "github.com/containerd/containerd/v2/images" + "github.com/containerd/containerd/v2/labels" "github.com/containerd/containerd/v2/platforms" + "github.com/containerd/log" digest "github.com/opencontainers/go-digest" ocispecs "github.com/opencontainers/image-spec/specs-go" ocispec "github.com/opencontainers/image-spec/specs-go/v1" @@ -191,6 +194,23 @@ func addNameAnnotation(name string, base map[string]string) map[string]string { return annotations } +func copySourceLabels(ctx context.Context, infoProvider content.InfoProvider, desc ocispec.Descriptor) (ocispec.Descriptor, error) { + info, err := infoProvider.Info(ctx, desc.Digest) + if err != nil { + return desc, err + } + for k, v := range info.Labels { + if strings.HasPrefix(k, labels.LabelDistributionSource) { + if desc.Annotations == nil { + desc.Annotations = map[string]string{k: v} + } else { + desc.Annotations[k] = v + } + } + } + return desc, nil +} + // ContentProvider provides both content and info about content type ContentProvider interface { content.Provider @@ -208,13 +228,22 @@ func Export(ctx context.Context, store ContentProvider, writer io.Writer, opts . records := []tarRecord{ ociLayoutFile(""), - ociIndexRecord(eo.manifests), + } + + manifests := make([]ocispec.Descriptor, 0, len(eo.manifests)) + for _, desc := range eo.manifests { + d, err := copySourceLabels(ctx, store, desc) + if err != nil { + log.G(ctx).WithError(err).WithField("desc", desc).Warn("failed to copy distribution.source labels") + continue + } + manifests = append(manifests, d) } algorithms := map[string]struct{}{} dManifests := map[digest.Digest]*exportManifest{} resolvedIndex := map[digest.Digest]digest.Digest{} - for _, desc := range eo.manifests { + for _, desc := range manifests { if images.IsManifestType(desc.MediaType) { mt, ok := dManifests[desc.Digest] if !ok { @@ -304,6 +333,8 @@ func Export(ctx context.Context, store ContentProvider, writer io.Writer, opts . } } + records = append(records, ociIndexRecord(manifests)) + if !eo.skipDockerManifest && len(dManifests) > 0 { tr, err := manifestsRecord(ctx, store, dManifests) if err != nil {