Skip to content

Commit a55a206

Browse files
mulpuriHarness
authored andcommitted
[fix]: [CCM-29228]: GCP NodePool Recommendations - Spot pricing is more than OnDemand pricing (#24)
* 1db88b CCM-29228: Fix onDemand pricing
1 parent 9c66329 commit a55a206

File tree

2 files changed

+184
-0
lines changed

2 files changed

+184
-0
lines changed

internal/cloudinfo/providers/google/cloudinfo.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -373,6 +373,10 @@ func (g *GceInfoer) getPrice() (map[string]map[string]map[string]float64, map[st
373373
if (sku.Category.ResourceGroup == "RAM" || sku.Category.ResourceGroup == "CPU") && (sku.Category.UsageType == "OnDemand" || sku.Category.UsageType == "Preemptible") {
374374
for _, standardMachineType := range standardMachineTypes {
375375
if strings.Contains(sku.Description, standardMachineType) && !strings.Contains(sku.Description, "Sole Tenancy") && !strings.Contains(sku.Description, "Custom") {
376+
// Skip "Reserved" SKUs for on-demand pricing - this was causing pricing to be updated to 0 sometimes
377+
if sku.Category.UsageType == "OnDemand" && strings.Contains(sku.Description, "Reserved") {
378+
continue
379+
}
376380
priceInUsd, err := g.priceInUsd(sku.PricingInfo)
377381
if err != nil {
378382
return err
@@ -425,6 +429,14 @@ func (g *GceInfoer) priceFromSku(price map[string]map[string]map[string]float64,
425429
if pr == nil {
426430
pr = make(map[string]float64)
427431
}
432+
433+
// Don't overwrite a non-zero price with zero - this prevents zero-price SKUs from overwriting valid prices
434+
if priceInUsd == 0 {
435+
if existingPrice, exists := pr[priceType]; exists && existingPrice > 0 {
436+
return pr
437+
}
438+
}
439+
428440
pr[priceType] = priceInUsd
429441

430442
return pr
Lines changed: 172 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,172 @@
1+
// Copyright © 2021 Banzai Cloud
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
package google
16+
17+
import (
18+
"testing"
19+
20+
"github.com/stretchr/testify/assert"
21+
"logur.dev/logur"
22+
23+
"github.com/banzaicloud/cloudinfo/internal/cloudinfo/cloudinfoadapter"
24+
)
25+
26+
func TestGceInfoer_priceFromSku(t *testing.T) {
27+
gceInfoer := GceInfoer{log: cloudinfoadapter.NewLogger(&logur.TestLogger{})}
28+
29+
tests := []struct {
30+
name string
31+
price map[string]map[string]map[string]float64
32+
region string
33+
device string
34+
priceType string
35+
priceInUsd float64
36+
expectedPrice float64
37+
expectedExists bool
38+
description string
39+
}{
40+
{
41+
name: "set initial non-zero price",
42+
price: make(map[string]map[string]map[string]float64),
43+
region: "us-east4",
44+
device: "m4-memory",
45+
priceType: "OnDemand",
46+
priceInUsd: 0.00457,
47+
expectedPrice: 0.00457,
48+
expectedExists: true,
49+
description: "should set price when map is empty",
50+
},
51+
{
52+
name: "update existing price with new non-zero value",
53+
price: map[string]map[string]map[string]float64{
54+
"us-east4": {
55+
"m4-memory": {
56+
"OnDemand": 0.00457,
57+
},
58+
},
59+
},
60+
region: "us-east4",
61+
device: "m4-memory",
62+
priceType: "OnDemand",
63+
priceInUsd: 0.00567588,
64+
expectedPrice: 0.00567588,
65+
expectedExists: true,
66+
description: "should overwrite existing price with new non-zero value",
67+
},
68+
{
69+
name: "do not overwrite non-zero price with zero",
70+
price: map[string]map[string]map[string]float64{
71+
"us-east4": {
72+
"m4-memory": {
73+
"OnDemand": 0.00567588,
74+
},
75+
},
76+
},
77+
region: "us-east4",
78+
device: "m4-memory",
79+
priceType: "OnDemand",
80+
priceInUsd: 0.0,
81+
expectedPrice: 0.00567588,
82+
expectedExists: true,
83+
description: "should not overwrite non-zero price with zero",
84+
},
85+
{
86+
name: "set zero price when no price exists",
87+
price: make(map[string]map[string]map[string]float64),
88+
region: "us-east4",
89+
device: "m4-memory",
90+
priceType: "OnDemand",
91+
priceInUsd: 0.0,
92+
expectedPrice: 0.0,
93+
expectedExists: true,
94+
description: "should allow setting zero price when no price exists",
95+
},
96+
{
97+
name: "set different price type independently",
98+
price: map[string]map[string]map[string]float64{
99+
"us-east4": {
100+
"m4-memory": {
101+
"OnDemand": 0.00457,
102+
},
103+
},
104+
},
105+
region: "us-east4",
106+
device: "m4-memory",
107+
priceType: "Preemptible",
108+
priceInUsd: 0.001828,
109+
expectedPrice: 0.001828,
110+
expectedExists: true,
111+
description: "should set Preemptible price independently of OnDemand",
112+
},
113+
{
114+
name: "preserve other price types when updating one",
115+
price: map[string]map[string]map[string]float64{
116+
"us-east4": {
117+
"m4-memory": {
118+
"OnDemand": 0.00457,
119+
"Preemptible": 0.001828,
120+
},
121+
},
122+
},
123+
region: "us-east4",
124+
device: "m4-memory",
125+
priceType: "OnDemand",
126+
priceInUsd: 0.00567588,
127+
expectedPrice: 0.00567588,
128+
expectedExists: true,
129+
description: "should preserve other price types when updating one",
130+
},
131+
{
132+
name: "handle different regions independently",
133+
price: map[string]map[string]map[string]float64{
134+
"us-east4": {
135+
"m4-memory": {
136+
"OnDemand": 0.00457,
137+
},
138+
},
139+
},
140+
region: "us-west1",
141+
device: "m4-memory",
142+
priceType: "OnDemand",
143+
priceInUsd: 0.006,
144+
expectedPrice: 0.006,
145+
expectedExists: true,
146+
description: "should handle different regions independently",
147+
},
148+
}
149+
150+
for _, test := range tests {
151+
t.Run(test.name, func(t *testing.T) {
152+
result := gceInfoer.priceFromSku(test.price, test.region, test.device, test.priceType, test.priceInUsd)
153+
154+
// Verify the returned map
155+
assert.NotNil(t, result, "result should not be nil")
156+
price, exists := result[test.priceType]
157+
assert.Equal(t, test.expectedExists, exists, "price existence should match")
158+
if test.expectedExists {
159+
assert.Equal(t, test.expectedPrice, price, test.description)
160+
}
161+
162+
// Verify the price map was updated correctly
163+
if test.price[test.region] != nil && test.price[test.region][test.device] != nil {
164+
storedPrice, storedExists := test.price[test.region][test.device][test.priceType]
165+
assert.Equal(t, test.expectedExists, storedExists, "stored price existence should match")
166+
if test.expectedExists {
167+
assert.Equal(t, test.expectedPrice, storedPrice, "stored price should match")
168+
}
169+
}
170+
})
171+
}
172+
}

0 commit comments

Comments
 (0)