From 4e75efc8aa9a5cb76d6a8613a796ebdd3162940f Mon Sep 17 00:00:00 2001 From: Avi Deitcher Date: Wed, 22 Nov 2023 11:59:56 +0200 Subject: [PATCH] fix merging indexes in pkg manifest command Signed-off-by: Avi Deitcher --- src/cmd/linuxkit/registry/manifest.go | 5 +++ src/cmd/linuxkit/util/index.go | 54 ++++++++++++++++++++++++--- 2 files changed, 53 insertions(+), 6 deletions(-) diff --git a/src/cmd/linuxkit/registry/manifest.go b/src/cmd/linuxkit/registry/manifest.go index c9c838a1a..1562ce34c 100644 --- a/src/cmd/linuxkit/registry/manifest.go +++ b/src/cmd/linuxkit/registry/manifest.go @@ -94,6 +94,11 @@ func PushManifest(img string, options ...remote.Option) (hash string, length int if err != nil { return hash, length, fmt.Errorf("getting index digest: %w", err) } + // if it is unchanged, do nothing + if desc != nil && desc.Digest == dig { + log.Debugf("not pushing manifest list for %s, unchanged", img) + return dig.String(), size, nil + } log.Debugf("pushing manifest list for %s -> %#v", img, index) err = remote.WriteIndex(baseRef, index, options...) if err != nil { diff --git a/src/cmd/linuxkit/util/index.go b/src/cmd/linuxkit/util/index.go index 02e16bf77..8a639e49f 100644 --- a/src/cmd/linuxkit/util/index.go +++ b/src/cmd/linuxkit/util/index.go @@ -4,6 +4,7 @@ import ( "fmt" v1 "github.com/google/go-containerregistry/pkg/v1" + "github.com/google/go-containerregistry/pkg/v1/mutate" ) const ( @@ -14,12 +15,15 @@ const ( AnnotationSPDXDoc = "https://spdx.dev/Document" ) -// AppendIndex appends the elements of secondary ImageIndex into primary ImageIndex, -// returning the updated primary ImageIndex. +// AppendIndex creates a new ImageIndex composed of the merge of the elements of secondary ImageIndex +// and primary ImageIndex. // In the case of conflicts, the primary ImageIndex wins. // For example, if both have a manifest for a specific platform, then use the one from primary. // The append is aware of the buildkit-style attestations, and will keep any attestations that point to a valid // manifest in the list, discarding any that do not. +// If either of the two ImageIndexes is nil, the other is returned. +// If the secondary ImageIndex is a precise superset of primary, +// then the returned new ImageIndex is an identical copy of the secondary ImageIndex. func AppendIndex(primary, secondary v1.ImageIndex) (v1.ImageIndex, error) { primaryManifest, err := primary.IndexManifest() if err != nil { @@ -35,10 +39,14 @@ func AppendIndex(primary, secondary v1.ImageIndex) (v1.ImageIndex, error) { // 2. attestation - after all platforms, does it point to something in the updated index? // If not, remove + if indexSuperset(primaryManifest, secondaryManifest) { + return secondary, nil + } // make a map of all the digests already in the index, so we can know what is there var ( manifestMap = map[v1.Hash]bool{} platformMap = map[string]bool{} + adds []mutate.IndexAddendum ) for _, m := range primaryManifest.Manifests { if m.Platform == nil || m.Platform.Architecture == "" { @@ -63,7 +71,15 @@ func AppendIndex(primary, secondary v1.ImageIndex) (v1.ImageIndex, error) { // we already have this one, so we can skip it continue } - primaryManifest.Manifests = append(primaryManifest.Manifests, m) + img, err := secondary.Image(m.Digest) + if err != nil { + return nil, fmt.Errorf("could not get image %s: %v", m.Digest, err) + } + adds = append(adds, mutate.IndexAddendum{ + Add: img, + Descriptor: m, + }) + // want to add manifest "m" manifestMap[m.Digest] = true } @@ -73,7 +89,7 @@ func AppendIndex(primary, secondary v1.ImageIndex) (v1.ImageIndex, error) { // we either add them to the local index, or remove them if they are no longer valid // we assume the ones in the local index are valid because they would have been generated now for _, m := range secondaryManifest.Manifests { - if m.Platform == nil || m.Platform.Architecture != "unknown" || m.Platform.OS == "unknown" || m.Annotations == nil || m.Annotations[AnnotationDockerReferenceDigest] == "" { + if m.Platform == nil || m.Platform.Architecture != "unknown" || m.Platform.OS != "unknown" || m.Annotations == nil || m.Annotations[AnnotationDockerReferenceDigest] == "" { continue } // if we already have this one, we are good @@ -90,8 +106,34 @@ func AppendIndex(primary, secondary v1.ImageIndex) (v1.ImageIndex, error) { if _, ok := manifestMap[dig]; !ok { continue } - primaryManifest.Manifests = append(primaryManifest.Manifests, m) + img, err := secondary.Image(m.Digest) + if err != nil { + return nil, fmt.Errorf("could not get image %s: %v", m.Digest, err) + } + adds = append(adds, mutate.IndexAddendum{ + Add: img, + Descriptor: m, + }) + // want to add manifest "m" manifestMap[m.Digest] = true } - return primary, nil + ret := mutate.AppendManifests(primary, adds...) + + return ret, nil +} + +func indexSuperset(inner, outer *v1.IndexManifest) bool { + var manifestMap = map[v1.Hash]bool{} + if len(inner.Manifests) > len(outer.Manifests) { + return false + } + for _, m := range outer.Manifests { + manifestMap[m.Digest] = true + } + for _, m := range inner.Manifests { + if _, ok := manifestMap[m.Digest]; !ok { + return false + } + } + return true }