2
0
Эх сурвалжийг харах

Ingest K8s ResourceQuota metrics (#3430)

Signed-off-by: Bianca Burtoiu <bianca.burtoiu@ibm.com>
Bianca Burtoiu 6 сар өмнө
parent
commit
eba802ef15

+ 2 - 0
core/pkg/clustercache/clustercache.go

@@ -161,6 +161,7 @@ type ReplicaSet struct {
 }
 
 type ResourceQuota struct {
+	UID       types.UID
 	Name      string
 	Namespace string
 	Spec      v1.ResourceQuotaSpec
@@ -390,6 +391,7 @@ func TransformReplicaSet(input *appsv1.ReplicaSet) *ReplicaSet {
 
 func TransformResourceQuota(input *v1.ResourceQuota) *ResourceQuota {
 	return &ResourceQuota{
+		UID:       input.UID,
 		Name:      input.Name,
 		Namespace: input.Namespace,
 		Spec:      input.Spec,

+ 18 - 0
core/pkg/source/datasource.go

@@ -117,6 +117,24 @@ type MetricsQuerier interface {
 	QueryReplicaSetsWithoutOwners(start, end time.Time) *Future[ReplicaSetsWithoutOwnersResult]
 	QueryReplicaSetsWithRollout(start, end time.Time) *Future[ReplicaSetsWithRolloutResult]
 
+	// ResourceQuotas
+	QueryResourceQuotaSpecCPURequestAverage(start, end time.Time) *Future[ResourceQuotaSpecCPURequestAvgResult]
+	QueryResourceQuotaSpecCPURequestMax(start, end time.Time) *Future[ResourceQuotaSpecCPURequestMaxResult]
+	QueryResourceQuotaSpecRAMRequestAverage(start, end time.Time) *Future[ResourceQuotaSpecRAMRequestAvgResult]
+	QueryResourceQuotaSpecRAMRequestMax(start, end time.Time) *Future[ResourceQuotaSpecRAMRequestMaxResult]
+	QueryResourceQuotaSpecCPULimitAverage(start, end time.Time) *Future[ResourceQuotaSpecCPULimitAvgResult]
+	QueryResourceQuotaSpecCPULimitMax(start, end time.Time) *Future[ResourceQuotaSpecCPULimitMaxResult]
+	QueryResourceQuotaSpecRAMLimitAverage(start, end time.Time) *Future[ResourceQuotaSpecRAMLimitAvgResult]
+	QueryResourceQuotaSpecRAMLimitMax(start, end time.Time) *Future[ResourceQuotaSpecRAMLimitMaxResult]
+	QueryResourceQuotaStatusUsedCPURequestAverage(start, end time.Time) *Future[ResourceQuotaStatusUsedCPURequestAvgResult]
+	QueryResourceQuotaStatusUsedCPURequestMax(start, end time.Time) *Future[ResourceQuotaStatusUsedCPURequestMaxResult]
+	QueryResourceQuotaStatusUsedRAMRequestAverage(start, end time.Time) *Future[ResourceQuotaStatusUsedRAMRequestAvgResult]
+	QueryResourceQuotaStatusUsedRAMRequestMax(start, end time.Time) *Future[ResourceQuotaStatusUsedRAMRequestMaxResult]
+	QueryResourceQuotaStatusUsedCPULimitAverage(start, end time.Time) *Future[ResourceQuotaStatusUsedCPULimitAvgResult]
+	QueryResourceQuotaStatusUsedCPULimitMax(start, end time.Time) *Future[ResourceQuotaStatusUsedCPULimitMaxResult]
+	QueryResourceQuotaStatusUsedRAMLimitAverage(start, end time.Time) *Future[ResourceQuotaStatusUsedRAMLimitAvgResult]
+	QueryResourceQuotaStatusUsedRAMLimitMax(start, end time.Time) *Future[ResourceQuotaStatusUsedRAMLimitMaxResult]
+
 	// Data Coverage Query
 	QueryDataCoverage(limitDays int) (time.Time, time.Time, error)
 }

+ 123 - 0
core/pkg/source/decoders.go

@@ -32,6 +32,7 @@ const (
 	DeploymentLabel      = "deployment"
 	StatefulSetLabel     = "statefulSet"
 	ReplicaSetLabel      = "replicaset"
+	ResourceQuotaLabel   = "resourcequota"
 	OwnerNameLabel       = "owner_name"
 	OwnerKindLabel       = "owner_kind"
 	UnitLabel            = "unit"
@@ -1497,6 +1498,128 @@ func DecodeReplicaSetsWithRolloutResult(result *QueryResult) *ReplicaSetsWithRol
 	}
 }
 
+type ResourceQuotaMetricResult struct {
+	UID           string
+	Namespace     string
+	ResourceQuota string
+	Resource      string
+	Unit          string
+	Data          []*util.Vector
+}
+
+func DecodeResourceQuotaMetricResult(result *QueryResult) *ResourceQuotaMetricResult {
+	uid, _ := result.GetString(UIDLabel)
+	namespace, _ := result.GetNamespace()
+	resourceQuota, _ := result.GetString(ResourceQuotaLabel)
+	resource, _ := result.GetString(ResourceLabel)
+	unit, _ := result.GetString(UnitLabel)
+
+	return &ResourceQuotaMetricResult{
+		UID:           uid,
+		Namespace:     namespace,
+		ResourceQuota: resourceQuota,
+		Resource:      resource,
+		Unit:          unit,
+		Data:          result.Values,
+	}
+}
+
+type ResourceQuotaSpecCPURequestAvgResult = ResourceQuotaMetricResult
+
+func DecodeResourceQuotaSpecCPURequestAvgResult(result *QueryResult) *ResourceQuotaSpecCPURequestAvgResult {
+	return DecodeResourceQuotaMetricResult(result)
+}
+
+type ResourceQuotaSpecCPURequestMaxResult = ResourceQuotaMetricResult
+
+func DecodeResourceQuotaSpecCPURequestMaxResult(result *QueryResult) *ResourceQuotaSpecCPURequestMaxResult {
+	return DecodeResourceQuotaMetricResult(result)
+}
+
+type ResourceQuotaSpecRAMRequestAvgResult = ResourceQuotaMetricResult
+
+func DecodeResourceQuotaSpecRAMRequestAvgResult(result *QueryResult) *ResourceQuotaSpecRAMRequestAvgResult {
+	return DecodeResourceQuotaMetricResult(result)
+}
+
+type ResourceQuotaSpecRAMRequestMaxResult = ResourceQuotaMetricResult
+
+func DecodeResourceQuotaSpecRAMRequestMaxResult(result *QueryResult) *ResourceQuotaSpecRAMRequestMaxResult {
+	return DecodeResourceQuotaMetricResult(result)
+}
+
+type ResourceQuotaSpecCPULimitAvgResult = ResourceQuotaMetricResult
+
+func DecodeResourceQuotaSpecCPULimitAvgResult(result *QueryResult) *ResourceQuotaSpecCPULimitAvgResult {
+	return DecodeResourceQuotaMetricResult(result)
+}
+
+type ResourceQuotaSpecCPULimitMaxResult = ResourceQuotaMetricResult
+
+func DecodeResourceQuotaSpecCPULimitMaxResult(result *QueryResult) *ResourceQuotaSpecCPULimitMaxResult {
+	return DecodeResourceQuotaMetricResult(result)
+}
+
+type ResourceQuotaSpecRAMLimitAvgResult = ResourceQuotaMetricResult
+
+func DecodeResourceQuotaSpecRAMLimitAvgResult(result *QueryResult) *ResourceQuotaSpecRAMLimitAvgResult {
+	return DecodeResourceQuotaMetricResult(result)
+}
+
+type ResourceQuotaSpecRAMLimitMaxResult = ResourceQuotaMetricResult
+
+func DecodeResourceQuotaSpecRAMLimitMaxResult(result *QueryResult) *ResourceQuotaSpecRAMLimitMaxResult {
+	return DecodeResourceQuotaMetricResult(result)
+}
+
+type ResourceQuotaStatusUsedCPURequestAvgResult = ResourceQuotaMetricResult
+
+func DecodeResourceQuotaStatusUsedCPURequestAvgResult(result *QueryResult) *ResourceQuotaStatusUsedCPURequestAvgResult {
+	return DecodeResourceQuotaMetricResult(result)
+}
+
+type ResourceQuotaStatusUsedCPURequestMaxResult = ResourceQuotaMetricResult
+
+func DecodeResourceQuotaStatusUsedCPURequestMaxResult(result *QueryResult) *ResourceQuotaStatusUsedCPURequestMaxResult {
+	return DecodeResourceQuotaMetricResult(result)
+}
+
+type ResourceQuotaStatusUsedRAMRequestAvgResult = ResourceQuotaMetricResult
+
+func DecodeResourceQuotaStatusUsedRAMRequestAvgResult(result *QueryResult) *ResourceQuotaStatusUsedRAMRequestAvgResult {
+	return DecodeResourceQuotaMetricResult(result)
+}
+
+type ResourceQuotaStatusUsedRAMRequestMaxResult = ResourceQuotaMetricResult
+
+func DecodeResourceQuotaStatusUsedRAMRequestMaxResult(result *QueryResult) *ResourceQuotaStatusUsedRAMRequestMaxResult {
+	return DecodeResourceQuotaMetricResult(result)
+}
+
+type ResourceQuotaStatusUsedCPULimitAvgResult = ResourceQuotaMetricResult
+
+func DecodeResourceQuotaStatusUsedCPULimitAvgResult(result *QueryResult) *ResourceQuotaStatusUsedCPULimitAvgResult {
+	return DecodeResourceQuotaMetricResult(result)
+}
+
+type ResourceQuotaStatusUsedCPULimitMaxResult = ResourceQuotaMetricResult
+
+func DecodeResourceQuotaStatusUsedCPULimitMaxResult(result *QueryResult) *ResourceQuotaStatusUsedCPULimitMaxResult {
+	return DecodeResourceQuotaMetricResult(result)
+}
+
+type ResourceQuotaStatusUsedRAMLimitAvgResult = ResourceQuotaMetricResult
+
+func DecodeResourceQuotaStatusUsedRAMLimitAvgResult(result *QueryResult) *ResourceQuotaStatusUsedRAMLimitAvgResult {
+	return DecodeResourceQuotaMetricResult(result)
+}
+
+type ResourceQuotaStatusUsedRAMLimitMaxResult = ResourceQuotaMetricResult
+
+func DecodeResourceQuotaStatusUsedRAMLimitMaxResult(result *QueryResult) *ResourceQuotaStatusUsedRAMLimitMaxResult {
+	return DecodeResourceQuotaMetricResult(result)
+}
+
 func DecodeAll[T any](results []*QueryResult, decode ResultDecoder[T]) []*T {
 	decoded := make([]*T, 0, len(results))
 	for _, result := range results {

+ 432 - 0
modules/collector-source/pkg/collector/collector.go

@@ -86,6 +86,22 @@ func NewOpenCostMetricStore() metric.MetricStore {
 	memStore.Register(NewPodsWithReplicaSetOwnerMetricCollector())
 	memStore.Register(NewReplicaSetsWithoutOwnersMetricCollector())
 	memStore.Register(NewReplicaSetsWithRolloutMetricCollector())
+	memStore.Register(NewResourceQuotaSpecCPURequestAverageMetricCollector())
+	memStore.Register(NewResourceQuotaSpecCPURequestMaxMetricCollector())
+	memStore.Register(NewResourceQuotaSpecRAMRequestAverageMetricCollector())
+	memStore.Register(NewResourceQuotaSpecRAMRequestMaxMetricCollector())
+	memStore.Register(NewResourceQuotaSpecCPULimitAverageMetricCollector())
+	memStore.Register(NewResourceQuotaSpecCPULimitMaxMetricCollector())
+	memStore.Register(NewResourceQuotaSpecRAMLimitAverageMetricCollector())
+	memStore.Register(NewResourceQuotaSpecRAMLimitMaxMetricCollector())
+	memStore.Register(NewResourceQuotaStatusUsedCPURequestAverageMetricCollector())
+	memStore.Register(NewResourceQuotaStatusUsedCPURequestMaxMetricCollector())
+	memStore.Register(NewResourceQuotaStatusUsedRAMRequestAverageMetricCollector())
+	memStore.Register(NewResourceQuotaStatusUsedRAMRequestMaxMetricCollector())
+	memStore.Register(NewResourceQuotaStatusUsedCPULimitAverageMetricCollector())
+	memStore.Register(NewResourceQuotaStatusUsedCPULimitMaxMetricCollector())
+	memStore.Register(NewResourceQuotaStatusUsedRAMLimitAverageMetricCollector())
+	memStore.Register(NewResourceQuotaStatusUsedRAMLimitMaxMetricCollector())
 
 	return memStore
 }
@@ -1892,3 +1908,419 @@ func NewReplicaSetsWithRolloutMetricCollector() *metric.MetricCollector {
 		},
 	)
 }
+
+// avg(
+//	avg_over_time(
+//		resourcequota_spec_resource_requests{
+//			resource="cpu",
+//			unit="core",
+//			<some_custom_filter>
+//		}[1h]
+//	)
+//) by (resourcequota, namespace, uid, cluster_id)
+
+func NewResourceQuotaSpecCPURequestAverageMetricCollector() *metric.MetricCollector {
+	return metric.NewMetricCollector(
+		metric.ResourceQuotaSpecCPURequestAverageID,
+		metric.KubeResourceQuotaSpecResourceRequests,
+		[]string{
+			source.NamespaceLabel,
+			source.ResourceQuotaLabel,
+			source.UIDLabel,
+		},
+		aggregator.AverageOverTime,
+		func(labels map[string]string) bool {
+			return labels[source.ResourceLabel] == "cpu" && labels[source.UnitLabel] == "core"
+		},
+	)
+}
+
+// max(
+//	max_over_time(
+//		resourcequota_spec_resource_requests{
+//			resource="cpu",
+//			unit="core",
+//			<some_custom_filter>
+//		}[1h]
+//	)
+//) by (resourcequota, namespace, uid, cluster_id)
+
+func NewResourceQuotaSpecCPURequestMaxMetricCollector() *metric.MetricCollector {
+	return metric.NewMetricCollector(
+		metric.ResourceQuotaSpecCPURequestMaxID,
+		metric.KubeResourceQuotaSpecResourceRequests,
+		[]string{
+			source.NamespaceLabel,
+			source.ResourceQuotaLabel,
+			source.UIDLabel,
+		},
+		aggregator.MaxOverTime,
+		func(labels map[string]string) bool {
+			return labels[source.ResourceLabel] == "cpu" && labels[source.UnitLabel] == "core"
+		},
+	)
+}
+
+// avg(
+//	avg_over_time(
+//		resourcequota_spec_resource_requests{
+//			resource="memory",
+//			unit="byte",
+//			<some_custom_filter>
+//		}[1h]
+//	)
+//) by (resourcequota, namespace, uid, cluster_id)
+
+func NewResourceQuotaSpecRAMRequestAverageMetricCollector() *metric.MetricCollector {
+	return metric.NewMetricCollector(
+		metric.ResourceQuotaSpecRAMRequestAverageID,
+		metric.KubeResourceQuotaSpecResourceRequests,
+		[]string{
+			source.NamespaceLabel,
+			source.ResourceQuotaLabel,
+			source.UIDLabel,
+		},
+		aggregator.AverageOverTime,
+		func(labels map[string]string) bool {
+			return labels[source.ResourceLabel] == "memory" && labels[source.UnitLabel] == "byte"
+		},
+	)
+}
+
+// max(
+//	max_over_time(
+//		resourcequota_spec_resource_requests{
+//			resource="memory",
+//			unit="byte",
+//			<some_custom_filter>
+//		}[1h]
+//	)
+//) by (resourcequota, namespace, uid, cluster_id)
+
+func NewResourceQuotaSpecRAMRequestMaxMetricCollector() *metric.MetricCollector {
+	return metric.NewMetricCollector(
+		metric.ResourceQuotaSpecRAMRequestMaxID,
+		metric.KubeResourceQuotaSpecResourceRequests,
+		[]string{
+			source.NamespaceLabel,
+			source.ResourceQuotaLabel,
+			source.UIDLabel,
+		},
+		aggregator.MaxOverTime,
+		func(labels map[string]string) bool {
+			return labels[source.ResourceLabel] == "memory" && labels[source.UnitLabel] == "byte"
+		},
+	)
+}
+
+// avg(
+//	avg_over_time(
+//		resourcequota_spec_resource_limits{
+//			resource="cpu",
+//			unit="core",
+//			<some_custom_filter>
+//		}[1h]
+//	)
+//) by (resourcequota, namespace, uid, cluster_id)
+
+func NewResourceQuotaSpecCPULimitAverageMetricCollector() *metric.MetricCollector {
+	return metric.NewMetricCollector(
+		metric.ResourceQuotaSpecCPULimitAverageID,
+		metric.KubeResourceQuotaSpecResourceLimits,
+		[]string{
+			source.NamespaceLabel,
+			source.ResourceQuotaLabel,
+			source.UIDLabel,
+		},
+		aggregator.AverageOverTime,
+		func(labels map[string]string) bool {
+			return labels[source.ResourceLabel] == "cpu" && labels[source.UnitLabel] == "core"
+		},
+	)
+}
+
+// max(
+//	max_over_time(
+//		resourcequota_spec_resource_limits{
+//			resource="cpu",
+//			unit="core",
+//			<some_custom_filter>
+//		}[1h]
+//	)
+//) by (resourcequota, namespace, uid, cluster_id)
+
+func NewResourceQuotaSpecCPULimitMaxMetricCollector() *metric.MetricCollector {
+	return metric.NewMetricCollector(
+		metric.ResourceQuotaSpecCPULimitMaxID,
+		metric.KubeResourceQuotaSpecResourceLimits,
+		[]string{
+			source.NamespaceLabel,
+			source.ResourceQuotaLabel,
+			source.UIDLabel,
+		},
+		aggregator.MaxOverTime,
+		func(labels map[string]string) bool {
+			return labels[source.ResourceLabel] == "cpu" && labels[source.UnitLabel] == "core"
+		},
+	)
+}
+
+// avg(
+//	avg_over_time(
+//		resourcequota_spec_resource_limits{
+//			resource="memory",
+//			unit="byte",
+//			<some_custom_filter>
+//		}[1h]
+//	)
+//) by (resourcequota, namespace, uid, cluster_id)
+
+func NewResourceQuotaSpecRAMLimitAverageMetricCollector() *metric.MetricCollector {
+	return metric.NewMetricCollector(
+		metric.ResourceQuotaSpecRAMLimitAverageID,
+		metric.KubeResourceQuotaSpecResourceLimits,
+		[]string{
+			source.NamespaceLabel,
+			source.ResourceQuotaLabel,
+			source.UIDLabel,
+		},
+		aggregator.AverageOverTime,
+		func(labels map[string]string) bool {
+			return labels[source.ResourceLabel] == "memory" && labels[source.UnitLabel] == "byte"
+		},
+	)
+}
+
+// max(
+//	max_over_time(
+//		resourcequota_spec_resource_limits{
+//			resource="memory",
+//			unit="byte",
+//			<some_custom_filter>
+//		}[1h]
+//	)
+//) by (resourcequota, namespace, uid, cluster_id)
+
+func NewResourceQuotaSpecRAMLimitMaxMetricCollector() *metric.MetricCollector {
+	return metric.NewMetricCollector(
+		metric.ResourceQuotaSpecRAMLimitMaxID,
+		metric.KubeResourceQuotaSpecResourceLimits,
+		[]string{
+			source.NamespaceLabel,
+			source.ResourceQuotaLabel,
+			source.UIDLabel,
+		},
+		aggregator.MaxOverTime,
+		func(labels map[string]string) bool {
+			return labels[source.ResourceLabel] == "memory" && labels[source.UnitLabel] == "byte"
+		},
+	)
+}
+
+// avg(
+//	avg_over_time(
+//		resourcequota_status_used_resource_requests{
+//			resource="cpu",
+//			unit="core",
+//			<some_custom_filter>
+//		}[1h]
+//	)
+//) by (resourcequota, namespace, uid, cluster_id)
+
+func NewResourceQuotaStatusUsedCPURequestAverageMetricCollector() *metric.MetricCollector {
+	return metric.NewMetricCollector(
+		metric.ResourceQuotaStatusUsedCPURequestAverageID,
+		metric.KubeResourceQuotaStatusUsedResourceRequests,
+		[]string{
+			source.NamespaceLabel,
+			source.ResourceQuotaLabel,
+			source.UIDLabel,
+		},
+		aggregator.AverageOverTime,
+		func(labels map[string]string) bool {
+			return labels[source.ResourceLabel] == "cpu" && labels[source.UnitLabel] == "core"
+		},
+	)
+}
+
+// max(
+//	max_over_time(
+//		resourcequota_status_used_resource_requests{
+//			resource="cpu",
+//			unit="core",
+//			<some_custom_filter>
+//		}[1h]
+//	)
+//) by (resourcequota, namespace, uid, cluster_id)
+
+func NewResourceQuotaStatusUsedCPURequestMaxMetricCollector() *metric.MetricCollector {
+	return metric.NewMetricCollector(
+		metric.ResourceQuotaStatusUsedCPURequestMaxID,
+		metric.KubeResourceQuotaStatusUsedResourceRequests,
+		[]string{
+			source.NamespaceLabel,
+			source.ResourceQuotaLabel,
+			source.UIDLabel,
+		},
+		aggregator.MaxOverTime,
+		func(labels map[string]string) bool {
+			return labels[source.ResourceLabel] == "cpu" && labels[source.UnitLabel] == "core"
+		},
+	)
+}
+
+// avg(
+//	avg_over_time(
+//		resourcequota_status_used_resource_requests{
+//			resource="memory",
+//			unit="byte",
+//			<some_custom_filter>
+//		}[1h]
+//	)
+//) by (resourcequota, namespace, uid, cluster_id)
+
+func NewResourceQuotaStatusUsedRAMRequestAverageMetricCollector() *metric.MetricCollector {
+	return metric.NewMetricCollector(
+		metric.ResourceQuotaStatusUsedRAMRequestAverageID,
+		metric.KubeResourceQuotaStatusUsedResourceRequests,
+		[]string{
+			source.NamespaceLabel,
+			source.ResourceQuotaLabel,
+			source.UIDLabel,
+		},
+		aggregator.AverageOverTime,
+		func(labels map[string]string) bool {
+			return labels[source.ResourceLabel] == "memory" && labels[source.UnitLabel] == "byte"
+		},
+	)
+}
+
+// max(
+//	max_over_time(
+//		resourcequota_status_used_resource_requests{
+//			resource="memory",
+//			unit="byte",
+//			<some_custom_filter>
+//		}[1h]
+//	)
+//) by (resourcequota, namespace, uid, cluster_id)
+
+func NewResourceQuotaStatusUsedRAMRequestMaxMetricCollector() *metric.MetricCollector {
+	return metric.NewMetricCollector(
+		metric.ResourceQuotaStatusUsedRAMRequestMaxID,
+		metric.KubeResourceQuotaStatusUsedResourceRequests,
+		[]string{
+			source.NamespaceLabel,
+			source.ResourceQuotaLabel,
+			source.UIDLabel,
+		},
+		aggregator.MaxOverTime,
+		func(labels map[string]string) bool {
+			return labels[source.ResourceLabel] == "memory" && labels[source.UnitLabel] == "byte"
+		},
+	)
+}
+
+// avg(
+//	avg_over_time(
+//		resourcequota_status_used_resource_limits{
+//			resource="cpu",
+//			unit="core",
+//			<some_custom_filter>
+//		}[1h]
+//	)
+//) by (resourcequota, namespace, uid, cluster_id)
+
+func NewResourceQuotaStatusUsedCPULimitAverageMetricCollector() *metric.MetricCollector {
+	return metric.NewMetricCollector(
+		metric.ResourceQuotaStatusUsedCPULimitAverageID,
+		metric.KubeResourceQuotaStatusUsedResourceLimits,
+		[]string{
+			source.NamespaceLabel,
+			source.ResourceQuotaLabel,
+			source.UIDLabel,
+		},
+		aggregator.AverageOverTime,
+		func(labels map[string]string) bool {
+			return labels[source.ResourceLabel] == "cpu" && labels[source.UnitLabel] == "core"
+		},
+	)
+}
+
+// max(
+//	max_over_time(
+//		resourcequota_status_used_resource_limits{
+//			resource="cpu",
+//			unit="core",
+//			<some_custom_filter>
+//		}[1h]
+//	)
+//) by (resourcequota, namespace, uid, cluster_id)
+
+func NewResourceQuotaStatusUsedCPULimitMaxMetricCollector() *metric.MetricCollector {
+	return metric.NewMetricCollector(
+		metric.ResourceQuotaStatusUsedCPULimitMaxID,
+		metric.KubeResourceQuotaStatusUsedResourceLimits,
+		[]string{
+			source.NamespaceLabel,
+			source.ResourceQuotaLabel,
+			source.UIDLabel,
+		},
+		aggregator.MaxOverTime,
+		func(labels map[string]string) bool {
+			return labels[source.ResourceLabel] == "cpu" && labels[source.UnitLabel] == "core"
+		},
+	)
+}
+
+// avg(
+//	avg_over_time(
+//		resourcequota_status_used_resource_limits{
+//			resource="memory",
+//			unit="byte",
+//			<some_custom_filter>
+//		}[1h]
+//	)
+//) by (resourcequota, namespace, uid, cluster_id)
+
+func NewResourceQuotaStatusUsedRAMLimitAverageMetricCollector() *metric.MetricCollector {
+	return metric.NewMetricCollector(
+		metric.ResourceQuotaStatusUsedRAMLimitAverageID,
+		metric.KubeResourceQuotaStatusUsedResourceLimits,
+		[]string{
+			source.NamespaceLabel,
+			source.ResourceQuotaLabel,
+			source.UIDLabel,
+		},
+		aggregator.AverageOverTime,
+		func(labels map[string]string) bool {
+			return labels[source.ResourceLabel] == "memory" && labels[source.UnitLabel] == "byte"
+		},
+	)
+}
+
+// max(
+//	max_over_time(
+//		resourcequota_status_used_resource_limits{
+//			resource="memory",
+//			unit="byte",
+//			<some_custom_filter>
+//		}[1h]
+//	)
+//) by (resourcequota, namespace, uid, cluster_id)
+
+func NewResourceQuotaStatusUsedRAMLimitMaxMetricCollector() *metric.MetricCollector {
+	return metric.NewMetricCollector(
+		metric.ResourceQuotaStatusUsedRAMLimitMaxID,
+		metric.KubeResourceQuotaStatusUsedResourceLimits,
+		[]string{
+			source.NamespaceLabel,
+			source.ResourceQuotaLabel,
+			source.UIDLabel,
+		},
+		aggregator.MaxOverTime,
+		func(labels map[string]string) bool {
+			return labels[source.ResourceLabel] == "memory" && labels[source.UnitLabel] == "byte"
+		},
+	)
+}

+ 64 - 0
modules/collector-source/pkg/collector/metricsquerier.go

@@ -520,6 +520,70 @@ func (c *collectorMetricsQuerier) QueryReplicaSetsWithRollout(start, end time.Ti
 	return queryCollector(c, start, end, metric.ReplicaSetsWithRolloutID, source.DecodeReplicaSetsWithRolloutResult)
 }
 
+func (c *collectorMetricsQuerier) QueryResourceQuotaSpecCPURequestAverage(start, end time.Time) *source.Future[source.ResourceQuotaSpecCPURequestAvgResult] {
+	return queryCollector(c, start, end, metric.ResourceQuotaSpecCPURequestAverageID, source.DecodeResourceQuotaSpecCPURequestAvgResult)
+}
+
+func (c *collectorMetricsQuerier) QueryResourceQuotaSpecCPURequestMax(start, end time.Time) *source.Future[source.ResourceQuotaSpecCPURequestMaxResult] {
+	return queryCollector(c, start, end, metric.ResourceQuotaSpecCPURequestMaxID, source.DecodeResourceQuotaSpecCPURequestMaxResult)
+}
+
+func (c *collectorMetricsQuerier) QueryResourceQuotaSpecRAMRequestAverage(start, end time.Time) *source.Future[source.ResourceQuotaSpecRAMRequestAvgResult] {
+	return queryCollector(c, start, end, metric.ResourceQuotaSpecRAMRequestAverageID, source.DecodeResourceQuotaSpecRAMRequestAvgResult)
+}
+
+func (c *collectorMetricsQuerier) QueryResourceQuotaSpecRAMRequestMax(start, end time.Time) *source.Future[source.ResourceQuotaSpecRAMRequestMaxResult] {
+	return queryCollector(c, start, end, metric.ResourceQuotaSpecRAMRequestMaxID, source.DecodeResourceQuotaSpecRAMRequestMaxResult)
+}
+
+func (c *collectorMetricsQuerier) QueryResourceQuotaSpecCPULimitAverage(start, end time.Time) *source.Future[source.ResourceQuotaSpecCPULimitAvgResult] {
+	return queryCollector(c, start, end, metric.ResourceQuotaSpecCPULimitAverageID, source.DecodeResourceQuotaSpecCPULimitAvgResult)
+}
+
+func (c *collectorMetricsQuerier) QueryResourceQuotaSpecCPULimitMax(start, end time.Time) *source.Future[source.ResourceQuotaSpecCPULimitMaxResult] {
+	return queryCollector(c, start, end, metric.ResourceQuotaSpecCPULimitMaxID, source.DecodeResourceQuotaSpecCPULimitMaxResult)
+}
+
+func (c *collectorMetricsQuerier) QueryResourceQuotaSpecRAMLimitAverage(start, end time.Time) *source.Future[source.ResourceQuotaSpecRAMLimitAvgResult] {
+	return queryCollector(c, start, end, metric.ResourceQuotaSpecRAMLimitAverageID, source.DecodeResourceQuotaSpecRAMLimitAvgResult)
+}
+
+func (c *collectorMetricsQuerier) QueryResourceQuotaSpecRAMLimitMax(start, end time.Time) *source.Future[source.ResourceQuotaSpecRAMLimitMaxResult] {
+	return queryCollector(c, start, end, metric.ResourceQuotaSpecRAMLimitMaxID, source.DecodeResourceQuotaSpecRAMLimitMaxResult)
+}
+
+func (c *collectorMetricsQuerier) QueryResourceQuotaStatusUsedCPURequestAverage(start, end time.Time) *source.Future[source.ResourceQuotaStatusUsedCPURequestAvgResult] {
+	return queryCollector(c, start, end, metric.ResourceQuotaStatusUsedCPURequestAverageID, source.DecodeResourceQuotaStatusUsedCPURequestAvgResult)
+}
+
+func (c *collectorMetricsQuerier) QueryResourceQuotaStatusUsedCPURequestMax(start, end time.Time) *source.Future[source.ResourceQuotaStatusUsedCPURequestMaxResult] {
+	return queryCollector(c, start, end, metric.ResourceQuotaStatusUsedCPURequestMaxID, source.DecodeResourceQuotaStatusUsedCPURequestMaxResult)
+}
+
+func (c *collectorMetricsQuerier) QueryResourceQuotaStatusUsedRAMRequestAverage(start, end time.Time) *source.Future[source.ResourceQuotaStatusUsedRAMRequestAvgResult] {
+	return queryCollector(c, start, end, metric.ResourceQuotaStatusUsedRAMRequestAverageID, source.DecodeResourceQuotaStatusUsedRAMRequestAvgResult)
+}
+
+func (c *collectorMetricsQuerier) QueryResourceQuotaStatusUsedRAMRequestMax(start, end time.Time) *source.Future[source.ResourceQuotaStatusUsedRAMRequestMaxResult] {
+	return queryCollector(c, start, end, metric.ResourceQuotaStatusUsedRAMRequestMaxID, source.DecodeResourceQuotaStatusUsedRAMRequestMaxResult)
+}
+
+func (c *collectorMetricsQuerier) QueryResourceQuotaStatusUsedCPULimitAverage(start, end time.Time) *source.Future[source.ResourceQuotaStatusUsedCPULimitAvgResult] {
+	return queryCollector(c, start, end, metric.ResourceQuotaStatusUsedCPULimitAverageID, source.DecodeResourceQuotaStatusUsedCPULimitAvgResult)
+}
+
+func (c *collectorMetricsQuerier) QueryResourceQuotaStatusUsedCPULimitMax(start, end time.Time) *source.Future[source.ResourceQuotaStatusUsedCPULimitMaxResult] {
+	return queryCollector(c, start, end, metric.ResourceQuotaStatusUsedCPULimitMaxID, source.DecodeResourceQuotaStatusUsedCPULimitMaxResult)
+}
+
+func (c *collectorMetricsQuerier) QueryResourceQuotaStatusUsedRAMLimitAverage(start, end time.Time) *source.Future[source.ResourceQuotaStatusUsedRAMLimitAvgResult] {
+	return queryCollector(c, start, end, metric.ResourceQuotaStatusUsedRAMLimitAverageID, source.DecodeResourceQuotaStatusUsedRAMLimitAvgResult)
+}
+
+func (c *collectorMetricsQuerier) QueryResourceQuotaStatusUsedRAMLimitMax(start, end time.Time) *source.Future[source.ResourceQuotaStatusUsedRAMLimitMaxResult] {
+	return queryCollector(c, start, end, metric.ResourceQuotaStatusUsedRAMLimitMaxID, source.DecodeResourceQuotaStatusUsedRAMLimitMaxResult)
+}
+
 func (c *collectorMetricsQuerier) QueryDataCoverage(limitDays int) (time.Time, time.Time, error) {
 	return c.collectorProvider.GetDailyDataCoverage(limitDays)
 }

+ 10 - 9
modules/collector-source/pkg/event/scrape.go

@@ -9,15 +9,16 @@ const (
 )
 
 const (
-	NodeScraperType        = "nodes"
-	NamespaceScraperType   = "namespaces"
-	ReplicaSetScraperType  = "replicasets"
-	DeploymentScraperType  = "deployments"
-	StatefulSetScraperType = "statefulsets"
-	ServiceScraperType     = "services"
-	PodScraperType         = "pods"
-	PvScraperType          = "pvs"
-	PvcScraperType         = "pvcs"
+	NodeScraperType          = "nodes"
+	NamespaceScraperType     = "namespaces"
+	ReplicaSetScraperType    = "replicasets"
+	DeploymentScraperType    = "deployments"
+	StatefulSetScraperType   = "statefulsets"
+	ServiceScraperType       = "services"
+	PodScraperType           = "pods"
+	PvScraperType            = "pvs"
+	PvcScraperType           = "pvcs"
+	ResourceQuotaScraperType = "resourcequotas"
 )
 
 // ScrapeEvent is dispatched when a scrape is performed over a set of targets. It contains the name

+ 90 - 74
modules/collector-source/pkg/metric/collector.go

@@ -15,80 +15,96 @@ import (
 type MetricCollectorID string
 
 const (
-	PVPricePerGiBHourID             MetricCollectorID = "PVPricePerGiBHour"
-	PVUsedAverageID                 MetricCollectorID = "PVUsedAverage"
-	PVUsedMaxID                     MetricCollectorID = "PVUsedMax"
-	PVCInfoID                       MetricCollectorID = "PVCInfo"
-	PVActiveMinutesID               MetricCollectorID = "PVActiveMinutes"
-	LocalStorageUsedActiveMinutesID MetricCollectorID = "LocalStorageUsedCost"
-	LocalStorageUsedAverageID       MetricCollectorID = "LocalStorageUsedAverage"
-	LocalStorageUsedMaxID           MetricCollectorID = "LocalStorageUsedMax"
-	LocalStorageBytesID             MetricCollectorID = "LocalStorageBytesID"
-	LocalStorageActiveMinutesID     MetricCollectorID = "LocalStorageActiveMinutes"
-	NodeCPUCoresCapacityID          MetricCollectorID = "NodeCPUCoresCapacity"
-	NodeCPUCoresAllocatableID       MetricCollectorID = "NodeCPUCoresAllocatable"
-	NodeRAMBytesCapacityID          MetricCollectorID = "NodeRAMBytesCapacity"
-	NodeRAMBytesAllocatableID       MetricCollectorID = "NodeRAMBytesAllocatable"
-	NodeGPUCountID                  MetricCollectorID = "NodeGPUCount"
-	NodeLabelsID                    MetricCollectorID = "NodeLabels"
-	NodeActiveMinutesID             MetricCollectorID = "NodeActiveMinutes"
-	NodeCPUModeTotalID              MetricCollectorID = "NodeCPUModeTotal"
-	NodeRAMSystemUsageAverageID     MetricCollectorID = "NodeRAMSystemUsageAverage"
-	NodeRAMUserUsageAverageID       MetricCollectorID = "NodeRAMUserUsageAverage"
-	LBPricePerHourID                MetricCollectorID = "LBPricePerHour"
-	LBActiveMinutesID               MetricCollectorID = "LBActiveMinutes"
-	ClusterManagementDurationID     MetricCollectorID = "ClusterManagementDuration"
-	ClusterManagementPricePerHourID MetricCollectorID = "ClusterManagementPricePerHour"
-	PodActiveMinutesID              MetricCollectorID = "PodActiveMinutes"
-	RAMBytesAllocatedID             MetricCollectorID = "RAMBytesAllocated"
-	RAMRequestsID                   MetricCollectorID = "RAMRequests"
-	RAMLimitsID                     MetricCollectorID = "RAMLimits"
-	RAMUsageAverageID               MetricCollectorID = "RAMUsageAverage"
-	RAMUsageMaxID                   MetricCollectorID = "RAMUsageMax"
-	CPUCoresAllocatedID             MetricCollectorID = "CPUCoresAllocated"
-	CPURequestsID                   MetricCollectorID = "CPURequestsID"
-	CPULimitsID                     MetricCollectorID = "CPULimitsID"
-	CPUUsageAverageID               MetricCollectorID = "CPUUsageAverage"
-	CPUUsageMaxID                   MetricCollectorID = "CPUUsageMax"
-	GPUsRequestedID                 MetricCollectorID = "GPUsRequested"
-	GPUsUsageAverageID              MetricCollectorID = "GPUsUsageAverage"
-	GPUsUsageMaxID                  MetricCollectorID = "GPUsUsageMax"
-	GPUsAllocatedID                 MetricCollectorID = "GPUsAllocated"
-	IsGPUSharedID                   MetricCollectorID = "IsGPUShared"
-	GPUInfoID                       MetricCollectorID = "GPUInfo"
-	NodeCPUPricePerHourID           MetricCollectorID = "NodeCPUPricePerHour"
-	NodeRAMPricePerGiBHourID        MetricCollectorID = "NodeRAMPricePerGiBHour"
-	NodeGPUPricePerHourID           MetricCollectorID = "NodeGPUPricePerHour"
-	NodeIsSpotID                    MetricCollectorID = "NodeIsSpot"
-	PodPVCAllocationID              MetricCollectorID = "PodPVCAllocation"
-	PVCBytesRequestedID             MetricCollectorID = "PVCBytesRequested"
-	PVBytesID                       MetricCollectorID = "PVBytesID"
-	PVInfoID                        MetricCollectorID = "PVInfo"
-	NetZoneGiBID                    MetricCollectorID = "NetZoneGiB"
-	NetZonePricePerGiBID            MetricCollectorID = "NetZonePricePerGiB"
-	NetRegionGiBID                  MetricCollectorID = "NetRegionGiB"
-	NetRegionPricePerGiBID          MetricCollectorID = "NetRegionPricePerGiB"
-	NetInternetGiBID                MetricCollectorID = "NetInternetGiB"
-	NetInternetPricePerGiBID        MetricCollectorID = "NetInternetPricePerGiB"
-	NetInternetServiceGiBID         MetricCollectorID = "NetInternetServiceGiB"
-	NetTransferBytesID              MetricCollectorID = "NetTransferBytes"
-	NetZoneIngressGiBID             MetricCollectorID = "NetZoneIngressGiB"
-	NetRegionIngressGiBID           MetricCollectorID = "NetRegionIngressGiB"
-	NetInternetIngressGiBID         MetricCollectorID = "NetInternetIngressGiB"
-	NetInternetServiceIngressGiBID  MetricCollectorID = "NetInternetServiceIngressGiB"
-	NetReceiveBytesID               MetricCollectorID = "NetReceiveBytes"
-	NamespaceLabelsID               MetricCollectorID = "NamespaceLabels"
-	NamespaceAnnotationsID          MetricCollectorID = "NamespaceAnnotations"
-	PodLabelsID                     MetricCollectorID = "PodLabels"
-	PodAnnotationsID                MetricCollectorID = "PodAnnotations"
-	ServiceLabelsID                 MetricCollectorID = "ServiceLabels"
-	DeploymentLabelsID              MetricCollectorID = "DeploymentLabels"
-	StatefulSetLabelsID             MetricCollectorID = "StatefulSetLabels"
-	DaemonSetLabelsID               MetricCollectorID = "DaemonSetLabels"
-	JobLabelsID                     MetricCollectorID = "JobLabels"
-	PodsWithReplicaSetOwnerID       MetricCollectorID = "PodsWithReplicaSetOwner"
-	ReplicaSetsWithoutOwnersID      MetricCollectorID = "ReplicaSetsWithoutOwners"
-	ReplicaSetsWithRolloutID        MetricCollectorID = "ReplicaSetsWithRollout"
+	PVPricePerGiBHourID                        MetricCollectorID = "PVPricePerGiBHour"
+	PVUsedAverageID                            MetricCollectorID = "PVUsedAverage"
+	PVUsedMaxID                                MetricCollectorID = "PVUsedMax"
+	PVCInfoID                                  MetricCollectorID = "PVCInfo"
+	PVActiveMinutesID                          MetricCollectorID = "PVActiveMinutes"
+	LocalStorageUsedActiveMinutesID            MetricCollectorID = "LocalStorageUsedCost"
+	LocalStorageUsedAverageID                  MetricCollectorID = "LocalStorageUsedAverage"
+	LocalStorageUsedMaxID                      MetricCollectorID = "LocalStorageUsedMax"
+	LocalStorageBytesID                        MetricCollectorID = "LocalStorageBytesID"
+	LocalStorageActiveMinutesID                MetricCollectorID = "LocalStorageActiveMinutes"
+	NodeCPUCoresCapacityID                     MetricCollectorID = "NodeCPUCoresCapacity"
+	NodeCPUCoresAllocatableID                  MetricCollectorID = "NodeCPUCoresAllocatable"
+	NodeRAMBytesCapacityID                     MetricCollectorID = "NodeRAMBytesCapacity"
+	NodeRAMBytesAllocatableID                  MetricCollectorID = "NodeRAMBytesAllocatable"
+	NodeGPUCountID                             MetricCollectorID = "NodeGPUCount"
+	NodeLabelsID                               MetricCollectorID = "NodeLabels"
+	NodeActiveMinutesID                        MetricCollectorID = "NodeActiveMinutes"
+	NodeCPUModeTotalID                         MetricCollectorID = "NodeCPUModeTotal"
+	NodeRAMSystemUsageAverageID                MetricCollectorID = "NodeRAMSystemUsageAverage"
+	NodeRAMUserUsageAverageID                  MetricCollectorID = "NodeRAMUserUsageAverage"
+	LBPricePerHourID                           MetricCollectorID = "LBPricePerHour"
+	LBActiveMinutesID                          MetricCollectorID = "LBActiveMinutes"
+	ClusterManagementDurationID                MetricCollectorID = "ClusterManagementDuration"
+	ClusterManagementPricePerHourID            MetricCollectorID = "ClusterManagementPricePerHour"
+	PodActiveMinutesID                         MetricCollectorID = "PodActiveMinutes"
+	RAMBytesAllocatedID                        MetricCollectorID = "RAMBytesAllocated"
+	RAMRequestsID                              MetricCollectorID = "RAMRequests"
+	RAMLimitsID                                MetricCollectorID = "RAMLimits"
+	RAMUsageAverageID                          MetricCollectorID = "RAMUsageAverage"
+	RAMUsageMaxID                              MetricCollectorID = "RAMUsageMax"
+	CPUCoresAllocatedID                        MetricCollectorID = "CPUCoresAllocated"
+	CPURequestsID                              MetricCollectorID = "CPURequestsID"
+	CPULimitsID                                MetricCollectorID = "CPULimitsID"
+	CPUUsageAverageID                          MetricCollectorID = "CPUUsageAverage"
+	CPUUsageMaxID                              MetricCollectorID = "CPUUsageMax"
+	GPUsRequestedID                            MetricCollectorID = "GPUsRequested"
+	GPUsUsageAverageID                         MetricCollectorID = "GPUsUsageAverage"
+	GPUsUsageMaxID                             MetricCollectorID = "GPUsUsageMax"
+	GPUsAllocatedID                            MetricCollectorID = "GPUsAllocated"
+	IsGPUSharedID                              MetricCollectorID = "IsGPUShared"
+	GPUInfoID                                  MetricCollectorID = "GPUInfo"
+	NodeCPUPricePerHourID                      MetricCollectorID = "NodeCPUPricePerHour"
+	NodeRAMPricePerGiBHourID                   MetricCollectorID = "NodeRAMPricePerGiBHour"
+	NodeGPUPricePerHourID                      MetricCollectorID = "NodeGPUPricePerHour"
+	NodeIsSpotID                               MetricCollectorID = "NodeIsSpot"
+	PodPVCAllocationID                         MetricCollectorID = "PodPVCAllocation"
+	PVCBytesRequestedID                        MetricCollectorID = "PVCBytesRequested"
+	PVBytesID                                  MetricCollectorID = "PVBytesID"
+	PVInfoID                                   MetricCollectorID = "PVInfo"
+	NetZoneGiBID                               MetricCollectorID = "NetZoneGiB"
+	NetZonePricePerGiBID                       MetricCollectorID = "NetZonePricePerGiB"
+	NetRegionGiBID                             MetricCollectorID = "NetRegionGiB"
+	NetRegionPricePerGiBID                     MetricCollectorID = "NetRegionPricePerGiB"
+	NetInternetGiBID                           MetricCollectorID = "NetInternetGiB"
+	NetInternetPricePerGiBID                   MetricCollectorID = "NetInternetPricePerGiB"
+	NetInternetServiceGiBID                    MetricCollectorID = "NetInternetServiceGiB"
+	NetTransferBytesID                         MetricCollectorID = "NetTransferBytes"
+	NetZoneIngressGiBID                        MetricCollectorID = "NetZoneIngressGiB"
+	NetRegionIngressGiBID                      MetricCollectorID = "NetRegionIngressGiB"
+	NetInternetIngressGiBID                    MetricCollectorID = "NetInternetIngressGiB"
+	NetInternetServiceIngressGiBID             MetricCollectorID = "NetInternetServiceIngressGiB"
+	NetReceiveBytesID                          MetricCollectorID = "NetReceiveBytes"
+	NamespaceLabelsID                          MetricCollectorID = "NamespaceLabels"
+	NamespaceAnnotationsID                     MetricCollectorID = "NamespaceAnnotations"
+	PodLabelsID                                MetricCollectorID = "PodLabels"
+	PodAnnotationsID                           MetricCollectorID = "PodAnnotations"
+	ServiceLabelsID                            MetricCollectorID = "ServiceLabels"
+	DeploymentLabelsID                         MetricCollectorID = "DeploymentLabels"
+	StatefulSetLabelsID                        MetricCollectorID = "StatefulSetLabels"
+	DaemonSetLabelsID                          MetricCollectorID = "DaemonSetLabels"
+	JobLabelsID                                MetricCollectorID = "JobLabels"
+	PodsWithReplicaSetOwnerID                  MetricCollectorID = "PodsWithReplicaSetOwner"
+	ReplicaSetsWithoutOwnersID                 MetricCollectorID = "ReplicaSetsWithoutOwners"
+	ReplicaSetsWithRolloutID                   MetricCollectorID = "ReplicaSetsWithRollout"
+	ResourceQuotaSpecCPURequestAverageID       MetricCollectorID = "ResourceQuotaSpecCPURequestAverage"
+	ResourceQuotaSpecCPURequestMaxID           MetricCollectorID = "ResourceQuotaSpecCPURequestMax"
+	ResourceQuotaSpecRAMRequestAverageID       MetricCollectorID = "ResourceQuotaSpecRAMRequestAverage"
+	ResourceQuotaSpecRAMRequestMaxID           MetricCollectorID = "ResourceQuotaSpecRAMRequestMax"
+	ResourceQuotaSpecCPULimitAverageID         MetricCollectorID = "ResourceQuotaSpecCPULimitAverage"
+	ResourceQuotaSpecCPULimitMaxID             MetricCollectorID = "ResourceQuotaSpecCPULimitMax"
+	ResourceQuotaSpecRAMLimitAverageID         MetricCollectorID = "ResourceQuotaSpecRAMLimitAverage"
+	ResourceQuotaSpecRAMLimitMaxID             MetricCollectorID = "ResourceQuotaSpecRAMLimitMax"
+	ResourceQuotaStatusUsedCPURequestAverageID MetricCollectorID = "ResourceQuotaStatusUsedCPURequestAverage"
+	ResourceQuotaStatusUsedCPURequestMaxID     MetricCollectorID = "ResourceQuotaStatusUsedCPURequestMax"
+	ResourceQuotaStatusUsedRAMRequestAverageID MetricCollectorID = "ResourceQuotaStatusUsedRAMRequestAverage"
+	ResourceQuotaStatusUsedRAMRequestMaxID     MetricCollectorID = "ResourceQuotaStatusUsedRAMRequestMax"
+	ResourceQuotaStatusUsedCPULimitAverageID   MetricCollectorID = "ResourceQuotaStatusUsedCPULimitAverage"
+	ResourceQuotaStatusUsedCPULimitMaxID       MetricCollectorID = "ResourceQuotaStatusUsedCPULimitMax"
+	ResourceQuotaStatusUsedRAMLimitAverageID   MetricCollectorID = "ResourceQuotaStatusUsedRAMLimitAverage"
+	ResourceQuotaStatusUsedRAMLimitMaxID       MetricCollectorID = "ResourceQuotaStatusUsedRAMLimitMax"
 )
 
 // MetricCollector is a data structure that represents a specific MetricCollector metric instance that contains its own breakdown

+ 4 - 0
modules/collector-source/pkg/metric/metrics.go

@@ -23,6 +23,10 @@ const (
 	ServiceSelectorLabels                                 = "service_selector_labels"
 	StatefulSetMatchLabels                                = "statefulSet_match_labels"
 	KubeReplicasetOwner                                   = "kube_replicaset_owner"
+	KubeResourceQuotaSpecResourceRequests                 = "resourcequota_spec_resource_requests"
+	KubeResourceQuotaSpecResourceLimits                   = "resourcequota_spec_resource_limits"
+	KubeResourceQuotaStatusUsedResourceRequests           = "resourcequota_status_used_resource_requests"
+	KubeResourceQuotaStatusUsedResourceLimits             = "resourcequota_status_used_resource_limits"
 
 	// DCGM Metrics
 	DCGMFIPROFGRENGINEACTIVE = "DCGM_FI_PROF_GR_ENGINE_ACTIVE"

+ 80 - 0
modules/collector-source/pkg/scrape/clustercache.go

@@ -40,6 +40,7 @@ func (ccs *ClusterCacheScraper) Scrape() []metric.Update {
 		ccs.ScrapeServices,
 		ccs.ScrapeStatefulSets,
 		ccs.ScrapeReplicaSets,
+		ccs.ScrapeResourceQuotas,
 	}
 	return concurrentScrape(scrapeFuncs...)
 }
@@ -538,6 +539,85 @@ func (ccs *ClusterCacheScraper) scrapeReplicaSets(replicaSets []*clustercache.Re
 	return scrapeResults
 }
 
+func (ccs *ClusterCacheScraper) ScrapeResourceQuotas() []metric.Update {
+	resourceQuotas := ccs.clusterCache.GetAllResourceQuotas()
+	return ccs.scrapeResourceQuotas(resourceQuotas)
+}
+
+func (ccs *ClusterCacheScraper) scrapeResourceQuotas(resourceQuotas []*clustercache.ResourceQuota) []metric.Update {
+	var scrapeResults []metric.Update
+
+	processResource := func(baseLabels map[string]string, name v1.ResourceName, quantity resource.Quantity, metricName string) metric.Update {
+		resource, unit, value := toResourceUnitValue(name, quantity)
+
+		labels := maps.Clone(baseLabels)
+		labels[source.ResourceLabel] = resource
+		labels[source.UnitLabel] = unit
+
+		return metric.Update{
+			Name:   metricName,
+			Labels: labels,
+			Value:  value,
+		}
+	}
+
+	for _, resourceQuota := range resourceQuotas {
+		resourceQuotaInfo := map[string]string{
+			source.ResourceQuotaLabel: resourceQuota.Name,
+			source.NamespaceLabel:     resourceQuota.Namespace,
+			source.UIDLabel:           string(resourceQuota.UID),
+		}
+
+		if resourceQuota.Spec.Hard != nil {
+			// CPU/memory requests can also be aliased as "cpu" and "memory". For now, however, only scrape the complete names
+			// https://kubernetes.io/docs/concepts/policy/resource-quotas/#compute-resource-quota
+
+			if quantity, ok := resourceQuota.Spec.Hard[v1.ResourceRequestsCPU]; ok {
+				scrapeResults = append(scrapeResults, processResource(resourceQuotaInfo, v1.ResourceCPU, quantity, metric.KubeResourceQuotaSpecResourceRequests))
+			}
+
+			if quantity, ok := resourceQuota.Spec.Hard[v1.ResourceRequestsMemory]; ok {
+				scrapeResults = append(scrapeResults, processResource(resourceQuotaInfo, v1.ResourceMemory, quantity, metric.KubeResourceQuotaSpecResourceRequests))
+			}
+
+			if quantity, ok := resourceQuota.Spec.Hard[v1.ResourceLimitsCPU]; ok {
+				scrapeResults = append(scrapeResults, processResource(resourceQuotaInfo, v1.ResourceCPU, quantity, metric.KubeResourceQuotaSpecResourceLimits))
+			}
+
+			if quantity, ok := resourceQuota.Spec.Hard[v1.ResourceLimitsMemory]; ok {
+				scrapeResults = append(scrapeResults, processResource(resourceQuotaInfo, v1.ResourceMemory, quantity, metric.KubeResourceQuotaSpecResourceLimits))
+			}
+		}
+
+		if resourceQuota.Status.Used != nil {
+			if quantity, ok := resourceQuota.Status.Used[v1.ResourceRequestsCPU]; ok {
+				scrapeResults = append(scrapeResults, processResource(resourceQuotaInfo, v1.ResourceCPU, quantity, metric.KubeResourceQuotaStatusUsedResourceRequests))
+			}
+
+			if quantity, ok := resourceQuota.Status.Used[v1.ResourceRequestsMemory]; ok {
+				scrapeResults = append(scrapeResults, processResource(resourceQuotaInfo, v1.ResourceMemory, quantity, metric.KubeResourceQuotaStatusUsedResourceRequests))
+			}
+
+			if quantity, ok := resourceQuota.Status.Used[v1.ResourceLimitsCPU]; ok {
+				scrapeResults = append(scrapeResults, processResource(resourceQuotaInfo, v1.ResourceCPU, quantity, metric.KubeResourceQuotaStatusUsedResourceLimits))
+			}
+
+			if quantity, ok := resourceQuota.Status.Used[v1.ResourceLimitsMemory]; ok {
+				scrapeResults = append(scrapeResults, processResource(resourceQuotaInfo, v1.ResourceMemory, quantity, metric.KubeResourceQuotaStatusUsedResourceLimits))
+			}
+		}
+	}
+
+	events.Dispatch(event.ScrapeEvent{
+		ScraperName: event.KubernetesClusterScraperName,
+		ScrapeType:  event.ResourceQuotaScraperType,
+		Targets:     len(resourceQuotas),
+		Errors:      nil,
+	})
+
+	return scrapeResults
+}
+
 // getPersistentVolumeClaimClass returns StorageClassName. If no storage class was
 // requested, it returns "".
 func getPersistentVolumeClaimClass(claim *clustercache.PersistentVolumeClaim) string {

+ 166 - 0
modules/collector-source/pkg/scrape/clustercache_test.go

@@ -912,3 +912,169 @@ func Test_kubernetesScraper_scrapeReplicaSets(t *testing.T) {
 		})
 	}
 }
+
+func Test_kubernetesScraper_scrapeResourceQuotas(t *testing.T) {
+	start1, _ := time.Parse(time.RFC3339, Start1Str)
+
+	type scrape struct {
+		ResourceQuotas []*clustercache.ResourceQuota
+		Timestamp      time.Time
+	}
+	tests := []struct {
+		name     string
+		scrapes  []scrape
+		expected []metric.Update
+	}{
+		{
+			name: "simple",
+			scrapes: []scrape{
+				{
+					ResourceQuotas: []*clustercache.ResourceQuota{
+						{
+							Name:      "resourceQuota1",
+							Namespace: "namespace1",
+							UID:       "uuid1",
+							Spec: v1.ResourceQuotaSpec{
+								Hard: v1.ResourceList{
+									v1.ResourceRequestsCPU:    resource.MustParse("1"),
+									v1.ResourceRequestsMemory: resource.MustParse("1024"),
+									v1.ResourceLimitsCPU:      resource.MustParse("2"),
+									v1.ResourceLimitsMemory:   resource.MustParse("2048"),
+								},
+							},
+							Status: v1.ResourceQuotaStatus{
+								Used: v1.ResourceList{
+									v1.ResourceRequestsCPU:    resource.MustParse("0.5"),
+									v1.ResourceRequestsMemory: resource.MustParse("512"),
+									v1.ResourceLimitsCPU:      resource.MustParse("1"),
+									v1.ResourceLimitsMemory:   resource.MustParse("1024"),
+								},
+							},
+						},
+					},
+					Timestamp: start1,
+				},
+			},
+			expected: []metric.Update{
+				{
+					Name: metric.KubeResourceQuotaSpecResourceRequests,
+					Labels: map[string]string{
+						source.ResourceQuotaLabel: "resourceQuota1",
+						source.NamespaceLabel:     "namespace1",
+						source.UIDLabel:           "uuid1",
+						source.ResourceLabel:      "cpu",
+						source.UnitLabel:          "core",
+					},
+					Value:          1,
+					AdditionalInfo: nil,
+				},
+				{
+					Name: metric.KubeResourceQuotaSpecResourceRequests,
+					Labels: map[string]string{
+						source.ResourceQuotaLabel: "resourceQuota1",
+						source.NamespaceLabel:     "namespace1",
+						source.UIDLabel:           "uuid1",
+						source.ResourceLabel:      "memory",
+						source.UnitLabel:          "byte",
+					},
+					Value:          1024,
+					AdditionalInfo: nil,
+				},
+				{
+					Name: metric.KubeResourceQuotaSpecResourceLimits,
+					Labels: map[string]string{
+						source.ResourceQuotaLabel: "resourceQuota1",
+						source.NamespaceLabel:     "namespace1",
+						source.UIDLabel:           "uuid1",
+						source.ResourceLabel:      "cpu",
+						source.UnitLabel:          "core",
+					},
+					Value:          2,
+					AdditionalInfo: nil,
+				},
+				{
+					Name: metric.KubeResourceQuotaSpecResourceLimits,
+					Labels: map[string]string{
+						source.ResourceQuotaLabel: "resourceQuota1",
+						source.NamespaceLabel:     "namespace1",
+						source.UIDLabel:           "uuid1",
+						source.ResourceLabel:      "memory",
+						source.UnitLabel:          "byte",
+					},
+					Value:          2048,
+					AdditionalInfo: nil,
+				},
+				{
+					Name: metric.KubeResourceQuotaStatusUsedResourceRequests,
+					Labels: map[string]string{
+						source.ResourceQuotaLabel: "resourceQuota1",
+						source.NamespaceLabel:     "namespace1",
+						source.UIDLabel:           "uuid1",
+						source.ResourceLabel:      "cpu",
+						source.UnitLabel:          "core",
+					},
+					Value:          0.5,
+					AdditionalInfo: nil,
+				},
+				{
+					Name: metric.KubeResourceQuotaStatusUsedResourceRequests,
+					Labels: map[string]string{
+						source.ResourceQuotaLabel: "resourceQuota1",
+						source.NamespaceLabel:     "namespace1",
+						source.UIDLabel:           "uuid1",
+						source.ResourceLabel:      "memory",
+						source.UnitLabel:          "byte",
+					},
+					Value:          512,
+					AdditionalInfo: nil,
+				},
+				{
+					Name: metric.KubeResourceQuotaStatusUsedResourceLimits,
+					Labels: map[string]string{
+						source.ResourceQuotaLabel: "resourceQuota1",
+						source.NamespaceLabel:     "namespace1",
+						source.UIDLabel:           "uuid1",
+						source.ResourceLabel:      "cpu",
+						source.UnitLabel:          "core",
+					},
+					Value:          1,
+					AdditionalInfo: nil,
+				},
+				{
+					Name: metric.KubeResourceQuotaStatusUsedResourceLimits,
+					Labels: map[string]string{
+						source.ResourceQuotaLabel: "resourceQuota1",
+						source.NamespaceLabel:     "namespace1",
+						source.UIDLabel:           "uuid1",
+						source.ResourceLabel:      "memory",
+						source.UnitLabel:          "byte",
+					},
+					Value:          1024,
+					AdditionalInfo: nil,
+				},
+			},
+		},
+	}
+
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			ks := &ClusterCacheScraper{}
+			var scrapeResults []metric.Update
+			for _, s := range tt.scrapes {
+				res := ks.scrapeResourceQuotas(s.ResourceQuotas)
+				scrapeResults = append(scrapeResults, res...)
+			}
+
+			if len(scrapeResults) != len(tt.expected) {
+				t.Errorf("Expected result length of %d, got %d", len(tt.expected), len(scrapeResults))
+			}
+
+			for i, expected := range tt.expected {
+				got := scrapeResults[i]
+				if !reflect.DeepEqual(expected, got) {
+					t.Errorf("Result did not match expected at index %d: got %v, want %v", i, got, expected)
+				}
+			}
+		})
+	}
+}

+ 290 - 0
modules/prometheus-source/pkg/prom/metricsquerier.go

@@ -1484,6 +1484,296 @@ func (pds *PrometheusMetricsQuerier) QueryReplicaSetsWithRollout(start, end time
 	return source.NewFuture(source.DecodeReplicaSetsWithRolloutResult, ctx.QueryAtTime(queryReplicaSetsWithRolloutOwner, end))
 }
 
+// Note: The ResourceQuota metrics are _not_ emitted at the moment. Leaving the query implementations here in case we add metric emission later on.
+
+func (pds *PrometheusMetricsQuerier) QueryResourceQuotaSpecCPURequestAverage(start, end time.Time) *source.Future[source.ResourceQuotaSpecCPURequestAvgResult] {
+	const queryName = "QueryResourceQuotaSpecCPURequestAverage"
+	const queryFmtResourceQuotaSpecCPURequests = `avg(avg_over_time(resourcequota_spec_resource_requests{resource="cpu",unit="core", %s}[%s])) by (resourcequota, namespace, uid, %s)`
+
+	cfg := pds.promConfig
+
+	durStr := timeutil.DurationString(end.Sub(start))
+	if durStr == "" {
+		panic(fmt.Sprintf("failed to parse duration string passed to %s", queryName))
+	}
+
+	queryResourceQuotaSpecCPURequests := fmt.Sprintf(queryFmtResourceQuotaSpecCPURequests, cfg.ClusterFilter, durStr, cfg.ClusterLabel)
+	log.Debugf(PrometheusMetricsQueryLogFormat, queryName, end.Unix(), queryResourceQuotaSpecCPURequests)
+
+	ctx := pds.promContexts.NewNamedContext(AllocationContextName)
+	return source.NewFuture(source.DecodeResourceQuotaSpecCPURequestAvgResult, ctx.QueryAtTime(queryResourceQuotaSpecCPURequests, end))
+}
+
+func (pds *PrometheusMetricsQuerier) QueryResourceQuotaSpecCPURequestMax(start, end time.Time) *source.Future[source.ResourceQuotaSpecCPURequestMaxResult] {
+	const queryName = "QueryResourceQuotaSpecCPURequestMax"
+	const queryFmtResourceQuotaSpecCPURequests = `max(max_over_time(resourcequota_spec_resource_requests{resource="cpu",unit="core", %s}[%s])) by (resourcequota, namespace, uid, %s)`
+
+	cfg := pds.promConfig
+
+	durStr := timeutil.DurationString(end.Sub(start))
+	if durStr == "" {
+		panic(fmt.Sprintf("failed to parse duration string passed to %s", queryName))
+	}
+
+	queryResourceQuotaSpecCPURequests := fmt.Sprintf(queryFmtResourceQuotaSpecCPURequests, cfg.ClusterFilter, durStr, cfg.ClusterLabel)
+	log.Debugf(PrometheusMetricsQueryLogFormat, queryName, end.Unix(), queryResourceQuotaSpecCPURequests)
+
+	ctx := pds.promContexts.NewNamedContext(AllocationContextName)
+	return source.NewFuture(source.DecodeResourceQuotaSpecCPURequestMaxResult, ctx.QueryAtTime(queryResourceQuotaSpecCPURequests, end))
+}
+
+func (pds *PrometheusMetricsQuerier) QueryResourceQuotaSpecRAMRequestAverage(start, end time.Time) *source.Future[source.ResourceQuotaSpecRAMRequestAvgResult] {
+	const queryName = "QueryResourceQuotaSpecRAMRequestAverage"
+	const queryFmtResourceQuotaSpecRAMRequests = `avg(avg_over_time(resourcequota_spec_resource_requests{resource="memory",unit="byte", %s}[%s])) by (resourcequota, namespace, uid, %s)`
+
+	cfg := pds.promConfig
+
+	durStr := timeutil.DurationString(end.Sub(start))
+	if durStr == "" {
+		panic(fmt.Sprintf("failed to parse duration string passed to %s", queryName))
+	}
+
+	queryResourceQuotaSpecRAMRequests := fmt.Sprintf(queryFmtResourceQuotaSpecRAMRequests, cfg.ClusterFilter, durStr, cfg.ClusterLabel)
+	log.Debugf(PrometheusMetricsQueryLogFormat, queryName, end.Unix(), queryResourceQuotaSpecRAMRequests)
+
+	ctx := pds.promContexts.NewNamedContext(AllocationContextName)
+	return source.NewFuture(source.DecodeResourceQuotaSpecRAMRequestAvgResult, ctx.QueryAtTime(queryResourceQuotaSpecRAMRequests, end))
+}
+
+func (pds *PrometheusMetricsQuerier) QueryResourceQuotaSpecRAMRequestMax(start, end time.Time) *source.Future[source.ResourceQuotaSpecRAMRequestMaxResult] {
+	const queryName = "QueryResourceQuotaSpecRAMRequestMax"
+	const queryFmtResourceQuotaSpecRAMRequests = `max(max_over_time(resourcequota_spec_resource_requests{resource="memory",unit="byte", %s}[%s])) by (resourcequota, namespace, uid, %s)`
+
+	cfg := pds.promConfig
+
+	durStr := timeutil.DurationString(end.Sub(start))
+	if durStr == "" {
+		panic(fmt.Sprintf("failed to parse duration string passed to %s", queryName))
+	}
+
+	queryResourceQuotaSpecRAMRequests := fmt.Sprintf(queryFmtResourceQuotaSpecRAMRequests, cfg.ClusterFilter, durStr, cfg.ClusterLabel)
+	log.Debugf(PrometheusMetricsQueryLogFormat, queryName, end.Unix(), queryResourceQuotaSpecRAMRequests)
+
+	ctx := pds.promContexts.NewNamedContext(AllocationContextName)
+	return source.NewFuture(source.DecodeResourceQuotaSpecRAMRequestMaxResult, ctx.QueryAtTime(queryResourceQuotaSpecRAMRequests, end))
+}
+
+func (pds *PrometheusMetricsQuerier) QueryResourceQuotaSpecCPULimitAverage(start, end time.Time) *source.Future[source.ResourceQuotaSpecCPULimitAvgResult] {
+	const queryName = "QueryResourceQuotaSpecCPULimitAverage"
+	const queryFmtResourceQuotaSpecCPULimits = `avg(avg_over_time(resourcequota_spec_resource_limits{resource="cpu",unit="core", %s}[%s])) by (resourcequota, namespace, uid, %s)`
+
+	cfg := pds.promConfig
+
+	durStr := timeutil.DurationString(end.Sub(start))
+	if durStr == "" {
+		panic(fmt.Sprintf("failed to parse duration string passed to %s", queryName))
+	}
+
+	queryResourceQuotaSpecCPULimits := fmt.Sprintf(queryFmtResourceQuotaSpecCPULimits, cfg.ClusterFilter, durStr, cfg.ClusterLabel)
+	log.Debugf(PrometheusMetricsQueryLogFormat, queryName, end.Unix(), queryResourceQuotaSpecCPULimits)
+
+	ctx := pds.promContexts.NewNamedContext(AllocationContextName)
+	return source.NewFuture(source.DecodeResourceQuotaSpecCPULimitAvgResult, ctx.QueryAtTime(queryResourceQuotaSpecCPULimits, end))
+}
+
+func (pds *PrometheusMetricsQuerier) QueryResourceQuotaSpecCPULimitMax(start, end time.Time) *source.Future[source.ResourceQuotaSpecCPULimitMaxResult] {
+	const queryName = "QueryResourceQuotaSpecCPULimitMax"
+	const queryFmtResourceQuotaSpecCPULimits = `max(max_over_time(resourcequota_spec_resource_limits{resource="cpu",unit="core", %s}[%s])) by (resourcequota, namespace, uid, %s)`
+
+	cfg := pds.promConfig
+
+	durStr := timeutil.DurationString(end.Sub(start))
+	if durStr == "" {
+		panic(fmt.Sprintf("failed to parse duration string passed to %s", queryName))
+	}
+
+	queryResourceQuotaSpecCPULimits := fmt.Sprintf(queryFmtResourceQuotaSpecCPULimits, cfg.ClusterFilter, durStr, cfg.ClusterLabel)
+	log.Debugf(PrometheusMetricsQueryLogFormat, queryName, end.Unix(), queryResourceQuotaSpecCPULimits)
+
+	ctx := pds.promContexts.NewNamedContext(AllocationContextName)
+	return source.NewFuture(source.DecodeResourceQuotaSpecCPULimitMaxResult, ctx.QueryAtTime(queryResourceQuotaSpecCPULimits, end))
+}
+
+func (pds *PrometheusMetricsQuerier) QueryResourceQuotaSpecRAMLimitAverage(start, end time.Time) *source.Future[source.ResourceQuotaSpecRAMLimitAvgResult] {
+	const queryName = "QueryResourceQuotaSpecRAMLimitAverage"
+	const queryFmtResourceQuotaSpecRAMLimits = `avg(avg_over_time(resourcequota_spec_resource_limits{resource="memory",unit="byte", %s}[%s])) by (resourcequota, namespace, uid, %s)`
+
+	cfg := pds.promConfig
+
+	durStr := timeutil.DurationString(end.Sub(start))
+	if durStr == "" {
+		panic(fmt.Sprintf("failed to parse duration string passed to %s", queryName))
+	}
+
+	queryResourceQuotaSpecRAMLimits := fmt.Sprintf(queryFmtResourceQuotaSpecRAMLimits, cfg.ClusterFilter, durStr, cfg.ClusterLabel)
+	log.Debugf(PrometheusMetricsQueryLogFormat, queryName, end.Unix(), queryResourceQuotaSpecRAMLimits)
+
+	ctx := pds.promContexts.NewNamedContext(AllocationContextName)
+	return source.NewFuture(source.DecodeResourceQuotaSpecRAMLimitAvgResult, ctx.QueryAtTime(queryResourceQuotaSpecRAMLimits, end))
+}
+
+func (pds *PrometheusMetricsQuerier) QueryResourceQuotaSpecRAMLimitMax(start, end time.Time) *source.Future[source.ResourceQuotaSpecRAMLimitMaxResult] {
+	const queryName = "QueryResourceQuotaSpecRAMLimitMax"
+	const queryFmtResourceQuotaSpecRAMLimits = `max(max_over_time(resourcequota_spec_resource_limits{resource="memory",unit="byte", %s}[%s])) by (resourcequota, namespace, uid, %s)`
+
+	cfg := pds.promConfig
+
+	durStr := timeutil.DurationString(end.Sub(start))
+	if durStr == "" {
+		panic(fmt.Sprintf("failed to parse duration string passed to %s", queryName))
+	}
+
+	queryResourceQuotaSpecRAMLimits := fmt.Sprintf(queryFmtResourceQuotaSpecRAMLimits, cfg.ClusterFilter, durStr, cfg.ClusterLabel)
+	log.Debugf(PrometheusMetricsQueryLogFormat, queryName, end.Unix(), queryResourceQuotaSpecRAMLimits)
+
+	ctx := pds.promContexts.NewNamedContext(AllocationContextName)
+	return source.NewFuture(source.DecodeResourceQuotaSpecRAMLimitMaxResult, ctx.QueryAtTime(queryResourceQuotaSpecRAMLimits, end))
+}
+
+func (pds *PrometheusMetricsQuerier) QueryResourceQuotaStatusUsedCPURequestAverage(start, end time.Time) *source.Future[source.ResourceQuotaStatusUsedCPURequestAvgResult] {
+	const queryName = "QueryResourceQuotaStatusUsedCPURequestAverage"
+	const queryFmtResourceQuotaStatusUsedCPURequests = `avg(avg_over_time(resourcequota_status_used_resource_requests{resource="cpu",unit="core", %s}[%s])) by (resourcequota, namespace, uid, %s)`
+
+	cfg := pds.promConfig
+
+	durStr := timeutil.DurationString(end.Sub(start))
+	if durStr == "" {
+		panic(fmt.Sprintf("failed to parse duration string passed to %s", queryName))
+	}
+
+	queryResourceQuotaStatusUsedCPURequests := fmt.Sprintf(queryFmtResourceQuotaStatusUsedCPURequests, cfg.ClusterFilter, durStr, cfg.ClusterLabel)
+	log.Debugf(PrometheusMetricsQueryLogFormat, queryName, end.Unix(), queryResourceQuotaStatusUsedCPURequests)
+
+	ctx := pds.promContexts.NewNamedContext(AllocationContextName)
+	return source.NewFuture(source.DecodeResourceQuotaStatusUsedCPURequestAvgResult, ctx.QueryAtTime(queryResourceQuotaStatusUsedCPURequests, end))
+}
+
+func (pds *PrometheusMetricsQuerier) QueryResourceQuotaStatusUsedCPURequestMax(start, end time.Time) *source.Future[source.ResourceQuotaStatusUsedCPURequestMaxResult] {
+	const queryName = "QueryResourceQuotaStatusUsedCPURequestMax"
+	const queryFmtResourceQuotaStatusUsedCPURequests = `max(max_over_time(resourcequota_status_used_resource_requests{resource="cpu",unit="core", %s}[%s])) by (resourcequota, namespace, uid, %s)`
+
+	cfg := pds.promConfig
+
+	durStr := timeutil.DurationString(end.Sub(start))
+	if durStr == "" {
+		panic(fmt.Sprintf("failed to parse duration string passed to %s", queryName))
+	}
+
+	queryResourceQuotaStatusUsedCPURequests := fmt.Sprintf(queryFmtResourceQuotaStatusUsedCPURequests, cfg.ClusterFilter, durStr, cfg.ClusterLabel)
+	log.Debugf(PrometheusMetricsQueryLogFormat, queryName, end.Unix(), queryResourceQuotaStatusUsedCPURequests)
+
+	ctx := pds.promContexts.NewNamedContext(AllocationContextName)
+	return source.NewFuture(source.DecodeResourceQuotaStatusUsedCPURequestMaxResult, ctx.QueryAtTime(queryResourceQuotaStatusUsedCPURequests, end))
+}
+
+func (pds *PrometheusMetricsQuerier) QueryResourceQuotaStatusUsedRAMRequestAverage(start, end time.Time) *source.Future[source.ResourceQuotaStatusUsedRAMRequestAvgResult] {
+	const queryName = "QueryResourceQuotaStatusUsedRAMRequestAverage"
+	const queryFmtResourceQuotaStatusUsedRAMRequests = `avg(avg_over_time(resourcequota_status_used_resource_requests{resource="memory",unit="byte", %s}[%s])) by (resourcequota, namespace, uid, %s)`
+
+	cfg := pds.promConfig
+
+	durStr := timeutil.DurationString(end.Sub(start))
+	if durStr == "" {
+		panic(fmt.Sprintf("failed to parse duration string passed to %s", queryName))
+	}
+
+	queryResourceQuotaStatusUsedRAMRequests := fmt.Sprintf(queryFmtResourceQuotaStatusUsedRAMRequests, cfg.ClusterFilter, durStr, cfg.ClusterLabel)
+	log.Debugf(PrometheusMetricsQueryLogFormat, queryName, end.Unix(), queryResourceQuotaStatusUsedRAMRequests)
+
+	ctx := pds.promContexts.NewNamedContext(AllocationContextName)
+	return source.NewFuture(source.DecodeResourceQuotaStatusUsedRAMRequestAvgResult, ctx.QueryAtTime(queryResourceQuotaStatusUsedRAMRequests, end))
+}
+
+func (pds *PrometheusMetricsQuerier) QueryResourceQuotaStatusUsedRAMRequestMax(start, end time.Time) *source.Future[source.ResourceQuotaStatusUsedRAMRequestMaxResult] {
+	const queryName = "QueryResourceQuotaStatusUsedRAMRequestMax"
+	const queryFmtResourceQuotaStatusUsedRAMRequests = `max(max_over_time(resourcequota_status_used_resource_requests{resource="memory",unit="byte", %s}[%s])) by (resourcequota, namespace, uid, %s)`
+
+	cfg := pds.promConfig
+
+	durStr := timeutil.DurationString(end.Sub(start))
+	if durStr == "" {
+		panic(fmt.Sprintf("failed to parse duration string passed to %s", queryName))
+	}
+
+	queryResourceQuotaStatusUsedRAMRequests := fmt.Sprintf(queryFmtResourceQuotaStatusUsedRAMRequests, cfg.ClusterFilter, durStr, cfg.ClusterLabel)
+	log.Debugf(PrometheusMetricsQueryLogFormat, queryName, end.Unix(), queryResourceQuotaStatusUsedRAMRequests)
+
+	ctx := pds.promContexts.NewNamedContext(AllocationContextName)
+	return source.NewFuture(source.DecodeResourceQuotaStatusUsedRAMRequestMaxResult, ctx.QueryAtTime(queryResourceQuotaStatusUsedRAMRequests, end))
+}
+
+func (pds *PrometheusMetricsQuerier) QueryResourceQuotaStatusUsedCPULimitAverage(start, end time.Time) *source.Future[source.ResourceQuotaStatusUsedCPULimitAvgResult] {
+	const queryName = "QueryResourceQuotaStatusUsedCPULimitAverage"
+	const queryFmtResourceQuotaStatusUsedCPULimits = `avg(avg_over_time(resourcequota_status_used_resource_limits{resource="cpu",unit="core", %s}[%s])) by (resourcequota, namespace, uid, %s)`
+
+	cfg := pds.promConfig
+
+	durStr := timeutil.DurationString(end.Sub(start))
+	if durStr == "" {
+		panic(fmt.Sprintf("failed to parse duration string passed to %s", queryName))
+	}
+
+	queryResourceQuotaStatusUsedCPULimits := fmt.Sprintf(queryFmtResourceQuotaStatusUsedCPULimits, cfg.ClusterFilter, durStr, cfg.ClusterLabel)
+	log.Debugf(PrometheusMetricsQueryLogFormat, queryName, end.Unix(), queryResourceQuotaStatusUsedCPULimits)
+
+	ctx := pds.promContexts.NewNamedContext(AllocationContextName)
+	return source.NewFuture(source.DecodeResourceQuotaStatusUsedCPULimitAvgResult, ctx.QueryAtTime(queryResourceQuotaStatusUsedCPULimits, end))
+}
+
+func (pds *PrometheusMetricsQuerier) QueryResourceQuotaStatusUsedCPULimitMax(start, end time.Time) *source.Future[source.ResourceQuotaStatusUsedCPULimitMaxResult] {
+	const queryName = "QueryResourceQuotaStatusUsedCPULimitMax"
+	const queryFmtResourceQuotaStatusUsedCPULimits = `max(max_over_time(resourcequota_status_used_resource_limits{resource="cpu",unit="core", %s}[%s])) by (resourcequota, namespace, uid, %s)`
+
+	cfg := pds.promConfig
+
+	durStr := timeutil.DurationString(end.Sub(start))
+	if durStr == "" {
+		panic(fmt.Sprintf("failed to parse duration string passed to %s", queryName))
+	}
+
+	queryResourceQuotaStatusUsedCPULimits := fmt.Sprintf(queryFmtResourceQuotaStatusUsedCPULimits, cfg.ClusterFilter, durStr, cfg.ClusterLabel)
+	log.Debugf(PrometheusMetricsQueryLogFormat, queryName, end.Unix(), queryResourceQuotaStatusUsedCPULimits)
+
+	ctx := pds.promContexts.NewNamedContext(AllocationContextName)
+	return source.NewFuture(source.DecodeResourceQuotaStatusUsedCPULimitMaxResult, ctx.QueryAtTime(queryResourceQuotaStatusUsedCPULimits, end))
+}
+
+func (pds *PrometheusMetricsQuerier) QueryResourceQuotaStatusUsedRAMLimitAverage(start, end time.Time) *source.Future[source.ResourceQuotaStatusUsedRAMLimitAvgResult] {
+	const queryName = "QueryResourceQuotaStatusUsedRAMLimitAverage"
+	const queryFmtResourceQuotaStatusUsedRAMLimits = `avg(avg_over_time(resourcequota_status_used_resource_limits{resource="memory",unit="byte", %s}[%s])) by (resourcequota, namespace, uid, %s)`
+
+	cfg := pds.promConfig
+
+	durStr := timeutil.DurationString(end.Sub(start))
+	if durStr == "" {
+		panic(fmt.Sprintf("failed to parse duration string passed to %s", queryName))
+	}
+
+	queryResourceQuotaStatusUsedRAMLimits := fmt.Sprintf(queryFmtResourceQuotaStatusUsedRAMLimits, cfg.ClusterFilter, durStr, cfg.ClusterLabel)
+	log.Debugf(PrometheusMetricsQueryLogFormat, queryName, end.Unix(), queryResourceQuotaStatusUsedRAMLimits)
+
+	ctx := pds.promContexts.NewNamedContext(AllocationContextName)
+	return source.NewFuture(source.DecodeResourceQuotaStatusUsedRAMLimitAvgResult, ctx.QueryAtTime(queryResourceQuotaStatusUsedRAMLimits, end))
+}
+
+func (pds *PrometheusMetricsQuerier) QueryResourceQuotaStatusUsedRAMLimitMax(start, end time.Time) *source.Future[source.ResourceQuotaStatusUsedRAMLimitMaxResult] {
+	const queryName = "QueryResourceQuotaStatusUsedRAMLimitMax"
+	const queryFmtResourceQuotaStatusUsedRAMLimits = `max(max_over_time(resourcequota_status_used_resource_limits{resource="memory",unit="byte", %s}[%s])) by (resourcequota, namespace, uid, %s)`
+
+	cfg := pds.promConfig
+
+	durStr := timeutil.DurationString(end.Sub(start))
+	if durStr == "" {
+		panic(fmt.Sprintf("failed to parse duration string passed to %s", queryName))
+	}
+
+	queryResourceQuotaStatusUsedRAMLimits := fmt.Sprintf(queryFmtResourceQuotaStatusUsedRAMLimits, cfg.ClusterFilter, durStr, cfg.ClusterLabel)
+	log.Debugf(PrometheusMetricsQueryLogFormat, queryName, end.Unix(), queryResourceQuotaStatusUsedRAMLimits)
+
+	ctx := pds.promContexts.NewNamedContext(AllocationContextName)
+	return source.NewFuture(source.DecodeResourceQuotaStatusUsedRAMLimitMaxResult, ctx.QueryAtTime(queryResourceQuotaStatusUsedRAMLimits, end))
+}
+
 func (pds *PrometheusMetricsQuerier) QueryDataCoverage(limitDays int) (time.Time, time.Time, error) {
 	const (
 		queryName            = "QueryDataCoverage"

+ 92 - 76
modules/prometheus-source/pkg/prom/metricsquerier_test.go

@@ -96,82 +96,98 @@ func TestQueryLogs(t *testing.T) {
 	queryStart := queryEnd.Add(-24 * time.Hour)
 
 	tests := map[string]func(time.Time, time.Time){
-		"QueryPVActiveMinutes":              func(s, e time.Time) { querier.QueryPVActiveMinutes(s, e) },
-		"QueryPVUsedAverage":                func(s, e time.Time) { querier.QueryPVUsedAverage(s, e) },
-		"QueryPVUsedMax":                    func(s, e time.Time) { querier.QueryPVUsedMax(s, e) },
-		"QueryLocalStorageActiveMinutes":    func(s, e time.Time) { querier.QueryLocalStorageActiveMinutes(s, e) },
-		"QueryLocalStorageCost":             func(s, e time.Time) { querier.QueryLocalStorageCost(s, e) },
-		"QueryLocalStorageUsedCost":         func(s, e time.Time) { querier.QueryLocalStorageUsedCost(s, e) },
-		"QueryLocalStorageUsedAvg":          func(s, e time.Time) { querier.QueryLocalStorageUsedAvg(s, e) },
-		"QueryLocalStorageUsedMax":          func(s, e time.Time) { querier.QueryLocalStorageUsedMax(s, e) },
-		"QueryLocalStorageBytes":            func(s, e time.Time) { querier.QueryLocalStorageBytes(s, e) },
-		"QueryNodeActiveMinutes":            func(s, e time.Time) { querier.QueryNodeActiveMinutes(s, e) },
-		"QueryNodeCPUCoresCapacity":         func(s, e time.Time) { querier.QueryNodeCPUCoresCapacity(s, e) },
-		"QueryNodeCPUCoresAllocatable":      func(s, e time.Time) { querier.QueryNodeCPUCoresAllocatable(s, e) },
-		"QueryNodeRAMBytesCapacity":         func(s, e time.Time) { querier.QueryNodeRAMBytesCapacity(s, e) },
-		"QueryNodeRAMBytesAllocatable":      func(s, e time.Time) { querier.QueryNodeRAMBytesAllocatable(s, e) },
-		"QueryNodeGPUCount":                 func(s, e time.Time) { querier.QueryNodeGPUCount(s, e) },
-		"QueryNodeCPUModeTotal":             func(s, e time.Time) { querier.QueryNodeCPUModeTotal(s, e) },
-		"QueryNodeIsSpot":                   func(s, e time.Time) { querier.QueryNodeIsSpot(s, e) },
-		"QueryNodeRAMSystemPercent":         func(s, e time.Time) { querier.QueryNodeRAMSystemPercent(s, e) },
-		"QueryNodeRAMUserPercent":           func(s, e time.Time) { querier.QueryNodeRAMUserPercent(s, e) },
-		"QueryLBActiveMinutes":              func(s, e time.Time) { querier.QueryLBActiveMinutes(s, e) },
-		"QueryLBPricePerHr":                 func(s, e time.Time) { querier.QueryLBPricePerHr(s, e) },
-		"QueryClusterManagementDuration":    func(s, e time.Time) { querier.QueryClusterManagementDuration(s, e) },
-		"QueryClusterManagementPricePerHr":  func(s, e time.Time) { querier.QueryClusterManagementPricePerHr(s, e) },
-		"QueryPods":                         func(s, e time.Time) { querier.QueryPods(s, e) },
-		"QueryPodsUID":                      func(s, e time.Time) { querier.QueryPodsUID(s, e) },
-		"QueryRAMBytesAllocated":            func(s, e time.Time) { querier.QueryRAMBytesAllocated(s, e) },
-		"QueryRAMRequests":                  func(s, e time.Time) { querier.QueryRAMRequests(s, e) },
-		"QueryRAMLimits":                    func(s, e time.Time) { querier.QueryRAMLimits(s, e) },
-		"QueryRAMUsageAvg":                  func(s, e time.Time) { querier.QueryRAMUsageAvg(s, e) },
-		"QueryRAMUsageMax":                  func(s, e time.Time) { querier.QueryRAMUsageMax(s, e) },
-		"QueryNodeRAMPricePerGiBHr":         func(s, e time.Time) { querier.QueryNodeRAMPricePerGiBHr(s, e) },
-		"QueryCPUCoresAllocated":            func(s, e time.Time) { querier.QueryCPUCoresAllocated(s, e) },
-		"QueryCPURequests":                  func(s, e time.Time) { querier.QueryCPURequests(s, e) },
-		"QueryCPULimits":                    func(s, e time.Time) { querier.QueryCPULimits(s, e) },
-		"QueryCPUUsageAvg":                  func(s, e time.Time) { querier.QueryCPUUsageAvg(s, e) },
-		"QueryCPUUsageMax":                  func(s, e time.Time) { querier.QueryCPUUsageMax(s, e) },
-		"QueryNodeCPUPricePerHr":            func(s, e time.Time) { querier.QueryNodeCPUPricePerHr(s, e) },
-		"QueryGPUsAllocated":                func(s, e time.Time) { querier.QueryGPUsAllocated(s, e) },
-		"QueryGPUsRequested":                func(s, e time.Time) { querier.QueryGPUsRequested(s, e) },
-		"QueryGPUsUsageAvg":                 func(s, e time.Time) { querier.QueryGPUsUsageAvg(s, e) },
-		"QueryGPUsUsageMax":                 func(s, e time.Time) { querier.QueryGPUsUsageMax(s, e) },
-		"QueryNodeGPUPricePerHr":            func(s, e time.Time) { querier.QueryNodeGPUPricePerHr(s, e) },
-		"QueryGPUInfo":                      func(s, e time.Time) { querier.QueryGPUInfo(s, e) },
-		"QueryIsGPUShared":                  func(s, e time.Time) { querier.QueryIsGPUShared(s, e) },
-		"QueryPodPVCAllocation":             func(s, e time.Time) { querier.QueryPodPVCAllocation(s, e) },
-		"QueryPVCBytesRequested":            func(s, e time.Time) { querier.QueryPVCBytesRequested(s, e) },
-		"QueryPVCInfo":                      func(s, e time.Time) { querier.QueryPVCInfo(s, e) },
-		"QueryPVBytes":                      func(s, e time.Time) { querier.QueryPVBytes(s, e) },
-		"QueryPVPricePerGiBHour":            func(s, e time.Time) { querier.QueryPVPricePerGiBHour(s, e) },
-		"QueryPVInfo":                       func(s, e time.Time) { querier.QueryPVInfo(s, e) },
-		"QueryNetZoneGiB":                   func(s, e time.Time) { querier.QueryNetZoneGiB(s, e) },
-		"QueryNetZonePricePerGiB":           func(s, e time.Time) { querier.QueryNetZonePricePerGiB(s, e) },
-		"QueryNetRegionGiB":                 func(s, e time.Time) { querier.QueryNetRegionGiB(s, e) },
-		"QueryNetRegionPricePerGiB":         func(s, e time.Time) { querier.QueryNetRegionPricePerGiB(s, e) },
-		"QueryNetInternetGiB":               func(s, e time.Time) { querier.QueryNetInternetGiB(s, e) },
-		"QueryNetInternetPricePerGiB":       func(s, e time.Time) { querier.QueryNetInternetPricePerGiB(s, e) },
-		"QueryNetInternetServiceGiB":        func(s, e time.Time) { querier.QueryNetInternetServiceGiB(s, e) },
-		"QueryNetTransferBytes":             func(s, e time.Time) { querier.QueryNetTransferBytes(s, e) },
-		"QueryNetZoneIngressGiB":            func(s, e time.Time) { querier.QueryNetZoneIngressGiB(s, e) },
-		"QueryNetRegionIngressGiB":          func(s, e time.Time) { querier.QueryNetRegionIngressGiB(s, e) },
-		"QueryNetInternetIngressGiB":        func(s, e time.Time) { querier.QueryNetInternetIngressGiB(s, e) },
-		"QueryNetInternetServiceIngressGiB": func(s, e time.Time) { querier.QueryNetInternetServiceIngressGiB(s, e) },
-		"QueryNetReceiveBytes":              func(s, e time.Time) { querier.QueryNetReceiveBytes(s, e) },
-		"QueryNamespaceAnnotations":         func(s, e time.Time) { querier.QueryNamespaceAnnotations(s, e) },
-		"QueryPodAnnotations":               func(s, e time.Time) { querier.QueryPodAnnotations(s, e) },
-		"QueryNodeLabels":                   func(s, e time.Time) { querier.QueryNodeLabels(s, e) },
-		"QueryNamespaceLabels":              func(s, e time.Time) { querier.QueryNamespaceLabels(s, e) },
-		"QueryPodLabels":                    func(s, e time.Time) { querier.QueryPodLabels(s, e) },
-		"QueryServiceLabels":                func(s, e time.Time) { querier.QueryServiceLabels(s, e) },
-		"QueryDeploymentLabels":             func(s, e time.Time) { querier.QueryDeploymentLabels(s, e) },
-		"QueryStatefulSetLabels":            func(s, e time.Time) { querier.QueryStatefulSetLabels(s, e) },
-		"QueryDaemonSetLabels":              func(s, e time.Time) { querier.QueryDaemonSetLabels(s, e) },
-		"QueryJobLabels":                    func(s, e time.Time) { querier.QueryJobLabels(s, e) },
-		"QueryPodsWithReplicaSetOwner":      func(s, e time.Time) { querier.QueryPodsWithReplicaSetOwner(s, e) },
-		"QueryReplicaSetsWithoutOwners":     func(s, e time.Time) { querier.QueryReplicaSetsWithoutOwners(s, e) },
-		"QueryReplicaSetsWithRollout":       func(s, e time.Time) { querier.QueryReplicaSetsWithRollout(s, e) },
+		"QueryPVActiveMinutes":                          func(s, e time.Time) { querier.QueryPVActiveMinutes(s, e) },
+		"QueryPVUsedAverage":                            func(s, e time.Time) { querier.QueryPVUsedAverage(s, e) },
+		"QueryPVUsedMax":                                func(s, e time.Time) { querier.QueryPVUsedMax(s, e) },
+		"QueryLocalStorageActiveMinutes":                func(s, e time.Time) { querier.QueryLocalStorageActiveMinutes(s, e) },
+		"QueryLocalStorageCost":                         func(s, e time.Time) { querier.QueryLocalStorageCost(s, e) },
+		"QueryLocalStorageUsedCost":                     func(s, e time.Time) { querier.QueryLocalStorageUsedCost(s, e) },
+		"QueryLocalStorageUsedAvg":                      func(s, e time.Time) { querier.QueryLocalStorageUsedAvg(s, e) },
+		"QueryLocalStorageUsedMax":                      func(s, e time.Time) { querier.QueryLocalStorageUsedMax(s, e) },
+		"QueryLocalStorageBytes":                        func(s, e time.Time) { querier.QueryLocalStorageBytes(s, e) },
+		"QueryNodeActiveMinutes":                        func(s, e time.Time) { querier.QueryNodeActiveMinutes(s, e) },
+		"QueryNodeCPUCoresCapacity":                     func(s, e time.Time) { querier.QueryNodeCPUCoresCapacity(s, e) },
+		"QueryNodeCPUCoresAllocatable":                  func(s, e time.Time) { querier.QueryNodeCPUCoresAllocatable(s, e) },
+		"QueryNodeRAMBytesCapacity":                     func(s, e time.Time) { querier.QueryNodeRAMBytesCapacity(s, e) },
+		"QueryNodeRAMBytesAllocatable":                  func(s, e time.Time) { querier.QueryNodeRAMBytesAllocatable(s, e) },
+		"QueryNodeGPUCount":                             func(s, e time.Time) { querier.QueryNodeGPUCount(s, e) },
+		"QueryNodeCPUModeTotal":                         func(s, e time.Time) { querier.QueryNodeCPUModeTotal(s, e) },
+		"QueryNodeIsSpot":                               func(s, e time.Time) { querier.QueryNodeIsSpot(s, e) },
+		"QueryNodeRAMSystemPercent":                     func(s, e time.Time) { querier.QueryNodeRAMSystemPercent(s, e) },
+		"QueryNodeRAMUserPercent":                       func(s, e time.Time) { querier.QueryNodeRAMUserPercent(s, e) },
+		"QueryLBActiveMinutes":                          func(s, e time.Time) { querier.QueryLBActiveMinutes(s, e) },
+		"QueryLBPricePerHr":                             func(s, e time.Time) { querier.QueryLBPricePerHr(s, e) },
+		"QueryClusterManagementDuration":                func(s, e time.Time) { querier.QueryClusterManagementDuration(s, e) },
+		"QueryClusterManagementPricePerHr":              func(s, e time.Time) { querier.QueryClusterManagementPricePerHr(s, e) },
+		"QueryPods":                                     func(s, e time.Time) { querier.QueryPods(s, e) },
+		"QueryPodsUID":                                  func(s, e time.Time) { querier.QueryPodsUID(s, e) },
+		"QueryRAMBytesAllocated":                        func(s, e time.Time) { querier.QueryRAMBytesAllocated(s, e) },
+		"QueryRAMRequests":                              func(s, e time.Time) { querier.QueryRAMRequests(s, e) },
+		"QueryRAMLimits":                                func(s, e time.Time) { querier.QueryRAMLimits(s, e) },
+		"QueryRAMUsageAvg":                              func(s, e time.Time) { querier.QueryRAMUsageAvg(s, e) },
+		"QueryRAMUsageMax":                              func(s, e time.Time) { querier.QueryRAMUsageMax(s, e) },
+		"QueryNodeRAMPricePerGiBHr":                     func(s, e time.Time) { querier.QueryNodeRAMPricePerGiBHr(s, e) },
+		"QueryCPUCoresAllocated":                        func(s, e time.Time) { querier.QueryCPUCoresAllocated(s, e) },
+		"QueryCPURequests":                              func(s, e time.Time) { querier.QueryCPURequests(s, e) },
+		"QueryCPULimits":                                func(s, e time.Time) { querier.QueryCPULimits(s, e) },
+		"QueryCPUUsageAvg":                              func(s, e time.Time) { querier.QueryCPUUsageAvg(s, e) },
+		"QueryCPUUsageMax":                              func(s, e time.Time) { querier.QueryCPUUsageMax(s, e) },
+		"QueryNodeCPUPricePerHr":                        func(s, e time.Time) { querier.QueryNodeCPUPricePerHr(s, e) },
+		"QueryGPUsAllocated":                            func(s, e time.Time) { querier.QueryGPUsAllocated(s, e) },
+		"QueryGPUsRequested":                            func(s, e time.Time) { querier.QueryGPUsRequested(s, e) },
+		"QueryGPUsUsageAvg":                             func(s, e time.Time) { querier.QueryGPUsUsageAvg(s, e) },
+		"QueryGPUsUsageMax":                             func(s, e time.Time) { querier.QueryGPUsUsageMax(s, e) },
+		"QueryNodeGPUPricePerHr":                        func(s, e time.Time) { querier.QueryNodeGPUPricePerHr(s, e) },
+		"QueryGPUInfo":                                  func(s, e time.Time) { querier.QueryGPUInfo(s, e) },
+		"QueryIsGPUShared":                              func(s, e time.Time) { querier.QueryIsGPUShared(s, e) },
+		"QueryPodPVCAllocation":                         func(s, e time.Time) { querier.QueryPodPVCAllocation(s, e) },
+		"QueryPVCBytesRequested":                        func(s, e time.Time) { querier.QueryPVCBytesRequested(s, e) },
+		"QueryPVCInfo":                                  func(s, e time.Time) { querier.QueryPVCInfo(s, e) },
+		"QueryPVBytes":                                  func(s, e time.Time) { querier.QueryPVBytes(s, e) },
+		"QueryPVPricePerGiBHour":                        func(s, e time.Time) { querier.QueryPVPricePerGiBHour(s, e) },
+		"QueryPVInfo":                                   func(s, e time.Time) { querier.QueryPVInfo(s, e) },
+		"QueryNetZoneGiB":                               func(s, e time.Time) { querier.QueryNetZoneGiB(s, e) },
+		"QueryNetZonePricePerGiB":                       func(s, e time.Time) { querier.QueryNetZonePricePerGiB(s, e) },
+		"QueryNetRegionGiB":                             func(s, e time.Time) { querier.QueryNetRegionGiB(s, e) },
+		"QueryNetRegionPricePerGiB":                     func(s, e time.Time) { querier.QueryNetRegionPricePerGiB(s, e) },
+		"QueryNetInternetGiB":                           func(s, e time.Time) { querier.QueryNetInternetGiB(s, e) },
+		"QueryNetInternetPricePerGiB":                   func(s, e time.Time) { querier.QueryNetInternetPricePerGiB(s, e) },
+		"QueryNetInternetServiceGiB":                    func(s, e time.Time) { querier.QueryNetInternetServiceGiB(s, e) },
+		"QueryNetTransferBytes":                         func(s, e time.Time) { querier.QueryNetTransferBytes(s, e) },
+		"QueryNetZoneIngressGiB":                        func(s, e time.Time) { querier.QueryNetZoneIngressGiB(s, e) },
+		"QueryNetRegionIngressGiB":                      func(s, e time.Time) { querier.QueryNetRegionIngressGiB(s, e) },
+		"QueryNetInternetIngressGiB":                    func(s, e time.Time) { querier.QueryNetInternetIngressGiB(s, e) },
+		"QueryNetInternetServiceIngressGiB":             func(s, e time.Time) { querier.QueryNetInternetServiceIngressGiB(s, e) },
+		"QueryNetReceiveBytes":                          func(s, e time.Time) { querier.QueryNetReceiveBytes(s, e) },
+		"QueryNamespaceAnnotations":                     func(s, e time.Time) { querier.QueryNamespaceAnnotations(s, e) },
+		"QueryPodAnnotations":                           func(s, e time.Time) { querier.QueryPodAnnotations(s, e) },
+		"QueryNodeLabels":                               func(s, e time.Time) { querier.QueryNodeLabels(s, e) },
+		"QueryNamespaceLabels":                          func(s, e time.Time) { querier.QueryNamespaceLabels(s, e) },
+		"QueryPodLabels":                                func(s, e time.Time) { querier.QueryPodLabels(s, e) },
+		"QueryServiceLabels":                            func(s, e time.Time) { querier.QueryServiceLabels(s, e) },
+		"QueryDeploymentLabels":                         func(s, e time.Time) { querier.QueryDeploymentLabels(s, e) },
+		"QueryStatefulSetLabels":                        func(s, e time.Time) { querier.QueryStatefulSetLabels(s, e) },
+		"QueryDaemonSetLabels":                          func(s, e time.Time) { querier.QueryDaemonSetLabels(s, e) },
+		"QueryJobLabels":                                func(s, e time.Time) { querier.QueryJobLabels(s, e) },
+		"QueryPodsWithReplicaSetOwner":                  func(s, e time.Time) { querier.QueryPodsWithReplicaSetOwner(s, e) },
+		"QueryReplicaSetsWithoutOwners":                 func(s, e time.Time) { querier.QueryReplicaSetsWithoutOwners(s, e) },
+		"QueryReplicaSetsWithRollout":                   func(s, e time.Time) { querier.QueryReplicaSetsWithRollout(s, e) },
+		"QueryResourceQuotaSpecCPURequestAverage":       func(s, e time.Time) { querier.QueryResourceQuotaSpecCPURequestAverage(s, e) },
+		"QueryResourceQuotaSpecCPURequestMax":           func(s, e time.Time) { querier.QueryResourceQuotaSpecCPURequestMax(s, e) },
+		"QueryResourceQuotaSpecRAMRequestAverage":       func(s, e time.Time) { querier.QueryResourceQuotaSpecRAMRequestAverage(s, e) },
+		"QueryResourceQuotaSpecRAMRequestMax":           func(s, e time.Time) { querier.QueryResourceQuotaSpecRAMRequestMax(s, e) },
+		"QueryResourceQuotaSpecCPULimitAverage":         func(s, e time.Time) { querier.QueryResourceQuotaSpecCPULimitAverage(s, e) },
+		"QueryResourceQuotaSpecCPULimitMax":             func(s, e time.Time) { querier.QueryResourceQuotaSpecCPULimitMax(s, e) },
+		"QueryResourceQuotaSpecRAMLimitAverage":         func(s, e time.Time) { querier.QueryResourceQuotaSpecRAMLimitAverage(s, e) },
+		"QueryResourceQuotaSpecRAMLimitMax":             func(s, e time.Time) { querier.QueryResourceQuotaSpecRAMLimitMax(s, e) },
+		"QueryResourceQuotaStatusUsedCPURequestAverage": func(s, e time.Time) { querier.QueryResourceQuotaStatusUsedCPURequestAverage(s, e) },
+		"QueryResourceQuotaStatusUsedCPURequestMax":     func(s, e time.Time) { querier.QueryResourceQuotaStatusUsedCPURequestMax(s, e) },
+		"QueryResourceQuotaStatusUsedRAMRequestAverage": func(s, e time.Time) { querier.QueryResourceQuotaStatusUsedRAMRequestAverage(s, e) },
+		"QueryResourceQuotaStatusUsedRAMRequestMax":     func(s, e time.Time) { querier.QueryResourceQuotaStatusUsedRAMRequestMax(s, e) },
+		"QueryResourceQuotaStatusUsedCPULimitAverage":   func(s, e time.Time) { querier.QueryResourceQuotaStatusUsedCPULimitAverage(s, e) },
+		"QueryResourceQuotaStatusUsedCPULimitMax":       func(s, e time.Time) { querier.QueryResourceQuotaStatusUsedCPULimitMax(s, e) },
+		"QueryResourceQuotaStatusUsedRAMLimitAverage":   func(s, e time.Time) { querier.QueryResourceQuotaStatusUsedRAMLimitAverage(s, e) },
+		"QueryResourceQuotaStatusUsedRAMLimitMax":       func(s, e time.Time) { querier.QueryResourceQuotaStatusUsedRAMLimitMax(s, e) },
 	}
 
 	for testName, queryFunc := range tests {