This is an automated email from the ASF dual-hosted git repository.
ccondit pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/yunikorn-core.git
The following commit(s) were added to refs/heads/master by this push:
new d7d1408c [YUNIKORN-2972] Remove internal object from user and group
REST info (#993)
d7d1408c is described below
commit d7d1408c6395d2d4d058cbe22a7f15205a28e69a
Author: Wilfred Spiegelenburg <[email protected]>
AuthorDate: Wed Nov 13 14:09:23 2024 -0600
[YUNIKORN-2972] Remove internal object from user and group REST info (#993)
Remove the Resource object from the REST response for the user and group
trackers. Removed the usage of the DAO objects in the internal unit
tests. The unit tests use new functions which directly expose the same
structures without using the DAO.
Cleanup:
- remove export from internal functions (UserTracker, GroupTracker)
- renamed functions to match their results (Manager)
- update handler to call renamed functions in Manager
- reimplemented test functions to not use DAO objects (Manager,
UserTracker, GroupTracker, QueueTracker)
- assert function changes to use new functions removing DAO usage
(scheduler/utilites_test, scheduler/objects/utilites_test)
Closes: #993
Signed-off-by: Craig Condit <[email protected]>
---
pkg/scheduler/objects/utilities_test.go | 24 +++++----
pkg/scheduler/ugm/group_tracker.go | 65 ++++++++++++++++------
pkg/scheduler/ugm/group_tracker_test.go | 13 ++---
pkg/scheduler/ugm/manager.go | 38 ++++++-------
pkg/scheduler/ugm/manager_test.go | 47 ++++++++--------
pkg/scheduler/ugm/queue_tracker.go | 96 ++++++++++++++++++++++++---------
pkg/scheduler/ugm/queue_tracker_test.go | 34 ++++++------
pkg/scheduler/ugm/user_tracker.go | 65 ++++++++++++++++------
pkg/scheduler/ugm/user_tracker_test.go | 14 ++---
pkg/scheduler/ugm/utilities_test.go | 13 -----
pkg/scheduler/utilities_test.go | 48 +++++------------
pkg/webservice/dao/ugm_info.go | 6 +--
pkg/webservice/handlers.go | 24 ++++-----
pkg/webservice/handlers_test.go | 18 +++----
14 files changed, 286 insertions(+), 219 deletions(-)
diff --git a/pkg/scheduler/objects/utilities_test.go
b/pkg/scheduler/objects/utilities_test.go
index f1369a7e..97be13c2 100644
--- a/pkg/scheduler/objects/utilities_test.go
+++ b/pkg/scheduler/objects/utilities_test.go
@@ -284,19 +284,23 @@ func getUserGroup(userName string, groupNameList
[]string) security.UserGroup {
}
func assertUserGroupResource(t *testing.T, userGroup security.UserGroup,
expected *resources.Resource) {
- ugm := ugm.GetUserManager()
- userResource := ugm.GetUserResources(userGroup)
- groupResource := ugm.GetGroupResources(userGroup.Groups[0])
- assert.Equal(t, resources.Equals(userResource, expected), true)
- assert.Equal(t, resources.Equals(groupResource, nil), true)
+ assertUserResourcesAndGroupResources(t, userGroup, expected, nil, 0)
}
func assertUserResourcesAndGroupResources(t *testing.T, userGroup
security.UserGroup, expectedUserResources *resources.Resource,
expectedGroupResources *resources.Resource, i int) {
- ugm := ugm.GetUserManager()
- userResource := ugm.GetUserResources(userGroup)
- groupResource := ugm.GetGroupResources(userGroup.Groups[i])
- assert.Equal(t, resources.Equals(userResource, expectedUserResources),
true)
- assert.Equal(t, resources.Equals(groupResource,
expectedGroupResources), true)
+ m := ugm.GetUserManager()
+ userResource := m.GetUserResources(userGroup.User)
+ if expectedUserResources == nil {
+ assert.Assert(t, userResource.IsEmpty(), "expected empty
resource in user tracker")
+ } else {
+ assert.Assert(t, resources.Equals(userResource,
expectedUserResources), "user value '%s' not equal to expected '%s'",
userResource.String(), expectedUserResources.String())
+ }
+ groupResource := m.GetGroupResources(userGroup.Groups[i])
+ if expectedGroupResources == nil {
+ assert.Assert(t, groupResource.IsEmpty(), "expected empty
resource in group tracker")
+ } else {
+ assert.Assert(t, resources.Equals(groupResource,
expectedGroupResources), "group value '%s' not equal to expected '%s'",
groupResource.String(), expectedGroupResources.String())
+ }
}
func assertAllocationLog(t *testing.T, ask *Allocation) {
diff --git a/pkg/scheduler/ugm/group_tracker.go
b/pkg/scheduler/ugm/group_tracker.go
index d6ec777f..29fa15e6 100644
--- a/pkg/scheduler/ugm/group_tracker.go
+++ b/pkg/scheduler/ugm/group_tracker.go
@@ -21,7 +21,6 @@ package ugm
import (
"strings"
- "github.com/apache/yunikorn-core/pkg/common"
"github.com/apache/yunikorn-core/pkg/common/configs"
"github.com/apache/yunikorn-core/pkg/common/resources"
"github.com/apache/yunikorn-core/pkg/locking"
@@ -92,43 +91,46 @@ func (gt *GroupTracker) clearLimits(queuePath string) {
gt.queueTracker.setLimit(strings.Split(queuePath, configs.DOT), nil, 0,
false, group, false)
}
-// Note: headroom of queue tracker is not read-only, it also traverses the
queue hierarchy and creates childQueueTracker if it does not exist.
+// headroom calculate the resource headroom for the group in the hierarchy
defined
+// Note: headroom of queue tracker is not read-only.
+// It traverses the queue hierarchy and creates a childQueueTracker if it does
not exist.
func (gt *GroupTracker) headroom(hierarchy []string) *resources.Resource {
gt.Lock()
defer gt.Unlock()
return gt.queueTracker.headroom(hierarchy, group)
}
-func (gt *GroupTracker) GetGroupResourceUsageDAOInfo()
*dao.GroupResourceUsageDAOInfo {
+// GetResourceUsageDAOInfo returns the DAO object used in the REST API for
this group tracker
+func (gt *GroupTracker) GetResourceUsageDAOInfo()
*dao.GroupResourceUsageDAOInfo {
gt.RLock()
defer gt.RUnlock()
- groupResourceUsage := &dao.GroupResourceUsageDAOInfo{
- Applications: []string{},
- }
- groupResourceUsage.GroupName = gt.groupName
+ var apps []string
for app := range gt.applications {
- groupResourceUsage.Applications =
append(groupResourceUsage.Applications, app)
+ apps = append(apps, app)
+ }
+ return &dao.GroupResourceUsageDAOInfo{
+ Applications: apps,
+ GroupName: gt.groupName,
+ Queues: gt.queueTracker.getResourceUsageDAOInfo(),
}
- groupResourceUsage.Queues =
gt.queueTracker.getResourceUsageDAOInfo(common.Empty)
- return groupResourceUsage
}
-func (gt *GroupTracker) IsQueuePathTrackedCompletely(hierarchy []string) bool {
+func (gt *GroupTracker) isQueuePathTrackedCompletely(hierarchy []string) bool {
gt.RLock()
defer gt.RUnlock()
- return gt.queueTracker.IsQueuePathTrackedCompletely(hierarchy)
+ return gt.queueTracker.isQueuePathTrackedCompletely(hierarchy)
}
-func (gt *GroupTracker) IsUnlinkRequired(hierarchy []string) bool {
+func (gt *GroupTracker) isUnlinkRequired(hierarchy []string) bool {
gt.RLock()
defer gt.RUnlock()
- return gt.queueTracker.IsUnlinkRequired(hierarchy)
+ return gt.queueTracker.isUnlinkRequired(hierarchy)
}
-func (gt *GroupTracker) UnlinkQT(hierarchy []string) bool {
+func (gt *GroupTracker) unlinkQT(hierarchy []string) bool {
gt.Lock()
defer gt.Unlock()
- return gt.queueTracker.UnlinkQT(hierarchy)
+ return gt.queueTracker.unlink(hierarchy)
}
func (gt *GroupTracker) canBeRemoved() bool {
@@ -153,9 +155,38 @@ func (gt *GroupTracker)
decreaseAllTrackedResourceUsage(hierarchy []string) map[
return removedApplications
}
-// Note: canRunApp of queue tracker is not read-only, it also traverses the
queue hierarchy and creates a childQueueTracker if it does not exist.
+// canRunApp checks if the group is allowed to run the application in the
queue defined in hierarchy.
+// Note: canRunApp of queue tracker is not read-only,
+// It traverses the queue hierarchy and creates a childQueueTracker if it does
not exist.
func (gt *GroupTracker) canRunApp(hierarchy []string, applicationID string)
bool {
gt.Lock()
defer gt.Unlock()
return gt.queueTracker.canRunApp(hierarchy, applicationID, group)
}
+
+// GetMaxResources returns a map of the maxResources for all queues registered
under this group tracker.
+// The key into the map is the queue path.
+// This should only be used in test
+func (gt *GroupTracker) GetMaxResources() map[string]*resources.Resource {
+ gt.RLock()
+ defer gt.RUnlock()
+ return gt.queueTracker.getMaxResources()
+}
+
+// GetMaxApplications returns a map of the maxRunningApps for all queues
registered under this group tracker.
+// The key into the map is the queue path.
+// This should only be used in test
+func (gt *GroupTracker) GetMaxApplications() map[string]uint64 {
+ gt.RLock()
+ defer gt.RUnlock()
+ return gt.queueTracker.getMaxApplications()
+}
+
+// getUsedResources returns a map of the usedResources for all queues
registered under this group tracker.
+// The key into the map is the queue path.
+// This should only be used in test
+func (gt *GroupTracker) getUsedResources() map[string]*resources.Resource {
+ gt.RLock()
+ defer gt.RUnlock()
+ return gt.queueTracker.getUsedResources()
+}
diff --git a/pkg/scheduler/ugm/group_tracker_test.go
b/pkg/scheduler/ugm/group_tracker_test.go
index 245e7613..833be072 100644
--- a/pkg/scheduler/ugm/group_tracker_test.go
+++ b/pkg/scheduler/ugm/group_tracker_test.go
@@ -69,8 +69,8 @@ func TestGTIncreaseTrackedResource(t *testing.T) {
t.Errorf("new resource create returned error or wrong resource:
error %t, res %v", err, usage3)
}
groupTracker.increaseTrackedResource(path4, TestApp4, usage4, user.User)
- actualResources := getGroupResource(groupTracker)
+ actualResources := groupTracker.queueTracker.getUsedResources()
assert.Equal(t, "map[mem:80000000 vcore:80000]",
actualResources["root"].String(), "wrong resource")
assert.Equal(t, "map[mem:80000000 vcore:80000]",
actualResources["root.parent"].String(), "wrong resource")
assert.Equal(t, "map[mem:40000000 vcore:40000]",
actualResources["root.parent.child1"].String(), "wrong resource")
@@ -104,9 +104,9 @@ func TestGTDecreaseTrackedResource(t *testing.T) {
t.Errorf("new resource create returned error or wrong resource:
error %t, res %v", err, usage2)
}
groupTracker.increaseTrackedResource(path2, TestApp2, usage2, user.User)
- actualResources := getGroupResource(groupTracker)
assert.Equal(t, 2, len(groupTracker.getTrackedApplications()))
+ actualResources := groupTracker.getUsedResources()
assert.Equal(t, "map[mem:90000000 vcore:90000]",
actualResources["root"].String(), "wrong resource")
assert.Equal(t, "map[mem:90000000 vcore:90000]",
actualResources["root.parent"].String(), "wrong resource")
assert.Equal(t, "map[mem:70000000 vcore:70000]",
actualResources["root.parent.child1"].String(), "wrong resource")
@@ -126,8 +126,7 @@ func TestGTDecreaseTrackedResource(t *testing.T) {
removeQT = groupTracker.decreaseTrackedResource(path2, TestApp2,
usage3, false)
assert.Equal(t, removeQT, false, "wrong remove queue tracker value")
- actualResources1 := getGroupResource(groupTracker)
-
+ actualResources1 := groupTracker.getUsedResources()
assert.Equal(t, "map[mem:70000000 vcore:70000]",
actualResources1["root"].String(), "wrong resource")
assert.Equal(t, "map[mem:70000000 vcore:70000]",
actualResources1["root.parent"].String(), "wrong resource")
assert.Equal(t, "map[mem:60000000 vcore:60000]",
actualResources1["root.parent.child1"].String(), "wrong resource")
@@ -282,9 +281,3 @@ func TestGTCanRunApp(t *testing.T) {
assert.Assert(t, groupTracker.canRunApp(hierarchy1, TestApp1))
assert.Assert(t, !groupTracker.canRunApp(hierarchy1, TestApp2))
}
-
-func getGroupResource(gt *GroupTracker) map[string]*resources.Resource {
- resources := make(map[string]*resources.Resource)
- usage := gt.GetGroupResourceUsageDAOInfo()
- return internalGetResource(usage.Queues, resources)
-}
diff --git a/pkg/scheduler/ugm/manager.go b/pkg/scheduler/ugm/manager.go
index 517751a1..e235f36b 100644
--- a/pkg/scheduler/ugm/manager.go
+++ b/pkg/scheduler/ugm/manager.go
@@ -188,7 +188,7 @@ func (m *Manager) DecreaseTrackedResource(queuePath,
applicationID string, usage
}
}
-func (m *Manager) GetUsersResources() []*UserTracker {
+func (m *Manager) GetUserTrackers() []*UserTracker {
m.RLock()
defer m.RUnlock()
var userTrackers []*UserTracker
@@ -205,7 +205,7 @@ func (m *Manager) GetUserTracker(user string) *UserTracker {
return m.userTrackers[user]
}
-func (m *Manager) GetGroupsResources() []*GroupTracker {
+func (m *Manager) GetGroupTrackers() []*GroupTracker {
m.RLock()
defer m.RUnlock()
var groupTrackers []*GroupTracker
@@ -496,14 +496,14 @@ func (m *Manager) clearEarlierSetUserLimits(newUserLimits
map[string]map[string]
func (m *Manager) resetUserEarlierUsage(ut *UserTracker, queuePath string) {
// Is this user already tracked for the queue path?
hierarchy := strings.Split(queuePath, configs.DOT)
- if ut.IsQueuePathTrackedCompletely(hierarchy) {
+ if ut.isQueuePathTrackedCompletely(hierarchy) {
log.Log(log.SchedUGM).Debug("Need to clear earlier set configs
for user",
zap.String("user", ut.userName),
zap.Strings("queue path", hierarchy))
ut.clearLimits(queuePath, false)
// Is there any running applications in end queue of this queue
path? If not, then remove the linkage between end queue and its immediate parent
- if ut.IsUnlinkRequired(hierarchy) {
- ut.UnlinkQT(hierarchy)
+ if ut.isUnlinkRequired(hierarchy) {
+ ut.unlinkQT(hierarchy)
}
log.Log(log.SchedUGM).Debug("Cleared earlier set limit configs
for user",
zap.String("user", ut.userName),
@@ -544,7 +544,7 @@ func (m *Manager) clearEarlierSetGroupLimits(newGroupLimits
map[string]map[strin
// eventually remove group tracker object itself from ugm if it can be removed.
func (m *Manager) resetGroupEarlierUsage(gt *GroupTracker, queuePath string) {
hierarchy := strings.Split(queuePath, configs.DOT)
- if gt.IsQueuePathTrackedCompletely(hierarchy) {
+ if gt.isQueuePathTrackedCompletely(hierarchy) {
log.Log(log.SchedUGM).Debug("Need to clear earlier set configs
for group",
zap.String("group", gt.groupName),
zap.Strings("queue path", hierarchy))
@@ -555,8 +555,8 @@ func (m *Manager) resetGroupEarlierUsage(gt *GroupTracker,
queuePath string) {
}
gt.clearLimits(queuePath)
// Is there any running applications in end queue of this queue
path? If not, then remove the linkage between end queue and its immediate parent
- if gt.IsUnlinkRequired(hierarchy) {
- gt.UnlinkQT(hierarchy)
+ if gt.isUnlinkRequired(hierarchy) {
+ gt.unlinkQT(hierarchy)
}
log.Log(log.SchedUGM).Debug("Cleared earlier set limit configs
for group",
zap.String("group", gt.groupName),
@@ -710,24 +710,26 @@ func (m *Manager) ClearConfigLimits() {
m.groupLimits = make(map[string]map[string]*LimitConfig)
}
-// GetUserResources only for tests
-func (m *Manager) GetUserResources(user security.UserGroup)
*resources.Resource {
+// GetUserResources returns the root queue maxResources for the user
+// Should only be used in tests
+func (m *Manager) GetUserResources(user string) *resources.Resource {
m.RLock()
defer m.RUnlock()
- ut := m.userTrackers[user.User]
- if ut != nil && ut.GetUserResourceUsageDAOInfo().Queues.ResourceUsage
!= nil && len(ut.GetUserResourceUsageDAOInfo().Queues.ResourceUsage.Resources)
> 0 {
- return ut.GetUserResourceUsageDAOInfo().Queues.ResourceUsage
+ ut := m.userTrackers[user]
+ if ut == nil {
+ return nil
}
- return nil
+ return ut.queueTracker.resourceUsage.Clone()
}
-// GetGroupResources only for tests
+// GetGroupResources returns the root queue maxResources
+// Should only be used in tests
func (m *Manager) GetGroupResources(group string) *resources.Resource {
m.RLock()
defer m.RUnlock()
gt := m.groupTrackers[group]
- if gt != nil && gt.GetGroupResourceUsageDAOInfo().Queues.ResourceUsage
!= nil && len(gt.GetGroupResourceUsageDAOInfo().Queues.ResourceUsage.Resources)
> 0 {
- return gt.GetGroupResourceUsageDAOInfo().Queues.ResourceUsage
+ if gt == nil {
+ return nil
}
- return nil
+ return gt.queueTracker.resourceUsage.Clone()
}
diff --git a/pkg/scheduler/ugm/manager_test.go
b/pkg/scheduler/ugm/manager_test.go
index 91d70257..4edc6ce4 100644
--- a/pkg/scheduler/ugm/manager_test.go
+++ b/pkg/scheduler/ugm/manager_test.go
@@ -194,7 +194,7 @@ func TestAddRemoveUserAndGroups(t *testing.T) {
manager.IncreaseTrackedResource("", "", usage1, user)
manager.IncreaseTrackedResource(queuePath1, TestApp1, usage1, user)
- groupTrackers := manager.GetGroupsResources()
+ groupTrackers := manager.GetGroupTrackers()
assert.Equal(t, len(groupTrackers), 0)
assertUGM(t, user, usage1, 1)
assert.Equal(t, user.User, manager.GetUserTracker(user.User).userName)
@@ -213,19 +213,19 @@ func TestAddRemoveUserAndGroups(t *testing.T) {
assert.Equal(t, user.User, manager.GetUserTracker(user.User).userName)
assert.Equal(t, user1.User, manager.GetUserTracker(user1.User).userName)
- assert.Equal(t, true,
manager.GetUserTracker(user.User).queueTracker.IsQueuePathTrackedCompletely(strings.Split(queuePath1,
configs.DOT)))
- assert.Equal(t, true,
manager.GetUserTracker(user1.User).queueTracker.IsQueuePathTrackedCompletely(strings.Split(queuePath2,
configs.DOT)))
- assert.Equal(t, false,
manager.GetUserTracker(user1.User).queueTracker.IsQueuePathTrackedCompletely(strings.Split(queuePath1,
configs.DOT)))
- assert.Equal(t, false,
manager.GetUserTracker(user.User).queueTracker.IsQueuePathTrackedCompletely(strings.Split(queuePath2,
configs.DOT)))
- assert.Equal(t, false,
manager.GetUserTracker(user.User).queueTracker.IsQueuePathTrackedCompletely(strings.Split(queuePath3,
configs.DOT)))
- assert.Equal(t, false,
manager.GetUserTracker(user.User).queueTracker.IsQueuePathTrackedCompletely(strings.Split(queuePath4,
configs.DOT)))
+ assert.Equal(t, true,
manager.GetUserTracker(user.User).queueTracker.isQueuePathTrackedCompletely(strings.Split(queuePath1,
configs.DOT)))
+ assert.Equal(t, true,
manager.GetUserTracker(user1.User).queueTracker.isQueuePathTrackedCompletely(strings.Split(queuePath2,
configs.DOT)))
+ assert.Equal(t, false,
manager.GetUserTracker(user1.User).queueTracker.isQueuePathTrackedCompletely(strings.Split(queuePath1,
configs.DOT)))
+ assert.Equal(t, false,
manager.GetUserTracker(user.User).queueTracker.isQueuePathTrackedCompletely(strings.Split(queuePath2,
configs.DOT)))
+ assert.Equal(t, false,
manager.GetUserTracker(user.User).queueTracker.isQueuePathTrackedCompletely(strings.Split(queuePath3,
configs.DOT)))
+ assert.Equal(t, false,
manager.GetUserTracker(user.User).queueTracker.isQueuePathTrackedCompletely(strings.Split(queuePath4,
configs.DOT)))
- assert.Equal(t, true,
manager.GetUserTracker(user.Groups[0]).queueTracker.IsQueuePathTrackedCompletely(strings.Split(queuePath1,
configs.DOT)))
- assert.Equal(t, true,
manager.GetUserTracker(user1.Groups[0]).queueTracker.IsQueuePathTrackedCompletely(strings.Split(queuePath2,
configs.DOT)))
- assert.Equal(t, false,
manager.GetUserTracker(user1.Groups[0]).queueTracker.IsQueuePathTrackedCompletely(strings.Split(queuePath1,
configs.DOT)))
- assert.Equal(t, false,
manager.GetUserTracker(user.Groups[0]).queueTracker.IsQueuePathTrackedCompletely(strings.Split(queuePath2,
configs.DOT)))
- assert.Equal(t, false,
manager.GetUserTracker(user.Groups[0]).queueTracker.IsQueuePathTrackedCompletely(strings.Split(queuePath3,
configs.DOT)))
- assert.Equal(t, false,
manager.GetUserTracker(user.Groups[0]).queueTracker.IsQueuePathTrackedCompletely(strings.Split(queuePath4,
configs.DOT)))
+ assert.Equal(t, true,
manager.GetUserTracker(user.Groups[0]).queueTracker.isQueuePathTrackedCompletely(strings.Split(queuePath1,
configs.DOT)))
+ assert.Equal(t, true,
manager.GetUserTracker(user1.Groups[0]).queueTracker.isQueuePathTrackedCompletely(strings.Split(queuePath2,
configs.DOT)))
+ assert.Equal(t, false,
manager.GetUserTracker(user1.Groups[0]).queueTracker.isQueuePathTrackedCompletely(strings.Split(queuePath1,
configs.DOT)))
+ assert.Equal(t, false,
manager.GetUserTracker(user.Groups[0]).queueTracker.isQueuePathTrackedCompletely(strings.Split(queuePath2,
configs.DOT)))
+ assert.Equal(t, false,
manager.GetUserTracker(user.Groups[0]).queueTracker.isQueuePathTrackedCompletely(strings.Split(queuePath3,
configs.DOT)))
+ assert.Equal(t, false,
manager.GetUserTracker(user.Groups[0]).queueTracker.isQueuePathTrackedCompletely(strings.Split(queuePath4,
configs.DOT)))
usage3, err := resources.NewResourceFromConf(map[string]string{"mem":
"5M", "vcore": "5"})
if err != nil {
@@ -237,12 +237,12 @@ func TestAddRemoveUserAndGroups(t *testing.T) {
assertUGM(t, user, usage1, 2)
manager.DecreaseTrackedResource(queuePath1, TestApp1, usage3, user,
true)
- assert.Equal(t, 1, len(manager.GetUsersResources()), "userTrackers
count should be 1")
- assert.Equal(t, 0, len(manager.GetGroupsResources()), "groupTrackers
count should be 0")
+ assert.Equal(t, 1, len(manager.GetUserTrackers()), "userTrackers count
should be 1")
+ assert.Equal(t, 0, len(manager.GetGroupTrackers()), "groupTrackers
count should be 0")
manager.DecreaseTrackedResource(queuePath2, TestApp2, usage2, user1,
true)
- assert.Equal(t, 0, len(manager.GetUsersResources()), "userTrackers
count should be 0")
- assert.Equal(t, 0, len(manager.GetGroupsResources()), "groupTrackers
count should be 0")
+ assert.Equal(t, 0, len(manager.GetUserTrackers()), "userTrackers count
should be 0")
+ assert.Equal(t, 0, len(manager.GetGroupTrackers()), "groupTrackers
count should be 0")
assert.Assert(t, manager.GetUserTracker(user.User) == nil)
assert.Assert(t, manager.GetGroupTracker(user.Groups[0]) == nil)
@@ -1979,12 +1979,13 @@ func setupUGM() {
func assertUGM(t *testing.T, userGroup security.UserGroup, expected
*resources.Resource, usersCount int) {
manager := GetUserManager()
- assert.Equal(t, usersCount, len(manager.GetUsersResources()),
"userTrackers count should be "+strconv.Itoa(usersCount))
- assert.Equal(t, 0, len(manager.GetGroupsResources()), "groupTrackers
count should be "+strconv.Itoa(0))
- userRes := manager.GetUserResources(userGroup)
- assert.Equal(t, resources.Equals(userRes, expected), true)
- groupRes := manager.GetGroupResources(userGroup.Groups[0])
- assert.Equal(t, resources.Equals(groupRes, nil), true)
+ assert.Equal(t, usersCount, len(manager.GetUserTrackers()),
"userTrackers count not as expected")
+ assert.Equal(t, 0, len(manager.GetGroupTrackers()), "groupTrackers
count should be 0")
+ userTR := manager.GetUserTracker(userGroup.User)
+ assert.Assert(t, userTR != nil, "user tracker should be defined")
+ assert.Assert(t, resources.Equals(userTR.queueTracker.resourceUsage,
expected), "user max resource for root not correct")
+ groupTR := manager.GetGroupTracker(userGroup.Groups[0])
+ assert.Assert(t, groupTR == nil, "group tracker should not be defined")
}
func assertMaxLimits(t *testing.T, userGroup security.UserGroup,
expectedResource *resources.Resource, expectedMaxApps int) {
diff --git a/pkg/scheduler/ugm/queue_tracker.go
b/pkg/scheduler/ugm/queue_tracker.go
index 36ddba25..c5351947 100644
--- a/pkg/scheduler/ugm/queue_tracker.go
+++ b/pkg/scheduler/ugm/queue_tracker.go
@@ -20,6 +20,7 @@ package ugm
import (
"go.uber.org/zap"
+ "golang.org/x/exp/maps"
"github.com/apache/yunikorn-core/pkg/common"
"github.com/apache/yunikorn-core/pkg/common/configs"
@@ -230,41 +231,86 @@ func (qt *QueueTracker) headroom(hierarchy []string,
trackType trackingType) *re
return resources.ComponentWiseMin(headroom, childHeadroom)
}
+// getResourceUsageDAOInfo returns the REST representation of the queue tracker
// Note: Lock free call. The RLock of the linked tracker (UserTracker and
GroupTracker) should be held before calling this function.
-func (qt *QueueTracker) getResourceUsageDAOInfo(parentQueuePath string)
*dao.ResourceUsageDAOInfo {
+func (qt *QueueTracker) getResourceUsageDAOInfo() *dao.ResourceUsageDAOInfo {
if qt == nil {
return &dao.ResourceUsageDAOInfo{}
}
- fullQueuePath := parentQueuePath + "." + qt.queueName
- if parentQueuePath == common.Empty {
- fullQueuePath = qt.queueName
+ apps := make([]string, len(qt.runningApplications))
+ i := 0
+ for app := range qt.runningApplications {
+ apps[i] = app
+ i++
}
- usage := &dao.ResourceUsageDAOInfo{
- QueuePath: fullQueuePath,
- ResourceUsage: qt.resourceUsage.Clone(),
+ children := make([]*dao.ResourceUsageDAOInfo,
len(qt.childQueueTrackers))
+ i = 0
+ for _, cqt := range qt.childQueueTrackers {
+ children[i] = cqt.getResourceUsageDAOInfo()
+ i++
}
- for app := range qt.runningApplications {
- usage.RunningApplications = append(usage.RunningApplications,
app)
+ return &dao.ResourceUsageDAOInfo{
+ QueuePath: qt.queuePath,
+ ResourceUsage: qt.resourceUsage.DAOMap(),
+ MaxResources: qt.maxResources.DAOMap(),
+ MaxApplications: qt.maxRunningApps,
+ RunningApplications: apps,
+ Children: children,
+ }
+}
+
+// getMaxResources returns a map of all maxResources defined in the queue
hierarchy.
+// Note: Lock free call. The RLock of the linked tracker (UserTracker and
GroupTracker) should be held before calling this function.
+func (qt *QueueTracker) getMaxResources() map[string]*resources.Resource {
+ if qt == nil {
+ return nil
+ }
+ maxRes := map[string]*resources.Resource{qt.queuePath: qt.maxResources}
+ for _, cqt := range qt.childQueueTrackers {
+ childUsage := cqt.getMaxResources()
+ maps.Copy(maxRes, childUsage)
+ }
+ return maxRes
+}
+
+// getMaxApplications returns a map of all maxRunningApps defined in the queue
hierarchy.
+// Note: Lock free call. The RLock of the linked tracker (UserTracker and
GroupTracker) should be held before calling this function.
+func (qt *QueueTracker) getMaxApplications() map[string]uint64 {
+ if qt == nil {
+ return nil
+ }
+ maxApps := map[string]uint64{qt.queuePath: qt.maxRunningApps}
+ for _, cqt := range qt.childQueueTrackers {
+ childApps := cqt.getMaxApplications()
+ maps.Copy(maxApps, childApps)
+ }
+ return maxApps
+}
+
+// getUsedResources returns a map of all resourceUsage defined in the queue
hierarchy.
+// Note: Lock free call. The RLock of the linked tracker (UserTracker and
GroupTracker) should be held before calling this function.
+func (qt *QueueTracker) getUsedResources() map[string]*resources.Resource {
+ if qt == nil {
+ return nil
}
- usage.MaxResources = qt.maxResources
- usage.MaxApplications = qt.maxRunningApps
+ maxRes := map[string]*resources.Resource{qt.queuePath: qt.resourceUsage}
for _, cqt := range qt.childQueueTrackers {
- childUsage := cqt.getResourceUsageDAOInfo(fullQueuePath)
- usage.Children = append(usage.Children, childUsage)
+ childUsage := cqt.getUsedResources()
+ maps.Copy(maxRes, childUsage)
}
- return usage
+ return maxRes
}
-// IsQueuePathTrackedCompletely Traverse queue path upto the end queue through
its linkage
+// isQueuePathTrackedCompletely Traverse queue path upto the end queue through
its linkage
// to confirm entire queuePath has been tracked completely or not
// Note: Lock free call. The RLock of the linked tracker (UserTracker and
GroupTracker) should be held before calling this function.
-func (qt *QueueTracker) IsQueuePathTrackedCompletely(hierarchy []string) bool {
+func (qt *QueueTracker) isQueuePathTrackedCompletely(hierarchy []string) bool {
// depth first: all the way to the leaf, ignore if not exists
// more than 1 in the slice means we need to recurse down
if len(hierarchy) > 1 {
childName := hierarchy[1]
if qt.childQueueTrackers[childName] != nil {
- return
qt.childQueueTrackers[childName].IsQueuePathTrackedCompletely(hierarchy[1:])
+ return
qt.childQueueTrackers[childName].isQueuePathTrackedCompletely(hierarchy[1:])
}
} else if len(hierarchy) == 1 {
// reach end of hierarchy
@@ -275,18 +321,18 @@ func (qt *QueueTracker)
IsQueuePathTrackedCompletely(hierarchy []string) bool {
return false
}
-// IsUnlinkRequired Traverse queue path upto the leaf queue and decide whether
+// isUnlinkRequired Traverse queue path upto the leaf queue and decide whether
// linkage needs to be removed or not based on the running applications.
// If there are any running applications in end leaf queue, we should remove
the linkage between
-// the leaf and its parent queue using UnlinkQT method. Otherwise, we should
leave as it is.
+// the leaf and its parent queue using unlink method. Otherwise, we should
leave as it is.
// Note: Lock free call. The RLock of the linked tracker (UserTracker and
GroupTracker) should be held before calling this function.
-func (qt *QueueTracker) IsUnlinkRequired(hierarchy []string) bool {
+func (qt *QueueTracker) isUnlinkRequired(hierarchy []string) bool {
// depth first: all the way to the leaf, ignore if not exists
// more than 1 in the slice means we need to recurse down
if len(hierarchy) > 1 {
childName := hierarchy[1]
if qt.childQueueTrackers[childName] != nil {
- return
qt.childQueueTrackers[childName].IsUnlinkRequired(hierarchy[1:])
+ return
qt.childQueueTrackers[childName].isUnlinkRequired(hierarchy[1:])
}
} else if len(hierarchy) == 1 {
// reach end of hierarchy
@@ -302,10 +348,10 @@ func (qt *QueueTracker) IsUnlinkRequired(hierarchy
[]string) bool {
return false
}
-// UnlinkQT Traverse queue path upto the end queue. If end queue has any more
child queue trackers,
+// unlink Traverse queue path upto the end queue. If end queue has any more
child queue trackers,
// then goes upto each child queue and removes the linkage with its immediate
parent
// Note: Lock free call. The Lock of the linked tracker (UserTracker and
GroupTracker) should be held before calling this function.
-func (qt *QueueTracker) UnlinkQT(hierarchy []string) bool {
+func (qt *QueueTracker) unlink(hierarchy []string) bool {
log.Log(log.SchedUGM).Debug("Unlinking current queue tracker from its
parent",
zap.String("current queue ", qt.queueName),
zap.String("queue path", qt.queuePath),
@@ -316,7 +362,7 @@ func (qt *QueueTracker) UnlinkQT(hierarchy []string) bool {
if len(hierarchy) > 1 {
childName := hierarchy[1]
if qt.childQueueTrackers[childName] != nil {
- if
qt.childQueueTrackers[childName].UnlinkQT(hierarchy[1:]) {
+ if
qt.childQueueTrackers[childName].unlink(hierarchy[1:]) {
delete(qt.childQueueTrackers, childName)
// returning false, so that it comes out when
end queue detach itself from its immediate parent.
// i.e., once leaf detached from root.parent
for root.parent.leaf queue path.
@@ -327,7 +373,7 @@ func (qt *QueueTracker) UnlinkQT(hierarchy []string) bool {
} else if len(hierarchy) <= 1 {
// reach end of hierarchy, unlink all queues under this queue
for childName, childQT := range qt.childQueueTrackers {
- if childQT.UnlinkQT([]string{childName}) {
+ if childQT.unlink([]string{childName}) {
delete(qt.childQueueTrackers, childName)
}
}
diff --git a/pkg/scheduler/ugm/queue_tracker_test.go
b/pkg/scheduler/ugm/queue_tracker_test.go
index 52f7c216..da1eb750 100644
--- a/pkg/scheduler/ugm/queue_tracker_test.go
+++ b/pkg/scheduler/ugm/queue_tracker_test.go
@@ -60,7 +60,7 @@ func TestQTIncreaseTrackedResource(t *testing.T) {
t.Errorf("new resource create returned error or wrong resource:
error %t, res %v", err, usage3)
}
queueTracker.increaseTrackedResource(strings.Split(queuePath4,
configs.DOT), TestApp4, user, usage4)
- actualResources := getQTResource(queueTracker)
+ actualResources := queueTracker.getUsedResources()
assert.Equal(t, "map[mem:80000000 vcore:80000]",
actualResources["root"].String(), "wrong resource")
assert.Equal(t, "map[mem:80000000 vcore:80000]",
actualResources["root.parent"].String(), "wrong resource")
@@ -90,7 +90,7 @@ func TestQTDecreaseTrackedResource(t *testing.T) {
t.Errorf("new resource create returned error or wrong resource:
error %t, res %v", err, usage2)
}
queueTracker.increaseTrackedResource(strings.Split(queuePath2,
configs.DOT), TestApp2, user, usage2)
- actualResources := getQTResource(queueTracker)
+ actualResources := queueTracker.getUsedResources()
assert.Equal(t, 2, len(queueTracker.runningApplications))
assert.Equal(t, "map[mem:90000000 vcore:90000]",
actualResources["root"].String(), "wrong resource")
@@ -107,7 +107,7 @@ func TestQTDecreaseTrackedResource(t *testing.T) {
assert.Equal(t, removeQT, false, "wrong remove queue tracker value")
removeQT =
queueTracker.decreaseTrackedResource(strings.Split(queuePath2, configs.DOT),
TestApp2, usage3, false)
- actualResources1 := getQTResource(queueTracker)
+ actualResources1 := queueTracker.getUsedResources()
assert.Equal(t, removeQT, false, "wrong remove queue tracker value")
assert.Equal(t, "map[mem:70000000 vcore:70000]",
actualResources1["root"].String(), "wrong resource")
@@ -361,33 +361,39 @@ func TestGetResourceUsageDAOInfo(t *testing.T) {
childQ.maxResources = maxRes.Clone()
parentQ.maxRunningApps = 3
- rootDao := root.getResourceUsageDAOInfo("")
- assert.Assert(t, resources.Equals(usage1, rootDao.ResourceUsage))
+ rootDao := root.getResourceUsageDAOInfo()
+ assert.DeepEqual(t, usage1.DAOMap(), rootDao.ResourceUsage)
assert.Equal(t, "root", rootDao.QueuePath)
assert.Equal(t, 1, len(rootDao.RunningApplications))
assert.Equal(t, TestApp1, rootDao.RunningApplications[0])
assert.Equal(t, 1, len(rootDao.Children))
assert.Equal(t, uint64(0), rootDao.MaxApplications)
- assert.Assert(t, rootDao.MaxResources == nil)
+ assert.Assert(t, len(rootDao.MaxResources) == 0, "expected empty max
resource")
parentDao := rootDao.Children[0]
- assert.Assert(t, resources.Equals(usage1, parentDao.ResourceUsage))
+ assert.DeepEqual(t, usage1.DAOMap(), parentDao.ResourceUsage)
assert.Equal(t, "root.parent", parentDao.QueuePath)
assert.Equal(t, 1, len(parentDao.RunningApplications))
assert.Equal(t, TestApp1, parentDao.RunningApplications[0])
assert.Equal(t, uint64(3), parentDao.MaxApplications)
- assert.Assert(t, parentDao.MaxResources == nil)
+ assert.Assert(t, len(parentDao.MaxResources) == 0, "expected empty max
resource")
assert.Equal(t, 1, len(parentDao.Children))
childDao := parentDao.Children[0]
- assert.Assert(t, resources.Equals(usage1, childDao.ResourceUsage))
+ assert.DeepEqual(t, usage1.DAOMap(), childDao.ResourceUsage)
assert.Equal(t, "root.parent.child1", childDao.QueuePath)
assert.Equal(t, 1, len(childDao.RunningApplications))
assert.Equal(t, TestApp1, childDao.RunningApplications[0])
assert.Equal(t, uint64(2), childDao.MaxApplications)
- assert.Assert(t, resources.Equals(maxRes, childDao.MaxResources))
+ assert.DeepEqual(t, maxRes.DAOMap(), childDao.MaxResources)
assert.Equal(t, 0, len(childDao.Children))
+ // final nil check for receiver
+ defer func() {
+ if r := recover(); r != nil {
+ t.Fatal("getResourceUsageDAOInfo panic on nil receiver")
+ }
+ }()
root = nil
- rootDao = root.getResourceUsageDAOInfo("")
+ rootDao = root.getResourceUsageDAOInfo()
assert.DeepEqual(t, rootDao, &dao.ResourceUsageDAOInfo{})
}
@@ -445,9 +451,3 @@ func TestSetLimit(t *testing.T) {
assert.Assert(t, resources.Equals(newLimit, childQ.maxResources))
assert.Equal(t, uint64(5), childQ.maxRunningApps)
}
-
-func getQTResource(qt *QueueTracker) map[string]*resources.Resource {
- resources := make(map[string]*resources.Resource)
- usage := qt.getResourceUsageDAOInfo("")
- return internalGetResource(usage, resources)
-}
diff --git a/pkg/scheduler/ugm/user_tracker.go
b/pkg/scheduler/ugm/user_tracker.go
index 56996464..df7de072 100644
--- a/pkg/scheduler/ugm/user_tracker.go
+++ b/pkg/scheduler/ugm/user_tracker.go
@@ -121,45 +121,49 @@ func (ut *UserTracker) clearLimits(queuePath string,
doWildCardCheck bool) {
ut.queueTracker.setLimit(strings.Split(queuePath, configs.DOT), nil, 0,
false, user, doWildCardCheck)
}
-// Note: headroom of queue tracker is not read-only, it also traverses the
queue hierarchy and creates childQueueTracker if it does not exist.
+// headroom calculate the resource headroom for the user in the hierarchy
defined
+// Note: headroom of queue tracker is not read-only.
+// It traverses the queue hierarchy and creates a childQueueTracker if it does
not exist.
func (ut *UserTracker) headroom(hierarchy []string) *resources.Resource {
ut.Lock()
defer ut.Unlock()
return ut.queueTracker.headroom(hierarchy, user)
}
-func (ut *UserTracker) GetUserResourceUsageDAOInfo()
*dao.UserResourceUsageDAOInfo {
+// GetResourceUsageDAOInfo returns the DAO object used in the REST API for
this user tracker
+func (ut *UserTracker) GetResourceUsageDAOInfo() *dao.UserResourceUsageDAOInfo
{
ut.RLock()
defer ut.RUnlock()
- userResourceUsage := &dao.UserResourceUsageDAOInfo{
- Groups: make(map[string]string),
- }
- userResourceUsage.UserName = ut.userName
+ groups := make(map[string]string, len(ut.appGroupTrackers))
for app, gt := range ut.appGroupTrackers {
if gt != nil {
- userResourceUsage.Groups[app] = gt.groupName
+ groups[app] = gt.groupName
}
}
- userResourceUsage.Queues =
ut.queueTracker.getResourceUsageDAOInfo(common.Empty)
- return userResourceUsage
+
+ return &dao.UserResourceUsageDAOInfo{
+ Groups: groups,
+ UserName: ut.userName,
+ Queues: ut.queueTracker.getResourceUsageDAOInfo(),
+ }
}
-func (ut *UserTracker) IsQueuePathTrackedCompletely(hierarchy []string) bool {
+func (ut *UserTracker) isQueuePathTrackedCompletely(hierarchy []string) bool {
ut.RLock()
defer ut.RUnlock()
- return ut.queueTracker.IsQueuePathTrackedCompletely(hierarchy)
+ return ut.queueTracker.isQueuePathTrackedCompletely(hierarchy)
}
-func (ut *UserTracker) IsUnlinkRequired(hierarchy []string) bool {
+func (ut *UserTracker) isUnlinkRequired(hierarchy []string) bool {
ut.RLock()
defer ut.RUnlock()
- return ut.queueTracker.IsUnlinkRequired(hierarchy)
+ return ut.queueTracker.isUnlinkRequired(hierarchy)
}
-func (ut *UserTracker) UnlinkQT(hierarchy []string) bool {
+func (ut *UserTracker) unlinkQT(hierarchy []string) bool {
ut.Lock()
defer ut.Unlock()
- return ut.queueTracker.UnlinkQT(hierarchy)
+ return ut.queueTracker.unlink(hierarchy)
}
func (ut *UserTracker) canBeRemoved() bool {
@@ -168,9 +172,38 @@ func (ut *UserTracker) canBeRemoved() bool {
return ut.queueTracker.canBeRemoved()
}
-// Note: canRunApp of queue tracker is not read-only, it also traverses the
queue hierarchy and creates a childQueueTracker if it does not exist.
+// canRunApp checks if the user is allowed to run the application in the queue
defined in hierarchy.
+// Note: canRunApp of queue tracker is not read-only.
+// It traverses the queue hierarchy and creates a childQueueTracker if it does
not exist.
func (ut *UserTracker) canRunApp(hierarchy []string, applicationID string)
bool {
ut.Lock()
defer ut.Unlock()
return ut.queueTracker.canRunApp(hierarchy, applicationID, user)
}
+
+// GetMaxResources returns a map of the maxResources for all queues registered
under this user tracker.
+// The key into the map is the queue path.
+// This should only be used in test
+func (ut *UserTracker) GetMaxResources() map[string]*resources.Resource {
+ ut.RLock()
+ defer ut.RUnlock()
+ return ut.queueTracker.getMaxResources()
+}
+
+// GetMaxApplications returns a map of the maxRunningApps for all queues
registered under this user tracker.
+// The key into the map is the queue path.
+// This should only be used in test
+func (ut *UserTracker) GetMaxApplications() map[string]uint64 {
+ ut.RLock()
+ defer ut.RUnlock()
+ return ut.queueTracker.getMaxApplications()
+}
+
+// getUsedResources returns a map of the usedResources for all queues
registered under this user tracker.
+// The key into the map is the queue path.
+// This should only be used in test
+func (ut *UserTracker) getUsedResources() map[string]*resources.Resource {
+ ut.RLock()
+ defer ut.RUnlock()
+ return ut.queueTracker.getUsedResources()
+}
diff --git a/pkg/scheduler/ugm/user_tracker_test.go
b/pkg/scheduler/ugm/user_tracker_test.go
index 1b860561..1fe81901 100644
--- a/pkg/scheduler/ugm/user_tracker_test.go
+++ b/pkg/scheduler/ugm/user_tracker_test.go
@@ -99,7 +99,7 @@ func TestIncreaseTrackedResource(t *testing.T) {
userTracker.increaseTrackedResource(path4, TestApp4, usage4)
userTracker.setGroupForApp(TestApp4, groupTracker)
- actualResources := getUserResource(userTracker)
+ actualResources := userTracker.getUsedResources()
assert.Equal(t, "map[mem:80000000 vcore:80000]",
actualResources["root"].String(), "wrong resource")
assert.Equal(t, "map[mem:80000000 vcore:80000]",
actualResources["root.parent"].String(), "wrong resource")
assert.Equal(t, "map[mem:40000000 vcore:40000]",
actualResources["root.parent.child1"].String(), "wrong resource")
@@ -134,8 +134,8 @@ func TestDecreaseTrackedResource(t *testing.T) {
}
userTracker.increaseTrackedResource(path2, TestApp2, usage2)
userTracker.setGroupForApp(TestApp2, groupTracker)
- actualResources := getUserResource(userTracker)
+ actualResources := userTracker.getUsedResources()
assert.Equal(t, 2, len(userTracker.getTrackedApplications()))
assert.Equal(t, "map[mem:90000000 vcore:90000]",
actualResources["root"].String(), "wrong resource")
assert.Equal(t, "map[mem:90000000 vcore:90000]",
actualResources["root.parent"].String(), "wrong resource")
@@ -153,9 +153,9 @@ func TestDecreaseTrackedResource(t *testing.T) {
assert.Equal(t, si.EventRecord_REMOVE,
eventSystem.Events[0].EventChangeType)
removeQT = userTracker.decreaseTrackedResource(path2, TestApp2, usage3,
false)
- actualResources1 := getUserResource(userTracker)
-
assert.Equal(t, removeQT, false, "wrong remove queue tracker value")
+
+ actualResources1 := userTracker.getUsedResources()
assert.Equal(t, "map[mem:70000000 vcore:70000]",
actualResources1["root"].String(), "wrong resource")
assert.Equal(t, "map[mem:70000000 vcore:70000]",
actualResources1["root.parent"].String(), "wrong resource")
assert.Equal(t, "map[mem:60000000 vcore:60000]",
actualResources1["root.parent.child1"].String(), "wrong resource")
@@ -289,9 +289,3 @@ func TestUTCanRunApp(t *testing.T) {
assert.Assert(t, userTracker.canRunApp(hierarchy1, TestApp1))
assert.Assert(t, !userTracker.canRunApp(hierarchy1, TestApp2))
}
-
-func getUserResource(ut *UserTracker) map[string]*resources.Resource {
- resources := make(map[string]*resources.Resource)
- usage := ut.GetUserResourceUsageDAOInfo()
- return internalGetResource(usage.Queues, resources)
-}
diff --git a/pkg/scheduler/ugm/utilities_test.go
b/pkg/scheduler/ugm/utilities_test.go
index 09481e1e..ec666b46 100644
--- a/pkg/scheduler/ugm/utilities_test.go
+++ b/pkg/scheduler/ugm/utilities_test.go
@@ -22,21 +22,8 @@ import (
"testing"
"gotest.tools/v3/assert"
-
- "github.com/apache/yunikorn-core/pkg/common/resources"
- "github.com/apache/yunikorn-core/pkg/webservice/dao"
)
-func internalGetResource(usage *dao.ResourceUsageDAOInfo, resources
map[string]*resources.Resource) map[string]*resources.Resource {
- resources[usage.QueuePath] = usage.ResourceUsage
- if len(usage.Children) > 0 {
- for _, resourceUsage := range usage.Children {
- internalGetResource(resourceUsage, resources)
- }
- }
- return resources
-}
-
func TestGetParentQueuePath(t *testing.T) {
assert.Equal(t, getParentPath(""), "")
assert.Equal(t, getParentPath("root"), "")
diff --git a/pkg/scheduler/utilities_test.go b/pkg/scheduler/utilities_test.go
index d2f9df80..c3bd6c9a 100644
--- a/pkg/scheduler/utilities_test.go
+++ b/pkg/scheduler/utilities_test.go
@@ -30,7 +30,6 @@ import (
"github.com/apache/yunikorn-core/pkg/rmproxy"
"github.com/apache/yunikorn-core/pkg/scheduler/objects"
"github.com/apache/yunikorn-core/pkg/scheduler/ugm"
- "github.com/apache/yunikorn-core/pkg/webservice/dao"
siCommon "github.com/apache/yunikorn-scheduler-interface/lib/go/common"
"github.com/apache/yunikorn-scheduler-interface/lib/go/si"
)
@@ -714,20 +713,24 @@ func assertLimits(t *testing.T, userGroup
security.UserGroup, expected *resource
func assertUserGroupResourceMaxLimits(t *testing.T, userGroup
security.UserGroup, expected *resources.Resource, expectedQueuesMaxLimits
map[string]map[string]interface{}) {
manager := ugm.GetUserManager()
- userResource := manager.GetUserResources(userGroup)
+ userResource := manager.GetUserResources(userGroup.User)
groupResource := manager.GetGroupResources(userGroup.Groups[0])
+ if expected == nil {
+ assert.Assert(t, userResource.IsEmpty(), "expected empty
resource in user tracker")
+ assert.Assert(t, groupResource.IsEmpty(), "expected empty
resource in group tracker")
+ } else {
+ assert.Assert(t, resources.Equals(userResource, expected),
"user value '%s' not equal to expected '%s'", userResource.String(),
expected.String())
+ assert.Assert(t, resources.Equals(groupResource, expected),
"group value '%s' not equal to expected '%s'", groupResource.String(),
expected.String())
+ }
ut := manager.GetUserTracker(userGroup.User)
if ut != nil {
- maxResources := make(map[string]*resources.Resource)
- usage := ut.GetUserResourceUsageDAOInfo()
- getMaxResource(usage.Queues, maxResources)
+ maxResources := ut.GetMaxResources()
for q, qMaxLimits := range expectedQueuesMaxLimits {
if qRes, ok := maxResources[q]; ok {
assert.Equal(t, resources.Equals(qRes,
qMaxLimits[maxresources].(*resources.Resource)), true)
}
}
- maxApplications := make(map[string]uint64)
- getMaxApplications(usage.Queues, maxApplications)
+ maxApplications := ut.GetMaxApplications()
for q, qMaxLimits := range expectedQueuesMaxLimits {
if qApps, ok := maxApplications[q]; ok {
assert.Equal(t, qApps,
qMaxLimits[maxapplications].(uint64), "queue path is "+q+" actual:
"+strconv.Itoa(int(qApps))+", expected:
"+strconv.Itoa(int(qMaxLimits[maxapplications].(uint64))))
@@ -735,44 +738,19 @@ func assertUserGroupResourceMaxLimits(t *testing.T,
userGroup security.UserGroup
}
}
- gt := manager.GetUserTracker(userGroup.User)
+ gt := manager.GetGroupTracker(userGroup.Groups[0])
if gt != nil {
- gMaxResources := make(map[string]*resources.Resource)
- gUsage := gt.GetUserResourceUsageDAOInfo()
- getMaxResource(gUsage.Queues, gMaxResources)
+ gMaxResources := gt.GetMaxResources()
for q, qMaxLimits := range expectedQueuesMaxLimits {
if qRes, ok := gMaxResources[q]; ok {
assert.Equal(t, resources.Equals(qRes,
qMaxLimits[maxresources].(*resources.Resource)), true)
}
}
- gMaxApps := make(map[string]uint64)
- getMaxApplications(gUsage.Queues, gMaxApps)
+ gMaxApps := gt.GetMaxApplications()
for q, qMaxLimits := range expectedQueuesMaxLimits {
if qApps, ok := gMaxApps[q]; ok {
assert.Equal(t, qApps,
qMaxLimits[maxapplications].(uint64))
}
}
}
- assert.Equal(t, resources.Equals(userResource, expected), true)
- assert.Equal(t, resources.Equals(groupResource, expected), true)
-}
-
-func getMaxResource(usage *dao.ResourceUsageDAOInfo, maxResources
map[string]*resources.Resource) map[string]*resources.Resource {
- maxResources[usage.QueuePath] = usage.MaxResources
- if len(usage.Children) > 0 {
- for _, resourceUsage := range usage.Children {
- getMaxResource(resourceUsage, maxResources)
- }
- }
- return maxResources
-}
-
-func getMaxApplications(usage *dao.ResourceUsageDAOInfo, maxApplications
map[string]uint64) map[string]uint64 {
- maxApplications[usage.QueuePath] = usage.MaxApplications
- if len(usage.Children) > 0 {
- for _, resourceUsage := range usage.Children {
- getMaxApplications(resourceUsage, maxApplications)
- }
- }
- return maxApplications
}
diff --git a/pkg/webservice/dao/ugm_info.go b/pkg/webservice/dao/ugm_info.go
index e7b26cf2..4ac5dee1 100644
--- a/pkg/webservice/dao/ugm_info.go
+++ b/pkg/webservice/dao/ugm_info.go
@@ -18,8 +18,6 @@
package dao
-import "github.com/apache/yunikorn-core/pkg/common/resources"
-
type UserResourceUsageDAOInfo struct {
UserName string `json:"userName"` // no omitempty, user
name should not be empty
Groups map[string]string `json:"groups,omitempty"`
@@ -34,9 +32,9 @@ type GroupResourceUsageDAOInfo struct {
type ResourceUsageDAOInfo struct {
QueuePath string `json:"queuePath"` // no
omitempty, queue path should not be empty
- ResourceUsage *resources.Resource
`json:"resourceUsage,omitempty"`
+ ResourceUsage map[string]int64
`json:"resourceUsage,omitempty"`
RunningApplications []string
`json:"runningApplications,omitempty"`
- MaxResources *resources.Resource
`json:"maxResources,omitempty"`
+ MaxResources map[string]int64
`json:"maxResources,omitempty"`
MaxApplications uint64
`json:"maxApplications,omitempty"`
Children []*ResourceUsageDAOInfo `json:"children,omitempty"`
}
diff --git a/pkg/webservice/handlers.go b/pkg/webservice/handlers.go
index d06d6234..93468516 100644
--- a/pkg/webservice/handlers.go
+++ b/pkg/webservice/handlers.go
@@ -1183,10 +1183,10 @@ func getMetrics(w http.ResponseWriter, r *http.Request)
{
func getUsersResourceUsage(w http.ResponseWriter, _ *http.Request) {
writeHeaders(w)
userManager := ugm.GetUserManager()
- usersResources := userManager.GetUsersResources()
- result := make([]*dao.UserResourceUsageDAOInfo, len(usersResources))
- for i, tracker := range usersResources {
- result[i] = tracker.GetUserResourceUsageDAOInfo()
+ trackers := userManager.GetUserTrackers()
+ result := make([]*dao.UserResourceUsageDAOInfo, len(trackers))
+ for i, tracker := range trackers {
+ result[i] = tracker.GetResourceUsageDAOInfo()
}
if err := json.NewEncoder(w).Encode(result); err != nil {
buildJSONErrorResponse(w, err.Error(),
http.StatusInternalServerError)
@@ -1215,8 +1215,8 @@ func getUserResourceUsage(w http.ResponseWriter, r
*http.Request) {
buildJSONErrorResponse(w, UserDoesNotExists,
http.StatusNotFound)
return
}
- var result = userTracker.GetUserResourceUsageDAOInfo()
- if err := json.NewEncoder(w).Encode(result); err != nil {
+ result := userTracker.GetResourceUsageDAOInfo()
+ if err = json.NewEncoder(w).Encode(result); err != nil {
buildJSONErrorResponse(w, err.Error(),
http.StatusInternalServerError)
}
}
@@ -1224,10 +1224,10 @@ func getUserResourceUsage(w http.ResponseWriter, r
*http.Request) {
func getGroupsResourceUsage(w http.ResponseWriter, r *http.Request) {
writeHeaders(w)
userManager := ugm.GetUserManager()
- groupsResources := userManager.GetGroupsResources()
- result := make([]*dao.GroupResourceUsageDAOInfo, len(groupsResources))
- for i, tracker := range groupsResources {
- result[i] = tracker.GetGroupResourceUsageDAOInfo()
+ trackers := userManager.GetGroupTrackers()
+ result := make([]*dao.GroupResourceUsageDAOInfo, len(trackers))
+ for i, tracker := range trackers {
+ result[i] = tracker.GetResourceUsageDAOInfo()
}
if err := json.NewEncoder(w).Encode(result); err != nil {
buildJSONErrorResponse(w, err.Error(),
http.StatusInternalServerError)
@@ -1256,8 +1256,8 @@ func getGroupResourceUsage(w http.ResponseWriter, r
*http.Request) {
buildJSONErrorResponse(w, GroupDoesNotExists,
http.StatusNotFound)
return
}
- var result = groupTracker.GetGroupResourceUsageDAOInfo()
- if err := json.NewEncoder(w).Encode(result); err != nil {
+ result := groupTracker.GetResourceUsageDAOInfo()
+ if err = json.NewEncoder(w).Encode(result); err != nil {
buildJSONErrorResponse(w, err.Error(),
http.StatusInternalServerError)
}
}
diff --git a/pkg/webservice/handlers_test.go b/pkg/webservice/handlers_test.go
index 4ffb231c..f262140b 100644
--- a/pkg/webservice/handlers_test.go
+++ b/pkg/webservice/handlers_test.go
@@ -2149,12 +2149,12 @@ func TestSpecificUserResourceUsage(t *testing.T) {
Groups: map[string]string{"app-1": "testgroup"},
Queues: &dao.ResourceUsageDAOInfo{
QueuePath: "root",
- ResourceUsage:
resources.NewResourceFromMap(map[string]resources.Quantity{"vcore": 1}),
+ ResourceUsage: map[string]int64{"vcore":
1},
RunningApplications: []string{"app-1"},
Children: []*dao.ResourceUsageDAOInfo{
{
QueuePath:
"root.default",
- ResourceUsage:
resources.NewResourceFromMap(map[string]resources.Quantity{"vcore": 1}),
+ ResourceUsage:
map[string]int64{"vcore": 1},
RunningApplications:
[]string{"app-1"},
},
},
@@ -2220,13 +2220,13 @@ func TestSpecificGroupResourceUsage(t *testing.T) {
Applications: []string{"app-1"},
Queues: &dao.ResourceUsageDAOInfo{
QueuePath: "root",
- ResourceUsage:
resources.NewResourceFromMap(map[string]resources.Quantity{"vcore": 1}),
+ ResourceUsage: map[string]int64{"vcore":
1},
RunningApplications: []string{"app-1"},
Children: []*dao.ResourceUsageDAOInfo{
{
QueuePath:
"root.default",
- ResourceUsage:
resources.NewResourceFromMap(map[string]resources.Quantity{"vcore": 1}),
- MaxResources:
resources.NewResourceFromMap(map[string]resources.Quantity{"cpu": 200}),
+ ResourceUsage:
map[string]int64{"vcore": 1},
+ MaxResources:
map[string]int64{"cpu": 200},
RunningApplications:
[]string{"app-1"},
},
},
@@ -2283,8 +2283,8 @@ func TestUsersAndGroupsResourceUsage(t *testing.T) {
getUsersResourceUsage(resp, req)
err = json.Unmarshal(resp.outputBytes, &usersResourceUsageDao)
assert.NilError(t, err, unmarshalError)
- assert.Equal(t, usersResourceUsageDao[0].Queues.ResourceUsage.String(),
-
resources.NewResourceFromMap(map[string]resources.Quantity{siCommon.CPU:
1}).String())
+ assert.DeepEqual(t, usersResourceUsageDao[0].Queues.ResourceUsage,
+
resources.NewResourceFromMap(map[string]resources.Quantity{siCommon.CPU:
1}).DAOMap())
// Assert existing users
assert.Equal(t, len(usersResourceUsageDao), 1)
@@ -2298,8 +2298,8 @@ func TestUsersAndGroupsResourceUsage(t *testing.T) {
getGroupsResourceUsage(resp, req)
err = json.Unmarshal(resp.outputBytes, &groupsResourceUsageDao)
assert.NilError(t, err, unmarshalError)
- assert.Equal(t, groupsResourceUsageDao[0].Queues.ResourceUsage.String(),
-
resources.NewResourceFromMap(map[string]resources.Quantity{siCommon.CPU:
1}).String())
+ assert.DeepEqual(t, groupsResourceUsageDao[0].Queues.ResourceUsage,
+
resources.NewResourceFromMap(map[string]resources.Quantity{siCommon.CPU:
1}).DAOMap())
// Assert existing groups
assert.Equal(t, len(groupsResourceUsageDao), 1)
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]