Pārlūkot izejas kodu

Merge branch 'develop' into justfile

Matt Ray 2 gadi atpakaļ
vecāks
revīzija
2164aa6bc9

+ 2 - 2
.github/workflows/build-test.yaml

@@ -29,7 +29,7 @@ jobs:
 
 
       # Saves us from having to redownload all modules
       # Saves us from having to redownload all modules
       - name: Go Mod cache
       - name: Go Mod cache
-        uses: actions/cache@v3
+        uses: actions/cache@v4
         with:
         with:
           path: |
           path: |
             ~/.cache/go-build
             ~/.cache/go-build
@@ -86,7 +86,7 @@ jobs:
         shell: bash
         shell: bash
         run: echo "dir=$(npm config get cache)" >> ${GITHUB_OUTPUT}
         run: echo "dir=$(npm config get cache)" >> ${GITHUB_OUTPUT}
 
 
-      - uses: actions/cache@v3
+      - uses: actions/cache@v4
         id: npm-cache # use this to check for `cache-hit` ==> if: steps.npm-cache.outputs.cache-hit != 'true'
         id: npm-cache # use this to check for `cache-hit` ==> if: steps.npm-cache.outputs.cache-hit != 'true'
         with:
         with:
           path: ${{ steps.npm-cache-dir.outputs.dir }}
           path: ${{ steps.npm-cache-dir.outputs.dir }}

+ 3 - 0
README.md

@@ -1,3 +1,6 @@
+[![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0)
+[![OpenSSF Best Practices](https://www.bestpractices.dev/projects/6219/badge)](https://www.bestpractices.dev/projects/6219)
+
 <img src="./opencost-header.png"/>
 <img src="./opencost-header.png"/>
 
 
 # OpenCost — your favorite open source cost monitoring tool for Kubernetes and cloud spend
 # OpenCost — your favorite open source cost monitoring tool for Kubernetes and cloud spend

+ 8 - 8
core/pkg/filter/allocation/parser.go

@@ -26,16 +26,16 @@ var allocationFilterFields []*ast.Field = []*ast.Field{
 // fieldMap is a lazily loaded mapping from AllocationField to ast.Field
 // fieldMap is a lazily loaded mapping from AllocationField to ast.Field
 var fieldMap map[AllocationField]*ast.Field
 var fieldMap map[AllocationField]*ast.Field
 
 
-// DefaultFieldByName returns only default allocation filter fields by name.
-func DefaultFieldByName(field AllocationField) *ast.Field {
-	if fieldMap == nil {
-		fieldMap = make(map[AllocationField]*ast.Field, len(allocationFilterFields))
-		for _, f := range allocationFilterFields {
-			ff := *f
-			fieldMap[AllocationField(ff.Name)] = &ff
-		}
+func init() {
+	fieldMap = make(map[AllocationField]*ast.Field, len(allocationFilterFields))
+	for _, f := range allocationFilterFields {
+		ff := *f
+		fieldMap[AllocationField(ff.Name)] = &ff
 	}
 	}
+}
 
 
+// DefaultFieldByName returns only default allocation filter fields by name.
+func DefaultFieldByName(field AllocationField) *ast.Field {
 	if af, ok := fieldMap[field]; ok {
 	if af, ok := fieldMap[field]; ok {
 		afcopy := *af
 		afcopy := *af
 		return &afcopy
 		return &afcopy

+ 8 - 8
core/pkg/filter/asset/parser.go

@@ -25,16 +25,16 @@ var assetFilterFields []*ast.Field = []*ast.Field{
 // fieldMap is a lazily loaded mapping from AllocationField to ast.Field
 // fieldMap is a lazily loaded mapping from AllocationField to ast.Field
 var fieldMap map[AssetField]*ast.Field
 var fieldMap map[AssetField]*ast.Field
 
 
-// DefaultFieldByName returns only default allocation filter fields by name.
-func DefaultFieldByName(field AssetField) *ast.Field {
-	if fieldMap == nil {
-		fieldMap = make(map[AssetField]*ast.Field, len(assetFilterFields))
-		for _, f := range assetFilterFields {
-			ff := *f
-			fieldMap[AssetField(ff.Name)] = &ff
-		}
+func init() {
+	fieldMap = make(map[AssetField]*ast.Field, len(assetFilterFields))
+	for _, f := range assetFilterFields {
+		ff := *f
+		fieldMap[AssetField(ff.Name)] = &ff
 	}
 	}
+}
 
 
+// DefaultFieldByName returns only default allocation filter fields by name.
+func DefaultFieldByName(field AssetField) *ast.Field {
 	if af, ok := fieldMap[field]; ok {
 	if af, ok := fieldMap[field]; ok {
 		afcopy := *af
 		afcopy := *af
 		return &afcopy
 		return &afcopy

+ 8 - 8
core/pkg/filter/cloudcost/parser.go

@@ -17,16 +17,16 @@ var cloudCostFilterFields []*ast.Field = []*ast.Field{
 // fieldMap is a lazily loaded mapping from CloudAggregationField to ast.Field
 // fieldMap is a lazily loaded mapping from CloudAggregationField to ast.Field
 var fieldMap map[CloudCostField]*ast.Field
 var fieldMap map[CloudCostField]*ast.Field
 
 
-// DefaultFieldByName returns only default cloud cost filter fields by name.
-func DefaultFieldByName(field CloudCostField) *ast.Field {
-	if fieldMap == nil {
-		fieldMap = make(map[CloudCostField]*ast.Field, len(cloudCostFilterFields))
-		for _, f := range cloudCostFilterFields {
-			ff := *f
-			fieldMap[CloudCostField(ff.Name)] = &ff
-		}
+func init() {
+	fieldMap = make(map[CloudCostField]*ast.Field, len(cloudCostFilterFields))
+	for _, f := range cloudCostFilterFields {
+		ff := *f
+		fieldMap[CloudCostField(ff.Name)] = &ff
 	}
 	}
+}
 
 
+// DefaultFieldByName returns only default cloud cost filter fields by name.
+func DefaultFieldByName(field CloudCostField) *ast.Field {
 	if af, ok := fieldMap[field]; ok {
 	if af, ok := fieldMap[field]; ok {
 		afcopy := *af
 		afcopy := *af
 		return &afcopy
 		return &afcopy

+ 9 - 1
core/pkg/opencost/allocation.go

@@ -115,6 +115,7 @@ func (orig LbAllocations) Clone() LbAllocations {
 			Cost:    lbAlloc.Cost,
 			Cost:    lbAlloc.Cost,
 			Private: lbAlloc.Private,
 			Private: lbAlloc.Private,
 			Ip:      lbAlloc.Ip,
 			Ip:      lbAlloc.Ip,
+			Hours:   lbAlloc.Hours,
 		}
 		}
 	}
 	}
 	return newAllocs
 	return newAllocs
@@ -124,7 +125,8 @@ type LbAllocation struct {
 	Service string  `json:"service"`
 	Service string  `json:"service"`
 	Cost    float64 `json:"cost"`
 	Cost    float64 `json:"cost"`
 	Private bool    `json:"private"`
 	Private bool    `json:"private"`
-	Ip      string  `json:"ip"` //@bingen:field[version=19]
+	Ip      string  `json:"ip"`    //@bingen:field[version=19]
+	Hours   float64 `json:"hours"` //@bingen:field[version=21]
 }
 }
 
 
 func (lba *LbAllocation) SanitizeNaN() {
 func (lba *LbAllocation) SanitizeNaN() {
@@ -135,6 +137,10 @@ func (lba *LbAllocation) SanitizeNaN() {
 		log.DedupedWarningf(5, "LBAllocation: Unexpected NaN found for Cost service:%s", lba.Service)
 		log.DedupedWarningf(5, "LBAllocation: Unexpected NaN found for Cost service:%s", lba.Service)
 		lba.Cost = 0
 		lba.Cost = 0
 	}
 	}
+	if math.IsNaN(lba.Hours) {
+		log.DedupedWarningf(5, "LBAllocation: Unexpected NaN found for Hours service:%s", lba.Service)
+		lba.Hours = 0
+	}
 }
 }
 
 
 // RawAllocationOnlyData is information that only belong in "raw" Allocations,
 // RawAllocationOnlyData is information that only belong in "raw" Allocations,
@@ -1249,10 +1255,12 @@ func (thisLbAllocs LbAllocations) Add(thatLbAllocs LbAllocations) LbAllocations
 				thisLbAlloc = &LbAllocation{
 				thisLbAlloc = &LbAllocation{
 					Service: thatlbAlloc.Service,
 					Service: thatlbAlloc.Service,
 					Cost:    thatlbAlloc.Cost,
 					Cost:    thatlbAlloc.Cost,
+					Hours:   thatlbAlloc.Hours,
 				}
 				}
 				mergedLbAllocs[lbKey] = thisLbAlloc
 				mergedLbAllocs[lbKey] = thisLbAlloc
 			} else {
 			} else {
 				thisLbAlloc.Cost += thatlbAlloc.Cost
 				thisLbAlloc.Cost += thatlbAlloc.Cost
+				thisLbAlloc.Hours += thatlbAlloc.Hours
 			}
 			}
 
 
 		}
 		}

+ 1 - 1
core/pkg/opencost/bingen.go

@@ -46,7 +46,7 @@ package opencost
 // @bingen:end
 // @bingen:end
 
 
 // Allocation Version Set: Includes Allocation pipeline specific resources
 // Allocation Version Set: Includes Allocation pipeline specific resources
-// @bingen:set[name=Allocation,version=20]
+// @bingen:set[name=Allocation,version=21]
 // @bingen:generate:Allocation
 // @bingen:generate:Allocation
 // @bingen:generate[stringtable]:AllocationSet
 // @bingen:generate[stringtable]:AllocationSet
 // @bingen:generate:AllocationSetRange
 // @bingen:generate:AllocationSetRange

+ 1 - 2
core/pkg/opencost/cloudcostprops.go

@@ -5,7 +5,6 @@ import (
 	"strings"
 	"strings"
 
 
 	"github.com/opencost/opencost/core/pkg/log"
 	"github.com/opencost/opencost/core/pkg/log"
-	"github.com/opencost/opencost/core/pkg/util/promutil"
 )
 )
 
 
 type CloudCostProperty string
 type CloudCostProperty string
@@ -70,7 +69,7 @@ func ParseCloudCostProperty(text string) (CloudCostProperty, error) {
 	}
 	}
 
 
 	if strings.HasPrefix(text, "label:") {
 	if strings.HasPrefix(text, "label:") {
-		label := promutil.SanitizeLabelName(strings.TrimSpace(strings.TrimPrefix(text, "label:")))
+		label := strings.TrimSpace(strings.TrimPrefix(text, "label:"))
 		return CloudCostProperty(fmt.Sprintf("label:%s", label)), nil
 		return CloudCostProperty(fmt.Sprintf("label:%s", label)), nil
 	}
 	}
 
 

+ 11 - 1
core/pkg/opencost/opencost_codecs.go

@@ -41,7 +41,7 @@ const (
 	AssetsCodecVersion uint8 = 21
 	AssetsCodecVersion uint8 = 21
 
 
 	// AllocationCodecVersion is used for any resources listed in the Allocation version set
 	// AllocationCodecVersion is used for any resources listed in the Allocation version set
-	AllocationCodecVersion uint8 = 20
+	AllocationCodecVersion uint8 = 21
 
 
 	// CloudCostCodecVersion is used for any resources listed in the CloudCost version set
 	// CloudCostCodecVersion is used for any resources listed in the CloudCost version set
 	CloudCostCodecVersion uint8 = 2
 	CloudCostCodecVersion uint8 = 2
@@ -5433,6 +5433,7 @@ func (target *LbAllocation) MarshalBinaryWithContext(ctx *EncodingContext) (err
 	} else {
 	} else {
 		buff.WriteString(target.Ip) // write string
 		buff.WriteString(target.Ip) // write string
 	}
 	}
+	buff.WriteFloat64(target.Hours) // write float64
 	return nil
 	return nil
 }
 }
 
 
@@ -5522,6 +5523,15 @@ func (target *LbAllocation) UnmarshalBinaryWithContext(ctx *DecodingContext) (er
 		target.Ip = "" // default
 		target.Ip = "" // default
 	}
 	}
 
 
+	// field version check
+	if uint8(21) <= version {
+		k := buff.ReadFloat64() // read float64
+		target.Hours = k
+
+	} else {
+		target.Hours = float64(0) // default
+	}
+
 	return nil
 	return nil
 }
 }
 
 

+ 10 - 10
go.mod

@@ -20,14 +20,14 @@ require (
 	github.com/Azure/go-autorest/autorest/azure/auth v0.5.11
 	github.com/Azure/go-autorest/autorest/azure/auth v0.5.11
 	github.com/aliyun/alibaba-cloud-sdk-go v1.62.3
 	github.com/aliyun/alibaba-cloud-sdk-go v1.62.3
 	github.com/aws/aws-sdk-go v1.44.153
 	github.com/aws/aws-sdk-go v1.44.153
-	github.com/aws/aws-sdk-go-v2 v1.24.0
-	github.com/aws/aws-sdk-go-v2/config v1.26.1
-	github.com/aws/aws-sdk-go-v2/credentials v1.16.12
+	github.com/aws/aws-sdk-go-v2 v1.23.5
+	github.com/aws/aws-sdk-go-v2/config v1.25.12
+	github.com/aws/aws-sdk-go-v2/credentials v1.16.10
 	github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.9.1
 	github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.9.1
 	github.com/aws/aws-sdk-go-v2/service/athena v1.12.0
 	github.com/aws/aws-sdk-go-v2/service/athena v1.12.0
 	github.com/aws/aws-sdk-go-v2/service/ec2 v1.29.0
 	github.com/aws/aws-sdk-go-v2/service/ec2 v1.29.0
 	github.com/aws/aws-sdk-go-v2/service/s3 v1.31.0
 	github.com/aws/aws-sdk-go-v2/service/s3 v1.31.0
-	github.com/aws/aws-sdk-go-v2/service/sts v1.26.5
+	github.com/aws/aws-sdk-go-v2/service/sts v1.26.3
 	github.com/aws/smithy-go v1.19.0
 	github.com/aws/smithy-go v1.19.0
 	github.com/davecgh/go-spew v1.1.1
 	github.com/davecgh/go-spew v1.1.1
 	github.com/getsentry/sentry-go v0.25.0
 	github.com/getsentry/sentry-go v0.25.0
@@ -83,17 +83,17 @@ require (
 	github.com/apache/arrow/go/v12 v12.0.0 // indirect
 	github.com/apache/arrow/go/v12 v12.0.0 // indirect
 	github.com/apache/thrift v0.16.0 // indirect
 	github.com/apache/thrift v0.16.0 // indirect
 	github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.4.10 // indirect
 	github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.4.10 // indirect
-	github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.14.10 // indirect
-	github.com/aws/aws-sdk-go-v2/internal/configsources v1.2.9 // indirect
-	github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.5.9 // indirect
+	github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.14.9 // indirect
+	github.com/aws/aws-sdk-go-v2/internal/configsources v1.2.8 // indirect
+	github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.5.8 // indirect
 	github.com/aws/aws-sdk-go-v2/internal/ini v1.7.2 // indirect
 	github.com/aws/aws-sdk-go-v2/internal/ini v1.7.2 // indirect
 	github.com/aws/aws-sdk-go-v2/internal/v4a v1.0.23 // indirect
 	github.com/aws/aws-sdk-go-v2/internal/v4a v1.0.23 // indirect
 	github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.10.4 // indirect
 	github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.10.4 // indirect
 	github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.1.26 // indirect
 	github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.1.26 // indirect
-	github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.10.9 // indirect
+	github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.10.8 // indirect
 	github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.14.0 // indirect
 	github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.14.0 // indirect
-	github.com/aws/aws-sdk-go-v2/service/sso v1.18.5 // indirect
-	github.com/aws/aws-sdk-go-v2/service/ssooidc v1.21.5 // indirect
+	github.com/aws/aws-sdk-go-v2/service/sso v1.18.3 // indirect
+	github.com/aws/aws-sdk-go-v2/service/ssooidc v1.21.3 // indirect
 	github.com/aymerick/douceur v0.2.0 // indirect
 	github.com/aymerick/douceur v0.2.0 // indirect
 	github.com/beorn7/perks v1.0.1 // indirect
 	github.com/beorn7/perks v1.0.1 // indirect
 	github.com/cespare/xxhash/v2 v2.2.0 // indirect
 	github.com/cespare/xxhash/v2 v2.2.0 // indirect

+ 20 - 20
go.sum

@@ -119,30 +119,30 @@ github.com/aws/aws-sdk-go v1.44.153 h1:KfN5URb9O/Fk48xHrAinrPV2DzPcLa0cd9yo1ax5K
 github.com/aws/aws-sdk-go v1.44.153/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI=
 github.com/aws/aws-sdk-go v1.44.153/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI=
 github.com/aws/aws-sdk-go-v2 v1.13.0/go.mod h1:L6+ZpqHaLbAaxsqV0L4cvxZY7QupWJB4fhkf8LXvC7w=
 github.com/aws/aws-sdk-go-v2 v1.13.0/go.mod h1:L6+ZpqHaLbAaxsqV0L4cvxZY7QupWJB4fhkf8LXvC7w=
 github.com/aws/aws-sdk-go-v2 v1.17.7/go.mod h1:uzbQtefpm44goOPmdKyAlXSNcwlRgF3ePWVW6EtJvvw=
 github.com/aws/aws-sdk-go-v2 v1.17.7/go.mod h1:uzbQtefpm44goOPmdKyAlXSNcwlRgF3ePWVW6EtJvvw=
-github.com/aws/aws-sdk-go-v2 v1.24.0 h1:890+mqQ+hTpNuw0gGP6/4akolQkSToDJgHfQE7AwGuk=
-github.com/aws/aws-sdk-go-v2 v1.24.0/go.mod h1:LNh45Br1YAkEKaAqvmE1m8FUx6a5b/V0oAKV7of29b4=
+github.com/aws/aws-sdk-go-v2 v1.23.5 h1:xK6C4udTyDMd82RFvNkDQxtAd00xlzFUtX4fF2nMZyg=
+github.com/aws/aws-sdk-go-v2 v1.23.5/go.mod h1:t3szzKfP0NeRU27uBFczDivYJjsmSnqI8kIvKyWb9ds=
 github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.2.0/go.mod h1:oZHzg1OVbuCiRTY0oRPM+c2HQvwnFCGJwKeSqqAJ/yM=
 github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.2.0/go.mod h1:oZHzg1OVbuCiRTY0oRPM+c2HQvwnFCGJwKeSqqAJ/yM=
 github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.4.10 h1:dK82zF6kkPeCo8J1e+tGx4JdvDIQzj7ygIoLg8WMuGs=
 github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.4.10 h1:dK82zF6kkPeCo8J1e+tGx4JdvDIQzj7ygIoLg8WMuGs=
 github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.4.10/go.mod h1:VeTZetY5KRJLuD/7fkQXMU6Mw7H5m/KP2J5Iy9osMno=
 github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.4.10/go.mod h1:VeTZetY5KRJLuD/7fkQXMU6Mw7H5m/KP2J5Iy9osMno=
 github.com/aws/aws-sdk-go-v2/config v1.13.1/go.mod h1:Ba5Z4yL/UGbjQUzsiaN378YobhFo0MLfueXGiOsYtEs=
 github.com/aws/aws-sdk-go-v2/config v1.13.1/go.mod h1:Ba5Z4yL/UGbjQUzsiaN378YobhFo0MLfueXGiOsYtEs=
-github.com/aws/aws-sdk-go-v2/config v1.26.1 h1:z6DqMxclFGL3Zfo+4Q0rLnAZ6yVkzCRxhRMsiRQnD1o=
-github.com/aws/aws-sdk-go-v2/config v1.26.1/go.mod h1:ZB+CuKHRbb5v5F0oJtGdhFTelmrxd4iWO1lf0rQwSAg=
+github.com/aws/aws-sdk-go-v2/config v1.25.12 h1:mF4cMuNh/2G+d19nWnm1vJ/ak0qK6SbqF0KtSX9pxu0=
+github.com/aws/aws-sdk-go-v2/config v1.25.12/go.mod h1:lOvvqtZP9p29GIjOTuA/76HiVk0c/s8qRcFRq2+E2uc=
 github.com/aws/aws-sdk-go-v2/credentials v1.8.0/go.mod h1:gnMo58Vwx3Mu7hj1wpcG8DI0s57c9o42UQ6wgTQT5to=
 github.com/aws/aws-sdk-go-v2/credentials v1.8.0/go.mod h1:gnMo58Vwx3Mu7hj1wpcG8DI0s57c9o42UQ6wgTQT5to=
-github.com/aws/aws-sdk-go-v2/credentials v1.16.12 h1:v/WgB8NxprNvr5inKIiVVrXPuuTegM+K8nncFkr1usU=
-github.com/aws/aws-sdk-go-v2/credentials v1.16.12/go.mod h1:X21k0FjEJe+/pauud82HYiQbEr9jRKY3kXEIQ4hXeTQ=
+github.com/aws/aws-sdk-go-v2/credentials v1.16.10 h1:VmRkuoKaGl2ZDNGkkRQgw80Hxj1Bb9a+bsT5shqlCwo=
+github.com/aws/aws-sdk-go-v2/credentials v1.16.10/go.mod h1:WEn22lpd50buTs/TDqywytW5xQ2zPOMbYipIlqI6xXg=
 github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.10.0/go.mod h1:I6/fHT/fH460v09eg2gVrd8B/IqskhNdpcLH0WNO3QI=
 github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.10.0/go.mod h1:I6/fHT/fH460v09eg2gVrd8B/IqskhNdpcLH0WNO3QI=
-github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.14.10 h1:w98BT5w+ao1/r5sUuiH6JkVzjowOKeOJRHERyy1vh58=
-github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.14.10/go.mod h1:K2WGI7vUvkIv1HoNbfBA1bvIZ+9kL3YVmWxeKuLQsiw=
+github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.14.9 h1:FZVFahMyZle6WcogZCOxo6D/lkDA2lqKIn4/ueUmVXw=
+github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.14.9/go.mod h1:kjq7REMIkxdtcEC9/4BVXjOsNY5isz6jQbEgk6osRTU=
 github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.9.1 h1:oUCLhAKNaXyTqdJyw+KEjDVVBs1V5mCy8YDLMi08LL8=
 github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.9.1 h1:oUCLhAKNaXyTqdJyw+KEjDVVBs1V5mCy8YDLMi08LL8=
 github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.9.1/go.mod h1:pB38jI+AdaPoLAgaL9bwxDdy6rjwO6LIArBZDLjq6zs=
 github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.9.1/go.mod h1:pB38jI+AdaPoLAgaL9bwxDdy6rjwO6LIArBZDLjq6zs=
 github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.4/go.mod h1:XHgQ7Hz2WY2GAn//UXHofLfPXWh+s62MbMOijrg12Lw=
 github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.4/go.mod h1:XHgQ7Hz2WY2GAn//UXHofLfPXWh+s62MbMOijrg12Lw=
 github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.31/go.mod h1:QT0BqUvX1Bh2ABdTGnjqEjvjzrCfIniM9Sc8zn9Yndo=
 github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.31/go.mod h1:QT0BqUvX1Bh2ABdTGnjqEjvjzrCfIniM9Sc8zn9Yndo=
-github.com/aws/aws-sdk-go-v2/internal/configsources v1.2.9 h1:v+HbZaCGmOwnTTVS86Fleq0vPzOd7tnJGbFhP0stNLs=
-github.com/aws/aws-sdk-go-v2/internal/configsources v1.2.9/go.mod h1:Xjqy+Nyj7VDLBtCMkQYOw1QYfAEZCVLrfI0ezve8wd4=
+github.com/aws/aws-sdk-go-v2/internal/configsources v1.2.8 h1:8GVZIR0y6JRIUNSYI1xAMF4HDfV8H/bOsZ/8AD/uY5Q=
+github.com/aws/aws-sdk-go-v2/internal/configsources v1.2.8/go.mod h1:rwBfu0SoUkBUZndVgPZKAD9Y2JigaZtRP68unRiYToQ=
 github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.2.0/go.mod h1:BsCSJHx5DnDXIrOcqB8KN1/B+hXLG/bi4Y6Vjcx/x9E=
 github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.2.0/go.mod h1:BsCSJHx5DnDXIrOcqB8KN1/B+hXLG/bi4Y6Vjcx/x9E=
 github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.25/go.mod h1:zBHOPwhBc3FlQjQJE/D3IfPWiWaQmT06Vq9aNukDo0k=
 github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.25/go.mod h1:zBHOPwhBc3FlQjQJE/D3IfPWiWaQmT06Vq9aNukDo0k=
-github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.5.9 h1:N94sVhRACtXyVcjXxrwK1SKFIJrA9pOJ5yu2eSHnmls=
-github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.5.9/go.mod h1:hqamLz7g1/4EJP+GH5NBhcUMLjW+gKLQabgyz6/7WAU=
+github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.5.8 h1:ZE2ds/qeBkhk3yqYvS3CDCFNvd9ir5hMjlVStLZWrvM=
+github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.5.8/go.mod h1:/lAPPymDYL023+TS6DJmjuL42nxix2AvEvfjqOBRODk=
 github.com/aws/aws-sdk-go-v2/internal/ini v1.3.5/go.mod h1:R3sWUqPcfXSiF/LSFJhjyJmpg9uV6yP2yv3YZZjldVI=
 github.com/aws/aws-sdk-go-v2/internal/ini v1.3.5/go.mod h1:R3sWUqPcfXSiF/LSFJhjyJmpg9uV6yP2yv3YZZjldVI=
 github.com/aws/aws-sdk-go-v2/internal/ini v1.7.2 h1:GrSw8s0Gs/5zZ0SX+gX4zQjRnRsMJDJ2sLur1gRBhEM=
 github.com/aws/aws-sdk-go-v2/internal/ini v1.7.2 h1:GrSw8s0Gs/5zZ0SX+gX4zQjRnRsMJDJ2sLur1gRBhEM=
 github.com/aws/aws-sdk-go-v2/internal/ini v1.7.2/go.mod h1:6fQQgfuGmw8Al/3M2IgIllycxV7ZW7WCdVSqfBeUiCY=
 github.com/aws/aws-sdk-go-v2/internal/ini v1.7.2/go.mod h1:6fQQgfuGmw8Al/3M2IgIllycxV7ZW7WCdVSqfBeUiCY=
@@ -160,8 +160,8 @@ github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.1.26 h1:CeuSeq/8FnYpPt
 github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.1.26/go.mod h1:2UqAAwMUXKeRkAHIlDJqvMVgOWkUi/AUXPk/YIe+Dg4=
 github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.1.26/go.mod h1:2UqAAwMUXKeRkAHIlDJqvMVgOWkUi/AUXPk/YIe+Dg4=
 github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.7.0/go.mod h1:K/qPe6AP2TGYv4l6n7c88zh9jWBDf6nHhvg1fx/EWfU=
 github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.7.0/go.mod h1:K/qPe6AP2TGYv4l6n7c88zh9jWBDf6nHhvg1fx/EWfU=
 github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.25/go.mod h1:/95IA+0lMnzW6XzqYJRpjjsAbKEORVeO0anQqjd2CNU=
 github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.25/go.mod h1:/95IA+0lMnzW6XzqYJRpjjsAbKEORVeO0anQqjd2CNU=
-github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.10.9 h1:Nf2sHxjMJR8CSImIVCONRi4g0Su3J+TSTbS7G0pUeMU=
-github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.10.9/go.mod h1:idky4TER38YIjr2cADF1/ugFMKvZV7p//pVeV5LZbF0=
+github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.10.8 h1:EamsKe+ZjkOQjDdHd86/JCEucjFKQ9T0atWKO4s2Lgs=
+github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.10.8/go.mod h1:Q0vV3/csTpbkfKLI5Sb56cJQTCTtJ0ixdb7P+Wedqiw=
 github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.11.0/go.mod h1:RMlgnt1LbOT2BxJ3cdw+qVz7KL84714LFkWtF6sLI7A=
 github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.11.0/go.mod h1:RMlgnt1LbOT2BxJ3cdw+qVz7KL84714LFkWtF6sLI7A=
 github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.14.0 h1:e2ooMhpYGhDnBfSvIyusvAwX7KexuZaHbQY2Dyei7VU=
 github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.14.0 h1:e2ooMhpYGhDnBfSvIyusvAwX7KexuZaHbQY2Dyei7VU=
 github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.14.0/go.mod h1:bh2E0CXKZsQN+faiKVqC40vfNMAWheoULBCnEgO9K+8=
 github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.14.0/go.mod h1:bh2E0CXKZsQN+faiKVqC40vfNMAWheoULBCnEgO9K+8=
@@ -169,13 +169,13 @@ github.com/aws/aws-sdk-go-v2/service/s3 v1.24.1/go.mod h1:oIUXg/5F0x0gy6nkwEnlxZ
 github.com/aws/aws-sdk-go-v2/service/s3 v1.31.0 h1:B1G2pSPvbAtQjilPq+Y7jLIzCOwKzuVEl+aBBaNG0AQ=
 github.com/aws/aws-sdk-go-v2/service/s3 v1.31.0 h1:B1G2pSPvbAtQjilPq+Y7jLIzCOwKzuVEl+aBBaNG0AQ=
 github.com/aws/aws-sdk-go-v2/service/s3 v1.31.0/go.mod h1:ncltU6n4Nof5uJttDtcNQ537uNuwYqsZZQcpkd2/GUQ=
 github.com/aws/aws-sdk-go-v2/service/s3 v1.31.0/go.mod h1:ncltU6n4Nof5uJttDtcNQ537uNuwYqsZZQcpkd2/GUQ=
 github.com/aws/aws-sdk-go-v2/service/sso v1.9.0/go.mod h1:vCV4glupK3tR7pw7ks7Y4jYRL86VvxS+g5qk04YeWrU=
 github.com/aws/aws-sdk-go-v2/service/sso v1.9.0/go.mod h1:vCV4glupK3tR7pw7ks7Y4jYRL86VvxS+g5qk04YeWrU=
-github.com/aws/aws-sdk-go-v2/service/sso v1.18.5 h1:ldSFWz9tEHAwHNmjx2Cvy1MjP5/L9kNoR0skc6wyOOM=
-github.com/aws/aws-sdk-go-v2/service/sso v1.18.5/go.mod h1:CaFfXLYL376jgbP7VKC96uFcU8Rlavak0UlAwk1Dlhc=
-github.com/aws/aws-sdk-go-v2/service/ssooidc v1.21.5 h1:2k9KmFawS63euAkY4/ixVNsYYwrwnd5fIvgEKkfZFNM=
-github.com/aws/aws-sdk-go-v2/service/ssooidc v1.21.5/go.mod h1:W+nd4wWDVkSUIox9bacmkBP5NMFQeTJ/xqNabpzSR38=
+github.com/aws/aws-sdk-go-v2/service/sso v1.18.3 h1:wKspi1zc2ZVcgZEu3k2Mt4zGKQSoZTftsoUTLsYPcVo=
+github.com/aws/aws-sdk-go-v2/service/sso v1.18.3/go.mod h1:zxk6y1X2KXThESWMS5CrKRvISD8mbIMab6nZrCGxDG0=
+github.com/aws/aws-sdk-go-v2/service/ssooidc v1.21.3 h1:CxAHBS0BWSUqI7qzXHc2ZpTeHaM9JNnWJ9BN6Kmo2CY=
+github.com/aws/aws-sdk-go-v2/service/ssooidc v1.21.3/go.mod h1:7Lt5mjQ8x5rVdKqg+sKKDeuwoszDJIIPmkd8BVsEdS0=
 github.com/aws/aws-sdk-go-v2/service/sts v1.14.0/go.mod h1:u0xMJKDvvfocRjiozsoZglVNXRG19043xzp3r2ivLIk=
 github.com/aws/aws-sdk-go-v2/service/sts v1.14.0/go.mod h1:u0xMJKDvvfocRjiozsoZglVNXRG19043xzp3r2ivLIk=
-github.com/aws/aws-sdk-go-v2/service/sts v1.26.5 h1:5UYvv8JUvllZsRnfrcMQ+hJ9jNICmcgKPAO1CER25Wg=
-github.com/aws/aws-sdk-go-v2/service/sts v1.26.5/go.mod h1:XX5gh4CB7wAs4KhcF46G6C8a2i7eupU19dcAAE+EydU=
+github.com/aws/aws-sdk-go-v2/service/sts v1.26.3 h1:KfREzajmHCSYjCaMRtdLr9boUMA7KPpoPApitPlbNeo=
+github.com/aws/aws-sdk-go-v2/service/sts v1.26.3/go.mod h1:7Ld9eTqocTvJqqJ5K/orbSDwmGcpRdlDiLjz2DO+SL8=
 github.com/aws/smithy-go v1.10.0/go.mod h1:SObp3lf9smib00L/v3U2eAKG8FyQ7iLrJnQiAmR5n+E=
 github.com/aws/smithy-go v1.10.0/go.mod h1:SObp3lf9smib00L/v3U2eAKG8FyQ7iLrJnQiAmR5n+E=
 github.com/aws/smithy-go v1.13.5/go.mod h1:Tg+OJXh4MB2R/uN61Ko2f6hTZwB/ZYGOtib8J3gBHzA=
 github.com/aws/smithy-go v1.13.5/go.mod h1:Tg+OJXh4MB2R/uN61Ko2f6hTZwB/ZYGOtib8J3gBHzA=
 github.com/aws/smithy-go v1.19.0 h1:KWFKQV80DpP3vJrrA9sVAHQ5gc2z8i4EzrLhLlWXcBM=
 github.com/aws/smithy-go v1.19.0 h1:KWFKQV80DpP3vJrrA9sVAHQ5gc2z8i4EzrLhLlWXcBM=

+ 5 - 4
pkg/cloud/aws/provider.go

@@ -1615,9 +1615,10 @@ func (aws *AWS) getAllAddresses() ([]*ec2Types.Address, error) {
 
 
 	// Get volumes from each AWS region
 	// Get volumes from each AWS region
 	for _, r := range regions {
 	for _, r := range regions {
+		region := r // make a copy of r to avoid capturing loop variable
 		// Fetch IP address response and send results and errors to their
 		// Fetch IP address response and send results and errors to their
 		// respective channels
 		// respective channels
-		go func(region string) {
+		go func() {
 			defer wg.Done()
 			defer wg.Done()
 			defer errs.HandlePanic()
 			defer errs.HandlePanic()
 
 
@@ -1628,7 +1629,7 @@ func (aws *AWS) getAllAddresses() ([]*ec2Types.Address, error) {
 				if errors.As(err, &awsErr) {
 				if errors.As(err, &awsErr) {
 					switch awsErr.ErrorCode() {
 					switch awsErr.ErrorCode() {
 					case "AuthFailure", "InvalidClientTokenId", "UnauthorizedOperation":
 					case "AuthFailure", "InvalidClientTokenId", "UnauthorizedOperation":
-						log.DedupedInfof(5, "Unable to get addresses for region %s due to AWS permissions, error message: %s", r, awsErr.ErrorMessage())
+						log.DedupedInfof(5, "Unable to get addresses for region %s due to AWS permissions, error message: %s", region, awsErr.ErrorMessage())
 						return
 						return
 					default:
 					default:
 						errorCh <- err
 						errorCh <- err
@@ -1640,7 +1641,7 @@ func (aws *AWS) getAllAddresses() ([]*ec2Types.Address, error) {
 				}
 				}
 			}
 			}
 			addressCh <- resp
 			addressCh <- resp
-		}(r)
+		}()
 	}
 	}
 
 
 	// Close the result channels after everything has been sent
 	// Close the result channels after everything has been sent
@@ -1742,7 +1743,7 @@ func (aws *AWS) getAllDisks() ([]*ec2Types.Volume, error) {
 				if errors.As(err, &awsErr) {
 				if errors.As(err, &awsErr) {
 					switch awsErr.ErrorCode() {
 					switch awsErr.ErrorCode() {
 					case "AuthFailure", "InvalidClientTokenId", "UnauthorizedOperation":
 					case "AuthFailure", "InvalidClientTokenId", "UnauthorizedOperation":
-						log.DedupedInfof(5, "Unable to get disks for region %s due to AWS permissions, error message: %s", r, awsErr.ErrorMessage())
+						log.DedupedInfof(5, "Unable to get disks for region %s due to AWS permissions, error message: %s", region, awsErr.ErrorMessage())
 						return
 						return
 					default:
 					default:
 						errorCh <- err
 						errorCh <- err

+ 2 - 2
pkg/costmodel/allocation.go

@@ -40,9 +40,9 @@ const (
 	queryFmtPVBytes                     = `avg(avg_over_time(kube_persistentvolume_capacity_bytes{%s}[%s])) by (persistentvolume, %s)`
 	queryFmtPVBytes                     = `avg(avg_over_time(kube_persistentvolume_capacity_bytes{%s}[%s])) by (persistentvolume, %s)`
 	queryFmtPVCostPerGiBHour            = `avg(avg_over_time(pv_hourly_cost{%s}[%s])) by (volumename, %s)`
 	queryFmtPVCostPerGiBHour            = `avg(avg_over_time(pv_hourly_cost{%s}[%s])) by (volumename, %s)`
 	queryFmtPVMeta                      = `avg(avg_over_time(kubecost_pv_info{%s}[%s])) by (%s, persistentvolume, provider_id)`
 	queryFmtPVMeta                      = `avg(avg_over_time(kubecost_pv_info{%s}[%s])) by (%s, persistentvolume, provider_id)`
-	queryFmtNetZoneGiB                  = `sum(increase(kubecost_pod_network_egress_bytes_total{internet="false", sameZone="false", sameRegion="true", %s}[%s])) by (pod_name, namespace, %s) / 1024 / 1024 / 1024`
+	queryFmtNetZoneGiB                  = `sum(increase(kubecost_pod_network_egress_bytes_total{internet="false", same_zone="false", same_region="true", %s}[%s])) by (pod_name, namespace, %s) / 1024 / 1024 / 1024`
 	queryFmtNetZoneCostPerGiB           = `avg(avg_over_time(kubecost_network_zone_egress_cost{%s}[%s])) by (%s)`
 	queryFmtNetZoneCostPerGiB           = `avg(avg_over_time(kubecost_network_zone_egress_cost{%s}[%s])) by (%s)`
-	queryFmtNetRegionGiB                = `sum(increase(kubecost_pod_network_egress_bytes_total{internet="false", sameZone="false", sameRegion="false", %s}[%s])) by (pod_name, namespace, %s) / 1024 / 1024 / 1024`
+	queryFmtNetRegionGiB                = `sum(increase(kubecost_pod_network_egress_bytes_total{internet="false", same_zone="false", same_region="false", %s}[%s])) by (pod_name, namespace, %s) / 1024 / 1024 / 1024`
 	queryFmtNetRegionCostPerGiB         = `avg(avg_over_time(kubecost_network_region_egress_cost{%s}[%s])) by (%s)`
 	queryFmtNetRegionCostPerGiB         = `avg(avg_over_time(kubecost_network_region_egress_cost{%s}[%s])) by (%s)`
 	queryFmtNetInternetGiB              = `sum(increase(kubecost_pod_network_egress_bytes_total{internet="true", %s}[%s])) by (pod_name, namespace, %s) / 1024 / 1024 / 1024`
 	queryFmtNetInternetGiB              = `sum(increase(kubecost_pod_network_egress_bytes_total{internet="true", %s}[%s])) by (pod_name, namespace, %s) / 1024 / 1024 / 1024`
 	queryFmtNetInternetCostPerGiB       = `avg(avg_over_time(kubecost_network_internet_egress_cost{%s}[%s])) by (%s)`
 	queryFmtNetInternetCostPerGiB       = `avg(avg_over_time(kubecost_network_internet_egress_cost{%s}[%s])) by (%s)`

+ 11 - 0
pkg/costmodel/allocation_helpers.go

@@ -1440,18 +1440,29 @@ func applyLoadBalancersToPods(window opencost.Window, podMap map[podKey]*pod, lb
 		}
 		}
 
 
 		for _, alloc := range allocs {
 		for _, alloc := range allocs {
+			// reocord the hours overlapped with the allocation for the load balancer
+			// if there was overlap. Otherwise, record a 0.0.
+			// TODO: Do we really want to include load balancers that have 0 overlap
+			// TODO: hours with the allocation?
+			var hours float64 = 0.0
+			if _, ok := allocHours[alloc]; ok {
+				hours = allocHours[alloc]
+			}
+
 			if alloc.LoadBalancers == nil {
 			if alloc.LoadBalancers == nil {
 				alloc.LoadBalancers = opencost.LbAllocations{}
 				alloc.LoadBalancers = opencost.LbAllocations{}
 			}
 			}
 
 
 			if _, found := alloc.LoadBalancers[sKey.String()]; found {
 			if _, found := alloc.LoadBalancers[sKey.String()]; found {
 				alloc.LoadBalancers[sKey.String()].Cost += alloc.LoadBalancerCost
 				alloc.LoadBalancers[sKey.String()].Cost += alloc.LoadBalancerCost
+				alloc.LoadBalancers[sKey.String()].Hours += hours
 			} else {
 			} else {
 				alloc.LoadBalancers[sKey.String()] = &opencost.LbAllocation{
 				alloc.LoadBalancers[sKey.String()] = &opencost.LbAllocation{
 					Service: sKey.Namespace + "/" + sKey.Service,
 					Service: sKey.Namespace + "/" + sKey.Service,
 					Cost:    alloc.LoadBalancerCost,
 					Cost:    alloc.LoadBalancerCost,
 					Private: lb.Private,
 					Private: lb.Private,
 					Ip:      lb.Ip,
 					Ip:      lb.Ip,
+					Hours:   hours,
 				}
 				}
 			}
 			}
 		}
 		}

+ 10 - 15
pkg/costmodel/costmodel.go

@@ -146,9 +146,8 @@ const (
 	queryRAMRequestsStr = `avg(
 	queryRAMRequestsStr = `avg(
 		label_replace(
 		label_replace(
 			label_replace(
 			label_replace(
-				avg(
-					sum_over_time(kube_pod_container_resource_requests{resource="memory", unit="byte", container!="",container!="POD", node!="", %s}[%s] %s)
-				) by (namespace,container,pod,node,%s) , "container_name","$1","container","(.+)"
+				sum_over_time(kube_pod_container_resource_requests{resource="memory", unit="byte", container!="",container!="POD", node!="", %s}[%s] %s)
+				, "container_name","$1","container","(.+)"
 			), "pod_name","$1","pod","(.+)"
 			), "pod_name","$1","pod","(.+)"
 		)
 		)
 	) by (namespace,container_name,pod_name,node,%s)`
 	) by (namespace,container_name,pod_name,node,%s)`
@@ -164,9 +163,8 @@ const (
 	queryCPURequestsStr = `avg(
 	queryCPURequestsStr = `avg(
 		label_replace(
 		label_replace(
 			label_replace(
 			label_replace(
-				avg(
-					sum_over_time(kube_pod_container_resource_requests{resource="cpu", unit="core", container!="",container!="POD", node!="", %s}[%s] %s)
-				) by (namespace,container,pod,node,%s) , "container_name","$1","container","(.+)"
+				sum_over_time(kube_pod_container_resource_requests{resource="cpu", unit="core", container!="",container!="POD", node!="", %s}[%s] %s)
+				, "container_name","$1","container","(.+)"
 			), "pod_name","$1","pod","(.+)"
 			), "pod_name","$1","pod","(.+)"
 		)
 		)
 	) by (namespace,container_name,pod_name,node,%s)`
 	) by (namespace,container_name,pod_name,node,%s)`
@@ -184,14 +182,11 @@ const (
 	queryGPURequestsStr = `avg(
 	queryGPURequestsStr = `avg(
 		label_replace(
 		label_replace(
 			label_replace(
 			label_replace(
-				avg(
-					sum_over_time(kube_pod_container_resource_requests{resource="nvidia_com_gpu", container!="",container!="POD", node!="", %s}[%s] %s)
-					* %f
-				) by (namespace,container,pod,node,%s) , "container_name","$1","container","(.+)"
+				sum_over_time(kube_pod_container_resource_requests{resource="nvidia_com_gpu", container!="",container!="POD", node!="", %s}[%s] %s), 
+				"container_name","$1","container","(.+)"
 			), "pod_name","$1","pod","(.+)"
 			), "pod_name","$1","pod","(.+)"
 		)
 		)
-	) by (namespace,container_name,pod_name,node,%s)
-	* on (pod_name, namespace, %s) group_left(container) label_replace(avg(avg_over_time(kube_pod_status_phase{phase="Running", %s}[%s] %s)) by (pod,namespace,%s), "pod_name","$1","pod","(.+)")`
+	) by (namespace,container_name,pod_name,node,%s)`
 	queryPVRequestsStr = `avg(avg(kube_persistentvolumeclaim_info{volumename != "", %s}) by (persistentvolumeclaim, storageclass, namespace, volumename, %s, kubernetes_node)
 	queryPVRequestsStr = `avg(avg(kube_persistentvolumeclaim_info{volumename != "", %s}) by (persistentvolumeclaim, storageclass, namespace, volumename, %s, kubernetes_node)
 	*
 	*
 	on (persistentvolumeclaim, namespace, %s, kubernetes_node) group_right(storageclass, volumename)
 	on (persistentvolumeclaim, namespace, %s, kubernetes_node) group_right(storageclass, volumename)
@@ -1740,11 +1735,11 @@ func (cm *CostModel) costDataRange(cli prometheusClient.Client, cp costAnalyzerC
 
 
 	queryRAMAlloc := fmt.Sprintf(queryRAMAllocationByteHours, env.GetPromClusterFilter(), resStr, env.GetPromClusterLabel(), scrapeIntervalSeconds)
 	queryRAMAlloc := fmt.Sprintf(queryRAMAllocationByteHours, env.GetPromClusterFilter(), resStr, env.GetPromClusterLabel(), scrapeIntervalSeconds)
 	queryCPUAlloc := fmt.Sprintf(queryCPUAllocationVCPUHours, env.GetPromClusterFilter(), resStr, env.GetPromClusterLabel(), scrapeIntervalSeconds)
 	queryCPUAlloc := fmt.Sprintf(queryCPUAllocationVCPUHours, env.GetPromClusterFilter(), resStr, env.GetPromClusterLabel(), scrapeIntervalSeconds)
-	queryRAMRequests := fmt.Sprintf(queryRAMRequestsStr, env.GetPromClusterFilter(), resStr, "", env.GetPromClusterLabel(), env.GetPromClusterLabel())
+	queryRAMRequests := fmt.Sprintf(queryRAMRequestsStr, env.GetPromClusterFilter(), resStr, "", env.GetPromClusterLabel())
 	queryRAMUsage := fmt.Sprintf(queryRAMUsageStr, env.GetPromClusterFilter(), resStr, "", env.GetPromClusterLabel())
 	queryRAMUsage := fmt.Sprintf(queryRAMUsageStr, env.GetPromClusterFilter(), resStr, "", env.GetPromClusterLabel())
-	queryCPURequests := fmt.Sprintf(queryCPURequestsStr, env.GetPromClusterFilter(), resStr, "", env.GetPromClusterLabel(), env.GetPromClusterLabel())
+	queryCPURequests := fmt.Sprintf(queryCPURequestsStr, env.GetPromClusterFilter(), resStr, "", env.GetPromClusterLabel())
 	queryCPUUsage := fmt.Sprintf(queryCPUUsageStr, env.GetPromClusterFilter(), resStr, "", env.GetPromClusterLabel())
 	queryCPUUsage := fmt.Sprintf(queryCPUUsageStr, env.GetPromClusterFilter(), resStr, "", env.GetPromClusterLabel())
-	queryGPURequests := fmt.Sprintf(queryGPURequestsStr, env.GetPromClusterFilter(), resStr, "", resolution.Hours(), env.GetPromClusterLabel(), env.GetPromClusterLabel(), env.GetPromClusterLabel(), env.GetPromClusterFilter(), resStr, "", env.GetPromClusterLabel())
+	queryGPURequests := fmt.Sprintf(queryGPURequestsStr, env.GetPromClusterFilter(), resStr, "", env.GetPromClusterLabel())
 	queryPVRequests := fmt.Sprintf(queryPVRequestsStr, env.GetPromClusterFilter(), env.GetPromClusterLabel(), env.GetPromClusterLabel(), env.GetPromClusterFilter(), env.GetPromClusterLabel(), env.GetPromClusterLabel())
 	queryPVRequests := fmt.Sprintf(queryPVRequestsStr, env.GetPromClusterFilter(), env.GetPromClusterLabel(), env.GetPromClusterLabel(), env.GetPromClusterFilter(), env.GetPromClusterLabel(), env.GetPromClusterLabel())
 	queryPVCAllocation := fmt.Sprintf(queryPVCAllocationFmt, env.GetPromClusterFilter(), resStr, env.GetPromClusterLabel(), scrapeIntervalSeconds)
 	queryPVCAllocation := fmt.Sprintf(queryPVCAllocationFmt, env.GetPromClusterFilter(), resStr, env.GetPromClusterLabel(), scrapeIntervalSeconds)
 	queryPVHourlyCost := fmt.Sprintf(queryPVHourlyCostFmt, env.GetPromClusterFilter(), resStr)
 	queryPVHourlyCost := fmt.Sprintf(queryPVHourlyCostFmt, env.GetPromClusterFilter(), resStr)

+ 12 - 2
pkg/costmodel/metrics.go

@@ -345,6 +345,7 @@ func NewCostModelMetricsEmitter(promClient promclient.Client, clusterCache clust
 		EmitPodAnnotations:            env.IsEmitPodAnnotationsMetric(),
 		EmitPodAnnotations:            env.IsEmitPodAnnotationsMetric(),
 		EmitKubeStateMetrics:          env.IsEmitKsmV1Metrics(),
 		EmitKubeStateMetrics:          env.IsEmitKsmV1Metrics(),
 		EmitKubeStateMetricsV1Only:    env.IsEmitKsmV1MetricsOnly(),
 		EmitKubeStateMetricsV1Only:    env.IsEmitKsmV1MetricsOnly(),
+		EmitDeprecatedMetrics:         env.IsEmitDeprecatedMetrics(),
 	})
 	})
 
 
 	metrics.InitOpencostTelemetry(metricsConfig)
 	metrics.InitOpencostTelemetry(metricsConfig)
@@ -619,8 +620,17 @@ func (cmme *CostModelMetricsEmitter) Start() bool {
 				if len(costs.GPUReq) > 0 {
 				if len(costs.GPUReq) > 0 {
 					// allocation here is set to the request because shared GPU usage not yet supported.
 					// allocation here is set to the request because shared GPU usage not yet supported.
 					// if VPGUs, request x (actual/virtual)
 					// if VPGUs, request x (actual/virtual)
-					vgpu, verr := strconv.ParseFloat(nodes[nodeName].VGPU, 64)
-					gpu, err := strconv.ParseFloat(nodes[nodeName].GPU, 64)
+					vgpu := 0.0
+					gpu := 0.0
+					var err, verr error
+					if matchedNode, found := nodes[nodeName]; found {
+						vgpu, verr = strconv.ParseFloat(matchedNode.VGPU, 64)
+						gpu, err = strconv.ParseFloat(matchedNode.GPU, 64)
+					} else {
+						log.Tracef("cost data for node %s had GPUReq, but there was no cost data available for the node", nodeName)
+						log.Trace("defaulting GPU to 0 cost")
+					}
+
 					gpualloc := costs.GPUReq[0].Value
 					gpualloc := costs.GPUReq[0].Value
 					if verr != nil && err != nil && vgpu != 0 {
 					if verr != nil && err != nil && vgpu != 0 {
 						gpualloc = gpualloc * (gpu / vgpu)
 						gpualloc = gpualloc * (gpu / vgpu)

+ 5 - 0
pkg/env/costmodelenv.go

@@ -43,6 +43,7 @@ const (
 
 
 	EmitPodAnnotationsMetricEnvVar       = "EMIT_POD_ANNOTATIONS_METRIC"
 	EmitPodAnnotationsMetricEnvVar       = "EMIT_POD_ANNOTATIONS_METRIC"
 	EmitNamespaceAnnotationsMetricEnvVar = "EMIT_NAMESPACE_ANNOTATIONS_METRIC"
 	EmitNamespaceAnnotationsMetricEnvVar = "EMIT_NAMESPACE_ANNOTATIONS_METRIC"
+	EmitDeprecatedMetrics                = "EMIT_DEPRECATED_METRICS"
 
 
 	EmitKsmV1MetricsEnvVar = "EMIT_KSM_V1_METRICS"
 	EmitKsmV1MetricsEnvVar = "EMIT_KSM_V1_METRICS"
 	EmitKsmV1MetricsOnly   = "EMIT_KSM_V1_METRICS_ONLY"
 	EmitKsmV1MetricsOnly   = "EMIT_KSM_V1_METRICS_ONLY"
@@ -252,6 +253,10 @@ func IsEmitKsmV1MetricsOnly() bool {
 	return env.GetBool(EmitKsmV1MetricsOnly, false)
 	return env.GetBool(EmitKsmV1MetricsOnly, false)
 }
 }
 
 
+func IsEmitDeprecatedMetrics() bool {
+	return env.GetBool(EmitDeprecatedMetrics, false)
+}
+
 // GetAWSAccessKeyID returns the environment variable value for AWSAccessKeyIDEnvVar which represents
 // GetAWSAccessKeyID returns the environment variable value for AWSAccessKeyIDEnvVar which represents
 // the AWS access key for authentication
 // the AWS access key for authentication
 func GetAWSAccessKeyID() string {
 func GetAWSAccessKeyID() string {

+ 16 - 0
pkg/metrics/kubemetrics.go

@@ -29,6 +29,7 @@ type KubeMetricsOpts struct {
 	EmitPodAnnotations            bool
 	EmitPodAnnotations            bool
 	EmitKubeStateMetrics          bool
 	EmitKubeStateMetrics          bool
 	EmitKubeStateMetricsV1Only    bool
 	EmitKubeStateMetricsV1Only    bool
+	EmitDeprecatedMetrics         bool
 }
 }
 
 
 // DefaultKubeMetricsOpts returns KubeMetricsOpts with default values set
 // DefaultKubeMetricsOpts returns KubeMetricsOpts with default values set
@@ -39,6 +40,7 @@ func DefaultKubeMetricsOpts() *KubeMetricsOpts {
 		EmitPodAnnotations:            false,
 		EmitPodAnnotations:            false,
 		EmitKubeStateMetrics:          true,
 		EmitKubeStateMetrics:          true,
 		EmitKubeStateMetricsV1Only:    false,
 		EmitKubeStateMetricsV1Only:    false,
+		EmitDeprecatedMetrics:         false,
 	}
 	}
 }
 }
 
 
@@ -49,6 +51,20 @@ func InitKubeMetrics(clusterCache clustercache.ClusterCache, metricsConfig *Metr
 	}
 	}
 
 
 	kubeMetricInit.Do(func() {
 	kubeMetricInit.Do(func() {
+		if !opts.EmitDeprecatedMetrics {
+			metricsConfig.DisabledMetrics = append(metricsConfig.DisabledMetrics,
+				"kube_pod_container_resource_limits",
+				"kube_pod_container_resource_limits_memory_bytes",
+				"kube_pod_container_resource_limits_cpu_cores",
+				"kube_pod_container_status_restarts_total",
+				"kube_node_status_condition",
+				"kube_deployment_status_replicas_available",
+				"kube_deployment_spec_replicas",
+				"kube_persistentvolume_status_phase",
+				"kube_pod_status_phase",
+			)
+		}
+
 		if opts.EmitKubecostControllerMetrics {
 		if opts.EmitKubecostControllerMetrics {
 			prometheus.MustRegister(KubecostServiceCollector{
 			prometheus.MustRegister(KubecostServiceCollector{
 				KubeClusterCache: clusterCache,
 				KubeClusterCache: clusterCache,

+ 123 - 3
ui/package-lock.json

@@ -1092,6 +1092,21 @@
         "url": "https://opencollective.com/parcel"
         "url": "https://opencollective.com/parcel"
       }
       }
     },
     },
+    "node_modules/@parcel/codeframe/node_modules/ansi-styles": {
+      "version": "4.3.0",
+      "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+      "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+      "dev": true,
+      "dependencies": {
+        "color-convert": "^2.0.1"
+      },
+      "engines": {
+        "node": ">=8"
+      },
+      "funding": {
+        "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+      }
+    },
     "node_modules/@parcel/codeframe/node_modules/chalk": {
     "node_modules/@parcel/codeframe/node_modules/chalk": {
       "version": "4.1.2",
       "version": "4.1.2",
       "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
       "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
@@ -1108,6 +1123,24 @@
         "url": "https://github.com/chalk/chalk?sponsor=1"
         "url": "https://github.com/chalk/chalk?sponsor=1"
       }
       }
     },
     },
+    "node_modules/@parcel/codeframe/node_modules/color-convert": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+      "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+      "dev": true,
+      "dependencies": {
+        "color-name": "~1.1.4"
+      },
+      "engines": {
+        "node": ">=7.0.0"
+      }
+    },
+    "node_modules/@parcel/codeframe/node_modules/color-name": {
+      "version": "1.1.4",
+      "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+      "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+      "dev": true
+    },
     "node_modules/@parcel/codeframe/node_modules/has-flag": {
     "node_modules/@parcel/codeframe/node_modules/has-flag": {
       "version": "4.0.0",
       "version": "4.0.0",
       "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
       "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
@@ -1232,6 +1265,18 @@
         "url": "https://opencollective.com/parcel"
         "url": "https://opencollective.com/parcel"
       }
       }
     },
     },
+    "node_modules/@parcel/core/node_modules/lru-cache": {
+      "version": "6.0.0",
+      "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
+      "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
+      "dev": true,
+      "dependencies": {
+        "yallist": "^4.0.0"
+      },
+      "engines": {
+        "node": ">=10"
+      }
+    },
     "node_modules/@parcel/core/node_modules/semver": {
     "node_modules/@parcel/core/node_modules/semver": {
       "version": "7.5.4",
       "version": "7.5.4",
       "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz",
       "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz",
@@ -1247,6 +1292,12 @@
         "node": ">=10"
         "node": ">=10"
       }
       }
     },
     },
+    "node_modules/@parcel/core/node_modules/yallist": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
+      "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
+      "dev": true
+    },
     "node_modules/@parcel/diagnostic": {
     "node_modules/@parcel/diagnostic": {
       "version": "2.10.1",
       "version": "2.10.1",
       "resolved": "https://registry.npmjs.org/@parcel/diagnostic/-/diagnostic-2.10.1.tgz",
       "resolved": "https://registry.npmjs.org/@parcel/diagnostic/-/diagnostic-2.10.1.tgz",
@@ -1349,6 +1400,21 @@
         "url": "https://opencollective.com/parcel"
         "url": "https://opencollective.com/parcel"
       }
       }
     },
     },
+    "node_modules/@parcel/markdown-ansi/node_modules/ansi-styles": {
+      "version": "4.3.0",
+      "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+      "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+      "dev": true,
+      "dependencies": {
+        "color-convert": "^2.0.1"
+      },
+      "engines": {
+        "node": ">=8"
+      },
+      "funding": {
+        "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+      }
+    },
     "node_modules/@parcel/markdown-ansi/node_modules/chalk": {
     "node_modules/@parcel/markdown-ansi/node_modules/chalk": {
       "version": "4.1.2",
       "version": "4.1.2",
       "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
       "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
@@ -1365,6 +1431,24 @@
         "url": "https://github.com/chalk/chalk?sponsor=1"
         "url": "https://github.com/chalk/chalk?sponsor=1"
       }
       }
     },
     },
+    "node_modules/@parcel/markdown-ansi/node_modules/color-convert": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+      "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+      "dev": true,
+      "dependencies": {
+        "color-name": "~1.1.4"
+      },
+      "engines": {
+        "node": ">=7.0.0"
+      }
+    },
+    "node_modules/@parcel/markdown-ansi/node_modules/color-name": {
+      "version": "1.1.4",
+      "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+      "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+      "dev": true
+    },
     "node_modules/@parcel/markdown-ansi/node_modules/has-flag": {
     "node_modules/@parcel/markdown-ansi/node_modules/has-flag": {
       "version": "4.0.0",
       "version": "4.0.0",
       "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
       "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
@@ -2600,6 +2684,18 @@
         "url": "https://opencollective.com/parcel"
         "url": "https://opencollective.com/parcel"
       }
       }
     },
     },
+    "node_modules/@parcel/transformer-svg/node_modules/lru-cache": {
+      "version": "6.0.0",
+      "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
+      "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
+      "dev": true,
+      "dependencies": {
+        "yallist": "^4.0.0"
+      },
+      "engines": {
+        "node": ">=10"
+      }
+    },
     "node_modules/@parcel/transformer-svg/node_modules/semver": {
     "node_modules/@parcel/transformer-svg/node_modules/semver": {
       "version": "7.5.4",
       "version": "7.5.4",
       "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz",
       "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz",
@@ -2615,6 +2711,12 @@
         "node": ">=10"
         "node": ">=10"
       }
       }
     },
     },
+    "node_modules/@parcel/transformer-svg/node_modules/yallist": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
+      "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
+      "dev": true
+    },
     "node_modules/@parcel/types": {
     "node_modules/@parcel/types": {
       "version": "2.10.1",
       "version": "2.10.1",
       "resolved": "https://registry.npmjs.org/@parcel/types/-/types-2.10.1.tgz",
       "resolved": "https://registry.npmjs.org/@parcel/types/-/types-2.10.1.tgz",
@@ -4171,9 +4273,9 @@
       }
       }
     },
     },
     "node_modules/follow-redirects": {
     "node_modules/follow-redirects": {
-      "version": "1.15.3",
-      "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.3.tgz",
-      "integrity": "sha512-1VzOtuEM8pC9SFU1E+8KfTjZyMztRsgEfwQl44z8A25uy13jSzTj6dyK2Df52iV0vgHCfBwLhDWevLn95w5v6Q==",
+      "version": "1.15.4",
+      "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.4.tgz",
+      "integrity": "sha512-Cr4D/5wlrb0z9dgERpUL3LrmPKVDsETIJhaCMeDfuFYcqa5bldGV6wBsAN6X/vxlXQtFBMrXdXxdL8CbDTGniw==",
       "funding": [
       "funding": [
         {
         {
           "type": "individual",
           "type": "individual",
@@ -5118,6 +5220,24 @@
         "url": "https://github.com/chalk/chalk?sponsor=1"
         "url": "https://github.com/chalk/chalk?sponsor=1"
       }
       }
     },
     },
+    "node_modules/parcel/node_modules/color-convert": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+      "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+      "dev": true,
+      "dependencies": {
+        "color-name": "~1.1.4"
+      },
+      "engines": {
+        "node": ">=7.0.0"
+      }
+    },
+    "node_modules/parcel/node_modules/color-name": {
+      "version": "1.1.4",
+      "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+      "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+      "dev": true
+    },
     "node_modules/parcel/node_modules/has-flag": {
     "node_modules/parcel/node_modules/has-flag": {
       "version": "4.0.0",
       "version": "4.0.0",
       "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
       "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",