Niko Kovacevic 6 месяцев назад
Родитель
Сommit
201ad95d7d

+ 0 - 5
core/pkg/exporter/pathing/bingenpath.go

@@ -63,11 +63,6 @@ func NewBingenStoragePathFormatter(rootDir, clusterId, pipeline, resolution stri
 	}, nil
 }
 
-// RootDir returns the root directory of the storage path formatter.
-func (bsf *BingenStoragePathFormatter) RootDir() string {
-	return bsf.rootDir
-}
-
 // Dir returns the director that files will be placed in
 func (bsf *BingenStoragePathFormatter) Dir() string {
 	return path.Join(

+ 0 - 5
core/pkg/exporter/pathing/eventpath.go

@@ -48,11 +48,6 @@ func NewEventStoragePathFormatter(rootDir, clusterId, event string, subPaths ...
 	}, nil
 }
 
-// RootDir returns the root directory of the storage path formatter.
-func (espf *EventStoragePathFormatter) RootDir() string {
-	return espf.rootDir
-}
-
 // Dir  returns the director that files will be placed in
 func (espf *EventStoragePathFormatter) Dir() string {
 	return path.Join(

+ 16 - 24
core/pkg/exporter/pathing/kubemodelpath.go

@@ -9,18 +9,19 @@ import (
 	"github.com/opencost/opencost/core/pkg/pipelines"
 )
 
-const KubeModelStorageTimeFormat = "20060102150405"
+const (
+	KubeModelDateDirTimeFormat = "2006/01/02"
+	KubeModelStorageTimeFormat = "20060102150405"
+)
 
 // KubeModelStoragePathFormatter is an implementation of the StoragePathFormatter interface for
 // a cluster separated storage path of the format:
 //
-//	<root>/<clusterid>/kubemodel/<resolution>/<YYYYMMDDHHiiSS>
+//	<root>/<clusterid>/kubemodel/<resolution>/<YYYY>/<MM>/<DD>/<YYYYMMDDHHiiSS>
 //
 // where <root> is, e.g., s3://<bucket>/<appid>
 type KubeModelStoragePathFormatter struct {
-	rootDir    string
-	clusterId  string
-	resolution string
+	dir string
 }
 
 func NewKubeModelStoragePathFormatter(rootDir, clusterId, resolution string) (StoragePathFormatter[opencost.Window], error) {
@@ -29,36 +30,27 @@ func NewKubeModelStoragePathFormatter(rootDir, clusterId, resolution string) (St
 	}
 
 	return &KubeModelStoragePathFormatter{
-		rootDir:    rootDir,
-		clusterId:  clusterId,
-		resolution: resolution,
+		dir: path.Join(
+			rootDir,
+			clusterId,
+			pipelines.KubeModelPipelineName,
+			resolution,
+		),
 	}, nil
 }
 
-// RootDir returns the root directory of the storage path formatter.
-func (kmspf *KubeModelStoragePathFormatter) RootDir() string {
-	return kmspf.rootDir
-}
-
 // Dir returns the director that files will be placed in
 func (kmspf *KubeModelStoragePathFormatter) Dir() string {
-	return path.Join(
-		kmspf.rootDir,
-		kmspf.clusterId,
-		pipelines.KubeModelPipelineName,
-		kmspf.resolution,
-	)
+	return kmspf.dir
 }
 
 // ToFullPath returns the full path to a file name within the storage directory using the format:
 //
-//	<root>/<clusterid>/kubemodel/<resolution>/<prefix>.<YYYYMMDDHHiiSS>.<fileExt>
+//	<root>/<clusterid>/kubemodel/<resolution>/<YYYY>/<MM>/<DD>/<prefix>.<YYYYMMDDHHiiSS>.<fileExt>
 func (kmspf *KubeModelStoragePathFormatter) ToFullPath(prefix string, window opencost.Window, fileExt string) string {
 	return path.Join(
-		kmspf.rootDir,
-		kmspf.clusterId,
-		pipelines.KubeModelPipelineName,
-		kmspf.resolution,
+		kmspf.dir,
+		window.Start().Format(KubeModelDateDirTimeFormat),
 		toKubeModelFileName(prefix, window.Start(), fileExt),
 	)
 }

+ 1 - 4
core/pkg/exporter/pathing/pathing.go

@@ -2,10 +2,7 @@ package pathing
 
 // StoragePathFormatter is an interface used to format storage paths for exporting data types.
 type StoragePathFormatter[T any] interface {
-	// RootDir returns the root directory for the storage path.
-	RootDir() string
-
-	// Dir returns the director where files are placed
+	// Dir returns the directory where files are placed
 	Dir() string
 
 	// ToFullPath returns the full path to a file name within the storage

+ 0 - 21
core/pkg/model/kubemodel/bingen.go

@@ -20,25 +20,4 @@ package kubemodel
 //
 ////////////////////////////////////////////////////////////////////////////////
 
-// Kubemodel Version Set: Includes Kubemodel pipeline specific resources
-// @bingen:set[name=KubeModel,version=1]
-// @bingen:generate[stringtable]:KubeModelSet
-// @bingen:generate:Cluster
-// @bingen:generate:Metadata
-// @bingen:generate:Namespace
-// @bingen:generate:Provider
-// @bingen:generate:Resource
-// @bingen:generate:ResourceQuantity
-// @bingen:generate:ResourceQuantities
-// @bingen:generate:ResourceQuota
-// @bingen:generate:ResourceQuotaSpec
-// @bingen:generate:ResourceQuotaSpecHard
-// @bingen:generate:ResourceQuotaStatus
-// @bingen:generate:ResourceQuotaStatusUsed
-// @bingen:generate:Stats
-// @bingen:generate:StatType
-// @bingen:generate:Unit
-// @bingen:generate:Window
-// @bingen:end
-
 //go:generate bingen -package=kubemodel -version=1 -buffer=github.com/opencost/opencost/core/pkg/util

+ 1 - 0
core/pkg/model/kubemodel/cluster.go

@@ -2,6 +2,7 @@ package kubemodel
 
 import "time"
 
+// @bingen:generate:Cluster
 type Cluster struct {
 	UID      string    `json:"uid"`      // @bingen:field[version=1]
 	Provider Provider  `json:"provider"` // @bingen:field[version=1]

+ 1 - 0
core/pkg/model/kubemodel/kubemodel.go

@@ -6,6 +6,7 @@ import (
 	"time"
 )
 
+// @bingen:generate[stringtable]:KubeModelSet
 type KubeModelSet struct {
 	Metadata       *Metadata                 `json:"meta"`           // @bingen:field[version=1]
 	Window         Window                    `json:"window"`         // @bingen:field[version=1]

+ 35 - 35
core/pkg/model/kubemodel/kubemodel_codecs.go

@@ -33,8 +33,8 @@ const (
 )
 
 const (
-	// KubeModelCodecVersion is used for any resources listed in the KubeModel version set
-	KubeModelCodecVersion uint8 = 1
+	// DefaultCodecVersion is used for any resources listed in the Default version set
+	DefaultCodecVersion uint8 = 1
 )
 
 //--------------------------------------------------------------------------
@@ -270,7 +270,7 @@ func (target *Cluster) MarshalBinaryWithContext(ctx *EncodingContext) (err error
 	}()
 
 	buff := ctx.Buffer
-	buff.WriteUInt8(KubeModelCodecVersion) // version
+	buff.WriteUInt8(DefaultCodecVersion) // version
 
 	if ctx.IsStringTable() {
 		a := ctx.Table.AddOrGet(target.UID)
@@ -370,8 +370,8 @@ func (target *Cluster) UnmarshalBinaryWithContext(ctx *DecodingContext) (err err
 	buff := ctx.Buffer
 	version := buff.ReadUInt8()
 
-	if version > KubeModelCodecVersion {
-		return fmt.Errorf("Invalid Version Unmarshaling Cluster. Expected %d or less, got %d", KubeModelCodecVersion, version)
+	if version > DefaultCodecVersion {
+		return fmt.Errorf("Invalid Version Unmarshaling Cluster. Expected %d or less, got %d", DefaultCodecVersion, version)
 	}
 
 	// field version check
@@ -517,7 +517,7 @@ func (target *KubeModelSet) MarshalBinaryWithContext(ctx *EncodingContext) (err
 	}()
 
 	buff := ctx.Buffer
-	buff.WriteUInt8(KubeModelCodecVersion) // version
+	buff.WriteUInt8(DefaultCodecVersion) // version
 
 	if target.Metadata == nil {
 		buff.WriteUInt8(uint8(0)) // write nil byte
@@ -672,8 +672,8 @@ func (target *KubeModelSet) UnmarshalBinaryWithContext(ctx *DecodingContext) (er
 	buff := ctx.Buffer
 	version := buff.ReadUInt8()
 
-	if version > KubeModelCodecVersion {
-		return fmt.Errorf("Invalid Version Unmarshaling KubeModelSet. Expected %d or less, got %d", KubeModelCodecVersion, version)
+	if version > DefaultCodecVersion {
+		return fmt.Errorf("Invalid Version Unmarshaling KubeModelSet. Expected %d or less, got %d", DefaultCodecVersion, version)
 	}
 
 	// field version check
@@ -866,7 +866,7 @@ func (target *Metadata) MarshalBinaryWithContext(ctx *EncodingContext) (err erro
 	}()
 
 	buff := ctx.Buffer
-	buff.WriteUInt8(KubeModelCodecVersion) // version
+	buff.WriteUInt8(DefaultCodecVersion) // version
 
 	// --- [begin][write][reference](time.Time) ---
 	a, errA := target.CreatedAt.MarshalBinary()
@@ -976,8 +976,8 @@ func (target *Metadata) UnmarshalBinaryWithContext(ctx *DecodingContext) (err er
 	buff := ctx.Buffer
 	version := buff.ReadUInt8()
 
-	if version > KubeModelCodecVersion {
-		return fmt.Errorf("Invalid Version Unmarshaling Metadata. Expected %d or less, got %d", KubeModelCodecVersion, version)
+	if version > DefaultCodecVersion {
+		return fmt.Errorf("Invalid Version Unmarshaling Metadata. Expected %d or less, got %d", DefaultCodecVersion, version)
 	}
 
 	// field version check
@@ -1124,7 +1124,7 @@ func (target *Namespace) MarshalBinaryWithContext(ctx *EncodingContext) (err err
 	}()
 
 	buff := ctx.Buffer
-	buff.WriteUInt8(KubeModelCodecVersion) // version
+	buff.WriteUInt8(DefaultCodecVersion) // version
 
 	if ctx.IsStringTable() {
 		a := ctx.Table.AddOrGet(target.UID)
@@ -1263,8 +1263,8 @@ func (target *Namespace) UnmarshalBinaryWithContext(ctx *DecodingContext) (err e
 	buff := ctx.Buffer
 	version := buff.ReadUInt8()
 
-	if version > KubeModelCodecVersion {
-		return fmt.Errorf("Invalid Version Unmarshaling Namespace. Expected %d or less, got %d", KubeModelCodecVersion, version)
+	if version > DefaultCodecVersion {
+		return fmt.Errorf("Invalid Version Unmarshaling Namespace. Expected %d or less, got %d", DefaultCodecVersion, version)
 	}
 
 	// field version check
@@ -1472,7 +1472,7 @@ func (target *ResourceQuantity) MarshalBinaryWithContext(ctx *EncodingContext) (
 	}()
 
 	buff := ctx.Buffer
-	buff.WriteUInt8(KubeModelCodecVersion) // version
+	buff.WriteUInt8(DefaultCodecVersion) // version
 
 	// --- [begin][write][alias](Resource) ---
 	if ctx.IsStringTable() {
@@ -1570,8 +1570,8 @@ func (target *ResourceQuantity) UnmarshalBinaryWithContext(ctx *DecodingContext)
 	buff := ctx.Buffer
 	version := buff.ReadUInt8()
 
-	if version > KubeModelCodecVersion {
-		return fmt.Errorf("Invalid Version Unmarshaling ResourceQuantity. Expected %d or less, got %d", KubeModelCodecVersion, version)
+	if version > DefaultCodecVersion {
+		return fmt.Errorf("Invalid Version Unmarshaling ResourceQuantity. Expected %d or less, got %d", DefaultCodecVersion, version)
 	}
 
 	// field version check
@@ -1697,7 +1697,7 @@ func (target *ResourceQuota) MarshalBinaryWithContext(ctx *EncodingContext) (err
 	}()
 
 	buff := ctx.Buffer
-	buff.WriteUInt8(KubeModelCodecVersion) // version
+	buff.WriteUInt8(DefaultCodecVersion) // version
 
 	if ctx.IsStringTable() {
 		a := ctx.Table.AddOrGet(target.UID)
@@ -1798,8 +1798,8 @@ func (target *ResourceQuota) UnmarshalBinaryWithContext(ctx *DecodingContext) (e
 	buff := ctx.Buffer
 	version := buff.ReadUInt8()
 
-	if version > KubeModelCodecVersion {
-		return fmt.Errorf("Invalid Version Unmarshaling ResourceQuota. Expected %d or less, got %d", KubeModelCodecVersion, version)
+	if version > DefaultCodecVersion {
+		return fmt.Errorf("Invalid Version Unmarshaling ResourceQuota. Expected %d or less, got %d", DefaultCodecVersion, version)
 	}
 
 	// field version check
@@ -1933,7 +1933,7 @@ func (target *ResourceQuotaSpec) MarshalBinaryWithContext(ctx *EncodingContext)
 	}()
 
 	buff := ctx.Buffer
-	buff.WriteUInt8(KubeModelCodecVersion) // version
+	buff.WriteUInt8(DefaultCodecVersion) // version
 
 	if target.Hard == nil {
 		buff.WriteUInt8(uint8(0)) // write nil byte
@@ -2002,8 +2002,8 @@ func (target *ResourceQuotaSpec) UnmarshalBinaryWithContext(ctx *DecodingContext
 	buff := ctx.Buffer
 	version := buff.ReadUInt8()
 
-	if version > KubeModelCodecVersion {
-		return fmt.Errorf("Invalid Version Unmarshaling ResourceQuotaSpec. Expected %d or less, got %d", KubeModelCodecVersion, version)
+	if version > DefaultCodecVersion {
+		return fmt.Errorf("Invalid Version Unmarshaling ResourceQuotaSpec. Expected %d or less, got %d", DefaultCodecVersion, version)
 	}
 
 	// field version check
@@ -2068,7 +2068,7 @@ func (target *ResourceQuotaSpecHard) MarshalBinaryWithContext(ctx *EncodingConte
 	}()
 
 	buff := ctx.Buffer
-	buff.WriteUInt8(KubeModelCodecVersion) // version
+	buff.WriteUInt8(DefaultCodecVersion) // version
 
 	// --- [begin][write][alias](ResourceQuantities) ---
 	if map[Resource]ResourceQuantity(target.Requests) == nil {
@@ -2187,8 +2187,8 @@ func (target *ResourceQuotaSpecHard) UnmarshalBinaryWithContext(ctx *DecodingCon
 	buff := ctx.Buffer
 	version := buff.ReadUInt8()
 
-	if version > KubeModelCodecVersion {
-		return fmt.Errorf("Invalid Version Unmarshaling ResourceQuotaSpecHard. Expected %d or less, got %d", KubeModelCodecVersion, version)
+	if version > DefaultCodecVersion {
+		return fmt.Errorf("Invalid Version Unmarshaling ResourceQuotaSpecHard. Expected %d or less, got %d", DefaultCodecVersion, version)
 	}
 
 	// field version check
@@ -2328,7 +2328,7 @@ func (target *ResourceQuotaStatus) MarshalBinaryWithContext(ctx *EncodingContext
 	}()
 
 	buff := ctx.Buffer
-	buff.WriteUInt8(KubeModelCodecVersion) // version
+	buff.WriteUInt8(DefaultCodecVersion) // version
 
 	if target.Used == nil {
 		buff.WriteUInt8(uint8(0)) // write nil byte
@@ -2397,8 +2397,8 @@ func (target *ResourceQuotaStatus) UnmarshalBinaryWithContext(ctx *DecodingConte
 	buff := ctx.Buffer
 	version := buff.ReadUInt8()
 
-	if version > KubeModelCodecVersion {
-		return fmt.Errorf("Invalid Version Unmarshaling ResourceQuotaStatus. Expected %d or less, got %d", KubeModelCodecVersion, version)
+	if version > DefaultCodecVersion {
+		return fmt.Errorf("Invalid Version Unmarshaling ResourceQuotaStatus. Expected %d or less, got %d", DefaultCodecVersion, version)
 	}
 
 	// field version check
@@ -2463,7 +2463,7 @@ func (target *ResourceQuotaStatusUsed) MarshalBinaryWithContext(ctx *EncodingCon
 	}()
 
 	buff := ctx.Buffer
-	buff.WriteUInt8(KubeModelCodecVersion) // version
+	buff.WriteUInt8(DefaultCodecVersion) // version
 
 	// --- [begin][write][alias](ResourceQuantities) ---
 	if map[Resource]ResourceQuantity(target.Requests) == nil {
@@ -2582,8 +2582,8 @@ func (target *ResourceQuotaStatusUsed) UnmarshalBinaryWithContext(ctx *DecodingC
 	buff := ctx.Buffer
 	version := buff.ReadUInt8()
 
-	if version > KubeModelCodecVersion {
-		return fmt.Errorf("Invalid Version Unmarshaling ResourceQuotaStatusUsed. Expected %d or less, got %d", KubeModelCodecVersion, version)
+	if version > DefaultCodecVersion {
+		return fmt.Errorf("Invalid Version Unmarshaling ResourceQuotaStatusUsed. Expected %d or less, got %d", DefaultCodecVersion, version)
 	}
 
 	// field version check
@@ -2723,7 +2723,7 @@ func (target *Window) MarshalBinaryWithContext(ctx *EncodingContext) (err error)
 	}()
 
 	buff := ctx.Buffer
-	buff.WriteUInt8(KubeModelCodecVersion) // version
+	buff.WriteUInt8(DefaultCodecVersion) // version
 
 	// --- [begin][write][reference](time.Time) ---
 	a, errA := target.Start.MarshalBinary()
@@ -2796,8 +2796,8 @@ func (target *Window) UnmarshalBinaryWithContext(ctx *DecodingContext) (err erro
 	buff := ctx.Buffer
 	version := buff.ReadUInt8()
 
-	if version > KubeModelCodecVersion {
-		return fmt.Errorf("Invalid Version Unmarshaling Window. Expected %d or less, got %d", KubeModelCodecVersion, version)
+	if version > DefaultCodecVersion {
+		return fmt.Errorf("Invalid Version Unmarshaling Window. Expected %d or less, got %d", DefaultCodecVersion, version)
 	}
 
 	// field version check

+ 4 - 2
core/pkg/model/kubemodel/metadata.go

@@ -1,8 +1,10 @@
 package kubemodel
 
-import "time"
+import (
+	"time"
+)
 
-// TODO can bingen support marshaling type `error`?
+// @bingen:generate:Metadata
 type Metadata struct {
 	CreatedAt   time.Time `json:"createdAt"`   // @bingen:field[version=1]
 	CompletedAt time.Time `json:"completedAt"` // @bingen:field[version=1]

+ 1 - 0
core/pkg/model/kubemodel/namespace.go

@@ -2,6 +2,7 @@ package kubemodel
 
 import "time"
 
+// @bingen:generate:Namespace
 type Namespace struct {
 	UID         string            `json:"uid"`         // @bingen:field[version=1]
 	ClusterUID  string            `json:"clusterUID"`  // @bingen:field[version=1]

+ 1 - 0
core/pkg/model/kubemodel/provider.go

@@ -1,5 +1,6 @@
 package kubemodel
 
+// @bingen:generate:Provider
 type Provider string
 
 const (

+ 3 - 18
core/pkg/model/kubemodel/resource.go

@@ -1,5 +1,6 @@
 package kubemodel
 
+// @bingen:generate:Resource
 type Resource string
 
 const (
@@ -9,30 +10,14 @@ const (
 	ResourceStorage Resource = "storage"
 )
 
-type Unit string
-
-const (
-	UnitMillicore     = "mCPU"
-	UnitByte          = "B"
-	UnitMi            = "Mi"
-	UnitGB            = "GB"
-	UnitGPU           = "GPU"
-	UnitSecond        = "s"
-	UnitMinute        = "m"
-	UnitHour          = "h"
-	UnitMillicoreHour = "m-h"
-	UnitByteHour      = "B-h"
-	UnitMiHour        = "Mi-h"
-	UnitGBHour        = "GB-h"
-	UnitGPUHour       = "GPU-h"
-)
-
+// @bingen:generate:ResourceQuantity
 type ResourceQuantity struct {
 	Resource Resource `json:"resource"` // @bingen:field[version=1]
 	Unit     Unit     `json:"unit"`     // @bingen:field[version=1]
 	Values   Stats    `json:"values"`   // @bingen:field[version=1]
 }
 
+// @bingen:generate:ResourceQuantities
 type ResourceQuantities map[Resource]ResourceQuantity
 
 func (rqs ResourceQuantities) Set(resource Resource, unit Unit, statType StatType, value float64) {

+ 5 - 0
core/pkg/model/kubemodel/resourcequota.go

@@ -1,5 +1,6 @@
 package kubemodel
 
+// @bingen:generate:ResourceQuota
 type ResourceQuota struct {
 	UID          string               `json:"uid"`          // @bingen:field[version=1]
 	NamespaceUID string               `json:"namespaceUID"` // @bingen:field[version=1]
@@ -8,19 +9,23 @@ type ResourceQuota struct {
 	Status       *ResourceQuotaStatus `json:"status"`       // @bingen:field[version=1]
 }
 
+// @bingen:generate:ResourceQuotaSpec
 type ResourceQuotaSpec struct {
 	Hard *ResourceQuotaSpecHard `json:"hard"` // @bingen:field[version=1]
 }
 
+// @bingen:generate:ResourceQuotaSpecHard
 type ResourceQuotaSpecHard struct {
 	Requests ResourceQuantities `json:"requests"` // @bingen:field[version=1]
 	Limits   ResourceQuantities `json:"limits"`   // @bingen:field[version=1]
 }
 
+// @bingen:generate:ResourceQuotaStatus
 type ResourceQuotaStatus struct {
 	Used *ResourceQuotaStatusUsed `json:"used"` // @bingen:field[version=1]
 }
 
+// @bingen:generate:ResourceQuotaStatusUsed
 type ResourceQuotaStatusUsed struct {
 	Requests ResourceQuantities `json:"requests"` // @bingen:field[version=1]
 	Limits   ResourceQuantities `json:"limits"`   // @bingen:field[version=1]

+ 12 - 10
core/pkg/model/kubemodel/stats.go

@@ -6,16 +6,18 @@ import (
 	"math"
 )
 
+// @bingen:generate:StatType
 type StatType string
 
 const (
-	Avg StatType = "avg"
-	Max StatType = "max"
-	Min StatType = "min"
-	P95 StatType = "p95"
-	P85 StatType = "p85"
+	StatAvg StatType = "avg"
+	StatMax StatType = "max"
+	StatMin StatType = "min"
+	StatP95 StatType = "p95"
+	StatP85 StatType = "p85"
 )
 
+// @bingen:generate:Stats
 type Stats map[StatType]float64
 
 func NewStats(capacity ...int) Stats {
@@ -32,7 +34,7 @@ func (s Stats) Avg() (float64, bool) {
 		return 0.0, false
 	}
 
-	val, ok := s[Avg]
+	val, ok := s[StatAvg]
 
 	return val, ok
 }
@@ -42,7 +44,7 @@ func (s Stats) Max() (float64, bool) {
 		return 0.0, false
 	}
 
-	val, ok := s[Max]
+	val, ok := s[StatMax]
 
 	return val, ok
 }
@@ -52,7 +54,7 @@ func (s Stats) Min() (float64, bool) {
 		return 0.0, false
 	}
 
-	val, ok := s[Min]
+	val, ok := s[StatMin]
 
 	return val, ok
 }
@@ -62,7 +64,7 @@ func (s Stats) P95() (float64, bool) {
 		return 0.0, false
 	}
 
-	val, ok := s[P95]
+	val, ok := s[StatP95]
 
 	return val, ok
 }
@@ -72,7 +74,7 @@ func (s Stats) P85() (float64, bool) {
 		return 0.0, false
 	}
 
-	val, ok := s[P85]
+	val, ok := s[StatP85]
 
 	return val, ok
 }

+ 6 - 6
core/pkg/model/kubemodel/stats_test.go

@@ -23,22 +23,22 @@ func TestStats_Sanitize(t *testing.T) {
 		},
 		{
 			Stats{
-				Avg: 0.1,
-				Max: 1.0,
+				StatAvg: 0.1,
+				StatMax: 1.0,
 			},
 			nil,
 		},
 		{
 			Stats{
-				Avg: math.Inf(0),
-				Max: 1.0,
+				StatAvg: math.Inf(0),
+				StatMax: 1.0,
 			},
 			errors.New("1 errors: [avg is Inf]"),
 		},
 		{
 			Stats{
-				Avg: math.Inf(0),
-				Max: math.NaN(),
+				StatAvg: math.Inf(0),
+				StatMax: math.NaN(),
 			},
 			errors.New("2 errors: [avg is Inf] [max is NaN]"),
 		},

+ 20 - 0
core/pkg/model/kubemodel/unit.go

@@ -0,0 +1,20 @@
+package kubemodel
+
+// @bingen:generate:Unit
+type Unit string
+
+const (
+	UnitMillicore     = "mCPU"
+	UnitByte          = "B"
+	UnitMi            = "Mi"
+	UnitGB            = "GB"
+	UnitGPU           = "GPU"
+	UnitSecond        = "s"
+	UnitMinute        = "m"
+	UnitHour          = "h"
+	UnitMillicoreHour = "m-h"
+	UnitByteHour      = "B-h"
+	UnitMiHour        = "Mi-h"
+	UnitGBHour        = "GB-h"
+	UnitGPUHour       = "GPU-h"
+)

+ 1 - 0
core/pkg/model/kubemodel/window.go

@@ -2,6 +2,7 @@ package kubemodel
 
 import "time"
 
+// @bingen:generate:Window
 type Window struct {
 	Start time.Time `json:"start"` // @bingen:field[version=1]
 	End   time.Time `json:"end"`   // @bingen:field[version=1]

+ 16 - 16
pkg/costmodel/kubemodel.go

@@ -115,104 +115,104 @@ func (cm *CostModel) kmComputeResourceQuotas(kms *kubemodel.KubeModelSet, start,
 	for _, res := range rqSpecCPURequestAverageResult {
 		kms.RegisterResourceQuota(res.UID, res.ResourceQuota, res.Namespace)
 		mcpu := res.Data[0].Value * 1000
-		kms.ResourceQuotas[res.UID].Spec.Hard.Requests.Set(kubemodel.ResourceCPU, kubemodel.UnitMillicore, kubemodel.Avg, mcpu)
+		kms.ResourceQuotas[res.UID].Spec.Hard.Requests.Set(kubemodel.ResourceCPU, kubemodel.UnitMillicore, kubemodel.StatAvg, mcpu)
 	}
 
 	rqSpecCPURequestMaxResult, _ := rqSpecCPURequestMaxResultFuture.Await()
 	for _, res := range rqSpecCPURequestMaxResult {
 		kms.RegisterResourceQuota(res.UID, res.ResourceQuota, res.Namespace)
 		mcpu := res.Data[0].Value * 1000
-		kms.ResourceQuotas[res.UID].Spec.Hard.Requests.Set(kubemodel.ResourceCPU, kubemodel.UnitMillicore, kubemodel.Max, mcpu)
+		kms.ResourceQuotas[res.UID].Spec.Hard.Requests.Set(kubemodel.ResourceCPU, kubemodel.UnitMillicore, kubemodel.StatMax, mcpu)
 	}
 
 	rqSpecRAMRequestAverageResult, _ := rqSpecRAMRequestAverageResultFuture.Await()
 	for _, res := range rqSpecRAMRequestAverageResult {
 		kms.RegisterResourceQuota(res.UID, res.ResourceQuota, res.Namespace)
-		kms.ResourceQuotas[res.UID].Spec.Hard.Requests.Set(kubemodel.ResourceMemory, kubemodel.UnitByte, kubemodel.Avg, res.Data[0].Value)
+		kms.ResourceQuotas[res.UID].Spec.Hard.Requests.Set(kubemodel.ResourceMemory, kubemodel.UnitByte, kubemodel.StatAvg, res.Data[0].Value)
 	}
 
 	rqSpecRAMRequestMaxResult, _ := rqSpecRAMRequestMaxResultFuture.Await()
 	for _, res := range rqSpecRAMRequestMaxResult {
 		kms.RegisterResourceQuota(res.UID, res.ResourceQuota, res.Namespace)
-		kms.ResourceQuotas[res.UID].Spec.Hard.Requests.Set(kubemodel.ResourceMemory, kubemodel.UnitByte, kubemodel.Max, res.Data[0].Value)
+		kms.ResourceQuotas[res.UID].Spec.Hard.Requests.Set(kubemodel.ResourceMemory, kubemodel.UnitByte, kubemodel.StatMax, res.Data[0].Value)
 	}
 
 	rqSpecCPULimitAverageResult, _ := rqSpecCPULimitAverageResultFuture.Await()
 	for _, res := range rqSpecCPULimitAverageResult {
 		kms.RegisterResourceQuota(res.UID, res.ResourceQuota, res.Namespace)
 		mcpu := res.Data[0].Value * 1000
-		kms.ResourceQuotas[res.UID].Spec.Hard.Limits.Set(kubemodel.ResourceCPU, kubemodel.UnitMillicore, kubemodel.Avg, mcpu)
+		kms.ResourceQuotas[res.UID].Spec.Hard.Limits.Set(kubemodel.ResourceCPU, kubemodel.UnitMillicore, kubemodel.StatAvg, mcpu)
 	}
 
 	rqSpecCPULimitMaxResult, _ := rqSpecCPULimitMaxResultFuture.Await()
 	for _, res := range rqSpecCPULimitMaxResult {
 		kms.RegisterResourceQuota(res.UID, res.ResourceQuota, res.Namespace)
 		mcpu := res.Data[0].Value * 1000
-		kms.ResourceQuotas[res.UID].Spec.Hard.Limits.Set(kubemodel.ResourceCPU, kubemodel.UnitMillicore, kubemodel.Max, mcpu)
+		kms.ResourceQuotas[res.UID].Spec.Hard.Limits.Set(kubemodel.ResourceCPU, kubemodel.UnitMillicore, kubemodel.StatMax, mcpu)
 	}
 
 	rqSpecRAMLimitAverageResult, _ := rqSpecRAMLimitAverageResultFuture.Await()
 	for _, res := range rqSpecRAMLimitAverageResult {
 		kms.RegisterResourceQuota(res.UID, res.ResourceQuota, res.Namespace)
-		kms.ResourceQuotas[res.UID].Spec.Hard.Limits.Set(kubemodel.ResourceMemory, kubemodel.UnitByte, kubemodel.Avg, res.Data[0].Value)
+		kms.ResourceQuotas[res.UID].Spec.Hard.Limits.Set(kubemodel.ResourceMemory, kubemodel.UnitByte, kubemodel.StatAvg, res.Data[0].Value)
 	}
 
 	rqSpecRAMLimitMaxResult, _ := rqSpecRAMLimitMaxResultFuture.Await()
 	for _, res := range rqSpecRAMLimitMaxResult {
 		kms.RegisterResourceQuota(res.UID, res.ResourceQuota, res.Namespace)
-		kms.ResourceQuotas[res.UID].Spec.Hard.Limits.Set(kubemodel.ResourceMemory, kubemodel.UnitByte, kubemodel.Max, res.Data[0].Value)
+		kms.ResourceQuotas[res.UID].Spec.Hard.Limits.Set(kubemodel.ResourceMemory, kubemodel.UnitByte, kubemodel.StatMax, res.Data[0].Value)
 	}
 
 	rqStatusUsedCPURequestAverageResult, _ := rqStatusUsedCPURequestAverageResultFuture.Await()
 	for _, res := range rqStatusUsedCPURequestAverageResult {
 		kms.RegisterResourceQuota(res.UID, res.ResourceQuota, res.Namespace)
 		mcpu := res.Data[0].Value * 1000
-		kms.ResourceQuotas[res.UID].Status.Used.Requests.Set(kubemodel.ResourceCPU, kubemodel.UnitMillicore, kubemodel.Avg, mcpu)
+		kms.ResourceQuotas[res.UID].Status.Used.Requests.Set(kubemodel.ResourceCPU, kubemodel.UnitMillicore, kubemodel.StatAvg, mcpu)
 	}
 
 	rqStatusUsedCPURequestMaxResult, _ := rqStatusUsedCPURequestMaxResultFuture.Await()
 	for _, res := range rqStatusUsedCPURequestMaxResult {
 		kms.RegisterResourceQuota(res.UID, res.ResourceQuota, res.Namespace)
 		mcpu := res.Data[0].Value * 1000
-		kms.ResourceQuotas[res.UID].Status.Used.Requests.Set(kubemodel.ResourceCPU, kubemodel.UnitMillicore, kubemodel.Max, mcpu)
+		kms.ResourceQuotas[res.UID].Status.Used.Requests.Set(kubemodel.ResourceCPU, kubemodel.UnitMillicore, kubemodel.StatMax, mcpu)
 	}
 
 	rqStatusUsedRAMRequestAverageResult, _ := rqStatusUsedRAMRequestAverageResultFuture.Await()
 	for _, res := range rqStatusUsedRAMRequestAverageResult {
 		kms.RegisterResourceQuota(res.UID, res.ResourceQuota, res.Namespace)
-		kms.ResourceQuotas[res.UID].Status.Used.Requests.Set(kubemodel.ResourceMemory, kubemodel.UnitByte, kubemodel.Avg, res.Data[0].Value)
+		kms.ResourceQuotas[res.UID].Status.Used.Requests.Set(kubemodel.ResourceMemory, kubemodel.UnitByte, kubemodel.StatAvg, res.Data[0].Value)
 	}
 
 	rqStatusUsedRAMRequestMaxResult, _ := rqStatusUsedRAMRequestMaxResultFuture.Await()
 	for _, res := range rqStatusUsedRAMRequestMaxResult {
 		kms.RegisterResourceQuota(res.UID, res.ResourceQuota, res.Namespace)
-		kms.ResourceQuotas[res.UID].Status.Used.Requests.Set(kubemodel.ResourceMemory, kubemodel.UnitByte, kubemodel.Max, res.Data[0].Value)
+		kms.ResourceQuotas[res.UID].Status.Used.Requests.Set(kubemodel.ResourceMemory, kubemodel.UnitByte, kubemodel.StatMax, res.Data[0].Value)
 	}
 
 	rqStatusUsedCPULimitAverageResult, _ := rqStatusUsedCPULimitAverageResultFuture.Await()
 	for _, res := range rqStatusUsedCPULimitAverageResult {
 		kms.RegisterResourceQuota(res.UID, res.ResourceQuota, res.Namespace)
 		mcpu := res.Data[0].Value * 1000
-		kms.ResourceQuotas[res.UID].Status.Used.Limits.Set(kubemodel.ResourceCPU, kubemodel.UnitMillicore, kubemodel.Avg, mcpu)
+		kms.ResourceQuotas[res.UID].Status.Used.Limits.Set(kubemodel.ResourceCPU, kubemodel.UnitMillicore, kubemodel.StatAvg, mcpu)
 	}
 
 	rqStatusUsedCPULimitMaxResult, _ := rqStatusUsedCPULimitMaxResultFuture.Await()
 	for _, res := range rqStatusUsedCPULimitMaxResult {
 		kms.RegisterResourceQuota(res.UID, res.ResourceQuota, res.Namespace)
 		mcpu := res.Data[0].Value * 1000
-		kms.ResourceQuotas[res.UID].Status.Used.Limits.Set(kubemodel.ResourceCPU, kubemodel.UnitMillicore, kubemodel.Max, mcpu)
+		kms.ResourceQuotas[res.UID].Status.Used.Limits.Set(kubemodel.ResourceCPU, kubemodel.UnitMillicore, kubemodel.StatMax, mcpu)
 	}
 
 	rqStatusUsedRAMLimitAverageResult, _ := rqStatusUsedRAMLimitAverageResultFuture.Await()
 	for _, res := range rqStatusUsedRAMLimitAverageResult {
 		kms.RegisterResourceQuota(res.UID, res.ResourceQuota, res.Namespace)
-		kms.ResourceQuotas[res.UID].Status.Used.Limits.Set(kubemodel.ResourceMemory, kubemodel.UnitByte, kubemodel.Avg, res.Data[0].Value)
+		kms.ResourceQuotas[res.UID].Status.Used.Limits.Set(kubemodel.ResourceMemory, kubemodel.UnitByte, kubemodel.StatAvg, res.Data[0].Value)
 	}
 
 	rqStatusUsedRAMLimitMaxResult, _ := rqStatusUsedRAMLimitMaxResultFuture.Await()
 	for _, res := range rqStatusUsedRAMLimitMaxResult {
 		kms.RegisterResourceQuota(res.UID, res.ResourceQuota, res.Namespace)
-		kms.ResourceQuotas[res.UID].Status.Used.Limits.Set(kubemodel.ResourceMemory, kubemodel.UnitByte, kubemodel.Max, res.Data[0].Value)
+		kms.ResourceQuotas[res.UID].Status.Used.Limits.Set(kubemodel.ResourceMemory, kubemodel.UnitByte, kubemodel.StatMax, res.Data[0].Value)
 	}
 
 	return nil