Browse Source

Update to match with PR #1787

Signed-off-by: Christian Muirhead <christian.muirhead@microsoft.com>
Christian Muirhead 3 years ago
parent
commit
17ef777fc3

+ 34 - 33
pkg/cloud/aliyunprovider.go

@@ -15,7 +15,8 @@ import (
 	"github.com/aliyun/alibaba-cloud-sdk-go/sdk/auth/credentials"
 	"github.com/aliyun/alibaba-cloud-sdk-go/sdk/auth/signers"
 	"github.com/aliyun/alibaba-cloud-sdk-go/sdk/requests"
-	"github.com/opencost/opencost/pkg/cloud/types"
+	"github.com/opencost/opencost/pkg/cloud/models"
+	"github.com/opencost/opencost/pkg/cloud/utils"
 	"github.com/opencost/opencost/pkg/clustercache"
 	"github.com/opencost/opencost/pkg/env"
 	"github.com/opencost/opencost/pkg/kubecost"
@@ -310,8 +311,8 @@ type AlibabaPricing struct {
 	NodeAttributes *AlibabaNodeAttributes
 	PVAttributes   *AlibabaPVAttributes
 	PricingTerms   *AlibabaPricingTerms
-	Node           *types.Node
-	PV             *types.PV
+	Node           *models.Node
+	PV             *models.PV
 }
 
 // Alibaba cloud's Provider struct
@@ -327,7 +328,7 @@ type Alibaba struct {
 
 	// The following fields are unexported because of avoiding any leak of secrets of these keys.
 	// Alibaba Access key used specifically in signer interface used to sign API calls
-	serviceAccountChecks *types.ServiceAccountChecks
+	serviceAccountChecks *models.ServiceAccountChecks
 	clusterAccountId     string
 	clusterRegion        string
 	accessKey            *credentials.AccessKeyCredential
@@ -512,7 +513,7 @@ func (alibaba *Alibaba) AllNodePricing() (interface{}, error) {
 }
 
 // NodePricing gives pricing information of a specific node given by the key
-func (alibaba *Alibaba) NodePricing(key types.Key) (*types.Node, error) {
+func (alibaba *Alibaba) NodePricing(key models.Key) (*models.Node, error) {
 	alibaba.DownloadPricingDataLock.RLock()
 	defer alibaba.DownloadPricingDataLock.RUnlock()
 
@@ -532,7 +533,7 @@ func (alibaba *Alibaba) NodePricing(key types.Key) (*types.Node, error) {
 }
 
 // PVPricing gives a pricing information of a specific PV given by PVkey
-func (alibaba *Alibaba) PVPricing(pvk types.PVKey) (*types.PV, error) {
+func (alibaba *Alibaba) PVPricing(pvk models.PVKey) (*models.PV, error) {
 	alibaba.DownloadPricingDataLock.RLock()
 	defer alibaba.DownloadPricingDataLock.RUnlock()
 
@@ -551,7 +552,7 @@ func (alibaba *Alibaba) PVPricing(pvk types.PVKey) (*types.PV, error) {
 
 // Inter zone and Inter region network cost are defaulted based on https://www.alibabacloud.com/help/en/cloud-data-transmission/latest/cross-region-data-transfers
 // Internet cost is default based on https://www.alibabacloud.com/help/en/elastic-compute-service/latest/public-bandwidth to $0.123
-func (alibaba *Alibaba) NetworkPricing() (*types.Network, error) {
+func (alibaba *Alibaba) NetworkPricing() (*models.Network, error) {
 	cpricing, err := alibaba.Config.GetCustomPricingData()
 	if err != nil {
 		return nil, err
@@ -569,7 +570,7 @@ func (alibaba *Alibaba) NetworkPricing() (*types.Network, error) {
 		return nil, err
 	}
 
-	return &types.Network{
+	return &models.Network{
 		ZoneNetworkEgressCost:     znec,
 		RegionNetworkEgressCost:   rnec,
 		InternetNetworkEgressCost: inec,
@@ -578,7 +579,7 @@ func (alibaba *Alibaba) NetworkPricing() (*types.Network, error) {
 
 // Alibaba loadbalancer has three different types https://www.alibabacloud.com/product/server-load-balancer,
 // defaulted price to classic load balancer https://www.alibabacloud.com/help/en/server-load-balancer/latest/pay-as-you-go.
-func (alibaba *Alibaba) LoadBalancerPricing() (*types.LoadBalancer, error) {
+func (alibaba *Alibaba) LoadBalancerPricing() (*models.LoadBalancer, error) {
 	cpricing, err := alibaba.Config.GetCustomPricingData()
 	if err != nil {
 		return nil, err
@@ -587,12 +588,12 @@ func (alibaba *Alibaba) LoadBalancerPricing() (*types.LoadBalancer, error) {
 	if err != nil {
 		return nil, err
 	}
-	return &types.LoadBalancer{
+	return &models.LoadBalancer{
 		Cost: lbPricing,
 	}, nil
 }
 
-func (alibaba *Alibaba) GetConfig() (*types.CustomPricing, error) {
+func (alibaba *Alibaba) GetConfig() (*models.CustomPricing, error) {
 	c, err := alibaba.Config.GetCustomPricingData()
 	if err != nil {
 		return nil, err
@@ -604,7 +605,7 @@ func (alibaba *Alibaba) GetConfig() (*types.CustomPricing, error) {
 		c.NegotiatedDiscount = "0%"
 	}
 	if c.ShareTenancyCosts == "" {
-		c.ShareTenancyCosts = types.DefaultShareTenancyCost
+		c.ShareTenancyCosts = models.DefaultShareTenancyCost
 	}
 
 	return c, nil
@@ -618,14 +619,14 @@ func (alibaba *Alibaba) loadAlibabaAuthSecretAndSetEnv(force bool) error {
 		return nil
 	}
 
-	exists, err := fileutil.FileExists(types.AuthSecretPath)
+	exists, err := fileutil.FileExists(models.AuthSecretPath)
 	if !exists || err != nil {
-		return fmt.Errorf("failed to locate service account file: %s with err: %w", types.AuthSecretPath, err)
+		return fmt.Errorf("failed to locate service account file: %s with err: %w", models.AuthSecretPath, err)
 	}
 
-	result, err := os.ReadFile(types.AuthSecretPath)
+	result, err := os.ReadFile(models.AuthSecretPath)
 	if err != nil {
-		return fmt.Errorf("failed to read service account file: %s with err: %w", types.AuthSecretPath, err)
+		return fmt.Errorf("failed to read service account file: %s with err: %w", models.AuthSecretPath, err)
 	}
 
 	var ak *AlibabaAccessKey
@@ -700,12 +701,12 @@ func (alibaba *Alibaba) GetDisks() ([]byte, error) {
 	return nil, nil
 }
 
-func (alibaba *Alibaba) GetOrphanedResources() ([]types.OrphanedResource, error) {
+func (alibaba *Alibaba) GetOrphanedResources() ([]models.OrphanedResource, error) {
 	return nil, errors.New("not implemented")
 }
 
-func (alibaba *Alibaba) UpdateConfig(r io.Reader, updateType string) (*types.CustomPricing, error) {
-	return alibaba.Config.Update(func(c *types.CustomPricing) error {
+func (alibaba *Alibaba) UpdateConfig(r io.Reader, updateType string) (*models.CustomPricing, error) {
+	return alibaba.Config.Update(func(c *models.CustomPricing) error {
 		if updateType != "" {
 			return fmt.Errorf("UpdateConfig for Alibaba Provider doesn't support updateType %s at this time", updateType)
 
@@ -716,10 +717,10 @@ func (alibaba *Alibaba) UpdateConfig(r io.Reader, updateType string) (*types.Cus
 				return err
 			}
 			for k, v := range a {
-				kUpper := types.ToTitle.String(k) // Just so we consistently supply / receive the same values, uppercase the first letter.
+				kUpper := utils.ToTitle.String(k) // Just so we consistently supply / receive the same values, uppercase the first letter.
 				vstr, ok := v.(string)
 				if ok {
-					err := types.SetCustomPricingField(c, kUpper, vstr)
+					err := models.SetCustomPricingField(c, kUpper, vstr)
 					if err != nil {
 						return err
 					}
@@ -730,7 +731,7 @@ func (alibaba *Alibaba) UpdateConfig(r io.Reader, updateType string) (*types.Cus
 		}
 
 		if env.IsRemoteEnabled() {
-			err := types.UpdateClusterMeta(env.GetClusterID(), c.ClusterName)
+			err := utils.UpdateClusterMeta(env.GetClusterID(), c.ClusterName)
 			if err != nil {
 				return err
 			}
@@ -739,7 +740,7 @@ func (alibaba *Alibaba) UpdateConfig(r io.Reader, updateType string) (*types.Cus
 	})
 }
 
-func (alibaba *Alibaba) UpdateConfigFromConfigMap(cm map[string]string) (*types.CustomPricing, error) {
+func (alibaba *Alibaba) UpdateConfigFromConfigMap(cm map[string]string) (*models.CustomPricing, error) {
 	return alibaba.Config.UpdateFromMap(cm)
 }
 
@@ -754,18 +755,18 @@ func (alibaba *Alibaba) GetLocalStorageQuery(window, offset time.Duration, rate
 }
 
 // Will look at this in Next PR if needed
-func (alibaba *Alibaba) ApplyReservedInstancePricing(nodes map[string]*types.Node) {
+func (alibaba *Alibaba) ApplyReservedInstancePricing(nodes map[string]*models.Node) {
 
 }
 
 // Will look at this in Next PR if needed
-func (alibaba *Alibaba) ServiceAccountStatus() *types.ServiceAccountStatus {
-	return &types.ServiceAccountStatus{}
+func (alibaba *Alibaba) ServiceAccountStatus() *models.ServiceAccountStatus {
+	return &models.ServiceAccountStatus{}
 }
 
 // Will look at this in Next PR if needed
-func (alibaba *Alibaba) PricingSourceStatus() map[string]*types.PricingSource {
-	return map[string]*types.PricingSource{}
+func (alibaba *Alibaba) PricingSourceStatus() map[string]*models.PricingSource {
+	return map[string]*models.PricingSource{}
 }
 
 // Will look at this in Next PR if needed
@@ -841,7 +842,7 @@ func (alibabaNodeKey *AlibabaNodeKey) GPUCount() int {
 }
 
 // Get's the key for the k8s node input
-func (alibaba *Alibaba) GetKey(mapValue map[string]string, node *v1.Node) types.Key {
+func (alibaba *Alibaba) GetKey(mapValue map[string]string, node *v1.Node) models.Key {
 	slimK8sNode := generateSlimK8sNodeFromV1Node(node)
 
 	var aak *credentials.AccessKeyCredential
@@ -907,7 +908,7 @@ type AlibabaPVKey struct {
 	SizeInGiB         string
 }
 
-func (alibaba *Alibaba) GetPVKey(pv *v1.PersistentVolume, parameters map[string]string, defaultRegion string) types.PVKey {
+func (alibaba *Alibaba) GetPVKey(pv *v1.PersistentVolume, parameters map[string]string, defaultRegion string) models.PVKey {
 	regionID := defaultRegion
 	// If default Region is not passed default it to cluster region ID.
 	if defaultRegion == "" {
@@ -1066,7 +1067,7 @@ type DescribePriceResponse struct {
 }
 
 // processDescribePriceAndCreateAlibabaPricing processes the DescribePrice API and generates the pricing information for alibaba node resource and alibaba pv resource that's backed by cloud disk.
-func processDescribePriceAndCreateAlibabaPricing(client *sdk.Client, i interface{}, signer *signers.AccessKeySigner, custom *types.CustomPricing) (pricing *AlibabaPricing, err error) {
+func processDescribePriceAndCreateAlibabaPricing(client *sdk.Client, i interface{}, signer *signers.AccessKeySigner, custom *models.CustomPricing) (pricing *AlibabaPricing, err error) {
 	pricing = &AlibabaPricing{}
 	var response DescribePriceResponse
 
@@ -1092,7 +1093,7 @@ func processDescribePriceAndCreateAlibabaPricing(client *sdk.Client, i interface
 				return nil, fmt.Errorf("unable to unmarshall json response to custom struct with err: %w", err)
 			}
 			// TO-DO : Ask in PR How to get the defaults is it equal to AWS/GCP defaults? And what needs to be returned
-			pricing.Node = &types.Node{
+			pricing.Node = &models.Node{
 				Cost:         fmt.Sprintf("%f", response.PriceInfo.Price.TradePrice),
 				BaseCPUPrice: custom.CPU,
 				BaseRAMPrice: custom.RAM,
@@ -1117,7 +1118,7 @@ func processDescribePriceAndCreateAlibabaPricing(client *sdk.Client, i interface
 				return nil, fmt.Errorf("unable to unmarshall json response to custom struct with err: %w", err)
 			}
 			pricing.PVAttributes = NewAlibabaPVAttributes(disk)
-			pricing.PV = &types.PV{
+			pricing.PV = &models.PV{
 				Cost: fmt.Sprintf("%f", response.PriceInfo.Price.TradePrice),
 			}
 			// TO-DO : Disk has support for Hour and Month but pricing API is failing for month for disk(Research why?) and same challenge as node pricing no prepaid/postpaid distinction in v1.PersistentVolume object have to look at APIs for th information.

+ 2 - 2
pkg/cloud/aliyunprovider_test.go

@@ -7,7 +7,7 @@ import (
 	"github.com/aliyun/alibaba-cloud-sdk-go/sdk"
 	"github.com/aliyun/alibaba-cloud-sdk-go/sdk/auth/credentials"
 	"github.com/aliyun/alibaba-cloud-sdk-go/sdk/auth/signers"
-	"github.com/opencost/opencost/pkg/cloud/types"
+	"github.com/opencost/opencost/pkg/cloud/models"
 	v1 "k8s.io/api/core/v1"
 	resource "k8s.io/apimachinery/pkg/api/resource"
 )
@@ -409,7 +409,7 @@ func TestProcessDescribePriceAndCreateAlibabaPricing(t *testing.T) {
 			expectedError: nil,
 		},
 	}
-	custom := &types.CustomPricing{}
+	custom := &models.CustomPricing{}
 	for _, c := range cases {
 		t.Run(c.name, func(t *testing.T) {
 			pricingObj, err := processDescribePriceAndCreateAlibabaPricing(client, c.teststruct, signer, custom)

+ 54 - 53
pkg/cloud/awsprovider.go

@@ -15,7 +15,8 @@ import (
 	"sync"
 	"time"
 
-	"github.com/opencost/opencost/pkg/cloud/types"
+	"github.com/opencost/opencost/pkg/cloud/models"
+	"github.com/opencost/opencost/pkg/cloud/utils"
 	"github.com/opencost/opencost/pkg/kubecost"
 
 	"github.com/opencost/opencost/pkg/clustercache"
@@ -69,11 +70,11 @@ var (
 	regionRx      = regexp.MustCompile("([a-z]+-[a-z]+-[0-9])")
 )
 
-func (aws *AWS) PricingSourceStatus() map[string]*types.PricingSource {
+func (aws *AWS) PricingSourceStatus() map[string]*models.PricingSource {
 
-	sources := make(map[string]*types.PricingSource)
+	sources := make(map[string]*models.PricingSource)
 
-	sps := &types.PricingSource{
+	sps := &models.PricingSource{
 		Name:    SpotPricingSource,
 		Enabled: true,
 	}
@@ -97,7 +98,7 @@ func (aws *AWS) PricingSourceStatus() map[string]*types.PricingSource {
 	}
 	sources[SpotPricingSource] = sps
 
-	rps := &types.PricingSource{
+	rps := &models.PricingSource{
 		Name:    ReservedInstancePricingSource,
 		Enabled: true,
 	}
@@ -178,7 +179,7 @@ type AWS struct {
 	ProjectID                   string
 	DownloadPricingDataLock     sync.RWMutex
 	Config                      *ProviderConfig
-	serviceAccountChecks        *types.ServiceAccountChecks
+	serviceAccountChecks        *models.ServiceAccountChecks
 	clusterManagementPrice      float64
 	clusterRegion               string
 	clusterAccountID            string
@@ -295,7 +296,7 @@ type AWSProductTerms struct {
 	Storage  string        `json:"storage"`
 	VCpu     string        `json:"vcpu"`
 	GPU      string        `json:"gpu"` // GPU represents the number of GPU on the instance
-	PV       *types.PV     `json:"pv"`
+	PV       *models.PV    `json:"pv"`
 }
 
 // ClusterIdEnvVar is the environment variable in which one can manually set the ClusterId
@@ -451,7 +452,7 @@ func (aws *AWS) GetManagementPlatform() (string, error) {
 	return "", nil
 }
 
-func (aws *AWS) GetConfig() (*types.CustomPricing, error) {
+func (aws *AWS) GetConfig() (*models.CustomPricing, error) {
 	c, err := aws.Config.GetCustomPricingData()
 	if err != nil {
 		return nil, err
@@ -463,7 +464,7 @@ func (aws *AWS) GetConfig() (*types.CustomPricing, error) {
 		c.NegotiatedDiscount = "0%"
 	}
 	if c.ShareTenancyCosts == "" {
-		c.ShareTenancyCosts = types.DefaultShareTenancyCost
+		c.ShareTenancyCosts = models.DefaultShareTenancyCost
 	}
 
 	return c, nil
@@ -519,12 +520,12 @@ func (aws *AWS) GetAWSAthenaInfo() (*AwsAthenaInfo, error) {
 	}, nil
 }
 
-func (aws *AWS) UpdateConfigFromConfigMap(cm map[string]string) (*types.CustomPricing, error) {
+func (aws *AWS) UpdateConfigFromConfigMap(cm map[string]string) (*models.CustomPricing, error) {
 	return aws.Config.UpdateFromMap(cm)
 }
 
-func (aws *AWS) UpdateConfig(r io.Reader, updateType string) (*types.CustomPricing, error) {
-	return aws.Config.Update(func(c *types.CustomPricing) error {
+func (aws *AWS) UpdateConfig(r io.Reader, updateType string) (*models.CustomPricing, error) {
+	return aws.Config.Update(func(c *models.CustomPricing) error {
 		if updateType == SpotInfoUpdateType {
 			asfi := AwsSpotFeedInfo{}
 			err := json.NewDecoder(r).Decode(&asfi)
@@ -569,10 +570,10 @@ func (aws *AWS) UpdateConfig(r io.Reader, updateType string) (*types.CustomPrici
 				return err
 			}
 			for k, v := range a {
-				kUpper := types.ToTitle.String(k) // Just so we consistently supply / receive the same values, uppercase the first letter.
+				kUpper := utils.ToTitle.String(k) // Just so we consistently supply / receive the same values, uppercase the first letter.
 				vstr, ok := v.(string)
 				if ok {
-					err := types.SetCustomPricingField(c, kUpper, vstr)
+					err := models.SetCustomPricingField(c, kUpper, vstr)
 					if err != nil {
 						return err
 					}
@@ -583,7 +584,7 @@ func (aws *AWS) UpdateConfig(r io.Reader, updateType string) (*types.CustomPrici
 		}
 
 		if env.IsRemoteEnabled() {
-			err := types.UpdateClusterMeta(env.GetClusterID(), c.ClusterName)
+			err := utils.UpdateClusterMeta(env.GetClusterID(), c.ClusterName)
 			if err != nil {
 				return err
 			}
@@ -655,11 +656,11 @@ func (k *awsKey) getUsageType(labels map[string]string) string {
 	return ""
 }
 
-func (aws *AWS) PVPricing(pvk types.PVKey) (*types.PV, error) {
+func (aws *AWS) PVPricing(pvk models.PVKey) (*models.PV, error) {
 	pricing, ok := aws.Pricing[pvk.Features()]
 	if !ok {
 		log.Debugf("Persistent Volume pricing not found for %s: %s", pvk.GetStorageClass(), pvk.Features())
-		return &types.PV{}, nil
+		return &models.PV{}, nil
 	}
 	return pricing.PV, nil
 }
@@ -673,7 +674,7 @@ type awsPVKey struct {
 	ProviderID             string
 }
 
-func (aws *AWS) GetPVKey(pv *v1.PersistentVolume, parameters map[string]string, defaultRegion string) types.PVKey {
+func (aws *AWS) GetPVKey(pv *v1.PersistentVolume, parameters map[string]string, defaultRegion string) models.PVKey {
 	providerID := ""
 	if pv.Spec.AWSElasticBlockStore != nil {
 		providerID = pv.Spec.AWSElasticBlockStore.VolumeID
@@ -718,7 +719,7 @@ func (key *awsPVKey) Features() string {
 }
 
 // GetKey maps node labels to information needed to retrieve pricing data
-func (aws *AWS) GetKey(labels map[string]string, n *v1.Node) types.Key {
+func (aws *AWS) GetKey(labels map[string]string, n *v1.Node) models.Key {
 	return &awsKey{
 		SpotLabelName:  aws.SpotLabelName,
 		SpotLabelValue: aws.SpotLabelValue,
@@ -848,7 +849,7 @@ func (aws *AWS) DownloadPricingData() error {
 		}
 	}
 
-	pvkeys := make(map[string]types.PVKey)
+	pvkeys := make(map[string]models.PVKey)
 	for _, pv := range pvList {
 		params, ok := storageClassMap[pv.Spec.StorageClassName]
 		if !ok {
@@ -997,7 +998,7 @@ func (aws *AWS) populatePricing(resp *http.Response, inputkeys map[string]bool)
 					usageTypeNoRegion := usageTypeMatch[len(usageTypeMatch)-1]
 					key := locationToRegion[product.Attributes.Location] + "," + usageTypeNoRegion
 					spotKey := key + ",preemptible"
-					pv := &types.PV{
+					pv := &models.PV{
 						Class:  volTypes[usageTypeNoRegion],
 						Region: locationToRegion[product.Attributes.Location],
 					}
@@ -1114,7 +1115,7 @@ func (aws *AWS) refreshSpotPricing(force bool) {
 }
 
 // Stubbed NetworkPricing for AWS. Pull directly from aws.json for now
-func (aws *AWS) NetworkPricing() (*types.Network, error) {
+func (aws *AWS) NetworkPricing() (*models.Network, error) {
 	cpricing, err := aws.Config.GetCustomPricingData()
 	if err != nil {
 		return nil, err
@@ -1132,14 +1133,14 @@ func (aws *AWS) NetworkPricing() (*types.Network, error) {
 		return nil, err
 	}
 
-	return &types.Network{
+	return &models.Network{
 		ZoneNetworkEgressCost:     znec,
 		RegionNetworkEgressCost:   rnec,
 		InternetNetworkEgressCost: inec,
 	}, nil
 }
 
-func (aws *AWS) LoadBalancerPricing() (*types.LoadBalancer, error) {
+func (aws *AWS) LoadBalancerPricing() (*models.LoadBalancer, error) {
 	fffrc := 0.025
 	afrc := 0.010
 	lbidc := 0.008
@@ -1153,7 +1154,7 @@ func (aws *AWS) LoadBalancerPricing() (*types.LoadBalancer, error) {
 	} else {
 		totalCost = fffrc*5 + afrc*(numForwardingRules-5) + lbidc*dataIngressGB
 	}
-	return &types.LoadBalancer{
+	return &models.LoadBalancer{
 		Cost: totalCost,
 	}, nil
 }
@@ -1189,7 +1190,7 @@ func (aws *AWS) savingsPlanPricing(instanceID string) (*SavingsPlanData, bool) {
 	return data, ok
 }
 
-func (aws *AWS) createNode(terms *AWSProductTerms, usageType string, k types.Key) (*types.Node, error) {
+func (aws *AWS) createNode(terms *AWSProductTerms, usageType string, k models.Key) (*models.Node, error) {
 	key := k.Features()
 
 	if spotInfo, ok := aws.spotPricing(k.ID()); ok {
@@ -1201,7 +1202,7 @@ func (aws *AWS) createNode(terms *AWSProductTerms, usageType string, k types.Key
 		} else {
 			log.Infof("Spot data for node %s is missing", k.ID())
 		}
-		return &types.Node{
+		return &models.Node{
 			Cost:         spotcost,
 			VCPU:         terms.VCpu,
 			RAM:          terms.Memory,
@@ -1214,7 +1215,7 @@ func (aws *AWS) createNode(terms *AWSProductTerms, usageType string, k types.Key
 		}, nil
 	} else if aws.isPreemptible(key) { // Preemptible but we don't have any data in the pricing report.
 		log.DedupedWarningf(5, "Node %s marked preemptible but we have no data in spot feed", k.ID())
-		return &types.Node{
+		return &models.Node{
 			VCPU:         terms.VCpu,
 			VCPUCost:     aws.BaseSpotCPUPrice,
 			RAM:          terms.Memory,
@@ -1227,7 +1228,7 @@ func (aws *AWS) createNode(terms *AWSProductTerms, usageType string, k types.Key
 		}, nil
 	} else if sp, ok := aws.savingsPlanPricing(k.ID()); ok {
 		strCost := fmt.Sprintf("%f", sp.EffectiveCost)
-		return &types.Node{
+		return &models.Node{
 			Cost:         strCost,
 			VCPU:         terms.VCpu,
 			RAM:          terms.Memory,
@@ -1241,7 +1242,7 @@ func (aws *AWS) createNode(terms *AWSProductTerms, usageType string, k types.Key
 
 	} else if ri, ok := aws.reservedInstancePricing(k.ID()); ok {
 		strCost := fmt.Sprintf("%f", ri.EffectiveCost)
-		return &types.Node{
+		return &models.Node{
 			Cost:         strCost,
 			VCPU:         terms.VCpu,
 			RAM:          terms.Memory,
@@ -1268,7 +1269,7 @@ func (aws *AWS) createNode(terms *AWSProductTerms, usageType string, k types.Key
 		}
 	}
 
-	return &types.Node{
+	return &models.Node{
 		Cost:         cost,
 		VCPU:         terms.VCpu,
 		RAM:          terms.Memory,
@@ -1282,7 +1283,7 @@ func (aws *AWS) createNode(terms *AWSProductTerms, usageType string, k types.Key
 }
 
 // NodePricing takes in a key from GetKey and returns a Node object for use in building the cost model.
-func (aws *AWS) NodePricing(k types.Key) (*types.Node, error) {
+func (aws *AWS) NodePricing(k models.Key) (*models.Node, error) {
 	aws.DownloadPricingDataLock.RLock()
 	defer aws.DownloadPricingDataLock.RUnlock()
 
@@ -1300,7 +1301,7 @@ func (aws *AWS) NodePricing(k types.Key) (*types.Node, error) {
 		err := aws.DownloadPricingData()
 		aws.DownloadPricingDataLock.RLock()
 		if err != nil {
-			return &types.Node{
+			return &models.Node{
 				Cost:             aws.BaseCPUPrice,
 				BaseCPUPrice:     aws.BaseCPUPrice,
 				BaseRAMPrice:     aws.BaseRAMPrice,
@@ -1311,7 +1312,7 @@ func (aws *AWS) NodePricing(k types.Key) (*types.Node, error) {
 		}
 		terms, termsOk := aws.Pricing[key]
 		if !termsOk {
-			return &types.Node{
+			return &models.Node{
 				Cost:             aws.BaseCPUPrice,
 				BaseCPUPrice:     aws.BaseCPUPrice,
 				BaseRAMPrice:     aws.BaseRAMPrice,
@@ -1382,7 +1383,7 @@ func (aws *AWS) ConfigureAuth() error {
 }
 
 // updates the authentication to the latest values (via config or secret)
-func (aws *AWS) ConfigureAuthWith(config *types.CustomPricing) error {
+func (aws *AWS) ConfigureAuthWith(config *models.CustomPricing) error {
 	accessKeyID, accessKeySecret := aws.getAWSAuth(false, config)
 	if accessKeyID != "" && accessKeySecret != "" { // credentials may exist on the actual AWS node-- if so, use those. If not, override with the service key
 		err := env.Set(env.AWSAccessKeyIDEnvVar, accessKeyID)
@@ -1398,11 +1399,11 @@ func (aws *AWS) ConfigureAuthWith(config *types.CustomPricing) error {
 }
 
 // Gets the aws key id and secret
-func (aws *AWS) getAWSAuth(forceReload bool, cp *types.CustomPricing) (string, string) {
+func (aws *AWS) getAWSAuth(forceReload bool, cp *models.CustomPricing) (string, string) {
 
 	// 1. Check config values first (set from frontend UI)
 	if cp.ServiceKeyName != "" && cp.ServiceKeySecret != "" {
-		aws.serviceAccountChecks.Set("hasKey", &types.ServiceAccountCheck{
+		aws.serviceAccountChecks.Set("hasKey", &models.ServiceAccountCheck{
 			Message: "AWS ServiceKey exists",
 			Status:  true,
 		})
@@ -1412,7 +1413,7 @@ func (aws *AWS) getAWSAuth(forceReload bool, cp *types.CustomPricing) (string, s
 	// 2. Check for secret
 	s, _ := aws.loadAWSAuthSecret(forceReload)
 	if s != nil && s.AccessKeyID != "" && s.SecretAccessKey != "" {
-		aws.serviceAccountChecks.Set("hasKey", &types.ServiceAccountCheck{
+		aws.serviceAccountChecks.Set("hasKey", &models.ServiceAccountCheck{
 			Message: "AWS ServiceKey exists",
 			Status:  true,
 		})
@@ -1421,12 +1422,12 @@ func (aws *AWS) getAWSAuth(forceReload bool, cp *types.CustomPricing) (string, s
 
 	// 3. Fall back to env vars
 	if env.GetAWSAccessKeyID() == "" || env.GetAWSAccessKeySecret() == "" {
-		aws.serviceAccountChecks.Set("hasKey", &types.ServiceAccountCheck{
+		aws.serviceAccountChecks.Set("hasKey", &models.ServiceAccountCheck{
 			Message: "AWS ServiceKey exists",
 			Status:  false,
 		})
 	} else {
-		aws.serviceAccountChecks.Set("hasKey", &types.ServiceAccountCheck{
+		aws.serviceAccountChecks.Set("hasKey", &models.ServiceAccountCheck{
 			Message: "AWS ServiceKey exists",
 			Status:  true,
 		})
@@ -1443,12 +1444,12 @@ func (aws *AWS) loadAWSAuthSecret(force bool) (*AWSAccessKey, error) {
 	}
 	loadedAWSSecret = true
 
-	exists, err := fileutil.FileExists(types.AuthSecretPath)
+	exists, err := fileutil.FileExists(models.AuthSecretPath)
 	if !exists || err != nil {
-		return nil, fmt.Errorf("Failed to locate service account file: %s", types.AuthSecretPath)
+		return nil, fmt.Errorf("Failed to locate service account file: %s", models.AuthSecretPath)
 	}
 
-	result, err := os.ReadFile(types.AuthSecretPath)
+	result, err := os.ReadFile(models.AuthSecretPath)
 	if err != nil {
 		return nil, err
 	}
@@ -1683,7 +1684,7 @@ func (aws *AWS) isDiskOrphaned(vol *ec2Types.Volume) bool {
 	return true
 }
 
-func (aws *AWS) GetOrphanedResources() ([]types.OrphanedResource, error) {
+func (aws *AWS) GetOrphanedResources() ([]models.OrphanedResource, error) {
 	volumes, err := aws.getAllDisks()
 	if err != nil {
 		return nil, err
@@ -1694,7 +1695,7 @@ func (aws *AWS) GetOrphanedResources() ([]types.OrphanedResource, error) {
 		return nil, err
 	}
 
-	var orphanedResources []types.OrphanedResource
+	var orphanedResources []models.OrphanedResource
 
 	for _, volume := range volumes {
 		if aws.isDiskOrphaned(volume) {
@@ -1721,7 +1722,7 @@ func (aws *AWS) GetOrphanedResources() ([]types.OrphanedResource, error) {
 				url = "https://console.aws.amazon.com/ec2/home?#Volumes:sort=desc:createTime"
 			}
 
-			or := types.OrphanedResource{
+			or := models.OrphanedResource{
 				Kind:        "disk",
 				Region:      zone,
 				Size:        &volumeSize,
@@ -1750,7 +1751,7 @@ func (aws *AWS) GetOrphanedResources() ([]types.OrphanedResource, error) {
 				}
 			}
 
-			or := types.OrphanedResource{
+			or := models.OrphanedResource{
 				Kind:        "address",
 				Address:     *address.PublicIp,
 				Description: desc,
@@ -2153,14 +2154,14 @@ func (aws *AWS) parseSpotData(bucket string, prefix string, projectID string, re
 	}
 	lso, err := cli.ListObjects(context.TODO(), ls)
 	if err != nil {
-		aws.serviceAccountChecks.Set("bucketList", &types.ServiceAccountCheck{
+		aws.serviceAccountChecks.Set("bucketList", &models.ServiceAccountCheck{
 			Message:        "Bucket List Permissions Available",
 			Status:         false,
 			AdditionalInfo: err.Error(),
 		})
 		return nil, err
 	} else {
-		aws.serviceAccountChecks.Set("bucketList", &types.ServiceAccountCheck{
+		aws.serviceAccountChecks.Set("bucketList", &models.ServiceAccountCheck{
 			Message: "Bucket List Permissions Available",
 			Status:  true,
 		})
@@ -2205,14 +2206,14 @@ func (aws *AWS) parseSpotData(bucket string, prefix string, projectID string, re
 		buf := manager.NewWriteAtBuffer([]byte{})
 		_, err := downloader.Download(context.TODO(), buf, getObj)
 		if err != nil {
-			aws.serviceAccountChecks.Set("objectList", &types.ServiceAccountCheck{
+			aws.serviceAccountChecks.Set("objectList", &models.ServiceAccountCheck{
 				Message:        "Object Get Permissions Available",
 				Status:         false,
 				AdditionalInfo: err.Error(),
 			})
 			return nil, err
 		} else {
-			aws.serviceAccountChecks.Set("objectList", &types.ServiceAccountCheck{
+			aws.serviceAccountChecks.Set("objectList", &models.ServiceAccountCheck{
 				Message: "Object Get Permissions Available",
 				Status:  true,
 			})
@@ -2283,11 +2284,11 @@ func (aws *AWS) parseSpotData(bucket string, prefix string, projectID string, re
 }
 
 // ApplyReservedInstancePricing TODO
-func (aws *AWS) ApplyReservedInstancePricing(nodes map[string]*types.Node) {
+func (aws *AWS) ApplyReservedInstancePricing(nodes map[string]*models.Node) {
 
 }
 
-func (aws *AWS) ServiceAccountStatus() *types.ServiceAccountStatus {
+func (aws *AWS) ServiceAccountStatus() *models.ServiceAccountStatus {
 	return aws.serviceAccountChecks.GetStatus()
 }
 

+ 3 - 3
pkg/cloud/awsprovider_test.go

@@ -8,7 +8,7 @@ import (
 	"reflect"
 	"testing"
 
-	"github.com/opencost/opencost/pkg/cloud/types"
+	"github.com/opencost/opencost/pkg/cloud/models"
 )
 
 func Test_awsKey_getUsageType(t *testing.T) {
@@ -335,7 +335,7 @@ func Test_populate_pricing(t *testing.T) {
 				},
 			},
 		},
-		PV: &types.PV{
+		PV: &models.PV{
 			Cost:       "0.00010958904109589041",
 			CostPerIO:  "",
 			Class:      "gp3",
@@ -474,7 +474,7 @@ func Test_populate_pricing(t *testing.T) {
 				},
 			},
 		},
-		PV: &types.PV{
+		PV: &models.PV{
 			Cost:       "0.0007276712328767123",
 			CostPerIO:  "",
 			Class:      "gp3",

+ 50 - 49
pkg/cloud/azure/azureprovider.go

@@ -21,7 +21,8 @@ import (
 	"github.com/Azure/go-autorest/autorest/azure"
 	"github.com/Azure/go-autorest/autorest/azure/auth"
 
-	"github.com/opencost/opencost/pkg/cloud/types"
+	"github.com/opencost/opencost/pkg/cloud/models"
+	"github.com/opencost/opencost/pkg/cloud/utils"
 	"github.com/opencost/opencost/pkg/clustercache"
 	"github.com/opencost/opencost/pkg/env"
 	"github.com/opencost/opencost/pkg/kubecost"
@@ -387,16 +388,16 @@ type AzureRetailPricingAttributes struct {
 
 // AzurePricing either contains a Node or PV
 type AzurePricing struct {
-	Node *types.Node
-	PV   *types.PV
+	Node *models.Node
+	PV   *models.PV
 }
 
 type Azure struct {
 	Pricing                 map[string]*AzurePricing
 	DownloadPricingDataLock sync.RWMutex
 	Clientset               clustercache.ClusterCache
-	Config                  types.ProviderConfig
-	ServiceAccountChecks    *types.ServiceAccountChecks
+	Config                  models.ProviderConfig
+	ServiceAccountChecks    *models.ServiceAccountChecks
 	ClusterAccountID        string
 	ClusterRegion           string
 
@@ -532,7 +533,7 @@ func (ask *AzureServiceKey) IsValid() bool {
 }
 
 // Loads the azure authentication via configuration or a secret set at install time.
-func (az *Azure) getAzureRateCardAuth(forceReload bool, cp *types.CustomPricing) (subscriptionID, clientID, clientSecret, tenantID string) {
+func (az *Azure) getAzureRateCardAuth(forceReload bool, cp *models.CustomPricing) (subscriptionID, clientID, clientSecret, tenantID string) {
 	// 1. Check for secret (secret values will always be used if they are present)
 	s, _ := az.loadAzureAuthSecret(forceReload)
 	if s != nil && s.IsValid() {
@@ -562,7 +563,7 @@ func (az *Azure) getAzureRateCardAuth(forceReload bool, cp *types.CustomPricing)
 }
 
 // GetAzureStorageConfig retrieves storage config from secret and sets default values
-func (az *Azure) GetAzureStorageConfig(forceReload bool, cp *types.CustomPricing) (*AzureStorageConfig, error) {
+func (az *Azure) GetAzureStorageConfig(forceReload bool, cp *models.CustomPricing) (*AzureStorageConfig, error) {
 	// default subscription id
 	defaultSubscriptionID := cp.AzureSubscriptionID
 
@@ -578,7 +579,7 @@ func (az *Azure) GetAzureStorageConfig(forceReload bool, cp *types.CustomPricing
 
 	// check for required fields
 	if asc != nil && asc.AccessKey != "" && asc.AccountName != "" && asc.ContainerName != "" && asc.SubscriptionId != "" {
-		az.ServiceAccountChecks.Set("hasStorage", &types.ServiceAccountCheck{
+		az.ServiceAccountChecks.Set("hasStorage", &models.ServiceAccountCheck{
 			Message: "Azure Storage Config exists",
 			Status:  true,
 		})
@@ -597,7 +598,7 @@ func (az *Azure) GetAzureStorageConfig(forceReload bool, cp *types.CustomPricing
 		}
 		// check for required fields
 		if asc.AccessKey != "" && asc.AccountName != "" && asc.ContainerName != "" && asc.SubscriptionId != "" {
-			az.ServiceAccountChecks.Set("hasStorage", &types.ServiceAccountCheck{
+			az.ServiceAccountChecks.Set("hasStorage", &models.ServiceAccountCheck{
 				Message: "Azure Storage Config exists",
 				Status:  true,
 			})
@@ -606,7 +607,7 @@ func (az *Azure) GetAzureStorageConfig(forceReload bool, cp *types.CustomPricing
 		}
 	}
 
-	az.ServiceAccountChecks.Set("hasStorage", &types.ServiceAccountCheck{
+	az.ServiceAccountChecks.Set("hasStorage", &models.ServiceAccountCheck{
 		Message: "Azure Storage Config exists",
 		Status:  false,
 	})
@@ -623,12 +624,12 @@ func (az *Azure) loadAzureAuthSecret(force bool) (*AzureServiceKey, error) {
 	}
 	az.loadedAzureSecret = true
 
-	exists, err := fileutil.FileExists(types.AuthSecretPath)
+	exists, err := fileutil.FileExists(models.AuthSecretPath)
 	if !exists || err != nil {
-		return nil, fmt.Errorf("Failed to locate service account file: %s", types.AuthSecretPath)
+		return nil, fmt.Errorf("Failed to locate service account file: %s", models.AuthSecretPath)
 	}
 
-	result, err := os.ReadFile(types.AuthSecretPath)
+	result, err := os.ReadFile(models.AuthSecretPath)
 	if err != nil {
 		return nil, err
 	}
@@ -652,12 +653,12 @@ func (az *Azure) loadAzureStorageConfig(force bool) (*AzureStorageConfig, error)
 	}
 	az.loadedAzureStorageConfigSecret = true
 
-	exists, err := fileutil.FileExists(types.StorageConfigSecretPath)
+	exists, err := fileutil.FileExists(models.StorageConfigSecretPath)
 	if !exists || err != nil {
-		return nil, fmt.Errorf("Failed to locate azure storage config file: %s", types.StorageConfigSecretPath)
+		return nil, fmt.Errorf("Failed to locate azure storage config file: %s", models.StorageConfigSecretPath)
 	}
 
-	result, err := os.ReadFile(types.StorageConfigSecretPath)
+	result, err := os.ReadFile(models.StorageConfigSecretPath)
 	if err != nil {
 		return nil, err
 	}
@@ -672,7 +673,7 @@ func (az *Azure) loadAzureStorageConfig(force bool) (*AzureStorageConfig, error)
 	return &asc, nil
 }
 
-func (az *Azure) GetKey(labels map[string]string, n *v1.Node) types.Key {
+func (az *Azure) GetKey(labels map[string]string, n *v1.Node) models.Key {
 	cfg, err := az.GetConfig()
 	if err != nil {
 		log.Infof("Error loading azure custom pricing information")
@@ -958,7 +959,7 @@ func convertMeterToPricings(info commerce.MeterInfo, regions map[string]string,
 				log.Debugf("Adding PV.Key: %s, Cost: %s", key, priceStr)
 				return map[string]*AzurePricing{
 					key: {
-						PV: &types.PV{
+						PV: &models.PV{
 							Cost:   priceStr,
 							Region: region,
 						},
@@ -1008,7 +1009,7 @@ func convertMeterToPricings(info commerce.MeterInfo, regions map[string]string,
 
 		key := fmt.Sprintf("%s,%s,%s", region, instanceType, usageType)
 		pricing := &AzurePricing{
-			Node: &types.Node{
+			Node: &models.Node{
 				Cost:         priceStr,
 				BaseCPUPrice: baseCPUPrice,
 				UsageType:    usageType,
@@ -1029,7 +1030,7 @@ func addAzureFilePricing(prices map[string]*AzurePricing, regions map[string]str
 		key := region + "," + AzureFileStandardStorageClass
 		log.Debugf("Adding PV.Key: %s, Cost: %s", key, zeroPrice)
 		prices[key] = &AzurePricing{
-			PV: &types.PV{
+			PV: &models.PV{
 				Cost:   zeroPrice,
 				Region: region,
 			},
@@ -1076,7 +1077,7 @@ func (az *Azure) AllNodePricing() (interface{}, error) {
 }
 
 // NodePricing returns Azure pricing data for a single node
-func (az *Azure) NodePricing(key types.Key) (*types.Node, error) {
+func (az *Azure) NodePricing(key models.Key) (*models.Node, error) {
 	az.DownloadPricingDataLock.RLock()
 	defer az.DownloadPricingDataLock.RUnlock()
 	pricingDataExists := true
@@ -1113,7 +1114,7 @@ func (az *Azure) NodePricing(key types.Key) (*types.Node, error) {
 			if azKey.isValidGPUNode() {
 				gpu = "1"
 			}
-			spotNode := &types.Node{
+			spotNode := &models.Node{
 				Cost:      spotCost,
 				UsageType: "spot",
 				GPU:       gpu,
@@ -1144,7 +1145,7 @@ func (az *Azure) NodePricing(key types.Key) (*types.Node, error) {
 
 	// GPU Node
 	if azKey.isValidGPUNode() {
-		return &types.Node{
+		return &models.Node{
 			VCPUCost:         c.CPU,
 			RAMCost:          c.RAM,
 			UsesBaseCPUPrice: true,
@@ -1157,14 +1158,14 @@ func (az *Azure) NodePricing(key types.Key) (*types.Node, error) {
 	// scheduled to this node. Azure does not charge for this node. Set costs to
 	// zero.
 	if azKey.Labels["kubernetes.io/hostname"] == "virtual-node-aci-linux" {
-		return &types.Node{
+		return &models.Node{
 			VCPUCost: "0",
 			RAMCost:  "0",
 		}, nil
 	}
 
 	// Regular Node
-	return &types.Node{
+	return &models.Node{
 		VCPUCost:         c.CPU,
 		RAMCost:          c.RAM,
 		UsesBaseCPUPrice: true,
@@ -1172,7 +1173,7 @@ func (az *Azure) NodePricing(key types.Key) (*types.Node, error) {
 }
 
 // Stubbed NetworkPricing for Azure. Pull directly from azure.json for now
-func (az *Azure) NetworkPricing() (*types.Network, error) {
+func (az *Azure) NetworkPricing() (*models.Network, error) {
 	cpricing, err := az.Config.GetCustomPricingData()
 	if err != nil {
 		return nil, err
@@ -1190,7 +1191,7 @@ func (az *Azure) NetworkPricing() (*types.Network, error) {
 		return nil, err
 	}
 
-	return &types.Network{
+	return &models.Network{
 		ZoneNetworkEgressCost:     znec,
 		RegionNetworkEgressCost:   rnec,
 		InternetNetworkEgressCost: inec,
@@ -1201,8 +1202,8 @@ func (az *Azure) NetworkPricing() (*types.Network, error) {
 // services will be that of a standard static public IP https://azure.microsoft.com/en-us/pricing/details/ip-addresses/.
 // Azure still has load balancers which follow the standard pricing scheme based on rules
 // https://azure.microsoft.com/en-us/pricing/details/load-balancer/, they are created on a per-cluster basis.
-func (azr *Azure) LoadBalancerPricing() (*types.LoadBalancer, error) {
-	return &types.LoadBalancer{
+func (azr *Azure) LoadBalancerPricing() (*models.LoadBalancer, error) {
+	return &models.LoadBalancer{
 		Cost: 0.005,
 	}, nil
 }
@@ -1215,7 +1216,7 @@ type azurePvKey struct {
 	ProviderId             string
 }
 
-func (az *Azure) GetPVKey(pv *v1.PersistentVolume, parameters map[string]string, defaultRegion string) types.PVKey {
+func (az *Azure) GetPVKey(pv *v1.PersistentVolume, parameters map[string]string, defaultRegion string) models.PVKey {
 	providerID := ""
 	if pv.Spec.AzureDisk != nil {
 		providerID = pv.Spec.AzureDisk.DiskName
@@ -1345,13 +1346,13 @@ func (az *Azure) isDiskOrphaned(disk *compute.Disk) bool {
 	return disk.DiskState == "Unattached" || disk.DiskState == "Reserved"
 }
 
-func (az *Azure) GetOrphanedResources() ([]types.OrphanedResource, error) {
+func (az *Azure) GetOrphanedResources() ([]models.OrphanedResource, error) {
 	disks, err := az.getDisks()
 	if err != nil {
 		return nil, err
 	}
 
-	var orphanedResources []types.OrphanedResource
+	var orphanedResources []models.OrphanedResource
 
 	for _, d := range disks {
 		if az.isDiskOrphaned(d) {
@@ -1384,7 +1385,7 @@ func (az *Azure) GetOrphanedResources() ([]types.OrphanedResource, error) {
 				}
 			}
 
-			or := types.OrphanedResource{
+			or := models.OrphanedResource{
 				Kind:        "disk",
 				Region:      diskRegion,
 				Description: desc,
@@ -1444,12 +1445,12 @@ func (az *Azure) ClusterInfo() (map[string]string, error) {
 
 }
 
-func (az *Azure) UpdateConfigFromConfigMap(a map[string]string) (*types.CustomPricing, error) {
+func (az *Azure) UpdateConfigFromConfigMap(a map[string]string) (*models.CustomPricing, error) {
 	return az.Config.UpdateFromMap(a)
 }
 
-func (az *Azure) UpdateConfig(r io.Reader, updateType string) (*types.CustomPricing, error) {
-	return az.Config.Update(func(c *types.CustomPricing) error {
+func (az *Azure) UpdateConfig(r io.Reader, updateType string) (*models.CustomPricing, error) {
+	return az.Config.Update(func(c *models.CustomPricing) error {
 		if updateType == AzureStorageUpdateType {
 			asc := &AzureStorageConfig{}
 			err := json.NewDecoder(r).Decode(&asc)
@@ -1482,10 +1483,10 @@ func (az *Azure) UpdateConfig(r io.Reader, updateType string) (*types.CustomPric
 
 			for k, v := range a {
 				// Just so we consistently supply / receive the same values, uppercase the first letter.
-				kUpper := types.ToTitle.String(k)
+				kUpper := utils.ToTitle.String(k)
 				vstr, ok := v.(string)
 				if ok {
-					err := types.SetCustomPricingField(c, kUpper, vstr)
+					err := models.SetCustomPricingField(c, kUpper, vstr)
 					if err != nil {
 						return fmt.Errorf("error setting custom pricing field on AzureStorageConfig: %s", err)
 					}
@@ -1496,7 +1497,7 @@ func (az *Azure) UpdateConfig(r io.Reader, updateType string) (*types.CustomPric
 		}
 
 		if env.IsRemoteEnabled() {
-			err := types.UpdateClusterMeta(env.GetClusterID(), c.ClusterName)
+			err := utils.UpdateClusterMeta(env.GetClusterID(), c.ClusterName)
 			if err != nil {
 				return fmt.Errorf("error updating cluster metadata: %s", err)
 			}
@@ -1506,7 +1507,7 @@ func (az *Azure) UpdateConfig(r io.Reader, updateType string) (*types.CustomPric
 	})
 }
 
-func (az *Azure) GetConfig() (*types.CustomPricing, error) {
+func (az *Azure) GetConfig() (*models.CustomPricing, error) {
 	c, err := az.Config.GetCustomPricingData()
 	if err != nil {
 		return nil, err
@@ -1528,7 +1529,7 @@ func (az *Azure) GetConfig() (*types.CustomPricing, error) {
 		c.AzureOfferDurableID = "MS-AZR-0003p"
 	}
 	if c.ShareTenancyCosts == "" {
-		c.ShareTenancyCosts = types.DefaultShareTenancyCost
+		c.ShareTenancyCosts = models.DefaultShareTenancyCost
 	}
 	if c.SpotLabel == "" {
 		c.SpotLabel = defaultSpotLabel
@@ -1539,18 +1540,18 @@ func (az *Azure) GetConfig() (*types.CustomPricing, error) {
 	return c, nil
 }
 
-func (az *Azure) ApplyReservedInstancePricing(nodes map[string]*types.Node) {
+func (az *Azure) ApplyReservedInstancePricing(nodes map[string]*models.Node) {
 
 }
 
-func (az *Azure) PVPricing(pvk types.PVKey) (*types.PV, error) {
+func (az *Azure) PVPricing(pvk models.PVKey) (*models.PV, error) {
 	az.DownloadPricingDataLock.RLock()
 	defer az.DownloadPricingDataLock.RUnlock()
 
 	pricing, ok := az.Pricing[pvk.Features()]
 	if !ok {
 		log.Debugf("Persistent Volume pricing not found for %s: %s", pvk.GetStorageClass(), pvk.Features())
-		return &types.PV{}, nil
+		return &models.PV{}, nil
 	}
 	return pricing.PV, nil
 }
@@ -1559,7 +1560,7 @@ func (az *Azure) GetLocalStorageQuery(window, offset time.Duration, rate bool, u
 	return ""
 }
 
-func (az *Azure) ServiceAccountStatus() *types.ServiceAccountStatus {
+func (az *Azure) ServiceAccountStatus() *models.ServiceAccountStatus {
 	return az.ServiceAccountChecks.GetStatus()
 }
 
@@ -1569,15 +1570,15 @@ const (
 )
 
 // PricingSourceStatus returns the status of the rate card api
-func (az *Azure) PricingSourceStatus() map[string]*types.PricingSource {
+func (az *Azure) PricingSourceStatus() map[string]*models.PricingSource {
 	az.DownloadPricingDataLock.Lock()
 	defer az.DownloadPricingDataLock.Unlock()
-	sources := make(map[string]*types.PricingSource)
+	sources := make(map[string]*models.PricingSource)
 	errMsg := ""
 	if az.rateCardPricingError != nil {
 		errMsg = az.rateCardPricingError.Error()
 	}
-	rcps := &types.PricingSource{
+	rcps := &models.PricingSource{
 		Name:    rateCardPricingSource,
 		Enabled: az.pricingSource == rateCardPricingSource,
 		Error:   errMsg,
@@ -1595,7 +1596,7 @@ func (az *Azure) PricingSourceStatus() map[string]*types.PricingSource {
 	if az.priceSheetPricingError != nil {
 		errMsg = az.priceSheetPricingError.Error()
 	}
-	psps := &types.PricingSource{
+	psps := &models.PricingSource{
 		Name:    priceSheetPricingSource,
 		Enabled: az.pricingSource == priceSheetPricingSource,
 		Error:   errMsg,

+ 4 - 4
pkg/cloud/azure/azureprovider_test.go

@@ -6,7 +6,7 @@ import (
 	"github.com/Azure/azure-sdk-for-go/services/preview/commerce/mgmt/2015-06-01-preview/commerce"
 	"github.com/stretchr/testify/require"
 
-	"github.com/opencost/opencost/pkg/cloud/types"
+	"github.com/opencost/opencost/pkg/cloud/models"
 )
 
 func TestParseAzureSubscriptionID(t *testing.T) {
@@ -73,7 +73,7 @@ func TestConvertMeterToPricings(t *testing.T) {
 
 		expected := map[string]*AzurePricing{
 			"useast,premium_ssd": {
-				PV: &types.PV{Cost: "0.085616", Region: "useast"},
+				PV: &models.PV{Cost: "0.085616", Region: "useast"},
 			},
 		}
 		require.Equal(t, expected, results)
@@ -86,10 +86,10 @@ func TestConvertMeterToPricings(t *testing.T) {
 
 		expected := map[string]*AzurePricing{
 			"japanwest,Standard_E96a_v4,preemptible": {
-				Node: &types.Node{Cost: "10.000000", BaseCPUPrice: "0.30000", UsageType: "preemptible"},
+				Node: &models.Node{Cost: "10.000000", BaseCPUPrice: "0.30000", UsageType: "preemptible"},
 			},
 			"japanwest,Standard_E96as_v4,preemptible": {
-				Node: &types.Node{Cost: "10.000000", BaseCPUPrice: "0.30000", UsageType: "preemptible"},
+				Node: &models.Node{Cost: "10.000000", BaseCPUPrice: "0.30000", UsageType: "preemptible"},
 			},
 		}
 		require.Equal(t, expected, results)

+ 8 - 8
pkg/cloud/azure/downloader_test.go

@@ -7,7 +7,7 @@ import (
 	"testing"
 
 	"github.com/Azure/azure-sdk-for-go/profiles/2020-09-01/commerce/mgmt/commerce"
-	"github.com/opencost/opencost/pkg/cloud/types"
+	"github.com/opencost/opencost/pkg/cloud/models"
 	"github.com/stretchr/testify/require"
 )
 
@@ -28,10 +28,10 @@ func TestDownloader(t *testing.T) {
 		// Units and prices are normalised.
 		// Info for saving plans and other offers is skipped.
 		expected := map[string]*AzurePricing{
-			"DC96as_v4 1 Hour": {Node: &types.Node{Cost: "10.505"}},
-			"DC2as_v4 1 Hour":  {Node: &types.Node{Cost: "0.219"}},
-			"VM1 1 Hour":       {Node: &types.Node{Cost: "1.0"}},
-			"VM2 1 Hour":       {Node: &types.Node{Cost: "2.0"}},
+			"DC96as_v4 1 Hour": {Node: &models.Node{Cost: "10.505"}},
+			"DC2as_v4 1 Hour":  {Node: &models.Node{Cost: "0.219"}},
+			"VM1 1 Hour":       {Node: &models.Node{Cost: "1.0"}},
+			"VM2 1 Hour":       {Node: &models.Node{Cost: "2.0"}},
 		}
 		require.Equal(t, expected, results)
 	})
@@ -70,15 +70,15 @@ func convertMeter(info commerce.MeterInfo) (map[string]*AzurePricing, error) {
 		return nil, nil
 	case "multiple-prices":
 		return map[string]*AzurePricing{
-			"VM1 1 Hour": {Node: &types.Node{Cost: "1.0"}},
-			"VM2 1 Hour": {Node: &types.Node{Cost: "2.0"}},
+			"VM1 1 Hour": {Node: &models.Node{Cost: "1.0"}},
+			"VM2 1 Hour": {Node: &models.Node{Cost: "2.0"}},
 		}, nil
 	case "error":
 		return nil, fmt.Errorf("there was an error handling this row!")
 	default:
 		return map[string]*AzurePricing{
 			*info.MeterName + " " + *info.Unit: {
-				Node: &types.Node{Cost: fmt.Sprintf("%0.3f", *info.MeterRates["0"])},
+				Node: &models.Node{Cost: fmt.Sprintf("%0.3f", *info.MeterRates["0"])},
 			},
 		}, nil
 	}

+ 17 - 17
pkg/cloud/csvprovider.go

@@ -10,7 +10,7 @@ import (
 	"sync"
 	"time"
 
-	"github.com/opencost/opencost/pkg/cloud/types"
+	"github.com/opencost/opencost/pkg/cloud/models"
 	"github.com/opencost/opencost/pkg/env"
 	"github.com/opencost/opencost/pkg/util"
 
@@ -223,31 +223,31 @@ func (k *csvKey) ID() string {
 	return k.ProviderID
 }
 
-func (c *CSVProvider) NodePricing(key types.Key) (*types.Node, error) {
+func (c *CSVProvider) NodePricing(key models.Key) (*models.Node, error) {
 	c.DownloadPricingDataLock.RLock()
 	defer c.DownloadPricingDataLock.RUnlock()
-	var node *types.Node
+	var node *models.Node
 	if p, ok := c.Pricing[key.ID()]; ok {
-		node = &types.Node{
+		node = &models.Node{
 			Cost:        p.MarketPriceHourly,
-			PricingType: types.CsvExact,
+			PricingType: models.CsvExact,
 		}
 	}
 	s := strings.Split(key.ID(), ",") // Try without a region to be sure
 	if len(s) == 2 {
 		if p, ok := c.Pricing[s[1]]; ok {
-			node = &types.Node{
+			node = &models.Node{
 				Cost:        p.MarketPriceHourly,
-				PricingType: types.CsvExact,
+				PricingType: models.CsvExact,
 			}
 		}
 	}
 	classKey := key.Features() // Use node attributes to try and do a class match
 	if cost, ok := c.NodeClassPricing[classKey]; ok {
 		log.Infof("Unable to find provider ID `%s`, using features:`%s`", key.ID(), key.Features())
-		node = &types.Node{
+		node = &models.Node{
 			Cost:        fmt.Sprintf("%f", cost),
-			PricingType: types.CsvClass,
+			PricingType: models.CsvClass,
 		}
 	}
 
@@ -347,7 +347,7 @@ func PVValueFromMapField(m string, n *v1.PersistentVolume) string {
 	}
 }
 
-func (c *CSVProvider) GetKey(l map[string]string, n *v1.Node) types.Key {
+func (c *CSVProvider) GetKey(l map[string]string, n *v1.Node) models.Key {
 	id := NodeValueFromMapField(c.NodeMapField, n, c.UsesRegion)
 	var gpuCount int64
 	gpuCount = 0
@@ -383,7 +383,7 @@ func (key *csvPVKey) Features() string {
 	return key.ProviderID
 }
 
-func (c *CSVProvider) GetPVKey(pv *v1.PersistentVolume, parameters map[string]string, defaultRegion string) types.PVKey {
+func (c *CSVProvider) GetPVKey(pv *v1.PersistentVolume, parameters map[string]string, defaultRegion string) models.PVKey {
 	id := PVValueFromMapField(c.PVMapField, pv)
 	return &csvPVKey{
 		Labels:                 pv.Labels,
@@ -395,22 +395,22 @@ func (c *CSVProvider) GetPVKey(pv *v1.PersistentVolume, parameters map[string]st
 	}
 }
 
-func (c *CSVProvider) PVPricing(pvk types.PVKey) (*types.PV, error) {
+func (c *CSVProvider) PVPricing(pvk models.PVKey) (*models.PV, error) {
 	c.DownloadPricingDataLock.RLock()
 	defer c.DownloadPricingDataLock.RUnlock()
 	pricing, ok := c.PricingPV[pvk.Features()]
 	if !ok {
 		log.Infof("Persistent Volume pricing not found for %s: %s", pvk.GetStorageClass(), pvk.Features())
-		return &types.PV{}, nil
+		return &models.PV{}, nil
 	}
-	return &types.PV{
+	return &models.PV{
 		Cost: pricing.MarketPriceHourly,
 	}, nil
 }
 
-func (c *CSVProvider) ServiceAccountStatus() *types.ServiceAccountStatus {
-	return &types.ServiceAccountStatus{
-		Checks: []*types.ServiceAccountCheck{},
+func (c *CSVProvider) ServiceAccountStatus() *models.ServiceAccountStatus {
+	return &models.ServiceAccountStatus{
+		Checks: []*models.ServiceAccountCheck{},
 	}
 }
 

+ 26 - 25
pkg/cloud/customprovider.go

@@ -8,7 +8,8 @@ import (
 	"sync"
 	"time"
 
-	"github.com/opencost/opencost/pkg/cloud/types"
+	"github.com/opencost/opencost/pkg/cloud/models"
+	"github.com/opencost/opencost/pkg/cloud/utils"
 	"github.com/opencost/opencost/pkg/clustercache"
 	"github.com/opencost/opencost/pkg/env"
 	"github.com/opencost/opencost/pkg/kubecost"
@@ -60,7 +61,7 @@ func (*CustomProvider) GetLocalStorageQuery(window, offset time.Duration, rate b
 	return ""
 }
 
-func (cp *CustomProvider) GetConfig() (*types.CustomPricing, error) {
+func (cp *CustomProvider) GetConfig() (*models.CustomPricing, error) {
 	return cp.Config.GetCustomPricingData()
 }
 
@@ -68,15 +69,15 @@ func (*CustomProvider) GetManagementPlatform() (string, error) {
 	return "", nil
 }
 
-func (*CustomProvider) ApplyReservedInstancePricing(nodes map[string]*types.Node) {
+func (*CustomProvider) ApplyReservedInstancePricing(nodes map[string]*models.Node) {
 
 }
 
-func (cp *CustomProvider) UpdateConfigFromConfigMap(a map[string]string) (*types.CustomPricing, error) {
+func (cp *CustomProvider) UpdateConfigFromConfigMap(a map[string]string) (*models.CustomPricing, error) {
 	return cp.Config.UpdateFromMap(a)
 }
 
-func (cp *CustomProvider) UpdateConfig(r io.Reader, updateType string) (*types.CustomPricing, error) {
+func (cp *CustomProvider) UpdateConfig(r io.Reader, updateType string) (*models.CustomPricing, error) {
 	// Parse config updates from reader
 	a := make(map[string]interface{})
 	err := json.NewDecoder(r).Decode(&a)
@@ -85,12 +86,12 @@ func (cp *CustomProvider) UpdateConfig(r io.Reader, updateType string) (*types.C
 	}
 
 	// Update Config
-	c, err := cp.Config.Update(func(c *types.CustomPricing) error {
+	c, err := cp.Config.Update(func(c *models.CustomPricing) error {
 		for k, v := range a {
-			kUpper := types.ToTitle.String(k) // Just so we consistently supply / receive the same values, uppercase the first letter.
+			kUpper := utils.ToTitle.String(k) // Just so we consistently supply / receive the same values, uppercase the first letter.
 			vstr, ok := v.(string)
 			if ok {
-				err := types.SetCustomPricingField(c, kUpper, vstr)
+				err := models.SetCustomPricingField(c, kUpper, vstr)
 				if err != nil {
 					return err
 				}
@@ -134,7 +135,7 @@ func (*CustomProvider) GetDisks() ([]byte, error) {
 	return nil, nil
 }
 
-func (*CustomProvider) GetOrphanedResources() ([]types.OrphanedResource, error) {
+func (*CustomProvider) GetOrphanedResources() ([]models.OrphanedResource, error) {
 	return nil, errors.New("not implemented")
 }
 
@@ -145,7 +146,7 @@ func (cp *CustomProvider) AllNodePricing() (interface{}, error) {
 	return cp.Pricing, nil
 }
 
-func (cp *CustomProvider) NodePricing(key types.Key) (*types.Node, error) {
+func (cp *CustomProvider) NodePricing(key models.Key) (*models.Node, error) {
 	cp.DownloadPricingDataLock.RLock()
 	defer cp.DownloadPricingDataLock.RUnlock()
 
@@ -173,7 +174,7 @@ func (cp *CustomProvider) NodePricing(key types.Key) (*types.Node, error) {
 		gpuCost = pricing.GPU
 	}
 
-	return &types.Node{
+	return &models.Node{
 		VCPUCost: cpuCost,
 		RAMCost:  ramCost,
 		GPUCost:  gpuCost,
@@ -213,7 +214,7 @@ func (cp *CustomProvider) DownloadPricingData() error {
 	return nil
 }
 
-func (cp *CustomProvider) GetKey(labels map[string]string, n *v1.Node) types.Key {
+func (cp *CustomProvider) GetKey(labels map[string]string, n *v1.Node) models.Key {
 	return &customProviderKey{
 		SpotLabel:      cp.SpotLabel,
 		SpotLabelValue: cp.SpotLabelValue,
@@ -226,7 +227,7 @@ func (cp *CustomProvider) GetKey(labels map[string]string, n *v1.Node) types.Key
 // ExternalAllocations represents tagged assets outside the scope of kubernetes.
 // "start" and "end" are dates of the format YYYY-MM-DD
 // "aggregator" is the tag used to determine how to allocate those assets, ie namespace, pod, etc.
-func (*CustomProvider) ExternalAllocations(start string, end string, aggregator []string, filterType string, filterValue string, crossCluster bool) ([]*types.OutOfClusterAllocation, error) {
+func (*CustomProvider) ExternalAllocations(start string, end string, aggregator []string, filterType string, filterValue string, crossCluster bool) ([]*models.OutOfClusterAllocation, error) {
 	return nil, nil // TODO: transform the QuerySQL lines into the new OutOfClusterAllocation Struct
 }
 
@@ -234,17 +235,17 @@ func (*CustomProvider) QuerySQL(query string) ([]byte, error) {
 	return nil, nil
 }
 
-func (cp *CustomProvider) PVPricing(pvk types.PVKey) (*types.PV, error) {
+func (cp *CustomProvider) PVPricing(pvk models.PVKey) (*models.PV, error) {
 	cpricing, err := cp.Config.GetCustomPricingData()
 	if err != nil {
 		return nil, err
 	}
-	return &types.PV{
+	return &models.PV{
 		Cost: cpricing.Storage,
 	}, nil
 }
 
-func (cp *CustomProvider) NetworkPricing() (*types.Network, error) {
+func (cp *CustomProvider) NetworkPricing() (*models.Network, error) {
 	cpricing, err := cp.Config.GetCustomPricingData()
 	if err != nil {
 		return nil, err
@@ -262,14 +263,14 @@ func (cp *CustomProvider) NetworkPricing() (*types.Network, error) {
 		return nil, err
 	}
 
-	return &types.Network{
+	return &models.Network{
 		ZoneNetworkEgressCost:     znec,
 		RegionNetworkEgressCost:   rnec,
 		InternetNetworkEgressCost: inec,
 	}, nil
 }
 
-func (cp *CustomProvider) LoadBalancerPricing() (*types.LoadBalancer, error) {
+func (cp *CustomProvider) LoadBalancerPricing() (*models.LoadBalancer, error) {
 	cpricing, err := cp.Config.GetCustomPricingData()
 	if err != nil {
 		return nil, err
@@ -295,12 +296,12 @@ func (cp *CustomProvider) LoadBalancerPricing() (*types.LoadBalancer, error) {
 	} else {
 		totalCost = fffrc*5 + afrc*(numForwardingRules-5) + lbidc*dataIngressGB
 	}
-	return &types.LoadBalancer{
+	return &models.LoadBalancer{
 		Cost: totalCost,
 	}, nil
 }
 
-func (*CustomProvider) GetPVKey(pv *v1.PersistentVolume, parameters map[string]string, defaultRegion string) types.PVKey {
+func (*CustomProvider) GetPVKey(pv *v1.PersistentVolume, parameters map[string]string, defaultRegion string) models.PVKey {
 	return &awsPVKey{
 		Labels:                 pv.Labels,
 		StorageClassName:       pv.Spec.StorageClassName,
@@ -331,14 +332,14 @@ func (cpk *customProviderKey) Features() string {
 	return "default" // TODO: multiple custom pricing support.
 }
 
-func (cp *CustomProvider) ServiceAccountStatus() *types.ServiceAccountStatus {
-	return &types.ServiceAccountStatus{
-		Checks: []*types.ServiceAccountCheck{},
+func (cp *CustomProvider) ServiceAccountStatus() *models.ServiceAccountStatus {
+	return &models.ServiceAccountStatus{
+		Checks: []*models.ServiceAccountCheck{},
 	}
 }
 
-func (cp *CustomProvider) PricingSourceStatus() map[string]*types.PricingSource {
-	return make(map[string]*types.PricingSource)
+func (cp *CustomProvider) PricingSourceStatus() map[string]*models.PricingSource {
+	return make(map[string]*models.PricingSource)
 }
 
 func (cp *CustomProvider) CombinedDiscountForNode(instanceType string, isPreemptible bool, defaultDiscount, negotiatedDiscount float64) float64 {

+ 49 - 48
pkg/cloud/gcpprovider.go

@@ -14,7 +14,8 @@ import (
 	"sync"
 	"time"
 
-	"github.com/opencost/opencost/pkg/cloud/types"
+	"github.com/opencost/opencost/pkg/cloud/models"
+	"github.com/opencost/opencost/pkg/cloud/utils"
 	"github.com/opencost/opencost/pkg/kubecost"
 
 	"github.com/opencost/opencost/pkg/clustercache"
@@ -154,7 +155,7 @@ func (gcp *GCP) GetLocalStorageQuery(window, offset time.Duration, rate bool, us
 	return fmt.Sprintf(fmtQuery, baseMetric, fmtWindow, fmtOffset, env.GetPromClusterLabel(), localStorageCost)
 }
 
-func (gcp *GCP) GetConfig() (*types.CustomPricing, error) {
+func (gcp *GCP) GetConfig() (*models.CustomPricing, error) {
 	c, err := gcp.Config.GetCustomPricingData()
 	if err != nil {
 		return nil, err
@@ -169,7 +170,7 @@ func (gcp *GCP) GetConfig() (*types.CustomPricing, error) {
 		c.CurrencyCode = "USD"
 	}
 	if c.ShareTenancyCosts == "" {
-		c.ShareTenancyCosts = types.DefaultShareTenancyCost
+		c.ShareTenancyCosts = models.DefaultShareTenancyCost
 	}
 	return c, nil
 }
@@ -211,7 +212,7 @@ func (*GCP) loadGCPAuthSecret() {
 		return
 	}
 
-	exists, err := fileutil.FileExists(types.AuthSecretPath)
+	exists, err := fileutil.FileExists(models.AuthSecretPath)
 	if !exists || err != nil {
 		errMessage := "Secret does not exist"
 		if err != nil {
@@ -222,7 +223,7 @@ func (*GCP) loadGCPAuthSecret() {
 		return
 	}
 
-	result, err := os.ReadFile(types.AuthSecretPath)
+	result, err := os.ReadFile(models.AuthSecretPath)
 	if err != nil {
 		log.Warnf("Failed to load auth secret, or was not mounted: %s", err.Error())
 		return
@@ -234,12 +235,12 @@ func (*GCP) loadGCPAuthSecret() {
 	}
 }
 
-func (gcp *GCP) UpdateConfigFromConfigMap(a map[string]string) (*types.CustomPricing, error) {
+func (gcp *GCP) UpdateConfigFromConfigMap(a map[string]string) (*models.CustomPricing, error) {
 	return gcp.Config.UpdateFromMap(a)
 }
 
-func (gcp *GCP) UpdateConfig(r io.Reader, updateType string) (*types.CustomPricing, error) {
-	return gcp.Config.Update(func(c *types.CustomPricing) error {
+func (gcp *GCP) UpdateConfig(r io.Reader, updateType string) (*models.CustomPricing, error) {
+	return gcp.Config.Update(func(c *models.CustomPricing) error {
 		if updateType == BigqueryUpdateType {
 			a := BigQueryConfig{}
 			err := json.NewDecoder(r).Decode(&a)
@@ -286,10 +287,10 @@ func (gcp *GCP) UpdateConfig(r io.Reader, updateType string) (*types.CustomPrici
 				return err
 			}
 			for k, v := range a {
-				kUpper := types.ToTitle.String(k) // Just so we consistently supply / receive the same values, uppercase the first letter.
+				kUpper := utils.ToTitle.String(k) // Just so we consistently supply / receive the same values, uppercase the first letter.
 				vstr, ok := v.(string)
 				if ok {
-					err := types.SetCustomPricingField(c, kUpper, vstr)
+					err := models.SetCustomPricingField(c, kUpper, vstr)
 					if err != nil {
 						return err
 					}
@@ -300,7 +301,7 @@ func (gcp *GCP) UpdateConfig(r io.Reader, updateType string) (*types.CustomPrici
 		}
 
 		if env.IsRemoteEnabled() {
-			err := types.UpdateClusterMeta(env.GetClusterID(), c.ClusterName)
+			err := utils.UpdateClusterMeta(env.GetClusterID(), c.ClusterName)
 			if err != nil {
 				return err
 			}
@@ -445,7 +446,7 @@ func (gcp *GCP) isDiskOrphaned(disk *compute.Disk) (bool, error) {
 	return true, nil
 }
 
-func (gcp *GCP) GetOrphanedResources() ([]types.OrphanedResource, error) {
+func (gcp *GCP) GetOrphanedResources() ([]models.OrphanedResource, error) {
 	disks, err := gcp.getAllDisks()
 	if err != nil {
 		return nil, err
@@ -456,7 +457,7 @@ func (gcp *GCP) GetOrphanedResources() ([]types.OrphanedResource, error) {
 		return nil, err
 	}
 
-	var orphanedResources []types.OrphanedResource
+	var orphanedResources []models.OrphanedResource
 
 	for _, diskList := range disks.Items {
 		if len(diskList.Disks) == 0 {
@@ -489,7 +490,7 @@ func (gcp *GCP) GetOrphanedResources() ([]types.OrphanedResource, error) {
 					zone = ""
 				}
 
-				or := types.OrphanedResource{
+				or := models.OrphanedResource{
 					Kind:        "disk",
 					Region:      zone,
 					Description: desc,
@@ -519,7 +520,7 @@ func (gcp *GCP) GetOrphanedResources() ([]types.OrphanedResource, error) {
 					region = ""
 				}
 
-				or := types.OrphanedResource{
+				or := models.OrphanedResource{
 					Kind:   "address",
 					Region: region,
 					Description: map[string]string{
@@ -573,8 +574,8 @@ type GCPPricing struct {
 	ServiceRegions      []string         `json:"serviceRegions"`
 	PricingInfo         []*PricingInfo   `json:"pricingInfo"`
 	ServiceProviderName string           `json:"serviceProviderName"`
-	Node                *types.Node      `json:"node"`
-	PV                  *types.PV        `json:"pv"`
+	Node                *models.Node     `json:"node"`
+	PV                  *models.PV       `json:"pv"`
 }
 
 // PricingInfo contains metadata about a cost.
@@ -616,7 +617,7 @@ type GCPResourceInfo struct {
 	UsageType          string `json:"usageType"`
 }
 
-func (gcp *GCP) parsePage(r io.Reader, inputKeys map[string]types.Key, pvKeys map[string]types.PVKey) (map[string]*GCPPricing, string, error) {
+func (gcp *GCP) parsePage(r io.Reader, inputKeys map[string]models.Key, pvKeys map[string]models.PVKey) (map[string]*GCPPricing, string, error) {
 	gcpPricingList := make(map[string]*GCPPricing)
 	var nextPageToken string
 	dec := json.NewDecoder(r)
@@ -657,7 +658,7 @@ func (gcp *GCP) parsePage(r io.Reader, inputKeys map[string]types.Key, pvKeys ma
 						region := sr
 						candidateKey := region + "," + "ssd"
 						if _, ok := pvKeys[candidateKey]; ok {
-							product.PV = &types.PV{
+							product.PV = &models.PV{
 								Cost: strconv.FormatFloat(hourlyPrice, 'f', -1, 64),
 							}
 							gcpPricingList[candidateKey] = product
@@ -679,7 +680,7 @@ func (gcp *GCP) parsePage(r io.Reader, inputKeys map[string]types.Key, pvKeys ma
 						region := sr
 						candidateKey := region + "," + "ssd" + "," + "regional"
 						if _, ok := pvKeys[candidateKey]; ok {
-							product.PV = &types.PV{
+							product.PV = &models.PV{
 								Cost: strconv.FormatFloat(hourlyPrice, 'f', -1, 64),
 							}
 							gcpPricingList[candidateKey] = product
@@ -700,7 +701,7 @@ func (gcp *GCP) parsePage(r io.Reader, inputKeys map[string]types.Key, pvKeys ma
 						region := sr
 						candidateKey := region + "," + "pdstandard"
 						if _, ok := pvKeys[candidateKey]; ok {
-							product.PV = &types.PV{
+							product.PV = &models.PV{
 								Cost: strconv.FormatFloat(hourlyPrice, 'f', -1, 64),
 							}
 							gcpPricingList[candidateKey] = product
@@ -721,7 +722,7 @@ func (gcp *GCP) parsePage(r io.Reader, inputKeys map[string]types.Key, pvKeys ma
 						region := sr
 						candidateKey := region + "," + "pdstandard" + "," + "regional"
 						if _, ok := pvKeys[candidateKey]; ok {
-							product.PV = &types.PV{
+							product.PV = &models.PV{
 								Cost: strconv.FormatFloat(hourlyPrice, 'f', -1, 64),
 							}
 							gcpPricingList[candidateKey] = product
@@ -839,7 +840,7 @@ func (gcp *GCP) parsePage(r io.Reader, inputKeys map[string]types.Key, pvKeys ma
 										pl.Node.GPUCost = strconv.FormatFloat(hourlyPrice, 'f', -1, 64)
 										pl.Node.GPU = "1"
 									} else {
-										product.Node = &types.Node{
+										product.Node = &models.Node{
 											GPUName: gpuType,
 											GPUCost: strconv.FormatFloat(hourlyPrice, 'f', -1, 64),
 											GPU:     "1",
@@ -881,7 +882,7 @@ func (gcp *GCP) parsePage(r io.Reader, inputKeys map[string]types.Key, pvKeys ma
 									gcpPricingList[candidateKey].Node.RAMCost = strconv.FormatFloat(hourlyPrice, 'f', -1, 64)
 								} else {
 									product = &GCPPricing{}
-									product.Node = &types.Node{
+									product.Node = &models.Node{
 										RAMCost: strconv.FormatFloat(hourlyPrice, 'f', -1, 64),
 									}
 									partialCPU, pcok := partialCPUMap[instanceType]
@@ -897,7 +898,7 @@ func (gcp *GCP) parsePage(r io.Reader, inputKeys map[string]types.Key, pvKeys ma
 								} else {
 									log.Infof("Adding RAM %f for %s", hourlyPrice, candidateKeyGPU)
 									product = &GCPPricing{}
-									product.Node = &types.Node{
+									product.Node = &models.Node{
 										RAMCost: strconv.FormatFloat(hourlyPrice, 'f', -1, 64),
 									}
 									partialCPU, pcok := partialCPUMap[instanceType]
@@ -913,7 +914,7 @@ func (gcp *GCP) parsePage(r io.Reader, inputKeys map[string]types.Key, pvKeys ma
 									gcpPricingList[candidateKey].Node.VCPUCost = strconv.FormatFloat(hourlyPrice, 'f', -1, 64)
 								} else {
 									product = &GCPPricing{}
-									product.Node = &types.Node{
+									product.Node = &models.Node{
 										VCPUCost: strconv.FormatFloat(hourlyPrice, 'f', -1, 64),
 									}
 									partialCPU, pcok := partialCPUMap[instanceType]
@@ -927,7 +928,7 @@ func (gcp *GCP) parsePage(r io.Reader, inputKeys map[string]types.Key, pvKeys ma
 									gcpPricingList[candidateKeyGPU].Node.VCPUCost = strconv.FormatFloat(hourlyPrice, 'f', -1, 64)
 								} else {
 									product = &GCPPricing{}
-									product.Node = &types.Node{
+									product.Node = &models.Node{
 										VCPUCost: strconv.FormatFloat(hourlyPrice, 'f', -1, 64),
 									}
 									partialCPU, pcok := partialCPUMap[instanceType]
@@ -960,7 +961,7 @@ func (gcp *GCP) parsePage(r io.Reader, inputKeys map[string]types.Key, pvKeys ma
 	return gcpPricingList, nextPageToken, nil
 }
 
-func (gcp *GCP) parsePages(inputKeys map[string]types.Key, pvKeys map[string]types.PVKey) (map[string]*GCPPricing, error) {
+func (gcp *GCP) parsePages(inputKeys map[string]models.Key, pvKeys map[string]models.PVKey) (map[string]*GCPPricing, error) {
 	var pages []map[string]*GCPPricing
 	c, err := gcp.GetConfig()
 	if err != nil {
@@ -1045,7 +1046,7 @@ func (gcp *GCP) DownloadPricingData() error {
 	gcp.BillingDataDataset = c.BillingDataDataset
 
 	nodeList := gcp.Clientset.GetAllNodes()
-	inputkeys := make(map[string]types.Key)
+	inputkeys := make(map[string]models.Key)
 
 	defaultRegion := "" // Sometimes, PVs may be missing the region label. In that case assume that they are in the same region as the nodes
 	for _, n := range nodeList {
@@ -1074,7 +1075,7 @@ func (gcp *GCP) DownloadPricingData() error {
 		}
 	}
 
-	pvkeys := make(map[string]types.PVKey)
+	pvkeys := make(map[string]models.PVKey)
 	for _, pv := range pvList {
 		params, ok := storageClassMap[pv.Spec.StorageClassName]
 		if !ok {
@@ -1108,19 +1109,19 @@ func (gcp *GCP) DownloadPricingData() error {
 	return nil
 }
 
-func (gcp *GCP) PVPricing(pvk types.PVKey) (*types.PV, error) {
+func (gcp *GCP) PVPricing(pvk models.PVKey) (*models.PV, error) {
 	gcp.DownloadPricingDataLock.RLock()
 	defer gcp.DownloadPricingDataLock.RUnlock()
 	pricing, ok := gcp.Pricing[pvk.Features()]
 	if !ok {
 		log.Infof("Persistent Volume pricing not found for %s: %s", pvk.GetStorageClass(), pvk.Features())
-		return &types.PV{}, nil
+		return &models.PV{}, nil
 	}
 	return pricing.PV, nil
 }
 
 // Stubbed NetworkPricing for GCP. Pull directly from gcp.json for now
-func (gcp *GCP) NetworkPricing() (*types.Network, error) {
+func (gcp *GCP) NetworkPricing() (*models.Network, error) {
 	cpricing, err := gcp.Config.GetCustomPricingData()
 	if err != nil {
 		return nil, err
@@ -1138,14 +1139,14 @@ func (gcp *GCP) NetworkPricing() (*types.Network, error) {
 		return nil, err
 	}
 
-	return &types.Network{
+	return &models.Network{
 		ZoneNetworkEgressCost:     znec,
 		RegionNetworkEgressCost:   rnec,
 		InternetNetworkEgressCost: inec,
 	}, nil
 }
 
-func (gcp *GCP) LoadBalancerPricing() (*types.LoadBalancer, error) {
+func (gcp *GCP) LoadBalancerPricing() (*models.LoadBalancer, error) {
 	fffrc := 0.025
 	afrc := 0.010
 	lbidc := 0.008
@@ -1159,7 +1160,7 @@ func (gcp *GCP) LoadBalancerPricing() (*types.LoadBalancer, error) {
 	} else {
 		totalCost = fffrc*5 + afrc*(numForwardingRules-5) + lbidc*dataIngressGB
 	}
-	return &types.LoadBalancer{
+	return &models.LoadBalancer{
 		Cost: totalCost,
 	}, nil
 }
@@ -1219,7 +1220,7 @@ var gcpReservedInstancePlans map[string]*GCPReservedInstancePlan = map[string]*G
 	},
 }
 
-func (gcp *GCP) ApplyReservedInstancePricing(nodes map[string]*types.Node) {
+func (gcp *GCP) ApplyReservedInstancePricing(nodes map[string]*models.Node) {
 	numReserved := len(gcp.ReservedInstances)
 
 	// Early return if no reserved instance data loaded
@@ -1277,7 +1278,7 @@ func (gcp *GCP) ApplyReservedInstancePricing(nodes map[string]*types.Node) {
 			continue
 		}
 
-		node.Reserved = &types.ReservedInstanceData{
+		node.Reserved = &models.ReservedInstanceData{
 			ReservedCPU: 0,
 			ReservedRAM: 0,
 		}
@@ -1403,7 +1404,7 @@ func (key *pvKey) GetStorageClass() string {
 	return key.StorageClass
 }
 
-func (gcp *GCP) GetPVKey(pv *v1.PersistentVolume, parameters map[string]string, defaultRegion string) types.PVKey {
+func (gcp *GCP) GetPVKey(pv *v1.PersistentVolume, parameters map[string]string, defaultRegion string) models.PVKey {
 	providerID := ""
 	if pv.Spec.GCEPersistentDisk != nil {
 		providerID = pv.Spec.GCEPersistentDisk.PDName
@@ -1442,7 +1443,7 @@ type gcpKey struct {
 	Labels map[string]string
 }
 
-func (gcp *GCP) GetKey(labels map[string]string, n *v1.Node) types.Key {
+func (gcp *GCP) GetKey(labels map[string]string, n *v1.Node) models.Key {
 	return &gcpKey{
 		Labels: labels,
 	}
@@ -1523,13 +1524,13 @@ func (gcp *GCP) AllNodePricing() (interface{}, error) {
 	return gcp.Pricing, nil
 }
 
-func (gcp *GCP) getPricing(key types.Key) (*GCPPricing, bool) {
+func (gcp *GCP) getPricing(key models.Key) (*GCPPricing, bool) {
 	gcp.DownloadPricingDataLock.RLock()
 	defer gcp.DownloadPricingDataLock.RUnlock()
 	n, ok := gcp.Pricing[key.Features()]
 	return n, ok
 }
-func (gcp *GCP) isValidPricingKey(key types.Key) bool {
+func (gcp *GCP) isValidPricingKey(key models.Key) bool {
 	gcp.DownloadPricingDataLock.RLock()
 	defer gcp.DownloadPricingDataLock.RUnlock()
 	_, ok := gcp.ValidPricingKeys[key.Features()]
@@ -1537,7 +1538,7 @@ func (gcp *GCP) isValidPricingKey(key types.Key) bool {
 }
 
 // NodePricing returns GCP pricing data for a single node
-func (gcp *GCP) NodePricing(key types.Key) (*types.Node, error) {
+func (gcp *GCP) NodePricing(key models.Key) (*models.Node, error) {
 	if n, ok := gcp.getPricing(key); ok {
 		log.Debugf("Returning pricing for node %s: %+v from SKU %s", key, n.Node, n.Name)
 		n.Node.BaseCPUPrice = gcp.BaseCPUPrice
@@ -1558,14 +1559,14 @@ func (gcp *GCP) NodePricing(key types.Key) (*types.Node, error) {
 	return nil, fmt.Errorf("Warning: no pricing data found for %s", key)
 }
 
-func (gcp *GCP) ServiceAccountStatus() *types.ServiceAccountStatus {
-	return &types.ServiceAccountStatus{
-		Checks: []*types.ServiceAccountCheck{},
+func (gcp *GCP) ServiceAccountStatus() *models.ServiceAccountStatus {
+	return &models.ServiceAccountStatus{
+		Checks: []*models.ServiceAccountCheck{},
 	}
 }
 
-func (gcp *GCP) PricingSourceStatus() map[string]*types.PricingSource {
-	return make(map[string]*types.PricingSource)
+func (gcp *GCP) PricingSourceStatus() map[string]*models.PricingSource {
+	return make(map[string]*models.PricingSource)
 }
 
 func (gcp *GCP) CombinedDiscountForNode(instanceType string, isPreemptible bool, defaultDiscount, negotiatedDiscount float64) float64 {

+ 5 - 5
pkg/cloud/gcpprovider_test.go

@@ -6,7 +6,7 @@ import (
 	"reflect"
 	"testing"
 
-	"github.com/opencost/opencost/pkg/cloud/types"
+	"github.com/opencost/opencost/pkg/cloud/models"
 )
 
 func TestParseGCPInstanceTypeLabel(t *testing.T) {
@@ -284,7 +284,7 @@ func TestParsePage(t *testing.T) {
 
 	testGcp := &GCP{}
 
-	inputKeys := map[string]types.Key{
+	inputKeys := map[string]models.Key{
 		"us-central1,a2highgpu,ondemand,gpu": &gcpKey{
 			Labels: map[string]string{
 				"node.kubernetes.io/instance-type": "a2-highgpu-1g",
@@ -295,7 +295,7 @@ func TestParsePage(t *testing.T) {
 		},
 	}
 
-	pvKeys := map[string]types.PVKey{}
+	pvKeys := map[string]models.PVKey{}
 
 	actualPrices, token, err := testGcp.parsePage(reader, inputKeys, pvKeys)
 	if err != nil {
@@ -344,7 +344,7 @@ func TestParsePage(t *testing.T) {
 				},
 			},
 			ServiceProviderName: "Google",
-			Node: &types.Node{
+			Node: &models.Node{
 				VCPUCost:         "0.031611",
 				RAMCost:          "0.004237",
 				UsesBaseCPUPrice: false,
@@ -354,7 +354,7 @@ func TestParsePage(t *testing.T) {
 			},
 		},
 		"us-central1,a2highgpu,ondemand": &GCPPricing{
-			Node: &types.Node{
+			Node: &models.Node{
 				VCPUCost:         "0.031611",
 				RAMCost:          "0.004237",
 				UsesBaseCPUPrice: false,

+ 1 - 67
pkg/cloud/types/types.go → pkg/cloud/models/models.go

@@ -1,4 +1,4 @@
-package types
+package models
 
 import (
 	"fmt"
@@ -6,12 +6,9 @@ import (
 	"reflect"
 	"strconv"
 	"strings"
-	"sync"
 	"time"
 
 	"github.com/microcosm-cc/bluemonday"
-	"golang.org/x/text/cases"
-	"golang.org/x/text/language"
 	v1 "k8s.io/api/core/v1"
 
 	"github.com/opencost/opencost/pkg/config"
@@ -20,7 +17,6 @@ import (
 
 var (
 	sanitizePolicy = bluemonday.UGCPolicy()
-	ToTitle        = cases.Title(language.Und, cases.NoLower)
 )
 
 const (
@@ -73,26 +69,6 @@ func (n *Node) IsSpot() bool {
 	}
 }
 
-// LoadBalancer is the interface by which the provider and cost model communicate LoadBalancer prices.
-// The provider will best-effort try to fill out this struct.
-type LoadBalancer struct {
-	IngressIPAddresses []string `json:"IngressIPAddresses"`
-	Cost               float64  `json:"hourlyCost"`
-}
-
-// TODO: used for dynamic cloud provider price fetching.
-// determine what identifies a load balancer in the json returned from the cloud provider pricing API call
-// type LBKey interface {
-// }
-
-// Network is the interface by which the provider and cost model communicate network egress prices.
-// The provider will best-effort try to fill out this struct.
-type Network struct {
-	ZoneNetworkEgressCost     float64
-	RegionNetworkEgressCost   float64
-	InternetNetworkEgressCost float64
-}
-
 type OrphanedResource struct {
 	Kind        string            `json:"resourceKind"`
 	Region      string            `json:"region"`
@@ -260,48 +236,6 @@ func SetCustomPricingField(obj *CustomPricing, name string, value string) error
 	return nil
 }
 
-type ServiceAccountStatus struct {
-	Checks []*ServiceAccountCheck `json:"checks"`
-}
-
-// ServiceAccountChecks is a thread safe map for holding ServiceAccountCheck objects
-type ServiceAccountChecks struct {
-	sync.RWMutex
-	serviceAccountChecks map[string]*ServiceAccountCheck
-}
-
-// NewServiceAccountChecks initialize ServiceAccountChecks
-func NewServiceAccountChecks() *ServiceAccountChecks {
-	return &ServiceAccountChecks{
-		serviceAccountChecks: make(map[string]*ServiceAccountCheck),
-	}
-}
-
-func (sac *ServiceAccountChecks) Set(key string, check *ServiceAccountCheck) {
-	sac.Lock()
-	defer sac.Unlock()
-	sac.serviceAccountChecks[key] = check
-}
-
-// getStatus extracts ServiceAccountCheck objects into a slice and returns them in a ServiceAccountStatus
-func (sac *ServiceAccountChecks) GetStatus() *ServiceAccountStatus {
-	sac.Lock()
-	defer sac.Unlock()
-	checks := []*ServiceAccountCheck{}
-	for _, v := range sac.serviceAccountChecks {
-		checks = append(checks, v)
-	}
-	return &ServiceAccountStatus{
-		Checks: checks,
-	}
-}
-
-type ServiceAccountCheck struct {
-	Message        string `json:"message"`
-	Status         bool   `json:"status"`
-	AdditionalInfo string `json:"additionalInfo"`
-}
-
 type PricingSources struct {
 	PricingSources map[string]*PricingSource
 }

+ 21 - 0
pkg/cloud/models/network.go

@@ -0,0 +1,21 @@
+package models
+
+// TODO: used for dynamic cloud provider price fetching.
+// determine what identifies a load balancer in the json returned from the cloud provider pricing API call
+// type LBKey interface {
+// }
+
+// Network is the interface by which the provider and cost model communicate network egress prices.
+// The provider will best-effort try to fill out this struct.
+type Network struct {
+	ZoneNetworkEgressCost     float64
+	RegionNetworkEgressCost   float64
+	InternetNetworkEgressCost float64
+}
+
+// LoadBalancer is the interface by which the provider and cost model communicate LoadBalancer prices.
+// The provider will best-effort try to fill out this struct.
+type LoadBalancer struct {
+	IngressIPAddresses []string `json:"IngressIPAddresses"`
+	Cost               float64  `json:"hourlyCost"`
+}

+ 45 - 0
pkg/cloud/models/serviceaccounts.go

@@ -0,0 +1,45 @@
+package models
+
+import "sync"
+
+type ServiceAccountStatus struct {
+	Checks []*ServiceAccountCheck `json:"checks"`
+}
+
+// ServiceAccountChecks is a thread safe map for holding ServiceAccountCheck objects
+type ServiceAccountChecks struct {
+	sync.RWMutex
+	serviceAccountChecks map[string]*ServiceAccountCheck
+}
+
+// NewServiceAccountChecks initialize ServiceAccountChecks
+func NewServiceAccountChecks() *ServiceAccountChecks {
+	return &ServiceAccountChecks{
+		serviceAccountChecks: make(map[string]*ServiceAccountCheck),
+	}
+}
+
+func (sac *ServiceAccountChecks) Set(key string, check *ServiceAccountCheck) {
+	sac.Lock()
+	defer sac.Unlock()
+	sac.serviceAccountChecks[key] = check
+}
+
+// getStatus extracts ServiceAccountCheck objects into a slice and returns them in a ServiceAccountStatus
+func (sac *ServiceAccountChecks) GetStatus() *ServiceAccountStatus {
+	sac.Lock()
+	defer sac.Unlock()
+	checks := []*ServiceAccountCheck{}
+	for _, v := range sac.serviceAccountChecks {
+		checks = append(checks, v)
+	}
+	return &ServiceAccountStatus{
+		Checks: checks,
+	}
+}
+
+type ServiceAccountCheck struct {
+	Message        string `json:"message"`
+	Status         bool   `json:"status"`
+	AdditionalInfo string `json:"additionalInfo"`
+}

+ 12 - 12
pkg/cloud/provider.go

@@ -9,7 +9,7 @@ import (
 	"time"
 
 	"github.com/opencost/opencost/pkg/cloud/azure"
-	"github.com/opencost/opencost/pkg/cloud/types"
+	"github.com/opencost/opencost/pkg/cloud/models"
 	"github.com/opencost/opencost/pkg/kubecost"
 
 	"github.com/opencost/opencost/pkg/util"
@@ -31,7 +31,7 @@ const KarpenterCapacitySpotTypeValue = "spot"
 
 // ClusterName returns the name defined in cluster info, defaulting to the
 // CLUSTER_ID environment variable
-func ClusterName(p types.Provider) string {
+func ClusterName(p models.Provider) string {
 	info, err := p.ClusterInfo()
 	if err != nil {
 		return env.GetClusterID()
@@ -47,7 +47,7 @@ func ClusterName(p types.Provider) string {
 
 // CustomPricesEnabled returns the boolean equivalent of the cloup provider's custom prices flag,
 // indicating whether or not the cluster is using custom pricing.
-func CustomPricesEnabled(p types.Provider) bool {
+func CustomPricesEnabled(p models.Provider) bool {
 	config, err := p.GetConfig()
 	if err != nil {
 		return false
@@ -62,7 +62,7 @@ func CustomPricesEnabled(p types.Provider) bool {
 
 // ConfigWatcherFor returns a new ConfigWatcher instance which watches changes to the "pricing-configs"
 // configmap
-func ConfigWatcherFor(p types.Provider) *watcher.ConfigMapWatcher {
+func ConfigWatcherFor(p models.Provider) *watcher.ConfigMapWatcher {
 	return &watcher.ConfigMapWatcher{
 		ConfigMapName: env.GetPricingConfigmapName(),
 		WatchFunc: func(name string, data map[string]string) error {
@@ -73,7 +73,7 @@ func ConfigWatcherFor(p types.Provider) *watcher.ConfigMapWatcher {
 }
 
 // AllocateIdleByDefault returns true if the application settings specify to allocate idle by default
-func AllocateIdleByDefault(p types.Provider) bool {
+func AllocateIdleByDefault(p models.Provider) bool {
 	config, err := p.GetConfig()
 	if err != nil {
 		return false
@@ -83,7 +83,7 @@ func AllocateIdleByDefault(p types.Provider) bool {
 }
 
 // SharedNamespace returns a list of names of shared namespaces, as defined in the application settings
-func SharedNamespaces(p types.Provider) []string {
+func SharedNamespaces(p models.Provider) []string {
 	namespaces := []string{}
 
 	config, err := p.GetConfig()
@@ -104,7 +104,7 @@ func SharedNamespaces(p types.Provider) []string {
 // SharedLabel returns the configured set of shared labels as a parallel tuple of keys to values; e.g.
 // for app:kubecost,type:staging this returns (["app", "type"], ["kubecost", "staging"]) in order to
 // match the signature of the NewSharedResourceInfo
-func SharedLabels(p types.Provider) ([]string, []string) {
+func SharedLabels(p models.Provider) ([]string, []string) {
 	names := []string{}
 	values := []string{}
 
@@ -134,7 +134,7 @@ func SharedLabels(p types.Provider) ([]string, []string) {
 
 // ShareTenancyCosts returns true if the application settings specify to share
 // tenancy costs by default.
-func ShareTenancyCosts(p types.Provider) bool {
+func ShareTenancyCosts(p models.Provider) bool {
 	config, err := p.GetConfig()
 	if err != nil {
 		return false
@@ -144,7 +144,7 @@ func ShareTenancyCosts(p types.Provider) bool {
 }
 
 // NewProvider looks at the nodespec or provider metadata server to decide which provider to instantiate.
-func NewProvider(cache clustercache.ClusterCache, apiKey string, config *config.ConfigFileManager) (types.Provider, error) {
+func NewProvider(cache clustercache.ClusterCache, apiKey string, config *config.ConfigFileManager) (models.Provider, error) {
 	nodes := cache.GetAllNodes()
 	if len(nodes) == 0 {
 		log.Infof("Could not locate any nodes for cluster.") // valid in ETL readonly mode
@@ -203,7 +203,7 @@ func NewProvider(cache clustercache.ClusterCache, apiKey string, config *config.
 			Config:               NewProviderConfig(config, cp.configFileName),
 			clusterRegion:        cp.region,
 			clusterAccountID:     cp.accountID,
-			serviceAccountChecks: types.NewServiceAccountChecks(),
+			serviceAccountChecks: models.NewServiceAccountChecks(),
 		}, nil
 	case kubecost.AzureProvider:
 		log.Info("Found ProviderID starting with \"azure\", using Azure Provider")
@@ -212,7 +212,7 @@ func NewProvider(cache clustercache.ClusterCache, apiKey string, config *config.
 			Config:               NewProviderConfig(config, cp.configFileName),
 			ClusterRegion:        cp.region,
 			ClusterAccountID:     cp.accountID,
-			ServiceAccountChecks: types.NewServiceAccountChecks(),
+			ServiceAccountChecks: models.NewServiceAccountChecks(),
 		}, nil
 	case kubecost.AlibabaProvider:
 		log.Info("Found ProviderID starting with \"alibaba\", using Alibaba Cloud Provider")
@@ -221,7 +221,7 @@ func NewProvider(cache clustercache.ClusterCache, apiKey string, config *config.
 			Config:               NewProviderConfig(config, cp.configFileName),
 			clusterRegion:        cp.region,
 			clusterAccountId:     cp.accountID,
-			serviceAccountChecks: types.NewServiceAccountChecks(),
+			serviceAccountChecks: models.NewServiceAccountChecks(),
 		}, nil
 	case kubecost.ScalewayProvider:
 		log.Info("Found ProviderID starting with \"scaleway\", using Scaleway Provider")

+ 22 - 21
pkg/cloud/providerconfig.go

@@ -8,7 +8,8 @@ import (
 	"strconv"
 	"sync"
 
-	"github.com/opencost/opencost/pkg/cloud/types"
+	"github.com/opencost/opencost/pkg/cloud/models"
+	"github.com/opencost/opencost/pkg/cloud/utils"
 	"github.com/opencost/opencost/pkg/config"
 	"github.com/opencost/opencost/pkg/env"
 	"github.com/opencost/opencost/pkg/log"
@@ -23,7 +24,7 @@ type ProviderConfig struct {
 	lock            *sync.Mutex
 	configManager   *config.ConfigFileManager
 	configFile      *config.ConfigFile
-	customPricing   *types.CustomPricing
+	customPricing   *models.CustomPricing
 	watcherHandleID config.HandlerID
 }
 
@@ -56,7 +57,7 @@ func (pc *ProviderConfig) onConfigFileUpdated(changeType config.ChangeType, data
 		pc.lock.Lock()
 		defer pc.lock.Unlock()
 
-		customPricing := new(types.CustomPricing)
+		customPricing := new(models.CustomPricing)
 		err := json.Unmarshal(data, customPricing)
 		if err != nil {
 			log.Infof("Could not decode Custom Pricing file at path %s. Using default.", pc.configFile.Path())
@@ -69,14 +70,14 @@ func (pc *ProviderConfig) onConfigFileUpdated(changeType config.ChangeType, data
 		}
 
 		if pc.customPricing.ShareTenancyCosts == "" {
-			pc.customPricing.ShareTenancyCosts = types.DefaultShareTenancyCost
+			pc.customPricing.ShareTenancyCosts = models.DefaultShareTenancyCost
 		}
 	}
 }
 
 // Non-ThreadSafe logic to load the config file if a cache does not exist. Flag to write
 // the default config if the config file doesn't exist.
-func (pc *ProviderConfig) loadConfig(writeIfNotExists bool) (*types.CustomPricing, error) {
+func (pc *ProviderConfig) loadConfig(writeIfNotExists bool) (*models.CustomPricing, error) {
 	if pc.customPricing != nil {
 		return pc.customPricing, nil
 	}
@@ -127,7 +128,7 @@ func (pc *ProviderConfig) loadConfig(writeIfNotExists bool) (*types.CustomPricin
 		return DefaultPricing(), err
 	}
 
-	var customPricing types.CustomPricing
+	var customPricing models.CustomPricing
 	err = json.Unmarshal(byteValue, &customPricing)
 	if err != nil {
 		log.Infof("Could not decode Custom Pricing file at path %s", pc.configFile.Path())
@@ -140,14 +141,14 @@ func (pc *ProviderConfig) loadConfig(writeIfNotExists bool) (*types.CustomPricin
 	}
 
 	if pc.customPricing.ShareTenancyCosts == "" {
-		pc.customPricing.ShareTenancyCosts = types.DefaultShareTenancyCost
+		pc.customPricing.ShareTenancyCosts = models.DefaultShareTenancyCost
 	}
 
 	return pc.customPricing, nil
 }
 
 // ThreadSafe method for retrieving the custom pricing config.
-func (pc *ProviderConfig) GetCustomPricingData() (*types.CustomPricing, error) {
+func (pc *ProviderConfig) GetCustomPricingData() (*models.CustomPricing, error) {
 	pc.lock.Lock()
 	defer pc.lock.Unlock()
 
@@ -163,7 +164,7 @@ func (pc *ProviderConfig) ConfigFileManager() *config.ConfigFileManager {
 
 // Allows a call to manually update the configuration while maintaining proper thread-safety
 // for read/write methods.
-func (pc *ProviderConfig) Update(updateFunc func(*types.CustomPricing) error) (*types.CustomPricing, error) {
+func (pc *ProviderConfig) Update(updateFunc func(*models.CustomPricing) error) (*models.CustomPricing, error) {
 	pc.lock.Lock()
 	defer pc.lock.Unlock()
 
@@ -195,12 +196,12 @@ func (pc *ProviderConfig) Update(updateFunc func(*types.CustomPricing) error) (*
 }
 
 // ThreadSafe update of the config using a string map
-func (pc *ProviderConfig) UpdateFromMap(a map[string]string) (*types.CustomPricing, error) {
+func (pc *ProviderConfig) UpdateFromMap(a map[string]string) (*models.CustomPricing, error) {
 	// Run our Update() method using SetCustomPricingField logic
-	return pc.Update(func(c *types.CustomPricing) error {
+	return pc.Update(func(c *models.CustomPricing) error {
 		for k, v := range a {
 			// Just so we consistently supply / receive the same values, uppercase the first letter.
-			kUpper := types.ToTitle.String(k)
+			kUpper := utils.ToTitle.String(k)
 			if kUpper == "CPU" || kUpper == "SpotCPU" || kUpper == "RAM" || kUpper == "SpotRAM" || kUpper == "GPU" || kUpper == "Storage" {
 				val, err := strconv.ParseFloat(v, 64)
 				if err != nil {
@@ -209,7 +210,7 @@ func (pc *ProviderConfig) UpdateFromMap(a map[string]string) (*types.CustomPrici
 				v = fmt.Sprintf("%f", val/730)
 			}
 
-			err := types.SetCustomPricingField(c, kUpper, v)
+			err := models.SetCustomPricingField(c, kUpper, v)
 			if err != nil {
 				return err
 			}
@@ -220,9 +221,9 @@ func (pc *ProviderConfig) UpdateFromMap(a map[string]string) (*types.CustomPrici
 }
 
 // DefaultPricing should be returned so we can do computation even if no file is supplied.
-func DefaultPricing() *types.CustomPricing {
+func DefaultPricing() *models.CustomPricing {
 	// https://cloud.google.com/compute/all-pricing
-	return &types.CustomPricing{
+	return &models.CustomPricing{
 		Provider:    "base",
 		Description: "Default prices based on GCP us-central1",
 
@@ -268,23 +269,23 @@ func filenameInConfigPath(fqfn string) string {
 
 // ReturnPricingFromConfigs is a safe function to return pricing from configs of opensource to the closed source
 // before defaulting it with the above function DefaultPricing
-func ReturnPricingFromConfigs(filename string) (*types.CustomPricing, error) {
+func ReturnPricingFromConfigs(filename string) (*models.CustomPricing, error) {
 	if _, err := os.Stat(closedSourceConfigMount); os.IsNotExist(err) {
-		return &types.CustomPricing{}, fmt.Errorf("ReturnPricingFromConfigs: %s likely running in provider config in opencost itself with err: %v", closedSourceConfigMount, err)
+		return &models.CustomPricing{}, fmt.Errorf("ReturnPricingFromConfigs: %s likely running in provider config in opencost itself with err: %v", closedSourceConfigMount, err)
 	}
 	providerConfigFile := gopath.Join(closedSourceConfigMount, filename)
 	if _, err := os.Stat(providerConfigFile); err != nil {
-		return &types.CustomPricing{}, fmt.Errorf("ReturnPricingFromConfigs: unable to find file %s with err: %v", providerConfigFile, err)
+		return &models.CustomPricing{}, fmt.Errorf("ReturnPricingFromConfigs: unable to find file %s with err: %v", providerConfigFile, err)
 	}
 	configFile, err := ioutil.ReadFile(providerConfigFile)
 	if err != nil {
-		return &types.CustomPricing{}, fmt.Errorf("ReturnPricingFromConfigs: unable to open file %s with err: %v", providerConfigFile, err)
+		return &models.CustomPricing{}, fmt.Errorf("ReturnPricingFromConfigs: unable to open file %s with err: %v", providerConfigFile, err)
 	}
 
-	defaultPricing := &types.CustomPricing{}
+	defaultPricing := &models.CustomPricing{}
 	err = json.Unmarshal(configFile, defaultPricing)
 	if err != nil {
-		return &types.CustomPricing{}, fmt.Errorf("ReturnPricingFromConfigs: unable to open file %s with err: %v", providerConfigFile, err)
+		return &models.CustomPricing{}, fmt.Errorf("ReturnPricingFromConfigs: unable to open file %s with err: %v", providerConfigFile, err)
 	}
 	return defaultPricing, nil
 }

+ 29 - 28
pkg/cloud/scalewayprovider.go

@@ -9,7 +9,8 @@ import (
 	"sync"
 	"time"
 
-	"github.com/opencost/opencost/pkg/cloud/types"
+	"github.com/opencost/opencost/pkg/cloud/models"
+	"github.com/opencost/opencost/pkg/cloud/utils"
 	"github.com/opencost/opencost/pkg/kubecost"
 
 	"github.com/opencost/opencost/pkg/clustercache"
@@ -132,7 +133,7 @@ func (k *scalewayKey) ID() string {
 	return ""
 }
 
-func (c *Scaleway) NodePricing(key types.Key) (*types.Node, error) {
+func (c *Scaleway) NodePricing(key models.Key) (*models.Node, error) {
 	c.DownloadPricingDataLock.RLock()
 	defer c.DownloadPricingDataLock.RUnlock()
 
@@ -140,9 +141,9 @@ func (c *Scaleway) NodePricing(key types.Key) (*types.Node, error) {
 	split := strings.Split(key.Features(), ",")
 	if pricing, ok := c.Pricing[split[0]]; ok {
 		if info, ok := pricing.NodesInfos[split[1]]; ok {
-			return &types.Node{
+			return &models.Node{
 				Cost:        fmt.Sprintf("%f", info.HourlyPrice),
-				PricingType: types.DefaultPrices,
+				PricingType: models.DefaultPrices,
 				VCPU:        fmt.Sprintf("%d", info.Ncpus),
 				RAM:         fmt.Sprintf("%d", info.RAM),
 				// This is tricky, as instances can have local volumes or not
@@ -159,24 +160,24 @@ func (c *Scaleway) NodePricing(key types.Key) (*types.Node, error) {
 	return nil, fmt.Errorf("Unable to find node pricing matching thes features `%s`", key.Features())
 }
 
-func (c *Scaleway) LoadBalancerPricing() (*types.LoadBalancer, error) {
+func (c *Scaleway) LoadBalancerPricing() (*models.LoadBalancer, error) {
 	// Different LB types, lets take the cheaper for now, we can't get the type
 	// without a service specifying the type in the annotations
-	return &types.LoadBalancer{
+	return &models.LoadBalancer{
 		Cost: 0.014,
 	}, nil
 }
 
-func (c *Scaleway) NetworkPricing() (*types.Network, error) {
+func (c *Scaleway) NetworkPricing() (*models.Network, error) {
 	// it's free baby!
-	return &types.Network{
+	return &models.Network{
 		ZoneNetworkEgressCost:     0,
 		RegionNetworkEgressCost:   0,
 		InternetNetworkEgressCost: 0,
 	}, nil
 }
 
-func (c *Scaleway) GetKey(l map[string]string, n *v1.Node) types.Key {
+func (c *Scaleway) GetKey(l map[string]string, n *v1.Node) models.Key {
 	return &scalewayKey{
 		Labels: l,
 	}
@@ -203,7 +204,7 @@ func (key *scalewayPVKey) Features() string {
 	return key.Zone
 }
 
-func (c *Scaleway) GetPVKey(pv *v1.PersistentVolume, parameters map[string]string, defaultRegion string) types.PVKey {
+func (c *Scaleway) GetPVKey(pv *v1.PersistentVolume, parameters map[string]string, defaultRegion string) models.PVKey {
 	// the csi volume handle is the form <az>/<volume-id>
 	zone := strings.Split(pv.Spec.CSI.VolumeHandle, "/")[0]
 	return &scalewayPVKey{
@@ -215,24 +216,24 @@ func (c *Scaleway) GetPVKey(pv *v1.PersistentVolume, parameters map[string]strin
 	}
 }
 
-func (c *Scaleway) PVPricing(pvk types.PVKey) (*types.PV, error) {
+func (c *Scaleway) PVPricing(pvk models.PVKey) (*models.PV, error) {
 	c.DownloadPricingDataLock.RLock()
 	defer c.DownloadPricingDataLock.RUnlock()
 
 	pricing, ok := c.Pricing[pvk.Features()]
 	if !ok {
 		log.Infof("Persistent Volume pricing not found for %s: %s", pvk.GetStorageClass(), pvk.Features())
-		return &types.PV{}, nil
+		return &models.PV{}, nil
 	}
-	return &types.PV{
+	return &models.PV{
 		Cost:  fmt.Sprintf("%f", pricing.PVCost),
 		Class: pvk.GetStorageClass(),
 	}, nil
 }
 
-func (c *Scaleway) ServiceAccountStatus() *types.ServiceAccountStatus {
-	return &types.ServiceAccountStatus{
-		Checks: []*types.ServiceAccountCheck{},
+func (c *Scaleway) ServiceAccountStatus() *models.ServiceAccountStatus {
+	return &models.ServiceAccountStatus{
+		Checks: []*models.ServiceAccountCheck{},
 	}
 }
 
@@ -261,7 +262,7 @@ func (c *Scaleway) Regions() []string {
 	return zones
 }
 
-func (*Scaleway) ApplyReservedInstancePricing(map[string]*types.Node) {}
+func (*Scaleway) ApplyReservedInstancePricing(map[string]*models.Node) {}
 
 func (*Scaleway) GetAddresses() ([]byte, error) {
 	return nil, nil
@@ -271,7 +272,7 @@ func (*Scaleway) GetDisks() ([]byte, error) {
 	return nil, nil
 }
 
-func (*Scaleway) GetOrphanedResources() ([]types.OrphanedResource, error) {
+func (*Scaleway) GetOrphanedResources() ([]models.OrphanedResource, error) {
 	return nil, errors.New("not implemented")
 }
 
@@ -296,24 +297,24 @@ func (scw *Scaleway) ClusterInfo() (map[string]string, error) {
 
 }
 
-func (c *Scaleway) UpdateConfigFromConfigMap(a map[string]string) (*types.CustomPricing, error) {
+func (c *Scaleway) UpdateConfigFromConfigMap(a map[string]string) (*models.CustomPricing, error) {
 	return c.Config.UpdateFromMap(a)
 }
 
-func (c *Scaleway) UpdateConfig(r io.Reader, updateType string) (*types.CustomPricing, error) {
+func (c *Scaleway) UpdateConfig(r io.Reader, updateType string) (*models.CustomPricing, error) {
 	defer c.DownloadPricingData()
 
-	return c.Config.Update(func(c *types.CustomPricing) error {
+	return c.Config.Update(func(c *models.CustomPricing) error {
 		a := make(map[string]interface{})
 		err := json.NewDecoder(r).Decode(&a)
 		if err != nil {
 			return err
 		}
 		for k, v := range a {
-			kUpper := types.ToTitle.String(k) // Just so we consistently supply / receive the same values, uppercase the first letter.
+			kUpper := utils.ToTitle.String(k) // Just so we consistently supply / receive the same values, uppercase the first letter.
 			vstr, ok := v.(string)
 			if ok {
-				err := types.SetCustomPricingField(c, kUpper, vstr)
+				err := models.SetCustomPricingField(c, kUpper, vstr)
 				if err != nil {
 					return err
 				}
@@ -323,7 +324,7 @@ func (c *Scaleway) UpdateConfig(r io.Reader, updateType string) (*types.CustomPr
 		}
 
 		if env.IsRemoteEnabled() {
-			err := types.UpdateClusterMeta(env.GetClusterID(), c.ClusterName)
+			err := utils.UpdateClusterMeta(env.GetClusterID(), c.ClusterName)
 			if err != nil {
 				return err
 			}
@@ -332,7 +333,7 @@ func (c *Scaleway) UpdateConfig(r io.Reader, updateType string) (*types.CustomPr
 		return nil
 	})
 }
-func (scw *Scaleway) GetConfig() (*types.CustomPricing, error) {
+func (scw *Scaleway) GetConfig() (*models.CustomPricing, error) {
 	c, err := scw.Config.GetCustomPricingData()
 	if err != nil {
 		return nil, err
@@ -368,9 +369,9 @@ func (scw *Scaleway) GetManagementPlatform() (string, error) {
 	return "", nil
 }
 
-func (c *Scaleway) PricingSourceStatus() map[string]*types.PricingSource {
-	return map[string]*types.PricingSource{
-		InstanceAPIPricing: &types.PricingSource{
+func (c *Scaleway) PricingSourceStatus() map[string]*models.PricingSource {
+	return map[string]*models.PricingSource{
+		InstanceAPIPricing: &models.PricingSource{
 			Name:      InstanceAPIPricing,
 			Enabled:   true,
 			Available: true,

+ 6 - 1
pkg/cloud/types/clustermeta.go → pkg/cloud/utils/utils.go

@@ -1,12 +1,17 @@
-package types
+package utils
 
 import (
 	"database/sql"
 	"fmt"
 
+	"golang.org/x/text/cases"
+	"golang.org/x/text/language"
+
 	"github.com/opencost/opencost/pkg/env"
 )
 
+var ToTitle = cases.Title(language.Und, cases.NoLower)
+
 var createTableStatements = []string{
 	`CREATE TABLE IF NOT EXISTS names (
 		cluster_id VARCHAR(255) NOT NULL,

+ 8 - 8
pkg/costmodel/aggregation.go

@@ -15,7 +15,7 @@ import (
 	prometheusClient "github.com/prometheus/client_golang/api"
 
 	"github.com/opencost/opencost/pkg/cloud"
-	"github.com/opencost/opencost/pkg/cloud/types"
+	"github.com/opencost/opencost/pkg/cloud/models"
 	"github.com/opencost/opencost/pkg/env"
 	"github.com/opencost/opencost/pkg/errors"
 	"github.com/opencost/opencost/pkg/kubecost"
@@ -182,7 +182,7 @@ func NewSharedResourceInfo(shareResources bool, sharedNamespaces []string, label
 	return sr
 }
 
-func GetTotalContainerCost(costData map[string]*CostData, rate string, cp types.Provider, discount float64, customDiscount float64, idleCoefficients map[string]float64) float64 {
+func GetTotalContainerCost(costData map[string]*CostData, rate string, cp models.Provider, discount float64, customDiscount float64, idleCoefficients map[string]float64) float64 {
 	totalContainerCost := 0.0
 	for _, costDatum := range costData {
 		clusterID := costDatum.ClusterID
@@ -198,7 +198,7 @@ func GetTotalContainerCost(costData map[string]*CostData, rate string, cp types.
 	return totalContainerCost
 }
 
-func (a *Accesses) ComputeIdleCoefficient(costData map[string]*CostData, cli prometheusClient.Client, cp types.Provider, discount float64, customDiscount float64, window, offset time.Duration) (map[string]float64, error) {
+func (a *Accesses) ComputeIdleCoefficient(costData map[string]*CostData, cli prometheusClient.Client, cp models.Provider, discount float64, customDiscount float64, window, offset time.Duration) (map[string]float64, error) {
 	coefficients := make(map[string]float64)
 
 	profileName := "ComputeIdleCoefficient: ComputeClusterCosts"
@@ -288,7 +288,7 @@ func clampAverage(requestsAvg float64, usedAverage float64, allocationAvg float6
 // AggregateCostData aggregates raw cost data by field; e.g. namespace, cluster, service, or label. In the case of label, callers
 // must pass a slice of subfields indicating the labels by which to group. Provider is used to define custom resource pricing.
 // See AggregationOptions for optional parameters.
-func AggregateCostData(costData map[string]*CostData, field string, subfields []string, cp types.Provider, opts *AggregationOptions) map[string]*Aggregation {
+func AggregateCostData(costData map[string]*CostData, field string, subfields []string, cp models.Provider, opts *AggregationOptions) map[string]*Aggregation {
 	discount := opts.Discount
 	customDiscount := opts.CustomDiscount
 	idleCoefficients := opts.IdleCoefficients
@@ -585,7 +585,7 @@ func AggregateCostData(costData map[string]*CostData, field string, subfields []
 	return aggregations
 }
 
-func aggregateDatum(cp types.Provider, aggregations map[string]*Aggregation, costDatum *CostData, field string, subfields []string, rate string, key string, discount float64, customDiscount float64, idleCoefficient float64, includeProperties bool) {
+func aggregateDatum(cp models.Provider, aggregations map[string]*Aggregation, costDatum *CostData, field string, subfields []string, rate string, key string, discount float64, customDiscount float64, idleCoefficient float64, includeProperties bool) {
 	// add new entry to aggregation results if a new key is encountered
 	if _, ok := aggregations[key]; !ok {
 		agg := &Aggregation{
@@ -618,7 +618,7 @@ func aggregateDatum(cp types.Provider, aggregations map[string]*Aggregation, cos
 	mergeVectors(cp, costDatum, aggregations[key], rate, discount, customDiscount, idleCoefficient)
 }
 
-func mergeVectors(cp types.Provider, costDatum *CostData, aggregation *Aggregation, rate string, discount float64, customDiscount float64, idleCoefficient float64) {
+func mergeVectors(cp models.Provider, costDatum *CostData, aggregation *Aggregation, rate string, discount float64, customDiscount float64, idleCoefficient float64) {
 	aggregation.CPUAllocationVectors = addVectors(costDatum.CPUAllocation, aggregation.CPUAllocationVectors)
 	aggregation.CPURequestedVectors = addVectors(costDatum.CPUReq, aggregation.CPURequestedVectors)
 	aggregation.CPUUsedVectors = addVectors(costDatum.CPUUsed, aggregation.CPUUsedVectors)
@@ -712,7 +712,7 @@ func getDiscounts(costDatum *CostData, cpuCost float64, ramCost float64, discoun
 	return blendedCPUDiscount, blendedRAMDiscount
 }
 
-func parseVectorPricing(cfg *types.CustomPricing, costDatum *CostData, cpuCostStr, ramCostStr, gpuCostStr, pvCostStr string) (float64, float64, float64, float64, bool) {
+func parseVectorPricing(cfg *models.CustomPricing, costDatum *CostData, cpuCostStr, ramCostStr, gpuCostStr, pvCostStr string) (float64, float64, float64, float64, bool) {
 	usesCustom := false
 	cpuCost, err := strconv.ParseFloat(cpuCostStr, 64)
 	if err != nil || math.IsNaN(cpuCost) || math.IsInf(cpuCost, 0) || cpuCost == 0 {
@@ -747,7 +747,7 @@ func parseVectorPricing(cfg *types.CustomPricing, costDatum *CostData, cpuCostSt
 	return cpuCost, ramCost, gpuCost, pvCost, usesCustom
 }
 
-func getPriceVectors(cp types.Provider, costDatum *CostData, rate string, discount float64, customDiscount float64, idleCoefficient float64) ([]*util.Vector, []*util.Vector, []*util.Vector, [][]*util.Vector, []*util.Vector) {
+func getPriceVectors(cp models.Provider, costDatum *CostData, rate string, discount float64, customDiscount float64, idleCoefficient float64) ([]*util.Vector, []*util.Vector, []*util.Vector, [][]*util.Vector, []*util.Vector) {
 
 	var cpuCost float64
 	var ramCost float64

+ 6 - 6
pkg/costmodel/cluster.go

@@ -9,7 +9,7 @@ import (
 	"golang.org/x/exp/slices"
 
 	"github.com/opencost/opencost/pkg/cloud"
-	"github.com/opencost/opencost/pkg/cloud/types"
+	"github.com/opencost/opencost/pkg/cloud/models"
 	"github.com/opencost/opencost/pkg/env"
 	"github.com/opencost/opencost/pkg/kubecost"
 	"github.com/opencost/opencost/pkg/log"
@@ -141,7 +141,7 @@ type DiskIdentifier struct {
 	Name    string
 }
 
-func ClusterDisks(client prometheus.Client, provider types.Provider, start, end time.Time) (map[DiskIdentifier]*Disk, error) {
+func ClusterDisks(client prometheus.Client, provider models.Provider, start, end time.Time) (map[DiskIdentifier]*Disk, error) {
 	// Query for the duration between start and end
 	durStr := timeutil.DurationString(end.Sub(start))
 	if durStr == "" {
@@ -542,7 +542,7 @@ func costTimesMinute(activeDataMap map[NodeIdentifier]activeData, costMap map[No
 	}
 }
 
-func ClusterNodes(cp types.Provider, client prometheus.Client, start, end time.Time) (map[NodeIdentifier]*Node, error) {
+func ClusterNodes(cp models.Provider, client prometheus.Client, start, end time.Time) (map[NodeIdentifier]*Node, error) {
 	// Query for the duration between start and end
 	durStr := timeutil.DurationString(end.Sub(start))
 	if durStr == "" {
@@ -833,7 +833,7 @@ func ClusterLoadBalancers(client prometheus.Client, start, end time.Time) (map[L
 }
 
 // ComputeClusterCosts gives the cumulative and monthly-rate cluster costs over a window of time for all clusters.
-func (a *Accesses) ComputeClusterCosts(client prometheus.Client, provider types.Provider, window, offset time.Duration, withBreakdown bool) (map[string]*ClusterCosts, error) {
+func (a *Accesses) ComputeClusterCosts(client prometheus.Client, provider models.Provider, window, offset time.Duration, withBreakdown bool) (map[string]*ClusterCosts, error) {
 	if window < 10*time.Minute {
 		return nil, fmt.Errorf("minimum window of 10m required; got %s", window)
 	}
@@ -1192,7 +1192,7 @@ func resultToTotals(qrs []*prom.QueryResult) ([][]string, error) {
 }
 
 // ClusterCostsOverTime gives the full cluster costs over time
-func ClusterCostsOverTime(cli prometheus.Client, provider types.Provider, startString, endString string, window, offset time.Duration) (*Totals, error) {
+func ClusterCostsOverTime(cli prometheus.Client, provider models.Provider, startString, endString string, window, offset time.Duration) (*Totals, error) {
 	localStorageQuery := provider.GetLocalStorageQuery(window, offset, true, false)
 	if localStorageQuery != "" {
 		localStorageQuery = fmt.Sprintf("+ %s", localStorageQuery)
@@ -1298,7 +1298,7 @@ func ClusterCostsOverTime(cli prometheus.Client, provider types.Provider, startS
 	}, nil
 }
 
-func pvCosts(diskMap map[DiskIdentifier]*Disk, resolution time.Duration, resActiveMins, resPVSize, resPVCost, resPVUsedAvg, resPVUsedMax, resPVCInfo []*prom.QueryResult, cp types.Provider) {
+func pvCosts(diskMap map[DiskIdentifier]*Disk, resolution time.Duration, resActiveMins, resPVSize, resPVCost, resPVUsedAvg, resPVUsedMax, resPVCInfo []*prom.QueryResult, cp models.Provider) {
 	for _, result := range resActiveMins {
 		cluster, err := result.GetString(env.GetPromClusterLabel())
 		if err != nil {

+ 4 - 4
pkg/costmodel/cluster_helpers.go

@@ -5,7 +5,7 @@ import (
 	"time"
 
 	"github.com/opencost/opencost/pkg/cloud"
-	"github.com/opencost/opencost/pkg/cloud/types"
+	"github.com/opencost/opencost/pkg/cloud/models"
 
 	"github.com/opencost/opencost/pkg/env"
 	"github.com/opencost/opencost/pkg/log"
@@ -31,7 +31,7 @@ func mergeTypeMaps(clusterAndNameToType1, clusterAndNameToType2 map[nodeIdentifi
 
 func buildCPUCostMap(
 	resNodeCPUCost []*prom.QueryResult,
-	cp types.Provider,
+	cp models.Provider,
 	preemptible map[NodeIdentifier]bool,
 ) (
 	map[NodeIdentifier]float64,
@@ -105,7 +105,7 @@ func buildCPUCostMap(
 
 func buildRAMCostMap(
 	resNodeRAMCost []*prom.QueryResult,
-	cp types.Provider,
+	cp models.Provider,
 	preemptible map[NodeIdentifier]bool,
 ) (
 	map[NodeIdentifier]float64,
@@ -180,7 +180,7 @@ func buildRAMCostMap(
 func buildGPUCostMap(
 	resNodeGPUCost []*prom.QueryResult,
 	gpuCountMap map[NodeIdentifier]float64,
-	cp types.Provider,
+	cp models.Provider,
 	preemptible map[NodeIdentifier]bool,
 ) (
 	map[NodeIdentifier]float64,

+ 1 - 1
pkg/costmodel/clusterinfo.go

@@ -3,7 +3,7 @@ package costmodel
 import (
 	"fmt"
 
-	cloudProvider "github.com/opencost/opencost/pkg/cloud/types"
+	cloudProvider "github.com/opencost/opencost/pkg/cloud/models"
 	"github.com/opencost/opencost/pkg/config"
 	"github.com/opencost/opencost/pkg/costmodel/clusters"
 	"github.com/opencost/opencost/pkg/env"

+ 1 - 1
pkg/costmodel/costmodel.go

@@ -9,7 +9,7 @@ import (
 	"strings"
 	"time"
 
-	costAnalyzerCloud "github.com/opencost/opencost/pkg/cloud/types"
+	costAnalyzerCloud "github.com/opencost/opencost/pkg/cloud/models"
 	"github.com/opencost/opencost/pkg/clustercache"
 	"github.com/opencost/opencost/pkg/costmodel/clusters"
 	"github.com/opencost/opencost/pkg/env"

+ 5 - 5
pkg/costmodel/metrics.go

@@ -7,7 +7,7 @@ import (
 	"sync"
 	"time"
 
-	"github.com/opencost/opencost/pkg/cloud/types"
+	"github.com/opencost/opencost/pkg/cloud/models"
 	"github.com/opencost/opencost/pkg/clustercache"
 	"github.com/opencost/opencost/pkg/costmodel/clusters"
 	"github.com/opencost/opencost/pkg/env"
@@ -136,7 +136,7 @@ var (
 )
 
 // initCostModelMetrics uses a sync.Once to ensure that these metrics are only created once
-func initCostModelMetrics(clusterCache clustercache.ClusterCache, provider types.Provider, clusterInfo clusters.ClusterInfoProvider, metricsConfig *metrics.MetricsConfig) {
+func initCostModelMetrics(clusterCache clustercache.ClusterCache, provider models.Provider, clusterInfo clusters.ClusterInfoProvider, metricsConfig *metrics.MetricsConfig) {
 
 	disabledMetrics := metricsConfig.GetDisabledMetricsMap()
 	var toRegisterGV []*prometheus.GaugeVec
@@ -297,7 +297,7 @@ func initCostModelMetrics(clusterCache clustercache.ClusterCache, provider types
 type CostModelMetricsEmitter struct {
 	PrometheusClient promclient.Client
 	KubeClusterCache clustercache.ClusterCache
-	CloudProvider    types.Provider
+	CloudProvider    models.Provider
 	Model            *CostModel
 
 	// Metrics
@@ -323,7 +323,7 @@ type CostModelMetricsEmitter struct {
 }
 
 // NewCostModelMetricsEmitter creates a new cost-model metrics emitter. Use Start() to begin metric emission.
-func NewCostModelMetricsEmitter(promClient promclient.Client, clusterCache clustercache.ClusterCache, provider types.Provider, clusterInfo clusters.ClusterInfoProvider, model *CostModel) *CostModelMetricsEmitter {
+func NewCostModelMetricsEmitter(promClient promclient.Client, clusterCache clustercache.ClusterCache, provider models.Provider, clusterInfo clusters.ClusterInfoProvider, model *CostModel) *CostModelMetricsEmitter {
 
 	// Get metric configurations, if any
 	metricsConfig, err := metrics.GetMetricsConfig()
@@ -652,7 +652,7 @@ func (cmme *CostModelMetricsEmitter) Start() bool {
 				} else {
 					region = defaultRegion
 				}
-				cacPv := &types.PV{
+				cacPv := &models.PV{
 					Class:      pv.Spec.StorageClassName,
 					Region:     region,
 					Parameters: parameters,

+ 1 - 1
pkg/costmodel/networkcosts.go

@@ -1,7 +1,7 @@
 package costmodel
 
 import (
-	costAnalyzerCloud "github.com/opencost/opencost/pkg/cloud/types"
+	costAnalyzerCloud "github.com/opencost/opencost/pkg/cloud/models"
 	"github.com/opencost/opencost/pkg/env"
 	"github.com/opencost/opencost/pkg/log"
 	"github.com/opencost/opencost/pkg/prom"

+ 1 - 1
pkg/costmodel/promparsers.go

@@ -5,7 +5,7 @@ import (
 	"fmt"
 	"time"
 
-	costAnalyzerCloud "github.com/opencost/opencost/pkg/cloud/types"
+	costAnalyzerCloud "github.com/opencost/opencost/pkg/cloud/models"
 	"github.com/opencost/opencost/pkg/clustercache"
 	"github.com/opencost/opencost/pkg/env"
 	"github.com/opencost/opencost/pkg/log"

+ 4 - 3
pkg/costmodel/router.go

@@ -34,7 +34,8 @@ import (
 
 	"github.com/opencost/opencost/pkg/cloud"
 	"github.com/opencost/opencost/pkg/cloud/azure"
-	"github.com/opencost/opencost/pkg/cloud/types"
+	"github.com/opencost/opencost/pkg/cloud/models"
+	"github.com/opencost/opencost/pkg/cloud/utils"
 	"github.com/opencost/opencost/pkg/clustercache"
 	"github.com/opencost/opencost/pkg/costmodel/clusters"
 	"github.com/opencost/opencost/pkg/env"
@@ -85,7 +86,7 @@ type Accesses struct {
 	KubeClientSet       kubernetes.Interface
 	ClusterCache        clustercache.ClusterCache
 	ClusterMap          clusters.ClusterMap
-	CloudProvider       types.Provider
+	CloudProvider       models.Provider
 	ConfigFileManager   *config.ConfigFileManager
 	ClusterInfoProvider clusters.ClusterInfoProvider
 	Model               *CostModel
@@ -1622,7 +1623,7 @@ func Initialize(additionalConfigWatchers ...*watcher.ConfigMapWatcher) *Accesses
 		if err != nil {
 			log.Infof("Error saving cluster id %s", err.Error())
 		}
-		_, _, err = types.GetOrCreateClusterMeta(info["id"], info["name"])
+		_, _, err = utils.GetOrCreateClusterMeta(info["id"], info["name"])
 		if err != nil {
 			log.Infof("Unable to set cluster id '%s' for cluster '%s', %s", info["id"], info["name"], err.Error())
 		}

+ 3 - 3
pkg/costmodel/settings.go

@@ -4,7 +4,7 @@ import (
 	"fmt"
 	"time"
 
-	"github.com/opencost/opencost/pkg/cloud/types"
+	"github.com/opencost/opencost/pkg/cloud/models"
 	"github.com/opencost/opencost/pkg/log"
 	"github.com/patrickmn/go-cache"
 )
@@ -87,7 +87,7 @@ func (a *Accesses) customPricingHasChanged() bool {
 
 	// describe parameters by which we determine whether or not custom
 	// pricing settings have changed
-	encodeCustomPricing := func(cp *types.CustomPricing) string {
+	encodeCustomPricing := func(cp *models.CustomPricing) string {
 		return fmt.Sprintf("%s:%s:%s:%s:%s:%s:%s:%s:%s", cp.CustomPricesEnabled, cp.CPU, cp.SpotCPU,
 			cp.RAM, cp.SpotRAM, cp.GPU, cp.Storage, cp.CurrencyCode, cp.SharedOverhead)
 	}
@@ -127,7 +127,7 @@ func (a *Accesses) discountHasChanged() bool {
 
 	// describe parameters by which we determine whether or not custom
 	// pricing settings have changed
-	encodeDiscount := func(cp *types.CustomPricing) string {
+	encodeDiscount := func(cp *models.CustomPricing) string {
 		return fmt.Sprintf("%s:%s", cp.Discount, cp.NegotiatedDiscount)
 	}
 

+ 1 - 1
pkg/costmodel/sql.go

@@ -5,7 +5,7 @@ import (
 	"fmt"
 	"time"
 
-	costAnalyzerCloud "github.com/opencost/opencost/pkg/cloud/types"
+	costAnalyzerCloud "github.com/opencost/opencost/pkg/cloud/models"
 	"github.com/opencost/opencost/pkg/env"
 	"github.com/opencost/opencost/pkg/log"
 	"github.com/opencost/opencost/pkg/util"