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

Add provider_id to ClusterNodes; add CombinedDiscountForNode to Provider interface and implement for GCP

Niko Kovacevic 5 лет назад
Родитель
Сommit
b5c5a6742c

+ 4 - 0
pkg/cloud/awsprovider.go

@@ -2395,3 +2395,7 @@ func (a *AWS) ServiceAccountStatus() *ServiceAccountStatus {
 		Checks: checks,
 	}
 }
+
+func (aws *AWS) CombinedDiscountForNode(instanceType string, isPreemptible bool, defaultDiscount, negotiatedDiscount float64) float64 {
+	return 1.0 - ((1.0 - defaultDiscount) * (1.0 - negotiatedDiscount))
+}

+ 4 - 0
pkg/cloud/azureprovider.go

@@ -780,3 +780,7 @@ func (az *Azure) ServiceAccountStatus() *ServiceAccountStatus {
 		Checks: []*ServiceAccountCheck{},
 	}
 }
+
+func (az *Azure) CombinedDiscountForNode(instanceType string, isPreemptible bool, defaultDiscount, negotiatedDiscount float64) float64 {
+	return 1.0 - ((1.0 - defaultDiscount) * (1.0 - negotiatedDiscount))
+}

+ 4 - 0
pkg/cloud/csvprovider.go

@@ -294,3 +294,7 @@ func (c *CSVProvider) ServiceAccountStatus() *ServiceAccountStatus {
 		Checks: []*ServiceAccountCheck{},
 	}
 }
+
+func (c *CSVProvider) CombinedDiscountForNode(instanceType string, isPreemptible bool, defaultDiscount, negotiatedDiscount float64) float64 {
+	return 1.0 - ((1.0 - defaultDiscount) * (1.0 - negotiatedDiscount))
+}

+ 4 - 0
pkg/cloud/customprovider.go

@@ -268,3 +268,7 @@ func (cp *CustomProvider) ServiceAccountStatus() *ServiceAccountStatus {
 		Checks: []*ServiceAccountCheck{},
 	}
 }
+
+func (cp *CustomProvider) CombinedDiscountForNode(instanceType string, isPreemptible bool, defaultDiscount, negotiatedDiscount float64) float64 {
+	return 1.0 - ((1.0 - defaultDiscount) * (1.0 - negotiatedDiscount))
+}

+ 16 - 0
pkg/cloud/gcpprovider.go

@@ -1385,3 +1385,19 @@ func (gcp *GCP) ServiceAccountStatus() *ServiceAccountStatus {
 		Checks: []*ServiceAccountCheck{},
 	}
 }
+
+func (gcp *GCP) CombinedDiscountForNode(instanceType string, isPreemptible bool, defaultDiscount, negotiatedDiscount float64) float64 {
+	class := strings.Split(instanceType, "-")[0]
+	return 1.0 - ((1.0 - sustainedUseDiscount(class, defaultDiscount)) * (1.0 - negotiatedDiscount))
+}
+
+func sustainedUseDiscount(class string, defaultDiscount float64) float64 {
+	discount := defaultDiscount
+	switch class {
+	case "e2", "f1", "g1":
+		discount = 0.0
+	case "n2":
+		discount = 0.2
+	}
+	return discount
+}

+ 1 - 0
pkg/cloud/provider.go

@@ -188,6 +188,7 @@ type Provider interface {
 	ExternalAllocations(string, string, []string, string, string, bool) ([]*OutOfClusterAllocation, error)
 	ApplyReservedInstancePricing(map[string]*Node)
 	ServiceAccountStatus() *ServiceAccountStatus
+	CombinedDiscountForNode(string, bool, float64, float64) float64
 }
 
 // ClusterName returns the name defined in cluster info, defaulting to the

+ 28 - 28
pkg/costmodel/cluster.go

@@ -291,11 +291,11 @@ func ClusterNodes(cp cloud.Provider, client prometheus.Client, duration, offset
 	hourlyToCumulative := float64(minsPerResolution) * (1.0 / 60.0)
 
 	ctx := prom.NewContext(client)
-	queryNodeCPUCost := fmt.Sprintf(`sum_over_time((avg(kube_node_status_capacity_cpu_cores) by (cluster_id, node) * on(node, cluster_id) group_right avg(node_cpu_hourly_cost) by (cluster_id, node, instance_type))[%s:%dm]%s) * %f`, durationStr, minsPerResolution, offsetStr, hourlyToCumulative)
+	queryNodeCPUCost := fmt.Sprintf(`sum_over_time((avg(kube_node_status_capacity_cpu_cores) by (cluster_id, node) * on(node, cluster_id) group_right avg(node_cpu_hourly_cost) by (cluster_id, node, instance_type, provider_id))[%s:%dm]%s) * %f`, durationStr, minsPerResolution, offsetStr, hourlyToCumulative)
 	queryNodeCPUCores := fmt.Sprintf(`avg_over_time(avg(kube_node_status_capacity_cpu_cores) by (cluster_id, node)[%s:%dm]%s)`, durationStr, minsPerResolution, offsetStr)
-	queryNodeRAMCost := fmt.Sprintf(`sum_over_time((avg(kube_node_status_capacity_memory_bytes) by (cluster_id, node) * on(cluster_id, node) group_right avg(node_ram_hourly_cost) by (cluster_id, node, instance_type))[%s:%dm]%s) / 1024 / 1024 / 1024 * %f`, durationStr, minsPerResolution, offsetStr, hourlyToCumulative)
+	queryNodeRAMCost := fmt.Sprintf(`sum_over_time((avg(kube_node_status_capacity_memory_bytes) by (cluster_id, node) * on(cluster_id, node) group_right avg(node_ram_hourly_cost) by (cluster_id, node, instance_type, provider_id))[%s:%dm]%s) / 1024 / 1024 / 1024 * %f`, durationStr, minsPerResolution, offsetStr, hourlyToCumulative)
 	queryNodeRAMBytes := fmt.Sprintf(`avg_over_time(avg(kube_node_status_capacity_memory_bytes) by (cluster_id, node)[%s:%dm]%s)`, durationStr, minsPerResolution, offsetStr)
-	queryNodeGPUCost := fmt.Sprintf(`sum_over_time((avg(node_gpu_hourly_cost) by (cluster_id, node))[%s:%dm]%s)`, durationStr, minsPerResolution, offsetStr)
+	queryNodeGPUCost := fmt.Sprintf(`sum_over_time((avg(node_gpu_hourly_cost) by (cluster_id, node, provider_id))[%s:%dm]%s)`, durationStr, minsPerResolution, offsetStr)
 	queryNodeLabels := fmt.Sprintf(`count_over_time(kube_node_labels[%s:%dm]%s)`, durationStr, minsPerResolution, offsetStr)
 
 	resChNodeCPUCost := ctx.Query(queryNodeCPUCost)
@@ -329,19 +329,18 @@ func ClusterNodes(cp cloud.Provider, client prometheus.Client, duration, offset
 			continue
 		}
 
-		nodeType, err := result.GetString("instance_type")
-		if err != nil {
-			log.Warningf("ClusterNodes: CPU cost data missing node type")
-		}
+		nodeType, _ := result.GetString("instance_type")
+		providerID, _ := result.GetString("provider_id")
 
 		cpuCost := result.Values[0].Value
 
 		key := fmt.Sprintf("%s/%s", cluster, name)
 		if _, ok := nodeMap[key]; !ok {
 			nodeMap[key] = &Node{
-				Cluster:  cluster,
-				Name:     name,
-				NodeType: nodeType,
+				Cluster:    cluster,
+				Name:       name,
+				NodeType:   nodeType,
+				ProviderID: providerID,
 			}
 		}
 		nodeMap[key].CPUCost = cpuCost
@@ -384,19 +383,18 @@ func ClusterNodes(cp cloud.Provider, client prometheus.Client, duration, offset
 			continue
 		}
 
-		nodeType, err := result.GetString("instance_type")
-		if err != nil {
-			log.Warningf("ClusterNodes: RAM cost data missing node type")
-		}
+		nodeType, _ := result.GetString("instance_type")
+		providerID, _ := result.GetString("provider_id")
 
 		ramCost := result.Values[0].Value
 
 		key := fmt.Sprintf("%s/%s", cluster, name)
 		if _, ok := nodeMap[key]; !ok {
 			nodeMap[key] = &Node{
-				Cluster:  cluster,
-				Name:     name,
-				NodeType: nodeType,
+				Cluster:    cluster,
+				Name:       name,
+				NodeType:   nodeType,
+				ProviderID: providerID,
 			}
 		}
 		nodeMap[key].RAMCost = ramCost
@@ -439,19 +437,24 @@ func ClusterNodes(cp cloud.Provider, client prometheus.Client, duration, offset
 			continue
 		}
 
+		nodeType, _ := result.GetString("instance_type")
+		providerID, _ := result.GetString("provider_id")
+
 		gpuCost := result.Values[0].Value
 
 		key := fmt.Sprintf("%s/%s", cluster, name)
 		if _, ok := nodeMap[key]; !ok {
 			nodeMap[key] = &Node{
-				Cluster: cluster,
-				Name:    name,
+				Cluster:    cluster,
+				Name:       name,
+				NodeType:   nodeType,
+				ProviderID: providerID,
 			}
 		}
 		nodeMap[key].GPUCost = gpuCost
 	}
 
-	// node_labels label_cloud_google_com_gke_preemptible
+	// Determine preemptibility with node labels
 	for _, result := range resNodeLabels {
 		nodeName, err := result.GetString("node")
 		if err != nil {
@@ -465,6 +468,7 @@ func ClusterNodes(cp cloud.Provider, client prometheus.Client, duration, offset
 		}
 
 		// TODO AWS preemptible
+
 		// TODO Azure preemptible
 	}
 
@@ -472,24 +476,20 @@ func ClusterNodes(cp cloud.Provider, client prometheus.Client, duration, offset
 	if err != nil {
 		return nil, []error{err}
 	}
+
 	discount, err := ParsePercentString(c.Discount)
 	if err != nil {
 		return nil, []error{err}
 	}
+
 	negotiatedDiscount, err := ParsePercentString(c.NegotiatedDiscount)
 	if err != nil {
 		return nil, []error{err}
 	}
 
 	for _, node := range nodeMap {
-		if !node.Preemptible {
-			// TODO determine discount(s) based on:
-			// - custom settings
-			// - node RI data
-			// - provider-specific rules, e.g.
-			//   cp.GetDiscount(instanceType string) float64
-			node.Discount = (1.0 - (1.0-discount)*(1.0-negotiatedDiscount))
-		}
+		// TODO take RI into account
+		node.Discount = cp.CombinedDiscountForNode(node.NodeType, node.Preemptible, discount, negotiatedDiscount)
 	}
 
 	return nodeMap, nil