This is an automated email from the ASF dual-hosted git repository.
mani 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 148f221a [YUNIKORN-1610] Enforcement changes for User Based Quota(#563)
148f221a is described below
commit 148f221ab4f17d10e2e20b52fc2c48991d5b2b65
Author: Manikandan R <[email protected]>
AuthorDate: Mon Jun 26 12:19:33 2023 +0530
[YUNIKORN-1610] Enforcement changes for User Based Quota(#563)
Closes: #563
Signed-off-by: Manikandan R <[email protected]>
---
pkg/common/configs/config_test.go | 2 +
pkg/common/configs/configvalidator.go | 3 +-
.../ugm/tracker.go => common/constants.go} | 21 +-
pkg/common/security/acl.go | 19 +-
pkg/common/security/acl_test.go | 16 +-
pkg/scheduler/objects/application.go | 16 +-
pkg/scheduler/partition_test.go | 21 +-
pkg/scheduler/ugm/group_tracker.go | 41 +-
pkg/scheduler/ugm/group_tracker_test.go | 97 ++--
pkg/scheduler/ugm/manager.go | 578 ++++++++-------------
pkg/scheduler/ugm/manager_test.go | 557 +++++++++++++-------
pkg/scheduler/ugm/queue_tracker.go | 283 +++++++---
pkg/scheduler/ugm/queue_tracker_test.go | 144 +++--
pkg/scheduler/ugm/tracker.go | 4 +-
pkg/scheduler/ugm/user_tracker.go | 41 +-
pkg/scheduler/ugm/user_tracker_test.go | 84 ++-
pkg/scheduler/utilities_test.go | 20 +-
17 files changed, 1090 insertions(+), 857 deletions(-)
diff --git a/pkg/common/configs/config_test.go
b/pkg/common/configs/config_test.go
index ca67a47a..437d73a4 100644
--- a/pkg/common/configs/config_test.go
+++ b/pkg/common/configs/config_test.go
@@ -1848,6 +1848,7 @@ partitions:
`
return fmt.Sprintf(data, leafQueueMaxResource, leafQueueMaxResource,
leafQueueMaxApps, userMaxResource)
}
+
func TestUserLimitsWithHierarchicalQueue(t *testing.T) {
// Make sure parent queue user max apps should not less than the child
queue max resource
// validate the config and check after the update
@@ -2050,6 +2051,7 @@ partitions:
`
return fmt.Sprintf(data, leafQueueMaxResources, leafQueueMaxResources,
leafQueueMaxApps, groupMaxResources)
}
+
func TestGroupLimitsWithHierarchicalQueue(t *testing.T) {
// Make sure parent queue user max apps should not less than the child
queue max resource
// validate the config and check after the update
diff --git a/pkg/common/configs/configvalidator.go
b/pkg/common/configs/configvalidator.go
index ab7dc550..b4c25e45 100644
--- a/pkg/common/configs/configvalidator.go
+++ b/pkg/common/configs/configvalidator.go
@@ -31,7 +31,6 @@ import (
"github.com/apache/yunikorn-core/pkg/common"
"github.com/apache/yunikorn-core/pkg/common/resources"
- "github.com/apache/yunikorn-core/pkg/common/security"
"github.com/apache/yunikorn-core/pkg/log"
"github.com/apache/yunikorn-core/pkg/scheduler/placement/types"
"github.com/apache/yunikorn-core/pkg/scheduler/policies"
@@ -99,7 +98,7 @@ func checkACL(acl string) error {
// trim any white space
acl = strings.TrimSpace(acl)
// handle special cases: deny and wildcard
- if len(acl) == 0 || acl == security.WildCard {
+ if len(acl) == 0 || acl == common.Wildcard {
return nil
}
diff --git a/pkg/scheduler/ugm/tracker.go b/pkg/common/constants.go
similarity index 52%
copy from pkg/scheduler/ugm/tracker.go
copy to pkg/common/constants.go
index 85f3c56d..f7dc90d0 100644
--- a/pkg/scheduler/ugm/tracker.go
+++ b/pkg/common/constants.go
@@ -16,21 +16,10 @@
limitations under the License.
*/
-package ugm
+package common
-import (
- "github.com/apache/yunikorn-core/pkg/common/resources"
- "github.com/apache/yunikorn-core/pkg/common/security"
+const (
+ Wildcard = "*"
+ Separator = ","
+ Space = " "
)
-
-// Tracker Defines a set of interfaces to track and retrieve the user group
resource usage
-type Tracker interface {
- GetUserResources(user security.UserGroup) *resources.Resource
- GetGroupResources(group string) *resources.Resource
-
- GetUsersResources() []*UserTracker
- GetGroupsResources() []*GroupTracker
-
- IncreaseTrackedResource(queuePath, applicationID string, usage
*resources.Resource, user security.UserGroup) error
- DecreaseTrackedResource(queuePath, applicationID string, usage
*resources.Resource, user security.UserGroup, removeApp bool) error
-}
diff --git a/pkg/common/security/acl.go b/pkg/common/security/acl.go
index 3d83a5ad..e1ec919f 100644
--- a/pkg/common/security/acl.go
+++ b/pkg/common/security/acl.go
@@ -25,15 +25,10 @@ import (
"go.uber.org/zap"
+ "github.com/apache/yunikorn-core/pkg/common"
"github.com/apache/yunikorn-core/pkg/log"
)
-const (
- WildCard = "*"
- Separator = ","
- Space = " "
-)
-
// User and group regexp, must allow at least what we allow in the config
checks
// See configs.UserNameRegExp and configs.GroupRegExp in the config validator.
var userNameRegExp = regexp.MustCompile("^[_a-zA-Z][a-zA-Z0-9_.@-]*[$]?$")
@@ -48,7 +43,7 @@ type ACL struct {
// the ACL allows all access, set the flag
func (a *ACL) setAllAllowed(part string) {
part = strings.TrimSpace(part)
- a.allAllowed = part == WildCard
+ a.allAllowed = part == common.Wildcard
}
// set the user list in the ACL, invalid user names are ignored
@@ -59,7 +54,7 @@ func (a *ACL) setUsers(userList []string) {
return
}
// special case if the user list is just the wildcard
- if len(userList) == 1 && userList[0] == WildCard {
+ if len(userList) == 1 && userList[0] == common.Wildcard {
log.Log(log.Security).Info("user list is wildcard, allowing all
access")
a.allAllowed = true
return
@@ -92,7 +87,7 @@ func (a *ACL) setGroups(groupList []string) {
log.Log(log.Security).Info("ignoring group list in ACL:
wildcard set")
return
}
- if len(groupList) == 1 && groupList[0] == WildCard {
+ if len(groupList) == 1 && groupList[0] == common.Wildcard {
log.Log(log.Security).Info("group list is wildcard, allowing
all access")
a.users = make(map[string]bool)
a.allAllowed = true
@@ -122,7 +117,7 @@ func NewACL(aclStr string) (ACL, error) {
}
// before trimming check
// should have no more than two groups defined
- fields := strings.Split(aclStr, Space)
+ fields := strings.Split(aclStr, common.Space)
if len(fields) > 2 {
return acl, fmt.Errorf("multiple spaces found in ACL: '%s'",
aclStr)
}
@@ -133,9 +128,9 @@ func NewACL(aclStr string) (ACL, error) {
return acl, nil
}
// parse users and groups
- acl.setUsers(strings.Split(fields[0], Separator))
+ acl.setUsers(strings.Split(fields[0], common.Separator))
if len(fields) == 2 {
- acl.setGroups(strings.Split(fields[1], Separator))
+ acl.setGroups(strings.Split(fields[1], common.Separator))
}
return acl, nil
}
diff --git a/pkg/common/security/acl_test.go b/pkg/common/security/acl_test.go
index db2c4993..b57649d4 100644
--- a/pkg/common/security/acl_test.go
+++ b/pkg/common/security/acl_test.go
@@ -22,6 +22,8 @@ import (
"errors"
"fmt"
"testing"
+
+ "github.com/apache/yunikorn-core/pkg/common"
)
func IsSameACL(got, expected ACL) error {
@@ -111,23 +113,23 @@ func TestACLCreate(t *testing.T) {
ACL{users: make(map[string]bool), groups:
map[string]bool{"group1": true, "group2": true}, allAllowed: false},
},
{
- "* group1,group2",
+ common.Wildcard + " group1,group2",
ACL{users: make(map[string]bool), groups:
make(map[string]bool), allAllowed: true},
},
{
- "user1,user2 *",
+ "user1,user2 " + common.Wildcard,
ACL{users: make(map[string]bool), groups:
make(map[string]bool), allAllowed: true},
},
{
- "*",
+ common.Wildcard,
ACL{users: make(map[string]bool), allAllowed: true},
},
{
- "* ",
+ common.Wildcard + " ",
ACL{users: make(map[string]bool), groups:
make(map[string]bool), allAllowed: true},
},
{
- " *",
+ " " + common.Wildcard,
ACL{users: make(map[string]bool), groups:
make(map[string]bool), allAllowed: true},
},
{
@@ -210,12 +212,12 @@ func TestACLAccess(t *testing.T) {
false,
},
{
- "*",
+ common.Wildcard,
UserGroup{User: "", Groups: nil},
true,
},
{
- "*",
+ common.Wildcard,
UserGroup{User: "user1", Groups: []string{"group1"}},
true,
},
diff --git a/pkg/scheduler/objects/application.go
b/pkg/scheduler/objects/application.go
index 4de1764c..4ac248d6 100644
--- a/pkg/scheduler/objects/application.go
+++ b/pkg/scheduler/objects/application.go
@@ -1637,25 +1637,13 @@ func (sa *Application) addAllocationInternal(info
*Allocation) {
// Increase user resource usage
// No locking must be called while holding the lock
func (sa *Application) incUserResourceUsage(resource *resources.Resource) {
- if err := ugm.GetUserManager().IncreaseTrackedResource(sa.queuePath,
sa.ApplicationID, resource, sa.user); err != nil {
- log.Log(log.SchedApplication).Error("Unable to track the user
resource usage",
- zap.String("application id", sa.ApplicationID),
- zap.String("user", sa.user.User),
- zap.String("currentState", sa.stateMachine.Current()),
- zap.Error(err))
- }
+ ugm.GetUserManager().IncreaseTrackedResource(sa.queuePath,
sa.ApplicationID, resource, sa.user)
}
// Decrease user resource usage
// No locking must be called while holding the lock
func (sa *Application) decUserResourceUsage(resource *resources.Resource,
removeApp bool) {
- if err := ugm.GetUserManager().DecreaseTrackedResource(sa.queuePath,
sa.ApplicationID, resource, sa.user, removeApp); err != nil {
- log.Log(log.SchedApplication).Error("Unable to track the user
resource usage",
- zap.String("application id", sa.ApplicationID),
- zap.String("user", sa.user.User),
- zap.String("currentState", sa.stateMachine.Current()),
- zap.Error(err))
- }
+ ugm.GetUserManager().DecreaseTrackedResource(sa.queuePath,
sa.ApplicationID, resource, sa.user, removeApp)
}
// When the resource allocated with this allocation is to be removed,
diff --git a/pkg/scheduler/partition_test.go b/pkg/scheduler/partition_test.go
index 99210f11..5a2995d2 100644
--- a/pkg/scheduler/partition_test.go
+++ b/pkg/scheduler/partition_test.go
@@ -107,7 +107,7 @@ func TestNewPartition(t *testing.T) {
"memory": "10",
"vcores": "10",
},
- MaxApplications: 1,
+ MaxApplications: 2,
},
},
},
@@ -350,7 +350,7 @@ func TestRemoveNodeWithAllocations(t *testing.T) {
assert.Equal(t, 1, len(released), "node did not release correct
allocation")
assert.Equal(t, 0, len(confirmed), "node did not confirm correct
allocation")
assert.Equal(t, released[0].GetUUID(), allocUUID, "uuid returned by
release not the same as on allocation")
- assertLimits(t, getTestUserGroup(), nil)
+ assertLimits(t, getTestUserGroup(), resources.Zero)
// wait for events to be processed
err = common.WaitFor(10*time.Millisecond, time.Second, func() bool {
@@ -1084,7 +1084,7 @@ func TestRemoveApp(t *testing.T) {
allocs = partition.removeApplication("will_not_remove")
assert.Equal(t, 1, len(allocs), "existing application with allocations
returned unexpected allocations %v", allocs)
- assertLimits(t, getTestUserGroup(), nil)
+ assertLimits(t, getTestUserGroup(), resources.Zero)
}
func TestRemoveAppAllocs(t *testing.T) {
@@ -1145,7 +1145,7 @@ func TestRemoveAppAllocs(t *testing.T) {
allocs, _ = partition.removeAllocation(release)
assert.Equal(t, 1, len(allocs), "removal request for existing
allocation returned wrong allocations: %v", allocs)
assert.Equal(t, 0, partition.GetTotalAllocationCount(), "removal
requests did not remove all allocations: %v", partition.allocations)
- assertLimits(t, getTestUserGroup(), nil)
+ assertLimits(t, getTestUserGroup(), resources.Zero)
}
// Dynamic queue creation based on the name from the rules
@@ -1375,7 +1375,7 @@ func TestTryAllocate(t *testing.T) {
expectedQueuesMaxLimits["root.leaf"] = make(map[string]interface{})
expectedQueuesMaxLimits["root"][maxresources] =
resources.NewResourceFromMap(map[string]resources.Quantity{"memory": 10,
"vcores": 10})
expectedQueuesMaxLimits["root.leaf"][maxresources] =
resources.NewResourceFromMap(map[string]resources.Quantity{"memory": 5,
"vcores": 5})
- expectedQueuesMaxLimits["root"][maxapplications] = uint64(2)
+ expectedQueuesMaxLimits["root"][maxapplications] = uint64(10)
expectedQueuesMaxLimits["root.leaf"][maxapplications] = uint64(1)
assertUserGroupResourceMaxLimits(t, getTestUserGroup(), nil,
expectedQueuesMaxLimits)
@@ -1891,10 +1891,9 @@ func getExpectedQueuesLimitsForPreemption()
map[string]map[string]interface{} {
expectedQueuesMaxLimits["root"][maxresources] =
resources.NewResourceFromMap(map[string]resources.Quantity{"memory": 10,
"vcores": 10})
expectedQueuesMaxLimits["root.parent"][maxresources] =
resources.NewResourceFromMap(map[string]resources.Quantity{"memory": 5,
"vcores": 5})
expectedQueuesMaxLimits["root.parent.leaf1"][maxresources] =
expectedQueuesMaxLimits["root.parent"][maxresources]
- expectedQueuesMaxLimits["root"][maxapplications] = uint64(2)
- expectedQueuesMaxLimits["root.parent"][maxapplications] = uint64(2)
- expectedQueuesMaxLimits["root.parent.leaf1"][maxapplications] =
uint64(1)
- expectedQueuesMaxLimits["root.parent.leaf1"][maxapplications] =
uint64(1)
+ expectedQueuesMaxLimits["root"][maxapplications] = uint64(10)
+ expectedQueuesMaxLimits["root.parent"][maxapplications] = uint64(8)
+ expectedQueuesMaxLimits["root.parent.leaf1"][maxapplications] =
uint64(8)
return expectedQueuesMaxLimits
}
@@ -1908,9 +1907,9 @@ func
getExpectedQueuesLimitsForPreemptionWithRequiredNode() map[string]map[strin
expectedQueuesMaxLimits["root.leaf"][maxresources] =
resources.NewResourceFromMap(map[string]resources.Quantity{"memory": 5,
"vcores": 5})
expectedQueuesMaxLimits["root.parent"][maxresources] =
expectedQueuesMaxLimits["root.leaf"][maxresources]
expectedQueuesMaxLimits["root.parent.sub-leaf"][maxresources] =
resources.NewResourceFromMap(map[string]resources.Quantity{"memory": 3,
"vcores": 3})
- expectedQueuesMaxLimits["root"][maxapplications] = uint64(2)
+ expectedQueuesMaxLimits["root"][maxapplications] = uint64(10)
expectedQueuesMaxLimits["root.leaf"][maxapplications] = uint64(1)
- expectedQueuesMaxLimits["root.parent"][maxapplications] = uint64(2)
+ expectedQueuesMaxLimits["root.parent"][maxapplications] = uint64(8)
expectedQueuesMaxLimits["root.parent.sub-leaf"][maxapplications] =
uint64(2)
return expectedQueuesMaxLimits
}
diff --git a/pkg/scheduler/ugm/group_tracker.go
b/pkg/scheduler/ugm/group_tracker.go
index 6a4f99b2..48287a44 100644
--- a/pkg/scheduler/ugm/group_tracker.go
+++ b/pkg/scheduler/ugm/group_tracker.go
@@ -43,14 +43,14 @@ func newGroupTracker(group string) *GroupTracker {
return groupTracker
}
-func (gt *GroupTracker) increaseTrackedResource(queuePath, applicationID
string, usage *resources.Resource) error {
+func (gt *GroupTracker) increaseTrackedResource(queuePath, applicationID
string, usage *resources.Resource) bool {
gt.Lock()
defer gt.Unlock()
gt.applications[applicationID] = true
- return gt.queueTracker.increaseTrackedResource(queuePath,
applicationID, usage)
+ return gt.queueTracker.increaseTrackedResource(queuePath,
applicationID, group, usage)
}
-func (gt *GroupTracker) decreaseTrackedResource(queuePath, applicationID
string, usage *resources.Resource, removeApp bool) (bool, error) {
+func (gt *GroupTracker) decreaseTrackedResource(queuePath, applicationID
string, usage *resources.Resource, removeApp bool) (bool, bool) {
gt.Lock()
defer gt.Unlock()
if removeApp {
@@ -65,16 +65,10 @@ func (gt *GroupTracker) getTrackedApplications()
map[string]bool {
return gt.applications
}
-func (gt *GroupTracker) setMaxApplications(count uint64, queuePath string)
error {
+func (gt *GroupTracker) setLimits(queuePath string, resource
*resources.Resource, maxApps uint64) {
gt.Lock()
defer gt.Unlock()
- return gt.queueTracker.setMaxApplications(count, queuePath)
-}
-
-func (gt *GroupTracker) setMaxResources(resource *resources.Resource,
queuePath string) error {
- gt.Lock()
- defer gt.Unlock()
- return gt.queueTracker.setMaxResources(resource, queuePath)
+ gt.queueTracker.setLimit(queuePath, resource, maxApps)
}
func (gt *GroupTracker) GetGroupResourceUsageDAOInfo()
*dao.GroupResourceUsageDAOInfo {
@@ -90,3 +84,28 @@ func (gt *GroupTracker) GetGroupResourceUsageDAOInfo()
*dao.GroupResourceUsageDA
groupResourceUsage.Queues = gt.queueTracker.getResourceUsageDAOInfo("")
return groupResourceUsage
}
+
+func (gt *GroupTracker) IsQueuePathTrackedCompletely(queuePath string) bool {
+ gt.RLock()
+ defer gt.RUnlock()
+ return gt.queueTracker.IsQueuePathTrackedCompletely(queuePath)
+}
+
+func (gt *GroupTracker) IsUnlinkRequired(queuePath string) bool {
+ gt.RLock()
+ defer gt.RUnlock()
+ return gt.queueTracker.IsUnlinkRequired(queuePath)
+}
+
+func (gt *GroupTracker) UnlinkQT(queuePath string) bool {
+ gt.RLock()
+ defer gt.RUnlock()
+ return gt.queueTracker.UnlinkQT(queuePath)
+}
+
+// canBeRemoved Does "root" queue has any child queue trackers? Is there any
running applications in "root" qt?
+func (gt *GroupTracker) canBeRemoved() bool {
+ gt.RLock()
+ defer gt.RUnlock()
+ return len(gt.queueTracker.childQueueTrackers) == 0 &&
len(gt.queueTracker.runningApplications) == 0
+}
diff --git a/pkg/scheduler/ugm/group_tracker_test.go
b/pkg/scheduler/ugm/group_tracker_test.go
index f9608b21..7d0ce280 100644
--- a/pkg/scheduler/ugm/group_tracker_test.go
+++ b/pkg/scheduler/ugm/group_tracker_test.go
@@ -32,6 +32,7 @@ func TestGTIncreaseTrackedResource(t *testing.T) {
// root->parent->child1->child12
// root->parent->child2
// root->parent->child12 (similar name like above leaf queue, but it is
being treated differently as similar names are allowed)
+ GetUserManager()
user := &security.UserGroup{User: "test", Groups: []string{"test"}}
groupTracker := newGroupTracker(user.User)
@@ -39,36 +40,36 @@ func TestGTIncreaseTrackedResource(t *testing.T) {
if err != nil {
t.Errorf("new resource create returned error or wrong resource:
error %t, res %v", err, usage1)
}
- err = groupTracker.increaseTrackedResource(queuePath1, TestApp1, usage1)
- if err != nil {
- t.Fatalf("unable to increase tracked resource: queuepath %s,
app %s, res %v, error %t", queuePath1, TestApp1, usage1, err)
+ result := groupTracker.increaseTrackedResource(queuePath1, TestApp1,
usage1)
+ if !result {
+ t.Fatalf("unable to increase tracked resource: queuepath %s,
app %s, res %v", queuePath1, TestApp1, usage1)
}
usage2, err := resources.NewResourceFromConf(map[string]string{"mem":
"20M", "vcore": "20"})
if err != nil {
t.Errorf("new resource create returned error or wrong resource:
error %t, res %v", err, usage2)
}
- err = groupTracker.increaseTrackedResource(queuePath2, TestApp2, usage2)
- if err != nil {
- t.Fatalf("unable to increase tracked resource: queuepath %s,
app %s, res %v, error %t", queuePath2, TestApp2, usage2, err)
+ result = groupTracker.increaseTrackedResource(queuePath2, TestApp2,
usage2)
+ if !result {
+ t.Fatalf("unable to increase tracked resource: queuepath %s,
app %s, res %v", queuePath2, TestApp2, usage2)
}
usage3, err := resources.NewResourceFromConf(map[string]string{"mem":
"30M", "vcore": "30"})
if err != nil {
t.Errorf("new resource create returned error or wrong resource:
error %t, res %v", err, usage3)
}
- err = groupTracker.increaseTrackedResource(queuePath3, TestApp3, usage3)
- if err != nil {
- t.Fatalf("unable to increase tracked resource: queuepath %s,
app %s, res %v, error %t", queuePath3, TestApp3, usage3, err)
+ result = groupTracker.increaseTrackedResource(queuePath3, TestApp3,
usage3)
+ if !result {
+ t.Fatalf("unable to increase tracked resource: queuepath %s,
app %s, res %v", queuePath3, TestApp3, usage3)
}
usage4, err := resources.NewResourceFromConf(map[string]string{"mem":
"20M", "vcore": "20"})
if err != nil {
t.Errorf("new resource create returned error or wrong resource:
error %t, res %v", err, usage3)
}
- err = groupTracker.increaseTrackedResource(queuePath4, TestApp4, usage4)
- if err != nil {
- t.Fatalf("unable to increase tracked resource: queuepath %s,
app %s, res %v, error %t", queuePath4, TestApp4, usage4, err)
+ result = groupTracker.increaseTrackedResource(queuePath4, TestApp4,
usage4)
+ if !result {
+ t.Fatalf("unable to increase tracked resource: queuepath %s,
app %s, res %v", queuePath4, TestApp4, usage4)
}
actualResources := getGroupResource(groupTracker)
@@ -91,9 +92,9 @@ func TestGTDecreaseTrackedResource(t *testing.T) {
if err != nil {
t.Errorf("new resource create returned error or wrong resource:
error %t, res %v", err, usage1)
}
- err = groupTracker.increaseTrackedResource(queuePath1, TestApp1, usage1)
- if err != nil {
- t.Fatalf("unable to increase tracked resource: queuepath %s,
app %s, res %v, error %t", queuePath1, TestApp1, usage1, err)
+ result := groupTracker.increaseTrackedResource(queuePath1, TestApp1,
usage1)
+ if !result {
+ t.Fatalf("unable to increase tracked resource: queuepath %s,
app %s, res %v", queuePath1, TestApp1, usage1)
}
assert.Equal(t, 1, len(groupTracker.getTrackedApplications()))
@@ -101,9 +102,9 @@ func TestGTDecreaseTrackedResource(t *testing.T) {
if err != nil {
t.Errorf("new resource create returned error or wrong resource:
error %t, res %v", err, usage2)
}
- err = groupTracker.increaseTrackedResource(queuePath2, TestApp2, usage2)
- if err != nil {
- t.Fatalf("unable to increase tracked resource: queuepath %s,
app %s, res %v, error %t", queuePath2, TestApp2, usage2, err)
+ result = groupTracker.increaseTrackedResource(queuePath2, TestApp2,
usage2)
+ if !result {
+ t.Fatalf("unable to increase tracked resource: queuepath %s,
app %s, res %v", queuePath2, TestApp2, usage2)
}
actualResources := getGroupResource(groupTracker)
@@ -117,14 +118,14 @@ func TestGTDecreaseTrackedResource(t *testing.T) {
if err != nil {
t.Errorf("new resource create returned error or wrong resource:
error %t, res %v", err, usage3)
}
- removeQT, err := groupTracker.decreaseTrackedResource(queuePath1,
TestApp1, usage3, false)
- if err != nil {
+ removeQT, decreased := groupTracker.decreaseTrackedResource(queuePath1,
TestApp1, usage3, false)
+ if !decreased {
t.Fatalf("unable to decrease tracked resource: queuepath %s,
app %s, res %v, error %t", queuePath1, TestApp1, usage3, err)
}
assert.Equal(t, removeQT, false, "wrong remove queue tracker value")
- removeQT, err = groupTracker.decreaseTrackedResource(queuePath2,
TestApp2, usage3, false)
- if err != nil {
+ removeQT, decreased = groupTracker.decreaseTrackedResource(queuePath2,
TestApp2, usage3, false)
+ if !decreased {
t.Fatalf("unable to decrease tracked resource: queuepath %s,
app %s, res %v, error %t", queuePath2, TestApp2, usage3, err)
}
assert.Equal(t, removeQT, false, "wrong remove queue tracker value")
@@ -141,8 +142,8 @@ func TestGTDecreaseTrackedResource(t *testing.T) {
t.Errorf("new resource create returned error or wrong resource:
error %t, res %v", err, usage3)
}
- removeQT, err = groupTracker.decreaseTrackedResource(queuePath1,
TestApp1, usage4, true)
- if err != nil {
+ removeQT, decreased = groupTracker.decreaseTrackedResource(queuePath1,
TestApp1, usage4, true)
+ if !decreased {
t.Fatalf("unable to decrease tracked resource: queuepath %s,
app %s, res %v, error %t", queuePath1, TestApp1, usage1, err)
}
assert.Equal(t, 1, len(groupTracker.getTrackedApplications()))
@@ -153,8 +154,8 @@ func TestGTDecreaseTrackedResource(t *testing.T) {
t.Errorf("new resource create returned error or wrong resource:
error %t, res %v", err, usage3)
}
- removeQT, err = groupTracker.decreaseTrackedResource(queuePath2,
TestApp2, usage5, true)
- if err != nil {
+ removeQT, decreased = groupTracker.decreaseTrackedResource(queuePath2,
TestApp2, usage5, true)
+ if !decreased {
t.Fatalf("unable to decrease tracked resource: queuepath %s,
app %s, res %v, error %t", queuePath2, TestApp2, usage2, err)
}
assert.Equal(t, 0, len(groupTracker.getTrackedApplications()))
@@ -170,39 +171,25 @@ func TestGTSetMaxLimits(t *testing.T) {
if err != nil {
t.Errorf("new resource create returned error or wrong resource:
error %t, res %v", err, usage1)
}
- err = groupTracker.increaseTrackedResource(queuePath1, TestApp1, usage1)
- if err != nil {
- t.Fatalf("unable to increase tracked resource: queuepath %s,
app %s, res %v, error %t", queuePath1, TestApp1, usage1, err)
- }
-
- setMaxAppsErr := groupTracker.setMaxApplications(1, queuePath1)
- assert.NilError(t, setMaxAppsErr)
-
- setMaxResourcesErr := groupTracker.setMaxResources(usage1, queuePath1)
- assert.NilError(t, setMaxResourcesErr)
-
- setParentMaxAppsErr := groupTracker.setMaxApplications(1, "root.parent")
- assert.NilError(t, setParentMaxAppsErr)
-
- setParentMaxResourcesErr := groupTracker.setMaxResources(usage1,
"root.parent")
- assert.NilError(t, setParentMaxResourcesErr)
- err = groupTracker.increaseTrackedResource(queuePath1, TestApp2, usage1)
- if err != nil {
- t.Fatalf("unable to increase tracked resource: queuepath %s,
app %s, res %v, error %t", queuePath1, TestApp1, usage1, err)
+ result := groupTracker.increaseTrackedResource(queuePath1, TestApp1,
usage1)
+ if !result {
+ t.Fatalf("unable to increase tracked resource: queuepath %s,
app %s, res %v", queuePath1, TestApp1, usage1)
}
- setMaxAppsErr1 := groupTracker.setMaxApplications(1, queuePath1)
- assert.Error(t, setMaxAppsErr1, "current running applications is
greater than config max applications for "+queuePath1)
-
- setMaxResourcesErr1 := groupTracker.setMaxResources(usage1, queuePath1)
- assert.Error(t, setMaxResourcesErr1, "current resource usage is greater
than config max resource for "+queuePath1)
-
- setParentMaxAppsErr1 := groupTracker.setMaxApplications(1,
"root.parent")
- assert.Error(t, setParentMaxAppsErr1, "current running applications is
greater than config max applications for root.parent")
+ groupTracker.setLimits(queuePath1, resources.Multiply(usage1, 5), 5)
+ groupTracker.setLimits("root.parent", resources.Multiply(usage1, 10),
10)
- setParentMaxResourcesErr1 := groupTracker.setMaxResources(usage1,
"root.parent")
- assert.Error(t, setParentMaxResourcesErr1, "current resource usage is
greater than config max resource for root.parent")
+ result = groupTracker.increaseTrackedResource(queuePath1, TestApp2,
usage1)
+ if !result {
+ t.Fatalf("unable to increase tracked resource: queuepath %s,
app %s, res %v", queuePath1, TestApp2, usage1)
+ }
+ result = groupTracker.increaseTrackedResource(queuePath1, TestApp3,
usage1)
+ if !result {
+ t.Fatalf("unable to increase tracked resource: queuepath %s,
app %s, res %v", queuePath1, TestApp2, usage1)
+ }
+ groupTracker.setLimits(queuePath1, usage1, 1)
+ groupTracker.setLimits("root.parent", usage1, 1)
}
func getGroupResource(gt *GroupTracker) map[string]*resources.Resource {
diff --git a/pkg/scheduler/ugm/manager.go b/pkg/scheduler/ugm/manager.go
index be5b5679..5b6a41f5 100644
--- a/pkg/scheduler/ugm/manager.go
+++ b/pkg/scheduler/ugm/manager.go
@@ -24,6 +24,7 @@ import (
"go.uber.org/zap"
+ "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/common/security"
@@ -33,25 +34,22 @@ import (
var once sync.Once
var m *Manager
-const maxresources = "maxresources"
-const maxapplications = "maxapplications"
-
// Manager implements tracker. A User Group Manager to track the usage for
both user and groups.
// Holds object of both user and group trackers
type Manager struct {
- userTrackers map[string]*UserTracker
- groupTrackers map[string]*GroupTracker
- userLimitsConfig map[string]map[string]map[string]interface{} // Hold
limits settings of user * queue path
- groupLimitsConfig map[string]map[string]map[string]interface{} // Hold
limits settings of group * queue path
+ userTrackers map[string]*UserTracker
+ groupTrackers map[string]*GroupTracker
+ userWildCardLimitsConfig map[string]*LimitConfig // Hold limits
settings of user '*'
+ groupWildCardLimitsConfig map[string]*LimitConfig // Hold limits
settings of group '*'
sync.RWMutex
}
func newManager() *Manager {
manager := &Manager{
- userTrackers: make(map[string]*UserTracker),
- groupTrackers: make(map[string]*GroupTracker),
- userLimitsConfig:
make(map[string]map[string]map[string]interface{}),
- groupLimitsConfig:
make(map[string]map[string]map[string]interface{}),
+ userTrackers: make(map[string]*UserTracker),
+ groupTrackers: make(map[string]*GroupTracker),
+ userWildCardLimitsConfig: make(map[string]*LimitConfig),
+ groupWildCardLimitsConfig: make(map[string]*LimitConfig),
}
return manager
}
@@ -63,192 +61,134 @@ func GetUserManager() *Manager {
return m
}
+// LimitConfig Holds limit settings of wild card user/group
+type LimitConfig struct {
+ maxResources *resources.Resource
+ maxApplications uint64
+}
+
// IncreaseTrackedResource Increase the resource usage for the given user
group and queue path combination.
// As and when every allocation or asks requests fulfilled on application,
corresponding user and group
// resource usage would be increased against specific application.
-func (m *Manager) IncreaseTrackedResource(queuePath string, applicationID
string, usage *resources.Resource, user security.UserGroup) error {
- log.Log(log.SchedUGM).Debug("Increasing resource usage",
zap.String("user", user.User),
+func (m *Manager) IncreaseTrackedResource(queuePath, applicationID string,
usage *resources.Resource, user security.UserGroup) bool {
+ log.Log(log.SchedUGM).Debug("Increasing resource usage",
+ zap.String("user", user.User),
+ zap.String("group", user.Groups[0]),
zap.String("queue path", queuePath),
zap.String("application", applicationID),
zap.Stringer("resource", usage))
if queuePath == "" || applicationID == "" || usage == nil || user.User
== "" {
- log.Log(log.SchedUGM).Error("Mandatory parameters are missing
to increase the resource usage",
+ log.Log(log.SchedUGM).Debug("Mandatory parameters are missing
to increase the resource usage",
zap.String("user", user.User),
zap.String("queue path", queuePath),
zap.String("application", applicationID),
zap.Stringer("resource", usage))
- return fmt.Errorf("mandatory parameters are missing. queuepath:
%s, application id: %s, resource usage: %s, user: %s",
- queuePath, applicationID, usage.String(), user.User)
- }
- m.Lock()
- defer m.Unlock()
- var userTracker *UserTracker
- if m.userTrackers[user.User] == nil {
- userTracker = newUserTracker(user.User)
-
- // Set the limits for all configured queue paths of the user
- for configQueuePath, config := range
m.userLimitsConfig[user.User] {
- log.Log(log.SchedUGM).Debug("Setting the limit max
applications settings.",
- zap.String("user", user.User),
- zap.String("queue path", configQueuePath))
- maxApps, ok := config[maxapplications].(uint64)
- if !ok {
- log.Log(log.SchedUGM).Warn("Problem in setting
the limit max applications settings. Unable to cast the value from interface to
uint64",
- zap.String("user", user.User),
- zap.String("queue path",
configQueuePath),
- zap.Uint64("limit max applications",
maxApps))
- return fmt.Errorf("unable to set the max
applications. user: %s, queuepath : %s, applicationid: %s",
- user.User, configQueuePath,
applicationID)
- }
- err := userTracker.setMaxApplications(maxApps,
configQueuePath)
- if err != nil {
- log.Log(log.SchedUGM).Warn("Problem in setting
the limit max applications settings.",
- zap.String("user", user.User),
- zap.String("queue path",
configQueuePath),
- zap.Uint64("limit max applications",
maxApps),
- zap.Error(err))
- return fmt.Errorf("unable to set the max
applications. user: %s, queuepath : %s, applicationid: %s, usage: %s, reason:
%w",
- user.User, configQueuePath,
applicationID, usage.String(), err)
- }
- maxResources, ok :=
config[maxresources].(map[string]string)
- if !ok {
- log.Log(log.SchedUGM).Warn("Problem in setting
the limit max resources settings. Unable to cast the value from interface to
resource",
- zap.String("user", user.User),
- zap.String("queue path",
configQueuePath),
- zap.Any("limit max resources",
maxResources))
- return fmt.Errorf("unable to set the max
resources. user: %s, queuepath : %s, applicationid: %s",
- user.User, configQueuePath,
applicationID)
- }
- resource, resourceErr :=
resources.NewResourceFromConf(maxResources)
- if resourceErr != nil {
- log.Log(log.SchedUGM).Warn("Problem in setting
the limit max resources settings.",
- zap.String("user", user.User),
- zap.String("queue path",
configQueuePath),
- zap.Any("limit max resources",
maxResources),
- zap.Error(resourceErr))
- return fmt.Errorf("unable to set the max
resources. user: %s, queuepath : %s, applicationid: %s, usage: %s, reason: %w",
- user.User, configQueuePath,
applicationID, usage.String(), resourceErr)
- }
- setMaxResourcesErr :=
userTracker.setMaxResources(resource, configQueuePath)
- if setMaxResourcesErr != nil {
- log.Log(log.SchedUGM).Warn("Problem in setting
the limit max resources settings.",
- zap.String("user", user.User),
- zap.String("queue path",
configQueuePath),
- zap.Any("limit max resources",
maxResources),
- zap.Error(setMaxResourcesErr))
- return fmt.Errorf("unable to set the max
resources. user: %s, queuepath : %s, applicationid: %s, usage: %s, reason: %w",
- user.User, configQueuePath,
applicationID, usage.String(), setMaxResourcesErr)
- }
- }
- m.userTrackers[user.User] = userTracker
- } else {
- userTracker = m.userTrackers[user.User]
+ return false
}
- err := userTracker.increaseTrackedResource(queuePath, applicationID,
usage)
- if err != nil {
- log.Log(log.SchedUGM).Error("Problem in increasing the user
resource usage",
- zap.String("user", user.User),
- zap.String("queue path", queuePath),
- zap.String("application", applicationID),
- zap.Stringer("resource", usage),
- zap.String("err message", err.Error()))
- return err
+ userTracker := m.getUserTracker(user.User, true)
+ log.Log(log.SchedUGM).Debug("Increasing resource usage for user",
+ zap.String("user", user.User),
+ zap.String("queue path", queuePath),
+ zap.String("application", applicationID),
+ zap.Stringer("resource", usage))
+ increased := userTracker.increaseTrackedResource(queuePath,
applicationID, usage)
+ if !increased {
+ return increased
}
- if err = m.ensureGroupTrackerForApp(queuePath, applicationID, user);
err != nil {
- return err
+ if err := m.ensureGroupTrackerForApp(queuePath, applicationID, user);
err != nil {
+ return false
}
group, err := m.getGroup(user)
if err != nil {
- return err
+ return false
}
- groupTracker := m.groupTrackers[group]
- if groupTracker != nil {
- err = groupTracker.increaseTrackedResource(queuePath,
applicationID, usage)
- if err != nil {
- log.Log(log.SchedUGM).Error("Problem in increasing the
group resource usage",
- zap.String("user", user.User),
- zap.String("group", group),
- zap.String("queue path", queuePath),
- zap.String("application", applicationID),
- zap.Stringer("resource", usage),
- zap.String("err message", err.Error()))
- return err
- }
+ groupTracker := m.getGroupTracker(group, true)
+ log.Log(log.SchedUGM).Debug("Increasing resource usage for group",
+ zap.String("group", group),
+ zap.String("queue path", queuePath),
+ zap.String("application", applicationID),
+ zap.Stringer("resource", usage))
+ increased = groupTracker.increaseTrackedResource(queuePath,
applicationID, usage)
+ if !increased {
+ return increased
}
- return nil
+ return true
}
// DecreaseTrackedResource Decrease the resource usage for the given user
group and queue path combination.
// As and when every allocation or asks release happens, corresponding user
and group
// resource usage would be decreased against specific application. When the
final asks release happens, removeApp should be set to true and
// application itself would be removed from the tracker and no more usage
would be tracked further for that specific application.
-func (m *Manager) DecreaseTrackedResource(queuePath string, applicationID
string, usage *resources.Resource, user security.UserGroup, removeApp bool)
error {
+func (m *Manager) DecreaseTrackedResource(queuePath, applicationID string,
usage *resources.Resource, user security.UserGroup, removeApp bool) bool {
log.Log(log.SchedUGM).Debug("Decreasing resource usage",
zap.String("user", user.User),
zap.String("queue path", queuePath),
zap.String("application", applicationID),
zap.Stringer("resource", usage),
zap.Bool("removeApp", removeApp))
if queuePath == "" || applicationID == "" || usage == nil || user.User
== "" {
- log.Log(log.SchedUGM).Error("Mandatory parameters are missing
to decrease the resource usage",
+ log.Log(log.SchedUGM).Debug("Mandatory parameters are missing
to decrease the resource usage",
zap.String("user", user.User),
zap.String("queue path", queuePath),
zap.String("application", applicationID),
zap.Stringer("resource", usage),
zap.Bool("removeApp", removeApp))
- return fmt.Errorf("mandatory parameters are missing. queuepath:
%s, application id: %s, resource usage: %s, user: %s",
- queuePath, applicationID, usage.String(), user.User)
+ return false
}
- m.Lock()
- defer m.Unlock()
- userTracker := m.userTrackers[user.User]
- if userTracker != nil {
- removeQT, err := userTracker.decreaseTrackedResource(queuePath,
applicationID, usage, removeApp)
- if err != nil {
- log.Log(log.SchedUGM).Error("Problem in decreasing the
user resource usage",
- zap.String("user", user.User),
- zap.String("queue path", queuePath),
- zap.String("application", applicationID),
- zap.Stringer("resource", usage),
- zap.Bool("removeApp", removeApp),
- zap.String("err message", err.Error()))
- return err
- }
- if removeApp && removeQT {
- delete(m.userTrackers, user.User)
- }
- } else {
+
+ userTracker := m.getUserTracker(user.User, false)
+ if userTracker == nil {
log.Log(log.SchedUGM).Error("user tracker must be available in
userTrackers map",
zap.String("user", user.User))
- return fmt.Errorf("user tracker for %s is missing in
userTrackers map", user.User)
+ return false
+ }
+ log.Log(log.SchedUGM).Debug("Decreasing resource usage for user",
+ zap.String("user", user.User),
+ zap.String("queue path", queuePath),
+ zap.String("application", applicationID),
+ zap.Stringer("resource", usage),
+ zap.Bool("removeApp", removeApp))
+ removeQT, decreased := userTracker.decreaseTrackedResource(queuePath,
applicationID, usage, removeApp)
+ if !decreased {
+ return decreased
+ }
+ if removeApp && removeQT {
+ log.Log(log.SchedUGM).Debug("Removing user from manager",
+ zap.String("user", user.User),
+ zap.String("queue path", queuePath),
+ zap.String("application", applicationID),
+ zap.Bool("removeApp", removeApp))
+ delete(m.userTrackers, user.User)
}
group, err := m.getGroup(user)
if err != nil {
- return err
+ return false
}
- groupTracker := m.groupTrackers[group]
- if groupTracker != nil {
- removeQT, err :=
groupTracker.decreaseTrackedResource(queuePath, applicationID, usage, removeApp)
- if err != nil {
- log.Log(log.SchedUGM).Error("Problem in decreasing the
group resource usage",
- zap.String("user", user.User),
- zap.String("group", group),
- zap.String("queue path", queuePath),
- zap.String("application", applicationID),
- zap.Stringer("resource", usage),
- zap.Bool("removeApp", removeApp),
- zap.String("err message", err.Error()))
- return err
- }
- if removeApp && removeQT {
- delete(m.groupTrackers, group)
- }
- } else {
+ groupTracker := m.getGroupTracker(group, false)
+ if groupTracker == nil {
log.Log(log.SchedUGM).Error("appGroupTrackers tracker must be
available in groupTrackers map",
zap.String("appGroupTrackers", group))
- return fmt.Errorf("appGroupTrackers tracker for %s is missing
in groupTrackers map", group)
+ return false
}
- return nil
+ log.Log(log.SchedUGM).Debug("Decreasing resource usage for group",
+ zap.String("group", group),
+ zap.String("queue path", queuePath),
+ zap.String("application", applicationID),
+ zap.Stringer("resource", usage),
+ zap.Bool("removeApp", removeApp))
+ removeQT, decreased = groupTracker.decreaseTrackedResource(queuePath,
applicationID, usage, removeApp)
+ if !decreased {
+ return decreased
+ }
+ if removeApp && removeQT {
+ log.Log(log.SchedUGM).Debug("Removing group from manager",
+ zap.String("group", group),
+ zap.String("queue path", queuePath),
+ zap.String("application", applicationID),
+ zap.Bool("removeApp", removeApp))
+ delete(m.groupTrackers, group)
+ }
+ return true
}
func (m *Manager) GetUserResources(user security.UserGroup)
*resources.Resource {
@@ -310,6 +250,8 @@ func (m *Manager) GetGroupTracker(group string)
*GroupTracker {
}
func (m *Manager) ensureGroupTrackerForApp(queuePath string, applicationID
string, user security.UserGroup) error {
+ m.Lock()
+ defer m.Unlock()
userTracker := m.userTrackers[user.User]
if !userTracker.hasGroupForApp(applicationID) {
var groupTracker *GroupTracker
@@ -318,66 +260,12 @@ func (m *Manager) ensureGroupTrackerForApp(queuePath
string, applicationID strin
return err
}
if m.groupTrackers[group] == nil {
- log.Log(log.SchedUGM).Debug("Group tracker does not
exist. Creating group tracker object and linking the same with application",
+ log.Log(log.SchedUGM).Debug("Group tracker doesn't
exists. Creating group tracker",
zap.String("application", applicationID),
zap.String("queue path", queuePath),
zap.String("user", user.User),
zap.String("group", group))
groupTracker = newGroupTracker(group)
-
- // Set the limits for all configured queue paths of the
group
- for configQueuePath, config := range
m.groupLimitsConfig[group] {
- log.Log(log.SchedUGM).Debug("Setting the limit
max applications settings.",
- zap.String("group", group),
- zap.String("queue path",
configQueuePath))
- maxApps, ok := config[maxapplications].(uint64)
- if !ok {
- log.Log(log.SchedUGM).Warn("Problem in
setting the limit max applications settings. Unable to cast the value from
interface to uint64",
- zap.String("group", group),
- zap.String("queue path",
configQueuePath),
- zap.Uint64("limit max
applications", maxApps))
- return fmt.Errorf("unable to set the
max applications. group: %s, queuepath : %s, applicationid: %s",
- group, configQueuePath,
applicationID)
- }
- if setMaxApplicationsErr :=
groupTracker.setMaxApplications(maxApps, configQueuePath);
setMaxApplicationsErr != nil {
- log.Log(log.SchedUGM).Warn("Problem in
setting the limit max applications settings.",
- zap.String("group", group),
- zap.String("queue path",
configQueuePath),
- zap.Uint64("limit max
applications", maxApps),
-
zap.Error(setMaxApplicationsErr))
- return fmt.Errorf("unable to set the
max applications. group: %s, queuepath : %s, applicationid: %s, reason: %w",
- group, configQueuePath,
applicationID, setMaxApplicationsErr)
- }
-
- maxResources, ok :=
config[maxresources].(map[string]string)
- if !ok {
- log.Log(log.SchedUGM).Warn("Problem in
setting the limit max resources settings. Unable to cast the value from
interface to resource",
- zap.String("group", group),
- zap.String("queue path",
configQueuePath),
- zap.Any("limit max resources",
maxResources))
- return fmt.Errorf("unable to set the
max resources. group: %s, queuepath : %s, applicationid: %s",
- group, configQueuePath,
applicationID)
- }
- resource, resourceErr :=
resources.NewResourceFromConf(maxResources)
- if resourceErr != nil {
- log.Log(log.SchedUGM).Warn("Problem in
setting the limit max resources settings.",
- zap.String("group", group),
- zap.String("queue path",
configQueuePath),
- zap.Any("limit max resources",
maxResources),
- zap.Error(resourceErr))
- return fmt.Errorf("unable to set the
max resources. group: %s, queuepath : %s, applicationid: %s, reason: %w",
- group, configQueuePath,
applicationID, resourceErr)
- }
- if setMaxResourcesErr :=
groupTracker.setMaxResources(resource, configQueuePath); setMaxResourcesErr !=
nil {
- log.Log(log.SchedUGM).Warn("Problem in
setting the limit max resources settings.",
- zap.String("group", group),
- zap.String("queue path",
configQueuePath),
- zap.Any("limit max resources",
maxResources),
- zap.Error(setMaxResourcesErr))
- return fmt.Errorf("unable to set the
max resources. group: %s, queuepath : %s, applicationid: %s, reason: %w",
- group, configQueuePath,
applicationID, setMaxResourcesErr)
- }
- }
m.groupTrackers[group] = groupTracker
} else {
log.Log(log.SchedUGM).Debug("Group tracker already
exists and linking (reusing) the same with application",
@@ -419,20 +307,27 @@ func (m *Manager) UpdateConfig(config
configs.QueueConfig, queuePath string) err
m.Lock()
defer m.Unlock()
- // clear the local limit config maps before processing the limit config
- m.userLimitsConfig = make(map[string]map[string]map[string]interface{})
- m.groupLimitsConfig = make(map[string]map[string]map[string]interface{})
+ m.userWildCardLimitsConfig = make(map[string]*LimitConfig)
+ m.groupWildCardLimitsConfig = make(map[string]*LimitConfig)
return m.internalProcessConfig(config, queuePath)
}
func (m *Manager) internalProcessConfig(cur configs.QueueConfig, queuePath
string) error {
// Holds user and group for which limits have been configured with
specific queue path
- userGroupLimits := make(map[string]bool)
+ userLimits := make(map[string]bool)
+ groupLimits := make(map[string]bool)
// Traverse limits of specific queue path
for _, limit := range cur.Limits {
- tempLimitsMap := make(map[string]interface{})
- tempLimitsMap[maxresources] = limit.MaxResources
- tempLimitsMap[maxapplications] = limit.MaxApplications
+ var maxResource *resources.Resource
+ var err error
+ if maxResource, err =
resources.NewResourceFromConf(limit.MaxResources); err != nil {
+ log.Log(log.SchedUGM).Warn("Problem in using the limit
max resources settings.",
+ zap.String("queue path", queuePath),
+ zap.Any("limit max resources",
limit.MaxResources),
+ zap.Error(err))
+ return fmt.Errorf("problem in using the max resources
settings for queuepath: %s. reason: %w", queuePath, err)
+ }
+ limitConfig := &LimitConfig{maxResources: maxResource,
maxApplications: limit.MaxApplications}
for _, user := range limit.Users {
log.Log(log.SchedUGM).Debug("Processing user limits
configuration",
zap.String("user", user),
@@ -440,9 +335,11 @@ func (m *Manager) internalProcessConfig(cur
configs.QueueConfig, queuePath strin
zap.String("queue path", queuePath),
zap.Uint64("max application",
limit.MaxApplications),
zap.Any("max resources", limit.MaxResources))
- tempUserMap := make(map[string]map[string]interface{})
- tempUserMap[queuePath] = tempLimitsMap
- if err := m.processUserConfig(user, limit, queuePath,
userGroupLimits, tempLimitsMap, tempUserMap); err != nil {
+ if user == common.Wildcard {
+ m.userWildCardLimitsConfig[queuePath] =
limitConfig
+ continue
+ }
+ if err := m.processUserConfig(user, limitConfig,
queuePath, userLimits); err != nil {
return err
}
}
@@ -453,14 +350,16 @@ func (m *Manager) internalProcessConfig(cur
configs.QueueConfig, queuePath strin
zap.String("queue path", queuePath),
zap.Uint64("max application",
limit.MaxApplications),
zap.Any("max resources", limit.MaxResources))
- tempGroupMap := make(map[string]map[string]interface{})
- tempGroupMap[queuePath] = tempLimitsMap
- if err := m.processGroupConfig(group, limit, queuePath,
userGroupLimits, tempLimitsMap, tempGroupMap); err != nil {
+ if group == common.Wildcard {
+ m.groupWildCardLimitsConfig[queuePath] =
limitConfig
+ continue
+ }
+ if err := m.processGroupConfig(group, limitConfig,
queuePath, groupLimits); err != nil {
return err
}
}
}
- if err := m.clearEarlierSetLimits(userGroupLimits, queuePath); err !=
nil {
+ if err := m.clearEarlierSetLimits(userLimits, groupLimits, queuePath);
err != nil {
return err
}
@@ -475,113 +374,111 @@ func (m *Manager) internalProcessConfig(cur
configs.QueueConfig, queuePath strin
return nil
}
-func (m *Manager) processUserConfig(user string, limit configs.Limit,
queuePath string, userGroupLimits map[string]bool, tempLimitsMap
map[string]interface{}, tempUserMap map[string]map[string]interface{}) error {
+func (m *Manager) processUserConfig(user string, limitConfig *LimitConfig,
queuePath string, userLimits map[string]bool) error {
if user == "*" {
// traverse all tracked users
for u, ut := range m.userTrackers {
// Is this user already tracked for the queue path?
- if m.IsQueuePathTrackedCompletely(ut.queueTracker,
queuePath) {
+ if ut.IsQueuePathTrackedCompletely(queuePath) {
log.Log(log.SchedUGM).Debug("Processing wild
card user limits configuration for all existing users",
zap.String("user", u),
- zap.String("limit", limit.Limit),
zap.String("queue path", queuePath),
- zap.Uint64("max application",
limit.MaxApplications),
- zap.Any("max resources",
limit.MaxResources))
-
- // creates an entry for the user being
processed always as it has been cleaned before
- if _, ok := m.userLimitsConfig[u]; ok {
- m.userLimitsConfig[u][queuePath] =
tempLimitsMap
- } else {
- m.userLimitsConfig[u] = tempUserMap
- }
- if err := m.setUserLimits(u, limit, queuePath);
err != nil {
+ zap.Uint64("max application",
limitConfig.maxApplications),
+ zap.Any("max resources",
limitConfig.maxResources))
+ if err := m.setUserLimits(u, limitConfig,
queuePath); err != nil {
return err
}
- userGroupLimits[u] = true
+ userLimits[u] = true
}
}
- } else {
- // creates an entry for the user being processed always as it
has been cleaned before
- if _, ok := m.userLimitsConfig[user]; ok {
- m.userLimitsConfig[user][queuePath] = tempLimitsMap
- } else {
- m.userLimitsConfig[user] = tempUserMap
- }
- if err := m.setUserLimits(user, limit, queuePath); err != nil {
+ } else if user != "" {
+ if err := m.setUserLimits(user, limitConfig, queuePath); err !=
nil {
return err
}
- userGroupLimits[user] = true
+ userLimits[user] = true
}
return nil
}
-func (m *Manager) processGroupConfig(group string, limit configs.Limit,
queuePath string, userGroupLimits map[string]bool, tempLimitsMap
map[string]interface{}, tempGroupMap map[string]map[string]interface{}) error {
+func (m *Manager) processGroupConfig(group string, limitConfig *LimitConfig,
queuePath string, groupLimits map[string]bool) error {
if group == "*" {
// traverse all tracked groups
for g, gt := range m.groupTrackers {
// Is this group already tracked for the queue path?
- if m.IsQueuePathTrackedCompletely(gt.queueTracker,
queuePath) {
+ if gt.IsQueuePathTrackedCompletely(queuePath) {
log.Log(log.SchedUGM).Debug("Processing wild
card user limits configuration for all existing groups",
zap.String("group", g),
- zap.String("limit", limit.Limit),
zap.String("queue path", queuePath),
- zap.Uint64("max application",
limit.MaxApplications),
- zap.Any("max resources",
limit.MaxResources))
- // creates an entry for the group being
processed always as it has been cleaned before
- if _, ok := m.groupLimitsConfig[g]; ok {
- m.groupLimitsConfig[g][queuePath] =
tempLimitsMap
- } else {
- m.groupLimitsConfig[g] = tempGroupMap
- }
- if err := m.setGroupLimits(g, limit,
queuePath); err != nil {
+ zap.Uint64("max application",
limitConfig.maxApplications),
+ zap.Any("max resources",
limitConfig.maxResources))
+ if err := m.setGroupLimits(g, limitConfig,
queuePath); err != nil {
return err
}
- userGroupLimits[g] = true
+ groupLimits[g] = true
}
}
- } else {
- // creates an entry for the group being processed always as it
has been cleaned before
- if _, ok := m.groupLimitsConfig[group]; ok {
- m.groupLimitsConfig[group][queuePath] = tempLimitsMap
- } else {
- m.groupLimitsConfig[group] = tempGroupMap
- }
- if err := m.setGroupLimits(group, limit, queuePath); err != nil
{
+ } else if group != "" {
+ if err := m.setGroupLimits(group, limitConfig, queuePath); err
!= nil {
return err
}
- userGroupLimits[group] = true
+ groupLimits[group] = true
}
return nil
}
-func (m *Manager) clearEarlierSetLimits(userGroupLimits map[string]bool,
queuePath string) error {
- // Clear already configured limits of user for which limits have been
configured before but not now through #cur
+// clearEarlierSetLimits Clear already configured limits of users and groups
for which limits have been configured before but not now
+func (m *Manager) clearEarlierSetLimits(userLimits map[string]bool,
groupLimits map[string]bool, queuePath string) error {
+ // Clear already configured limits of user for which limits have been
configured before but not now
for u, ut := range m.userTrackers {
// Is this user already tracked for the queue path?
- if m.IsQueuePathTrackedCompletely(ut.queueTracker, queuePath) {
- if _, ok := userGroupLimits[u]; !ok {
- err :=
ut.setMaxResources(resources.NewResource(), queuePath)
- if err != nil {
- return err
+ if ut.IsQueuePathTrackedCompletely(queuePath) {
+ // Is there any limit config set for user in the
current configuration? If not, then clear those old limit settings
+ if _, ok := userLimits[u]; !ok {
+ log.Log(log.SchedUGM).Debug("Need to clear
earlier set configs for user",
+ zap.String("user", u),
+ zap.String("queue path", 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 ut.IsUnlinkRequired(queuePath) {
+ ut.UnlinkQT(queuePath)
+ } else {
+ ut.setLimits(queuePath,
resources.NewResource(), 0)
+ log.Log(log.SchedUGM).Debug("Cleared
earlier set limit configs for user",
+ zap.String("user", u),
+ zap.String("queue path",
queuePath))
}
- err = ut.setMaxApplications(0, queuePath)
- if err != nil {
- return err
+ // Does "root" queue has any child queue
trackers? At some point during this whole traversal, root might
+ // not have any child queue trackers. When the
situation comes, remove the linkage between the user and
+ // its root queue tracker
+ if ut.canBeRemoved() {
+ delete(m.userTrackers, ut.userName)
}
}
}
}
- // Clear already configured limits of group for which limits have been
configured before but not now through #cur
+ // Clear already configured limits of group for which limits have been
configured before but not now
for g, gt := range m.groupTrackers {
// Is this group already tracked for the queue path?
- if m.IsQueuePathTrackedCompletely(gt.queueTracker, queuePath) {
- if _, ok := userGroupLimits[g]; !ok {
- if err :=
gt.setMaxResources(resources.NewResource(), queuePath); err != nil {
- return err
+ if gt.IsQueuePathTrackedCompletely(queuePath) {
+ // Is there any limit config set for group in the
current configuration? If not, then clear those old limit settings
+ if ok := groupLimits[g]; !ok {
+ log.Log(log.SchedUGM).Debug("Need to clear
earlier set configs for group",
+ zap.String("group", g),
+ zap.String("queue path", 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(queuePath) {
+ gt.UnlinkQT(queuePath)
+ } else {
+ gt.setLimits(queuePath,
resources.NewResource(), 0)
+ log.Log(log.SchedUGM).Debug("Cleared
earlier set limit configs for group",
+ zap.String("group", g),
+ zap.String("queue path",
queuePath))
}
- if err := gt.setMaxApplications(0, queuePath);
err != nil {
- return err
+ // Does "root" queue has any child queue
trackers? At some point during this whole traversal, root might
+ // not have any child queue trackers. When the
situation comes, remove the linkage between the group and
+ // its root queue tracker
+ if gt.canBeRemoved() {
+ delete(m.groupTrackers, gt.groupName)
}
}
}
@@ -589,13 +486,12 @@ func (m *Manager) clearEarlierSetLimits(userGroupLimits
map[string]bool, queuePa
return nil
}
-func (m *Manager) setUserLimits(user string, limit configs.Limit, queuePath
string) error {
+func (m *Manager) setUserLimits(user string, limitConfig *LimitConfig,
queuePath string) error {
log.Log(log.SchedUGM).Debug("Setting user limits",
zap.String("user", user),
- zap.String("limit", limit.Limit),
zap.String("queue path", queuePath),
- zap.Uint64("max application", limit.MaxApplications),
- zap.Any("max resources", limit.MaxResources))
+ zap.Uint64("max application", limitConfig.maxApplications),
+ zap.Any("max resources", limitConfig.maxResources))
userTracker, ok := m.userTrackers[user]
if !ok {
log.Log(log.SchedUGM).Debug("User tracker does not exist.
Creating user tracker object to set the limit configuration",
@@ -604,42 +500,16 @@ func (m *Manager) setUserLimits(user string, limit
configs.Limit, queuePath stri
userTracker = newUserTracker(user)
m.userTrackers[user] = userTracker
}
- if err := userTracker.setMaxApplications(limit.MaxApplications,
queuePath); err != nil {
- log.Log(log.SchedUGM).Warn("Problem in setting the limit max
applications settings.",
- zap.String("user", user),
- zap.String("queue path", queuePath),
- zap.Uint64("limit max applications",
limit.MaxApplications),
- zap.Error(err))
- return fmt.Errorf("unable to set the limit for user %s because
%w", user, err)
- }
-
- if resource, err := resources.NewResourceFromConf(limit.MaxResources);
err == nil {
- if err = userTracker.setMaxResources(resource, queuePath); err
!= nil {
- log.Log(log.SchedUGM).Warn("Problem in setting the
limit max resources settings.",
- zap.String("user", user),
- zap.String("queue path", queuePath),
- zap.Any("limit max resources",
limit.MaxResources),
- zap.Error(err))
- return fmt.Errorf("unable to set the limit for user %s
because %w", user, err)
- }
- } else {
- log.Log(log.SchedUGM).Warn("Problem in using the limit max
resources settings.",
- zap.String("user", user),
- zap.String("queue path", queuePath),
- zap.Any("limit max resources", limit.MaxResources),
- zap.Error(err))
- return fmt.Errorf("unable to set the limit for user %s because
%w", user, err)
- }
+ userTracker.setLimits(queuePath, limitConfig.maxResources,
limitConfig.maxApplications)
return nil
}
-func (m *Manager) setGroupLimits(group string, limit configs.Limit, queuePath
string) error {
+func (m *Manager) setGroupLimits(group string, limitConfig *LimitConfig,
queuePath string) error {
log.Log(log.SchedUGM).Debug("Setting group limits",
zap.String("group", group),
- zap.String("limit", limit.Limit),
zap.String("queue path", queuePath),
- zap.Uint64("max application", limit.MaxApplications),
- zap.Any("max resources", limit.MaxResources))
+ zap.Uint64("max application", limitConfig.maxApplications),
+ zap.Any("max resources", limitConfig.maxResources))
groupTracker, ok := m.groupTrackers[group]
if !ok {
log.Log(log.SchedUGM).Debug("Group tracker does not exist.
Creating group tracker object to set the limit configuration",
@@ -648,46 +518,58 @@ func (m *Manager) setGroupLimits(group string, limit
configs.Limit, queuePath st
groupTracker = newGroupTracker(group)
m.groupTrackers[group] = groupTracker
}
- if err := groupTracker.setMaxApplications(limit.MaxApplications,
queuePath); err != nil {
- log.Log(log.SchedUGM).Warn("Problem in setting the limit max
applications settings.",
- zap.String("group", group),
- zap.String("queue path", queuePath),
- zap.Uint64("limit max applications",
limit.MaxApplications),
- zap.Error(err))
- return fmt.Errorf("unable to set the limit for group %s because
%w", group, err)
+ groupTracker.setLimits(queuePath, limitConfig.maxResources,
limitConfig.maxApplications)
+ return nil
+}
+
+func (m *Manager) getUserTracker(user string, createIfNotPresent bool)
*UserTracker {
+ m.Lock()
+ defer m.Unlock()
+ if ut, ok := m.userTrackers[user]; ok {
+ return ut
+ }
+ if createIfNotPresent {
+ log.Log(log.SchedUGM).Debug("User tracker doesn't exists.
Creating user tracker.",
+ zap.String("user", user))
+ userTracker := newUserTracker(user)
+ m.userTrackers[user] = userTracker
+ return userTracker
}
+ return nil
+}
- if resource, err := resources.NewResourceFromConf(limit.MaxResources);
err == nil {
- if err = groupTracker.setMaxResources(resource, queuePath); err
!= nil {
- log.Log(log.SchedUGM).Warn("Problem in setting the
limit max resources settings.",
- zap.String("group", group),
- zap.String("queue path", queuePath),
- zap.Any("limit max resources",
limit.MaxResources),
- zap.Error(err))
- return fmt.Errorf("unable to set the limit for group %s
because %w", group, err)
- }
- } else {
- log.Log(log.SchedUGM).Warn("Problem in using the limit max
resources settings.",
- zap.String("group", group),
- zap.String("queue path", queuePath),
- zap.Any("limit max resources", limit.MaxResources),
- zap.Error(err))
- return fmt.Errorf("unable to set the limit for group %s because
%w", group, err)
+func (m *Manager) getGroupTracker(group string, createIfNotPresent bool)
*GroupTracker {
+ m.Lock()
+ defer m.Unlock()
+ if gt, ok := m.groupTrackers[group]; ok {
+ return gt
+ }
+ if createIfNotPresent {
+ log.Log(log.SchedUGM).Debug("Group tracker doesn't exists.
Creating group tracker.",
+ zap.String("group", group))
+ groupTracker := newGroupTracker(group)
+ m.groupTrackers[group] = groupTracker
+ return groupTracker
}
return nil
}
-func (m *Manager) IsQueuePathTrackedCompletely(qt *QueueTracker, queuePath
string) bool {
- if queuePath == configs.RootQueue || queuePath == qt.queueName {
- return true
+func (m *Manager) getUserWildCardLimitsConfig(queuePath string) *LimitConfig {
+ m.RLock()
+ defer m.RUnlock()
+ if config, ok := m.userWildCardLimitsConfig[queuePath]; ok {
+ return config
}
- childQueuePath, immediateChildQueueName := getChildQueuePath(queuePath)
- if immediateChildQueueName != "" {
- if childUt, ok :=
qt.childQueueTrackers[immediateChildQueueName]; ok {
- return m.IsQueuePathTrackedCompletely(childUt,
childQueuePath)
- }
+ return nil
+}
+
+func (m *Manager) getGroupWildCardLimitsConfig(queuePath string) *LimitConfig {
+ m.RLock()
+ defer m.RUnlock()
+ if config, ok := m.groupWildCardLimitsConfig[queuePath]; ok {
+ return config
}
- return false
+ return nil
}
// ClearUserTrackers only for tests
diff --git a/pkg/scheduler/ugm/manager_test.go
b/pkg/scheduler/ugm/manager_test.go
index c8765553..c0bae9dd 100644
--- a/pkg/scheduler/ugm/manager_test.go
+++ b/pkg/scheduler/ugm/manager_test.go
@@ -59,12 +59,14 @@ func TestAddRemoveUserAndGroups(t *testing.T) {
}
manager := GetUserManager()
- err = manager.IncreaseTrackedResource("", "", usage1, user)
- assert.Error(t, err, "mandatory parameters are missing. queuepath: ,
application id: , resource usage: "+usage1.String()+", user: "+user.User)
+ increased := manager.IncreaseTrackedResource("", "", usage1, user)
+ if increased {
+ t.Errorf("mandatory parameters are missing. queuepath: ,
application id: , resource usage: %s, user: %s", usage1.String(), user.User)
+ }
- err = manager.IncreaseTrackedResource(queuePath1, TestApp1, usage1,
user)
- if err != nil {
- t.Fatalf("unable to increase tracked resource: queuepath %s,
app %s, res %v, error %t", queuePath1, TestApp1, usage1, err)
+ increased = manager.IncreaseTrackedResource(queuePath1, TestApp1,
usage1, user)
+ if !increased {
+ t.Errorf("unable to increase tracked resource. queuepath: %s,
application id: %s, resource usage: %s, user: %s", queuePath1, TestApp1,
usage1.String(), user.User)
}
userTrackers := manager.GetUsersResources()
@@ -77,9 +79,9 @@ func TestAddRemoveUserAndGroups(t *testing.T) {
assert.Equal(t, user.User, manager.GetUserTracker(user.User).userName)
assert.Equal(t, user.Groups[0],
manager.GetGroupTracker(user.Groups[0]).groupName)
- err = manager.IncreaseTrackedResource(queuePath1, TestApp1, usage1,
user)
- if err != nil {
- t.Fatalf("unable to increase tracked resource: queuepath %s,
app %s, res %v, error %t", queuePath1, TestApp1, usage1, err)
+ increased = manager.IncreaseTrackedResource(queuePath1, TestApp1,
usage1, user)
+ if !increased {
+ t.Fatalf("unable to increase tracked resource: queuepath %s,
app %s, res %v", queuePath1, TestApp1, usage1)
}
assertUGM(t, user, resources.Multiply(usage1, 2), 1)
@@ -88,9 +90,9 @@ func TestAddRemoveUserAndGroups(t *testing.T) {
if err != nil {
t.Errorf("new resource create returned error or wrong resource:
error %t, res %v", err, usage2)
}
- err = manager.IncreaseTrackedResource(queuePath2, TestApp2, usage2,
user1)
- if err != nil {
- t.Fatalf("unable to increase tracked resource: queuepath %s,
app %s, res %v, error %t", queuePath2, TestApp2, usage2, err)
+ increased = manager.IncreaseTrackedResource(queuePath2, TestApp2,
usage2, user1)
+ if !increased {
+ t.Fatalf("unable to increase tracked resource: queuepath %s,
app %s, res %v", queuePath2, TestApp2, usage2)
}
assertUGM(t, user1, usage2, 2)
assert.Equal(t, user.User, manager.GetUserTracker(user.User).userName)
@@ -98,43 +100,43 @@ func TestAddRemoveUserAndGroups(t *testing.T) {
assert.Equal(t, user1.User, manager.GetUserTracker(user1.User).userName)
assert.Equal(t, user1.Groups[0],
manager.GetGroupTracker(user1.Groups[0]).groupName)
- assert.Equal(t, true,
manager.IsQueuePathTrackedCompletely(manager.GetUserTracker(user.User).queueTracker,
queuePath1))
- assert.Equal(t, true,
manager.IsQueuePathTrackedCompletely(manager.GetUserTracker(user1.User).queueTracker,
queuePath2))
- assert.Equal(t, false,
manager.IsQueuePathTrackedCompletely(manager.GetUserTracker(user1.User).queueTracker,
queuePath1))
- assert.Equal(t, false,
manager.IsQueuePathTrackedCompletely(manager.GetUserTracker(user.User).queueTracker,
queuePath2))
- assert.Equal(t, false,
manager.IsQueuePathTrackedCompletely(manager.GetUserTracker(user.User).queueTracker,
queuePath3))
- assert.Equal(t, false,
manager.IsQueuePathTrackedCompletely(manager.GetUserTracker(user.User).queueTracker,
queuePath4))
+ assert.Equal(t, true,
manager.GetUserTracker(user.User).queueTracker.IsQueuePathTrackedCompletely(queuePath1))
+ assert.Equal(t, true,
manager.GetUserTracker(user1.User).queueTracker.IsQueuePathTrackedCompletely(queuePath2))
+ assert.Equal(t, false,
manager.GetUserTracker(user1.User).queueTracker.IsQueuePathTrackedCompletely(queuePath1))
+ assert.Equal(t, false,
manager.GetUserTracker(user.User).queueTracker.IsQueuePathTrackedCompletely(queuePath2))
+ assert.Equal(t, false,
manager.GetUserTracker(user.User).queueTracker.IsQueuePathTrackedCompletely(queuePath3))
+ assert.Equal(t, false,
manager.GetUserTracker(user.User).queueTracker.IsQueuePathTrackedCompletely(queuePath4))
- assert.Equal(t, true,
manager.IsQueuePathTrackedCompletely(manager.GetUserTracker(user.Groups[0]).queueTracker,
queuePath1))
- assert.Equal(t, true,
manager.IsQueuePathTrackedCompletely(manager.GetUserTracker(user1.Groups[0]).queueTracker,
queuePath2))
- assert.Equal(t, false,
manager.IsQueuePathTrackedCompletely(manager.GetUserTracker(user1.Groups[0]).queueTracker,
queuePath1))
- assert.Equal(t, false,
manager.IsQueuePathTrackedCompletely(manager.GetUserTracker(user.Groups[0]).queueTracker,
queuePath2))
- assert.Equal(t, false,
manager.IsQueuePathTrackedCompletely(manager.GetUserTracker(user.Groups[0]).queueTracker,
queuePath3))
- assert.Equal(t, false,
manager.IsQueuePathTrackedCompletely(manager.GetUserTracker(user.Groups[0]).queueTracker,
queuePath4))
+ assert.Equal(t, true,
manager.GetUserTracker(user.Groups[0]).queueTracker.IsQueuePathTrackedCompletely(queuePath1))
+ assert.Equal(t, true,
manager.GetUserTracker(user1.Groups[0]).queueTracker.IsQueuePathTrackedCompletely(queuePath2))
+ assert.Equal(t, false,
manager.GetUserTracker(user1.Groups[0]).queueTracker.IsQueuePathTrackedCompletely(queuePath1))
+ assert.Equal(t, false,
manager.GetUserTracker(user.Groups[0]).queueTracker.IsQueuePathTrackedCompletely(queuePath2))
+ assert.Equal(t, false,
manager.GetUserTracker(user.Groups[0]).queueTracker.IsQueuePathTrackedCompletely(queuePath3))
+ assert.Equal(t, false,
manager.GetUserTracker(user.Groups[0]).queueTracker.IsQueuePathTrackedCompletely(queuePath4))
usage3, err := resources.NewResourceFromConf(map[string]string{"mem":
"5M", "vcore": "5"})
if err != nil {
t.Errorf("new resource create returned error or wrong resource:
error %t, res %v", err, usage3)
}
- err = manager.DecreaseTrackedResource("", "", usage1, user, false)
- assert.Error(t, err, "mandatory parameters are missing. queuepath: ,
application id: , resource usage: "+usage1.String()+", user: "+user.User)
+ decreased := manager.DecreaseTrackedResource("", "", usage1, user,
false)
+ assert.Equal(t, decreased, false)
- err = manager.DecreaseTrackedResource(queuePath1, TestApp1, usage3,
user, false)
- if err != nil {
+ decreased = manager.DecreaseTrackedResource(queuePath1, TestApp1,
usage3, user, false)
+ if !decreased {
t.Fatalf("unable to decrease tracked resource: queuepath %s,
app %s, res %v, error %t", queuePath1, TestApp1, usage3, err)
}
assertUGM(t, user, usage1, 2)
- err = manager.DecreaseTrackedResource(queuePath1, TestApp1, usage3,
user, true)
- if err != nil {
+ decreased = manager.DecreaseTrackedResource(queuePath1, TestApp1,
usage3, user, true)
+ if !decreased {
t.Fatalf("unable to decrease tracked resource: queuepath %s,
app %s, res %v, error %t", queuePath1, TestApp1, usage3, err)
}
assert.Equal(t, 1, len(manager.GetUsersResources()), "userTrackers
count should be 1")
assert.Equal(t, 1, len(manager.GetGroupsResources()), "groupTrackers
count should be 1")
- err = manager.DecreaseTrackedResource(queuePath2, TestApp2, usage2,
user1, true)
- if err != nil {
+ decreased = manager.DecreaseTrackedResource(queuePath2, TestApp2,
usage2, user1, true)
+ if !decreased {
t.Fatalf("unable to increase tracked resource: queuepath %s,
app %s, res %v, error %t", queuePath2, TestApp2, usage2, err)
}
assert.Equal(t, 0, len(manager.GetUsersResources()), "userTrackers
count should be 0")
@@ -144,124 +146,301 @@ func TestAddRemoveUserAndGroups(t *testing.T) {
assert.Assert(t, manager.GetGroupTracker(user.Groups[0]) == nil)
}
-func TestIncreaseUserResourceWithInvalidConfig(t *testing.T) {
+func TestUpdateConfig(t *testing.T) {
setupUGM()
// Queue setup:
// root->parent
user := security.UserGroup{User: "user1", Groups: []string{"group1"}}
manager := GetUserManager()
- expectedResource, err :=
resources.NewResourceFromConf(map[string]string{"memory": "5", "vcores": "5"})
+ expectedResource, err :=
resources.NewResourceFromConf(map[string]string{"memory": "50", "vcores": "50"})
if err != nil {
t.Errorf("new resource create returned error or wrong resource:
error %t, res %v", err, expectedResource)
}
- m.userLimitsConfig[user.User] = make(map[string]map[string]interface{})
- m.userLimitsConfig[user.User][queuePath1] = make(map[string]interface{})
- m.userLimitsConfig[user.User][queuePath1][maxapplications] = -2
- assert.Error(t, manager.IncreaseTrackedResource(queuePath1, TestApp1,
expectedResource, user), "unable to set the max applications. user:
"+user.User+", queuepath : "+queuePath1+", applicationid: "+TestApp1)
-
- m.userLimitsConfig[user.User][queuePath1][maxapplications] = uint64(2)
- m.userLimitsConfig[user.User][queuePath1][maxresources] =
make(map[string]interface{})
- assert.Error(t, manager.IncreaseTrackedResource(queuePath1, TestApp1,
expectedResource, user), "unable to set the max resources. user: "+user.User+",
queuepath : "+queuePath1+", applicationid: "+TestApp1)
-
- m.userLimitsConfig[user.User][queuePath1][maxapplications] = uint64(2)
- m.userLimitsConfig[user.User][queuePath1][maxresources] =
map[string]string{"invalid": "-5", "vcores": "5"}
- assert.Error(t, manager.IncreaseTrackedResource(queuePath1, TestApp1,
expectedResource, user), "unable to set the max resources. user: "+user.User+",
queuepath : "+queuePath1+", applicationid: "+TestApp1+", usage: map[memory:5
vcores:5], reason: invalid quantity")
-
- m.userLimitsConfig[user.User][queuePath1][maxapplications] = uint64(2)
- m.userLimitsConfig[user.User][queuePath1][maxresources] =
map[string]string{"memory": "5", "vcores": "5"}
- m.groupLimitsConfig[user.Groups[0]] =
make(map[string]map[string]interface{})
- m.groupLimitsConfig[user.Groups[0]][queuePath1] =
make(map[string]interface{})
- m.groupLimitsConfig[user.Groups[0]][queuePath1][maxapplications] = -2
- assert.Error(t, manager.IncreaseTrackedResource(queuePath1, TestApp1,
expectedResource, user), "unable to set the max applications. group:
"+user.Groups[0]+", queuepath : "+queuePath1+", applicationid: "+TestApp1)
-
- m.userLimitsConfig[user.User][queuePath1][maxapplications] = uint64(2)
- m.userLimitsConfig[user.User][queuePath1][maxresources] =
map[string]string{"memory": "5", "vcores": "5"}
- m.groupLimitsConfig[user.Groups[0]][queuePath1][maxapplications] =
uint64(2)
- m.groupLimitsConfig[user.Groups[0]][queuePath1][maxresources] =
make(map[string]interface{})
- assert.Error(t, manager.IncreaseTrackedResource(queuePath1, TestApp1,
expectedResource, user), "unable to set the max resources. group:
"+user.Groups[0]+", queuepath : "+queuePath1+", applicationid: "+TestApp1)
-
- m.userLimitsConfig[user.User][queuePath1][maxapplications] = uint64(2)
- m.userLimitsConfig[user.User][queuePath1][maxresources] =
map[string]string{"memory": "5", "vcores": "5"}
- m.groupLimitsConfig[user.Groups[0]][queuePath1][maxapplications] =
uint64(2)
- m.groupLimitsConfig[user.Groups[0]][queuePath1][maxresources] =
map[string]string{"invalid": "-5", "vcores": "5"}
- assert.Error(t, manager.IncreaseTrackedResource(queuePath1, TestApp1,
expectedResource, user), "unable to set the max resources. group:
"+user.Groups[0]+", queuepath : "+queuePath1+", applicationid: "+TestApp1+",
reason: invalid quantity")
+ conf := createConfig(user.User, user.Groups[0], "memory", "50", 50, 5)
+ assert.NilError(t, manager.UpdateConfig(conf.Queues[0], "root"))
+
+ usage, err := resources.NewResourceFromConf(map[string]string{"memory":
"10", "vcores": "10"})
+ if err != nil {
+ t.Errorf("new resource create returned error or wrong resource:
error %t, res %v", err, usage)
+ }
+ assertMaxLimits(t, user, expectedResource, 5)
+
+ for i := 1; i <= 5; i++ {
+ increased := manager.IncreaseTrackedResource(queuePath1,
TestApp1, usage, user)
+ if !increased {
+ t.Fatalf("unable to increase tracked resource:
queuepath %s, app %s, res %v, error %t", queuePath1, TestApp1, usage, err)
+ }
+ }
+ // configure max resource for root.parent lesser than current resource
usage. should be allowed to set but user cannot be allowed to do any activity
further
+ conf = createConfig(user.User, user.Groups[0], "memory", "50", 40, 4)
+ err = manager.UpdateConfig(conf.Queues[0], "root")
+ assert.NilError(t, err)
+ increased := manager.IncreaseTrackedResource(queuePath1, TestApp1,
usage, user)
+ if increased {
+ t.Fatalf("unable to increase tracked resource: queuepath %s,
app %s, res %v", queuePath1, TestApp1, user)
+ }
+
+ // configure max resource for root and parent to allow one more
application to run
+ conf = createConfig(user.User, user.Groups[0], "memory", "50", 60, 6)
+ err = manager.UpdateConfig(conf.Queues[0], "root")
+ assert.NilError(t, err, "unable to set the limit for user user1 because
current resource usage is greater than config max resource for root.parent")
+
+ increased = manager.IncreaseTrackedResource(queuePath1, TestApp1,
usage, user)
+ if !increased {
+ t.Fatalf("unable to increase tracked resource: queuepath %s,
app %s, res %v", queuePath1, TestApp1, user)
+ }
+
+ // configure max resource for root lesser than current resource usage.
should be allowed to set but user cannot be allowed to do any activity further
+ conf = createConfig(user.User, user.Groups[0], "memory", "50", 10, 10)
+ err = manager.UpdateConfig(conf.Queues[0], "root")
+ assert.NilError(t, err)
+ increased = manager.IncreaseTrackedResource(queuePath1, TestApp1,
usage, user)
+ if increased {
+ t.Fatalf("unable to increase tracked resource: queuepath %s,
app %s, res %v", queuePath1, TestApp1, user)
+ }
}
-func TestUpdateConfig(t *testing.T) {
+func TestUpdateConfigWithWildCardUsersAndGroups(t *testing.T) {
setupUGM()
// Queue setup:
// root->parent
user := security.UserGroup{User: "user1", Groups: []string{"group1"}}
+ conf := createUpdateConfig(user.User, user.Groups[0])
manager := GetUserManager()
+ assert.NilError(t, manager.UpdateConfig(conf.Queues[0], "root"))
- expectedResource, err :=
resources.NewResourceFromConf(map[string]string{"memory": "5", "vcores": "5"})
+ expectedResource, err :=
resources.NewResourceFromConf(map[string]string{"memory": "50", "vcores": "50"})
+ if err != nil {
+ t.Errorf("new resource create returned error or wrong resource:
error %t, res %v", err, expectedResource)
+ }
+ usage, err := resources.NewResourceFromConf(map[string]string{"memory":
"10", "vcores": "10"})
if err != nil {
t.Errorf("new resource create returned error or wrong resource:
error %t, res %v", err, expectedResource)
}
+ assertMaxLimits(t, user, expectedResource, 5)
+
+ for i := 1; i <= 5; i++ {
+ increased := manager.IncreaseTrackedResource(queuePath1,
TestApp1, usage, user)
+ if !increased {
+ t.Fatalf("unable to increase tracked resource:
queuepath %s, app %s, res %v", queuePath1, TestApp1, expectedResource)
+ }
+ }
- conf := createConfig(user.User, user.Groups[0], "memory", "-10")
- assert.Error(t, manager.UpdateConfig(conf.Queues[0], "root"), "unable
to set the limit for user user1 because invalid quantity")
- conf = createConfig(user.User, user.Groups[0], "invalid", "invalidate")
- assert.Error(t, manager.UpdateConfig(conf.Queues[0], "root"), "unable
to set the limit for user user1 because invalid quantity")
- conf = createUpdateConfig(user.User, user.Groups[0])
+ // configure max resource for root.parent to allow one more application
to run
+ conf = createConfig(user.User, user.Groups[0], "memory", "50", 60, 6)
+ err = manager.UpdateConfig(conf.Queues[0], "root")
+ assert.NilError(t, err, "unable to set the limit for user user1 because
current resource usage is greater than config max resource for root.parent")
- manager = GetUserManager()
+ // should run as user 'user' setting is map[memory:60 vcores:60] and
total usage of "root.parent" is map[memory:50 vcores:50]
+ increased := manager.IncreaseTrackedResource(queuePath1, TestApp1,
usage, user)
+ if !increased {
+ t.Fatalf("unable to increase tracked resource: queuepath %s,
app %s, res %v", queuePath1, TestApp1, user)
+ }
+
+ // should not run as user 'user' setting is map[memory:60 vcores:60]
and total usage of "root.parent" is map[memory:60 vcores:60]
+ increased = manager.IncreaseTrackedResource(queuePath1, TestApp1,
usage, user)
+ if increased {
+ t.Fatalf("unable to increase tracked resource: queuepath %s,
app %s, res %v", queuePath1, TestApp1, user)
+ }
+
+ // configure max resource for root.parent to allow one more application
to run through wild card user settings (not through specific user)
+ user1 := security.UserGroup{User: "user2", Groups: []string{"group2"}}
+ conf = createUpdateConfigWithWildCardUsersAndGroups(user1.User,
user1.Groups[0], "*", "*", "70", "70")
assert.NilError(t, manager.UpdateConfig(conf.Queues[0], "root"))
- assertMaxLimits(t, user, expectedResource, 1)
+ // should run as wild card user '*' setting is map[memory:70 vcores:70]
and total usage of "root.parent" is map[memory:60 vcores:60]
+ increased = manager.IncreaseTrackedResource(queuePath1, TestApp1,
usage, user)
+ if !increased {
+ t.Fatalf("unable to increase tracked resource: queuepath %s,
app %s, res %v", queuePath1, TestApp1, user)
+ }
- for i := 1; i <= 2; i++ {
- err = manager.IncreaseTrackedResource(queuePath1, TestApp1,
expectedResource, user)
- if err != nil {
- t.Fatalf("unable to increase tracked resource:
queuepath %s, app %s, res %v, error %t", queuePath1, TestApp1,
expectedResource, err)
+ // should not run as wild card user '*' setting is map[memory:70
vcores:70] and total usage of "root.parent" is map[memory:70 vcores:70]
+ increased = manager.IncreaseTrackedResource(queuePath1, TestApp1,
usage, user)
+ if increased {
+ t.Fatalf("unable to increase tracked resource: queuepath %s,
app %s, res %v", queuePath1, TestApp1, user)
+ }
+
+ // configure max resource for root.parent to allow one more application
to run through wild card group settings (not through specific group)
+ // also wild card user limit settings not set
+ conf = createUpdateConfigWithWildCardUsersAndGroups(user1.User,
user1.Groups[0], "", "*", "80", "80")
+ assert.NilError(t, manager.UpdateConfig(conf.Queues[0], "root"))
+
+ // should run as wild card group '*' setting is map[memory:80
vcores:80] and total usage of "root.parent" is map[memory:70 vcores:70]
+ increased = manager.IncreaseTrackedResource(queuePath1, TestApp1,
usage, user)
+ if !increased {
+ t.Fatalf("unable to increase tracked resource: queuepath %s,
app %s, res %v", queuePath1, TestApp1, user)
+ }
+
+ // should not run as wild card group '*' setting is map[memory:80
vcores:80] and total usage of "root.parent" is map[memory:80 vcores:80]
+ increased = manager.IncreaseTrackedResource(queuePath1, TestApp1,
usage, user)
+ if increased {
+ t.Fatalf("unable to increase tracked resource: queuepath %s,
app %s, res %v", queuePath1, TestApp1, user)
+ }
+
+ // should run as wild card group '*' setting is map[memory:80
vcores:80] and total usage of "root.parent" is map[memory:70 vcores:70]
+ increased = manager.IncreaseTrackedResource(queuePath1, TestApp1,
usage, user1)
+ if !increased {
+ t.Fatalf("unable to increase tracked resource: queuepath %s,
app %s, res %v", queuePath1, TestApp1, user1)
+ }
+
+ // configure max resource for user2 * root.parent (map[memory:70
vcores:70]) higher than wild card user * root.parent settings (map[memory:10
vcores:10])
+ // ensure user's specific settings overrides the wild card user limit
settings
+ conf = createUpdateConfigWithWildCardUsersAndGroups(user1.User,
user1.Groups[0], "", "*", "10", "10")
+ assert.NilError(t, manager.UpdateConfig(conf.Queues[0], "root"))
+
+ // can be allowed to run upto resource usage map[memory:70 vcores:70]
+ for i := 1; i <= 6; i++ {
+ increased = manager.IncreaseTrackedResource(queuePath1,
TestApp1, usage, user1)
+ if !increased {
+ t.Fatalf("unable to increase tracked resource:
queuepath %s, app %s, res %v", queuePath1, TestApp1, user)
}
}
- assert.Error(t, manager.UpdateConfig(conf.Queues[0], "root"), "unable
to set the limit for user user1 because current resource usage is greater than
config max resource for root.parent")
- err = manager.IncreaseTrackedResource(queuePath1, TestApp1,
expectedResource, user)
- if err != nil {
- t.Fatalf("unable to increase tracked resource: queuepath %s,
app %s, res %v, error %t", queuePath1, TestApp1, expectedResource, err)
+ // should not run as user2 max limit is map[memory:70 vcores:70] and
usage so far is map[memory:70 vcores:70]
+ increased = manager.IncreaseTrackedResource(queuePath1, TestApp1,
usage, user1)
+ if increased {
+ t.Fatalf("unable to increase tracked resource: queuepath %s,
app %s, res %v", queuePath1, TestApp1, user)
}
- assert.Error(t, manager.UpdateConfig(conf.Queues[0], "root"), "unable
to set the limit for user user1 because current resource usage is greater than
config max resource for root")
}
-func TestUpdateConfigWithWildCardUsersAndGroups(t *testing.T) {
+func TestUpdateConfigClearEarlierSetLimits(t *testing.T) {
setupUGM()
// Queue setup:
// root->parent
user := security.UserGroup{User: "user1", Groups: []string{"group1"}}
conf := createUpdateConfig(user.User, user.Groups[0])
+
manager := GetUserManager()
assert.NilError(t, manager.UpdateConfig(conf.Queues[0], "root"))
- expectedResource, err :=
resources.NewResourceFromConf(map[string]string{"memory": "5", "vcores": "5"})
+ expectedResource, err :=
resources.NewResourceFromConf(map[string]string{"memory": "50", "vcores": "50"})
if err != nil {
t.Errorf("new resource create returned error or wrong resource:
error %t, res %v", err, expectedResource)
}
- assertMaxLimits(t, user, expectedResource, 1)
+ assertMaxLimits(t, user, expectedResource, 5)
- for i := 1; i <= 2; i++ {
- err = manager.IncreaseTrackedResource(queuePath1, TestApp1,
expectedResource, user)
- if err != nil {
- t.Fatalf("unable to increase tracked resource:
queuepath %s, app %s, res %v, error %t", queuePath1, TestApp1,
expectedResource, err)
- }
+ // create config user2 * root.parent with [50, 50] and maxapps as 5
(twice for root), but not user1. so user1 should not be there as it doesn't
have any running applications
+ user1 := security.UserGroup{User: "user2", Groups: []string{"group2"}}
+ conf = createUpdateConfig(user1.User, user1.Groups[0])
+ assert.NilError(t, manager.UpdateConfig(conf.Queues[0], "root"))
+
+ expectedResource, err =
resources.NewResourceFromConf(map[string]string{"memory": "50", "vcores": "50"})
+ if err != nil {
+ t.Errorf("new resource create returned error or wrong resource:
error %t, res %v", err, expectedResource)
}
- assert.Error(t, manager.UpdateConfig(conf.Queues[0], "root"), "unable
to set the limit for user user1 because current resource usage is greater than
config max resource for root.parent")
- err = manager.IncreaseTrackedResource(queuePath1, TestApp1,
expectedResource, user)
+ // ensure user1 has been removed from local maps
+ assert.Equal(t, manager.GetUserTracker(user.User) == nil, true)
+ assert.Equal(t, manager.GetGroupTracker(user.Groups[0]) == nil, true)
+ assertMaxLimits(t, user1, expectedResource, 5)
+
+ // override user2 * root.parent config with [60, 60] and maxapps as 6
(twice for root)
+ conf = createConfig(user1.User, user1.Groups[0], "memory", "10", 60, 6)
+ assert.NilError(t, manager.UpdateConfig(conf.Queues[0], "root"))
+
+ expectedResource, err =
resources.NewResourceFromConf(map[string]string{"memory": "60", "vcores": "60"})
if err != nil {
- t.Fatalf("unable to increase tracked resource: queuepath %s,
app %s, res %v, error %t", queuePath1, TestApp1, expectedResource, err)
+ t.Errorf("new resource create returned error or wrong resource:
error %t, res %v", err, expectedResource)
}
- assert.Error(t, manager.UpdateConfig(conf.Queues[0], "root"), "unable
to set the limit for user user1 because current resource usage is greater than
config max resource for root")
+ assert.Equal(t, manager.GetUserTracker(user.User) == nil, true)
+ assert.Equal(t, manager.GetGroupTracker(user.Groups[0]) == nil, true)
+ assertMaxLimits(t, user1, expectedResource, 6)
- user1 := security.UserGroup{User: "user2", Groups: []string{"group2"}}
- conf = createUpdateConfigWithWildCardUsersAndGroups(user1.User,
user1.Groups[0])
+ expectedResource, err =
resources.NewResourceFromConf(map[string]string{"memory": "70", "vcores": "70"})
+ if err != nil {
+ t.Errorf("new resource create returned error or wrong resource:
error %t, res %v", err, expectedResource)
+ }
+
+ // override user2 * root.parent maxapps as [70, 70] and maxapps as 10
(twice for root)
+ // and wild card settings
+ conf = createUpdateConfigWithWildCardUsersAndGroups(user1.User,
user1.Groups[0], "*", "*", "10", "10")
+ assert.NilError(t, manager.UpdateConfig(conf.Queues[0], "root"))
+ assert.Equal(t, manager.GetUserTracker(user.User) == nil, true)
+ assert.Equal(t, manager.GetGroupTracker(user.Groups[0]) == nil, true)
+ assertMaxLimits(t, user1, expectedResource, 10)
+ assertWildCardLimits(t, m.userWildCardLimitsConfig, expectedResource)
+ assertWildCardLimits(t, m.groupWildCardLimitsConfig, expectedResource)
+
+ print("ggg")
+ // config without limits - should clear all earlier set configs
+ conf = createConfigWithoutLimits()
+ assert.NilError(t, manager.UpdateConfig(conf.Queues[0], "root"))
+ assert.Equal(t, manager.GetUserTracker(user.User) == nil, true)
+ assert.Equal(t, manager.GetGroupTracker(user.Groups[0]) == nil, true)
+ assert.Equal(t, manager.GetUserTracker(user1.User) == nil, true)
+ assert.Equal(t, manager.GetGroupTracker(user1.Groups[0]) == nil, true)
+ assert.Equal(t, len(manager.userWildCardLimitsConfig), 0)
+ assert.Equal(t, len(manager.groupWildCardLimitsConfig), 0)
+}
+
+func TestSetMaxLimitsForRemovedUsers(t *testing.T) {
+ setupUGM()
+ // Queue setup:
+ // root->parent
+ user := security.UserGroup{User: "user1", Groups: []string{"group1"}}
+ conf := createUpdateConfig(user.User, user.Groups[0])
+ manager := GetUserManager()
+ assert.NilError(t, manager.UpdateConfig(conf.Queues[0], "root"))
+
+ expectedResource, err :=
resources.NewResourceFromConf(map[string]string{"memory": "50", "vcores": "50"})
+ if err != nil {
+ t.Errorf("new resource create returned error or wrong resource:
error %t, res %v", err, expectedResource)
+ }
+ usage, err := resources.NewResourceFromConf(map[string]string{"memory":
"10", "vcores": "10"})
+ if err != nil {
+ t.Errorf("new resource create returned error or wrong resource:
error %t, res %v", err, usage)
+ }
+ assertMaxLimits(t, user, expectedResource, 5)
+
+ for i := 1; i <= 2; i++ {
+ increased := manager.IncreaseTrackedResource(queuePath1,
TestApp1, usage, user)
+ assert.Equal(t, increased, true, "unable to increase tracked
resource: queuepath "+queuePath1+", app "+TestApp1+", res "+usage.String())
+ }
+ assert.Equal(t, manager.GetUserTracker(user.User) != nil, true)
+ assert.Equal(t, manager.GetGroupTracker(user.Groups[0]) != nil, true)
+
+ decreased := manager.DecreaseTrackedResource(queuePath1, TestApp1,
usage, user, false)
+ assert.Equal(t, decreased, true)
+
+ decreased = manager.DecreaseTrackedResource(queuePath1, TestApp1,
usage, user, true)
+ assert.Equal(t, decreased, true)
+ assert.Equal(t, manager.GetUserTracker(user.User) != nil, true)
+ assert.Equal(t, manager.GetGroupTracker(user.Groups[0]) != nil, true)
+
+ increased := manager.IncreaseTrackedResource("root.parent.leaf",
TestApp1, usage, user)
+ assert.Equal(t, increased, true, "unable to increase tracked resource:
queuepath root.parent.leaf, app "+TestApp1+", res "+usage.String())
+
+ increased = manager.IncreaseTrackedResource("root.parent.leaf",
TestApp1, usage, user)
+ assert.Equal(t, increased, false, "unable to increase tracked resource:
queuepath root.parent.leaf, app "+TestApp1+", res "+usage.String())
+
+ assert.Equal(t, manager.GetUserTracker(user.User) != nil, true)
+ assert.Equal(t, manager.GetGroupTracker(user.Groups[0]) != nil, true)
+
+ decreased = manager.DecreaseTrackedResource("root.parent.leaf",
TestApp1, usage, user, true)
+ assert.Equal(t, decreased, true, "unable to decrease tracked resource:
queuepath root.parent.leaf, app "+TestApp1+", res "+usage.String())
+
+ conf = createConfigWithoutLimits()
assert.NilError(t, manager.UpdateConfig(conf.Queues[0], "root"))
+
+ for i := 1; i <= 2; i++ {
+ increased := manager.IncreaseTrackedResource(queuePath1,
TestApp1, usage, user)
+ assert.Equal(t, increased, true, "unable to increase tracked
resource: queuepath "+queuePath1+", app "+TestApp1+", res "+usage.String())
+ }
+ assert.Equal(t, manager.GetUserTracker(user.User) != nil, true)
+ assert.Equal(t, manager.GetGroupTracker(user.Groups[0]) != nil, true)
+
+ decreased = manager.DecreaseTrackedResource(queuePath1, TestApp1,
usage, user, false)
+ assert.Equal(t, decreased, true)
+
+ decreased = manager.DecreaseTrackedResource(queuePath1, TestApp1,
usage, user, true)
+ assert.Equal(t, decreased, true)
+ assert.Equal(t, manager.GetUserTracker(user.User) == nil, true)
+ assert.Equal(t, manager.GetGroupTracker(user.Groups[0]) == nil, true)
}
-func createUpdateConfigWithWildCardUsersAndGroups(user string, group string)
configs.PartitionConfig {
+func createUpdateConfigWithWildCardUsersAndGroups(user string, group string,
wildUser string, wildGroup string, memory string, vcores string)
configs.PartitionConfig {
conf := configs.PartitionConfig{
Name: "test",
Queues: []configs.QueueConfig{
@@ -277,16 +456,30 @@ func createUpdateConfigWithWildCardUsersAndGroups(user
string, group string) con
Queues: nil,
Limits: []configs.Limit{
{
- Limit: "root
queue limit",
+ Limit: "parent
queue limit for specific user",
+ Users: []string{
+ user,
+ },
+ Groups:
[]string{
+ group,
+ },
+ MaxResources:
map[string]string{
+
"memory": "70",
+
"vcores": "70",
+ },
+
MaxApplications: 10,
+ },
+ {
+ Limit: "parent
queue limit for wild card user",
Users: []string{
- user,
"*",
+
wildUser,
},
Groups:
[]string{
- group,
"*",
+
wildGroup,
},
MaxResources:
map[string]string{
-
"memory": "50",
-
"vcores": "50",
+
"memory": memory,
+
"vcores": vcores,
},
MaxApplications: 10,
},
@@ -297,14 +490,14 @@ func createUpdateConfigWithWildCardUsersAndGroups(user
string, group string) con
{
Limit: "root queue limit",
Users: []string{
- user, "*",
+ user, wildUser,
},
Groups: []string{
- group, "*",
+ group, wildGroup,
},
MaxResources: map[string]string{
- "memory": "100",
- "vcores": "100",
+ "memory": "140",
+ "vcores": "140",
},
MaxApplications: 20,
},
@@ -316,10 +509,10 @@ func createUpdateConfigWithWildCardUsersAndGroups(user
string, group string) con
}
func createUpdateConfig(user string, group string) configs.PartitionConfig {
- return createConfig(user, group, "memory", "10")
+ return createConfig(user, group, "memory", "10", 50, 5)
}
-func createConfig(user string, group string, resourceKey string, resourceValue
string) configs.PartitionConfig {
+func createConfig(user string, group string, resourceKey string, resourceValue
string, mem int, maxApps uint64) configs.PartitionConfig {
conf := configs.PartitionConfig{
Name: "test",
Queues: []configs.QueueConfig{
@@ -332,10 +525,33 @@ func createConfig(user string, group string, resourceKey
string, resourceValue s
Name: "parent",
Parent: true,
SubmitACL: "*",
- Queues: nil,
+ Queues: []configs.QueueConfig{
+ {
+ Name:
"leaf",
+ Parent:
false,
+ SubmitACL: "*",
+ Queues: nil,
+ Limits:
[]configs.Limit{
+ {
+
Limit: "leaf queue limit",
+
Users: []string{
+
user,
+
},
+
Groups: []string{
+
group,
+
},
+
MaxResources: map[string]string{
+
resourceKey: resourceValue,
+
"vcores": "10",
+
},
+
MaxApplications: maxApps,
+ },
+ },
+ },
+ },
Limits: []configs.Limit{
{
- Limit: "root
queue limit",
+ Limit: "parent
queue limit",
Users: []string{
user,
},
@@ -343,10 +559,10 @@ func createConfig(user string, group string, resourceKey
string, resourceValue s
group,
},
MaxResources:
map[string]string{
-
"memory": "5",
-
"vcores": "5",
+
"memory": strconv.Itoa(mem),
+
"vcores": strconv.Itoa(mem),
},
-
MaxApplications: 1,
+
MaxApplications: maxApps,
},
},
},
@@ -361,10 +577,10 @@ func createConfig(user string, group string, resourceKey
string, resourceValue s
group,
},
MaxResources: map[string]string{
- resourceKey:
resourceValue,
- "vcores": "10",
+ "memory":
strconv.Itoa(mem * 2),
+ "vcores":
strconv.Itoa(mem * 2),
},
- MaxApplications: 2,
+ MaxApplications: maxApps * 2,
},
},
},
@@ -373,76 +589,26 @@ func createConfig(user string, group string, resourceKey
string, resourceValue s
return conf
}
-func TestUpdateConfigClearEarlierSetLimits(t *testing.T) {
- setupUGM()
- // Queue setup:
- // root->parent
- user := security.UserGroup{User: "user1", Groups: []string{"group1"}}
- conf := createUpdateConfig(user.User, user.Groups[0])
-
- manager := GetUserManager()
- assert.NilError(t, manager.UpdateConfig(conf.Queues[0], "root"))
-
- expectedResource, err :=
resources.NewResourceFromConf(map[string]string{"memory": "5", "vcores": "5"})
- if err != nil {
- t.Errorf("new resource create returned error or wrong resource:
error %t, res %v", err, expectedResource)
- }
- assertMaxLimits(t, user, expectedResource, 1)
-
- user1 := security.UserGroup{User: "user2", Groups: []string{"group2"}}
- conf = createUpdateConfig(user1.User, user1.Groups[0])
- assert.NilError(t, manager.UpdateConfig(conf.Queues[0], "root"))
-
- expectedResource, err =
resources.NewResourceFromConf(map[string]string{"memory": "5", "vcores": "5"})
- if err != nil {
- t.Errorf("new resource create returned error or wrong resource:
error %t, res %v", err, expectedResource)
- }
- assertMaxLimits(t, user, resources.NewResource(), 0)
- assertMaxLimits(t, user1, expectedResource, 1)
-}
-
-func TestSetMaxLimitsForRemovedUsers(t *testing.T) {
- setupUGM()
- // Queue setup:
- // root->parent
- user := security.UserGroup{User: "user1", Groups: []string{"group1"}}
- conf := createUpdateConfig(user.User, user.Groups[0])
- manager := GetUserManager()
- assert.NilError(t, manager.UpdateConfig(conf.Queues[0], "root"))
-
- expectedResource, err :=
resources.NewResourceFromConf(map[string]string{"memory": "5", "vcores": "5"})
- if err != nil {
- t.Errorf("new resource create returned error or wrong resource:
error %t, res %v", err, expectedResource)
- }
- assertMaxLimits(t, user, expectedResource, 1)
-
- for i := 1; i <= 2; i++ {
- err = manager.IncreaseTrackedResource(queuePath1, TestApp1,
expectedResource, user)
- if err != nil {
- t.Fatalf("unable to increase tracked resource:
queuepath %s, app %s, res %v, error %t", queuePath1, TestApp1,
expectedResource, err)
- }
- }
- assert.Equal(t, manager.GetUserTracker(user.User) != nil, true)
- assert.Equal(t, manager.GetGroupTracker(user.Groups[0]) != nil, true)
-
- err = manager.DecreaseTrackedResource(queuePath1, TestApp1,
expectedResource, user, false)
- if err != nil {
- t.Fatalf("unable to increase tracked resource: queuepath %s,
app %s, res %v, error %t", queuePath1, TestApp1, expectedResource, err)
- }
- err = manager.DecreaseTrackedResource(queuePath1, TestApp1,
expectedResource, user, true)
- if err != nil {
- t.Fatalf("unable to increase tracked resource: queuepath %s,
app %s, res %v, error %t", queuePath1, TestApp1, expectedResource, err)
- }
- assert.Equal(t, manager.GetUserTracker(user.User) == nil, true)
- assert.Equal(t, manager.GetGroupTracker(user.Groups[0]) == nil, true)
-
- err = manager.IncreaseTrackedResource(queuePath1, TestApp1,
expectedResource, user)
- if err != nil {
- t.Fatalf("unable to increase tracked resource: queuepath %s,
app %s, res %v, error %t", queuePath1, TestApp1, expectedResource, err)
+func createConfigWithoutLimits() configs.PartitionConfig {
+ conf := configs.PartitionConfig{
+ Name: "test",
+ Queues: []configs.QueueConfig{
+ {
+ Name: "root",
+ Parent: true,
+ SubmitACL: "*",
+ Queues: []configs.QueueConfig{
+ {
+ Name: "parent",
+ Parent: true,
+ SubmitACL: "*",
+ Queues: nil,
+ },
+ },
+ },
+ },
}
- assert.Equal(t, manager.GetUserTracker(user.User) != nil, true)
- assert.Equal(t, manager.GetGroupTracker(user.Groups[0]) != nil, true)
- assertMaxLimits(t, user, expectedResource, 1)
+ return conf
}
func setupUGM() {
@@ -465,10 +631,23 @@ func assertMaxLimits(t *testing.T, userGroup
security.UserGroup, expectedResourc
manager := GetUserManager()
assert.Equal(t,
manager.GetUserTracker(userGroup.User).queueTracker.maxRunningApps,
uint64(expectedMaxApps*2))
assert.Equal(t,
manager.GetGroupTracker(userGroup.Groups[0]).queueTracker.maxRunningApps,
uint64(expectedMaxApps*2))
- assert.Equal(t,
resources.Equals(manager.GetUserTracker(userGroup.User).queueTracker.maxResourceUsage,
resources.Multiply(expectedResource, 2)), true)
- assert.Equal(t,
resources.Equals(manager.GetGroupTracker(userGroup.Groups[0]).queueTracker.maxResourceUsage,
resources.Multiply(expectedResource, 2)), true)
+ assert.Equal(t,
resources.Equals(manager.GetUserTracker(userGroup.User).queueTracker.maxResources,
resources.Multiply(expectedResource, 2)), true)
+ assert.Equal(t,
resources.Equals(manager.GetGroupTracker(userGroup.Groups[0]).queueTracker.maxResources,
resources.Multiply(expectedResource, 2)), true)
assert.Equal(t,
manager.GetUserTracker(userGroup.User).queueTracker.childQueueTrackers["parent"].maxRunningApps,
uint64(expectedMaxApps))
assert.Equal(t,
manager.GetGroupTracker(userGroup.Groups[0]).queueTracker.childQueueTrackers["parent"].maxRunningApps,
uint64(expectedMaxApps))
- assert.Equal(t,
resources.Equals(manager.GetUserTracker(userGroup.User).queueTracker.childQueueTrackers["parent"].maxResourceUsage,
expectedResource), true)
- assert.Equal(t,
resources.Equals(manager.GetGroupTracker(userGroup.Groups[0]).queueTracker.childQueueTrackers["parent"].maxResourceUsage,
expectedResource), true)
+ assert.Equal(t,
resources.Equals(manager.GetUserTracker(userGroup.User).queueTracker.childQueueTrackers["parent"].maxResources,
expectedResource), true)
+ assert.Equal(t,
resources.Equals(manager.GetGroupTracker(userGroup.Groups[0]).queueTracker.childQueueTrackers["parent"].maxResources,
expectedResource), true)
+}
+
+func assertWildCardLimits(t *testing.T, limitsConfig map[string]*LimitConfig,
expectedResource *resources.Resource) {
+ assert.Equal(t, limitsConfig["root"].maxApplications, uint64(20))
+ assert.Equal(t, limitsConfig["root.parent"].maxApplications, uint64(10))
+ expResource := limitsConfig["root"].maxResources
+ assert.Equal(t, resources.Equals(expResource,
resources.Multiply(expectedResource, 2)), true)
+ expResource = limitsConfig["root.parent"].maxResources
+ configuredResource, err :=
resources.NewResourceFromConf(map[string]string{"memory": "10", "vcores": "10"})
+ if err != nil {
+ t.Errorf("new resource create returned error or wrong resource:
error %t, res %v", err, configuredResource)
+ }
+ assert.Equal(t, resources.Equals(expResource, configuredResource), true)
}
diff --git a/pkg/scheduler/ugm/queue_tracker.go
b/pkg/scheduler/ugm/queue_tracker.go
index 415ab3aa..9ca5e1c7 100644
--- a/pkg/scheduler/ugm/queue_tracker.go
+++ b/pkg/scheduler/ugm/queue_tracker.go
@@ -19,8 +19,6 @@
package ugm
import (
- "fmt"
-
"go.uber.org/zap"
"github.com/apache/yunikorn-core/pkg/common/configs"
@@ -31,73 +29,171 @@ import (
type QueueTracker struct {
queueName string
+ queuePath string
resourceUsage *resources.Resource
runningApplications map[string]bool
- maxResourceUsage *resources.Resource
+ maxResources *resources.Resource
maxRunningApps uint64
childQueueTrackers map[string]*QueueTracker
}
func newRootQueueTracker() *QueueTracker {
- return newQueueTracker(configs.RootQueue)
+ qt := newQueueTracker("", configs.RootQueue)
+ return qt
}
-func newQueueTracker(queueName string) *QueueTracker {
- log.Log(log.SchedUGM).Debug("Creating queue tracker object for queue",
- zap.String("queue", queueName))
+func newQueueTracker(queuePath string, queueName string) *QueueTracker {
+ qp := queueName
+ if queuePath != "" {
+ qp = queuePath + "." + queueName
+ }
queueTracker := &QueueTracker{
queueName: queueName,
+ queuePath: qp,
resourceUsage: resources.NewResource(),
runningApplications: make(map[string]bool),
+ maxResources: resources.NewResource(),
+ maxRunningApps: 0,
childQueueTrackers: make(map[string]*QueueTracker),
}
+ log.Log(log.SchedUGM).Debug("Created queue tracker object for queue",
+ zap.String("queue", queueName))
return queueTracker
}
-func (qt *QueueTracker) increaseTrackedResource(queuePath string,
applicationID string, usage *resources.Resource) error {
+type trackingType int
+
+const (
+ none trackingType = iota
+ user
+ group
+)
+
+func (qt *QueueTracker) increaseTrackedResource(queuePath string,
applicationID string, trackType trackingType, usage *resources.Resource) bool {
log.Log(log.SchedUGM).Debug("Increasing resource usage",
+ zap.Int("tracking type", int(trackType)),
zap.String("queue path", queuePath),
zap.String("application", applicationID),
zap.Stringer("resource", usage))
- if queuePath == "" || applicationID == "" || usage == nil {
- return fmt.Errorf("mandatory parameters are missing. queuepath:
%s, application id: %s, resource usage: %s",
- queuePath, applicationID, usage.String())
+ finalResourceUsage := qt.resourceUsage.Clone()
+ finalResourceUsage.AddTo(usage)
+ wildCardQuotaExceeded := false
+ existingApp := qt.runningApplications[applicationID]
+
+ // apply user/group specific limit settings set if configured,
otherwise use wild card limit settings
+ if qt.maxRunningApps != 0 && !resources.Equals(resources.NewResource(),
qt.maxResources) {
+ log.Log(log.SchedUGM).Debug("applying enforcement checks using
limit settings of specific user/group",
+ zap.Int("tracking type", int(trackType)),
+ zap.String("queue path", queuePath),
+ zap.Bool("existing app", existingApp),
+ zap.Uint64("max running apps", qt.maxRunningApps),
+ zap.String("max resources", qt.maxResources.String()))
+ if (!existingApp && len(qt.runningApplications)+1 >
int(qt.maxRunningApps)) ||
+ resources.StrictlyGreaterThan(finalResourceUsage,
qt.maxResources) {
+ log.Log(log.SchedUGM).Warn("Unable to increase resource
usage as allowing new application to run would exceed either configured max
applications or max resources limit of specific user/group",
+ zap.Int("tracking type", int(trackType)),
+ zap.String("queue path", queuePath),
+ zap.Bool("existing app", existingApp),
+ zap.Int("current running applications",
len(qt.runningApplications)),
+ zap.Uint64("max running applications",
qt.maxRunningApps),
+ zap.String("current resource usage",
qt.resourceUsage.String()),
+ zap.String("max resource usage",
qt.maxResources.String()))
+ return false
+ }
+ }
+
+ // Try wild card settings
+ if qt.maxRunningApps == 0 && resources.Equals(resources.NewResource(),
qt.maxResources) {
+ // Is there any wild card settings? Do we need to apply
enforcement checks using wild card limit settings?
+ var config *LimitConfig
+ if trackType == user {
+ config = m.getUserWildCardLimitsConfig(qt.queuePath)
+ } else if trackType == group {
+ config = m.getGroupWildCardLimitsConfig(qt.queuePath)
+ }
+ if config != nil {
+ log.Log(log.SchedUGM).Debug("applying enforcement
checks using limit settings of wild card user/group",
+ zap.Int("tracking type", int(trackType)),
+ zap.String("queue path", queuePath),
+ zap.Bool("existing app", existingApp),
+ zap.Uint64("wild card max running apps",
config.maxApplications),
+ zap.String("wild card max resources",
config.maxResources.String()),
+ zap.Bool("wild card quota exceeded",
wildCardQuotaExceeded))
+ wildCardQuotaExceeded = (config.maxApplications != 0 &&
!existingApp && len(qt.runningApplications)+1 > int(config.maxApplications)) ||
+ (!resources.Equals(resources.NewResource(),
config.maxResources) && resources.StrictlyGreaterThan(finalResourceUsage,
config.maxResources))
+ if wildCardQuotaExceeded {
+ log.Log(log.SchedUGM).Warn("Unable to increase
resource usage as allowing new application to run would exceed either
configured max applications or max resources limit of wild card user/group",
+ zap.Int("tracking type",
int(trackType)),
+ zap.String("queue path", queuePath),
+ zap.Bool("existing app", existingApp),
+ zap.Int("current running applications",
len(qt.runningApplications)),
+ zap.Uint64("max running applications",
config.maxApplications),
+ zap.String("current resource usage",
qt.resourceUsage.String()),
+ zap.String("max resource usage",
config.maxResources.String()))
+ return false
+ }
+ }
+ }
+
+ childQueuePath, immediateChildQueueName := getChildQueuePath(queuePath)
+ if childQueuePath != "" {
+ if qt.childQueueTrackers[immediateChildQueueName] == nil {
+ qt.childQueueTrackers[immediateChildQueueName] =
newQueueTracker(qt.queuePath, immediateChildQueueName)
+ }
+ allowed :=
qt.childQueueTrackers[immediateChildQueueName].increaseTrackedResource(childQueuePath,
applicationID, trackType, usage)
+ if !allowed {
+ return allowed
+ }
}
+
qt.resourceUsage.AddTo(usage)
qt.runningApplications[applicationID] = true
log.Log(log.SchedUGM).Debug("Successfully increased resource usage",
+ zap.Int("tracking type", int(trackType)),
zap.String("queue path", queuePath),
zap.String("application", applicationID),
+ zap.Bool("existing app", existingApp),
zap.Stringer("resource", usage),
+ zap.Uint64("max running applications", qt.maxRunningApps),
+ zap.String("max resource usage", qt.maxResources.String()),
zap.Stringer("total resource after increasing",
qt.resourceUsage),
zap.Int("total applications after increasing",
len(qt.runningApplications)))
-
- childQueuePath, immediateChildQueueName := getChildQueuePath(queuePath)
- if childQueuePath != "" {
- if qt.childQueueTrackers[immediateChildQueueName] == nil {
- qt.childQueueTrackers[immediateChildQueueName] =
newQueueTracker(immediateChildQueueName)
- }
- err :=
qt.childQueueTrackers[immediateChildQueueName].increaseTrackedResource(childQueuePath,
applicationID, usage)
- if err != nil {
- return err
- }
- }
- return nil
+ return true
}
-func (qt *QueueTracker) decreaseTrackedResource(queuePath string,
applicationID string, usage *resources.Resource, removeApp bool) (bool, error) {
+func (qt *QueueTracker) decreaseTrackedResource(queuePath string,
applicationID string, usage *resources.Resource, removeApp bool) (bool, bool) {
log.Log(log.SchedUGM).Debug("Decreasing resource usage",
zap.String("queue path", queuePath),
zap.String("application", applicationID),
zap.Stringer("resource", usage),
zap.Bool("removeApp", removeApp))
- if queuePath == "" || usage == nil {
- return false, fmt.Errorf("mandatory parameters are missing.
queuepath: %s, application id: %s, resource usage: %s",
- queuePath, applicationID, usage.String())
+ childQueuePath, immediateChildQueueName := getChildQueuePath(queuePath)
+ if childQueuePath != "" {
+ if qt.childQueueTrackers[immediateChildQueueName] == nil {
+ log.Log(log.SchedUGM).Error("Child queueTracker tracker
must be available in child queues map",
+ zap.String("child queueTracker name",
immediateChildQueueName))
+ return false, false
+ }
+ removeQT, decreased :=
qt.childQueueTrackers[immediateChildQueueName].decreaseTrackedResource(childQueuePath,
applicationID, usage, removeApp)
+ if !decreased {
+ return false, decreased
+ }
+ if removeQT {
+ log.Log(log.SchedUGM).Debug("Removed queue tracker
linkage from its parent",
+ zap.String("queue path ", queuePath),
+ zap.String("removed queue name",
immediateChildQueueName),
+ zap.String("parent queue", qt.queueName))
+ delete(qt.childQueueTrackers, immediateChildQueueName)
+ }
}
+
qt.resourceUsage.SubFrom(usage)
if removeApp {
+ log.Log(log.SchedUGM).Debug("Removed application from running
applications",
+ zap.String("application", applicationID),
+ zap.String("queue path", queuePath),
+ zap.String("queue name", qt.queueName))
delete(qt.runningApplications, applicationID)
}
log.Log(log.SchedUGM).Debug("Successfully decreased resource usage",
@@ -107,26 +203,13 @@ func (qt *QueueTracker) decreaseTrackedResource(queuePath
string, applicationID
zap.Stringer("total resource after decreasing",
qt.resourceUsage),
zap.Int("total applications after decreasing",
len(qt.runningApplications)))
- childQueuePath, immediateChildQueueName := getChildQueuePath(queuePath)
- if childQueuePath != "" {
- if qt.childQueueTrackers[immediateChildQueueName] != nil {
- removeQT, err :=
qt.childQueueTrackers[immediateChildQueueName].decreaseTrackedResource(childQueuePath,
applicationID, usage, removeApp)
- if err != nil {
- return false, err
- }
- if removeQT {
- delete(qt.childQueueTrackers,
immediateChildQueueName)
- }
- } else {
- log.Log(log.SchedUGM).Error("Child queueTracker tracker
must be available in child queues map",
- zap.String("child queueTracker name",
immediateChildQueueName))
- return false, fmt.Errorf("child queueTracker tracker
for %s is missing in child queues map", immediateChildQueueName)
- }
- }
-
// Determine if the queue tracker should be removed
- removeQT := len(qt.childQueueTrackers) == 0 &&
len(qt.runningApplications) == 0 && resources.IsZero(qt.resourceUsage)
- return removeQT, nil
+ removeQT := len(qt.childQueueTrackers) == 0 &&
len(qt.runningApplications) == 0 && resources.IsZero(qt.resourceUsage) &&
+ qt.maxRunningApps == 0 &&
resources.Equals(resources.NewResource(), qt.maxResources)
+ log.Log(log.SchedUGM).Debug("Remove queue tracker",
+ zap.String("queue path ", queuePath),
+ zap.Bool("remove QT", removeQT))
+ return removeQT, true
}
func (qt *QueueTracker) getChildQueueTracker(queuePath string) *QueueTracker {
@@ -137,7 +220,7 @@ func (qt *QueueTracker) getChildQueueTracker(queuePath
string) *QueueTracker {
for childQueuePath != "" {
if childQueueTracker != nil {
if len(childQueueTracker.childQueueTrackers) ==
0 || childQueueTracker.childQueueTrackers[immediateChildQueueName] == nil {
- newChildQt :=
newQueueTracker(immediateChildQueueName)
+ newChildQt :=
newQueueTracker(qt.queuePath, immediateChildQueueName)
childQueueTracker.childQueueTrackers[immediateChildQueueName] = newChildQt
childQueueTracker = newChildQt
} else {
@@ -150,40 +233,14 @@ func (qt *QueueTracker) getChildQueueTracker(queuePath
string) *QueueTracker {
return childQueueTracker
}
-func (qt *QueueTracker) setMaxApplications(count uint64, queuePath string)
error {
- log.Log(log.SchedUGM).Debug("Setting max applications",
+func (qt *QueueTracker) setLimit(queuePath string, maxResource
*resources.Resource, maxApps uint64) {
+ log.Log(log.SchedUGM).Debug("Setting limits",
zap.String("queue path", queuePath),
- zap.Uint64("max applications", count))
+ zap.Uint64("max applications", maxApps),
+ zap.String("max resources", maxResource.String()))
childQueueTracker := qt.getChildQueueTracker(queuePath)
- if childQueueTracker.maxRunningApps != 0 && count != 0 &&
len(childQueueTracker.runningApplications) > int(count) {
- log.Log(log.SchedUGM).Warn("Current running applications is
greater than config max applications",
- zap.String("queue path", queuePath),
- zap.Uint64("current max applications",
childQueueTracker.maxRunningApps),
- zap.Int("total running applications",
len(childQueueTracker.runningApplications)),
- zap.Uint64("config max applications", count))
- return fmt.Errorf("current running applications is greater than
config max applications for %s", queuePath)
- } else {
- childQueueTracker.maxRunningApps = count
- }
- return nil
-}
-
-func (qt *QueueTracker) setMaxResources(resource *resources.Resource,
queuePath string) error {
- log.Log(log.SchedUGM).Debug("Setting max resources",
- zap.String("queue path", queuePath),
- zap.String("max resources", resource.String()))
- childQueueTracker := qt.getChildQueueTracker(queuePath)
- if (!resources.Equals(childQueueTracker.maxResourceUsage,
resources.NewResource()) && !resources.Equals(resource,
resources.NewResource())) &&
resources.StrictlyGreaterThan(childQueueTracker.resourceUsage, resource) {
- log.Log(log.SchedUGM).Warn("Current resource usage is greater
than config max resource",
- zap.String("queue path", queuePath),
- zap.String("current max resource usage",
childQueueTracker.maxResourceUsage.String()),
- zap.String("total resource usage",
childQueueTracker.resourceUsage.String()),
- zap.String("config max resources", resource.String()))
- return fmt.Errorf("current resource usage is greater than
config max resource for %s", queuePath)
- } else {
- childQueueTracker.maxResourceUsage = resource
- }
- return nil
+ childQueueTracker.maxRunningApps = maxApps
+ childQueueTracker.maxResources = maxResource
}
func (qt *QueueTracker) getResourceUsageDAOInfo(parentQueuePath string)
*dao.ResourceUsageDAOInfo {
@@ -201,7 +258,7 @@ func (qt *QueueTracker)
getResourceUsageDAOInfo(parentQueuePath string) *dao.Res
for app := range qt.runningApplications {
usage.RunningApplications = append(usage.RunningApplications,
app)
}
- usage.MaxResources = qt.maxResourceUsage
+ usage.MaxResources = qt.maxResources
usage.MaxApplications = qt.maxRunningApps
for _, cqt := range qt.childQueueTrackers {
childUsage := cqt.getResourceUsageDAOInfo(fullQueuePath)
@@ -209,3 +266,69 @@ func (qt *QueueTracker)
getResourceUsageDAOInfo(parentQueuePath string) *dao.Res
}
return usage
}
+
+// IsQueuePathTrackedCompletely Traverse queue path upto the end queue through
its linkage
+// to confirm entire queuePath has been tracked completely or not
+func (qt *QueueTracker) IsQueuePathTrackedCompletely(queuePath string) bool {
+ if queuePath == configs.RootQueue || queuePath == qt.queueName {
+ return true
+ }
+ childQueuePath, immediateChildQueueName := getChildQueuePath(queuePath)
+ if immediateChildQueueName != "" {
+ if childUt, ok :=
qt.childQueueTrackers[immediateChildQueueName]; ok {
+ return
childUt.IsQueuePathTrackedCompletely(childQueuePath)
+ }
+ }
+ return false
+}
+
+// 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.
+func (qt *QueueTracker) IsUnlinkRequired(queuePath string) bool {
+ childQueuePath, immediateChildQueueName := getChildQueuePath(queuePath)
+ if immediateChildQueueName != "" {
+ if childUt, ok :=
qt.childQueueTrackers[immediateChildQueueName]; ok {
+ return childUt.IsUnlinkRequired(childQueuePath)
+ }
+ }
+ if queuePath == configs.RootQueue || queuePath == qt.queueName {
+ if len(qt.runningApplications) == 0 {
+ log.Log(log.SchedUGM).Debug("Is Unlink Required?",
+ zap.String("queue path", queuePath),
+ zap.Int("no. of applications",
len(qt.runningApplications)))
+ return true
+ }
+ }
+ return false
+}
+
+// UnlinkQT 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
+func (qt *QueueTracker) UnlinkQT(queuePath string) bool {
+ log.Log(log.SchedUGM).Debug("Unlinking current queue tracker from its
parent",
+ zap.String("current queue ", qt.queueName),
+ zap.String("queue path", queuePath),
+ zap.Int("no. of child queue trackers",
len(qt.childQueueTrackers)))
+ childQueuePath, immediateChildQueueName := getChildQueuePath(queuePath)
+
+ if childQueuePath == "" && len(qt.childQueueTrackers) > 0 {
+ for qName := range qt.childQueueTrackers {
+ qt.UnlinkQT(qt.queueName + configs.DOT + qName)
+ }
+ }
+
+ if childQueuePath != "" {
+ if qt.childQueueTrackers[immediateChildQueueName] != nil {
+ unlink :=
qt.childQueueTrackers[immediateChildQueueName].UnlinkQT(childQueuePath)
+ if unlink {
+ delete(qt.childQueueTrackers,
immediateChildQueueName)
+ }
+ }
+ }
+ if len(qt.runningApplications) == 0 && len(qt.childQueueTrackers) == 0 {
+ return true
+ }
+ return false
+}
diff --git a/pkg/scheduler/ugm/queue_tracker_test.go
b/pkg/scheduler/ugm/queue_tracker_test.go
index 1a79444e..ea88355a 100644
--- a/pkg/scheduler/ugm/queue_tracker_test.go
+++ b/pkg/scheduler/ugm/queue_tracker_test.go
@@ -31,45 +31,43 @@ func TestQTIncreaseTrackedResource(t *testing.T) {
// root->parent->child1->child12
// root->parent->child2
// root->parent->child12 (similar name like above leaf queue, but it is
being treated differently as similar names are allowed)
- queueTracker := newQueueTracker("root")
+ GetUserManager()
+ queueTracker := newQueueTracker("", "root")
usage1, err := resources.NewResourceFromConf(map[string]string{"mem":
"10M", "vcore": "10"})
if err != nil {
t.Errorf("new resource create returned error or wrong resource:
error %t, res %v", err, usage1)
}
- err = queueTracker.increaseTrackedResource("", "", usage1)
- assert.Error(t, err, "mandatory parameters are missing. queuepath: ,
application id: , resource usage: "+usage1.String())
-
- err = queueTracker.increaseTrackedResource(queuePath1, TestApp1, usage1)
- if err != nil {
- t.Fatalf("unable to increase tracked resource: queuepath %s,
app %s, res %v, error %t", queuePath1, TestApp1, usage1, err)
+ result := queueTracker.increaseTrackedResource(queuePath1, TestApp1,
user, usage1)
+ if !result {
+ t.Fatalf("unable to increase tracked resource: queuepath %s,
app %s, res %v", queuePath1, TestApp1, usage1)
}
usage2, err := resources.NewResourceFromConf(map[string]string{"mem":
"20M", "vcore": "20"})
if err != nil {
t.Errorf("new resource create returned error or wrong resource:
error %t, res %v", err, usage2)
}
- err = queueTracker.increaseTrackedResource(queuePath2, TestApp2, usage2)
- if err != nil {
- t.Fatalf("unable to increase tracked resource: queuepath %s,
app %s, res %v, error %t", queuePath2, TestApp2, usage2, err)
+ result = queueTracker.increaseTrackedResource(queuePath2, TestApp2,
user, usage2)
+ if !result {
+ t.Fatalf("unable to increase tracked resource: queuepath %s,
app %s, res %v", queuePath2, TestApp2, usage2)
}
usage3, err := resources.NewResourceFromConf(map[string]string{"mem":
"30M", "vcore": "30"})
if err != nil {
t.Errorf("new resource create returned error or wrong resource:
error %t, res %v", err, usage3)
}
- err = queueTracker.increaseTrackedResource(queuePath3, TestApp3, usage3)
- if err != nil {
- t.Fatalf("unable to increase tracked resource: queuepath %s,
app %s, res %v, error %t", queuePath3, TestApp3, usage3, err)
+ result = queueTracker.increaseTrackedResource(queuePath3, TestApp3,
user, usage3)
+ if !result {
+ t.Fatalf("unable to increase tracked resource: queuepath %s,
app %s, res %v", queuePath3, TestApp3, usage3)
}
usage4, err := resources.NewResourceFromConf(map[string]string{"mem":
"20M", "vcore": "20"})
if err != nil {
t.Errorf("new resource create returned error or wrong resource:
error %t, res %v", err, usage3)
}
- err = queueTracker.increaseTrackedResource(queuePath4, TestApp4, usage4)
- if err != nil {
- t.Fatalf("unable to increase tracked resource: queuepath %s,
app %s, res %v, error %t", queuePath4, TestApp4, usage4, err)
+ result = queueTracker.increaseTrackedResource(queuePath4, TestApp4,
user, usage4)
+ if !result {
+ t.Fatalf("unable to increase tracked resource: queuepath %s,
app %s, res %v", queuePath4, TestApp4, usage4)
}
actualResources := getQTResource(queueTracker)
@@ -86,15 +84,16 @@ func TestQTDecreaseTrackedResource(t *testing.T) {
// Queue setup:
// root->parent->child1
// root->parent->child2
- queueTracker := newQueueTracker("root")
+ GetUserManager()
+ queueTracker := newQueueTracker("", "root")
usage1, err := resources.NewResourceFromConf(map[string]string{"mem":
"70M", "vcore": "70"})
if err != nil {
t.Errorf("new resource create returned error or wrong resource:
error %t, res %v", err, usage1)
}
- err = queueTracker.increaseTrackedResource(queuePath1, TestApp1, usage1)
- if err != nil {
- t.Fatalf("unable to increase tracked resource: queuepath %s,
app %s, res %v, error %t", queuePath1, TestApp1, usage1, err)
+ result := queueTracker.increaseTrackedResource(queuePath1, TestApp1,
user, usage1)
+ if !result {
+ t.Fatalf("unable to increase tracked resource: queuepath %s,
app %s, res %v", queuePath1, TestApp1, usage1)
}
assert.Equal(t, 1, len(queueTracker.runningApplications))
@@ -102,9 +101,9 @@ func TestQTDecreaseTrackedResource(t *testing.T) {
if err != nil {
t.Errorf("new resource create returned error or wrong resource:
error %t, res %v", err, usage2)
}
- err = queueTracker.increaseTrackedResource(queuePath2, TestApp2, usage2)
- if err != nil {
- t.Fatalf("unable to increase tracked resource: queuepath %s,
app %s, res %v, error %t", queuePath2, TestApp2, usage2, err)
+ result = queueTracker.increaseTrackedResource(queuePath2, TestApp2,
user, usage2)
+ if !result {
+ t.Fatalf("unable to increase tracked resource: queuepath %s,
app %s, res %v", queuePath2, TestApp2, usage2)
}
actualResources := getQTResource(queueTracker)
@@ -119,17 +118,14 @@ func TestQTDecreaseTrackedResource(t *testing.T) {
t.Errorf("new resource create returned error or wrong resource:
error %t, res %v", err, usage3)
}
- err = queueTracker.increaseTrackedResource("", "", usage3)
- assert.Error(t, err, "mandatory parameters are missing. queuepath: ,
application id: , resource usage: "+usage3.String())
-
- removeQT, err := queueTracker.decreaseTrackedResource(queuePath1,
TestApp1, usage3, false)
- if err != nil {
+ removeQT, decreased := queueTracker.decreaseTrackedResource(queuePath1,
TestApp1, usage3, false)
+ if !decreased {
t.Fatalf("unable to decrease tracked resource: queuepath %s,
app %s, res %v, error %t", queuePath1, TestApp1, usage3, err)
}
assert.Equal(t, removeQT, false, "wrong remove queue tracker value")
- removeQT, err = queueTracker.decreaseTrackedResource(queuePath2,
TestApp2, usage3, false)
- if err != nil {
+ removeQT, decreased = queueTracker.decreaseTrackedResource(queuePath2,
TestApp2, usage3, false)
+ if !decreased {
t.Fatalf("unable to decrease tracked resource: queuepath %s,
app %s, res %v, error %t", queuePath2, TestApp2, usage3, err)
}
actualResources1 := getQTResource(queueTracker)
@@ -145,8 +141,8 @@ func TestQTDecreaseTrackedResource(t *testing.T) {
if err != nil {
t.Errorf("new resource create returned error or wrong resource:
error %t, res %v", err, usage3)
}
- removeQT, err = queueTracker.decreaseTrackedResource(queuePath1,
TestApp1, usage4, true)
- if err != nil {
+ removeQT, decreased = queueTracker.decreaseTrackedResource(queuePath1,
TestApp1, usage4, true)
+ if !decreased {
t.Fatalf("unable to decrease tracked resource: queuepath %s,
app %s, res %v, error %t", queuePath1, TestApp1, usage1, err)
}
assert.Equal(t, 1, len(queueTracker.runningApplications))
@@ -158,8 +154,8 @@ func TestQTDecreaseTrackedResource(t *testing.T) {
if err != nil {
t.Errorf("new resource create returned error or wrong resource:
error %t, res %v", err, usage5)
}
- removeQT, err = queueTracker.decreaseTrackedResource(queuePath2,
TestApp2, usage5, true)
- if err != nil {
+ removeQT, decreased = queueTracker.decreaseTrackedResource(queuePath2,
TestApp2, usage5, true)
+ if !decreased {
t.Fatalf("unable to decrease tracked resource: queuepath %s,
app %s, res %v, error %t", queuePath2, TestApp2, usage2, err)
}
assert.Equal(t, 0, len(queueTracker.runningApplications))
@@ -168,9 +164,9 @@ func TestQTDecreaseTrackedResource(t *testing.T) {
assert.Equal(t, removeQT, true, "wrong remove queue tracker value")
// Test parent queueTracker has not zero usage, but child queueTrackers
has all deleted
- err = queueTracker.increaseTrackedResource(queuePath1, TestApp1, usage1)
- if err != nil {
- t.Fatalf("unable to increase tracked resource: queuepath %s,
app %s, res %v, error %t", queuePath1, TestApp1, usage1, err)
+ result = queueTracker.increaseTrackedResource(queuePath1, TestApp1,
user, usage1)
+ if !result {
+ t.Fatalf("unable to increase tracked resource: queuepath %s,
app %s, res %v", queuePath1, TestApp1, usage1)
}
assert.Equal(t, 1, len(queueTracker.runningApplications))
@@ -178,9 +174,79 @@ func TestQTDecreaseTrackedResource(t *testing.T) {
if err != nil {
t.Errorf("new resource create returned error or wrong resource:
error %t, res %v", err, usage2)
}
- err = queueTracker.increaseTrackedResource("root.parent", TestApp2,
usage2)
+ result = queueTracker.increaseTrackedResource("root.parent", TestApp2,
user, usage2)
+ if !result {
+ t.Fatalf("unable to increase tracked resource: queuepath %s,
app %s, res %v", "root.parent", TestApp2, usage2)
+ }
+}
+
+func TestQTQuotaEnforcement(t *testing.T) {
+ // Queue setup:
+ // root. max apps - 6 , max res - 60M, 60cores
+ // root-> parent. max apps - 5 , max res - 50M, 50cores
+ // root->parent->child1. max apps - 2 , max res - 20M, 20cores
+ // root->parent->child1->child12. config not set
+ // root->parent->child2. max apps - 2 , max res - 20M, 20cores
+ // root->parent->child12 (similar name like above leaf queue, but it is
being treated differently as similar names are allowed). config not set
+ GetUserManager()
+ queueTracker := newQueueTracker("", "root")
+
+ usage1, err := resources.NewResourceFromConf(map[string]string{"mem":
"10M", "vcore": "10"})
if err != nil {
- t.Fatalf("unable to increase tracked resource: queuepath %s,
app %s, res %v, error %t", "root.parent", TestApp2, usage2, err)
+ t.Errorf("new resource create returned error or wrong resource:
error %t, res %v", err, usage1)
+ }
+
+ queueTracker.maxResources = resources.Multiply(usage1, 6)
+ queueTracker.maxRunningApps = 6
+
+ parentQueueTracker := newQueueTracker("root", "parent")
+ parentQueueTracker.maxResources = resources.Multiply(usage1, 5)
+ parentQueueTracker.maxRunningApps = 5
+ queueTracker.childQueueTrackers["parent"] = parentQueueTracker
+
+ child1QueueTracker := newQueueTracker("root.parent", "child1")
+ child1QueueTracker.maxResources = resources.Multiply(usage1, 2)
+ child1QueueTracker.maxRunningApps = 2
+ parentQueueTracker.childQueueTrackers["child1"] = child1QueueTracker
+
+ child2QueueTracker := newQueueTracker("root.parent.child2", "child2")
+ child2QueueTracker.maxResources = resources.Multiply(usage1, 2)
+ child2QueueTracker.maxRunningApps = 2
+ parentQueueTracker.childQueueTrackers["child2"] = child2QueueTracker
+
+ result := queueTracker.increaseTrackedResource(queuePath1, TestApp1,
user, usage1)
+ if !result {
+ t.Fatalf("unable to increase tracked resource: queuepath %s,
app %s, res %v", queuePath1, TestApp1, usage1)
+ }
+
+ result = queueTracker.increaseTrackedResource(queuePath2, TestApp2,
user, usage1)
+ if !result {
+ t.Fatalf("unable to increase tracked resource: queuepath %s,
app %s, res %v", queuePath2, TestApp2, usage1)
+ }
+
+ result = queueTracker.increaseTrackedResource(queuePath2, TestApp2,
user, usage1)
+ if !result {
+ t.Fatalf("unable to increase tracked resource: queuepath %s,
app %s, res %v", queuePath2, TestApp2, usage1)
+ }
+
+ result = queueTracker.increaseTrackedResource(queuePath2, TestApp3,
user, usage1)
+ if result {
+ t.Fatalf("Increasing resource usage should fail as child2's
resource usage exceeded configured max resources limit. queuepath %s, app %s,
res %v", queuePath2, TestApp3, usage1)
+ }
+
+ result = queueTracker.increaseTrackedResource(queuePath3, TestApp3,
user, usage1)
+ if !result {
+ t.Fatalf("unable to increase tracked resource: queuepath %s,
app %s, res %v", queuePath3, TestApp3, usage1)
+ }
+
+ result = queueTracker.increaseTrackedResource(queuePath4, TestApp4,
user, usage1)
+ if !result {
+ t.Fatalf("unable to increase tracked resource: queuepath %s,
app %s, res %v", queuePath4, TestApp4, usage1)
+ }
+
+ result = queueTracker.increaseTrackedResource(queuePath4, TestApp4,
user, usage1)
+ if result {
+ t.Fatalf("Increasing resource usage should fail as parent's
resource usage exceeded configured max resources limit. queuepath %s, app %s,
res %v", queuePath4, TestApp4, usage1)
}
}
diff --git a/pkg/scheduler/ugm/tracker.go b/pkg/scheduler/ugm/tracker.go
index 85f3c56d..ac2bf7af 100644
--- a/pkg/scheduler/ugm/tracker.go
+++ b/pkg/scheduler/ugm/tracker.go
@@ -31,6 +31,6 @@ type Tracker interface {
GetUsersResources() []*UserTracker
GetGroupsResources() []*GroupTracker
- IncreaseTrackedResource(queuePath, applicationID string, usage
*resources.Resource, user security.UserGroup) error
- DecreaseTrackedResource(queuePath, applicationID string, usage
*resources.Resource, user security.UserGroup, removeApp bool) error
+ IncreaseTrackedResource(queuePath, applicationID string, usage
*resources.Resource, user security.UserGroup) bool
+ DecreaseTrackedResource(queuePath, applicationID string, usage
*resources.Resource, user security.UserGroup, removeApp bool) bool
}
diff --git a/pkg/scheduler/ugm/user_tracker.go
b/pkg/scheduler/ugm/user_tracker.go
index 85d508d8..eb95824a 100644
--- a/pkg/scheduler/ugm/user_tracker.go
+++ b/pkg/scheduler/ugm/user_tracker.go
@@ -48,13 +48,13 @@ func newUserTracker(user string) *UserTracker {
return userTracker
}
-func (ut *UserTracker) increaseTrackedResource(queuePath, applicationID
string, usage *resources.Resource) error {
+func (ut *UserTracker) increaseTrackedResource(queuePath, applicationID
string, usage *resources.Resource) bool {
ut.Lock()
defer ut.Unlock()
- return ut.queueTracker.increaseTrackedResource(queuePath,
applicationID, usage)
+ return ut.queueTracker.increaseTrackedResource(queuePath,
applicationID, user, usage)
}
-func (ut *UserTracker) decreaseTrackedResource(queuePath, applicationID
string, usage *resources.Resource, removeApp bool) (bool, error) {
+func (ut *UserTracker) decreaseTrackedResource(queuePath, applicationID
string, usage *resources.Resource, removeApp bool) (bool, bool) {
ut.Lock()
defer ut.Unlock()
if removeApp {
@@ -83,16 +83,10 @@ func (ut *UserTracker) getTrackedApplications()
map[string]*GroupTracker {
return ut.appGroupTrackers
}
-func (ut *UserTracker) setMaxApplications(count uint64, queuePath string)
error {
+func (ut *UserTracker) setLimits(queuePath string, resource
*resources.Resource, maxApps uint64) {
ut.Lock()
defer ut.Unlock()
- return ut.queueTracker.setMaxApplications(count, queuePath)
-}
-
-func (ut *UserTracker) setMaxResources(resource *resources.Resource, queuePath
string) error {
- ut.Lock()
- defer ut.Unlock()
- return ut.queueTracker.setMaxResources(resource, queuePath)
+ ut.queueTracker.setLimit(queuePath, resource, maxApps)
}
func (ut *UserTracker) GetUserResourceUsageDAOInfo()
*dao.UserResourceUsageDAOInfo {
@@ -108,3 +102,28 @@ func (ut *UserTracker) GetUserResourceUsageDAOInfo()
*dao.UserResourceUsageDAOIn
userResourceUsage.Queues = ut.queueTracker.getResourceUsageDAOInfo("")
return userResourceUsage
}
+
+func (ut *UserTracker) IsQueuePathTrackedCompletely(queuePath string) bool {
+ ut.RLock()
+ defer ut.RUnlock()
+ return ut.queueTracker.IsQueuePathTrackedCompletely(queuePath)
+}
+
+func (ut *UserTracker) IsUnlinkRequired(queuePath string) bool {
+ ut.RLock()
+ defer ut.RUnlock()
+ return ut.queueTracker.IsUnlinkRequired(queuePath)
+}
+
+func (ut *UserTracker) UnlinkQT(queuePath string) bool {
+ ut.RLock()
+ defer ut.RUnlock()
+ return ut.queueTracker.UnlinkQT(queuePath)
+}
+
+// canBeRemoved Does "root" queue has any child queue trackers? Is there any
running applications in "root" qt?
+func (ut *UserTracker) canBeRemoved() bool {
+ ut.RLock()
+ defer ut.RUnlock()
+ return len(ut.queueTracker.childQueueTrackers) == 0 &&
len(ut.queueTracker.runningApplications) == 0
+}
diff --git a/pkg/scheduler/ugm/user_tracker_test.go
b/pkg/scheduler/ugm/user_tracker_test.go
index d8e5485d..bf9cc143 100644
--- a/pkg/scheduler/ugm/user_tracker_test.go
+++ b/pkg/scheduler/ugm/user_tracker_test.go
@@ -50,9 +50,9 @@ func TestIncreaseTrackedResource(t *testing.T) {
if err != nil {
t.Errorf("new resource create returned error or wrong resource:
error %t, res %v", err, usage1)
}
- err = userTracker.increaseTrackedResource(queuePath1, TestApp1, usage1)
- if err != nil {
- t.Fatalf("unable to increase tracked resource: queuepath %s,
app %s, res %v, error %t", queuePath1, TestApp1, usage1, err)
+ result := userTracker.increaseTrackedResource(queuePath1, TestApp1,
usage1)
+ if !result {
+ t.Fatalf("unable to increase tracked resource: queuepath %s,
app %s, res %v", queuePath1, TestApp1, usage1)
}
groupTracker := newGroupTracker(user.User)
userTracker.setGroupForApp(TestApp1, groupTracker)
@@ -61,8 +61,8 @@ func TestIncreaseTrackedResource(t *testing.T) {
if err != nil {
t.Errorf("new resource create returned error or wrong resource:
error %t, res %v", err, usage2)
}
- err = userTracker.increaseTrackedResource(queuePath2, TestApp2, usage2)
- if err != nil {
+ result = userTracker.increaseTrackedResource(queuePath2, TestApp2,
usage2)
+ if !result {
t.Fatalf("unable to increase tracked resource: queuepath %s,
app %s, res %v, error %t", queuePath2, TestApp2, usage2, err)
}
userTracker.setGroupForApp(TestApp2, groupTracker)
@@ -71,8 +71,8 @@ func TestIncreaseTrackedResource(t *testing.T) {
if err != nil {
t.Errorf("new resource create returned error or wrong resource:
error %t, res %v", err, usage3)
}
- err = userTracker.increaseTrackedResource(queuePath3, TestApp3, usage3)
- if err != nil {
+ result = userTracker.increaseTrackedResource(queuePath3, TestApp3,
usage3)
+ if !result {
t.Fatalf("unable to increase tracked resource: queuepath %s,
app %s, res %v, error %t", queuePath3, TestApp3, usage3, err)
}
userTracker.setGroupForApp(TestApp3, groupTracker)
@@ -81,8 +81,8 @@ func TestIncreaseTrackedResource(t *testing.T) {
if err != nil {
t.Errorf("new resource create returned error or wrong resource:
error %t, res %v", err, usage3)
}
- err = userTracker.increaseTrackedResource(queuePath4, TestApp4, usage4)
- if err != nil {
+ result = userTracker.increaseTrackedResource(queuePath4, TestApp4,
usage4)
+ if !result {
t.Fatalf("unable to increase tracked resource: queuepath %s,
app %s, res %v, error %t", queuePath4, TestApp4, usage4, err)
}
userTracker.setGroupForApp(TestApp4, groupTracker)
@@ -111,8 +111,8 @@ func TestDecreaseTrackedResource(t *testing.T) {
if err != nil {
t.Errorf("new resource create returned error or wrong resource:
error %t, res %v", err, usage1)
}
- err = userTracker.increaseTrackedResource(queuePath1, TestApp1, usage1)
- if err != nil {
+ result := userTracker.increaseTrackedResource(queuePath1, TestApp1,
usage1)
+ if !result {
t.Fatalf("unable to increase tracked resource: queuepath %s,
app %s, res %v, error %t", queuePath1, TestApp1, usage1, err)
}
groupTracker := newGroupTracker(user.User)
@@ -123,8 +123,8 @@ func TestDecreaseTrackedResource(t *testing.T) {
if err != nil {
t.Errorf("new resource create returned error or wrong resource:
error %t, res %v", err, usage2)
}
- err = userTracker.increaseTrackedResource(queuePath2, TestApp2, usage2)
- if err != nil {
+ result = userTracker.increaseTrackedResource(queuePath2, TestApp2,
usage2)
+ if !result {
t.Fatalf("unable to increase tracked resource: queuepath %s,
app %s, res %v, error %t", queuePath2, TestApp2, usage2, err)
}
userTracker.setGroupForApp(TestApp2, groupTracker)
@@ -140,14 +140,14 @@ func TestDecreaseTrackedResource(t *testing.T) {
if err != nil {
t.Errorf("new resource create returned error or wrong resource:
error %t, res %v", err, usage3)
}
- removeQT, err := userTracker.decreaseTrackedResource(queuePath1,
TestApp1, usage3, false)
- if err != nil {
+ removeQT, decreased := userTracker.decreaseTrackedResource(queuePath1,
TestApp1, usage3, false)
+ if !decreased {
t.Fatalf("unable to decrease tracked resource: queuepath %s,
app %s, res %v, error %t", queuePath1, TestApp1, usage3, err)
}
assert.Equal(t, removeQT, false, "wrong remove queue tracker value")
- removeQT, err = userTracker.decreaseTrackedResource(queuePath2,
TestApp2, usage3, false)
- if err != nil {
+ removeQT, decreased = userTracker.decreaseTrackedResource(queuePath2,
TestApp2, usage3, false)
+ if !decreased {
t.Fatalf("unable to decrease tracked resource: queuepath %s,
app %s, res %v, error %t", queuePath2, TestApp2, usage3, err)
}
actualResources1 := getUserResource(userTracker)
@@ -163,8 +163,8 @@ func TestDecreaseTrackedResource(t *testing.T) {
t.Errorf("new resource create returned error or wrong resource:
error %t, res %v", err, usage3)
}
- removeQT, err = userTracker.decreaseTrackedResource(queuePath1,
TestApp1, usage4, true)
- if err != nil {
+ removeQT, decreased = userTracker.decreaseTrackedResource(queuePath1,
TestApp1, usage4, true)
+ if !decreased {
t.Fatalf("unable to increase tracked resource: queuepath %s,
app %s, res %v, error %t", queuePath1, TestApp1, usage1, err)
}
assert.Equal(t, 1, len(userTracker.getTrackedApplications()))
@@ -174,8 +174,8 @@ func TestDecreaseTrackedResource(t *testing.T) {
if err != nil {
t.Errorf("new resource create returned error or wrong resource:
error %t, res %v", err, usage5)
}
- removeQT, err = userTracker.decreaseTrackedResource(queuePath2,
TestApp2, usage5, true)
- if err != nil {
+ removeQT, decreased = userTracker.decreaseTrackedResource(queuePath2,
TestApp2, usage5, true)
+ if !decreased {
t.Fatalf("unable to increase tracked resource: queuepath %s,
app %s, res %v, error %t", queuePath2, TestApp2, usage2, err)
}
assert.Equal(t, 0, len(userTracker.getTrackedApplications()))
@@ -191,41 +191,25 @@ func TestSetMaxLimits(t *testing.T) {
if err != nil {
t.Errorf("new resource create returned error or wrong resource:
error %t, res %v", err, usage1)
}
- err = userTracker.increaseTrackedResource(queuePath1, TestApp1, usage1)
- if err != nil {
+ result := userTracker.increaseTrackedResource(queuePath1, TestApp1,
usage1)
+ if !result {
t.Fatalf("unable to increase tracked resource: queuepath %s,
app %s, res %v, error %t", queuePath1, TestApp1, usage1, err)
}
- groupTracker := newGroupTracker(user.User)
- userTracker.setGroupForApp(TestApp1, groupTracker)
-
- setMaxAppsErr := userTracker.setMaxApplications(1, queuePath1)
- assert.NilError(t, setMaxAppsErr)
- setMaxResourcesErr := userTracker.setMaxResources(usage1, queuePath1)
- assert.NilError(t, setMaxResourcesErr)
+ userTracker.setLimits(queuePath1, resources.Multiply(usage1, 5), 5)
+ userTracker.setLimits("root.parent", resources.Multiply(usage1, 10), 10)
- setParentMaxAppsErr := userTracker.setMaxApplications(1, "root.parent")
- assert.NilError(t, setParentMaxAppsErr)
-
- setParentMaxResourcesErr := userTracker.setMaxResources(usage1,
"root.parent")
- assert.NilError(t, setParentMaxResourcesErr)
-
- err = userTracker.increaseTrackedResource(queuePath1, TestApp2, usage1)
- if err != nil {
- t.Fatalf("unable to increase tracked resource: queuepath %s,
app %s, res %v, error %t", queuePath1, TestApp1, usage1, err)
+ result = userTracker.increaseTrackedResource(queuePath1, TestApp1,
usage1)
+ if !result {
+ t.Fatalf("unable to increase tracked resource: queuepath %s,
app %s, res %v", queuePath1, TestApp1, usage1)
}
- setMaxAppsErr1 := userTracker.setMaxApplications(1, queuePath1)
- assert.Error(t, setMaxAppsErr1, "current running applications is
greater than config max applications for "+queuePath1)
-
- setMaxResourcesErr1 := userTracker.setMaxResources(usage1, queuePath1)
- assert.Error(t, setMaxResourcesErr1, "current resource usage is greater
than config max resource for "+queuePath1)
-
- setParentMaxAppsErr1 := userTracker.setMaxApplications(1, "root.parent")
- assert.Error(t, setParentMaxAppsErr1, "current running applications is
greater than config max applications for root.parent")
-
- setParentMaxResourcesErr1 := userTracker.setMaxResources(usage1,
"root.parent")
- assert.Error(t, setParentMaxResourcesErr1, "current resource usage is
greater than config max resource for root.parent")
+ result = userTracker.increaseTrackedResource(queuePath1, TestApp2,
usage1)
+ if !result {
+ t.Fatalf("unable to increase tracked resource: queuepath %s,
app %s, res %v", queuePath1, TestApp2, usage1)
+ }
+ userTracker.setLimits(queuePath1, usage1, 1)
+ userTracker.setLimits("root.parent", usage1, 1)
}
func getUserResource(ut *UserTracker) map[string]*resources.Resource {
diff --git a/pkg/scheduler/utilities_test.go b/pkg/scheduler/utilities_test.go
index 99daf94e..3233c61d 100644
--- a/pkg/scheduler/utilities_test.go
+++ b/pkg/scheduler/utilities_test.go
@@ -80,7 +80,7 @@ func newBasePartition() (*PartitionContext, error) {
"memory": "5",
"vcores": "5",
},
-
MaxApplications: 1,
+
MaxApplications: 8,
},
},
},
@@ -98,7 +98,7 @@ func newBasePartition() (*PartitionContext, error) {
"memory": "10",
"vcores": "10",
},
- MaxApplications: 2,
+ MaxApplications: 10,
},
},
},
@@ -179,7 +179,7 @@ func newConfiguredPartition() (*PartitionContext, error) {
"memory": "5",
"vcores": "5",
},
-
MaxApplications: 2,
+
MaxApplications: 8,
},
},
},
@@ -197,7 +197,7 @@ func newConfiguredPartition() (*PartitionContext, error) {
"memory": "10",
"vcores": "10",
},
- MaxApplications: 2,
+ MaxApplications: 10,
},
},
},
@@ -246,7 +246,7 @@ func newPreemptionConfiguredPartition(parentLimit
map[string]string, leafGuarant
"memory": "5",
"vcores": "5",
},
-
MaxApplications: 1,
+
MaxApplications: 8,
},
},
},
@@ -271,7 +271,7 @@ func newPreemptionConfiguredPartition(parentLimit
map[string]string, leafGuarant
"memory": "5",
"vcores": "5",
},
-
MaxApplications: 1,
+
MaxApplications: 6,
},
},
},
@@ -289,7 +289,7 @@ func newPreemptionConfiguredPartition(parentLimit
map[string]string, leafGuarant
"memory": "5",
"vcores": "5",
},
-
MaxApplications: 2,
+
MaxApplications: 8,
},
},
},
@@ -307,7 +307,7 @@ func newPreemptionConfiguredPartition(parentLimit
map[string]string, leafGuarant
"memory": "10",
"vcores": "10",
},
- MaxApplications: 2,
+ MaxApplications: 10,
},
},
},
@@ -592,8 +592,8 @@ func assertLimits(t *testing.T, userGroup
security.UserGroup, expected *resource
expectedQueuesMaxLimits["root.default"] = make(map[string]interface{})
expectedQueuesMaxLimits["root"][maxresources] =
resources.NewResourceFromMap(map[string]resources.Quantity{"memory": 10,
"vcores": 10})
expectedQueuesMaxLimits["root.default"][maxresources] =
resources.NewResourceFromMap(map[string]resources.Quantity{"memory": 5,
"vcores": 5})
- expectedQueuesMaxLimits["root"][maxapplications] = uint64(2)
- expectedQueuesMaxLimits["root.default"][maxapplications] = uint64(1)
+ expectedQueuesMaxLimits["root"][maxapplications] = uint64(10)
+ expectedQueuesMaxLimits["root.default"][maxapplications] = uint64(8)
assertUserGroupResourceMaxLimits(t, userGroup, expected,
expectedQueuesMaxLimits)
}
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]