This is an automated email from the ASF dual-hosted git repository.

wilfreds 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 418714df [YUNIKORN-1973] Queue Limits level checks (#646)
418714df is described below

commit 418714df43c8f22fa58227223b4e0279c943cf86
Author: Manikandan R <[email protected]>
AuthorDate: Thu Sep 21 18:17:48 2023 +1000

    [YUNIKORN-1973] Queue Limits level checks (#646)
    
    The configuration for a limit set on sibling queues should not interact
    with any queue but the parent and its own children.
    Change the internal structure to take the full path into account.
    
    Closes: #646
    
    Signed-off-by: Wilfred Spiegelenburg <[email protected]>
---
 pkg/common/configs/config_test.go          |   4 +-
 pkg/common/configs/configvalidator.go      | 187 +++++++++++--------
 pkg/common/configs/configvalidator_test.go | 287 +++++++++++++----------------
 pkg/webservice/handlers_test.go            |  95 ++++++++++
 4 files changed, 333 insertions(+), 240 deletions(-)

diff --git a/pkg/common/configs/config_test.go 
b/pkg/common/configs/config_test.go
index ef0fa645..5e4ddf4b 100644
--- a/pkg/common/configs/config_test.go
+++ b/pkg/common/configs/config_test.go
@@ -1037,7 +1037,7 @@ partitions:
        _, err := CreateConfig(data)
        assert.ErrorContains(t, err, "invalid MaxApplications settings for 
limit")
 
-       // Make sure limit max apps not set, but queue limit set, will fail.
+       // Make sure limit max apps not set, but queue limit set. will not fail.
        data = `
 partitions:
   - name: default
@@ -1071,7 +1071,7 @@ partitions:
 `
        // validate the config and check after the update
        _, err = CreateConfig(data)
-       assert.ErrorContains(t, err, "MaxApplications is 0")
+       assert.NilError(t, err, "No error should be thrown even when queue 
maxapps is set but not for user or group")
 
        // Make sure limit max apps set, but queue limit not set, will not fail.
        data = `
diff --git a/pkg/common/configs/configvalidator.go 
b/pkg/common/configs/configvalidator.go
index 7bab772a..571e37b4 100644
--- a/pkg/common/configs/configvalidator.go
+++ b/pkg/common/configs/configvalidator.go
@@ -140,57 +140,70 @@ func checkQueueResource(cur QueueConfig, parentM 
*resources.Resource) (*resource
        return curG, nil
 }
 
-func checkLimitResource(cur QueueConfig, parent *QueueConfig, users 
map[string]*resources.Resource, groups map[string]*resources.Resource) error {
-       // Collect user and group limits of parent queue
-       if parent != nil {
-               for _, limit := range parent.Limits {
-                       parentLimitMaxResources, err := 
resources.NewResourceFromConf(limit.MaxResources)
+func checkLimitResource(cur QueueConfig, users 
map[string]map[string]*resources.Resource, groups 
map[string]map[string]*resources.Resource, queuePath string) error {
+       var curQueuePath string
+       if cur.Name == RootQueue {
+               curQueuePath = RootQueue
+       } else {
+               curQueuePath = queuePath + DOT + cur.Name
+       }
+
+       // Carry forward (populate) the parent limit settings to the next level 
if limits are not configured for the current queue
+       if len(cur.Limits) == 0 {
+               if _, ok := users[queuePath]; ok {
+                       users[curQueuePath] = users[queuePath]
+               }
+               if _, ok := groups[queuePath]; ok {
+                       groups[curQueuePath] = groups[queuePath]
+               }
+       } else {
+               // compare user & group limit setting between the current queue 
and parent queue
+               for _, limit := range cur.Limits {
+                       limitMaxResources, err := 
resources.NewResourceFromConf(limit.MaxResources)
                        if err != nil {
                                return err
                        }
                        for _, user := range limit.Users {
-                               users[user] = parentLimitMaxResources
-                       }
-                       for _, group := range limit.Groups {
-                               groups[group] = parentLimitMaxResources
-                       }
-               }
-       }
-
-       // compare user & group limit setting between the current queue and 
parent queue
-       for _, limit := range cur.Limits {
-               limitMaxResources, err := 
resources.NewResourceFromConf(limit.MaxResources)
-               if err != nil {
-                       return err
-               }
-               for _, user := range limit.Users {
-                       // Is user limit setting exists?
-                       if userMaxResource, ok := users[user]; ok {
-                               if 
!userMaxResource.FitInMaxUndef(limitMaxResources) {
-                                       return fmt.Errorf("user %s max resource 
%s of queue %s is greater than immediate or ancestor parent maximum resource 
%s", user, limitMaxResources.String(), cur.Name, userMaxResource.String())
+                               // Is user limit setting exists?
+                               if userMaxResource, ok := 
users[queuePath][user]; ok {
+                                       if 
!userMaxResource.FitInMaxUndef(limitMaxResources) {
+                                               return fmt.Errorf("user %s max 
resource %s of queue %s is greater than immediate or ancestor parent maximum 
resource %s", user, limitMaxResources.String(), cur.Name, 
userMaxResource.String())
+                                       }
+                                       // Override with min resource
+                                       if _, ok := users[curQueuePath]; !ok {
+                                               users[curQueuePath] = 
make(map[string]*resources.Resource)
+                                       }
+                                       users[curQueuePath][user] = 
resources.ComponentWiseMinPermissive(limitMaxResources, userMaxResource)
+                               } else {
+                                       if _, ok := users[curQueuePath]; !ok {
+                                               users[curQueuePath] = 
make(map[string]*resources.Resource)
+                                       }
+                                       users[curQueuePath][user] = 
limitMaxResources
                                }
-                               // Override with min resource
-                               users[user] = 
resources.ComponentWiseMinPermissive(limitMaxResources, userMaxResource)
-                       } else {
-                               users[user] = limitMaxResources
                        }
-               }
-               for _, group := range limit.Groups {
-                       // Is group limit setting exists?
-                       if groupMaxResource, ok := groups[group]; ok {
-                               if 
!groupMaxResource.FitInMaxUndef(limitMaxResources) {
-                                       return fmt.Errorf("group %s max 
resource %s of queue %s is greater than immediate or ancestor parent maximum 
resource %s", group, limitMaxResources.String(), cur.Name, 
groupMaxResource.String())
+                       for _, group := range limit.Groups {
+                               // Is group limit setting exists?
+                               if groupMaxResource, ok := 
groups[queuePath][group]; ok {
+                                       if 
!groupMaxResource.FitInMaxUndef(limitMaxResources) {
+                                               return fmt.Errorf("group %s max 
resource %s of queue %s is greater than immediate or ancestor parent maximum 
resource %s", group, limitMaxResources.String(), cur.Name, 
groupMaxResource.String())
+                                       }
+                                       // Override with min resource
+                                       if _, ok := groups[curQueuePath]; !ok {
+                                               groups[curQueuePath] = 
make(map[string]*resources.Resource)
+                                       }
+                                       groups[curQueuePath][group] = 
resources.ComponentWiseMinPermissive(limitMaxResources, groupMaxResource)
+                               } else {
+                                       if _, ok := groups[curQueuePath]; !ok {
+                                               groups[curQueuePath] = 
make(map[string]*resources.Resource)
+                                       }
+                                       groups[curQueuePath][group] = 
limitMaxResources
                                }
-                               // Override with min resource
-                               groups[group] = 
resources.ComponentWiseMinPermissive(limitMaxResources, groupMaxResource)
-                       } else {
-                               groups[group] = limitMaxResources
                        }
                }
        }
        // traverse child queues
        for _, child := range cur.Queues {
-               err := checkLimitResource(child, &cur, users, groups)
+               err := checkLimitResource(child, users, groups, curQueuePath)
                if err != nil {
                        return err
                }
@@ -212,49 +225,68 @@ func checkQueueMaxApplications(cur QueueConfig) error {
        return nil
 }
 
-func checkLimitMaxApplications(cur QueueConfig, parent *QueueConfig, users 
map[string]uint64, groups map[string]uint64) error {
-       // Collect user and group limits of parent queue
-       if parent != nil {
-               for _, limit := range parent.Limits {
-                       parentLimitMaxApplications := limit.MaxApplications
-                       for _, user := range limit.Users {
-                               users[user] = parentLimitMaxApplications
-                       }
-                       for _, group := range limit.Groups {
-                               groups[group] = parentLimitMaxApplications
-                       }
-               }
+func checkLimitMaxApplications(cur QueueConfig, users 
map[string]map[string]uint64, groups map[string]map[string]uint64, queuePath 
string) error {
+       var curQueuePath string
+       if cur.Name == RootQueue {
+               curQueuePath = RootQueue
+       } else {
+               curQueuePath = queuePath + DOT + cur.Name
        }
 
-       // compare user & group limit setting between the current queue and 
parent queue
-       for _, limit := range cur.Limits {
-               limitMaxApplications := limit.MaxApplications
-               for _, user := range limit.Users {
-                       // Is user limit setting exists?
-                       if userMaxApplications, ok := users[user]; ok {
-                               if userMaxApplications != 0 && 
(userMaxApplications < limitMaxApplications || limitMaxApplications == 0) {
-                                       return fmt.Errorf("user %s max 
applications %d of queue %s is greater than immediate or ancestor parent max 
applications %d", user, limitMaxApplications, cur.Name, userMaxApplications)
+       // Carry forward (populate) the parent limit settings to the next level 
if limits are not configured for the current queue
+       if len(cur.Limits) == 0 {
+               if _, ok := users[queuePath]; ok {
+                       users[curQueuePath] = users[queuePath]
+               }
+               if _, ok := groups[queuePath]; ok {
+                       groups[curQueuePath] = groups[queuePath]
+               }
+       } else {
+               // compare user & group limit setting between the current queue 
and parent queue
+               for _, limit := range cur.Limits {
+                       limitMaxApplications := limit.MaxApplications
+                       for _, user := range limit.Users {
+                               // Is user limit setting exists?
+                               if userMaxApplications, ok := 
users[queuePath][user]; ok {
+                                       if userMaxApplications != 0 && 
(userMaxApplications < limitMaxApplications || limitMaxApplications == 0) {
+                                               return fmt.Errorf("user %s max 
applications %d of queue %s is greater than immediate or ancestor parent max 
applications %d", user, limitMaxApplications, cur.Name, userMaxApplications)
+                                       }
+                                       // Override with min resource
+                                       if _, ok := users[curQueuePath]; !ok {
+                                               users[curQueuePath] = 
make(map[string]uint64)
+                                       }
+                                       users[curQueuePath][user] = 
common.Min(limitMaxApplications, userMaxApplications)
+                               } else {
+                                       if _, ok := users[curQueuePath]; !ok {
+                                               users[curQueuePath] = 
make(map[string]uint64)
+                                       }
+                                       users[curQueuePath][user] = 
limitMaxApplications
                                }
-                               users[user] = common.Min(limitMaxApplications, 
userMaxApplications)
-                       } else {
-                               users[user] = limitMaxApplications
                        }
-               }
-               for _, group := range limit.Groups {
-                       // Is group limit setting exists?
-                       if groupMaxApplications, ok := groups[group]; ok {
-                               if groupMaxApplications != 0 && 
(groupMaxApplications < limitMaxApplications || limitMaxApplications == 0) {
-                                       return fmt.Errorf("group %s max 
applications %d of queue %s is greater than immediate or ancestor parent max 
applications %d", group, limitMaxApplications, cur.Name, groupMaxApplications)
+
+                       for _, group := range limit.Groups {
+                               // Is user limit setting exists?
+                               if groupMaxApplications, ok := 
groups[queuePath][group]; ok {
+                                       if groupMaxApplications != 0 && 
(groupMaxApplications < limitMaxApplications || limitMaxApplications == 0) {
+                                               return fmt.Errorf("group %s max 
applications %d of queue %s is greater than immediate or ancestor parent max 
applications %d", group, limitMaxApplications, cur.Name, groupMaxApplications)
+                                       }
+                                       // Override with min resource
+                                       if _, ok := groups[curQueuePath]; !ok {
+                                               groups[curQueuePath] = 
make(map[string]uint64)
+                                       }
+                                       groups[curQueuePath][group] = 
common.Min(limitMaxApplications, groupMaxApplications)
+                               } else {
+                                       if _, ok := groups[curQueuePath]; !ok {
+                                               groups[curQueuePath] = 
make(map[string]uint64)
+                                       }
+                                       groups[curQueuePath][group] = 
limitMaxApplications
                                }
-                               groups[group] = 
common.Min(limitMaxApplications, groupMaxApplications)
-                       } else {
-                               groups[group] = limitMaxApplications
                        }
                }
        }
        // traverse child queues
        for _, child := range cur.Queues {
-               err := checkLimitMaxApplications(child, &cur, users, groups)
+               err := checkLimitMaxApplications(child, users, groups, 
curQueuePath)
                if err != nil {
                        return err
                }
@@ -514,14 +546,10 @@ func checkLimit(limit Limit, existedUserName 
map[string]bool, existedGroupName m
                }
        }
        // at least some resource should be not null
-       if limit.MaxApplications == 0 && resources.IsZero(limitResource) {
+       if limit.MaxApplications == 0 && len(limit.MaxResources) == 0 {
                return fmt.Errorf("invalid resource combination for limit %s 
all resource limits are null", limit.Limit)
        }
 
-       if limit.MaxApplications == 0 {
-               return fmt.Errorf("MaxApplications is 0 in '%s' limit name, it 
should be between 1 - %d", limit.Limit, queue.MaxApplications)
-       }
-
        if queue.MaxApplications != 0 && queue.MaxApplications < 
limit.MaxApplications {
                return fmt.Errorf("invalid MaxApplications settings for limit 
%s exceed current the queue MaxApplications", limit.Limit)
        }
@@ -759,10 +787,11 @@ func Validate(newConfig *SchedulerConfig) error {
                        return err
                }
 
-               if err = checkLimitResource(partition.Queues[0], nil, 
make(map[string]*resources.Resource), make(map[string]*resources.Resource)); 
err != nil {
+               if err = checkLimitResource(partition.Queues[0], 
make(map[string]map[string]*resources.Resource), 
make(map[string]map[string]*resources.Resource), common.Empty); err != nil {
                        return err
                }
-               if err = checkLimitMaxApplications(partition.Queues[0], nil, 
make(map[string]uint64), make(map[string]uint64)); err != nil {
+
+               if err = checkLimitMaxApplications(partition.Queues[0], 
make(map[string]map[string]uint64), make(map[string]map[string]uint64), 
common.Empty); err != nil {
                        return err
                }
                // write back the partition to keep changes
diff --git a/pkg/common/configs/configvalidator_test.go 
b/pkg/common/configs/configvalidator_test.go
index c89b4563..05f2ad7d 100644
--- a/pkg/common/configs/configvalidator_test.go
+++ b/pkg/common/configs/configvalidator_test.go
@@ -24,6 +24,7 @@ import (
 
        "gotest.tools/v3/assert"
 
+       "github.com/apache/yunikorn-core/pkg/common"
        "github.com/apache/yunikorn-core/pkg/common/resources"
 )
 
@@ -744,51 +745,47 @@ func TestCheckLimitResource(t *testing.T) { 
//nolint:funlen
                hasError bool
        }{
                {
-                       name: "leaf queue user group maxresoruces are within 
parent queue user group maxresources",
+                       name: "leaf queue user group maxresources are within 
immediate parent queue user group maxresources",
                        config: QueueConfig{
                                Name: "parent",
-                               Limits: []Limit{
-                                       {
-                                               Limit:        "user-limit",
-                                               Users:        
[]string{"test-user"},
-                                               MaxResources: 
map[string]string{"memory": "100"},
-                                       },
+                               Limits: 
createLimitMaxResources(map[string]map[string]string{"test-user": {"memory": 
"100"}},
+                                       
map[string]map[string]string{"test-group": {"memory": "100"}}),
+                               Queues: []QueueConfig{
                                        {
-                                               Limit:        "group-limit",
-                                               Groups:       
[]string{"test-group"},
-                                               MaxResources: 
map[string]string{"memory": "100"},
+                                               Name: "child1",
+                                               Limits: 
createLimitMaxResources(map[string]map[string]string{"test-user": {"memory": 
"50"}},
+                                                       
map[string]map[string]string{"test-group": {"memory": "50"}}),
+                                               Queues: []QueueConfig{
+                                                       {
+                                                               Name: "child2",
+                                                               Limits: 
createLimitMaxResources(map[string]map[string]string{"test-user": {"memory": 
"10"}},
+                                                                       
map[string]map[string]string{"test-group": {"memory": "10"}}),
+                                                       },
+                                               },
                                        },
                                },
+                       },
+                       hasError: false,
+               },
+               {
+                       name: "leaf queue user group maxresources are within 
ancestor parent queue user group maxresources",
+                       config: QueueConfig{
+                               Name: "parent",
+                               Limits: 
createLimitMaxResources(map[string]map[string]string{"test-user": {"memory": 
"100"}},
+                                       
map[string]map[string]string{"test-group": {"memory": "100"}}),
                                Queues: []QueueConfig{
                                        {
                                                Name: "child1",
-                                               Limits: []Limit{
+                                               Queues: []QueueConfig{
                                                        {
-                                                               Limit:        
"user-limit",
-                                                               Users:        
[]string{"test-user"},
-                                                               MaxResources: 
map[string]string{"memory": "50"},
+                                                               Name: "childA",
+                                                               Limits: 
createLimitMaxResources(map[string]map[string]string{"test-user": {"memory": 
"50"}},
+                                                                       
map[string]map[string]string{"test-group": {"memory": "50"}}),
                                                        },
                                                        {
-                                                               Limit:        
"group-limit",
-                                                               Groups:       
[]string{"test-group"},
-                                                               MaxResources: 
map[string]string{"memory": "50"},
-                                                       },
-                                               },
-                                               Queues: []QueueConfig{
-                                                       {
-                                                               Name: "child2",
-                                                               Limits: []Limit{
-                                                                       {
-                                                                               
Limit:        "user-limit",
-                                                                               
Users:        []string{"test-user"},
-                                                                               
MaxResources: map[string]string{"memory": "10"},
-                                                                       },
-                                                                       {
-                                                                               
Limit:        "group-limit",
-                                                                               
Groups:       []string{"test-group"},
-                                                                               
MaxResources: map[string]string{"memory": "10"},
-                                                                       },
-                                                               },
+                                                               Name: "childB",
+                                                               Limits: 
createLimitMaxResources(map[string]map[string]string{"test-user": {"memory": 
"10"}},
+                                                                       
map[string]map[string]string{"test-group": {"memory": "10"}}),
                                                        },
                                                },
                                        },
@@ -800,79 +797,86 @@ func TestCheckLimitResource(t *testing.T) { 
//nolint:funlen
                        name: "leaf queue user maxresources exceed parent queue 
user maxresources",
                        config: QueueConfig{
                                Name: "parent",
-                               Limits: []Limit{
-                                       {
-                                               Limit:        "user-limit",
-                                               Users:        
[]string{"test-user"},
-                                               MaxResources: 
map[string]string{"memory": "100"},
-                                       },
+                               Limits: 
createLimitMaxResources(map[string]map[string]string{"test-user": {"memory": 
"100"}},
+                                       
map[string]map[string]string{"test-group": {"memory": "100"}}),
+                               Queues: []QueueConfig{
                                        {
-                                               Limit:        "group-limit",
-                                               Groups:       
[]string{"test-group"},
-                                               MaxResources: 
map[string]string{"memory": "100"},
+                                               Name: "child1",
+                                               Limits: 
createLimitMaxResources(map[string]map[string]string{"test-user": {"memory": 
"200"}},
+                                                       
map[string]map[string]string{"test-group": {"memory": "50"}}),
                                        },
                                },
+                       },
+                       hasError: true,
+               },
+               {
+                       name: "leaf queue group maxresources exceed parent 
queue group maxresources",
+                       config: QueueConfig{
+                               Name: "parent",
+                               Limits: 
createLimitMaxResources(map[string]map[string]string{"test-user": {"memory": 
"100"}},
+                                       
map[string]map[string]string{"test-group": {"memory": "100"}}),
                                Queues: []QueueConfig{
                                        {
                                                Name: "child1",
-                                               Limits: []Limit{
-                                                       {
-                                                               Limit:        
"user-limit",
-                                                               Users:        
[]string{"test-user"},
-                                                               MaxResources: 
map[string]string{"memory": "200"},
-                                                       },
-                                                       {
-                                                               Limit:        
"group-limit",
-                                                               Groups:       
[]string{"test-group"},
-                                                               MaxResources: 
map[string]string{"memory": "50"},
-                                                       },
-                                               },
+                                               Limits: 
createLimitMaxResources(map[string]map[string]string{"test-user": {"memory": 
"50"}},
+                                                       
map[string]map[string]string{"test-group": {"memory": "200"}}),
                                        },
                                },
                        },
                        hasError: true,
                },
                {
-                       name: "leaf queue group maxresources exceed parent 
queue group maxresources",
+                       name: "queues at same level maxresources can be greater 
or less than or equal to the other but with in immediate parent",
                        config: QueueConfig{
                                Name: "parent",
-                               Limits: []Limit{
+                               Limits: 
createLimitMaxResources(map[string]map[string]string{"test-user": {"memory": 
"100"}},
+                                       
map[string]map[string]string{"test-group": {"memory": "100"}}),
+                               Queues: []QueueConfig{
                                        {
-                                               Limit:        "user-limit",
-                                               Users:        
[]string{"test-user"},
-                                               MaxResources: 
map[string]string{"memory": "100"},
+                                               Name: "child1",
+                                               Limits: 
createLimitMaxResources(map[string]map[string]string{"test-user": {"memory": 
"50"}},
+                                                       
map[string]map[string]string{"test-group": {"memory": "50"}}),
                                        },
                                        {
-                                               Limit:        "group-limit",
-                                               Groups:       
[]string{"test-group"},
-                                               MaxResources: 
map[string]string{"memory": "100"},
+                                               Name: "child2",
+                                               Limits: 
createLimitMaxResources(map[string]map[string]string{"test-user": {"memory": 
"60"}},
+                                                       
map[string]map[string]string{"test-group": {"memory": "60"}}),
                                        },
                                },
+                       },
+                       hasError: false,
+               },
+               {
+                       name: "queues at same level maxresources can be greater 
or less than or equal to the other but with in ancestor parent",
+                       config: QueueConfig{
+                               Name: "parent",
+                               Limits: 
createLimitMaxResources(map[string]map[string]string{"test-user": {"memory": 
"100"}},
+                                       
map[string]map[string]string{"test-group": {"memory": "100"}}),
                                Queues: []QueueConfig{
                                        {
                                                Name: "child1",
-                                               Limits: []Limit{
+                                               Queues: []QueueConfig{
                                                        {
-                                                               Limit:        
"user-limit",
-                                                               Users:        
[]string{"test-user"},
-                                                               MaxResources: 
map[string]string{"memory": "50"},
+                                                               Name: "childA",
+                                                               Limits: 
createLimitMaxResources(map[string]map[string]string{"test-user": {"memory": 
"50"}},
+                                                                       
map[string]map[string]string{"test-group": {"memory": "50"}}),
                                                        },
                                                        {
-                                                               Limit:        
"group-limit",
-                                                               Groups:       
[]string{"test-group"},
-                                                               MaxResources: 
map[string]string{"memory": "200"},
+                                                               Name: "childB",
+                                                               Limits: 
createLimitMaxResources(map[string]map[string]string{"test-user": {"memory": 
"60"}},
+                                                                       
map[string]map[string]string{"test-group": {"memory": "60"}}),
                                                        },
                                                },
                                        },
                                },
                        },
-                       hasError: true,
+                       hasError: false,
                },
        }
 
        for _, testCase := range testCases {
                t.Run(testCase.name, func(t *testing.T) {
-                       err := checkLimitResource(testCase.config, nil, 
make(map[string]*resources.Resource), make(map[string]*resources.Resource))
+                       err := checkLimitResource(testCase.config, 
make(map[string]map[string]*resources.Resource), 
make(map[string]map[string]*resources.Resource), common.Empty)
                        if testCase.hasError {
                                assert.ErrorContains(t, err, "is greater than 
immediate or ancestor parent maximum resource")
                        } else {
@@ -882,6 +886,41 @@ func TestCheckLimitResource(t *testing.T) { //nolint:funlen
        }
 }
 
+func createLimitMaxResources(users map[string]map[string]string, groups 
map[string]map[string]string) []Limit {
+       var limits []Limit
+       for user, limit := range users {
+               var users []string
+               users = append(users, user)
+               limit := Limit{Limit: "user-limit", Users: users, MaxResources: 
limit}
+               limits = append(limits, limit)
+       }
+       for group, limit := range groups {
+               var groups []string
+               groups = append(groups, group)
+               limit := Limit{Limit: "group-limit", Groups: groups, 
MaxResources: limit}
+               limits = append(limits, limit)
+       }
+       return limits
+}
+
+func createLimitMaxApplications(users map[string]uint64, groups 
map[string]uint64) []Limit {
+       var limits []Limit
+       for user, limit := range users {
+               var users []string
+               users = append(users, user)
+               limit := Limit{Limit: "user-limit", Users: users, 
MaxApplications: limit}
+               limits = append(limits, limit)
+       }
+
+       for group, limit := range groups {
+               var groups []string
+               groups = append(groups, group)
+               limit := Limit{Limit: "group-limit", Groups: groups, 
MaxApplications: limit}
+               limits = append(limits, limit)
+       }
+       return limits
+}
+
 func TestCheckLimitMaxApplications(t *testing.T) { //nolint:funlen
        testCases := []struct {
                name     string
@@ -892,48 +931,18 @@ func TestCheckLimitMaxApplications(t *testing.T) { 
//nolint:funlen
                        name: "leaf queue user group maxapplications are within 
parent queue user group maxapplications",
                        config: QueueConfig{
                                Name: "parent",
-                               Limits: []Limit{
-                                       {
-                                               Limit:           "user-limit",
-                                               Users:           
[]string{"test-user"},
-                                               MaxApplications: 100,
-                                       },
-                                       {
-                                               Limit:           "group-limit",
-                                               Groups:          
[]string{"test-group"},
-                                               MaxApplications: 100,
-                                       },
-                               },
+                               Limits: 
createLimitMaxApplications(map[string]uint64{"test-user": 100},
+                                       map[string]uint64{"test-group": 100}),
                                Queues: []QueueConfig{
                                        {
                                                Name: "child1",
-                                               Limits: []Limit{
-                                                       {
-                                                               Limit:          
 "user-limit",
-                                                               Users:          
 []string{"test-user"},
-                                                               
MaxApplications: 100,
-                                                       },
-                                                       {
-                                                               Limit:          
 "group-limit",
-                                                               Groups:         
 []string{"test-group"},
-                                                               
MaxApplications: 100,
-                                                       },
-                                               },
+                                               Limits: 
createLimitMaxApplications(map[string]uint64{"test-user": 100},
+                                                       
map[string]uint64{"test-group": 100}),
                                                Queues: []QueueConfig{
                                                        {
                                                                Name: "child2",
-                                                               Limits: []Limit{
-                                                                       {
-                                                                               
Limit:           "user-limit",
-                                                                               
Users:           []string{"test-user"},
-                                                                               
MaxApplications: 100,
-                                                                       },
-                                                                       {
-                                                                               
Limit:           "group-limit",
-                                                                               
Groups:          []string{"test-group"},
-                                                                               
MaxApplications: 100,
-                                                                       },
-                                                               },
+                                                               Limits: 
createLimitMaxApplications(map[string]uint64{"test-user": 100},
+                                                                       
map[string]uint64{"test-group": 100}),
                                                        },
                                                },
                                        },
@@ -945,33 +954,13 @@ func TestCheckLimitMaxApplications(t *testing.T) { 
//nolint:funlen
                        name: "leaf queue user maxapplications exceed parent 
queue user maxapplications",
                        config: QueueConfig{
                                Name: "parent",
-                               Limits: []Limit{
-                                       {
-                                               Limit:           "user-limit",
-                                               Users:           
[]string{"test-user"},
-                                               MaxApplications: 100,
-                                       },
-                                       {
-                                               Limit:           "group-limit",
-                                               Groups:          
[]string{"test-group"},
-                                               MaxApplications: 100,
-                                       },
-                               },
+                               Limits: 
createLimitMaxApplications(map[string]uint64{"test-user": 100},
+                                       map[string]uint64{"test-group": 100}),
                                Queues: []QueueConfig{
                                        {
                                                Name: "child1",
-                                               Limits: []Limit{
-                                                       {
-                                                               Limit:          
 "user-limit",
-                                                               Users:          
 []string{"test-user"},
-                                                               
MaxApplications: 200,
-                                                       },
-                                                       {
-                                                               Limit:          
 "group-limit",
-                                                               Groups:         
 []string{"test-group"},
-                                                               
MaxApplications: 50,
-                                                       },
-                                               },
+                                               Limits: 
createLimitMaxApplications(map[string]uint64{"test-user": 200},
+                                                       
map[string]uint64{"test-group": 50}),
                                        },
                                },
                        },
@@ -981,33 +970,13 @@ func TestCheckLimitMaxApplications(t *testing.T) { 
//nolint:funlen
                        name: "leaf queue group maxapplications exceed parent 
queue group maxapplications",
                        config: QueueConfig{
                                Name: "parent",
-                               Limits: []Limit{
-                                       {
-                                               Limit:           "user-limit",
-                                               Users:           
[]string{"test-user"},
-                                               MaxApplications: 100,
-                                       },
-                                       {
-                                               Limit:           "group-limit",
-                                               Groups:          
[]string{"test-group"},
-                                               MaxApplications: 100,
-                                       },
-                               },
+                               Limits: 
createLimitMaxApplications(map[string]uint64{"test-user": 100},
+                                       map[string]uint64{"test-group": 100}),
                                Queues: []QueueConfig{
                                        {
                                                Name: "child1",
-                                               Limits: []Limit{
-                                                       {
-                                                               Limit:          
 "user-limit",
-                                                               Users:          
 []string{"test-user"},
-                                                               
MaxApplications: 50,
-                                                       },
-                                                       {
-                                                               Limit:          
 "group-limit",
-                                                               Groups:         
 []string{"test-group"},
-                                                               
MaxApplications: 200,
-                                                       },
-                                               },
+                                               Limits: 
createLimitMaxApplications(map[string]uint64{"test-user": 50},
+                                                       
map[string]uint64{"test-group": 200}),
                                        },
                                },
                        },
@@ -1017,7 +986,7 @@ func TestCheckLimitMaxApplications(t *testing.T) { 
//nolint:funlen
 
        for _, testCase := range testCases {
                t.Run(testCase.name, func(t *testing.T) {
-                       err := checkLimitMaxApplications(testCase.config, nil, 
make(map[string]uint64), make(map[string]uint64))
+                       err := checkLimitMaxApplications(testCase.config, 
make(map[string]map[string]uint64), make(map[string]map[string]uint64), 
common.Empty)
                        if testCase.hasError {
                                assert.ErrorContains(t, err, "is greater than 
immediate or ancestor parent max applications")
                        } else {
@@ -1231,7 +1200,7 @@ func TestCheckLimits(t *testing.T) { //nolint:funlen
                                        },
                                },
                        },
-                       errMsg: "MaxApplications is 0",
+                       errMsg: "",
                },
                {
                        name: "group maxapplications is 0",
@@ -1256,7 +1225,7 @@ func TestCheckLimits(t *testing.T) { //nolint:funlen
                                        },
                                },
                        },
-                       errMsg: "MaxApplications is 0",
+                       errMsg: "",
                },
                {
                        name: "user wildcard is not last entry",
diff --git a/pkg/webservice/handlers_test.go b/pkg/webservice/handlers_test.go
index a0199f85..d7f8eedc 100644
--- a/pkg/webservice/handlers_test.go
+++ b/pkg/webservice/handlers_test.go
@@ -197,6 +197,60 @@ partitions:
                 vcore: 10000
 `
 
+const userGroupLimitsConfig = `
+partitions:
+    - name: default
+      queues:
+        - name: root
+          parent: true
+          submitacl: '*'
+          queues:
+            - name: parent1
+              parent: true
+              limits:
+                - limit: ""
+                  users:
+                    - test_user
+                  maxapplications: 0
+                  maxresources:
+                    cpu: "200"
+`
+
+const userGroupLimitsInvalidConfig = `
+partitions:
+    - name: default
+      queues:
+        - name: root
+          parent: true
+          submitacl: '*'
+          queues:
+            - name: parent1
+              parent: true
+              limits:
+                - limit: ""
+                  users:
+                    - test_user
+                  maxapplications: 1
+                  maxresources:
+                    cpu: "0"
+`
+
+const userGroupLimitsInvalidConfig1 = `
+partitions:
+    - name: default
+      queues:
+        - name: root
+          parent: true
+          submitacl: '*'
+          queues:
+            - name: parent1
+              parent: true
+              limits:
+                - limit: ""
+                  users:
+                    - test_user
+`
+
 const rmID = "rm-123"
 const policyGroup = "default-policy-group"
 const queueName = "root.default"
@@ -266,6 +320,47 @@ func TestValidateConf(t *testing.T) {
        }
 }
 
+func TestUserGroupLimits(t *testing.T) {
+       confTests := []struct {
+               content          string
+               expectedResponse dao.ValidateConfResponse
+       }{
+               {
+                       content: userGroupLimitsConfig,
+                       expectedResponse: dao.ValidateConfResponse{
+                               Allowed: true,
+                               Reason:  common.Empty,
+                       },
+               },
+               {
+                       content: userGroupLimitsInvalidConfig,
+                       expectedResponse: dao.ValidateConfResponse{
+                               Allowed: false,
+                               Reason:  "MaxResources is zero in '' limit, all 
resource types are zero",
+                       },
+               },
+               {
+                       content: userGroupLimitsInvalidConfig1,
+                       expectedResponse: dao.ValidateConfResponse{
+                               Allowed: false,
+                               Reason:  "invalid resource combination for 
limit  all resource limits are null",
+                       },
+               },
+       }
+       for _, test := range confTests {
+               // No err check: new request always returns correctly
+               //nolint: errcheck
+               req, _ := http.NewRequest("POST", "", 
strings.NewReader(test.content))
+               resp := &MockResponseWriter{}
+               validateConf(resp, req)
+               var vcr dao.ValidateConfResponse
+               err := json.Unmarshal(resp.outputBytes, &vcr)
+               assert.NilError(t, err, "failed to unmarshal 
ValidateConfResponse from response body")
+               assert.Equal(t, vcr.Allowed, test.expectedResponse.Allowed, 
"allowed flag incorrect")
+               assert.Equal(t, vcr.Reason, test.expectedResponse.Reason, 
"response text not as expected")
+       }
+}
+
 func TestApplicationHistory(t *testing.T) {
        // make sure the history is nil when we finish this test
        defer ResetIMHistory()


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to