in pkg/common/configs/configvalidator.go [482:569]
func checkLimit(limit Limit, existingUserName map[string]bool, existingGroupName map[string]bool, queue *QueueConfig) error {
if len(limit.Users) == 0 && len(limit.Groups) == 0 {
return fmt.Errorf("empty user and group lists defined in limit '%v'", limit)
}
for _, name := range limit.Users {
if name != "*" && !UserRegExp.MatchString(name) {
return fmt.Errorf("invalid limit user name '%s' in limit definition", name)
}
if existingUserName[name] {
return fmt.Errorf("duplicated user name '%s', already exists", name)
}
existingUserName[name] = true
// The user without wildcard should not happen after the wildcard user
// It means the wildcard for user should be the last item for limits object list which including the username,
// and we should only set one wildcard user for all limits
if existingUserName["*"] && name != "*" {
return fmt.Errorf("should not set no wildcard user %s after wildcard user limit", name)
}
}
for _, name := range limit.Groups {
if name != "*" && !GroupRegExp.MatchString(name) {
return fmt.Errorf("invalid limit group name '%s' in limit definition", name)
}
if existingGroupName[name] {
return fmt.Errorf("duplicated group name '%s'", name)
}
existingGroupName[name] = true
// The group without wildcard should not happen after the wildcard group
// It means the wildcard for group should be the last item for limits object list which including the group name,
// and we should only set one wildcard group for all limits
if existingGroupName["*"] && name != "*" {
return fmt.Errorf("should not set no wildcard group %s after wildcard group limit", name)
}
}
// Specifying a wildcard for the group limit sets a cumulative limit for all users in that queue.
// If there is no specific group mentioned the wildcard group limit would thus be the same as the queue limit.
// For that reason we do not allow specifying only one group limit that is using the wildcard.
// There must be at least one limit with a group name defined.
if existingGroupName["*"] && len(existingGroupName) == 1 {
return fmt.Errorf("should not specify only one group limit that is using the wildcard. " +
"There must be at least one limit with a group name defined ")
}
var limitResource = resources.NewResource()
var err error
// check the resource (if defined)
if len(limit.MaxResources) != 0 {
limitResource, err = resources.NewResourceFromConf(limit.MaxResources)
if err != nil {
log.Log(log.Config).Debug("resource parsing failed",
zap.Error(err))
return err
}
if !resources.StrictlyGreaterThanZero(limitResource) {
return fmt.Errorf("MaxResources should be greater than zero in '%s' limit", limit.Limit)
}
}
// at least some resource should be not null
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 queue.MaxApplications != 0 && queue.MaxApplications < limit.MaxApplications {
return fmt.Errorf("invalid MaxApplications settings for limit %s exceed current the queue MaxApplications", limit.Limit)
}
// If queue is RootQueue, the queue.Resources.Max will be null, we don't need to check for root queue
// But we may need to check the root resource during loading the config and after partition resource loading when update node
if queue.Name != RootQueue {
queueMaxResource, err := resources.NewResourceFromConf(queue.Resources.Max)
if err != nil {
log.Log(log.Config).Debug("resource parsing failed",
zap.Error(err))
return fmt.Errorf("parse queue %s max resource failed: %s", queue.Name, err.Error())
}
if !queueMaxResource.FitInMaxUndef(limitResource) {
return fmt.Errorf("invalid MaxResources settings for limit %s exeecd current the queue MaxResources", limit.Limit)
}
}
return nil
}