Skip to content

Commit 9ebe338

Browse files
committed
Add support for multiple resource limits
1 parent 42f767b commit 9ebe338

File tree

10 files changed

+1243
-1
lines changed

10 files changed

+1243
-1
lines changed

cluster-autoscaler/cloudprovider/resource_limiter.go

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,11 @@ package cloudprovider
1818

1919
import (
2020
"fmt"
21-
"k8s.io/apimachinery/pkg/util/sets"
2221
"math"
2322
"strings"
23+
24+
apiv1 "k8s.io/api/core/v1"
25+
"k8s.io/apimachinery/pkg/util/sets"
2426
)
2527

2628
// ResourceLimiter contains limits (max, min) for resources (cores, memory etc.).
@@ -29,6 +31,10 @@ type ResourceLimiter struct {
2931
maxLimits map[string]int64
3032
}
3133

34+
func (r *ResourceLimiter) ID() string {
35+
return "cluster-wide"
36+
}
37+
3238
// NewResourceLimiter creates new ResourceLimiter for map. Maps are deep copied.
3339
func NewResourceLimiter(minLimits map[string]int64, maxLimits map[string]int64) *ResourceLimiter {
3440
minLimitsCopy := make(map[string]int64)
@@ -88,3 +94,15 @@ func (r *ResourceLimiter) String() string {
8894
}
8995
return strings.Join(resourceDetails, ", ")
9096
}
97+
98+
func (r *ResourceLimiter) AppliesTo(node *apiv1.Node) bool {
99+
return true
100+
}
101+
102+
func (r *ResourceLimiter) MaxLimits() map[string]int64 {
103+
return r.maxLimits
104+
}
105+
106+
func (r *ResourceLimiter) MinLimits() map[string]int64 {
107+
return r.minLimits
108+
}
Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
package resourcelimits
2+
3+
import (
4+
"fmt"
5+
6+
corev1 "k8s.io/api/core/v1"
7+
"k8s.io/autoscaler/cluster-autoscaler/context"
8+
"k8s.io/autoscaler/cluster-autoscaler/processors/customresources"
9+
)
10+
11+
// TrackerFactory builds trackers.
12+
type TrackerFactory struct {
13+
crp customresources.CustomResourcesProcessor
14+
limitProviders []Provider
15+
usageCalculator *usageCalculator
16+
}
17+
18+
// NewTrackerFactory creates a new TrackerFactory.
19+
func NewTrackerFactory(opts TrackerOptions) *TrackerFactory {
20+
uc := newUsageCalculator(opts.CRP, opts.NodeFilter)
21+
return &TrackerFactory{
22+
crp: opts.CRP,
23+
limitProviders: opts.Providers,
24+
usageCalculator: uc,
25+
}
26+
}
27+
28+
// NewMaxLimitsTracker builds a new Tracker for max limits.
29+
func (f *TrackerFactory) NewMaxLimitsTracker(ctx *context.AutoscalingContext, nodes []*corev1.Node) (*Tracker, error) {
30+
return f.newLimitsTracker(ctx, nodes, &maxLimitsStrategy{})
31+
}
32+
33+
// NewMinLimitsTracker builds a new Tracker for min limits.
34+
func (f *TrackerFactory) NewMinLimitsTracker(ctx *context.AutoscalingContext, nodes []*corev1.Node) (*Tracker, error) {
35+
return f.newLimitsTracker(ctx, nodes, &minLimitsStrategy{})
36+
}
37+
38+
func (f *TrackerFactory) newLimitsTracker(ctx *context.AutoscalingContext, nodes []*corev1.Node, strategy limitStrategy) (*Tracker, error) {
39+
limiters, err := f.limiters()
40+
if err != nil {
41+
return nil, err
42+
}
43+
usages, err := f.usageCalculator.calculateUsages(ctx, nodes, limiters)
44+
if err != nil {
45+
return nil, err
46+
}
47+
limitsLeft := make(map[string]resourceList)
48+
for _, rl := range limiters {
49+
limitsLeft[rl.ID()] = make(resourceList)
50+
limits := strategy.GetLimits(rl)
51+
for resourceType, limit := range limits {
52+
usage := usages[rl.ID()][resourceType]
53+
limitsLeft[rl.ID()][resourceType] = strategy.CalculateLimitsLeft(limit, usage)
54+
}
55+
}
56+
tracker := newTracker(f.crp, limiters, limitsLeft)
57+
return tracker, nil
58+
}
59+
60+
func (f *TrackerFactory) limiters() ([]Limiter, error) {
61+
var limiters []Limiter
62+
for _, provider := range f.limitProviders {
63+
provLimiters, err := provider.AllLimiters()
64+
if err != nil {
65+
return nil, fmt.Errorf("failed to get limiters from provider: %w", err)
66+
}
67+
for _, limiter := range provLimiters {
68+
limiters = append(limiters, limiter)
69+
}
70+
}
71+
return limiters, nil
72+
}
73+
74+
// limitStrategy is an interface for defining limit calculation strategies.
75+
type limitStrategy interface {
76+
GetLimits(rl Limiter) resourceList
77+
CalculateLimitsLeft(limit, usage int64) int64
78+
}
79+
80+
// maxLimitsStrategy is a strategy for max limits.
81+
type maxLimitsStrategy struct{}
82+
83+
// GetLimits returns max limits.
84+
func (s *maxLimitsStrategy) GetLimits(rl Limiter) resourceList {
85+
return rl.MaxLimits()
86+
}
87+
88+
// CalculateLimitsLeft calculates the remaining limits for max limits.
89+
func (s *maxLimitsStrategy) CalculateLimitsLeft(limit, usage int64) int64 {
90+
return max(0, limit-usage)
91+
}
92+
93+
// minLimitsStrategy is a strategy for min limits.
94+
type minLimitsStrategy struct{}
95+
96+
// GetLimits returns min limits.
97+
func (s *minLimitsStrategy) GetLimits(rl Limiter) resourceList {
98+
return rl.MinLimits()
99+
}
100+
101+
// CalculateLimitsLeft calculates the remaining limits for min limits.
102+
func (s *minLimitsStrategy) CalculateLimitsLeft(limit, usage int64) int64 {
103+
return max(0, usage-limit)
104+
}

0 commit comments

Comments
 (0)