calculator/pricing.go (424 lines of code) (raw):
// Copyright 2023 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package calculator
import (
"context"
"fmt"
"strings"
"golang.org/x/exp/slices"
"google.golang.org/api/cloudbilling/v1"
"google.golang.org/api/option"
)
type GCEPriceList struct {
// generic for all
Region string
H3CpuPrice float64
H3MemoryPrice float64
C2CpuPrice float64
C2MemoryPrice float64
C2DCpuPrice float64
C2DMemoryPrice float64
G2CpuPrice float64
G2MemoryPrice float64
A2CpuPrice float64
A2MemoryPrice float64
A3CpuPrice float64
A3MemoryPrice float64
SpotC2CpuPrice float64
SpotC2MemoryPrice float64
SpotC2DCpuPrice float64
SpotC2DMemoryPrice float64
SpotG2DCpuPrice float64
SpotG2DMemoryPrice float64
SpotA2CpuPrice float64
SpotA2MemoryPrice float64
SpotA3CpuPrice float64
SpotA3MemoryPrice float64
}
type AutopilotPriceList struct {
// generic for all
Region string
StoragePrice float64
// Non-specific workloads
CpuPrice float64
MemoryPrice float64
SpotCpuPrice float64
SpotMemoryPrice float64
CpuBalancedPrice float64
MemoryBalancedPrice float64
SpotCpuBalancedPrice float64
SpotMemoryBalancedPrice float64
CpuScaleoutPrice float64
MemoryScaleoutPrice float64
SpotCpuScaleoutPrice float64
SpotMemoryScaleoutPrice float64
CpuArmScaleoutPrice float64
MemoryArmScaleoutPrice float64
SpotArmCpuScaleoutPrice float64
SpotArmMemoryScaleoutPrice float64
// gpu pricing
GPUPodvCPUPrice float64
GPUPodMemoryPrice float64
GPUPodLocalSSDPrice float64
NVIDIAL4PodGPUPrice float64
NVIDIAT4PodGPUPrice float64
NVIDIAA10040GPodGPUPrice float64
NVIDIAA10080GPodGPUPrice float64
SpotGPUPodvCPUPrice float64
SpotGPUPodMemoryPrice float64
SpotGPUPodLocalSSDPrice float64
SpotGPUPodPDPricePremium float64
SpotNVIDIAL4PodGPUPrice float64
SpotNVIDIAT4PodGPUPrice float64
SpotNVIDIAA10040GPodGPUPrice float64
SpotNVIDIAA10080GPodGPUPrice float64
// performance tier baseline pricing
PerformanceCpuPricePremium float64
PerformanceMemoryPricePremium float64
PerformancePDPricePremium float64
PerformanceLocalSSDPricePremium float64
SpotPerformanceCpuPricePremium float64
SpotPerformanceMemoryPricePremium float64
SpotPerformancePDPricePremium float64
SpotPerformanceLocalSSDPricePremium float64
// accelerator tier baseline pricing
AcceleratorCpuPricePremium float64
AcceleratorMemoryGPUPricePremium float64
AcceleratorPDPricePremium float64
AcceleratorLocalSSDPricePremium float64
AcceleratorT4GPUPricePremium float64
AcceleratorL4GPUPricePremium float64
AcceleratorA10040GGPUPricePremium float64
AcceleratorA10080GGPUPricePremium float64
AcceleratorH100GPUPricePremium float64
SpotAcceleratorCpuPricePremium float64
SpotAcceleratorMemoryGPUPricePremium float64
SpotAcceleratorPDPricePremium float64
SpotAcceleratorLocalSSDPricePremium float64
SpotAcceleratorT4GPUPricePremium float64
SpotAcceleratorL4GPUPricePremium float64
SpotAcceleratorA10040GGPUPricePremium float64
SpotAcceleratorA10080GGPUPricePremium float64
SpotAcceleratorH100GPUPricePremium float64
}
func GetGCEPricing(sku string, region string) (GCEPriceList, error) {
pricing := GCEPriceList{
Region: region,
H3CpuPrice: 0,
H3MemoryPrice: 0,
C2CpuPrice: 0,
C2MemoryPrice: 0,
C2DCpuPrice: 0,
C2DMemoryPrice: 0,
G2CpuPrice: 0,
G2MemoryPrice: 0,
A2CpuPrice: 0,
A2MemoryPrice: 0,
A3CpuPrice: 0,
A3MemoryPrice: 0,
SpotC2CpuPrice: 0,
SpotC2MemoryPrice: 0,
SpotC2DCpuPrice: 0,
SpotC2DMemoryPrice: 0,
SpotG2DCpuPrice: 0,
SpotG2DMemoryPrice: 0,
SpotA2CpuPrice: 0,
SpotA2MemoryPrice: 0,
SpotA3CpuPrice: 0,
SpotA3MemoryPrice: 0,
}
// If the "region" is actual "zone", we need to remove the zone to get the pricing for the whole region.
if len(strings.Split(region, "-")) > 2 {
region = strings.Join(
strings.Split(region, "-")[:len(
strings.Split(
region,
"-",
),
)-1],
"-",
)
}
ctx := context.Background()
cloudbillingService, err := cloudbilling.NewService(ctx, option.WithScopes(cloudbilling.CloudPlatformScope))
if err != nil {
err = fmt.Errorf("unable to initialize cloud billing service: %v", err)
return GCEPriceList{}, err
}
err = cloudbillingService.Services.Skus.List("services/"+sku).CurrencyCode("USD").Pages(ctx, func(pricingInfo *cloudbilling.ListSkusResponse) error {
for _, sku := range pricingInfo.Skus {
if !slices.Contains(sku.ServiceRegions, region) {
continue
}
decimal := sku.PricingInfo[0].PricingExpression.TieredRates[0].UnitPrice.Units * 1000000000
mantissa := sku.PricingInfo[0].PricingExpression.TieredRates[0].UnitPrice.Nanos * int64(sku.PricingInfo[0].PricingExpression.DisplayQuantity)
price := float64(decimal+mantissa) / 1000000000
switch {
case strings.HasPrefix(sku.Description, "H3 Instance Core"):
pricing.H3CpuPrice = price
case strings.HasPrefix(sku.Description, "H3 Instance Ram"):
pricing.H3MemoryPrice = price
case strings.HasPrefix(sku.Description, "Compute optimized Instance Core"):
pricing.C2CpuPrice = price
case strings.HasPrefix(sku.Description, "Compute optimized Instance Ram"):
pricing.C2MemoryPrice = price
case strings.HasPrefix(sku.Description, "Spot Preemptible Compute optimized Instance Core"):
pricing.SpotC2CpuPrice = price
case strings.HasPrefix(sku.Description, "Spot Preemptible Compute optimized Instance Ram"):
pricing.SpotC2MemoryPrice = price
case strings.HasPrefix(sku.Description, "C2D AMD Instance Core"):
pricing.C2DCpuPrice = price
case strings.HasPrefix(sku.Description, "C2D AMD Instance Ram"):
pricing.C2DMemoryPrice = price
case strings.HasPrefix(sku.Description, "Spot Preemptible C2D AMD Instance Core"):
pricing.SpotC2DCpuPrice = price
case strings.HasPrefix(sku.Description, "Spot Preemptible C2D AMD Instance Ram"):
pricing.SpotC2DMemoryPrice = price
case strings.HasPrefix(sku.Description, "G2 Instance Core"):
pricing.G2CpuPrice = price
case strings.HasPrefix(sku.Description, "G2 Instance Ram"):
pricing.G2MemoryPrice = price
case strings.HasPrefix(sku.Description, "Spot Preemptible G2 Instance Core"):
pricing.SpotG2DCpuPrice = price
case strings.HasPrefix(sku.Description, "Spot Preemptible G2 Instance Ram"):
pricing.SpotG2DMemoryPrice = price
case strings.HasPrefix(sku.Description, "A2 Instance Core"):
pricing.A2CpuPrice = price
case strings.HasPrefix(sku.Description, "A2 Instance Ram"):
pricing.A2MemoryPrice = price
case strings.HasPrefix(sku.Description, "Spot Preemptible A2 Instance Core"):
pricing.SpotA2CpuPrice = price
case strings.HasPrefix(sku.Description, "Spot Preemptible A2 Instance Ram"):
pricing.SpotA2MemoryPrice = price
case strings.HasPrefix(sku.Description, "A3 Instance Core"):
pricing.A3CpuPrice = price
case strings.HasPrefix(sku.Description, "A3 Instance Ram"):
pricing.A3MemoryPrice = price
case strings.HasPrefix(sku.Description, "Spot Preemptible A3 Instance Core"):
pricing.SpotA3CpuPrice = price
case strings.HasPrefix(sku.Description, "Spot Preemptible A3 Instance Ram"):
pricing.SpotA3MemoryPrice = price
}
}
return nil
})
if err != nil {
err = fmt.Errorf("unable to fetch gce cloud billing information: %v", err)
return GCEPriceList{}, err
}
return pricing, nil
}
func GetAutopilotPricing(sku string, region string) (AutopilotPriceList, error) {
// Init all to zeroes
pricing := AutopilotPriceList{
Region: region,
StoragePrice: 0,
CpuPrice: 0,
MemoryPrice: 0,
SpotCpuPrice: 0,
SpotMemoryPrice: 0,
CpuBalancedPrice: 0,
MemoryBalancedPrice: 0,
SpotCpuBalancedPrice: 0,
SpotMemoryBalancedPrice: 0,
CpuScaleoutPrice: 0,
MemoryScaleoutPrice: 0,
SpotCpuScaleoutPrice: 0,
SpotMemoryScaleoutPrice: 0,
CpuArmScaleoutPrice: 0,
MemoryArmScaleoutPrice: 0,
SpotArmCpuScaleoutPrice: 0,
SpotArmMemoryScaleoutPrice: 0,
GPUPodvCPUPrice: 0,
GPUPodMemoryPrice: 0,
GPUPodLocalSSDPrice: 0,
NVIDIAL4PodGPUPrice: 0,
NVIDIAT4PodGPUPrice: 0,
NVIDIAA10040GPodGPUPrice: 0,
NVIDIAA10080GPodGPUPrice: 0,
SpotGPUPodvCPUPrice: 0,
SpotGPUPodMemoryPrice: 0,
SpotGPUPodLocalSSDPrice: 0,
SpotNVIDIAL4PodGPUPrice: 0,
SpotNVIDIAT4PodGPUPrice: 0,
SpotNVIDIAA10040GPodGPUPrice: 0,
SpotNVIDIAA10080GPodGPUPrice: 0,
PerformanceCpuPricePremium: 0,
PerformanceMemoryPricePremium: 0,
PerformancePDPricePremium: 0,
PerformanceLocalSSDPricePremium: 0,
SpotPerformanceCpuPricePremium: 0,
SpotPerformanceMemoryPricePremium: 0,
SpotPerformancePDPricePremium: 0,
SpotPerformanceLocalSSDPricePremium: 0,
AcceleratorCpuPricePremium: 0,
AcceleratorMemoryGPUPricePremium: 0,
AcceleratorPDPricePremium: 0,
AcceleratorLocalSSDPricePremium: 0,
AcceleratorT4GPUPricePremium: 0,
AcceleratorL4GPUPricePremium: 0,
AcceleratorA10040GGPUPricePremium: 0,
AcceleratorA10080GGPUPricePremium: 0,
AcceleratorH100GPUPricePremium: 0,
SpotAcceleratorCpuPricePremium: 0,
SpotAcceleratorMemoryGPUPricePremium: 0,
SpotAcceleratorPDPricePremium: 0,
SpotAcceleratorLocalSSDPricePremium: 0,
SpotAcceleratorT4GPUPricePremium: 0,
SpotAcceleratorL4GPUPricePremium: 0,
SpotAcceleratorA10040GGPUPricePremium: 0,
SpotAcceleratorA10080GGPUPricePremium: 0,
SpotAcceleratorH100GPUPricePremium: 0,
}
// If the "region" is actual "zone", we need to remove the zone to get the pricing for the whole region.
if len(strings.Split(region, "-")) > 2 {
region = strings.Join(
strings.Split(region, "-")[:len(
strings.Split(
region,
"-",
),
)-1],
"-",
)
}
ctx := context.Background()
cloudbillingService, err := cloudbilling.NewService(ctx, option.WithScopes(cloudbilling.CloudPlatformScope))
if err != nil {
err = fmt.Errorf("unable to initialize cloud billing service: %v", err)
return AutopilotPriceList{}, err
}
err = cloudbillingService.Services.Skus.List("services/"+sku).CurrencyCode("USD").Pages(ctx, func(pricingInfo *cloudbilling.ListSkusResponse) error {
for _, sku := range pricingInfo.Skus {
if !slices.Contains(sku.ServiceRegions, region) {
continue
}
decimal := sku.PricingInfo[0].PricingExpression.TieredRates[0].UnitPrice.Units * 1000000000
mantissa := sku.PricingInfo[0].PricingExpression.TieredRates[0].UnitPrice.Nanos * int64(sku.PricingInfo[0].PricingExpression.DisplayQuantity)
price := float64(decimal+mantissa) / 1000000000
switch sku.Description {
case "Autopilot Pod Ephemeral Storage Requests (" + region + ")":
pricing.StoragePrice = price
case "Autopilot Pod Memory Requests (" + region + ")":
pricing.MemoryPrice = price
case "Autopilot Pod mCPU Requests (" + region + ")":
pricing.CpuPrice = price
case "Autopilot Balanced Pod Memory Requests (" + region + ")":
pricing.MemoryBalancedPrice = price
case "Autopilot Balanced Pod mCPU Requests (" + region + ")":
pricing.CpuBalancedPrice = price
case "Autopilot Scale-Out x86 Pod Memory Requests (" + region + ")":
pricing.MemoryScaleoutPrice = price
case "Autopilot Scale-Out x86 Pod mCPU Requests (" + region + ")":
pricing.CpuScaleoutPrice = price
case "Autopilot Scale-Out Arm Spot Pod Memory Requests (" + region + ")":
pricing.MemoryArmScaleoutPrice = price
case "Autopilot Scale-Out Arm Spot Pod mCPU Requests (" + region + ")":
pricing.CpuArmScaleoutPrice = price
case "Autopilot Spot Pod Memory Requests (" + region + ")":
pricing.SpotMemoryPrice = price
case "Autopilot Spot Pod mCPU Requests (" + region + ")":
pricing.SpotCpuPrice = price
case "Autopilot Balanced Spot Pod Memory Requests (" + region + ")":
pricing.SpotMemoryBalancedPrice = price
case "Autopilot Balanced Spot Pod mCPU Requests (" + region + ")":
pricing.SpotCpuBalancedPrice = price
case "Autopilot Scale-Out x86 Spot Pod Memory Requests (" + region + ")":
pricing.SpotMemoryScaleoutPrice = price
case "Autopilot Scale-Out x86 Spot Pod mCPU Requests (" + region + ")":
pricing.SpotCpuScaleoutPrice = price
case "Autopilot Scale-Out Arm Spot Pod Memory Requests (" + region + ")":
pricing.SpotArmMemoryScaleoutPrice = price
case "Autopilot Scale-Out Arm Spot Pod mCPU Requests (" + region + ")":
pricing.SpotArmCpuScaleoutPrice = price
case "Autopilot NVIDIA T4 Pod mCPU Requests (" + region + ")":
case "Autopilot NVIDIA L4 Pod mCPU Requests (" + region + ")":
case "Autopilot NVIDIA A100 Pod mCPU Requests (" + region + ")":
case "Autopilot NVIDIA A100 80GB Pod mCPU Requests (" + region + ")":
pricing.GPUPodvCPUPrice = price
case "Autopilot NVIDIA T4 Pod Memory Requests (" + region + ")":
case "Autopilot NVIDIA L4 Pod Memory Requests (" + region + ")":
case "Autopilot NVIDIA A100 Pod Memory Requests (" + region + ")":
case "Autopilot NVIDIA A100 80GB Pod Memory Requests (" + region + ")":
pricing.GPUPodMemoryPrice = price
case "Autopilot NVIDIA T4 Pod GPU Requests (" + region + ")":
pricing.NVIDIAT4PodGPUPrice = price
case "Autopilot NVIDIA L4 Pod GPU Requests (" + region + ")":
pricing.NVIDIAL4PodGPUPrice = price
case "Autopilot NVIDIA A100 Pod GPU Requests (" + region + ")":
pricing.NVIDIAA10040GPodGPUPrice = price
case "Autopilot NVIDIA A100 80GB Pod GPU Requests (" + region + ")":
pricing.NVIDIAA10080GPodGPUPrice = price
case "Autopilot GPU Pod Local SSD (" + region + ")":
pricing.SpotGPUPodLocalSSDPrice = price
case "Autopilot NVIDIA T4 Spot Pod mCPU Requests (" + region + ")":
case "Autopilot NVIDIA L4 Spot Pod mCPU Requests (" + region + ")":
case "Autopilot NVIDIA A100 Spot Pod mCPU Requests (" + region + ")":
case "Autopilot NVIDIA A100 80GB Spot Pod mCPU Requests (" + region + ")":
pricing.GPUPodvCPUPrice = price
case "Autopilot NVIDIA T4 Spot Pod Memory Requests (" + region + ")":
case "Autopilot NVIDIA L4 Spot Pod Memory Requests (" + region + ")":
case "Autopilot NVIDIA A100 Spot Pod Memory Requests (" + region + ")":
case "Autopilot NVIDIA A100 80GB Spot Pod Memory Requests (" + region + ")":
pricing.GPUPodMemoryPrice = price
case "Autopilot NVIDIA T4 Spot Pod GPU Requests (" + region + ")":
pricing.NVIDIAT4PodGPUPrice = price
case "Autopilot NVIDIA L4 Spot Pod GPU Requests (" + region + ")":
pricing.NVIDIAL4PodGPUPrice = price
case "Autopilot NVIDIA A100 Spot Pod GPU Requests (" + region + ")":
pricing.NVIDIAA10040GPodGPUPrice = price
case "Autopilot NVIDIA A100 80GB Spot Pod GPU Requests (" + region + ")":
pricing.NVIDIAA10080GPodGPUPrice = price
case "Autopilot GPU Spot Pod Local SSD (" + region + ")":
pricing.SpotGPUPodLocalSSDPrice = price
case "Autopilot PD Balanced Premium (" + region + ")":
pricing.PerformancePDPricePremium = price
pricing.SpotPerformancePDPricePremium = price
pricing.AcceleratorPDPricePremium = price
pricing.SpotAcceleratorPDPricePremium = price
case "Autopilot Performance CPU Premium (" + region + ")":
pricing.PerformanceCpuPricePremium = price
case "Autopilot Performance Memory Premium (" + region + ")":
pricing.PerformanceMemoryPricePremium = price
case "Autopilot Local SSD Premium (" + region + ")":
pricing.PerformanceLocalSSDPricePremium = price
pricing.AcceleratorLocalSSDPricePremium = price
case "Autopilot Spot PD Balanced Premium (" + region + ")":
pricing.PerformancePDPricePremium = price
pricing.SpotPerformancePDPricePremium = price
pricing.AcceleratorPDPricePremium = price
pricing.SpotAcceleratorPDPricePremium = price
case "Autopilot Performance Spot CPU Premium (" + region + ")":
pricing.SpotPerformanceCpuPricePremium = price
case "Autopilot Performance Spot Memory Premium (" + region + ")":
pricing.SpotPerformanceMemoryPricePremium = price
case "Autopilot Local SSD Spot Premium (" + region + ")":
pricing.SpotPerformanceLocalSSDPricePremium = price
pricing.SpotAcceleratorLocalSSDPricePremium = price
case "Autopilot Accelerator CPU Premium (" + region + ")":
pricing.AcceleratorCpuPricePremium = price
case "Autopilot Accelerator Memory Premium (" + region + ")":
pricing.AcceleratorMemoryGPUPricePremium = price
case "Autopilot T4 Premium (" + region + ")":
pricing.AcceleratorT4GPUPricePremium = price
case "Autopilot L4 Premium (" + region + ")":
pricing.AcceleratorL4GPUPricePremium = price
case "Autopilot A100 40GB Premium (" + region + ")":
pricing.AcceleratorA10040GGPUPricePremium = price
case "Autopilot A100 80GB Premium (" + region + ")":
pricing.AcceleratorA10080GGPUPricePremium = price
case "Autopilot H100 80GB Premium (" + region + ")":
pricing.AcceleratorH100GPUPricePremium = price
case "Autopilot Accelerator Spot CPU Premium (" + region + ")":
pricing.SpotAcceleratorCpuPricePremium = price
case "Autopilot Accelerator Spot Memory Premium (" + region + ")":
pricing.SpotAcceleratorMemoryGPUPricePremium = price
case "Autopilot T4 Spot Premium (" + region + ")":
pricing.SpotAcceleratorT4GPUPricePremium = price
case "Autopilot L4 Spot Premium (" + region + ")":
pricing.SpotAcceleratorL4GPUPricePremium = price
case "Autopilot A100 40GB Spot Premium (" + region + ")":
pricing.SpotAcceleratorA10040GGPUPricePremium = price
case "Autopilot A100 80GB Spot Premium (" + region + ")":
pricing.SpotAcceleratorA10080GGPUPricePremium = price
case "Autopilot H100 80GB Spot Premium (" + region + ")":
pricing.SpotAcceleratorH100GPUPricePremium = price
}
}
return nil
})
if err != nil {
err = fmt.Errorf("unable to fetch autopilot cloud billing information: %v", err)
return AutopilotPriceList{}, err
}
return pricing, nil
}