diff --git a/pkg/scheduler/plugins/elasticquota/core/group_quota_manager.go b/pkg/scheduler/plugins/elasticquota/core/group_quota_manager.go index e1541af16..eed921ae5 100644 --- a/pkg/scheduler/plugins/elasticquota/core/group_quota_manager.go +++ b/pkg/scheduler/plugins/elasticquota/core/group_quota_manager.go @@ -721,6 +721,7 @@ func (gqm *GroupQuotaManager) GetQuotaSummaries() map[string]*QuotaInfoSummary { quotaSummary := quotaInfo.GetQuotaSummary() runtime := gqm.RefreshRuntimeNoLock(quotaName) quotaSummary.Runtime = runtime.DeepCopy() + quotaSummary.Tree = gqm.treeID result[quotaName] = quotaSummary } diff --git a/pkg/scheduler/plugins/elasticquota/core/quota_info.go b/pkg/scheduler/plugins/elasticquota/core/quota_info.go index db616583c..cf8106520 100644 --- a/pkg/scheduler/plugins/elasticquota/core/quota_info.go +++ b/pkg/scheduler/plugins/elasticquota/core/quota_info.go @@ -154,6 +154,8 @@ func (qi *QuotaInfo) GetQuotaSummary() *QuotaInfoSummary { quotaInfoSummary.SharedWeight = qi.CalculateInfo.SharedWeight.DeepCopy() quotaInfoSummary.Runtime = qi.CalculateInfo.Runtime.DeepCopy() quotaInfoSummary.ChildRequest = qi.CalculateInfo.ChildRequest.DeepCopy() + quotaInfoSummary.Allocated = qi.CalculateInfo.Allocated.DeepCopy() + quotaInfoSummary.Guaranteed = qi.CalculateInfo.Guaranteed.DeepCopy() for podName, podInfo := range qi.PodCache { quotaInfoSummary.PodCache[podName] = &SimplePodInfo{ diff --git a/pkg/scheduler/plugins/elasticquota/core/quota_summary.go b/pkg/scheduler/plugins/elasticquota/core/quota_summary.go index e80a66cbd..90280a1f8 100644 --- a/pkg/scheduler/plugins/elasticquota/core/quota_summary.go +++ b/pkg/scheduler/plugins/elasticquota/core/quota_summary.go @@ -31,6 +31,7 @@ type QuotaInfoSummary struct { IsParent bool `json:"isParent"` RuntimeVersion int64 `json:"runtimeVersion"` AllowLentResource bool `json:"allowLentResource"` + Tree string `json:"tree"` Max v1.ResourceList `json:"max"` Min v1.ResourceList `json:"min"` @@ -41,6 +42,8 @@ type QuotaInfoSummary struct { SharedWeight v1.ResourceList `json:"sharedWeight"` Runtime v1.ResourceList `json:"runtime"` ChildRequest v1.ResourceList `json:"childRequest"` + Allocated v1.ResourceList `json:"allocated"` + Guaranteed v1.ResourceList `json:"guaranteed"` PodCache map[string]*SimplePodInfo `json:"podCache"` } diff --git a/pkg/scheduler/plugins/elasticquota/plugin_service.go b/pkg/scheduler/plugins/elasticquota/plugin_service.go index 38218f90d..80fb1d83f 100644 --- a/pkg/scheduler/plugins/elasticquota/plugin_service.go +++ b/pkg/scheduler/plugins/elasticquota/plugin_service.go @@ -37,7 +37,8 @@ func (g *Plugin) RegisterEndpoints(group *gin.RouterGroup) { c.JSON(http.StatusOK, quotaSummary) }) group.GET("/quotas", func(c *gin.Context) { - quotaSummaries := g.GetQuotaSummaries() + tree := c.Query("tree") + quotaSummaries := g.GetQuotaSummaries(tree) c.JSON(http.StatusOK, quotaSummaries) }) } diff --git a/pkg/scheduler/plugins/elasticquota/plugin_service_test.go b/pkg/scheduler/plugins/elasticquota/plugin_service_test.go index 71b2b739a..2cfcbd6a8 100644 --- a/pkg/scheduler/plugins/elasticquota/plugin_service_test.go +++ b/pkg/scheduler/plugins/elasticquota/plugin_service_test.go @@ -27,9 +27,12 @@ import ( corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" quotav1 "k8s.io/apiserver/pkg/quota/v1" + k8sfeature "k8s.io/apiserver/pkg/util/feature" "github.com/koordinator-sh/koordinator/apis/extension" + koordfeatures "github.com/koordinator-sh/koordinator/pkg/features" "github.com/koordinator-sh/koordinator/pkg/scheduler/plugins/elasticquota/core" + utilfeature "github.com/koordinator-sh/koordinator/pkg/util/feature" ) func TestEndpointsQueryQuotaInfo(t *testing.T) { @@ -148,4 +151,30 @@ func TestEndpointsQueryQuotaInfo(t *testing.T) { assert.Equal(t, quotaSummary.PodCache[podToCreate.Namespace+"/"+podToCreate.Name].IsAssigned, true) assert.True(t, quotav1.Equals(quotaSummary.PodCache[podToCreate.Namespace+"/"+podToCreate.Name].Resource, createResourceList(33, 33))) } + { + defer utilfeature.SetFeatureGateDuringTest(t, k8sfeature.DefaultMutableFeatureGate, koordfeatures.MultiQuotaTree, true)() + + // add root quota + eq.addRootQuota("tree1-root", "", 20, 20, 10, 10, 30, 30, false, "", "tree1") + + engine := gin.Default() + eq.RegisterEndpoints(engine.Group("/")) + w := httptest.NewRecorder() + req, _ := http.NewRequest("GET", "/quotas?tree=tree1", nil) + engine.ServeHTTP(w, req) + assert.Equal(t, http.StatusOK, w.Result().StatusCode) + quotaSummaries := make(map[string]*core.QuotaInfoSummary) + err = json.Unmarshal([]byte(w.Body.String()), "aSummaries) + assert.NoError(t, err) + + _, ok := quotaSummaries["test1"] + assert.False(t, ok) + + quotaSummary, ok := quotaSummaries["tree1-root"] + assert.True(t, ok) + assert.True(t, quotav1.Equals(quotaSummary.Max, createResourceList(20, 20))) + assert.True(t, quotav1.Equals(quotaSummary.Min, createResourceList(10, 10))) + assert.True(t, quotav1.Equals(quotaSummary.AutoScaleMin, createResourceList(10, 10))) + assert.True(t, quotav1.Equals(quotaSummary.SharedWeight, createResourceList(30, 30))) + } } diff --git a/pkg/scheduler/plugins/elasticquota/quota_handler.go b/pkg/scheduler/plugins/elasticquota/quota_handler.go index 5f1383d28..6215668c5 100644 --- a/pkg/scheduler/plugins/elasticquota/quota_handler.go +++ b/pkg/scheduler/plugins/elasticquota/quota_handler.go @@ -119,11 +119,14 @@ func (g *Plugin) GetQuotaSummary(quotaName string) (*core.QuotaInfoSummary, bool return mgr.GetQuotaSummary(quotaName) } -func (g *Plugin) GetQuotaSummaries() map[string]*core.QuotaInfoSummary { - summaries := g.groupQuotaManager.GetQuotaSummaries() +func (g *Plugin) GetQuotaSummaries(tree string) map[string]*core.QuotaInfoSummary { + summaries := make(map[string]*core.QuotaInfoSummary) managers := g.ListGroupQuotaManagersForQuotaTree() for _, mgr := range managers { + if tree != "" && mgr.GetTreeID() != tree { + continue + } for quotaName, summary := range mgr.GetQuotaSummaries() { // quota tree root quota is virtual if quotaName == extension.RootQuotaName { @@ -133,6 +136,12 @@ func (g *Plugin) GetQuotaSummaries() map[string]*core.QuotaInfoSummary { } } + if g.groupQuotaManager.GetTreeID() == tree { + for quotaName, summary := range g.groupQuotaManager.GetQuotaSummaries() { + summaries[quotaName] = summary + } + } + return summaries }