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

Merge pull request #1870 from ameijer/compute-resource-cost

Compute resource cost
Michael Dresser 3 лет назад
Родитель
Сommit
5d02a1545b
4 измененных файлов с 114 добавлено и 83 удалено
  1. 4 1
      pkg/costmodel/router.go
  2. 38 20
      pkg/kubecost/allocation.go
  3. 2 2
      pkg/kubecost/allocation_json.go
  4. 70 60
      pkg/kubecost/allocation_test.go

+ 4 - 1
pkg/costmodel/router.go

@@ -278,11 +278,14 @@ func WrapData(data interface{}, err error) []byte {
 			Data:    data,
 		})
 	} else {
-		resp, _ = json.Marshal(&Response{
+		resp, err = json.Marshal(&Response{
 			Code:   http.StatusOK,
 			Status: "success",
 			Data:   data,
 		})
+		if err != nil {
+			log.Errorf("error marshaling response json: %s", err.Error())
+		}
 	}
 
 	return resp

+ 38 - 20
pkg/kubecost/allocation.go

@@ -247,12 +247,13 @@ func (pva *PVAllocation) Equal(that *PVAllocation) bool {
 }
 
 type ProportionalAssetResourceCost struct {
-	Cluster       string  `json:"cluster"`
-	Node          string  `json:"node,omitempty"`
-	ProviderID    string  `json:"providerID,omitempty"`
-	CPUPercentage float64 `json:"cpuPercentage"`
-	GPUPercentage float64 `json:"gpuPercentage"`
-	RAMPercentage float64 `json:"ramPercentage"`
+	Cluster                    string  `json:"cluster"`
+	Node                       string  `json:"node,omitempty"`
+	ProviderID                 string  `json:"providerID,omitempty"`
+	CPUPercentage              float64 `json:"cpuPercentage"`
+	GPUPercentage              float64 `json:"gpuPercentage"`
+	RAMPercentage              float64 `json:"ramPercentage"`
+	NodeResourceCostPercentage float64 `json:"nodeResourceCostPercentage"`
 }
 
 func (parc ProportionalAssetResourceCost) Key(insertByNode bool) string {
@@ -273,12 +274,13 @@ func (parcs ProportionalAssetResourceCosts) Insert(parc ProportionalAssetResourc
 	}
 	if curr, ok := parcs[parc.Key(insertByNode)]; ok {
 		parcs[parc.Key(insertByNode)] = ProportionalAssetResourceCost{
-			Node:          curr.Node,
-			Cluster:       curr.Cluster,
-			ProviderID:    curr.ProviderID,
-			CPUPercentage: curr.CPUPercentage + parc.CPUPercentage,
-			GPUPercentage: curr.GPUPercentage + parc.GPUPercentage,
-			RAMPercentage: curr.RAMPercentage + parc.RAMPercentage,
+			Node:                       curr.Node,
+			Cluster:                    curr.Cluster,
+			ProviderID:                 curr.ProviderID,
+			CPUPercentage:              curr.CPUPercentage + parc.CPUPercentage,
+			GPUPercentage:              curr.GPUPercentage + parc.GPUPercentage,
+			RAMPercentage:              curr.RAMPercentage + parc.RAMPercentage,
+			NodeResourceCostPercentage: curr.NodeResourceCostPercentage + parc.NodeResourceCostPercentage,
 		}
 	} else {
 		parcs[parc.Key(insertByNode)] = parc
@@ -1164,7 +1166,7 @@ func (as *AllocationSet) AggregateBy(aggregateBy []string, options *AllocationAg
 
 			// Attempt to derive proportional asset resource costs from idle
 			// coefficients, and insert them into the set if successful.
-			parc, err := deriveProportionalAssetResourceCostsFromIdleCoefficients(parcCoefficients, alloc, options)
+			parc, err := deriveProportionalAssetResourceCostsFromIdleCoefficients(parcCoefficients, allocatedTotalsMap, alloc, options)
 			if err != nil {
 				log.Debugf("AggregateBy: failed to derive proportional asset resource costs from idle coefficients for %s: %s", alloc.Name, err)
 				continue
@@ -1739,7 +1741,7 @@ func computeIdleCoeffs(options *AllocationAggregationOptions, as *AllocationSet,
 	return coeffs, totals, nil
 }
 
-func deriveProportionalAssetResourceCostsFromIdleCoefficients(idleCoeffs map[string]map[string]map[string]float64, allocation *Allocation, options *AllocationAggregationOptions) (ProportionalAssetResourceCost, error) {
+func deriveProportionalAssetResourceCostsFromIdleCoefficients(idleCoeffs map[string]map[string]map[string]float64, totals map[string]map[string]float64, allocation *Allocation, options *AllocationAggregationOptions) (ProportionalAssetResourceCost, error) {
 	idleId, err := allocation.getIdleId(options)
 	if err != nil {
 		return ProportionalAssetResourceCost{}, fmt.Errorf("failed to get idle ID for allocation %s", allocation.Name)
@@ -1757,13 +1759,29 @@ func deriveProportionalAssetResourceCostsFromIdleCoefficients(idleCoeffs map[str
 	gpuPct := idleCoeffs[idleId][allocation.Name]["gpu"]
 	ramPct := idleCoeffs[idleId][allocation.Name]["ram"]
 
+	// compute how much each component (cpu, gpu, ram) contributes to the overall price
+	totalCost := totals[idleId]["ram"] + totals[idleId]["gpu"] + totals[idleId]["cpu"]
+
+	var ramFraction, cpuFraction, gpuFraction float64
+
+	// only compute fraction if totalCost is nonzero, otherwise returns in NaN
+	if totalCost > 0 {
+		ramFraction = totals[idleId]["ram"] / totalCost
+		cpuFraction = totals[idleId]["cpu"] / totalCost
+		gpuFraction = totals[idleId]["gpu"] / totalCost
+	}
+
+	// compute the resource usage percentage based on the weighted fractions
+	nodeResourceCostPercentage := (ramPct * ramFraction) + (cpuPct * cpuFraction) + (gpuPct * gpuFraction)
+
 	return ProportionalAssetResourceCost{
-		Cluster:       allocation.Properties.Cluster,
-		Node:          allocation.Properties.Node,
-		ProviderID:    allocation.Properties.ProviderID,
-		CPUPercentage: cpuPct,
-		GPUPercentage: gpuPct,
-		RAMPercentage: ramPct,
+		Cluster:                    allocation.Properties.Cluster,
+		Node:                       allocation.Properties.Node,
+		ProviderID:                 allocation.Properties.ProviderID,
+		CPUPercentage:              cpuPct,
+		GPUPercentage:              gpuPct,
+		RAMPercentage:              ramPct,
+		NodeResourceCostPercentage: nodeResourceCostPercentage,
 	}, nil
 }
 

+ 2 - 2
pkg/kubecost/allocation_json.go

@@ -53,8 +53,8 @@ type AllocationJSON struct {
 	SharedCost                     *float64                        `json:"sharedCost"`
 	TotalCost                      *float64                        `json:"totalCost"`
 	TotalEfficiency                *float64                        `json:"totalEfficiency"`
-	RawAllocationOnly              *RawAllocationOnlyData          `json:"rawAllocationOnly,omitEmpty"`
-	ProportionalAssetResourceCosts *ProportionalAssetResourceCosts `json:"proportionalAssetResourceCosts,omitEmpty"`
+	RawAllocationOnly              *RawAllocationOnlyData          `json:"rawAllocationOnly,omitempty"`
+	ProportionalAssetResourceCosts *ProportionalAssetResourceCosts `json:"proportionalAssetResourceCosts,omitempty"`
 }
 
 func (aj *AllocationJSON) BuildFromAllocation(a *Allocation) {

+ 70 - 60
pkg/kubecost/allocation_test.go

@@ -1074,30 +1074,33 @@ func TestAllocationSet_AggregateBy(t *testing.T) {
 			expectedParcResults: map[string]ProportionalAssetResourceCosts{
 				"namespace1": ProportionalAssetResourceCosts{
 					"cluster1": ProportionalAssetResourceCost{
-						Cluster:       "cluster1",
-						Node:          "",
-						ProviderID:    "",
-						CPUPercentage: 0.5,
-						GPUPercentage: 0.5,
-						RAMPercentage: 0.8125,
+						Cluster:            "cluster1",
+						Node:               "",
+						ProviderID:         "",
+						CPUPercentage:      0.5,
+						GPUPercentage:      0.5,
+						RAMPercentage:      0.8125,
+						NodeResourceCostPercentage: 0.6785714285714285,
 					},
 				},
 				"namespace2": ProportionalAssetResourceCosts{
 					"cluster1": ProportionalAssetResourceCost{
-						Cluster:       "cluster1",
-						Node:          "",
-						ProviderID:    "",
-						CPUPercentage: 0.5,
-						GPUPercentage: 0.5,
-						RAMPercentage: 0.1875,
+						Cluster:            "cluster1",
+						Node:               "",
+						ProviderID:         "",
+						CPUPercentage:      0.5,
+						GPUPercentage:      0.5,
+						RAMPercentage:      0.1875,
+						NodeResourceCostPercentage: 0.3214285714285714,
 					},
 					"cluster2": ProportionalAssetResourceCost{
-						Cluster:       "cluster2",
-						Node:          "",
-						ProviderID:    "",
-						CPUPercentage: 0.5,
-						GPUPercentage: 0.5,
-						RAMPercentage: 0.5,
+						Cluster:            "cluster2",
+						Node:               "",
+						ProviderID:         "",
+						CPUPercentage:      0.5,
+						GPUPercentage:      0.5,
+						RAMPercentage:      0.5,
+						NodeResourceCostPercentage: 0.5,
 					},
 				},
 			},
@@ -1509,64 +1512,71 @@ func TestAllocationSet_AggregateBy(t *testing.T) {
 			expectedParcResults: map[string]ProportionalAssetResourceCosts{
 				"namespace1": {
 					"cluster1,c1nodes": ProportionalAssetResourceCost{
-						Cluster:       "cluster1",
-						Node:          "c1nodes",
-						ProviderID:    "c1nodes",
-						CPUPercentage: 0.5,
-						GPUPercentage: 0.5,
-						RAMPercentage: 0.8125,
+						Cluster:            "cluster1",
+						Node:               "c1nodes",
+						ProviderID:         "c1nodes",
+						CPUPercentage:      0.5,
+						GPUPercentage:      0.5,
+						RAMPercentage:      0.8125,
+						NodeResourceCostPercentage: 0.6785714285714285,
 					},
 					"cluster2,node2": ProportionalAssetResourceCost{
-						Cluster:       "cluster2",
-						Node:          "node2",
-						ProviderID:    "node2",
-						CPUPercentage: 0.5,
-						GPUPercentage: 0.5,
-						RAMPercentage: 0.5,
+						Cluster:            "cluster2",
+						Node:               "node2",
+						ProviderID:         "node2",
+						CPUPercentage:      0.5,
+						GPUPercentage:      0.5,
+						RAMPercentage:      0.5,
+						NodeResourceCostPercentage: 0.5,
 					},
 				},
 				"namespace2": {
 					"cluster1,c1nodes": ProportionalAssetResourceCost{
-						Cluster:       "cluster1",
-						Node:          "c1nodes",
-						ProviderID:    "c1nodes",
-						CPUPercentage: 0.5,
-						GPUPercentage: 0.5,
-						RAMPercentage: 0.1875,
+						Cluster:            "cluster1",
+						Node:               "c1nodes",
+						ProviderID:         "c1nodes",
+						CPUPercentage:      0.5,
+						GPUPercentage:      0.5,
+						RAMPercentage:      0.1875,
+						NodeResourceCostPercentage: 0.3214285714285714,
 					},
 					"cluster2,node1": ProportionalAssetResourceCost{
-						Cluster:       "cluster2",
-						Node:          "node1",
-						ProviderID:    "node1",
-						CPUPercentage: 1,
-						GPUPercentage: 1,
-						RAMPercentage: 1,
+						Cluster:            "cluster2",
+						Node:               "node1",
+						ProviderID:         "node1",
+						CPUPercentage:      1,
+						GPUPercentage:      1,
+						RAMPercentage:      1,
+						NodeResourceCostPercentage: 1,
 					},
 					"cluster2,node2": ProportionalAssetResourceCost{
-						Cluster:       "cluster2",
-						Node:          "node2",
-						ProviderID:    "node2",
-						CPUPercentage: 0.5,
-						GPUPercentage: 0.5,
-						RAMPercentage: 0.5,
+						Cluster:            "cluster2",
+						Node:               "node2",
+						ProviderID:         "node2",
+						CPUPercentage:      0.5,
+						GPUPercentage:      0.5,
+						RAMPercentage:      0.5,
+						NodeResourceCostPercentage: 0.5,
 					},
 				},
 				"namespace3": {
 					"cluster2,node3": ProportionalAssetResourceCost{
-						Cluster:       "cluster2",
-						Node:          "node3",
-						ProviderID:    "node3",
-						CPUPercentage: 1,
-						GPUPercentage: 1,
-						RAMPercentage: 1,
+						Cluster:            "cluster2",
+						Node:               "node3",
+						ProviderID:         "node3",
+						CPUPercentage:      1,
+						GPUPercentage:      1,
+						RAMPercentage:      1,
+						NodeResourceCostPercentage: 1,
 					},
 					"cluster2,node2": ProportionalAssetResourceCost{
-						Cluster:       "cluster2",
-						Node:          "node2",
-						ProviderID:    "node2",
-						CPUPercentage: 0.5,
-						GPUPercentage: 0.5,
-						RAMPercentage: 0.5,
+						Cluster:            "cluster2",
+						Node:               "node2",
+						ProviderID:         "node2",
+						CPUPercentage:      0.5,
+						GPUPercentage:      0.5,
+						RAMPercentage:      0.5,
+						NodeResourceCostPercentage: 0.5,
 					},
 				},
 			},