diff --git a/cmd/controller/purserctrl.go b/cmd/controller/purserctrl.go index 701608639..97c67220e 100644 --- a/cmd/controller/purserctrl.go +++ b/cmd/controller/purserctrl.go @@ -112,7 +112,8 @@ func startCronJobForPopulatingRateCard() { cloud.PopulateRateCard() c := cron.New() - err := c.AddFunc("@every 7d", cloud.PopulateRateCard) + + err := c.AddFunc("@every 168h", cloud.PopulateRateCard) if err != nil { log.Error(err) } diff --git a/pkg/controller/dgraph/models/rateCard.go b/pkg/controller/dgraph/models/rateCard.go index 41e5063e2..03a5c51dd 100644 --- a/pkg/controller/dgraph/models/rateCard.go +++ b/pkg/controller/dgraph/models/rateCard.go @@ -51,6 +51,8 @@ type NodePrice struct { InstanceFamily string `json:"instanceFamily,omitempty"` OperatingSystem string `json:"operatingSystem,omitempty"` Price float64 `json:"price,omitempty"` + PricePerCPU string `json:"cpuPrice,omitempty"` + PricePerMemory string `json:"memoryPrice,omitempty"` } // StoragePrice structure @@ -61,6 +63,7 @@ type StoragePrice struct { VolumeType string `json:"volumeType,omitempty"` UsageType string `json:"usageType,omitempty"` Price float64 `json:"price,omitempty"` + PricePerGB string `json:"pricePerGB,omitempty"` } // StoreRateCard given a cloudProvider and region it gets rate card and stores(create/update) in dgraph diff --git a/pkg/pricing/aws/aws.go b/pkg/pricing/aws/aws.go index 89c432bae..ae049ae93 100644 --- a/pkg/pricing/aws/aws.go +++ b/pkg/pricing/aws/aws.go @@ -66,6 +66,8 @@ type ProductAttributes struct { PreInstalledSW string VolumeType string UsageType string + Vcpu string + Memory string } // GetAWSPricing function details diff --git a/pkg/pricing/aws/convert.go b/pkg/pricing/aws/convert.go index 2785ed483..a167442a4 100644 --- a/pkg/pricing/aws/convert.go +++ b/pkg/pricing/aws/convert.go @@ -19,6 +19,7 @@ package aws import ( "strconv" + "strings" "github.com/Sirupsen/logrus" "github.com/vmware/purser/pkg/controller/dgraph" @@ -34,6 +35,12 @@ const ( computeInstance = "Compute Instance" priceError = -1.0 hoursInMonth = 720 + + // TODO: Determine priceSplitRatio according to instance type i.e, compute optimized or memory optimized etc + priceSplitRatio = 0.5 + defaultCPUCostPerCPUPerHour = "0.024" + defaultMemCostPerGBPerHour = "0.01" + defaultStorageCostInFloat64 = 0.00013888888 ) // GetRateCardForAWS takes region as input and returns RateCard and error if any @@ -66,13 +73,11 @@ func getResourcePricesFromAWSPricing(awsPricing *Pricing) ([]*models.NodePrice, duplicateComputeInstanceChecker := make(map[string]bool) for _, product := range products { priceInFloat64, unit := getResourcePrice(product, planList) - if priceInFloat64 != priceError { - switch product.ProductFamily { - case computeInstance: - nodePrices = updateComputeInstancePrices(product, priceInFloat64, duplicateComputeInstanceChecker, nodePrices) - case storageInstance: - storagePrices = updateStorageInstancePrices(product, priceInFloat64, unit, storagePrices) - } + switch product.ProductFamily { + case computeInstance: + nodePrices = updateComputeInstancePrices(product, priceInFloat64, duplicateComputeInstanceChecker, nodePrices) + case storageInstance: + storagePrices = updateStorageInstancePrices(product, priceInFloat64, unit, storagePrices) } } return nodePrices, storagePrices @@ -99,6 +104,7 @@ func updateComputeInstancePrices(product Product, priceInFloat64 float64, duplic if _, isPresent := duplicateComputeInstanceChecker[key]; !isPresent && product.Attributes.PreInstalledSW == na { // Unit of Compute price USD-perHour productXID := product.Attributes.InstanceType + deliminator + product.Attributes.InstanceFamily + deliminator + product.Attributes.OperatingSystem + pricePerCPU, pricePerGB := getPriceForUnitResource(product, priceInFloat64) nodePrice := &models.NodePrice{ ID: dgraph.ID{Xid: productXID}, IsNodePrice: true, @@ -106,6 +112,8 @@ func updateComputeInstancePrices(product Product, priceInFloat64 float64, duplic InstanceFamily: product.Attributes.InstanceFamily, OperatingSystem: product.Attributes.OperatingSystem, Price: priceInFloat64, + PricePerCPU: pricePerCPU, + PricePerMemory: pricePerGB, } duplicateComputeInstanceChecker[key] = true uid := models.StoreNodePrice(nodePrice, productXID) @@ -118,10 +126,13 @@ func updateComputeInstancePrices(product Product, priceInFloat64 float64, duplic } func updateStorageInstancePrices(product Product, priceInFloat64 float64, unit string, storagePrices []*models.StoragePrice) []*models.StoragePrice { - if unit == gbMonth { + if priceInFloat64 == priceError { + priceInFloat64 = defaultStorageCostInFloat64 + } else if unit == gbMonth { // convert to GBHour priceInFloat64 = priceInFloat64 / hoursInMonth } + productXID := product.Attributes.VolumeType + deliminator + product.Attributes.UsageType storagePrice := &models.StoragePrice{ ID: dgraph.ID{Xid: productXID}, @@ -129,6 +140,7 @@ func updateStorageInstancePrices(product Product, priceInFloat64 float64, unit s VolumeType: product.Attributes.VolumeType, UsageType: product.Attributes.UsageType, Price: priceInFloat64, + PricePerGB: strconv.FormatFloat(priceInFloat64, 'f', 11, 64), } uid := models.StoreStoragePrice(storagePrice, productXID) if uid != "" { @@ -137,3 +149,24 @@ func updateStorageInstancePrices(product Product, priceInFloat64 float64, unit s } return storagePrices } + +func getPriceForUnitResource(product Product, priceInFloat64 float64) (string, string) { + pricePerCPU := defaultCPUCostPerCPUPerHour + pricePerGB := defaultMemCostPerGBPerHour + + // priceInFloat64 should be greater than 0 otherwise this function returns default pricing + if priceInFloat64 != priceError && priceInFloat64 != 0 { + cpu, err := strconv.ParseFloat(product.Attributes.Vcpu, 64) + if err == nil { + pricePerCPU = strconv.FormatFloat(priceSplitRatio*priceInFloat64/cpu, 'f', 11, 64) + } + + memWithUnits := product.Attributes.Memory + // memWithUnits format: "3,126 GiB" + mem, err := strconv.ParseFloat(strings.Join(strings.Split(strings.Split(memWithUnits, " GiB")[0], ","), ""), 64) + if err == nil { + pricePerGB = strconv.FormatFloat((1-priceSplitRatio)*priceInFloat64/mem, 'f', 11, 64) + } + } + return pricePerCPU, pricePerGB +}