Skip to content

Commit

Permalink
feat: deprecated AMIs should be discoverable when specifying ami id o…
Browse files Browse the repository at this point in the history
…n the amiSelectorTerms
  • Loading branch information
skagalwala committed Jul 16, 2024
1 parent bcf9b09 commit 02056e0
Show file tree
Hide file tree
Showing 3 changed files with 243 additions and 14 deletions.
9 changes: 5 additions & 4 deletions pkg/providers/amifamily/ami.go
Original file line number Diff line number Diff line change
Expand Up @@ -179,10 +179,11 @@ func (p *DefaultProvider) amis(ctx context.Context, queries []DescribeImageQuery
}
}
images[reqsHash] = AMI{
Name: lo.FromPtr(image.Name),
AmiID: lo.FromPtr(image.ImageId),
CreationDate: lo.FromPtr(image.CreationDate),
Requirements: reqs,
Name: lo.FromPtr(image.Name),
AmiID: lo.FromPtr(image.ImageId),
CreationDate: lo.FromPtr(image.CreationDate),
DeprecationTime: lo.FromPtr(image.DeprecationTime),
Requirements: reqs,
}
}
}
Expand Down
206 changes: 206 additions & 0 deletions pkg/providers/amifamily/suite_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -553,6 +553,212 @@ var _ = Describe("AMIProvider", func() {
},
))
})
It("should sort amis with deprecation time and creation date consistently", func() {
amis := amifamily.AMIs{
{
Name: "test-ami-5",
AmiID: "test-ami-5-id",
CreationDate: "2021-08-31T00:04:42.000Z",
DeprecationTime: "2021-09-01T00:06:42.000Z",
Requirements: scheduling.NewRequirements(),
},
{
Name: "test-ami-4",
AmiID: "test-ami-4-id",
CreationDate: "2021-08-31T00:06:42.000Z",
DeprecationTime: "2021-09-01T00:08:42.000Z",
Requirements: scheduling.NewRequirements(),
},
{
Name: "test-ami-3",
AmiID: "test-ami-3-id",
CreationDate: "",
Requirements: scheduling.NewRequirements(),
},
{
Name: "test-ami-2",
AmiID: "test-ami-2-id",
CreationDate: "2021-08-31T00:08:42.000Z",
DeprecationTime: "",
Requirements: scheduling.NewRequirements(),
},
{
Name: "test-ami-1",
AmiID: "test-ami-1-id",
CreationDate: "2021-08-31T00:12:42.000Z",
Requirements: scheduling.NewRequirements(),
},
}

amis.Sort()
Expect(amis).To(Equal(
amifamily.AMIs{
{
Name: "test-ami-1",
AmiID: "test-ami-1-id",
CreationDate: "2021-08-31T00:12:42.000Z",
Requirements: scheduling.NewRequirements(),
},
{
Name: "test-ami-2",
AmiID: "test-ami-2-id",
CreationDate: "2021-08-31T00:08:42.000Z",
DeprecationTime: "",
Requirements: scheduling.NewRequirements(),
},
{
Name: "test-ami-3",
AmiID: "test-ami-3-id",
CreationDate: "",
Requirements: scheduling.NewRequirements(),
},
{
Name: "test-ami-4",
AmiID: "test-ami-4-id",
CreationDate: "2021-08-31T00:06:42.000Z",
DeprecationTime: "2021-09-01T00:08:42.000Z",
Requirements: scheduling.NewRequirements(),
},
{
Name: "test-ami-5",
AmiID: "test-ami-5-id",
CreationDate: "2021-08-31T00:04:42.000Z",
DeprecationTime: "2021-09-01T00:06:42.000Z",
Requirements: scheduling.NewRequirements(),
},
},
))
})
It("should sort non deprecated amis over deprecated amis with same creation time consistently", func() {
// If there are 2 AMIs with same creation date and one with a greater id is deprecated
// sort should priortize the non deprecated ami first
amis := amifamily.AMIs{
{
Name: "test-ami-3",
AmiID: "test-ami-3-id",
CreationDate: "2021-08-31T00:12:42.000Z",
DeprecationTime: time.Now().Add(-1 * time.Minute).Format(time.RFC3339),
Requirements: scheduling.NewRequirements(),
},
{
Name: "test-ami-2",
AmiID: "test-ami-2-id",
CreationDate: "2021-08-31T00:10:42.000Z",
Requirements: scheduling.NewRequirements(),
},
{
Name: "test-ami-1",
AmiID: "test-ami-1-id",
CreationDate: "2021-08-31T00:12:42.000Z",
Requirements: scheduling.NewRequirements(),
},
{
Name: "test-ami-4",
AmiID: "test-ami-4-id",
CreationDate: "2021-08-31T00:10:42.000Z",
DeprecationTime: time.Now().Add(-2 * time.Minute).Format(time.RFC3339),
Requirements: scheduling.NewRequirements(),
},
}

amis.Sort()
Expect(amis).To(Equal(
amifamily.AMIs{
{
Name: "test-ami-1",
AmiID: "test-ami-1-id",
CreationDate: "2021-08-31T00:12:42.000Z",
Requirements: scheduling.NewRequirements(),
},
{
Name: "test-ami-2",
AmiID: "test-ami-2-id",
CreationDate: "2021-08-31T00:10:42.000Z",
Requirements: scheduling.NewRequirements(),
},
{
Name: "test-ami-3",
AmiID: "test-ami-3-id",
CreationDate: "2021-08-31T00:12:42.000Z",
DeprecationTime: time.Now().Add(-1 * time.Minute).Format(time.RFC3339),
Requirements: scheduling.NewRequirements(),
},
{
Name: "test-ami-4",
AmiID: "test-ami-4-id",
CreationDate: "2021-08-31T00:10:42.000Z",
DeprecationTime: time.Now().Add(-2 * time.Minute).Format(time.RFC3339),
Requirements: scheduling.NewRequirements(),
},
},
))
})
It("should sort only deprecated amis with the same name and deprecation time consistently", func() {
amis := amifamily.AMIs{
{
Name: "test-ami-1",
AmiID: "test-ami-4-id",
CreationDate: "2021-08-31T00:10:42.000Z",
DeprecationTime: "2021-08-31T00:12:42.000Z",
Requirements: scheduling.NewRequirements(),
},
{
Name: "test-ami-1",
AmiID: "test-ami-3-id",
CreationDate: "2021-08-31T00:10:42.000Z",
DeprecationTime: "2021-08-31T00:12:42.000Z",
Requirements: scheduling.NewRequirements(),
},
{
Name: "test-ami-1",
AmiID: "test-ami-2-id",
CreationDate: "2021-08-31T00:10:42.000Z",
DeprecationTime: "2021-08-31T00:12:42.000Z",
Requirements: scheduling.NewRequirements(),
},
{
Name: "test-ami-1",
AmiID: "test-ami-1-id",
CreationDate: "2021-08-31T00:10:42.000Z",
DeprecationTime: "2021-08-31T00:12:42.000Z",
Requirements: scheduling.NewRequirements(),
},
}

amis.Sort()
Expect(amis).To(Equal(
amifamily.AMIs{
{
Name: "test-ami-1",
AmiID: "test-ami-1-id",
CreationDate: "2021-08-31T00:10:42.000Z",
DeprecationTime: "2021-08-31T00:12:42.000Z",
Requirements: scheduling.NewRequirements(),
},
{
Name: "test-ami-1",
AmiID: "test-ami-2-id",
CreationDate: "2021-08-31T00:10:42.000Z",
DeprecationTime: "2021-08-31T00:12:42.000Z",
Requirements: scheduling.NewRequirements(),
},
{
Name: "test-ami-1",
AmiID: "test-ami-3-id",
CreationDate: "2021-08-31T00:10:42.000Z",
DeprecationTime: "2021-08-31T00:12:42.000Z",
Requirements: scheduling.NewRequirements(),
},
{
Name: "test-ami-1",
AmiID: "test-ami-4-id",
CreationDate: "2021-08-31T00:10:42.000Z",
DeprecationTime: "2021-08-31T00:12:42.000Z",
Requirements: scheduling.NewRequirements(),
},
},
))
})
})
})

Expand Down
42 changes: 32 additions & 10 deletions pkg/providers/amifamily/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ package amifamily

import (
"fmt"
"math"
"sort"
"time"

Expand All @@ -36,27 +37,47 @@ const (
)

type AMI struct {
Name string
AmiID string
CreationDate string
Requirements scheduling.Requirements
Name string
AmiID string
CreationDate string
DeprecationTime string
Requirements scheduling.Requirements
}

type AMIs []AMI

// Sort orders the AMIs by creation date in descending order.
// If creation date is nil or two AMIs have the same creation date, the AMIs will be sorted by ID, which is guaranteed to be unique, in ascending order.
// If there are any amis with deprecation time, they will be sorted by deprecation time in descending order
// If deprecation time is nil or two AMIs have the same deprecation time, the AMIs will be sorted by ID, which is guaranteed to be unique, in ascending order.
// finally, if creation date is nil or two AMIs have the same creation date, the AMIs will be sorted by ID, which is guaranteed to be unique, in ascending order.
func (a AMIs) Sort() {
maxTime := time.Unix(math.MaxInt64, 0)
minTime := time.Unix(math.MinInt64, 0)
sort.Slice(a, func(i, j int) bool {
itime, _ := time.Parse(time.RFC3339, a[i].CreationDate)
jtime, _ := time.Parse(time.RFC3339, a[j].CreationDate)
ideptime := parseTimeWithDefault(a[i].DeprecationTime, maxTime)
jdeptime := parseTimeWithDefault(a[j].DeprecationTime, maxTime)

if ideptime.Unix() != jdeptime.Unix() {
return ideptime.Unix() > jdeptime.Unix()
}

itime := parseTimeWithDefault(a[i].CreationDate, minTime)
jtime := parseTimeWithDefault(a[j].CreationDate, minTime)

if itime.Unix() != jtime.Unix() {
return itime.Unix() > jtime.Unix()
}
return a[i].AmiID < a[j].AmiID
})
}

func parseTimeWithDefault(dateStr string, defaultTime time.Time) time.Time {
if dateStr == "" {
return defaultTime
}
return lo.Must(time.Parse(time.RFC3339, dateStr))
}

type Variant string

var (
Expand Down Expand Up @@ -102,9 +123,10 @@ type DescribeImageQuery struct {
func (q DescribeImageQuery) DescribeImagesInput() *ec2.DescribeImagesInput {
return &ec2.DescribeImagesInput{
// Don't include filters in the Describe Images call as EC2 API doesn't allow empty filters.
Filters: lo.Ternary(len(q.Filters) > 0, q.Filters, nil),
Owners: lo.Ternary(len(q.Owners) > 0, lo.ToSlicePtr(q.Owners), nil),
MaxResults: aws.Int64(1000),
Filters: lo.Ternary(len(q.Filters) > 0, q.Filters, nil),
Owners: lo.Ternary(len(q.Owners) > 0, lo.ToSlicePtr(q.Owners), nil),
IncludeDeprecated: aws.Bool(true),
MaxResults: aws.Int64(1000),
}
}

Expand Down

0 comments on commit 02056e0

Please sign in to comment.