Skip to content

Commit 1ef3f1e

Browse files
committed
add support for looking up Auto Mode management pricing
1 parent ab3eaea commit 1ef3f1e

1 file changed

Lines changed: 78 additions & 4 deletions

File tree

pkg/aws/pricing.go

Lines changed: 78 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ type pricingProvider struct {
4545
mu sync.RWMutex
4646
onUpdateFuncs []func()
4747
onDemandPrices map[ec2types.InstanceType]float64
48+
autoManagementPrices map[ec2types.InstanceType]float64
4849
spotPrices map[ec2types.InstanceType]zonalPricing
4950
fargateVCPUPricePerHour float64
5051
fargateGBPricePerHour float64
@@ -55,13 +56,23 @@ func (p *pricingProvider) OnUpdate(onUpdate func()) {
5556
}
5657

5758
func (p *pricingProvider) NodePrice(n *model.Node) (float64, bool) {
59+
autoManagementPrice := 0.0
60+
if n.IsAuto() {
61+
if price, ok := p.AutoManagementPrice(n.InstanceType()); ok {
62+
autoManagementPrice = price
63+
} else {
64+
// don't return a price until we've looked up the management price
65+
return 0.0, false
66+
}
67+
}
68+
5869
if n.IsOnDemand() {
5970
if price, ok := p.OnDemandPrice(n.InstanceType()); ok {
60-
return price, true
71+
return autoManagementPrice + price, true
6172
}
6273
} else if n.IsSpot() {
6374
if price, ok := p.SpotPrice(n.InstanceType(), n.Zone()); ok {
64-
return price, true
75+
return autoManagementPrice + price, true
6576
}
6677
} else if n.IsFargate() && len(n.Pods()) == 1 {
6778
cpu, mem, ok := n.Pods()[0].FargateCapacityProvisioned()
@@ -189,6 +200,18 @@ func (p *pricingProvider) OnDemandPrice(instanceType ec2types.InstanceType) (flo
189200
return price, true
190201
}
191202

203+
// AutoManagementPrice returns the EKS Auto Mode management price for the given instance type.
204+
func (p *pricingProvider) AutoManagementPrice(instanceType ec2types.InstanceType) (float64, bool) {
205+
p.mu.RLock()
206+
defer p.mu.RUnlock()
207+
price, ok := p.autoManagementPrices[instanceType]
208+
if !ok {
209+
return 0.0, false
210+
}
211+
return price, true
212+
}
213+
214+
// FargatePrice returns the last known Fargate price for the given CPU/memory.
192215
func (p *pricingProvider) FargatePrice(cpu, memory float64) (float64, bool) {
193216
p.mu.RLock()
194217
defer p.mu.RUnlock()
@@ -237,6 +260,14 @@ func (p *pricingProvider) updatePricing(ctx context.Context) {
237260
log.Printf("updating fargate pricing, %s", err)
238261
}
239262
}()
263+
264+
wg.Add(1)
265+
go func() {
266+
defer wg.Done()
267+
if err := p.updateAutoManagementPricing(ctx); err != nil {
268+
log.Printf("updating auto management pricing, %s", err)
269+
}
270+
}()
240271
wg.Wait()
241272

242273
// notify anyone that cares
@@ -245,6 +276,47 @@ func (p *pricingProvider) updatePricing(ctx context.Context) {
245276
}
246277
}
247278

279+
func (p *pricingProvider) updateAutoManagementPricing(ctx context.Context) error {
280+
if p.pricingClient == nil {
281+
return errors.New("pricing client not initialized")
282+
}
283+
prices := map[ec2types.InstanceType]float64{}
284+
filters := []pricingtypes.Filter{
285+
{
286+
Type: pricingtypes.FilterTypeTermMatch,
287+
Field: aws.String("operation"),
288+
Value: aws.String("EKSAutoUsage"),
289+
},
290+
{
291+
Type: pricingtypes.FilterTypeTermMatch,
292+
Field: aws.String("regionCode"),
293+
Value: aws.String("us-west-2"),
294+
},
295+
}
296+
297+
paginator := pricing.NewGetProductsPaginator(p.pricingClient, &pricing.GetProductsInput{
298+
Filters: filters,
299+
ServiceCode: aws.String("AmazonEKS"),
300+
MaxResults: aws.Int32(100),
301+
})
302+
303+
for paginator.HasMorePages() {
304+
output, err := paginator.NextPage(ctx)
305+
if err != nil {
306+
return err
307+
}
308+
p.processInstancePricingPage(output, prices)
309+
}
310+
if len(prices) == 0 {
311+
log.Printf("No Auto Mode managment prices found")
312+
}
313+
314+
p.mu.Lock()
315+
defer p.mu.Unlock()
316+
p.autoManagementPrices = prices
317+
return nil
318+
}
319+
248320
func (p *pricingProvider) updateOnDemandPricing(ctx context.Context) error {
249321
if p.pricingClient == nil {
250322
return errors.New("pricing client not initialized")
@@ -347,14 +419,15 @@ func (p *pricingProvider) fetchOnDemandPricing(ctx context.Context, additionalFi
347419
paginator := pricing.NewGetProductsPaginator(p.pricingClient, &pricing.GetProductsInput{
348420
Filters: filters,
349421
ServiceCode: aws.String("AmazonEC2"),
422+
MaxResults: aws.Int32(100),
350423
})
351424

352425
for paginator.HasMorePages() {
353426
output, err := paginator.NextPage(ctx)
354427
if err != nil {
355428
return nil, err
356429
}
357-
p.processOnDemandPage(output, prices)
430+
p.processInstancePricingPage(output, prices)
358431
}
359432

360433
return prices, nil
@@ -363,7 +436,7 @@ func (p *pricingProvider) fetchOnDemandPricing(ctx context.Context, additionalFi
363436
// turning off cyclo here, it measures as a 12 due to all of the type checks of the pricing data which returns a deeply
364437
// nested map[string]interface{}
365438
// nolint: gocyclo
366-
func (p *pricingProvider) processOnDemandPage(output *pricing.GetProductsOutput, prices map[ec2types.InstanceType]float64) {
439+
func (p *pricingProvider) processInstancePricingPage(output *pricing.GetProductsOutput, prices map[ec2types.InstanceType]float64) {
367440
// this isn't the full pricing struct, just the portions we care about
368441
type priceItem struct {
369442
Product struct {
@@ -482,6 +555,7 @@ func (p *pricingProvider) updateFargatePricing(ctx context.Context) error {
482555
paginator := pricing.NewGetProductsPaginator(p.pricingClient, &pricing.GetProductsInput{
483556
Filters: filters,
484557
ServiceCode: aws.String("AmazonEKS"),
558+
MaxResults: aws.Int32(100),
485559
})
486560

487561
for paginator.HasMorePages() {

0 commit comments

Comments
 (0)