Skip to content

Commit 75c2061

Browse files
committed
Add support for capacity unit reservation for load balancers
1 parent 13538cb commit 75c2061

File tree

4 files changed

+1041
-0
lines changed

4 files changed

+1041
-0
lines changed
Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
package elbv2
2+
3+
import (
4+
"context"
5+
awssdk "github.com/aws/aws-sdk-go-v2/aws"
6+
elbv2sdk "github.com/aws/aws-sdk-go-v2/service/elasticloadbalancingv2"
7+
elbv2types "github.com/aws/aws-sdk-go-v2/service/elasticloadbalancingv2/types"
8+
"github.com/go-logr/logr"
9+
"reflect"
10+
"sigs.k8s.io/aws-load-balancer-controller/pkg/aws/services"
11+
"sigs.k8s.io/aws-load-balancer-controller/pkg/config"
12+
elbv2model "sigs.k8s.io/aws-load-balancer-controller/pkg/model/elbv2"
13+
)
14+
15+
// reconciler for LoadBalancer Capacity Reservation
16+
type LoadBalancerCapacityReservationReconciler interface {
17+
// Reconcile loadBalancer capacity reservation
18+
Reconcile(ctx context.Context, resLB *elbv2model.LoadBalancer, sdkLB LoadBalancerWithTags) error
19+
}
20+
21+
// NewDefaultLoadBalancerCapacityReservationReconciler constructs new defaultLoadBalancerCapacityReservationReconciler.
22+
func NewDefaultLoadBalancerCapacityReservationReconciler(elbv2Client services.ELBV2, featureGates config.FeatureGates, logger logr.Logger) *defaultLoadBalancerCapacityReservationReconciler {
23+
return &defaultLoadBalancerCapacityReservationReconciler{
24+
elbv2Client: elbv2Client,
25+
logger: logger,
26+
featureGates: featureGates,
27+
}
28+
}
29+
30+
var _ LoadBalancerCapacityReservationReconciler = &defaultLoadBalancerCapacityReservationReconciler{}
31+
32+
// default implementation for LoadBalancerCapacityReservationReconciler
33+
type defaultLoadBalancerCapacityReservationReconciler struct {
34+
elbv2Client services.ELBV2
35+
logger logr.Logger
36+
featureGates config.FeatureGates
37+
}
38+
39+
func (r *defaultLoadBalancerCapacityReservationReconciler) Reconcile(ctx context.Context, resLB *elbv2model.LoadBalancer, sdkLB LoadBalancerWithTags) error {
40+
desiredCapacityReservation := resLB.Spec.MinimumLoadBalancerCapacity
41+
// If the annotation is missing or not set, skip the capacity reservation
42+
if desiredCapacityReservation == nil {
43+
return nil
44+
}
45+
//If the value of desired capacityUnits is zero then set desiredCapacityReservation to nil to reset the capacity
46+
if desiredCapacityReservation.CapacityUnits == 0 {
47+
desiredCapacityReservation = nil
48+
}
49+
currentCapacityReservation, err := r.getCurrentCapacityReservation(ctx, sdkLB)
50+
if err != nil {
51+
return err
52+
}
53+
isLBCapacityReservationDrifted := !reflect.DeepEqual(desiredCapacityReservation, currentCapacityReservation)
54+
if !isLBCapacityReservationDrifted {
55+
return nil
56+
}
57+
if desiredCapacityReservation == nil {
58+
//If the value of desired capacityUnits is nil then reset capacity
59+
req := &elbv2sdk.ModifyCapacityReservationInput{
60+
LoadBalancerArn: sdkLB.LoadBalancer.LoadBalancerArn,
61+
ResetCapacityReservation: awssdk.Bool(true),
62+
}
63+
64+
r.logger.Info("resetting loadBalancer capacity reservation",
65+
"stackID", resLB.Stack().StackID(),
66+
"resourceID", resLB.ID(),
67+
"arn", awssdk.ToString(sdkLB.LoadBalancer.LoadBalancerArn))
68+
if _, err := r.elbv2Client.ModifyCapacityReservationWithContext(ctx, req); err != nil {
69+
return err
70+
}
71+
r.logger.Info("reset successful for loadBalancer capacity reservation",
72+
"stackID", resLB.Stack().StackID(),
73+
"resourceID", resLB.ID(),
74+
"arn", awssdk.ToString(sdkLB.LoadBalancer.LoadBalancerArn))
75+
} else {
76+
req := &elbv2sdk.ModifyCapacityReservationInput{
77+
LoadBalancerArn: sdkLB.LoadBalancer.LoadBalancerArn,
78+
MinimumLoadBalancerCapacity: &elbv2types.MinimumLoadBalancerCapacity{
79+
CapacityUnits: awssdk.Int32(desiredCapacityReservation.CapacityUnits),
80+
},
81+
}
82+
r.logger.Info("modifying loadBalancer capacity reservation",
83+
"stackID", resLB.Stack().StackID(),
84+
"resourceID", resLB.ID(),
85+
"arn", awssdk.ToString(sdkLB.LoadBalancer.LoadBalancerArn),
86+
"change", desiredCapacityReservation)
87+
if _, err := r.elbv2Client.ModifyCapacityReservationWithContext(ctx, req); err != nil {
88+
return err
89+
}
90+
r.logger.Info("modified loadBalancer capacity reservation",
91+
"stackID", resLB.Stack().StackID(),
92+
"resourceID", resLB.ID(),
93+
"arn", awssdk.ToString(sdkLB.LoadBalancer.LoadBalancerArn))
94+
}
95+
return nil
96+
}
97+
98+
func (r *defaultLoadBalancerCapacityReservationReconciler) getCurrentCapacityReservation(ctx context.Context, sdkLB LoadBalancerWithTags) (*elbv2model.MinimumLoadBalancerCapacity, error) {
99+
req := &elbv2sdk.DescribeCapacityReservationInput{
100+
LoadBalancerArn: sdkLB.LoadBalancer.LoadBalancerArn,
101+
}
102+
resp, err := r.elbv2Client.DescribeCapacityReservationWithContext(ctx, req)
103+
if err != nil {
104+
return nil, err
105+
}
106+
var sdkLBMinimumCapacity = &elbv2model.MinimumLoadBalancerCapacity{}
107+
if (resp.CapacityReservationState == nil || len(resp.CapacityReservationState) == 0) && resp.MinimumLoadBalancerCapacity == nil {
108+
return nil, nil
109+
}
110+
sdkLBMinimumCapacity.CapacityUnits = awssdk.ToInt32(resp.MinimumLoadBalancerCapacity.CapacityUnits)
111+
return sdkLBMinimumCapacity, nil
112+
}

0 commit comments

Comments
 (0)