mirror of https://github.com/k3s-io/k3s
refactor quota calculation for re-use
parent
472dcec7b2
commit
89eaaa3d7d
|
@ -275,12 +275,22 @@ func (rq *ResourceQuotaController) syncResourceQuota(resourceQuota api.ResourceQ
|
||||||
// if this is our first sync, it will be dirty by default, since we need track usage
|
// if this is our first sync, it will be dirty by default, since we need track usage
|
||||||
dirty = dirty || (resourceQuota.Status.Hard == nil || resourceQuota.Status.Used == nil)
|
dirty = dirty || (resourceQuota.Status.Hard == nil || resourceQuota.Status.Used == nil)
|
||||||
|
|
||||||
|
used := api.ResourceList{}
|
||||||
|
if resourceQuota.Status.Used != nil {
|
||||||
|
used = quota.Add(api.ResourceList{}, resourceQuota.Status.Used)
|
||||||
|
}
|
||||||
|
hardLimits := quota.Add(api.ResourceList{}, resourceQuota.Spec.Hard)
|
||||||
|
|
||||||
|
newUsage, err := quota.CalculateUsage(resourceQuota.Namespace, resourceQuota.Spec.Scopes, hardLimits, rq.registry)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
for key, value := range newUsage {
|
||||||
|
used[key] = value
|
||||||
|
}
|
||||||
|
|
||||||
// Create a usage object that is based on the quota resource version that will handle updates
|
// Create a usage object that is based on the quota resource version that will handle updates
|
||||||
// by default, we preserve the past usage observation, and set hard to the current spec
|
// by default, we preserve the past usage observation, and set hard to the current spec
|
||||||
previousUsed := api.ResourceList{}
|
|
||||||
if resourceQuota.Status.Used != nil {
|
|
||||||
previousUsed = quota.Add(api.ResourceList{}, resourceQuota.Status.Used)
|
|
||||||
}
|
|
||||||
usage := api.ResourceQuota{
|
usage := api.ResourceQuota{
|
||||||
ObjectMeta: api.ObjectMeta{
|
ObjectMeta: api.ObjectMeta{
|
||||||
Name: resourceQuota.Name,
|
Name: resourceQuota.Name,
|
||||||
|
@ -289,45 +299,11 @@ func (rq *ResourceQuotaController) syncResourceQuota(resourceQuota api.ResourceQ
|
||||||
Labels: resourceQuota.Labels,
|
Labels: resourceQuota.Labels,
|
||||||
Annotations: resourceQuota.Annotations},
|
Annotations: resourceQuota.Annotations},
|
||||||
Status: api.ResourceQuotaStatus{
|
Status: api.ResourceQuotaStatus{
|
||||||
Hard: quota.Add(api.ResourceList{}, resourceQuota.Spec.Hard),
|
Hard: hardLimits,
|
||||||
Used: previousUsed,
|
Used: used,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
// find the intersection between the hard resources on the quota
|
|
||||||
// and the resources this controller can track to know what we can
|
|
||||||
// look to measure updated usage stats for
|
|
||||||
hardResources := quota.ResourceNames(usage.Status.Hard)
|
|
||||||
potentialResources := []api.ResourceName{}
|
|
||||||
evaluators := rq.registry.Evaluators()
|
|
||||||
for _, evaluator := range evaluators {
|
|
||||||
potentialResources = append(potentialResources, evaluator.MatchesResources()...)
|
|
||||||
}
|
|
||||||
matchedResources := quota.Intersection(hardResources, potentialResources)
|
|
||||||
|
|
||||||
// sum the observed usage from each evaluator
|
|
||||||
newUsage := api.ResourceList{}
|
|
||||||
usageStatsOptions := quota.UsageStatsOptions{Namespace: resourceQuota.Namespace, Scopes: resourceQuota.Spec.Scopes}
|
|
||||||
for _, evaluator := range evaluators {
|
|
||||||
// only trigger the evaluator if it matches a resource in the quota, otherwise, skip calculating anything
|
|
||||||
if intersection := quota.Intersection(evaluator.MatchesResources(), matchedResources); len(intersection) == 0 {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
stats, err := evaluator.UsageStats(usageStatsOptions)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
newUsage = quota.Add(newUsage, stats.Used)
|
|
||||||
}
|
|
||||||
|
|
||||||
// mask the observed usage to only the set of resources tracked by this quota
|
|
||||||
// merge our observed usage with the quota usage status
|
|
||||||
// if the new usage is different than the last usage, we will need to do an update
|
|
||||||
newUsage = quota.Mask(newUsage, matchedResources)
|
|
||||||
for key, value := range newUsage {
|
|
||||||
usage.Status.Used[key] = value
|
|
||||||
}
|
|
||||||
|
|
||||||
dirty = dirty || !quota.Equals(usage.Status.Used, resourceQuota.Status.Used)
|
dirty = dirty || !quota.Equals(usage.Status.Used, resourceQuota.Status.Used)
|
||||||
|
|
||||||
// there was a change observed by this controller that requires we update quota
|
// there was a change observed by this controller that requires we update quota
|
||||||
|
|
|
@ -177,3 +177,38 @@ func ToSet(resourceNames []api.ResourceName) sets.String {
|
||||||
}
|
}
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// CalculateUsage calculates and returns the requested ResourceList usage
|
||||||
|
func CalculateUsage(namespaceName string, scopes []api.ResourceQuotaScope, hardLimits api.ResourceList, registry Registry) (api.ResourceList, error) {
|
||||||
|
// find the intersection between the hard resources on the quota
|
||||||
|
// and the resources this controller can track to know what we can
|
||||||
|
// look to measure updated usage stats for
|
||||||
|
hardResources := ResourceNames(hardLimits)
|
||||||
|
potentialResources := []api.ResourceName{}
|
||||||
|
evaluators := registry.Evaluators()
|
||||||
|
for _, evaluator := range evaluators {
|
||||||
|
potentialResources = append(potentialResources, evaluator.MatchesResources()...)
|
||||||
|
}
|
||||||
|
matchedResources := Intersection(hardResources, potentialResources)
|
||||||
|
|
||||||
|
// sum the observed usage from each evaluator
|
||||||
|
newUsage := api.ResourceList{}
|
||||||
|
usageStatsOptions := UsageStatsOptions{Namespace: namespaceName, Scopes: scopes}
|
||||||
|
for _, evaluator := range evaluators {
|
||||||
|
// only trigger the evaluator if it matches a resource in the quota, otherwise, skip calculating anything
|
||||||
|
if intersection := Intersection(evaluator.MatchesResources(), matchedResources); len(intersection) == 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
stats, err := evaluator.UsageStats(usageStatsOptions)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
newUsage = Add(newUsage, stats.Used)
|
||||||
|
}
|
||||||
|
|
||||||
|
// mask the observed usage to only the set of resources tracked by this quota
|
||||||
|
// merge our observed usage with the quota usage status
|
||||||
|
// if the new usage is different than the last usage, we will need to do an update
|
||||||
|
newUsage = Mask(newUsage, matchedResources)
|
||||||
|
return newUsage, nil
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue