Просмотр исходного кода

Merge pull request #196 from kubecost/AjayTripathy-integration-tests-ic

run integration tests in cluster
Ajay Tripathy 6 лет назад
Родитель
Сommit
fbf909cd62

+ 47 - 32
costmodel/aggregations.go

@@ -74,49 +74,60 @@ func NewSharedResourceInfo(shareResources bool, sharedNamespaces []string, label
 	return sr
 }
 
-func ComputeIdleCoefficient(costData map[string]*CostData, cli prometheusClient.Client, cp cloud.Provider, discount float64, windowString, offset string) (float64, error) {
+func ComputeIdleCoefficient(costData map[string]*CostData, cli prometheusClient.Client, cp cloud.Provider, discount float64, windowString, offset string) (map[string]float64, error) {
+
+	coefficients := make(map[string]float64)
+
 	windowDuration, err := time.ParseDuration(windowString)
 	if err != nil {
-		return 0.0, err
-	}
-	totals, err := ClusterCosts(cli, cp, windowString, offset)
-	if err != nil {
-		return 0.0, err
-	}
-	cpuCost, err := strconv.ParseFloat(totals.CPUCost[0][1], 64)
-	if err != nil {
-		return 0.0, err
-	}
-	memCost, err := strconv.ParseFloat(totals.MemCost[0][1], 64)
-	if err != nil {
-		return 0.0, err
+		return nil, err
 	}
-	storageCost, err := strconv.ParseFloat(totals.StorageCost[0][1], 64)
+	tempCoefficient := make(map[string]float64)
+
+	aggregateContainerCosts := AggregateCostData(cp, costData, 0, "cluster", []string{}, "", false, discount, tempCoefficient, nil)
+	allTotals, err := ClusterCostsForAllClusters(cli, cp, windowString, offset)
 	if err != nil {
-		return 0.0, err
-	}
-	totalClusterCost := (cpuCost * (1 - discount)) + (memCost * (1 - discount)) + storageCost
-	if err != nil || totalClusterCost == 0.0 {
-		return 0.0, err
+		return nil, err
 	}
-	totalClusterCostOverWindow := (totalClusterCost / 730) * windowDuration.Hours()
-	totalContainerCost := 0.0
-	for _, costDatum := range costData {
-		cpuv, ramv, gpuv, pvvs, _ := getPriceVectors(cp, costDatum, "", discount, 1)
-		totalContainerCost += totalVector(cpuv)
-		totalContainerCost += totalVector(ramv)
-		totalContainerCost += totalVector(gpuv)
-		for _, pv := range pvvs {
-			totalContainerCost += totalVector(pv)
+	for cid, totals := range allTotals {
+
+		cpuCost, err := strconv.ParseFloat(totals.CPUCost[0][1], 64)
+		if err != nil {
+			return nil, err
+		}
+		memCost, err := strconv.ParseFloat(totals.MemCost[0][1], 64)
+		if err != nil {
+			return nil, err
+		}
+		storageCost, err := strconv.ParseFloat(totals.StorageCost[0][1], 64)
+		if err != nil {
+			return nil, err
+		}
+		totalClusterCost := (cpuCost * (1 - discount)) + (memCost * (1 - discount)) + storageCost
+		if err != nil || totalClusterCost == 0.0 {
+			return nil, err
 		}
+		totalClusterCostOverWindow := (totalClusterCost / 730) * windowDuration.Hours()
+		totalContainerCost := 0.0
+		for _, costDatum := range costData {
+			cpuv, ramv, gpuv, pvvs, _ := getPriceVectors(cp, costDatum, "", discount, 1)
+			totalContainerCost += totalVector(cpuv)
+			totalContainerCost += totalVector(ramv)
+			totalContainerCost += totalVector(gpuv)
+			for _, pv := range pvvs {
+				totalContainerCost += totalVector(pv)
+			}
+		}
+
+		coefficients[cid] = aggregateContainerCosts[cid].TotalCost / totalClusterCostOverWindow
 	}
 
-	return (totalContainerCost / totalClusterCostOverWindow), nil
+	return coefficients, nil
 }
 
 // AggregateCostData reduces the dimensions of raw cost data by field and, optionally, by time. The field parameter determines the field
 // by which to group data, with an optional subfield, e.g. for groupings like field="label" and subfield="app" for grouping by "label.app".
-func AggregateCostData(cp cloud.Provider, costData map[string]*CostData, dataCount int64, field string, subfields []string, rate string, timeSeries bool, discount float64, idleCoefficient float64, sr *SharedResourceInfo) map[string]*Aggregation {
+func AggregateCostData(cp cloud.Provider, costData map[string]*CostData, dataCount int64, field string, subfields []string, rate string, timeSeries bool, discount float64, idleCoefficients map[string]float64, sr *SharedResourceInfo) map[string]*Aggregation {
 	// aggregations collects key-value pairs of resource group-to-aggregated data
 	// e.g. namespace-to-data or label-value-to-data
 	aggregations := make(map[string]*Aggregation)
@@ -126,6 +137,10 @@ func AggregateCostData(cp cloud.Provider, costData map[string]*CostData, dataCou
 	sharedResourceCost := 0.0
 
 	for _, costDatum := range costData {
+		idleCoefficient, ok := idleCoefficients[costDatum.ClusterID]
+		if !ok {
+			idleCoefficient = 1.0
+		}
 		if sr != nil && sr.ShareResources && sr.IsSharedResource(costDatum) {
 			cpuv, ramv, gpuv, pvvs, netv := getPriceVectors(cp, costDatum, rate, discount, idleCoefficient)
 			sharedResourceCost += totalVector(cpuv)
@@ -162,7 +177,7 @@ func AggregateCostData(cp cloud.Provider, costData map[string]*CostData, dataCou
 					}
 				}
 			} else if field == "pod" {
-				aggregateDatum(cp, aggregations, costDatum, field, subfields, rate, costDatum.PodName, discount, idleCoefficient)
+				aggregateDatum(cp, aggregations, costDatum, field, subfields, rate, costDatum.Namespace+"/"+costDatum.PodName, discount, idleCoefficient)
 			}
 		}
 	}

+ 118 - 31
costmodel/cluster.go

@@ -2,6 +2,7 @@ package costmodel
 
 import (
 	"fmt"
+	"os"
 	"time"
 
 	costAnalyzerCloud "github.com/kubecost/cost-model/cloud"
@@ -12,24 +13,24 @@ import (
 
 const (
 	queryClusterCores = `sum(
-		avg(kube_node_status_capacity_cpu_cores %s) by (node) * avg(node_cpu_hourly_cost %s) by (node) * 730 +
-		avg(node_gpu_hourly_cost %s) by (node) * 730
-	  )`
+		avg(kube_node_status_capacity_cpu_cores %s) by (node, cluster_id) * avg(node_cpu_hourly_cost %s) by (node, cluster_id) * 730 +
+		avg(node_gpu_hourly_cost %s) by (node, cluster_id) * 730
+	  ) by (cluster_id)`
 
 	queryClusterRAM = `sum(
-		avg(kube_node_status_capacity_memory_bytes %s) by (node) / 1024 / 1024 / 1024 * avg(node_ram_hourly_cost %s) by (node) * 730
-	  )`
+		avg(kube_node_status_capacity_memory_bytes %s) by (node, cluster_id) / 1024 / 1024 / 1024 * avg(node_ram_hourly_cost %s) by (node, cluster_id) * 730
+	  ) by (cluster_id)`
 
 	queryStorage = `sum(
-		avg(avg_over_time(pv_hourly_cost[%s] %s)) by (persistentvolume) * 730 
-		* avg(avg_over_time(kube_persistentvolume_capacity_bytes[%s] %s)) by (persistentvolume) / 1024 / 1024 / 1024
-	  ) %s`
+		avg(avg_over_time(pv_hourly_cost[%s] %s)) by (persistentvolume, cluster_id) * 730 
+		* avg(avg_over_time(kube_persistentvolume_capacity_bytes[%s] %s)) by (persistentvolume, cluster_id) / 1024 / 1024 / 1024
+	  ) by (cluster_id) %s`
 
-	queryTotal = `sum(avg(node_total_hourly_cost) by (node)) * 730 +
+	queryTotal = `sum(avg(node_total_hourly_cost) by (node, cluster_id)) * 730 +
 	  sum(
-		avg(avg_over_time(pv_hourly_cost[1h])) by (persistentvolume) * 730 
-		* avg(avg_over_time(kube_persistentvolume_capacity_bytes[1h])) by (persistentvolume) / 1024 / 1024 / 1024
-	  ) %s`
+		avg(avg_over_time(pv_hourly_cost[1h])) by (persistentvolume, cluster_id) * 730 
+		* avg(avg_over_time(kube_persistentvolume_capacity_bytes[1h])) by (persistentvolume, cluster_id) / 1024 / 1024 / 1024
+	  ) by (cluster_id) %s`
 )
 
 type Totals struct {
@@ -79,14 +80,16 @@ func resultToTotals(qr interface{}) ([][]string, error) {
 	return totals, nil
 }
 
-func resultToTotal(qr interface{}) ([][]string, error) {
+func resultToTotal(qr interface{}) (map[string][][]string, error) {
+	defaultClusterID := os.Getenv(clusterIDKey)
+
 	data, ok := qr.(map[string]interface{})["data"]
 	if !ok {
 		e, err := wrapPrometheusError(qr)
 		if err != nil {
 			return nil, err
 		}
-		return nil, fmt.Errorf(e)
+		return nil, fmt.Errorf("Prometheus query error: %s", e)
 	}
 	r, ok := data.(map[string]interface{})["result"]
 	if !ok {
@@ -99,22 +102,104 @@ func resultToTotal(qr interface{}) ([][]string, error) {
 	if len(results) == 0 {
 		return nil, fmt.Errorf("Not enough data available in the selected time range")
 	}
-	val, ok := results[0].(map[string]interface{})["value"]
-	totals := [][]string{}
-	if !ok {
-		return nil, fmt.Errorf("Improperly formatted results from prometheus, value is not a field in the vector")
+	toReturn := make(map[string][][]string)
+	for i := range results {
+		metrics, ok := results[i].(map[string]interface{})["metric"]
+		if !ok {
+			return nil, fmt.Errorf("Improperly formatted results from prometheus, metric is not a field in the vector")
+		}
+		metricMap, ok := metrics.(map[string]interface{})
+		cid, ok := metricMap["cluster_id"]
+		if !ok {
+			klog.V(4).Info("Prometheus vector does not have cluster id")
+			cid = defaultClusterID
+		}
+		clusterID, ok := cid.(string)
+		if !ok {
+			return nil, fmt.Errorf("Prometheus vector does not have string cluster_id")
+		}
+
+		val, ok := results[i].(map[string]interface{})["value"]
+		if !ok {
+			return nil, fmt.Errorf("Improperly formatted results from prometheus, value is not a field in the vector")
+		}
+		dataPoint, ok := val.([]interface{})
+		if !ok || len(dataPoint) != 2 {
+			return nil, fmt.Errorf("Improperly formatted datapoint from Prometheus")
+		}
+		d0 := fmt.Sprintf("%f", dataPoint[0].(float64))
+		toAppend := []string{
+			d0,
+			dataPoint[1].(string),
+		}
+		if t, ok := toReturn[clusterID]; ok {
+			t = append(t, toAppend)
+		} else {
+			toReturn[clusterID] = [][]string{toAppend}
+		}
 	}
-	dataPoint, ok := val.([]interface{})
-	if !ok || len(dataPoint) != 2 {
-		return nil, fmt.Errorf("Improperly formatted datapoint from Prometheus")
+	return toReturn, nil
+}
+
+// ClusterCostsForAllClusters gives the cluster costs averaged over a window of time for all clusters.
+func ClusterCostsForAllClusters(cli prometheusClient.Client, cloud costAnalyzerCloud.Provider, windowString, offset string) (map[string]*Totals, error) {
+
+	offset = fmt.Sprintf("offset 3h") // Set offset to 3h for block sync
+
+	qCores := fmt.Sprintf(queryClusterCores, offset, offset, offset)
+	qRAM := fmt.Sprintf(queryClusterRAM, offset, offset)
+	qStorage := fmt.Sprintf(queryStorage, windowString, offset, windowString, offset, "")
+
+	resultClusterCores, err := Query(cli, qCores)
+	if err != nil {
+		return nil, fmt.Errorf("Error for query %s: %s", qCores, err.Error())
 	}
-	d0 := fmt.Sprintf("%f", dataPoint[0].(float64))
-	toAppend := []string{
-		d0,
-		dataPoint[1].(string),
+	resultClusterRAM, err := Query(cli, qRAM)
+	if err != nil {
+		return nil, fmt.Errorf("Error for query %s: %s", qRAM, err.Error())
 	}
-	totals = append(totals, toAppend)
-	return totals, nil
+
+	resultStorage, err := Query(cli, qStorage)
+	if err != nil {
+		return nil, fmt.Errorf("Error for query %s: %s", qStorage, err.Error())
+	}
+
+	toReturn := make(map[string]*Totals)
+
+	coreTotal, err := resultToTotal(resultClusterCores)
+	if err != nil {
+		return nil, fmt.Errorf("Error for query %s: %s", qCores, err.Error())
+	}
+	for clusterID, total := range coreTotal {
+		if _, ok := toReturn[clusterID]; !ok {
+			toReturn[clusterID] = &Totals{}
+		}
+		toReturn[clusterID].CPUCost = total
+	}
+
+	ramTotal, err := resultToTotal(resultClusterRAM)
+	if err != nil {
+		return nil, fmt.Errorf("Error for query %s: %s", qRAM, err.Error())
+	}
+	for clusterID, total := range ramTotal {
+		if _, ok := toReturn[clusterID]; !ok {
+			toReturn[clusterID] = &Totals{}
+		}
+		toReturn[clusterID].MemCost = total
+	}
+
+	storageTotal, err := resultToTotal(resultStorage)
+	if err != nil {
+		return nil, fmt.Errorf("Error for query %s: %s", qStorage, err.Error())
+	}
+	for clusterID, total := range storageTotal {
+		if _, ok := toReturn[clusterID]; !ok {
+			toReturn[clusterID] = &Totals{}
+		}
+		toReturn[clusterID].StorageCost = total
+	}
+
+	return toReturn, nil
 }
 
 // ClusterCosts gives the current full cluster costs averaged over a window of time.
@@ -177,11 +262,13 @@ func ClusterCosts(cli prometheusClient.Client, cloud costAnalyzerCloud.Provider,
 		return nil, err
 	}
 
+	defaultClusterID := os.Getenv(clusterIDKey)
+
 	return &Totals{
-		TotalCost:   clusterTotal,
-		CPUCost:     coreTotal,
-		MemCost:     ramTotal,
-		StorageCost: storageTotal,
+		TotalCost:   clusterTotal[defaultClusterID],
+		CPUCost:     coreTotal[defaultClusterID],
+		MemCost:     ramTotal[defaultClusterID],
+		StorageCost: storageTotal[defaultClusterID],
 	}, nil
 }
 

+ 2 - 2
costmodel/costmodel.go

@@ -1868,12 +1868,12 @@ func QueryRange(cli prometheusClient.Client, query string, start, end time.Time,
 		return nil, err
 	}
 
-	resp, body, warnings, err := cli.Do(context.Background(), req)
+	_, body, warnings, err := cli.Do(context.Background(), req)
 	for _, w := range warnings {
 		klog.V(3).Infof("%s", w)
 	}
 	if err != nil {
-		return nil, fmt.Errorf("%s Error %s fetching query %s", resp.StatusCode, err.Error(), query)
+		return nil, fmt.Errorf("Error %s fetching query %s", err.Error(), query)
 	}
 	var toReturn interface{}
 	err = json.Unmarshal(body, &toReturn)

+ 9 - 5
costmodel/router.go

@@ -211,8 +211,8 @@ func (a *Accesses) CostDataModel(w http.ResponseWriter, r *http.Request, ps http
 		// This assumes hourly data, incremented by one to capture the 0th data point.
 		dataCount := int64(dur.Hours()) + 1
 		klog.V(1).Infof("for duration %s dataCount = %d", dur.String(), dataCount)
-
-		agg := AggregateCostData(a.Cloud, data, dataCount, aggregationField, subfields, "", false, discount, 1.0, nil)
+		defaultIdleCoefficientMap := make(map[string]float64)
+		agg := AggregateCostData(a.Cloud, data, dataCount, aggregationField, subfields, "", false, discount, defaultIdleCoefficientMap, nil)
 		w.Write(wrapData(agg, nil))
 	} else {
 		if fields != "" {
@@ -417,10 +417,13 @@ func (a *Accesses) AggregateCostModel(w http.ResponseWriter, r *http.Request, ps
 	}
 	discount = discount * 0.01
 
-	idleCoefficient := 1.0
+	idleCoefficient := make(map[string]float64)
 	if allocateIdle {
 		windowStr := fmt.Sprintf("%dh", int(dur.Hours()))
-		idleCoefficient, err = ComputeIdleCoefficient(data, a.PrometheusClient, a.Cloud, discount, windowStr, offset)
+		if a.ThanosClient != nil {
+			offset = "3h"
+		}
+		idleCoefficient, err = ComputeIdleCoefficient(data, pClient, a.Cloud, discount, windowStr, offset)
 		if err != nil {
 			klog.V(1).Infof("error computing idle coefficient: windowString=%s, offset=%s, err=%s", windowStr, offset, err)
 			w.Write(wrapData(nil, err))
@@ -524,7 +527,8 @@ func (a *Accesses) CostDataModelRange(w http.ResponseWriter, r *http.Request, ps
 		dataCount := (int64(dur.Hours()) / windowHrs) + 1
 		klog.V(1).Infof("for duration %s dataCount = %d", dur.String(), dataCount)
 
-		agg := AggregateCostData(a.Cloud, data, dataCount, aggregationField, subfields, "", false, discount, 1.0, nil)
+		defaultIdleCoefficientMap := make(map[string]float64)
+		agg := AggregateCostData(a.Cloud, data, dataCount, aggregationField, subfields, "", false, discount, defaultIdleCoefficientMap, nil)
 		w.Write(wrapData(agg, nil))
 	} else {
 		if fields != "" {

+ 0 - 2
test/cluster_test.go

@@ -25,8 +25,6 @@ import (
 	"log"
 )
 
-const address = "http://localhost:9003"
-
 const apiPrefix = "/api/v1"
 
 const epQuery = apiPrefix + "/query"

+ 31 - 14
test/historical_pod_test.go

@@ -169,7 +169,7 @@ func TestPodUpDown(t *testing.T) {
 	klog.Infof("Sleeping 5 minutes to wait for steady state.")
 	time.Sleep(5 * time.Minute)
 
-	qr := `label_replace(label_replace(container_cpu_allocation{container='web',namespace='test'}, "container_name", "$1", "container","(.+)"), "pod_name", "$1", "pod","(.+)")`
+	qr := `label_replace(label_replace(container_cpu_allocation{container='web',namespace='test2'}, "container_name", "$1", "container","(.+)"), "pod_name", "$1", "pod","(.+)")`
 
 	end := time.Now()
 	start := end.Add(-1 * time.Duration(3*time.Minute))
@@ -180,16 +180,20 @@ func TestPodUpDown(t *testing.T) {
 		panic(err)
 	}
 
-	vectors, err := costModel.GetContainerMetricVectors(res, false, 0)
+	vectors, err := costModel.GetContainerMetricVectors(res, false, 0, "cluster-one")
 	if err != nil {
 		panic(err)
 	}
-
-	assert.Check(t, len(vectors) > 0)
+	klog.Infof("Found Vectors %+v", vectors)
+	if !(len(vectors) > 0) {
+		panic("Expected vectors to have data")
+	}
 	for _, values := range vectors {
 		assert.Check(t, len(values) > 0)
 		for _, vector := range values {
-			assert.Check(t, vector.Value == 0.25 || vector.Value == 0.125) // It's halved for fractional minute normalization.
+			if vector.Value != 0.25 && vector.Value != 0.125 { // It's halved for fractional minute normalization.
+				panic(fmt.Sprintf("Expected %f to equal 0.25", vector.Value))
+			}
 		}
 	}
 
@@ -197,10 +201,13 @@ func TestPodUpDown(t *testing.T) {
 	deleteOptions := &metav1.DeleteOptions{
 		PropagationPolicy: &deletePolicy,
 	}
+
+	klog.Infof("Deleting deployment in namespace test2")
 	if err := client.Resource(deploymentRes).Namespace("test2").Delete("demo-deployment", deleteOptions); err != nil {
 		panic(err)
 	}
 
+	klog.Infof("Sleeping 5 minutes to wait for steady state.")
 	time.Sleep(5 * time.Minute)
 
 	res, err = costModel.Query(promCli, qr)
@@ -208,13 +215,17 @@ func TestPodUpDown(t *testing.T) {
 		panic(err)
 	}
 
-	vectors, err = costModel.GetContainerMetricVector(res, false, 0)
+	vectors, err = costModel.GetContainerMetricVector(res, false, 0, "cluster-one")
 	if err != nil {
 		panic(err)
 	}
-	assert.Equal(t, len(vectors), 0)
-	provider := &cloud.CustomProvider{
-		Clientset: rclient,
+	if len(vectors) != 0 {
+		panic("Pods are not gone from namespace test2 data")
+	}
+	klog.Infof("Validated that pods are gone from namespace test2 data")
+	provider, err := cloud.NewProvider(rclient, os.Getenv("CLOUD_PROVIDER_API_KEY"))
+	if err != nil {
+		panic(err)
 	}
 	loc, _ := time.LoadLocation("UTC")
 	endTime := time.Now().In(loc)
@@ -233,8 +244,10 @@ func TestPodUpDown(t *testing.T) {
 	}
 
 	agg := costModel.AggregateCostData(provider, data, 1, "namespace", []string{""}, "", false, 0.0, 1.0, nil)
-	_, ok := agg["test"]
-	assert.Assert(t, ok)
+	_, ok := agg["test2"]
+	if !ok {
+		panic("No test2 namespace!")
+	}
 
 	data2, err := cm.ComputeCostData(promCli, rclient, provider, "10m", "", "")
 	if err != nil {
@@ -242,10 +255,14 @@ func TestPodUpDown(t *testing.T) {
 	}
 
 	agg2 := costModel.AggregateCostData(provider, data2, 1, "namespace", []string{""}, "", false, 0.0, 1.0, nil)
-	_, ok2 := agg2["test"]
-	assert.Assert(t, ok2)
+	_, ok2 := agg2["test2"]
+	if !ok2 {
+		panic("No test2 namespace!")
+	}
 
 	agg3 := costModel.AggregateCostData(provider, data, 1, "label", []string{"testaggregation"}, "", false, 0.0, 1.0, nil)
 	_, ok3 := agg3["foo"]
-	assert.Assert(t, ok3)
+	if !ok3 {
+		panic("No label foo aggregate!")
+	}
 }

+ 12 - 0
test/kubernetes/cluster-role-binding.yaml

@@ -0,0 +1,12 @@
+apiVersion: rbac.authorization.k8s.io/v1
+kind: ClusterRoleBinding
+metadata:
+  name: cost-model
+roleRef:
+  apiGroup: rbac.authorization.k8s.io
+  kind: ClusterRole
+  name: cost-model
+subjects:
+  - kind: ServiceAccount
+    name: cost-model
+    namespace: default

+ 80 - 0
test/kubernetes/cluster-role.yaml

@@ -0,0 +1,80 @@
+apiVersion: rbac.authorization.k8s.io/v1
+kind: ClusterRole
+metadata:
+  name: cost-model 
+rules:
+  - apiGroups:
+      - ''
+    resources:
+      - configmaps
+      - deployments
+      - nodes
+      - pods
+      - services
+      - resourcequotas
+      - replicationcontrollers
+      - limitranges
+      - persistentvolumeclaims
+      - persistentvolumes
+      - namespaces
+      - endpoints
+    verbs:
+      - get
+      - list
+      - watch
+      - create
+  - apiGroups:
+      - extensions
+    resources:
+      - daemonsets
+      - deployments
+      - replicasets
+    verbs:
+      - get
+      - list
+      - watch
+  - apiGroups:
+      - apps
+    resources:
+      - statefulsets
+      - deployments
+      - daemonsets
+      - replicasets
+    verbs:
+      - list
+      - watch
+      - create
+      - delete
+  - apiGroups:
+      - batch
+    resources:
+      - cronjobs
+      - jobs
+    verbs:
+      - get
+      - list
+      - watch
+  - apiGroups:
+      - autoscaling
+    resources:
+      - horizontalpodautoscalers
+    verbs:
+      - get
+      - list
+      - watch
+  - apiGroups:
+      - policy
+    resources:
+      - poddisruptionbudgets
+    verbs:
+      - get
+      - list
+      - watch
+  - apiGroups: 
+      - storage.k8s.io
+    resources: 
+      - storageclasses
+    verbs:
+      - get
+      - list
+      - watch

+ 4 - 0
test/kubernetes/service-account.yaml

@@ -0,0 +1,4 @@
+apiVersion: v1
+kind: ServiceAccount
+metadata:
+  name: cost-model

+ 30 - 0
test/kubernetes/test-pod.yaml

@@ -0,0 +1,30 @@
+apiVersion: batch/v1
+kind: Job
+metadata:
+  name: cost-model-test
+  labels:
+    app: cost-model-test
+spec:
+  backoffLimit: 0
+  template:
+    metadata:
+      labels:
+        app: cost-model-test
+    spec:
+      restartPolicy: Never
+      serviceAccountName: cost-model
+      containers:
+        - image: ajaytripathy/kubecost-cost-model-integration:latest
+          name: cost-model
+          securityContext:
+            runAsUser: 0
+          resources:
+            requests:
+              cpu: "10m"
+              memory: "55M"
+          env:
+            - name: PROMETHEUS_SERVER_ENDPOINT
+              value: http://kubecost-prometheus-server.kubecost #The endpoint should have the form http://<service-name>.<namespace-name>.svc.cluster.local 
+            - name: CLOUD_PROVIDER_API_KEY
+              value: "AIzaSyDXQPG_MHUEy9neR7stolq6l0ujXmjJlvk" # The GCP Pricing API requires a key.
+          imagePullPolicy: Always

+ 3 - 14
test/remote_cluster_test.go

@@ -1,22 +1,10 @@
 package costmodel_test
 
 import (
-	"log"
-	"net"
-	"net/http"
-	"os"
-	"testing"
-	"time"
-
-	"github.com/kubecost/cost-model/cloud"
-	costModel "github.com/kubecost/cost-model/costmodel"
-	"gotest.tools/assert"
-
-	prometheusClient "github.com/prometheus/client_golang/api"
-
 	_ "k8s.io/client-go/plugin/pkg/client/auth"
 )
 
+/*
 func TestClusterConvergence(t *testing.T) {
 	rclient, err := getKubernetesClient()
 	if err != nil {
@@ -32,7 +20,7 @@ func TestClusterConvergence(t *testing.T) {
 	}
 
 	pc := prometheusClient.Config{
-		Address:      address,
+		Address:      os.Getenv(PROMETHEUS_SERVER_ENDPOINT),
 		RoundTripper: LongTimeoutRoundTripper,
 	}
 	promCli, err := prometheusClient.NewClient(pc)
@@ -74,3 +62,4 @@ func TestClusterConvergence(t *testing.T) {
 	assert.Equal(t, agg["kubecost"].TotalCost, agg2["kubecost"].TotalCost)
 
 }
+*/