Преглед изворни кода

Merge branch 'develop' into sean/pv-alloc-recon

# Conflicts:
#	pkg/kubecost/allocation.go
#	pkg/kubecost/allocation_test.go
Sean Holcomb пре 5 година
родитељ
комит
9caa4118d6

+ 1 - 1
README.md

@@ -74,7 +74,7 @@ Resources are allocated based on the time-weighted maximum of resource Requests
 
 
 #### How do I set my AWS Spot bids for accurate allocation?
 #### How do I set my AWS Spot bids for accurate allocation?
 
 
-Modify [spotCPU](https://github.com/kubecost/cost-model/blob/master/cloud/default.json#L5) and  [spotRAM](https://github.com/kubecost/cost-model/blob/master/cloud/default.json#L7) in default.json to the price of your bid. Allocation will use these bid prices, but it does not take into account what you are actually charged by AWS. Alternatively, you can provide an AWS key to allow access to the Spot data feed. This will provide accurate Spot prices. 
+Modify [spotCPU](https://github.com/kubecost/cost-model/blob/master/configs/default.json#L5) and  [spotRAM](https://github.com/kubecost/cost-model/blob/master/configs/default.json#L7) in default.json to the price of your bid. Allocation will use these bid prices, but it does not take into account what you are actually charged by AWS. Alternatively, you can provide an AWS key to allow access to the Spot data feed. This will provide accurate Spot prices. 
 
 
 #### Do I need a GCP billing API key?
 #### Do I need a GCP billing API key?
 
 

+ 2 - 2
pkg/costmodel/costmodel.go

@@ -1057,7 +1057,7 @@ func (cm *CostModel) GetNodeCost(cp costAnalyzerCloud.Provider) (map[string]*cos
 
 
 			cpuToRAMRatio := defaultCPU / defaultRAM
 			cpuToRAMRatio := defaultCPU / defaultRAM
 			if math.IsNaN(cpuToRAMRatio) {
 			if math.IsNaN(cpuToRAMRatio) {
-				klog.V(1).Infof("[Warning] cpuToRAMRatio[defaultCPU: %f / defaultRam: %f] is NaN. Setting to 0.", defaultCPU, defaultRAM)
+				klog.V(1).Infof("[Warning] cpuToRAMRatio[defaultCPU: %f / defaultRAM: %f] is NaN. Setting to 0.", defaultCPU, defaultRAM)
 				cpuToRAMRatio = 0
 				cpuToRAMRatio = 0
 			}
 			}
 
 
@@ -1137,7 +1137,7 @@ func (cm *CostModel) GetNodeCost(cp costAnalyzerCloud.Provider) (map[string]*cos
 
 
 			cpuToRAMRatio := defaultCPU / defaultRAM
 			cpuToRAMRatio := defaultCPU / defaultRAM
 			if math.IsNaN(cpuToRAMRatio) {
 			if math.IsNaN(cpuToRAMRatio) {
-				klog.V(1).Infof("[Warning] cpuToRAMRatio[defaultCPU: %f / defaultRam: %f] is NaN. Setting to 0.", defaultCPU, defaultRAM)
+				klog.V(1).Infof("[Warning] cpuToRAMRatio[defaultCPU: %f / defaultRAM: %f] is NaN. Setting to 0.", defaultCPU, defaultRAM)
 				cpuToRAMRatio = 0
 				cpuToRAMRatio = 0
 			}
 			}
 
 

+ 46 - 37
pkg/kubecost/allocation.go

@@ -59,20 +59,20 @@ type Allocation struct {
 	CPUCoreRequestAverage  float64               `json:"cpuCoreRequestAverage"`
 	CPUCoreRequestAverage  float64               `json:"cpuCoreRequestAverage"`
 	CPUCoreUsageAverage    float64               `json:"cpuCoreUsageAverage"`
 	CPUCoreUsageAverage    float64               `json:"cpuCoreUsageAverage"`
 	CPUCost                float64               `json:"cpuCost"`
 	CPUCost                float64               `json:"cpuCost"`
-	CPUAdjustment          float64               `json:"cpuAdjustment"`
+	CPUCostAdjustment      float64               `json:"cpuCostAdjustment"`
 	GPUHours               float64               `json:"gpuHours"`
 	GPUHours               float64               `json:"gpuHours"`
 	GPUCost                float64               `json:"gpuCost"`
 	GPUCost                float64               `json:"gpuCost"`
-	GPUAdjustment          float64               `json:"gpuAdjustment"`
+	GPUCostAdjustment      float64               `json:"gpuCostAdjustment"`
 	NetworkCost            float64               `json:"networkCost"`
 	NetworkCost            float64               `json:"networkCost"`
 	LoadBalancerCost       float64               `json:"loadBalancerCost"`
 	LoadBalancerCost       float64               `json:"loadBalancerCost"`
 	PVByteHours            float64               `json:"pvByteHours"`
 	PVByteHours            float64               `json:"pvByteHours"`
 	PVCost                 float64               `json:"pvCost"`
 	PVCost                 float64               `json:"pvCost"`
-	PVAdjustment           float64               `json:"pvAdjustment"`
+	PVCostAdjustment       float64               `json:"pvAdjustment"`
 	RAMByteHours           float64               `json:"ramByteHours"`
 	RAMByteHours           float64               `json:"ramByteHours"`
 	RAMBytesRequestAverage float64               `json:"ramByteRequestAverage"`
 	RAMBytesRequestAverage float64               `json:"ramByteRequestAverage"`
 	RAMBytesUsageAverage   float64               `json:"ramByteUsageAverage"`
 	RAMBytesUsageAverage   float64               `json:"ramByteUsageAverage"`
 	RAMCost                float64               `json:"ramCost"`
 	RAMCost                float64               `json:"ramCost"`
-	RAMAdjustment          float64               `json:"ramAdjustment"`
+	RAMCostAdjustment      float64               `json:"ramCostAdjustment"`
 	SharedCost             float64               `json:"sharedCost"`
 	SharedCost             float64               `json:"sharedCost"`
 	ExternalCost           float64               `json:"externalCost"`
 	ExternalCost           float64               `json:"externalCost"`
 	// RawAllocationOnly is a pointer so if it is not present it will be
 	// RawAllocationOnly is a pointer so if it is not present it will be
@@ -147,20 +147,20 @@ func (a *Allocation) Clone() *Allocation {
 		CPUCoreRequestAverage:  a.CPUCoreRequestAverage,
 		CPUCoreRequestAverage:  a.CPUCoreRequestAverage,
 		CPUCoreUsageAverage:    a.CPUCoreUsageAverage,
 		CPUCoreUsageAverage:    a.CPUCoreUsageAverage,
 		CPUCost:                a.CPUCost,
 		CPUCost:                a.CPUCost,
-		CPUAdjustment:          a.CPUAdjustment,
+		CPUCostAdjustment:      a.CPUCostAdjustment,
 		GPUHours:               a.GPUHours,
 		GPUHours:               a.GPUHours,
 		GPUCost:                a.GPUCost,
 		GPUCost:                a.GPUCost,
-		GPUAdjustment:          a.GPUAdjustment,
+		GPUCostAdjustment:      a.GPUCostAdjustment,
 		NetworkCost:            a.NetworkCost,
 		NetworkCost:            a.NetworkCost,
 		LoadBalancerCost:       a.LoadBalancerCost,
 		LoadBalancerCost:       a.LoadBalancerCost,
 		PVByteHours:            a.PVByteHours,
 		PVByteHours:            a.PVByteHours,
 		PVCost:                 a.PVCost,
 		PVCost:                 a.PVCost,
-		PVAdjustment:           a.PVAdjustment,
+		PVCostAdjustment:       a.PVCostAdjustment,
 		RAMByteHours:           a.RAMByteHours,
 		RAMByteHours:           a.RAMByteHours,
 		RAMBytesRequestAverage: a.RAMBytesRequestAverage,
 		RAMBytesRequestAverage: a.RAMBytesRequestAverage,
 		RAMBytesUsageAverage:   a.RAMBytesUsageAverage,
 		RAMBytesUsageAverage:   a.RAMBytesUsageAverage,
 		RAMCost:                a.RAMCost,
 		RAMCost:                a.RAMCost,
-		RAMAdjustment:          a.RAMAdjustment,
+		RAMCostAdjustment:      a.RAMCostAdjustment,
 		SharedCost:             a.SharedCost,
 		SharedCost:             a.SharedCost,
 		ExternalCost:           a.ExternalCost,
 		ExternalCost:           a.ExternalCost,
 		RawAllocationOnly:      a.RawAllocationOnly.Clone(),
 		RawAllocationOnly:      a.RawAllocationOnly.Clone(),
@@ -209,7 +209,7 @@ func (a *Allocation) Equal(that *Allocation) bool {
 	if !util.IsApproximately(a.CPUCost, that.CPUCost) {
 	if !util.IsApproximately(a.CPUCost, that.CPUCost) {
 		return false
 		return false
 	}
 	}
-	if !util.IsApproximately(a.CPUAdjustment, that.CPUAdjustment) {
+	if !util.IsApproximately(a.CPUCostAdjustment, that.CPUCostAdjustment) {
 		return false
 		return false
 	}
 	}
 	if !util.IsApproximately(a.GPUHours, that.GPUHours) {
 	if !util.IsApproximately(a.GPUHours, that.GPUHours) {
@@ -218,7 +218,7 @@ func (a *Allocation) Equal(that *Allocation) bool {
 	if !util.IsApproximately(a.GPUCost, that.GPUCost) {
 	if !util.IsApproximately(a.GPUCost, that.GPUCost) {
 		return false
 		return false
 	}
 	}
-	if !util.IsApproximately(a.GPUAdjustment, that.GPUAdjustment) {
+	if !util.IsApproximately(a.GPUCostAdjustment, that.GPUCostAdjustment) {
 		return false
 		return false
 	}
 	}
 	if !util.IsApproximately(a.NetworkCost, that.NetworkCost) {
 	if !util.IsApproximately(a.NetworkCost, that.NetworkCost) {
@@ -233,7 +233,7 @@ func (a *Allocation) Equal(that *Allocation) bool {
 	if !util.IsApproximately(a.PVCost, that.PVCost) {
 	if !util.IsApproximately(a.PVCost, that.PVCost) {
 		return false
 		return false
 	}
 	}
-	if !util.IsApproximately(a.PVAdjustment, that.PVAdjustment) {
+	if !util.IsApproximately(a.PVCostAdjustment, that.PVCostAdjustment) {
 		return false
 		return false
 	}
 	}
 	if !util.IsApproximately(a.RAMByteHours, that.RAMByteHours) {
 	if !util.IsApproximately(a.RAMByteHours, that.RAMByteHours) {
@@ -242,7 +242,7 @@ func (a *Allocation) Equal(that *Allocation) bool {
 	if !util.IsApproximately(a.RAMCost, that.RAMCost) {
 	if !util.IsApproximately(a.RAMCost, that.RAMCost) {
 		return false
 		return false
 	}
 	}
-	if !util.IsApproximately(a.RAMAdjustment, that.RAMAdjustment) {
+	if !util.IsApproximately(a.RAMCostAdjustment, that.RAMCostAdjustment) {
 		return false
 		return false
 	}
 	}
 	if !util.IsApproximately(a.SharedCost, that.SharedCost) {
 	if !util.IsApproximately(a.SharedCost, that.SharedCost) {
@@ -277,19 +277,19 @@ func (a *Allocation) TotalCost() float64 {
 }
 }
 
 
 func (a *Allocation) CPUTotalCost() float64 {
 func (a *Allocation) CPUTotalCost() float64 {
-	return a.CPUCost + a.CPUAdjustment
+	return a.CPUCost + a.CPUCostAdjustment
 }
 }
 
 
 func (a *Allocation) GPUTotalCost() float64 {
 func (a *Allocation) GPUTotalCost() float64 {
-	return a.GPUCost + a.GPUAdjustment
+	return a.GPUCost + a.GPUCostAdjustment
 }
 }
 
 
 func (a *Allocation) RAMTotalCost() float64 {
 func (a *Allocation) RAMTotalCost() float64 {
-	return a.RAMCost + a.RAMAdjustment
+	return a.RAMCost + a.RAMCostAdjustment
 }
 }
 
 
 func (a *Allocation) PVTotalCost() float64 {
 func (a *Allocation) PVTotalCost() float64 {
-	return a.PVCost + a.PVAdjustment
+	return a.PVCost + a.PVCostAdjustment
 }
 }
 
 
 // CPUEfficiency is the ratio of usage to request. If there is no request and
 // CPUEfficiency is the ratio of usage to request. If there is no request and
@@ -350,6 +350,14 @@ func (a *Allocation) RAMBytes() float64 {
 	return a.RAMByteHours / (a.Minutes() / 60.0)
 	return a.RAMByteHours / (a.Minutes() / 60.0)
 }
 }
 
 
+// GPUs converts the Allocation's GPUHours into average GPUs
+func (a *Allocation) GPUs() float64 {
+	if a.Minutes() <= 0.0 {
+		return 0.0
+	}
+	return a.GPUHours / (a.Minutes() / 60.0)
+}
+
 // PVBytes converts the Allocation's PVByteHours into average PVBytes
 // PVBytes converts the Allocation's PVByteHours into average PVBytes
 func (a *Allocation) PVBytes() float64 {
 func (a *Allocation) PVBytes() float64 {
 	if a.Minutes() <= 0.0 {
 	if a.Minutes() <= 0.0 {
@@ -372,23 +380,24 @@ func (a *Allocation) MarshalJSON() ([]byte, error) {
 	jsonEncodeFloat64(buffer, "cpuCoreUsageAverage", a.CPUCoreUsageAverage, ",")
 	jsonEncodeFloat64(buffer, "cpuCoreUsageAverage", a.CPUCoreUsageAverage, ",")
 	jsonEncodeFloat64(buffer, "cpuCoreHours", a.CPUCoreHours, ",")
 	jsonEncodeFloat64(buffer, "cpuCoreHours", a.CPUCoreHours, ",")
 	jsonEncodeFloat64(buffer, "cpuCost", a.CPUCost, ",")
 	jsonEncodeFloat64(buffer, "cpuCost", a.CPUCost, ",")
-	jsonEncodeFloat64(buffer, "cpuAdjustment", a.CPUAdjustment, ",")
+	jsonEncodeFloat64(buffer, "cpuCostAdjustment", a.CPUCostAdjustment, ",")
 	jsonEncodeFloat64(buffer, "cpuEfficiency", a.CPUEfficiency(), ",")
 	jsonEncodeFloat64(buffer, "cpuEfficiency", a.CPUEfficiency(), ",")
+	jsonEncodeFloat64(buffer, "gpuCount", a.GPUs(), ",")
 	jsonEncodeFloat64(buffer, "gpuHours", a.GPUHours, ",")
 	jsonEncodeFloat64(buffer, "gpuHours", a.GPUHours, ",")
 	jsonEncodeFloat64(buffer, "gpuCost", a.GPUCost, ",")
 	jsonEncodeFloat64(buffer, "gpuCost", a.GPUCost, ",")
-	jsonEncodeFloat64(buffer, "gpuAdjustment", a.GPUAdjustment, ",")
+	jsonEncodeFloat64(buffer, "gpuCostAdjustment", a.GPUCostAdjustment, ",")
 	jsonEncodeFloat64(buffer, "networkCost", a.NetworkCost, ",")
 	jsonEncodeFloat64(buffer, "networkCost", a.NetworkCost, ",")
 	jsonEncodeFloat64(buffer, "loadBalancerCost", a.LoadBalancerCost, ",")
 	jsonEncodeFloat64(buffer, "loadBalancerCost", a.LoadBalancerCost, ",")
 	jsonEncodeFloat64(buffer, "pvBytes", a.PVBytes(), ",")
 	jsonEncodeFloat64(buffer, "pvBytes", a.PVBytes(), ",")
 	jsonEncodeFloat64(buffer, "pvByteHours", a.PVByteHours, ",")
 	jsonEncodeFloat64(buffer, "pvByteHours", a.PVByteHours, ",")
 	jsonEncodeFloat64(buffer, "pvCost", a.PVCost, ",")
 	jsonEncodeFloat64(buffer, "pvCost", a.PVCost, ",")
-	jsonEncodeFloat64(buffer, "pvAdjustment", a.PVAdjustment, ",")
+	jsonEncodeFloat64(buffer, "pvAdjustment", a.PVCostAdjustment, ",")
 	jsonEncodeFloat64(buffer, "ramBytes", a.RAMBytes(), ",")
 	jsonEncodeFloat64(buffer, "ramBytes", a.RAMBytes(), ",")
 	jsonEncodeFloat64(buffer, "ramByteRequestAverage", a.RAMBytesRequestAverage, ",")
 	jsonEncodeFloat64(buffer, "ramByteRequestAverage", a.RAMBytesRequestAverage, ",")
 	jsonEncodeFloat64(buffer, "ramByteUsageAverage", a.RAMBytesUsageAverage, ",")
 	jsonEncodeFloat64(buffer, "ramByteUsageAverage", a.RAMBytesUsageAverage, ",")
 	jsonEncodeFloat64(buffer, "ramByteHours", a.RAMByteHours, ",")
 	jsonEncodeFloat64(buffer, "ramByteHours", a.RAMByteHours, ",")
 	jsonEncodeFloat64(buffer, "ramCost", a.RAMCost, ",")
 	jsonEncodeFloat64(buffer, "ramCost", a.RAMCost, ",")
-	jsonEncodeFloat64(buffer, "ramAdjustment", a.RAMAdjustment, ",")
+	jsonEncodeFloat64(buffer, "ramCostAdjustment", a.RAMCostAdjustment, ",")
 	jsonEncodeFloat64(buffer, "ramEfficiency", a.RAMEfficiency(), ",")
 	jsonEncodeFloat64(buffer, "ramEfficiency", a.RAMEfficiency(), ",")
 	jsonEncodeFloat64(buffer, "sharedCost", a.SharedCost, ",")
 	jsonEncodeFloat64(buffer, "sharedCost", a.SharedCost, ",")
 	jsonEncodeFloat64(buffer, "externalCost", a.ExternalCost, ",")
 	jsonEncodeFloat64(buffer, "externalCost", a.ExternalCost, ",")
@@ -519,10 +528,10 @@ func (a *Allocation) add(that *Allocation) {
 	a.ExternalCost += that.ExternalCost
 	a.ExternalCost += that.ExternalCost
 
 
 	// Sum all cumulative adjustment fields
 	// Sum all cumulative adjustment fields
-	a.CPUAdjustment += that.CPUAdjustment
-	a.RAMAdjustment += that.RAMAdjustment
-	a.GPUAdjustment += that.GPUAdjustment
-	a.PVAdjustment += that.PVAdjustment
+	a.CPUCostAdjustment += that.CPUCostAdjustment
+	a.RAMCostAdjustment += that.RAMCostAdjustment
+	a.GPUCostAdjustment += that.GPUCostAdjustment
+	a.PVCostAdjustment += that.PVCostAdjustment
 
 
 	// Any data that is in a "raw allocation only" is not valid in any
 	// Any data that is in a "raw allocation only" is not valid in any
 	// sort of cumulative Allocation (like one that is added).
 	// sort of cumulative Allocation (like one that is added).
@@ -1505,9 +1514,9 @@ func (as *AllocationSet) ComputeIdleAllocations(assetSet *AssetSet) (map[string]
 	return idleAllocs, nil
 	return idleAllocs, nil
 }
 }
 
 
-// ReconcileAllocations calculate the exact cost of Allocation by resource(cpu, ram, gpu etc) based on Asset(s) on which
+// Reconcile calculate the exact cost of Allocation by resource(cpu, ram, gpu etc) based on Asset(s) on which
 // the Allocation depends.
 // the Allocation depends.
-func (as *AllocationSet) ReconcileAllocations(assetSet *AssetSet) error {
+func (as *AllocationSet) Reconcile(assetSet *AssetSet) error {
 	if as == nil {
 	if as == nil {
 		return fmt.Errorf("cannot reconcile allocation for nil AllocationSet")
 		return fmt.Errorf("cannot reconcile allocation for nil AllocationSet")
 	}
 	}
@@ -1521,11 +1530,11 @@ func (as *AllocationSet) ReconcileAllocations(assetSet *AssetSet) error {
 	}
 	}
 
 
 	// Build map of Assets with type Node by their ProviderId so that they can be matched to Allocations to determine
 	// Build map of Assets with type Node by their ProviderId so that they can be matched to Allocations to determine
-	// proper CPU GPU and Ram prices
+	// proper CPU GPU and RAM prices
 	nodeByProviderID := map[string]*Node{}
 	nodeByProviderID := map[string]*Node{}
 	diskByName := map[string]*Disk{}
 	diskByName := map[string]*Disk{}
 	assetSet.Each(func(key string, a Asset) {
 	assetSet.Each(func(key string, a Asset) {
-		if node, ok := a.(*Node); ok {
+		if node, ok := a.(*Node); ok && node.properties.ProviderID != "" {
 			nodeByProviderID[node.properties.ProviderID] = node
 			nodeByProviderID[node.properties.ProviderID] = node
 		}
 		}
 		if disk, ok := a.(*Disk); ok {
 		if disk, ok := a.(*Disk); ok {
@@ -1590,8 +1599,8 @@ func (a *Allocation) reconcileNodes(nodeByProviderID map[string]*Node) {
 		log.Warningf("Missing Ram Byte Hours for node Provider ID: %s", providerId)
 		log.Warningf("Missing Ram Byte Hours for node Provider ID: %s", providerId)
 	}
 	}
 	gpuUsageProportion := 0.0
 	gpuUsageProportion := 0.0
-	if node.GPUCount != 0 && node.Minutes() != 0 {
-		gpuUsageProportion = a.GPUHours / (node.GPUCount * node.Minutes() / 60)
+	if node.GPUHours != 0 {
+		gpuUsageProportion = a.GPUHours / node.GPUHours
 	}
 	}
 	// No log for GPU because not all nodes have GPU
 	// No log for GPU because not all nodes have GPU
 
 
@@ -1600,9 +1609,9 @@ func (a *Allocation) reconcileNodes(nodeByProviderID map[string]*Node) {
 	allocRAMCost := ramUsageProportion * ramCost
 	allocRAMCost := ramUsageProportion * ramCost
 	allocGPUCost := gpuUsageProportion * gpuCost
 	allocGPUCost := gpuUsageProportion * gpuCost
 
 
-	a.CPUAdjustment = allocCPUCost - a.CPUCost
-	a.RAMAdjustment = allocRAMCost - a.RAMCost
-	a.GPUAdjustment = allocGPUCost - a.GPUCost
+	a.CPUCostAdjustment = allocCPUCost - a.CPUCost
+	a.RAMCostAdjustment = allocRAMCost - a.RAMCost
+	a.GPUCostAdjustment = allocGPUCost - a.GPUCost
 }
 }
 
 
 func (a *Allocation) reconcileDisks(diskByName map[string]*Disk) {
 func (a *Allocation) reconcileDisks(diskByName map[string]*Disk) {
@@ -1612,14 +1621,13 @@ func (a *Allocation) reconcileDisks(diskByName map[string]*Disk) {
 		return
 		return
 	}
 	}
 	// Set PV Adjustment for allocation to 0 for idempotency
 	// Set PV Adjustment for allocation to 0 for idempotency
-	a.PVAdjustment = 0.0
+	a.PVCostAdjustment = 0.0
 	for pvName, pvUsage := range pvBreakDown {
 	for pvName, pvUsage := range pvBreakDown {
 		disk, ok := diskByName[pvName]
 		disk, ok := diskByName[pvName]
 		if !ok {
 		if !ok {
 			// Failed to find disk in assets
 			// Failed to find disk in assets
 			continue
 			continue
 		}
 		}
-
 		// Check the proportion of disk that is being used by
 		// Check the proportion of disk that is being used by
 		pvUsageProportion := 0.0
 		pvUsageProportion := 0.0
 		if disk.ByteHours != 0 {
 		if disk.ByteHours != 0 {
@@ -1631,9 +1639,10 @@ func (a *Allocation) reconcileDisks(diskByName map[string]*Disk) {
 		// take proportion of disk adjusted cost
 		// take proportion of disk adjusted cost
 		allocPVCost := pvUsageProportion * disk.TotalCost()
 		allocPVCost := pvUsageProportion * disk.TotalCost()
 
 
-		// PVAdjustment is cumulative as there can be many PVs for each Allocation
-		a.PVAdjustment += allocPVCost - pvUsage.Cost
+		// PVCostAdjustment is cumulative as there can be many PVs for each Allocation
+		a.PVCostAdjustment += allocPVCost - pvUsage.Cost
 	}
 	}
+
 }
 }
 
 
 // Delete removes the allocation with the given name from the set
 // Delete removes the allocation with the given name from the set

+ 111 - 111
pkg/kubecost/allocation_test.go

@@ -112,18 +112,18 @@ func TestAllocation_Add(t *testing.T) {
 		CPUCoreRequestAverage:  2.0,
 		CPUCoreRequestAverage:  2.0,
 		CPUCoreUsageAverage:    1.0,
 		CPUCoreUsageAverage:    1.0,
 		CPUCost:                2.0 * hrs1 * cpuPrice,
 		CPUCost:                2.0 * hrs1 * cpuPrice,
-		CPUAdjustment:          3.0,
+		CPUCostAdjustment:      3.0,
 		GPUHours:               1.0 * hrs1,
 		GPUHours:               1.0 * hrs1,
 		GPUCost:                1.0 * hrs1 * gpuPrice,
 		GPUCost:                1.0 * hrs1 * gpuPrice,
-		GPUAdjustment:          2.0,
+		GPUCostAdjustment:      2.0,
 		PVByteHours:            100.0 * gib * hrs1,
 		PVByteHours:            100.0 * gib * hrs1,
 		PVCost:                 100.0 * hrs1 * pvPrice,
 		PVCost:                 100.0 * hrs1 * pvPrice,
-		PVAdjustment:           4.0,
+		PVCostAdjustment:       4.0,
 		RAMByteHours:           8.0 * gib * hrs1,
 		RAMByteHours:           8.0 * gib * hrs1,
 		RAMBytesRequestAverage: 8.0 * gib,
 		RAMBytesRequestAverage: 8.0 * gib,
 		RAMBytesUsageAverage:   4.0 * gib,
 		RAMBytesUsageAverage:   4.0 * gib,
 		RAMCost:                8.0 * hrs1 * ramPrice,
 		RAMCost:                8.0 * hrs1 * ramPrice,
-		RAMAdjustment:          1.0,
+		RAMCostAdjustment:      1.0,
 		SharedCost:             2.00,
 		SharedCost:             2.00,
 		ExternalCost:           1.00,
 		ExternalCost:           1.00,
 		RawAllocationOnly:      &RawAllocationOnlyData{},
 		RawAllocationOnly:      &RawAllocationOnlyData{},
@@ -177,20 +177,20 @@ func TestAllocation_Add(t *testing.T) {
 	if !util.IsApproximately(a1.CPUCost+a2.CPUCost, act.CPUCost) {
 	if !util.IsApproximately(a1.CPUCost+a2.CPUCost, act.CPUCost) {
 		t.Fatalf("Allocation.Add: expected %f; actual %f", a1.CPUCost+a2.CPUCost, act.CPUCost)
 		t.Fatalf("Allocation.Add: expected %f; actual %f", a1.CPUCost+a2.CPUCost, act.CPUCost)
 	}
 	}
-	if !util.IsApproximately(a1.CPUAdjustment+a2.CPUAdjustment, act.CPUAdjustment) {
-		t.Fatalf("Allocation.Add: expected %f; actual %f", a1.CPUAdjustment+a2.CPUAdjustment, act.CPUAdjustment)
+	if !util.IsApproximately(a1.CPUCostAdjustment+a2.CPUCostAdjustment, act.CPUCostAdjustment) {
+		t.Fatalf("Allocation.Add: expected %f; actual %f", a1.CPUCostAdjustment+a2.CPUCostAdjustment, act.CPUCostAdjustment)
 	}
 	}
 	if !util.IsApproximately(a1.GPUCost+a2.GPUCost, act.GPUCost) {
 	if !util.IsApproximately(a1.GPUCost+a2.GPUCost, act.GPUCost) {
 		t.Fatalf("Allocation.Add: expected %f; actual %f", a1.GPUCost+a2.GPUCost, act.GPUCost)
 		t.Fatalf("Allocation.Add: expected %f; actual %f", a1.GPUCost+a2.GPUCost, act.GPUCost)
 	}
 	}
-	if !util.IsApproximately(a1.GPUAdjustment+a2.GPUAdjustment, act.GPUAdjustment) {
-		t.Fatalf("Allocation.Add: expected %f; actual %f", a1.GPUAdjustment+a2.GPUAdjustment, act.GPUAdjustment)
+	if !util.IsApproximately(a1.GPUCostAdjustment+a2.GPUCostAdjustment, act.GPUCostAdjustment) {
+		t.Fatalf("Allocation.Add: expected %f; actual %f", a1.GPUCostAdjustment+a2.GPUCostAdjustment, act.GPUCostAdjustment)
 	}
 	}
 	if !util.IsApproximately(a1.RAMCost+a2.RAMCost, act.RAMCost) {
 	if !util.IsApproximately(a1.RAMCost+a2.RAMCost, act.RAMCost) {
 		t.Fatalf("Allocation.Add: expected %f; actual %f", a1.RAMCost+a2.RAMCost, act.RAMCost)
 		t.Fatalf("Allocation.Add: expected %f; actual %f", a1.RAMCost+a2.RAMCost, act.RAMCost)
 	}
 	}
-	if !util.IsApproximately(a1.RAMAdjustment+a2.RAMAdjustment, act.RAMAdjustment) {
-		t.Fatalf("Allocation.Add: expected %f; actual %f", a1.RAMAdjustment+a2.RAMAdjustment, act.RAMAdjustment)
+	if !util.IsApproximately(a1.RAMCostAdjustment+a2.RAMCostAdjustment, act.RAMCostAdjustment) {
+		t.Fatalf("Allocation.Add: expected %f; actual %f", a1.RAMCostAdjustment+a2.RAMCostAdjustment, act.RAMCostAdjustment)
 	}
 	}
 	if !util.IsApproximately(a1.PVCost+a2.PVCost, act.PVCost) {
 	if !util.IsApproximately(a1.PVCost+a2.PVCost, act.PVCost) {
 		t.Fatalf("Allocation.Add: expected %f; actual %f", a1.PVCost+a2.PVCost, act.PVCost)
 		t.Fatalf("Allocation.Add: expected %f; actual %f", a1.PVCost+a2.PVCost, act.PVCost)
@@ -282,18 +282,18 @@ func TestAllocation_Share(t *testing.T) {
 		CPUCoreRequestAverage:  2.0,
 		CPUCoreRequestAverage:  2.0,
 		CPUCoreUsageAverage:    1.0,
 		CPUCoreUsageAverage:    1.0,
 		CPUCost:                2.0 * hrs1 * cpuPrice,
 		CPUCost:                2.0 * hrs1 * cpuPrice,
-		CPUAdjustment:          3.0,
+		CPUCostAdjustment:      3.0,
 		GPUHours:               1.0 * hrs1,
 		GPUHours:               1.0 * hrs1,
 		GPUCost:                1.0 * hrs1 * gpuPrice,
 		GPUCost:                1.0 * hrs1 * gpuPrice,
-		GPUAdjustment:          2.0,
+		GPUCostAdjustment:      2.0,
 		PVByteHours:            100.0 * gib * hrs1,
 		PVByteHours:            100.0 * gib * hrs1,
 		PVCost:                 100.0 * hrs1 * pvPrice,
 		PVCost:                 100.0 * hrs1 * pvPrice,
-		PVAdjustment:           4.0,
+		PVCostAdjustment:       4.0,
 		RAMByteHours:           8.0 * gib * hrs1,
 		RAMByteHours:           8.0 * gib * hrs1,
 		RAMBytesRequestAverage: 8.0 * gib,
 		RAMBytesRequestAverage: 8.0 * gib,
 		RAMBytesUsageAverage:   4.0 * gib,
 		RAMBytesUsageAverage:   4.0 * gib,
 		RAMCost:                8.0 * hrs1 * ramPrice,
 		RAMCost:                8.0 * hrs1 * ramPrice,
-		RAMAdjustment:          1.0,
+		RAMCostAdjustment:      1.0,
 		SharedCost:             2.00,
 		SharedCost:             2.00,
 		ExternalCost:           1.00,
 		ExternalCost:           1.00,
 	}
 	}
@@ -442,20 +442,20 @@ func TestAllocation_MarshalJSON(t *testing.T) {
 		CPUCoreRequestAverage:  2.0,
 		CPUCoreRequestAverage:  2.0,
 		CPUCoreUsageAverage:    1.0,
 		CPUCoreUsageAverage:    1.0,
 		CPUCost:                2.0 * hrs * cpuPrice,
 		CPUCost:                2.0 * hrs * cpuPrice,
-		CPUAdjustment:          3.0,
+		CPUCostAdjustment:      3.0,
 		GPUHours:               1.0 * hrs,
 		GPUHours:               1.0 * hrs,
 		GPUCost:                1.0 * hrs * gpuPrice,
 		GPUCost:                1.0 * hrs * gpuPrice,
-		GPUAdjustment:          2.0,
+		GPUCostAdjustment:      2.0,
 		NetworkCost:            0.05,
 		NetworkCost:            0.05,
 		LoadBalancerCost:       0.02,
 		LoadBalancerCost:       0.02,
 		PVByteHours:            100.0 * gib * hrs,
 		PVByteHours:            100.0 * gib * hrs,
 		PVCost:                 100.0 * hrs * pvPrice,
 		PVCost:                 100.0 * hrs * pvPrice,
-		PVAdjustment:           4.0,
+		PVCostAdjustment:       4.0,
 		RAMByteHours:           8.0 * gib * hrs,
 		RAMByteHours:           8.0 * gib * hrs,
 		RAMBytesRequestAverage: 8.0 * gib,
 		RAMBytesRequestAverage: 8.0 * gib,
 		RAMBytesUsageAverage:   4.0 * gib,
 		RAMBytesUsageAverage:   4.0 * gib,
 		RAMCost:                8.0 * hrs * ramPrice,
 		RAMCost:                8.0 * hrs * ramPrice,
-		RAMAdjustment:          1.0,
+		RAMCostAdjustment:      1.0,
 		SharedCost:             2.00,
 		SharedCost:             2.00,
 		ExternalCost:           1.00,
 		ExternalCost:           1.00,
 		RawAllocationOnly:      &RawAllocationOnlyData{},
 		RawAllocationOnly:      &RawAllocationOnlyData{},
@@ -761,7 +761,7 @@ func generateAssetSets(start, end time.Time) []*AssetSet {
 	cluster1Nodes.adjustment = -10.00
 	cluster1Nodes.adjustment = -10.00
 	cluster1Nodes.CPUCoreHours = 8
 	cluster1Nodes.CPUCoreHours = 8
 	cluster1Nodes.RAMByteHours = 6
 	cluster1Nodes.RAMByteHours = 6
-	cluster1Nodes.GPUCount = 1
+	cluster1Nodes.GPUHours = 24
 
 
 	cluster2Node1 := NewNode("node1", "cluster2", "node1", start, end, NewWindow(&start, &end))
 	cluster2Node1 := NewNode("node1", "cluster2", "node1", start, end, NewWindow(&start, &end))
 	cluster2Node1.CPUCost = 20.0
 	cluster2Node1.CPUCost = 20.0
@@ -769,7 +769,7 @@ func generateAssetSets(start, end time.Time) []*AssetSet {
 	cluster2Node1.GPUCost = 0.0
 	cluster2Node1.GPUCost = 0.0
 	cluster2Node1.CPUCoreHours = 4
 	cluster2Node1.CPUCoreHours = 4
 	cluster2Node1.RAMByteHours = 3
 	cluster2Node1.RAMByteHours = 3
-	cluster2Node1.GPUCount = 0
+	cluster2Node1.GPUHours = 0
 
 
 	cluster2Node2 := NewNode("node2", "cluster2", "node2", start, end, NewWindow(&start, &end))
 	cluster2Node2 := NewNode("node2", "cluster2", "node2", start, end, NewWindow(&start, &end))
 	cluster2Node2.CPUCost = 20.0
 	cluster2Node2.CPUCost = 20.0
@@ -777,7 +777,7 @@ func generateAssetSets(start, end time.Time) []*AssetSet {
 	cluster2Node2.GPUCost = 0.0
 	cluster2Node2.GPUCost = 0.0
 	cluster2Node2.CPUCoreHours = 3
 	cluster2Node2.CPUCoreHours = 3
 	cluster2Node2.RAMByteHours = 2
 	cluster2Node2.RAMByteHours = 2
-	cluster2Node2.GPUCount = 0
+	cluster2Node2.GPUHours = 0
 
 
 	cluster2Node3 := NewNode("node3", "cluster2", "node3", start, end, NewWindow(&start, &end))
 	cluster2Node3 := NewNode("node3", "cluster2", "node3", start, end, NewWindow(&start, &end))
 	cluster2Node3.CPUCost = 10.0
 	cluster2Node3.CPUCost = 10.0
@@ -785,7 +785,7 @@ func generateAssetSets(start, end time.Time) []*AssetSet {
 	cluster2Node3.GPUCost = 10.0
 	cluster2Node3.GPUCost = 10.0
 	cluster2Node3.CPUCoreHours = 2
 	cluster2Node3.CPUCoreHours = 2
 	cluster2Node3.RAMByteHours = 2
 	cluster2Node3.RAMByteHours = 2
-	cluster2Node3.GPUCount = 1
+	cluster2Node3.GPUHours = 24
 
 
 	cluster2Disk1 := NewDisk("disk1", "cluster2", "disk1", start, end, NewWindow(&start, &end))
 	cluster2Disk1 := NewDisk("disk1", "cluster2", "disk1", start, end, NewWindow(&start, &end))
 	cluster2Disk1.Cost = 5.0
 	cluster2Disk1.Cost = 5.0
@@ -834,7 +834,7 @@ func generateAssetSets(start, end time.Time) []*AssetSet {
 	cluster1Nodes.adjustment = 90.00
 	cluster1Nodes.adjustment = 90.00
 	cluster1Nodes.CPUCoreHours = 8
 	cluster1Nodes.CPUCoreHours = 8
 	cluster1Nodes.RAMByteHours = 6
 	cluster1Nodes.RAMByteHours = 6
-	cluster1Nodes.GPUCount = 1
+	cluster1Nodes.GPUHours = 24
 
 
 	cluster2Node1 = NewNode("node1", "cluster2", "node1", start, end, NewWindow(&start, &end))
 	cluster2Node1 = NewNode("node1", "cluster2", "node1", start, end, NewWindow(&start, &end))
 	cluster2Node1.CPUCost = 20.0
 	cluster2Node1.CPUCost = 20.0
@@ -842,7 +842,7 @@ func generateAssetSets(start, end time.Time) []*AssetSet {
 	cluster2Node1.GPUCost = 0.0
 	cluster2Node1.GPUCost = 0.0
 	cluster2Node1.CPUCoreHours = 4
 	cluster2Node1.CPUCoreHours = 4
 	cluster2Node1.RAMByteHours = 3
 	cluster2Node1.RAMByteHours = 3
-	cluster2Node1.GPUCount = 0
+	cluster2Node1.GPUHours = 0
 
 
 	cluster2Node2 = NewNode("node2", "cluster2", "node2", start, end, NewWindow(&start, &end))
 	cluster2Node2 = NewNode("node2", "cluster2", "node2", start, end, NewWindow(&start, &end))
 	cluster2Node2.CPUCost = 20.0
 	cluster2Node2.CPUCost = 20.0
@@ -850,7 +850,7 @@ func generateAssetSets(start, end time.Time) []*AssetSet {
 	cluster2Node2.GPUCost = 0.0
 	cluster2Node2.GPUCost = 0.0
 	cluster2Node2.CPUCoreHours = 3
 	cluster2Node2.CPUCoreHours = 3
 	cluster2Node2.RAMByteHours = 2
 	cluster2Node2.RAMByteHours = 2
-	cluster2Node2.GPUCount = 0
+	cluster2Node2.GPUHours = 0
 
 
 	cluster2Node3 = NewNode("node3", "cluster2", "node3", start, end, NewWindow(&start, &end))
 	cluster2Node3 = NewNode("node3", "cluster2", "node3", start, end, NewWindow(&start, &end))
 	cluster2Node3.CPUCost = 10.0
 	cluster2Node3.CPUCost = 10.0
@@ -858,7 +858,7 @@ func generateAssetSets(start, end time.Time) []*AssetSet {
 	cluster2Node3.GPUCost = 10.0
 	cluster2Node3.GPUCost = 10.0
 	cluster2Node3.CPUCoreHours = 2
 	cluster2Node3.CPUCoreHours = 2
 	cluster2Node3.RAMByteHours = 2
 	cluster2Node3.RAMByteHours = 2
-	cluster2Node3.GPUCount = 1
+	cluster2Node3.GPUHours = 24
 
 
 	cluster2Disk1 = NewDisk("disk1", "cluster2", "disk1", start, end, NewWindow(&start, &end))
 	cluster2Disk1 = NewDisk("disk1", "cluster2", "disk1", start, end, NewWindow(&start, &end))
 	cluster2Disk1.Cost = 5.0
 	cluster2Disk1.Cost = 5.0
@@ -1792,9 +1792,9 @@ func TestAllocationSet_ReconcileAllocations(t *testing.T) {
 				// RAM	|    44	    |	  6	     |     11 	  |	  1
 				// RAM	|    44	    |	  6	     |     11 	  |	  1
 				// GPU	|    11	    |	 24      |     1 	  |	  1
 				// GPU	|    11	    |	 24      |     1 	  |	  1
 				"cluster1/namespace1/pod1/container1": {
 				"cluster1/namespace1/pod1/container1": {
-					CPUAdjustment: 5.25,
-					RAMAdjustment: -4.333333,
-					GPUAdjustment: -0.583333,
+					CPUCostAdjustment: 5.25,
+					RAMCostAdjustment: -4.333333,
+					GPUCostAdjustment: -0.583333,
 				},
 				},
 				// ADJUSTMENT_RATE: 0.90909090909
 				// ADJUSTMENT_RATE: 0.90909090909
 				// Type | NODE_COST | NODE_HOURs | ALLOC_COST | ALLOC_HOURS
 				// Type | NODE_COST | NODE_HOURs | ALLOC_COST | ALLOC_HOURS
@@ -1802,29 +1802,29 @@ func TestAllocationSet_ReconcileAllocations(t *testing.T) {
 				// RAM	|    44	    |	  6	     |     1 	  |	  1
 				// RAM	|    44	    |	  6	     |     1 	  |	  1
 				// GPU	|    11	    |	 24      |     1 	  |	  1
 				// GPU	|    11	    |	 24      |     1 	  |	  1
 				"cluster1/namespace1/pod-abc/container2": {
 				"cluster1/namespace1/pod-abc/container2": {
-					CPUAdjustment: 5.25,
-					RAMAdjustment: 5.666667,
-					GPUAdjustment: -0.583333,
+					CPUCostAdjustment: 5.25,
+					RAMCostAdjustment: 5.666667,
+					GPUCostAdjustment: -0.583333,
 				},
 				},
 				"cluster1/namespace1/pod-def/container3": {
 				"cluster1/namespace1/pod-def/container3": {
-					CPUAdjustment: 5.25,
-					RAMAdjustment: 5.666667,
-					GPUAdjustment: -0.583333,
+					CPUCostAdjustment: 5.25,
+					RAMCostAdjustment: 5.666667,
+					GPUCostAdjustment: -0.583333,
 				},
 				},
 				"cluster1/namespace2/pod-ghi/container4": {
 				"cluster1/namespace2/pod-ghi/container4": {
-					CPUAdjustment: 5.25,
-					RAMAdjustment: 5.666667,
-					GPUAdjustment: -0.583333,
+					CPUCostAdjustment: 5.25,
+					RAMCostAdjustment: 5.666667,
+					GPUCostAdjustment: -0.583333,
 				},
 				},
 				"cluster1/namespace2/pod-ghi/container5": {
 				"cluster1/namespace2/pod-ghi/container5": {
-					CPUAdjustment: 5.25,
-					RAMAdjustment: 5.666667,
-					GPUAdjustment: -0.583333,
+					CPUCostAdjustment: 5.25,
+					RAMCostAdjustment: 5.666667,
+					GPUCostAdjustment: -0.583333,
 				},
 				},
 				"cluster1/namespace2/pod-jkl/container6": {
 				"cluster1/namespace2/pod-jkl/container6": {
-					CPUAdjustment: 5.25,
-					RAMAdjustment: 5.666667,
-					GPUAdjustment: -0.583333,
+					CPUCostAdjustment: 5.25,
+					RAMCostAdjustment: 5.666667,
+					GPUCostAdjustment: -0.583333,
 				},
 				},
 				// ADJUSTMENT_RATE: 1.0
 				// ADJUSTMENT_RATE: 1.0
 				// Type | NODE_COST | NODE_HOURs | ALLOC_COST | ALLOC_HOURS
 				// Type | NODE_COST | NODE_HOURs | ALLOC_COST | ALLOC_HOURS
@@ -1832,16 +1832,16 @@ func TestAllocationSet_ReconcileAllocations(t *testing.T) {
 				// RAM	|    15	    |	  3	     |     1 	  |	  1
 				// RAM	|    15	    |	  3	     |     1 	  |	  1
 				// GPU	|    0	    |	  0      |     1 	  |	  1
 				// GPU	|    0	    |	  0      |     1 	  |	  1
 				"cluster2/namespace2/pod-mno/container4": {
 				"cluster2/namespace2/pod-mno/container4": {
-					CPUAdjustment: 4.0,
-					RAMAdjustment: 4.0,
-					GPUAdjustment: -1.0,
-					PVAdjustment:  2.0,
+					CPUCostAdjustment: 4.0,
+					RAMCostAdjustment: 4.0,
+					GPUCostAdjustment: -1.0,
+					PVCostAdjustment:  2.0,
 				},
 				},
 				"cluster2/namespace2/pod-mno/container5": {
 				"cluster2/namespace2/pod-mno/container5": {
-					CPUAdjustment: 4.0,
-					RAMAdjustment: 4.0,
-					GPUAdjustment: -1.0,
-					PVAdjustment:  2.0,
+					CPUCostAdjustment: 4.0,
+					RAMCostAdjustment: 4.0,
+					GPUCostAdjustment: -1.0,
+					PVCostAdjustment:  2.0,
 				},
 				},
 				// ADJUSTMENT_RATE: 1.0
 				// ADJUSTMENT_RATE: 1.0
 				// Type | NODE_COST | NODE_HOURs | ALLOC_COST | ALLOC_HOURS
 				// Type | NODE_COST | NODE_HOURs | ALLOC_COST | ALLOC_HOURS
@@ -1849,14 +1849,14 @@ func TestAllocationSet_ReconcileAllocations(t *testing.T) {
 				// RAM	|    15	    |	  2	     |     1 	  |	  1
 				// RAM	|    15	    |	  2	     |     1 	  |	  1
 				// GPU	|    0	    |	  0      |     1 	  |	  1
 				// GPU	|    0	    |	  0      |     1 	  |	  1
 				"cluster2/namespace2/pod-pqr/container6": {
 				"cluster2/namespace2/pod-pqr/container6": {
-					CPUAdjustment: 5.666667,
-					RAMAdjustment: 6.5,
-					GPUAdjustment: -1.0,
+					CPUCostAdjustment: 5.666667,
+					RAMCostAdjustment: 6.5,
+					GPUCostAdjustment: -1.0,
 				},
 				},
 				"cluster2/namespace3/pod-stu/container7": {
 				"cluster2/namespace3/pod-stu/container7": {
-					CPUAdjustment: 5.666667,
-					RAMAdjustment: 6.5,
-					GPUAdjustment: -1.0,
+					CPUCostAdjustment: 5.666667,
+					RAMCostAdjustment: 6.5,
+					GPUCostAdjustment: -1.0,
 				},
 				},
 				// ADJUSTMENT_RATE: 1.0
 				// ADJUSTMENT_RATE: 1.0
 				// Type | NODE_COST | NODE_HOURs | ALLOC_COST | ALLOC_HOURS
 				// Type | NODE_COST | NODE_HOURs | ALLOC_COST | ALLOC_HOURS
@@ -1864,14 +1864,14 @@ func TestAllocationSet_ReconcileAllocations(t *testing.T) {
 				// RAM	|    10	    |	  2	     |     1 	  |	  1
 				// RAM	|    10	    |	  2	     |     1 	  |	  1
 				// GPU	|    10	    |	 24      |     1 	  |	  1
 				// GPU	|    10	    |	 24      |     1 	  |	  1
 				"cluster2/namespace3/pod-vwx/container8": {
 				"cluster2/namespace3/pod-vwx/container8": {
-					CPUAdjustment: 4.0,
-					RAMAdjustment: 4.0,
-					GPUAdjustment: -0.583333,
+					CPUCostAdjustment: 4.0,
+					RAMCostAdjustment: 4.0,
+					GPUCostAdjustment: -0.583333,
 				},
 				},
 				"cluster2/namespace3/pod-vwx/container9": {
 				"cluster2/namespace3/pod-vwx/container9": {
-					CPUAdjustment: 4.0,
-					RAMAdjustment: 4.0,
-					GPUAdjustment: -0.583333,
+					CPUCostAdjustment: 4.0,
+					RAMCostAdjustment: 4.0,
+					GPUCostAdjustment: -0.583333,
 				},
 				},
 			},
 			},
 		},
 		},
@@ -1885,9 +1885,9 @@ func TestAllocationSet_ReconcileAllocations(t *testing.T) {
 				// RAM	|     4	    |	  6	     |    11 	  |	  1
 				// RAM	|     4	    |	  6	     |    11 	  |	  1
 				// GPU	|     1	    |	 24      |     1 	  |	  1
 				// GPU	|     1	    |	 24      |     1 	  |	  1
 				"cluster1/namespace1/pod1/container1": {
 				"cluster1/namespace1/pod1/container1": {
-					CPUAdjustment: 5.25,
-					RAMAdjustment: -4.333333,
-					GPUAdjustment: -0.583333,
+					CPUCostAdjustment: 5.25,
+					RAMCostAdjustment: -4.333333,
+					GPUCostAdjustment: -0.583333,
 				},
 				},
 				// ADJUSTMENT_RATE: 10
 				// ADJUSTMENT_RATE: 10
 				// Type | NODE_COST | NODE_HOURs | ALLOC_COST | ALLOC_HOURS
 				// Type | NODE_COST | NODE_HOURs | ALLOC_COST | ALLOC_HOURS
@@ -1895,29 +1895,29 @@ func TestAllocationSet_ReconcileAllocations(t *testing.T) {
 				// RAM	|     4	    |	  6	     |     1 	  |	  1
 				// RAM	|     4	    |	  6	     |     1 	  |	  1
 				// GPU	|     1	    |	 24      |     1 	  |	  1
 				// GPU	|     1	    |	 24      |     1 	  |	  1
 				"cluster1/namespace1/pod-abc/container2": {
 				"cluster1/namespace1/pod-abc/container2": {
-					CPUAdjustment: 5.25,
-					RAMAdjustment: 5.6666667,
-					GPUAdjustment: -0.583333,
+					CPUCostAdjustment: 5.25,
+					RAMCostAdjustment: 5.6666667,
+					GPUCostAdjustment: -0.583333,
 				},
 				},
 				"cluster1/namespace1/pod-def/container3": {
 				"cluster1/namespace1/pod-def/container3": {
-					CPUAdjustment: 5.25,
-					RAMAdjustment: 5.6666667,
-					GPUAdjustment: -0.583333,
+					CPUCostAdjustment: 5.25,
+					RAMCostAdjustment: 5.6666667,
+					GPUCostAdjustment: -0.583333,
 				},
 				},
 				"cluster1/namespace2/pod-ghi/container4": {
 				"cluster1/namespace2/pod-ghi/container4": {
-					CPUAdjustment: 5.25,
-					RAMAdjustment: 5.6666667,
-					GPUAdjustment: -0.583333,
+					CPUCostAdjustment: 5.25,
+					RAMCostAdjustment: 5.6666667,
+					GPUCostAdjustment: -0.583333,
 				},
 				},
 				"cluster1/namespace2/pod-ghi/container5": {
 				"cluster1/namespace2/pod-ghi/container5": {
-					CPUAdjustment: 5.25,
-					RAMAdjustment: 5.6666667,
-					GPUAdjustment: -0.583333,
+					CPUCostAdjustment: 5.25,
+					RAMCostAdjustment: 5.6666667,
+					GPUCostAdjustment: -0.583333,
 				},
 				},
 				"cluster1/namespace2/pod-jkl/container6": {
 				"cluster1/namespace2/pod-jkl/container6": {
-					CPUAdjustment: 5.25,
-					RAMAdjustment: 5.6666667,
-					GPUAdjustment: -0.583333,
+					CPUCostAdjustment: 5.25,
+					RAMCostAdjustment: 5.6666667,
+					GPUCostAdjustment: -0.583333,
 				},
 				},
 				// ADJUSTMENT_RATE: 1.0
 				// ADJUSTMENT_RATE: 1.0
 				// Type | NODE_COST | NODE_HOURs | ALLOC_COST | ALLOC_HOURS
 				// Type | NODE_COST | NODE_HOURs | ALLOC_COST | ALLOC_HOURS
@@ -1925,16 +1925,16 @@ func TestAllocationSet_ReconcileAllocations(t *testing.T) {
 				// RAM	|    15	    |	  3	     |     1 	  |	  1
 				// RAM	|    15	    |	  3	     |     1 	  |	  1
 				// GPU	|    0	    |	  0      |     1 	  |	  1
 				// GPU	|    0	    |	  0      |     1 	  |	  1
 				"cluster2/namespace2/pod-mno/container4": {
 				"cluster2/namespace2/pod-mno/container4": {
-					CPUAdjustment: 4.0,
-					RAMAdjustment: 4.0,
-					GPUAdjustment: -1.0,
-					PVAdjustment:  -0.5,
+					CPUCostAdjustment: 4.0,
+					RAMCostAdjustment: 4.0,
+					GPUCostAdjustment: -1.0,
+					PVCostAdjustment:  -0.5,
 				},
 				},
 				"cluster2/namespace2/pod-mno/container5": {
 				"cluster2/namespace2/pod-mno/container5": {
-					CPUAdjustment: 4.0,
-					RAMAdjustment: 4.0,
-					GPUAdjustment: -1.0,
-					PVAdjustment:  -0.5,
+					CPUCostAdjustment: 4.0,
+					RAMCostAdjustment: 4.0,
+					GPUCostAdjustment: -1.0,
+					PVCostAdjustment:  -0.5,
 				},
 				},
 				// ADJUSTMENT_RATE: 1.0
 				// ADJUSTMENT_RATE: 1.0
 				// Type | NODE_COST | NODE_HOURs | ALLOC_COST | ALLOC_HOURS
 				// Type | NODE_COST | NODE_HOURs | ALLOC_COST | ALLOC_HOURS
@@ -1942,14 +1942,14 @@ func TestAllocationSet_ReconcileAllocations(t *testing.T) {
 				// RAM	|    15	    |	  2	     |     1 	  |	  1
 				// RAM	|    15	    |	  2	     |     1 	  |	  1
 				// GPU	|    0	    |	  0      |     1 	  |	  1
 				// GPU	|    0	    |	  0      |     1 	  |	  1
 				"cluster2/namespace2/pod-pqr/container6": {
 				"cluster2/namespace2/pod-pqr/container6": {
-					CPUAdjustment: 5.666667,
-					RAMAdjustment: 6.5,
-					GPUAdjustment: -1.0,
+					CPUCostAdjustment: 5.666667,
+					RAMCostAdjustment: 6.5,
+					GPUCostAdjustment: -1.0,
 				},
 				},
 				"cluster2/namespace3/pod-stu/container7": {
 				"cluster2/namespace3/pod-stu/container7": {
-					CPUAdjustment: 5.666667,
-					RAMAdjustment: 6.5,
-					GPUAdjustment: -1.0,
+					CPUCostAdjustment: 5.666667,
+					RAMCostAdjustment: 6.5,
+					GPUCostAdjustment: -1.0,
 				},
 				},
 				// ADJUSTMENT_RATE: 1.0
 				// ADJUSTMENT_RATE: 1.0
 				// Type | NODE_COST | NODE_HOURs | ALLOC_COST | ALLOC_HOURS
 				// Type | NODE_COST | NODE_HOURs | ALLOC_COST | ALLOC_HOURS
@@ -1957,14 +1957,14 @@ func TestAllocationSet_ReconcileAllocations(t *testing.T) {
 				// RAM	|    10	    |	  2	     |     1 	  |	  1
 				// RAM	|    10	    |	  2	     |     1 	  |	  1
 				// GPU	|    10	    |	 24      |     1 	  |	  1
 				// GPU	|    10	    |	 24      |     1 	  |	  1
 				"cluster2/namespace3/pod-vwx/container8": {
 				"cluster2/namespace3/pod-vwx/container8": {
-					CPUAdjustment: 4.0,
-					RAMAdjustment: 4.0,
-					GPUAdjustment: -0.583333,
+					CPUCostAdjustment: 4.0,
+					RAMCostAdjustment: 4.0,
+					GPUCostAdjustment: -0.583333,
 				},
 				},
 				"cluster2/namespace3/pod-vwx/container9": {
 				"cluster2/namespace3/pod-vwx/container9": {
-					CPUAdjustment: 4.0,
-					RAMAdjustment: 4.0,
-					GPUAdjustment: -0.583333,
+					CPUCostAdjustment: 4.0,
+					RAMCostAdjustment: 4.0,
+					GPUCostAdjustment: -0.583333,
 				},
 				},
 			},
 			},
 		},
 		},
@@ -1972,7 +1972,7 @@ func TestAllocationSet_ReconcileAllocations(t *testing.T) {
 
 
 	for name, testcase := range cases {
 	for name, testcase := range cases {
 		t.Run(name, func(t *testing.T) {
 		t.Run(name, func(t *testing.T) {
-			err = as.ReconcileAllocations(testcase.assetSet)
+			err = as.Reconcile(testcase.assetSet)
 			reconAllocs := as.allocations
 			reconAllocs := as.allocations
 			if err != nil {
 			if err != nil {
 				t.Fatalf("unexpected error: %s", err)
 				t.Fatalf("unexpected error: %s", err)
@@ -1983,17 +1983,17 @@ func TestAllocationSet_ReconcileAllocations(t *testing.T) {
 					t.Fatalf("expected allocation %s", allocationName)
 					t.Fatalf("expected allocation %s", allocationName)
 				}
 				}
 
 
-				if !util.IsApproximately(reconAllocs[allocationName].CPUAdjustment, testAlloc.CPUAdjustment) {
-					t.Fatalf("expected CPU Adjustment for %s to be %f; got %f", allocationName, testAlloc.CPUAdjustment, reconAllocs[allocationName].CPUAdjustment)
+				if !util.IsApproximately(reconAllocs[allocationName].CPUCostAdjustment, testAlloc.CPUCostAdjustment) {
+					t.Fatalf("expected CPU Adjustment for %s to be %f; got %f", allocationName, testAlloc.CPUCostAdjustment, reconAllocs[allocationName].CPUCostAdjustment)
 				}
 				}
-				if !util.IsApproximately(reconAllocs[allocationName].RAMAdjustment, testAlloc.RAMAdjustment) {
-					t.Fatalf("expected RAM Adjustment for %s to be %f; got %f", allocationName, testAlloc.RAMAdjustment, reconAllocs[allocationName].RAMAdjustment)
+				if !util.IsApproximately(reconAllocs[allocationName].RAMCostAdjustment, testAlloc.RAMCostAdjustment) {
+					t.Fatalf("expected RAM Adjustment for %s to be %f; got %f", allocationName, testAlloc.RAMCostAdjustment, reconAllocs[allocationName].RAMCostAdjustment)
 				}
 				}
-				if !util.IsApproximately(reconAllocs[allocationName].GPUAdjustment, testAlloc.GPUAdjustment) {
-					t.Fatalf("expected GPU Adjustment for %s to be %f; got %f", allocationName, testAlloc.GPUAdjustment, reconAllocs[allocationName].GPUAdjustment)
+				if !util.IsApproximately(reconAllocs[allocationName].GPUCostAdjustment, testAlloc.GPUCostAdjustment) {
+					t.Fatalf("expected GPU Adjustment for %s to be %f; got %f", allocationName, testAlloc.GPUCostAdjustment, reconAllocs[allocationName].GPUCostAdjustment)
 				}
 				}
-				if !util.IsApproximately(reconAllocs[allocationName].PVAdjustment, testAlloc.PVAdjustment) {
-					t.Fatalf("expected PV Adjustment for %s to be %f; got %f", allocationName, testAlloc.PVAdjustment, reconAllocs[allocationName].PVAdjustment)
+				if !util.IsApproximately(reconAllocs[allocationName].PVCostAdjustment, testAlloc.PVCostAdjustment) {
+					t.Fatalf("expected PV Adjustment for %s to be %f; got %f", allocationName, testAlloc.PVCostAdjustment, reconAllocs[allocationName].PVCostAdjustment)
 				}
 				}
 			}
 			}
 		})
 		})

+ 26 - 4
pkg/kubecost/asset.go

@@ -1663,6 +1663,7 @@ type Node struct {
 	NodeType     string
 	NodeType     string
 	CPUCoreHours float64
 	CPUCoreHours float64
 	RAMByteHours float64
 	RAMByteHours float64
+	GPUHours     float64
 	CPUBreakdown *Breakdown
 	CPUBreakdown *Breakdown
 	RAMBreakdown *Breakdown
 	RAMBreakdown *Breakdown
 	CPUCost      float64
 	CPUCost      float64
@@ -1889,6 +1890,7 @@ func (n *Node) add(that *Node) {
 
 
 	n.CPUCoreHours += that.CPUCoreHours
 	n.CPUCoreHours += that.CPUCoreHours
 	n.RAMByteHours += that.RAMByteHours
 	n.RAMByteHours += that.RAMByteHours
+	n.GPUHours += that.GPUHours
 
 
 	n.CPUCost += that.CPUCost
 	n.CPUCost += that.CPUCost
 	n.GPUCost += that.GPUCost
 	n.GPUCost += that.GPUCost
@@ -1912,6 +1914,7 @@ func (n *Node) Clone() Asset {
 		NodeType:     n.NodeType,
 		NodeType:     n.NodeType,
 		CPUCoreHours: n.CPUCoreHours,
 		CPUCoreHours: n.CPUCoreHours,
 		RAMByteHours: n.RAMByteHours,
 		RAMByteHours: n.RAMByteHours,
+		GPUHours:     n.GPUHours,
 		CPUBreakdown: n.CPUBreakdown.Clone(),
 		CPUBreakdown: n.CPUBreakdown.Clone(),
 		RAMBreakdown: n.RAMBreakdown.Clone(),
 		RAMBreakdown: n.RAMBreakdown.Clone(),
 		CPUCost:      n.CPUCost,
 		CPUCost:      n.CPUCost,
@@ -1960,6 +1963,9 @@ func (n *Node) Equal(a Asset) bool {
 	if n.RAMByteHours != that.RAMByteHours {
 	if n.RAMByteHours != that.RAMByteHours {
 		return false
 		return false
 	}
 	}
+	if n.GPUHours != that.GPUHours {
+		return false
+	}
 	if !n.CPUBreakdown.Equal(that.CPUBreakdown) {
 	if !n.CPUBreakdown.Equal(that.CPUBreakdown) {
 		return false
 		return false
 	}
 	}
@@ -2000,13 +2006,14 @@ func (n *Node) MarshalJSON() ([]byte, error) {
 	jsonEncodeFloat64(buffer, "ramBytes", n.RAMBytes(), ",")
 	jsonEncodeFloat64(buffer, "ramBytes", n.RAMBytes(), ",")
 	jsonEncodeFloat64(buffer, "cpuCoreHours", n.CPUCoreHours, ",")
 	jsonEncodeFloat64(buffer, "cpuCoreHours", n.CPUCoreHours, ",")
 	jsonEncodeFloat64(buffer, "ramByteHours", n.RAMByteHours, ",")
 	jsonEncodeFloat64(buffer, "ramByteHours", n.RAMByteHours, ",")
+	jsonEncodeFloat64(buffer, "GPUHours", n.GPUHours, ",")
 	jsonEncode(buffer, "cpuBreakdown", n.CPUBreakdown, ",")
 	jsonEncode(buffer, "cpuBreakdown", n.CPUBreakdown, ",")
 	jsonEncode(buffer, "ramBreakdown", n.RAMBreakdown, ",")
 	jsonEncode(buffer, "ramBreakdown", n.RAMBreakdown, ",")
 	jsonEncodeFloat64(buffer, "preemptible", n.Preemptible, ",")
 	jsonEncodeFloat64(buffer, "preemptible", n.Preemptible, ",")
 	jsonEncodeFloat64(buffer, "discount", n.Discount, ",")
 	jsonEncodeFloat64(buffer, "discount", n.Discount, ",")
 	jsonEncodeFloat64(buffer, "cpuCost", n.CPUCost, ",")
 	jsonEncodeFloat64(buffer, "cpuCost", n.CPUCost, ",")
 	jsonEncodeFloat64(buffer, "gpuCost", n.GPUCost, ",")
 	jsonEncodeFloat64(buffer, "gpuCost", n.GPUCost, ",")
-	jsonEncodeFloat64(buffer, "gpuCount", n.GPUCount, ",")
+	jsonEncodeFloat64(buffer, "gpuCount", n.GPUs(), ",")
 	jsonEncodeFloat64(buffer, "ramCost", n.RAMCost, ",")
 	jsonEncodeFloat64(buffer, "ramCost", n.RAMCost, ",")
 	jsonEncodeFloat64(buffer, "adjustment", n.Adjustment(), ",")
 	jsonEncodeFloat64(buffer, "adjustment", n.Adjustment(), ",")
 	jsonEncodeFloat64(buffer, "totalCost", n.TotalCost(), "")
 	jsonEncodeFloat64(buffer, "totalCost", n.TotalCost(), "")
@@ -2047,15 +2054,30 @@ func (n *Node) CPUCores() float64 {
 // and a 16GiB-RAM node running for the last 20 hours of the same 24-hour window
 // and a 16GiB-RAM node running for the last 20 hours of the same 24-hour window
 // would produce:
 // would produce:
 //   (12*10 + 16*20) / 24 = 18.333GiB RAM
 //   (12*10 + 16*20) / 24 = 18.333GiB RAM
-// However, any number of cores running for the full span of a window will
-// report the actual number of cores of the static node; e.g. the above
+// However, any number of bytes running for the full span of a window will
+// report the actual number of bytes of the static node; e.g. the above
 // scenario for one entire 24-hour window:
 // scenario for one entire 24-hour window:
-//   (12*24 + 16*24) / 24 = (12 + 16) = 28 cores
+//   (12*24 + 16*24) / 24 = (12 + 16) = 28GiB RAM
 func (n *Node) RAMBytes() float64 {
 func (n *Node) RAMBytes() float64 {
 	// [b*hr]*([min/hr]*[1/min]) = [b*hr]/[hr] = b
 	// [b*hr]*([min/hr]*[1/min]) = [b*hr]/[hr] = b
 	return n.RAMByteHours * (60.0 / n.Minutes())
 	return n.RAMByteHours * (60.0 / n.Minutes())
 }
 }
 
 
+// GPUs returns the amount of GPUs belonging to the node. This could be
+// fractional because it's the number of gpu*hours divided by the number of
+// hours running; e.g. the sum of a 2 gpu node running for the first 10 hours
+// and a 1 gpu node running for the last 20 hours of the same 24-hour window
+// would produce:
+//   (2*10 + 1*20) / 24 = 1.667 GPUs
+// However, any number of GPUs running for the full span of a window will
+// report the actual number of GPUs of the static node; e.g. the above
+// scenario for one entire 24-hour window:
+//   (2*24 + 1*24) / 24 = (2 + 1) = 3 GPUs
+func (n *Node) GPUs() float64 {
+	// [b*hr]*([min/hr]*[1/min]) = [b*hr]/[hr] = b
+	return n.GPUHours * (60.0 / n.Minutes())
+}
+
 // LoadBalancer is an Asset representing a single load balancer in a cluster
 // LoadBalancer is an Asset representing a single load balancer in a cluster
 // TODO: add GB of ingress processed, numForwardingRules once we start recording those to prometheus metric
 // TODO: add GB of ingress processed, numForwardingRules once we start recording those to prometheus metric
 type LoadBalancer struct {
 type LoadBalancer struct {

+ 16 - 0
pkg/kubecost/asset_test.go

@@ -65,6 +65,7 @@ func generateAssetSet(start time.Time) *AssetSet {
 	node1.Discount = 0.5
 	node1.Discount = 0.5
 	node1.CPUCoreHours = 2.0 * hours
 	node1.CPUCoreHours = 2.0 * hours
 	node1.RAMByteHours = 4.0 * gb * hours
 	node1.RAMByteHours = 4.0 * gb * hours
+	node1.GPUHours = 1.0 * hours
 	node1.SetAdjustment(1.0)
 	node1.SetAdjustment(1.0)
 	node1.SetLabels(map[string]string{"test": "test"})
 	node1.SetLabels(map[string]string{"test": "test"})
 
 
@@ -75,6 +76,7 @@ func generateAssetSet(start time.Time) *AssetSet {
 	node2.Discount = 0.5
 	node2.Discount = 0.5
 	node2.CPUCoreHours = 2.0 * hours
 	node2.CPUCoreHours = 2.0 * hours
 	node2.RAMByteHours = 4.0 * gb * hours
 	node2.RAMByteHours = 4.0 * gb * hours
+	node2.GPUHours = 0.0 * hours
 	node2.SetAdjustment(1.5)
 	node2.SetAdjustment(1.5)
 
 
 	node3 := NewNode("node3", "cluster1", "gcp-node3", *window.Clone().start, *window.Clone().end, window.Clone())
 	node3 := NewNode("node3", "cluster1", "gcp-node3", *window.Clone().start, *window.Clone().end, window.Clone())
@@ -84,6 +86,7 @@ func generateAssetSet(start time.Time) *AssetSet {
 	node3.Discount = 0.5
 	node3.Discount = 0.5
 	node3.CPUCoreHours = 2.0 * hours
 	node3.CPUCoreHours = 2.0 * hours
 	node3.RAMByteHours = 4.0 * gb * hours
 	node3.RAMByteHours = 4.0 * gb * hours
+	node3.GPUHours = 2.0 * hours
 	node3.SetAdjustment(-0.5)
 	node3.SetAdjustment(-0.5)
 
 
 	node4 := NewNode("node4", "cluster2", "gcp-node4", *window.Clone().start, *window.Clone().end, window.Clone())
 	node4 := NewNode("node4", "cluster2", "gcp-node4", *window.Clone().start, *window.Clone().end, window.Clone())
@@ -93,6 +96,7 @@ func generateAssetSet(start time.Time) *AssetSet {
 	node4.Discount = 0.25
 	node4.Discount = 0.25
 	node4.CPUCoreHours = 4.0 * hours
 	node4.CPUCoreHours = 4.0 * hours
 	node4.RAMByteHours = 12.0 * gb * hours
 	node4.RAMByteHours = 12.0 * gb * hours
+	node4.GPUHours = 0.0 * hours
 	node4.SetAdjustment(-1.0)
 	node4.SetAdjustment(-1.0)
 
 
 	node5 := NewNode("node5", "cluster3", "aws-node5", *window.Clone().start, *window.Clone().end, window.Clone())
 	node5 := NewNode("node5", "cluster3", "aws-node5", *window.Clone().start, *window.Clone().end, window.Clone())
@@ -102,6 +106,7 @@ func generateAssetSet(start time.Time) *AssetSet {
 	node5.Discount = 0.0
 	node5.Discount = 0.0
 	node5.CPUCoreHours = 8.0 * hours
 	node5.CPUCoreHours = 8.0 * hours
 	node5.RAMByteHours = 24.0 * gb * hours
 	node5.RAMByteHours = 24.0 * gb * hours
+	node5.GPUHours = 0.0 * hours
 	node5.SetAdjustment(2.0)
 	node5.SetAdjustment(2.0)
 
 
 	disk1 := NewDisk("disk1", "cluster1", "gcp-disk1", *window.Clone().start, *window.Clone().end, window.Clone())
 	disk1 := NewDisk("disk1", "cluster1", "gcp-disk1", *window.Clone().start, *window.Clone().end, window.Clone())
@@ -481,6 +486,7 @@ func TestNode_Add(t *testing.T) {
 	node1 := NewNode("node1", "cluster1", "node1", *windows[0].start, *windows[0].end, windows[0])
 	node1 := NewNode("node1", "cluster1", "node1", *windows[0].start, *windows[0].end, windows[0])
 	node1.CPUCoreHours = 1.0 * hours
 	node1.CPUCoreHours = 1.0 * hours
 	node1.RAMByteHours = 2.0 * gb * hours
 	node1.RAMByteHours = 2.0 * gb * hours
+	node1.GPUHours = 0.0 * hours
 	node1.GPUCost = 0.0
 	node1.GPUCost = 0.0
 	node1.CPUCost = 8.0
 	node1.CPUCost = 8.0
 	node1.RAMCost = 4.0
 	node1.RAMCost = 4.0
@@ -502,6 +508,7 @@ func TestNode_Add(t *testing.T) {
 	node2 := NewNode("node2", "cluster1", "node2", *windows[0].start, *windows[0].end, windows[0])
 	node2 := NewNode("node2", "cluster1", "node2", *windows[0].start, *windows[0].end, windows[0])
 	node2.CPUCoreHours = 1.0 * hours
 	node2.CPUCoreHours = 1.0 * hours
 	node2.RAMByteHours = 2.0 * gb * hours
 	node2.RAMByteHours = 2.0 * gb * hours
+	node2.GPUHours = 0.0 * hours
 	node2.GPUCost = 0.0
 	node2.GPUCost = 0.0
 	node2.CPUCost = 3.0
 	node2.CPUCost = 3.0
 	node2.RAMCost = 1.0
 	node2.RAMCost = 1.0
@@ -566,6 +573,7 @@ func TestNode_Add(t *testing.T) {
 	node3 := NewNode("node3", "cluster1", "node3", *windows[0].start, *windows[0].end, windows[0])
 	node3 := NewNode("node3", "cluster1", "node3", *windows[0].start, *windows[0].end, windows[0])
 	node3.CPUCoreHours = 0 * hours
 	node3.CPUCoreHours = 0 * hours
 	node3.RAMByteHours = 0 * hours
 	node3.RAMByteHours = 0 * hours
+	node3.GPUHours = 0.0 * hours
 	node3.GPUCost = 0
 	node3.GPUCost = 0
 	node3.CPUCost = 0.0
 	node3.CPUCost = 0.0
 	node3.RAMCost = 0.0
 	node3.RAMCost = 0.0
@@ -575,6 +583,7 @@ func TestNode_Add(t *testing.T) {
 	node4 := NewNode("node4", "cluster1", "node4", *windows[0].start, *windows[0].end, windows[0])
 	node4 := NewNode("node4", "cluster1", "node4", *windows[0].start, *windows[0].end, windows[0])
 	node4.CPUCoreHours = 0 * hours
 	node4.CPUCoreHours = 0 * hours
 	node4.RAMByteHours = 0 * hours
 	node4.RAMByteHours = 0 * hours
+	node4.GPUHours = 0.0 * hours
 	node4.GPUCost = 0
 	node4.GPUCost = 0
 	node4.CPUCost = 0.0
 	node4.CPUCost = 0.0
 	node4.RAMCost = 0.0
 	node4.RAMCost = 0.0
@@ -595,6 +604,7 @@ func TestNode_Add(t *testing.T) {
 	nodeA1 := NewNode("nodeA1", "cluster1", "nodeA1", *windows[0].start, *windows[0].end, windows[0])
 	nodeA1 := NewNode("nodeA1", "cluster1", "nodeA1", *windows[0].start, *windows[0].end, windows[0])
 	nodeA1.CPUCoreHours = 1.0 * hours
 	nodeA1.CPUCoreHours = 1.0 * hours
 	nodeA1.RAMByteHours = 2.0 * gb * hours
 	nodeA1.RAMByteHours = 2.0 * gb * hours
+	nodeA1.GPUHours = 0.0 * hours
 	nodeA1.GPUCost = 0.0
 	nodeA1.GPUCost = 0.0
 	nodeA1.CPUCost = 8.0
 	nodeA1.CPUCost = 8.0
 	nodeA1.RAMCost = 4.0
 	nodeA1.RAMCost = 4.0
@@ -604,6 +614,7 @@ func TestNode_Add(t *testing.T) {
 	nodeA2 := NewNode("nodeA2", "cluster1", "nodeA2", *windows[1].start, *windows[1].end, windows[1])
 	nodeA2 := NewNode("nodeA2", "cluster1", "nodeA2", *windows[1].start, *windows[1].end, windows[1])
 	nodeA2.CPUCoreHours = 1.0 * hours
 	nodeA2.CPUCoreHours = 1.0 * hours
 	nodeA2.RAMByteHours = 2.0 * gb * hours
 	nodeA2.RAMByteHours = 2.0 * gb * hours
+	nodeA2.GPUHours = 0.0 * hours
 	nodeA2.GPUCost = 0.0
 	nodeA2.GPUCost = 0.0
 	nodeA2.CPUCost = 3.0
 	nodeA2.CPUCost = 3.0
 	nodeA2.RAMCost = 1.0
 	nodeA2.RAMCost = 1.0
@@ -637,6 +648,9 @@ func TestNode_Add(t *testing.T) {
 	if nodeAT.RAMBytes() != 2.0*gb {
 	if nodeAT.RAMBytes() != 2.0*gb {
 		t.Fatalf("Node.Add: expected %f; got %f", 2.0*gb, nodeAT.RAMBytes())
 		t.Fatalf("Node.Add: expected %f; got %f", 2.0*gb, nodeAT.RAMBytes())
 	}
 	}
+	if nodeAT.GPUs() != 0.0 {
+		t.Fatalf("Node.Add: expected %f; got %f", 0.0, nodeAT.GPUs())
+	}
 
 
 	// Check that the original assets are unchanged
 	// Check that the original assets are unchanged
 	if !util.IsApproximately(nodeA1.TotalCost(), 10.0) {
 	if !util.IsApproximately(nodeA1.TotalCost(), 10.0) {
@@ -664,8 +678,10 @@ func TestNode_MarshalJSON(t *testing.T) {
 	})
 	})
 	node.CPUCost = 9.0
 	node.CPUCost = 9.0
 	node.RAMCost = 0.0
 	node.RAMCost = 0.0
+	node.RAMCost = 21.0
 	node.CPUCoreHours = 123.0
 	node.CPUCoreHours = 123.0
 	node.RAMByteHours = 13323.0
 	node.RAMByteHours = 13323.0
+	node.GPUHours = 123.0
 	node.SetAdjustment(1.0)
 	node.SetAdjustment(1.0)
 
 
 	_, err := json.Marshal(node)
 	_, err := json.Marshal(node)

+ 1 - 1
pkg/kubecost/bingen.go

@@ -26,4 +26,4 @@ package kubecost
 // @bingen:generate:AllocationAnnotations
 // @bingen:generate:AllocationAnnotations
 // @bingen:generate:RawAllocationOnlyData
 // @bingen:generate:RawAllocationOnlyData
 
 
-//go:generate bingen -package=kubecost -version=11 -buffer=github.com/kubecost/cost-model/pkg/util
+//go:generate bingen -package=kubecost -version=12 -buffer=github.com/kubecost/cost-model/pkg/util

+ 52 - 36
pkg/kubecost/kubecost_codecs.go

@@ -25,7 +25,7 @@ const (
 	GeneratorPackageName string = "kubecost"
 	GeneratorPackageName string = "kubecost"
 
 
 	// CodecVersion is the version passed into the generator
 	// CodecVersion is the version passed into the generator
-	CodecVersion uint8 = 11
+	CodecVersion uint8 = 12
 )
 )
 
 
 //--------------------------------------------------------------------------
 //--------------------------------------------------------------------------
@@ -164,8 +164,10 @@ func (target *Allocation) MarshalBinary() (data []byte, err error) {
 	buff.WriteFloat64(target.CPUCoreRequestAverage)  // write float64
 	buff.WriteFloat64(target.CPUCoreRequestAverage)  // write float64
 	buff.WriteFloat64(target.CPUCoreUsageAverage)    // write float64
 	buff.WriteFloat64(target.CPUCoreUsageAverage)    // write float64
 	buff.WriteFloat64(target.CPUCost)                // write float64
 	buff.WriteFloat64(target.CPUCost)                // write float64
+	buff.WriteFloat64(target.CPUCostAdjustment)      // write float64
 	buff.WriteFloat64(target.GPUHours)               // write float64
 	buff.WriteFloat64(target.GPUHours)               // write float64
 	buff.WriteFloat64(target.GPUCost)                // write float64
 	buff.WriteFloat64(target.GPUCost)                // write float64
+	buff.WriteFloat64(target.GPUCostAdjustment)      // write float64
 	buff.WriteFloat64(target.NetworkCost)            // write float64
 	buff.WriteFloat64(target.NetworkCost)            // write float64
 	buff.WriteFloat64(target.LoadBalancerCost)       // write float64
 	buff.WriteFloat64(target.LoadBalancerCost)       // write float64
 	buff.WriteFloat64(target.PVByteHours)            // write float64
 	buff.WriteFloat64(target.PVByteHours)            // write float64
@@ -174,6 +176,7 @@ func (target *Allocation) MarshalBinary() (data []byte, err error) {
 	buff.WriteFloat64(target.RAMBytesRequestAverage) // write float64
 	buff.WriteFloat64(target.RAMBytesRequestAverage) // write float64
 	buff.WriteFloat64(target.RAMBytesUsageAverage)   // write float64
 	buff.WriteFloat64(target.RAMBytesUsageAverage)   // write float64
 	buff.WriteFloat64(target.RAMCost)                // write float64
 	buff.WriteFloat64(target.RAMCost)                // write float64
+	buff.WriteFloat64(target.RAMCostAdjustment)      // write float64
 	buff.WriteFloat64(target.SharedCost)             // write float64
 	buff.WriteFloat64(target.SharedCost)             // write float64
 	buff.WriteFloat64(target.ExternalCost)           // write float64
 	buff.WriteFloat64(target.ExternalCost)           // write float64
 	if target.RawAllocationOnly == nil {
 	if target.RawAllocationOnly == nil {
@@ -282,53 +285,62 @@ func (target *Allocation) UnmarshalBinary(data []byte) (err error) {
 	target.CPUCost = s
 	target.CPUCost = s
 
 
 	t := buff.ReadFloat64() // read float64
 	t := buff.ReadFloat64() // read float64
-	target.GPUHours = t
+	target.CPUCostAdjustment = t
 
 
 	u := buff.ReadFloat64() // read float64
 	u := buff.ReadFloat64() // read float64
-	target.GPUCost = u
+	target.GPUHours = u
 
 
 	w := buff.ReadFloat64() // read float64
 	w := buff.ReadFloat64() // read float64
-	target.NetworkCost = w
+	target.GPUCost = w
 
 
 	x := buff.ReadFloat64() // read float64
 	x := buff.ReadFloat64() // read float64
-	target.LoadBalancerCost = x
+	target.GPUCostAdjustment = x
 
 
 	y := buff.ReadFloat64() // read float64
 	y := buff.ReadFloat64() // read float64
-	target.PVByteHours = y
+	target.NetworkCost = y
 
 
 	aa := buff.ReadFloat64() // read float64
 	aa := buff.ReadFloat64() // read float64
-	target.PVCost = aa
+	target.LoadBalancerCost = aa
 
 
 	bb := buff.ReadFloat64() // read float64
 	bb := buff.ReadFloat64() // read float64
-	target.RAMByteHours = bb
+	target.PVByteHours = bb
 
 
 	cc := buff.ReadFloat64() // read float64
 	cc := buff.ReadFloat64() // read float64
-	target.RAMBytesRequestAverage = cc
+	target.PVCost = cc
 
 
 	dd := buff.ReadFloat64() // read float64
 	dd := buff.ReadFloat64() // read float64
-	target.RAMBytesUsageAverage = dd
+	target.RAMByteHours = dd
 
 
 	ee := buff.ReadFloat64() // read float64
 	ee := buff.ReadFloat64() // read float64
-	target.RAMCost = ee
+	target.RAMBytesRequestAverage = ee
 
 
 	ff := buff.ReadFloat64() // read float64
 	ff := buff.ReadFloat64() // read float64
-	target.SharedCost = ff
+	target.RAMBytesUsageAverage = ff
 
 
 	gg := buff.ReadFloat64() // read float64
 	gg := buff.ReadFloat64() // read float64
-	target.ExternalCost = gg
+	target.RAMCost = gg
+
+	hh := buff.ReadFloat64() // read float64
+	target.RAMCostAdjustment = hh
+
+	kk := buff.ReadFloat64() // read float64
+	target.SharedCost = kk
+
+	ll := buff.ReadFloat64() // read float64
+	target.ExternalCost = ll
 
 
 	if buff.ReadUInt8() == uint8(0) {
 	if buff.ReadUInt8() == uint8(0) {
 		target.RawAllocationOnly = nil
 		target.RawAllocationOnly = nil
 	} else {
 	} else {
 		// --- [begin][read][struct](RawAllocationOnlyData) ---
 		// --- [begin][read][struct](RawAllocationOnlyData) ---
-		hh := &RawAllocationOnlyData{}
-		kk := buff.ReadInt()     // byte array length
-		ll := buff.ReadBytes(kk) // byte array
-		errE := hh.UnmarshalBinary(ll)
+		mm := &RawAllocationOnlyData{}
+		nn := buff.ReadInt()     // byte array length
+		oo := buff.ReadBytes(nn) // byte array
+		errE := mm.UnmarshalBinary(oo)
 		if errE != nil {
 		if errE != nil {
 			return errE
 			return errE
 		}
 		}
-		target.RawAllocationOnly = hh
+		target.RawAllocationOnly = mm
 		// --- [end][read][struct](RawAllocationOnlyData) ---
 		// --- [end][read][struct](RawAllocationOnlyData) ---
 
 
 	}
 	}
@@ -2658,6 +2670,7 @@ func (target *Node) MarshalBinary() (data []byte, err error) {
 	buff.WriteString(target.NodeType)      // write string
 	buff.WriteString(target.NodeType)      // write string
 	buff.WriteFloat64(target.CPUCoreHours) // write float64
 	buff.WriteFloat64(target.CPUCoreHours) // write float64
 	buff.WriteFloat64(target.RAMByteHours) // write float64
 	buff.WriteFloat64(target.RAMByteHours) // write float64
+	buff.WriteFloat64(target.GPUHours)     // write float64
 	if target.CPUBreakdown == nil {
 	if target.CPUBreakdown == nil {
 		buff.WriteUInt8(uint8(0)) // write nil byte
 		buff.WriteUInt8(uint8(0)) // write nil byte
 	} else {
 	} else {
@@ -2807,18 +2820,21 @@ func (target *Node) UnmarshalBinary(data []byte) (err error) {
 	x := buff.ReadFloat64() // read float64
 	x := buff.ReadFloat64() // read float64
 	target.RAMByteHours = x
 	target.RAMByteHours = x
 
 
+	y := buff.ReadFloat64() // read float64
+	target.GPUHours = y
+
 	if buff.ReadUInt8() == uint8(0) {
 	if buff.ReadUInt8() == uint8(0) {
 		target.CPUBreakdown = nil
 		target.CPUBreakdown = nil
 	} else {
 	} else {
 		// --- [begin][read][struct](Breakdown) ---
 		// --- [begin][read][struct](Breakdown) ---
-		y := &Breakdown{}
-		aa := buff.ReadInt()     // byte array length
-		bb := buff.ReadBytes(aa) // byte array
-		errE := y.UnmarshalBinary(bb)
+		aa := &Breakdown{}
+		bb := buff.ReadInt()     // byte array length
+		cc := buff.ReadBytes(bb) // byte array
+		errE := aa.UnmarshalBinary(cc)
 		if errE != nil {
 		if errE != nil {
 			return errE
 			return errE
 		}
 		}
-		target.CPUBreakdown = y
+		target.CPUBreakdown = aa
 		// --- [end][read][struct](Breakdown) ---
 		// --- [end][read][struct](Breakdown) ---
 
 
 	}
 	}
@@ -2826,34 +2842,34 @@ func (target *Node) UnmarshalBinary(data []byte) (err error) {
 		target.RAMBreakdown = nil
 		target.RAMBreakdown = nil
 	} else {
 	} else {
 		// --- [begin][read][struct](Breakdown) ---
 		// --- [begin][read][struct](Breakdown) ---
-		cc := &Breakdown{}
-		dd := buff.ReadInt()     // byte array length
-		ee := buff.ReadBytes(dd) // byte array
-		errF := cc.UnmarshalBinary(ee)
+		dd := &Breakdown{}
+		ee := buff.ReadInt()     // byte array length
+		ff := buff.ReadBytes(ee) // byte array
+		errF := dd.UnmarshalBinary(ff)
 		if errF != nil {
 		if errF != nil {
 			return errF
 			return errF
 		}
 		}
-		target.RAMBreakdown = cc
+		target.RAMBreakdown = dd
 		// --- [end][read][struct](Breakdown) ---
 		// --- [end][read][struct](Breakdown) ---
 
 
 	}
 	}
-	ff := buff.ReadFloat64() // read float64
-	target.CPUCost = ff
-
 	gg := buff.ReadFloat64() // read float64
 	gg := buff.ReadFloat64() // read float64
-	target.GPUCost = gg
+	target.CPUCost = gg
 
 
 	hh := buff.ReadFloat64() // read float64
 	hh := buff.ReadFloat64() // read float64
-	target.GPUCount = hh
+	target.GPUCost = hh
 
 
 	kk := buff.ReadFloat64() // read float64
 	kk := buff.ReadFloat64() // read float64
-	target.RAMCost = kk
+	target.GPUCount = kk
 
 
 	ll := buff.ReadFloat64() // read float64
 	ll := buff.ReadFloat64() // read float64
-	target.Discount = ll
+	target.RAMCost = ll
 
 
 	mm := buff.ReadFloat64() // read float64
 	mm := buff.ReadFloat64() // read float64
-	target.Preemptible = mm
+	target.Discount = mm
+
+	nn := buff.ReadFloat64() // read float64
+	target.Preemptible = nn
 
 
 	return nil
 	return nil
 }
 }