func checkLimit()

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
}