versionsapi: merging of ImageInfo

This commit is contained in:
Malte Poll 2023-05-23 11:13:31 +02:00 committed by Malte Poll
parent d0e53cbb59
commit 874c4b76cf
2 changed files with 223 additions and 0 deletions

View File

@ -11,6 +11,7 @@ import (
"fmt"
"net/url"
"path"
"sort"
"github.com/edgelesssys/constellation/v2/internal/constants"
"golang.org/x/mod/semver"
@ -96,3 +97,45 @@ func (i ImageInfo) Validate() error {
return retErr
}
// MergeImageInfos combines the image info entries from multiple sources into a single
// image info object.
func MergeImageInfos(infos ...ImageInfo) (ImageInfo, error) {
if len(infos) == 0 {
return ImageInfo{}, errors.New("no image info objects specified")
}
if len(infos) == 1 {
return infos[0], nil
}
out := ImageInfo{
Ref: infos[0].Ref,
Stream: infos[0].Stream,
Version: infos[0].Version,
List: []ImageInfoEntry{},
}
for _, info := range infos {
if info.Ref != out.Ref {
return ImageInfo{}, errors.New("image info objects have different refs")
}
if info.Stream != out.Stream {
return ImageInfo{}, errors.New("image info objects have different streams")
}
if info.Version != out.Version {
return ImageInfo{}, errors.New("image info objects have different versions")
}
out.List = append(out.List, info.List...)
}
sort.SliceStable(out.List, func(i, j int) bool {
if out.List[i].CSP != out.List[j].CSP {
return out.List[i].CSP < out.List[j].CSP
}
if out.List[i].AttestationVariant != out.List[j].AttestationVariant {
return out.List[i].AttestationVariant < out.List[j].AttestationVariant
}
if out.List[i].Region != out.List[j].Region {
return out.List[i].Region < out.List[j].Region
}
return out.List[i].Reference < out.List[j].Reference
})
return out, nil
}

View File

@ -281,3 +281,183 @@ func TestImageInfoValidateRequest(t *testing.T) {
})
}
}
func TestMergeImageInfos(t *testing.T) {
testCases := map[string]struct {
infos []ImageInfo
wantInfo ImageInfo
wantErr bool
}{
"only one element": {
infos: []ImageInfo{
{
Ref: "test-ref",
Stream: "nightly",
Version: "v1.0.0",
List: []ImageInfoEntry{
{
CSP: "aws",
AttestationVariant: "aws-nitro-tpm",
Reference: "ami-123",
Region: "us-east-1",
},
},
},
},
wantInfo: ImageInfo{
Ref: "test-ref",
Stream: "nightly",
Version: "v1.0.0",
List: []ImageInfoEntry{
{
CSP: "aws",
AttestationVariant: "aws-nitro-tpm",
Reference: "ami-123",
Region: "us-east-1",
},
},
},
},
"valid image info": {
infos: []ImageInfo{
{
Ref: "test-ref",
Stream: "nightly",
Version: "v1.0.0",
List: []ImageInfoEntry{
{
CSP: "aws",
AttestationVariant: "aws-nitro-tpm",
Reference: "ami-123",
Region: "us-east-1",
},
},
},
{
Ref: "test-ref",
Stream: "nightly",
Version: "v1.0.0",
List: []ImageInfoEntry{
{
CSP: "gcp",
AttestationVariant: "gcp-sev-es",
Reference: "image-123",
},
},
},
},
wantInfo: ImageInfo{
Ref: "test-ref",
Stream: "nightly",
Version: "v1.0.0",
List: []ImageInfoEntry{
{
CSP: "aws",
AttestationVariant: "aws-nitro-tpm",
Reference: "ami-123",
Region: "us-east-1",
},
{
CSP: "gcp",
AttestationVariant: "gcp-sev-es",
Reference: "image-123",
},
},
},
},
"sorting": {
infos: []ImageInfo{
{
Ref: "test-ref",
Stream: "nightly",
Version: "v1.0.0",
List: []ImageInfoEntry{
{
CSP: "gcp",
AttestationVariant: "gcp-sev-es",
Reference: "image-123",
},
},
},
{
Ref: "test-ref",
Stream: "nightly",
Version: "v1.0.0",
List: []ImageInfoEntry{
{
CSP: "aws",
AttestationVariant: "aws-nitro-tpm",
Reference: "ami-123",
Region: "us-east-1",
},
},
},
},
wantInfo: ImageInfo{
Ref: "test-ref",
Stream: "nightly",
Version: "v1.0.0",
List: []ImageInfoEntry{
{
CSP: "aws",
AttestationVariant: "aws-nitro-tpm",
Reference: "ami-123",
Region: "us-east-1",
},
{
CSP: "gcp",
AttestationVariant: "gcp-sev-es",
Reference: "image-123",
},
},
},
},
"mismatch in base info": {
infos: []ImageInfo{
{
Ref: "test-ref",
Stream: "nightly",
Version: "v1.0.0",
List: []ImageInfoEntry{
{
CSP: "gcp",
AttestationVariant: "gcp-sev-es",
Reference: "image-123",
},
},
},
{
Ref: "other-ref",
Stream: "stable",
Version: "v2.0.0",
List: []ImageInfoEntry{
{
CSP: "aws",
AttestationVariant: "aws-nitro-tpm",
Reference: "ami-123",
Region: "us-east-1",
},
},
},
},
wantErr: true,
},
"empty list": {
wantErr: true,
},
}
for name, tc := range testCases {
t.Run(name, func(t *testing.T) {
assert := assert.New(t)
gotInfo, err := MergeImageInfos(tc.infos...)
if tc.wantErr {
assert.Error(err)
return
}
assert.NoError(err)
assert.Equal(tc.wantInfo, gotInfo)
})
}
}