AjayTripathy 6 лет назад
Родитель
Сommit
e79dab291d

+ 9 - 0
cloud/awsprovider.go

@@ -815,10 +815,18 @@ func (aws *AWS) NodePricing(k Key) (*Node, error) {
 func (awsProvider *AWS) ClusterInfo() (map[string]string, error) {
 	defaultClusterName := "AWS Cluster #1"
 	c, err := awsProvider.GetConfig()
+	remote := os.Getenv(remoteEnabled)
+	remoteEnabled := false
+	if os.Getenv(remote) == "true" {
+		remoteEnabled = true
+	}
+
 	if c.ClusterName != "" {
 		m := make(map[string]string)
 		m["name"] = c.ClusterName
 		m["provider"] = "AWS"
+		m["id"] = os.Getenv(KC_CLUSTER_ID)
+		m["remoteReadEnabled"] = strconv.FormatBool(remoteEnabled)
 		return m, nil
 	}
 	makeStructure := func(clusterName string) (map[string]string, error) {
@@ -827,6 +835,7 @@ func (awsProvider *AWS) ClusterInfo() (map[string]string, error) {
 		m["name"] = clusterName
 		m["provider"] = "AWS"
 		m["id"] = os.Getenv(KC_CLUSTER_ID)
+		m["remoteReadEnabled"] = strconv.FormatBool(remoteEnabled)
 		return m, nil
 	}
 

+ 15 - 1
cloud/azureprovider.go

@@ -326,7 +326,8 @@ func (az *Azure) DownloadPricingData() error {
 	containerServiceClient := containerservice.NewContainerServicesClient(config.AzureSubscriptionID)
 	containerServiceClient.Authorizer = authorizer
 
-	rateCardFilter := "OfferDurableId eq 'MS-AZR-0003p' and Currency eq 'USD' and Locale eq 'en-US' and RegionInfo eq 'US'"
+	rateCardFilter := fmt.Sprintf("OfferDurableId eq 'MS-AZR-0003p' and Currency eq '%s' and Locale eq 'en-US' and RegionInfo eq '%s'", config.CurrencyCode, config.AzureBillingRegion)
+	klog.Infof("Using ratecard query %s", rateCardFilter)
 	result, err := rcClient.Get(context.TODO(), rateCardFilter)
 	if err != nil {
 		return err
@@ -488,6 +489,12 @@ func (*Azure) GetDisks() ([]byte, error) {
 }
 
 func (az *Azure) ClusterInfo() (map[string]string, error) {
+	remote := os.Getenv(remoteEnabled)
+	remoteEnabled := false
+	if os.Getenv(remote) == "true" {
+		remoteEnabled = true
+	}
+
 	m := make(map[string]string)
 	m["name"] = "Azure Cluster #1"
 	c, err := az.GetConfig()
@@ -498,6 +505,7 @@ func (az *Azure) ClusterInfo() (map[string]string, error) {
 		m["name"] = c.ClusterName
 	}
 	m["provider"] = "azure"
+	m["remoteReadEnabled"] = strconv.FormatBool(remoteEnabled)
 	m["id"] = os.Getenv(KC_CLUSTER_ID)
 	return m, nil
 
@@ -554,6 +562,12 @@ func (az *Azure) GetConfig() (*CustomPricing, error) {
 	if c.Discount == "" {
 		c.Discount = "0%"
 	}
+	if c.CurrencyCode == "" {
+		c.CurrencyCode = "USD"
+	}
+	if c.AzureBillingRegion == "" {
+		c.AzureBillingRegion = "US"
+	}
 	if err != nil {
 		return nil, err
 	}

+ 6 - 0
cloud/gcpprovider.go

@@ -242,6 +242,11 @@ func (gcp *GCP) QuerySQL(query string) ([]*OutOfClusterAllocation, error) {
 
 // ClusterName returns the name of a GKE cluster, as provided by metadata.
 func (gcp *GCP) ClusterInfo() (map[string]string, error) {
+	remote := os.Getenv(remoteEnabled)
+	remoteEnabled := false
+	if os.Getenv(remote) == "true" {
+		remoteEnabled = true
+	}
 	metadataClient := metadata.NewClient(&http.Client{Transport: userAgentTransport{
 		userAgent: "kubecost",
 		base:      http.DefaultTransport,
@@ -264,6 +269,7 @@ func (gcp *GCP) ClusterInfo() (map[string]string, error) {
 	m["name"] = attribute
 	m["provider"] = "GCP"
 	m["id"] = os.Getenv(KC_CLUSTER_ID)
+	m["remoteReadEnabled"] = strconv.FormatBool(remoteEnabled)
 	return m, nil
 }
 

+ 1 - 0
cloud/provider.go

@@ -205,6 +205,7 @@ type CustomPricing struct {
 	AzureClientID         string `json:"azureClientID"`
 	AzureClientSecret     string `json:"azureClientSecret"`
 	AzureTenantID         string `json:"azureTenantID"`
+	AzureBillingRegion    string `json:"azureBillingRegion"`
 	CurrencyCode          string `json:"currencyCode"`
 	Discount              string `json:"discount"`
 	ClusterName           string `json:"clusterName"`

+ 67 - 18
costmodel/aggregations.go

@@ -27,9 +27,46 @@ type Aggregation struct {
 	GPUCost            float64   `json:"gpuCost"`
 	PVCost             float64   `json:"pvCost"`
 	NetworkCost        float64   `json:"networkCost"`
+	SharedCost         float64   `json:"sharedCost"`
 	TotalCost          float64   `json:"totalCost"`
 }
 
+type SharedResourceInfo struct {
+	ShareResources  bool
+	SharedNamespace map[string]bool
+	LabelSelectors  map[string]string
+}
+
+func (s *SharedResourceInfo) IsSharedResource(costDatum *CostData) bool {
+	if _, ok := s.SharedNamespace[costDatum.Namespace]; ok {
+		return true
+	}
+	for labelName, labelValue := range s.LabelSelectors {
+		if val, ok := costDatum.Labels[labelName]; ok {
+			if val == labelValue {
+				return true
+			}
+		}
+	}
+	return false
+}
+
+func NewSharedResourceInfo(shareResources bool, sharedNamespaces []string, labelnames []string, labelvalues []string) *SharedResourceInfo {
+	sr := &SharedResourceInfo{
+		ShareResources:  shareResources,
+		SharedNamespace: make(map[string]bool),
+		LabelSelectors:  make(map[string]string),
+	}
+	for _, ns := range sharedNamespaces {
+		sr.SharedNamespace[ns] = true
+	}
+	sr.SharedNamespace["kube-system"] = true // kube-system should be split by default
+	for i := range labelnames {
+		sr.LabelSelectors[labelnames[i]] = labelvalues[i]
+	}
+	return sr
+}
+
 func ComputeIdleCoefficient(costData map[string]*CostData, cli prometheusClient.Client, cloud costAnalyzerCloud.Provider, discount float64, windowString, offset string) (float64, error) {
 	windowDuration, err := time.ParseDuration(windowString)
 	if err != nil {
@@ -58,25 +95,36 @@ func ComputeIdleCoefficient(costData map[string]*CostData, cli prometheusClient.
 	return (totalContainerCost / totalClusterCostOverWindow), nil
 }
 
-func AggregateCostModel(costData map[string]*CostData, discount float64, idleCoefficient float64, aggregationField string, aggregationSubField string) map[string]*Aggregation {
+func AggregateCostModel(costData map[string]*CostData, discount float64, idleCoefficient float64, sr *SharedResourceInfo, aggregationField string, aggregationSubField string) map[string]*Aggregation {
 	aggregations := make(map[string]*Aggregation)
+	sharedResourceCost := 0.0
 	for _, costDatum := range costData {
-		if aggregationField == "cluster" {
-			aggregationHelper(costDatum, aggregationField, aggregationSubField, costDatum.ClusterID, aggregations, discount, idleCoefficient)
-		} else if aggregationField == "namespace" {
-			aggregationHelper(costDatum, aggregationField, aggregationSubField, costDatum.Namespace, aggregations, discount, idleCoefficient)
-		} else if aggregationField == "service" {
-			if len(costDatum.Services) > 0 {
-				aggregationHelper(costDatum, aggregationField, aggregationSubField, costDatum.Services[0], aggregations, discount, idleCoefficient)
+		if sr != nil && sr.ShareResources && sr.IsSharedResource(costDatum) {
+			cpuv, ramv, gpuv, pvvs := getPriceVectors(costDatum, discount, idleCoefficient)
+			sharedResourceCost += totalVector(cpuv)
+			sharedResourceCost += totalVector(ramv)
+			sharedResourceCost += totalVector(gpuv)
+			for _, pv := range pvvs {
+				sharedResourceCost += totalVector(pv)
 			}
-		} else if aggregationField == "deployment" {
-			if len(costDatum.Deployments) > 0 {
-				aggregationHelper(costDatum, aggregationField, aggregationSubField, costDatum.Deployments[0], aggregations, discount, idleCoefficient)
-			}
-		} else if aggregationField == "label" {
-			if costDatum.Labels != nil {
-				if subfieldName, ok := costDatum.Labels[aggregationSubField]; ok {
-					aggregationHelper(costDatum, aggregationField, aggregationSubField, subfieldName, aggregations, discount, idleCoefficient)
+		} else {
+			if aggregationField == "cluster" {
+				aggregationHelper(costDatum, aggregationField, aggregationSubField, costDatum.ClusterID, aggregations, discount, idleCoefficient)
+			} else if aggregationField == "namespace" {
+				aggregationHelper(costDatum, aggregationField, aggregationSubField, costDatum.Namespace, aggregations, discount, idleCoefficient)
+			} else if aggregationField == "service" {
+				if len(costDatum.Services) > 0 {
+					aggregationHelper(costDatum, aggregationField, aggregationSubField, costDatum.Services[0], aggregations, discount, idleCoefficient)
+				}
+			} else if aggregationField == "deployment" {
+				if len(costDatum.Deployments) > 0 {
+					aggregationHelper(costDatum, aggregationField, aggregationSubField, costDatum.Deployments[0], aggregations, discount, idleCoefficient)
+				}
+			} else if aggregationField == "label" {
+				if costDatum.Labels != nil {
+					if subfieldName, ok := costDatum.Labels[aggregationSubField]; ok {
+						aggregationHelper(costDatum, aggregationField, aggregationSubField, subfieldName, aggregations, discount, idleCoefficient)
+					}
 				}
 			}
 		}
@@ -86,7 +134,8 @@ func AggregateCostModel(costData map[string]*CostData, discount float64, idleCoe
 		agg.RAMCost = totalVector(agg.RAMCostVector)
 		agg.GPUCost = totalVector(agg.GPUCostVector)
 		agg.PVCost = totalVector(agg.PVCostVector)
-		agg.TotalCost = agg.CPUCost + agg.RAMCost + agg.GPUCost + agg.PVCost
+		agg.SharedCost = sharedResourceCost / float64(len(aggregations))
+		agg.TotalCost = agg.CPUCost + agg.RAMCost + agg.GPUCost + agg.PVCost + agg.SharedCost
 	}
 	return aggregations
 }
@@ -228,4 +277,4 @@ func addVectors(req []*Vector, used []*Vector) []*Vector {
 	}
 
 	return allocation
-}
+}

+ 15 - 6
costmodel/costmodel.go

@@ -667,9 +667,12 @@ func findDeletedPodInfo(cli prometheusClient.Client, missingContainers map[strin
 
 		podLabelsResult, err := Query(cli, queryHistoricalPodLabels)
 		if err != nil {
-			return fmt.Errorf("Error fetching historical pod labels: " + err.Error())
+			return fmt.Errorf("Error fetching historical pod labels: %s", err.Error())
 		}
 		podLabels, err := labelsFromPrometheusQuery(podLabelsResult)
+		if err != nil {
+			klog.V(1).Infof("Error parsing historical labels: %s", err.Error())
+		}
 		for key, costData := range missingContainers {
 			cm, _ := NewContainerMetricFromKey(key)
 			labels, ok := podLabels[cm.PodName]
@@ -690,8 +693,16 @@ func findDeletedPodInfo(cli prometheusClient.Client, missingContainers map[strin
 }
 
 func labelsFromPrometheusQuery(qr interface{}) (map[string]map[string]string, error) {
+	data, ok := qr.(map[string]interface{})["data"]
+	if !ok {
+		e, err := wrapPrometheusError(qr)
+		if err != nil {
+			return nil, err
+		}
+		return nil, fmt.Errorf(e)
+	}
 	toReturn := make(map[string]map[string]string)
-	for _, val := range qr.(map[string]interface{})["data"].(map[string]interface{})["result"].([]interface{}) {
+	for _, val := range data.(map[string]interface{})["result"].([]interface{}) {
 		metricInterface, ok := val.(map[string]interface{})["metric"]
 		if !ok {
 			return nil, fmt.Errorf("Metric field does not exist in data result vector")
@@ -1103,7 +1114,7 @@ func getPodDeployments(cache ClusterCache, podList []*v1.Pod) (map[string]map[st
 }
 
 func (cm *CostModel) ComputeCostDataRange(cli prometheusClient.Client, clientset kubernetes.Interface, cloud costAnalyzerCloud.Provider,
-	startString, endString, windowString string, filterNamespace string) (map[string]*CostData, error) {
+	startString, endString, windowString string, filterNamespace string, remoteEnabled bool) (map[string]*CostData, error) {
 	queryRAMRequests := fmt.Sprintf(queryRAMRequestsStr, windowString, "", windowString, "")
 	queryRAMUsage := fmt.Sprintf(queryRAMUsageStr, windowString, "", windowString, "")
 	queryCPURequests := fmt.Sprintf(queryCPURequestsStr, windowString, "", windowString, "")
@@ -1133,8 +1144,7 @@ func (cm *CostModel) ComputeCostDataRange(cli prometheusClient.Client, clientset
 		return nil, err
 	}
 	clustID := os.Getenv(CLUSTER_ID)
-	remoteEnabled := os.Getenv(remoteEnabled)
-	if remoteEnabled == "true" {
+	if remoteEnabled == true {
 		remoteLayout := "2006-01-02T15:04:05Z"
 		remoteStartStr := start.Format(remoteLayout)
 		remoteEndStr := end.Format(remoteLayout)
@@ -1526,7 +1536,6 @@ func (cm *CostModel) ComputeCostDataRange(cli prometheusClient.Client, clientset
 		if err != nil {
 			return nil, err
 		}
-		klog.Infof("Finding deleted pod info from range query:")
 		err = findDeletedPodInfo(cli, missingContainers, wStr)
 		if err != nil {
 			return nil, err

+ 0 - 5
costmodel/watchcontroller.go

@@ -7,7 +7,6 @@ import (
 
 	"k8s.io/klog"
 
-	v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"k8s.io/apimachinery/pkg/fields"
 	rt "k8s.io/apimachinery/pkg/runtime"
 	"k8s.io/apimachinery/pkg/util/runtime"
@@ -129,14 +128,10 @@ func (c *CachingWatchController) handle(key string) error {
 	}
 
 	if !exists {
-		klog.V(3).Infof("Removed %s for key: %s\n", c.resourceType, key)
-
 		if c.removeHandler != nil {
 			c.removeHandler(key)
 		}
 	} else {
-		klog.V(3).Infof("Updated %s: %s\n", c.resourceType, obj.(v1.Object).GetName())
-
 		if c.updateHandler != nil {
 			c.updateHandler(obj)
 		}

+ 62 - 27
main.go

@@ -41,6 +41,8 @@ var (
 	gitCommit string
 )
 
+var Router = httprouter.New()
+
 type Accesses struct {
 	PrometheusClient              prometheusClient.Client
 	KubeClientSet                 kubernetes.Interface
@@ -155,7 +157,7 @@ func (a *Accesses) CostDataModel(w http.ResponseWriter, r *http.Request, ps http
 			w.Write(wrapData(nil, err))
 		}
 		discount = discount * 0.01
-		agg := costModel.AggregateCostModel(data, discount, 1.0, aggregation, aggregationSubField)
+		agg := costModel.AggregateCostModel(data, discount, 1.0, nil, aggregation, aggregationSubField)
 		w.Write(wrapData(agg, nil))
 	} else {
 		if fields != "" {
@@ -208,6 +210,9 @@ func (a *Accesses) AggregateCostModel(w http.ResponseWriter, r *http.Request, ps
 	namespace := r.URL.Query().Get("namespace")
 	aggregationSubField := r.URL.Query().Get("aggregationSubfield")
 	allocateIdle := r.URL.Query().Get("allocateIdle")
+	sharedNamespaces := r.URL.Query().Get("sharedNamespaces")
+	sharedLabelNames := r.URL.Query().Get("sharedLabelNames")
+	sharedLabelValues := r.URL.Query().Get("sharedLabelValues")
 
 	endTime := time.Now()
 	if offset != "" {
@@ -242,7 +247,15 @@ func (a *Accesses) AggregateCostModel(w http.ResponseWriter, r *http.Request, ps
 	start := startTime.Format(layout)
 	end := endTime.Format(layout)
 
-	data, err := a.Model.ComputeCostDataRange(a.PrometheusClient, a.KubeClientSet, a.Cloud, start, end, "1h", namespace)
+	remote := r.URL.Query().Get("remote")
+
+	remoteAvailable := os.Getenv(remoteEnabled)
+	remoteEnabled := false
+	if remoteAvailable == "true" && remote != "false" {
+		remoteEnabled = true
+	}
+	klog.Infof("REMOTE ENABLED: %t", remoteEnabled)
+	data, err := a.Model.ComputeCostDataRange(a.PrometheusClient, a.KubeClientSet, a.Cloud, start, end, "1h", namespace, remoteEnabled)
 	if err != nil {
 		w.Write(wrapData(nil, err))
 		return
@@ -269,7 +282,25 @@ func (a *Accesses) AggregateCostModel(w http.ResponseWriter, r *http.Request, ps
 	}
 
 	if aggregation != "" {
-		agg := costModel.AggregateCostModel(data, discount, idleCoefficient, aggregation, aggregationSubField)
+		sn := []string{}
+		sln := []string{}
+		slv := []string{}
+		if sharedNamespaces != "" {
+			sn = strings.Split(sharedNamespaces, ",")
+		}
+		if sharedLabelNames != "" {
+			sln = strings.Split(sharedLabelNames, ",")
+			slv = strings.Split(sharedLabelValues, ",")
+			if len(sln) != len(slv) || slv[0] == "" {
+				w.Write(wrapData(nil, fmt.Errorf("Supply exacly one label value per label name")))
+				return
+			}
+		}
+		var s *costModel.SharedResourceInfo
+		if len(sn) > 0 || len(sln) > 0 {
+			s = costModel.NewSharedResourceInfo(true, sn, sln, slv)
+		}
+		agg := costModel.AggregateCostModel(data, discount, idleCoefficient, s, aggregation, aggregationSubField)
 		w.Write(wrapData(agg, nil))
 	}
 }
@@ -285,8 +316,14 @@ func (a *Accesses) CostDataModelRange(w http.ResponseWriter, r *http.Request, ps
 	namespace := r.URL.Query().Get("namespace")
 	aggregation := r.URL.Query().Get("aggregation")
 	aggregationSubField := r.URL.Query().Get("aggregationSubfield")
+	remote := r.URL.Query().Get("remote")
 
-	data, err := a.Model.ComputeCostDataRange(a.PrometheusClient, a.KubeClientSet, a.Cloud, start, end, window, namespace)
+	remoteAvailable := os.Getenv(remoteEnabled)
+	remoteEnabled := false
+	if remoteAvailable == "true" && remote != "false" {
+		remoteEnabled = true
+	}
+	data, err := a.Model.ComputeCostDataRange(a.PrometheusClient, a.KubeClientSet, a.Cloud, start, end, window, namespace, remoteEnabled)
 	if err != nil {
 		w.Write(wrapData(nil, err))
 	}
@@ -300,7 +337,7 @@ func (a *Accesses) CostDataModelRange(w http.ResponseWriter, r *http.Request, ps
 			w.Write(wrapData(nil, err))
 		}
 		discount = discount * 0.01
-		agg := costModel.AggregateCostModel(data, discount, 1.0, aggregation, aggregationSubField)
+		agg := costModel.AggregateCostModel(data, discount, 1.0, nil, aggregation, aggregationSubField)
 		w.Write(wrapData(agg, nil))
 	} else {
 		if fields != "" {
@@ -573,7 +610,6 @@ func (a *Accesses) recordPrices() {
 				if podStatus[podName] == v1.PodRunning { // Only report data for current pods
 					containerSeen[labelKey] = true
 				} else {
-					klog.Infof("Container %s not running", labelKey)
 					containerSeen[labelKey] = false
 				}
 
@@ -828,29 +864,28 @@ func main() {
 
 	a.recordPrices()
 
-	router := httprouter.New()
-	router.GET("/costDataModel", a.CostDataModel)
-	router.GET("/costDataModelRange", a.CostDataModelRange)
-	router.GET("/costDataModelRangeLarge", a.CostDataModelRangeLarge)
-	router.GET("/outOfClusterCosts", a.OutofClusterCosts)
-	router.GET("/allNodePricing", a.GetAllNodePricing)
-	router.GET("/healthz", Healthz)
-	router.GET("/getConfigs", a.GetConfigs)
-	router.POST("/refreshPricing", a.RefreshPricingData)
-	router.POST("/updateSpotInfoConfigs", a.UpdateSpotInfoConfigs)
-	router.POST("/updateAthenaInfoConfigs", a.UpdateAthenaInfoConfigs)
-	router.POST("/updateBigQueryInfoConfigs", a.UpdateBigQueryInfoConfigs)
-	router.POST("/updateConfigByKey", a.UpdateConfigByKey)
-	router.GET("/clusterCostsOverTime", a.ClusterCostsOverTime)
-	router.GET("/clusterCosts", a.ClusterCosts)
-	router.GET("/validatePrometheus", a.GetPrometheusMetadata)
-	router.GET("/managementPlatform", a.ManagementPlatform)
-	router.GET("/clusterInfo", a.ClusterInfo)
-	router.GET("/containerUptimes", a.ContainerUptimes)
-	router.GET("/aggregatedCostModel", a.AggregateCostModel)
+	Router.GET("/costDataModel", a.CostDataModel)
+	Router.GET("/costDataModelRange", a.CostDataModelRange)
+	Router.GET("/costDataModelRangeLarge", a.CostDataModelRangeLarge)
+	Router.GET("/outOfClusterCosts", a.OutofClusterCosts)
+	Router.GET("/allNodePricing", a.GetAllNodePricing)
+	Router.GET("/healthz", Healthz)
+	Router.GET("/getConfigs", a.GetConfigs)
+	Router.POST("/refreshPricing", a.RefreshPricingData)
+	Router.POST("/updateSpotInfoConfigs", a.UpdateSpotInfoConfigs)
+	Router.POST("/updateAthenaInfoConfigs", a.UpdateAthenaInfoConfigs)
+	Router.POST("/updateBigQueryInfoConfigs", a.UpdateBigQueryInfoConfigs)
+	Router.POST("/updateConfigByKey", a.UpdateConfigByKey)
+	Router.GET("/clusterCostsOverTime", a.ClusterCostsOverTime)
+	Router.GET("/clusterCosts", a.ClusterCosts)
+	Router.GET("/validatePrometheus", a.GetPrometheusMetadata)
+	Router.GET("/managementPlatform", a.ManagementPlatform)
+	Router.GET("/clusterInfo", a.ClusterInfo)
+	Router.GET("/containerUptimes", a.ContainerUptimes)
+	Router.GET("/aggregatedCostModel", a.AggregateCostModel)
 
 	rootMux := http.NewServeMux()
-	rootMux.Handle("/", router)
+	rootMux.Handle("/", Router)
 	rootMux.Handle("/metrics", promhttp.Handler())
 
 	klog.Fatal(http.ListenAndServe(":9003", rootMux))

+ 4 - 4
test/historical_pod_test.go

@@ -190,11 +190,11 @@ func TestPodUpDown(t *testing.T) {
 	log.Printf("Starting at %s \n", startStr)
 	log.Printf("Ending at %s \n", endStr)
 	provider.DownloadPricingData()
-	data, err := cm.ComputeCostDataRange(promCli, rclient, provider, startStr, endStr, "1m", "")
+	data, err := cm.ComputeCostDataRange(promCli, rclient, provider, startStr, endStr, "1m", "", false)
 	if err != nil {
 		panic(err)
 	}
-	agg := costModel.AggregateCostModel(data, 0.0, "namespace", "")
+	agg := costModel.AggregateCostModel(data, 0.0, 1.0, nil, "namespace", "")
 	_, ok := agg["test"]
 	assert.Assert(t, ok)
 
@@ -202,11 +202,11 @@ func TestPodUpDown(t *testing.T) {
 	if err != nil {
 		panic(err)
 	}
-	agg2 := costModel.AggregateCostModel(data2, 0.0, "namespace", "")
+	agg2 := costModel.AggregateCostModel(data2, 0.0, 1.0, nil, "namespace", "")
 	_, ok2 := agg2["test"]
 	assert.Assert(t, ok2)
 
-	agg3 := costModel.AggregateCostModel(data, 0.0, "label", "testaggregation")
+	agg3 := costModel.AggregateCostModel(data, 0.0, 1.0, nil, "label", "testaggregation")
 	_, ok3 := agg3["foo"]
 	assert.Assert(t, ok3)
 }