fix merging indexes in pkg manifest command

Signed-off-by: Avi Deitcher <avi@deitcher.net>
This commit is contained in:
Avi Deitcher 2023-11-22 11:59:56 +02:00
parent 4c14831d6b
commit 4e75efc8aa
2 changed files with 53 additions and 6 deletions

View File

@ -94,6 +94,11 @@ func PushManifest(img string, options ...remote.Option) (hash string, length int
if err != nil { if err != nil {
return hash, length, fmt.Errorf("getting index digest: %w", err) 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) log.Debugf("pushing manifest list for %s -> %#v", img, index)
err = remote.WriteIndex(baseRef, index, options...) err = remote.WriteIndex(baseRef, index, options...)
if err != nil { if err != nil {

View File

@ -4,6 +4,7 @@ import (
"fmt" "fmt"
v1 "github.com/google/go-containerregistry/pkg/v1" v1 "github.com/google/go-containerregistry/pkg/v1"
"github.com/google/go-containerregistry/pkg/v1/mutate"
) )
const ( const (
@ -14,12 +15,15 @@ const (
AnnotationSPDXDoc = "https://spdx.dev/Document" AnnotationSPDXDoc = "https://spdx.dev/Document"
) )
// AppendIndex appends the elements of secondary ImageIndex into primary ImageIndex, // AppendIndex creates a new ImageIndex composed of the merge of the elements of secondary ImageIndex
// returning the updated primary ImageIndex. // and primary ImageIndex.
// In the case of conflicts, the primary ImageIndex wins. // 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. // 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 // 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. // 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) { func AppendIndex(primary, secondary v1.ImageIndex) (v1.ImageIndex, error) {
primaryManifest, err := primary.IndexManifest() primaryManifest, err := primary.IndexManifest()
if err != nil { 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? // 2. attestation - after all platforms, does it point to something in the updated index?
// If not, remove // 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 // make a map of all the digests already in the index, so we can know what is there
var ( var (
manifestMap = map[v1.Hash]bool{} manifestMap = map[v1.Hash]bool{}
platformMap = map[string]bool{} platformMap = map[string]bool{}
adds []mutate.IndexAddendum
) )
for _, m := range primaryManifest.Manifests { for _, m := range primaryManifest.Manifests {
if m.Platform == nil || m.Platform.Architecture == "" { 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 // we already have this one, so we can skip it
continue 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 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 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 // we assume the ones in the local index are valid because they would have been generated now
for _, m := range secondaryManifest.Manifests { 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 continue
} }
// if we already have this one, we are good // 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 { if _, ok := manifestMap[dig]; !ok {
continue 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 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
} }