Skip to content

Commit e942a0f

Browse files
authoredMar 3, 2025··
Update rule management to avoid sporadic 503 errors (#4039)
* Update rule management to avoid sporadic 503 errors * Update rule management to avoid sporadic 503 errors * Update rule management to avoid sporadic 503 errors * Update rule management to avoid sporadic 503 errors * Update rule management to avoid sporadic 503 errors * Update rule management to avoid sporadic 503 errors * Update rule management to avoid sporadic 503 errors
1 parent f9699da commit e942a0f

15 files changed

+1929
-68
lines changed
 

‎docs/install/iam_policy.json

+2-1
Original file line numberDiff line numberDiff line change
@@ -239,7 +239,8 @@
239239
"elasticloadbalancing:ModifyListener",
240240
"elasticloadbalancing:AddListenerCertificates",
241241
"elasticloadbalancing:RemoveListenerCertificates",
242-
"elasticloadbalancing:ModifyRule"
242+
"elasticloadbalancing:ModifyRule",
243+
"elasticloadbalancing:SetRulePriorities"
243244
],
244245
"Resource": "*"
245246
}

‎docs/install/iam_policy_cn.json

+2-1
Original file line numberDiff line numberDiff line change
@@ -239,7 +239,8 @@
239239
"elasticloadbalancing:ModifyListener",
240240
"elasticloadbalancing:AddListenerCertificates",
241241
"elasticloadbalancing:RemoveListenerCertificates",
242-
"elasticloadbalancing:ModifyRule"
242+
"elasticloadbalancing:ModifyRule",
243+
"elasticloadbalancing:SetRulePriorities"
243244
],
244245
"Resource": "*"
245246
}

‎docs/install/iam_policy_iso.json

+2-1
Original file line numberDiff line numberDiff line change
@@ -234,7 +234,8 @@
234234
"elasticloadbalancing:ModifyListener",
235235
"elasticloadbalancing:AddListenerCertificates",
236236
"elasticloadbalancing:RemoveListenerCertificates",
237-
"elasticloadbalancing:ModifyRule"
237+
"elasticloadbalancing:ModifyRule",
238+
"elasticloadbalancing:SetRulePriorities"
238239
],
239240
"Resource": "*"
240241
}

‎docs/install/iam_policy_isob.json

+2-1
Original file line numberDiff line numberDiff line change
@@ -234,7 +234,8 @@
234234
"elasticloadbalancing:ModifyListener",
235235
"elasticloadbalancing:AddListenerCertificates",
236236
"elasticloadbalancing:RemoveListenerCertificates",
237-
"elasticloadbalancing:ModifyRule"
237+
"elasticloadbalancing:ModifyRule",
238+
"elasticloadbalancing:SetRulePriorities"
238239
],
239240
"Resource": "*"
240241
}

‎docs/install/iam_policy_isoe.json

+2-1
Original file line numberDiff line numberDiff line change
@@ -234,7 +234,8 @@
234234
"elasticloadbalancing:ModifyListener",
235235
"elasticloadbalancing:AddListenerCertificates",
236236
"elasticloadbalancing:RemoveListenerCertificates",
237-
"elasticloadbalancing:ModifyRule"
237+
"elasticloadbalancing:ModifyRule",
238+
"elasticloadbalancing:SetRulePriorities"
238239
],
239240
"Resource": "*"
240241
}

‎docs/install/iam_policy_isof.json

+2-1
Original file line numberDiff line numberDiff line change
@@ -234,7 +234,8 @@
234234
"elasticloadbalancing:ModifyListener",
235235
"elasticloadbalancing:AddListenerCertificates",
236236
"elasticloadbalancing:RemoveListenerCertificates",
237-
"elasticloadbalancing:ModifyRule"
237+
"elasticloadbalancing:ModifyRule",
238+
"elasticloadbalancing:SetRulePriorities"
238239
],
239240
"Resource": "*"
240241
}

‎docs/install/iam_policy_us-gov.json

+2-1
Original file line numberDiff line numberDiff line change
@@ -239,7 +239,8 @@
239239
"elasticloadbalancing:ModifyListener",
240240
"elasticloadbalancing:AddListenerCertificates",
241241
"elasticloadbalancing:RemoveListenerCertificates",
242-
"elasticloadbalancing:ModifyRule"
242+
"elasticloadbalancing:ModifyRule",
243+
"elasticloadbalancing:SetRulePriorities"
243244
],
244245
"Resource": "*"
245246
}

‎pkg/aws/services/elbv2.go

+10-1
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,8 @@ type ELBV2 interface {
5050
DescribeRulesWithContext(ctx context.Context, input *elasticloadbalancingv2.DescribeRulesInput) (*elasticloadbalancingv2.DescribeRulesOutput, error)
5151
CreateRuleWithContext(ctx context.Context, input *elasticloadbalancingv2.CreateRuleInput) (*elasticloadbalancingv2.CreateRuleOutput, error)
5252
DeleteRuleWithContext(ctx context.Context, input *elasticloadbalancingv2.DeleteRuleInput) (*elasticloadbalancingv2.DeleteRuleOutput, error)
53-
ModifyRuleWithContext(ctx context.Context, inout *elasticloadbalancingv2.ModifyRuleInput) (*elasticloadbalancingv2.ModifyRuleOutput, error)
53+
ModifyRuleWithContext(ctx context.Context, input *elasticloadbalancingv2.ModifyRuleInput) (*elasticloadbalancingv2.ModifyRuleOutput, error)
54+
SetRulePrioritiesWithContext(ctx context.Context, input *elasticloadbalancingv2.SetRulePrioritiesInput) (*elasticloadbalancingv2.SetRulePrioritiesOutput, error)
5455
RegisterTargetsWithContext(ctx context.Context, input *elasticloadbalancingv2.RegisterTargetsInput) (*elasticloadbalancingv2.RegisterTargetsOutput, error)
5556
DeregisterTargetsWithContext(ctx context.Context, input *elasticloadbalancingv2.DeregisterTargetsInput) (*elasticloadbalancingv2.DeregisterTargetsOutput, error)
5657
DescribeTrustStoresWithContext(ctx context.Context, input *elasticloadbalancingv2.DescribeTrustStoresInput) (*elasticloadbalancingv2.DescribeTrustStoresOutput, error)
@@ -163,6 +164,14 @@ func (c *elbv2Client) DeleteRuleWithContext(ctx context.Context, input *elasticl
163164
return client.DeleteRule(ctx, input)
164165
}
165166

167+
func (c *elbv2Client) SetRulePrioritiesWithContext(ctx context.Context, input *elasticloadbalancingv2.SetRulePrioritiesInput) (*elasticloadbalancingv2.SetRulePrioritiesOutput, error) {
168+
client, err := c.awsClientsProvider.GetELBv2Client(ctx, "SetRulePriorities")
169+
if err != nil {
170+
return nil, err
171+
}
172+
return client.SetRulePriorities(ctx, input)
173+
}
174+
166175
func (c *elbv2Client) CreateRuleWithContext(ctx context.Context, input *elasticloadbalancingv2.CreateRuleInput) (*elasticloadbalancingv2.CreateRuleOutput, error) {
167176
client, err := c.getClient(ctx, "CreateRule")
168177
if err != nil {

‎pkg/aws/services/elbv2_mocks.go

+15
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎pkg/deploy/elbv2/listener_rule_manager.go

+86-41
Original file line numberDiff line numberDiff line change
@@ -6,24 +6,29 @@ import (
66
elbv2sdk "github.com/aws/aws-sdk-go-v2/service/elasticloadbalancingv2"
77
elbv2types "github.com/aws/aws-sdk-go-v2/service/elasticloadbalancingv2/types"
88
"github.com/go-logr/logr"
9-
"github.com/google/go-cmp/cmp"
109
"github.com/pkg/errors"
1110
"sigs.k8s.io/aws-load-balancer-controller/pkg/aws/services"
1211
"sigs.k8s.io/aws-load-balancer-controller/pkg/config"
1312
"sigs.k8s.io/aws-load-balancer-controller/pkg/deploy/tracking"
14-
elbv2equality "sigs.k8s.io/aws-load-balancer-controller/pkg/equality/elbv2"
1513
elbv2model "sigs.k8s.io/aws-load-balancer-controller/pkg/model/elbv2"
1614
"sigs.k8s.io/aws-load-balancer-controller/pkg/runtime"
15+
"slices"
16+
"sort"
17+
"strconv"
1718
"time"
1819
)
1920

2021
// ListenerRuleManager is responsible for create/update/delete ListenerRule resources.
2122
type ListenerRuleManager interface {
22-
Create(ctx context.Context, resLR *elbv2model.ListenerRule) (elbv2model.ListenerRuleStatus, error)
23+
Create(ctx context.Context, resLR *elbv2model.ListenerRule, desiredActionsAndConditions *resLRDesiredActionsAndConditionsPair) (elbv2model.ListenerRuleStatus, error)
2324

24-
Update(ctx context.Context, resLR *elbv2model.ListenerRule, sdkLR ListenerRuleWithTags) (elbv2model.ListenerRuleStatus, error)
25+
UpdateRules(ctx context.Context, resLR *elbv2model.ListenerRule, sdkLR ListenerRuleWithTags, desiredActionsAndConditions *resLRDesiredActionsAndConditionsPair) (elbv2model.ListenerRuleStatus, error)
26+
27+
UpdateRulesTags(ctx context.Context, resLR *elbv2model.ListenerRule, sdkLR ListenerRuleWithTags) (elbv2model.ListenerRuleStatus, error)
2528

2629
Delete(ctx context.Context, sdkLR ListenerRuleWithTags) error
30+
31+
SetRulePriorities(ctx context.Context, matchedResAndSDKLRsBySettings []resAndSDKListenerRulePair, unmatchedSDKLRs []ListenerRuleWithTags) error
2732
}
2833

2934
// NewDefaultListenerRuleManager constructs new defaultListenerRuleManager.
@@ -54,8 +59,8 @@ type defaultListenerRuleManager struct {
5459
waitLSExistenceTimeout time.Duration
5560
}
5661

57-
func (m *defaultListenerRuleManager) Create(ctx context.Context, resLR *elbv2model.ListenerRule) (elbv2model.ListenerRuleStatus, error) {
58-
req, err := buildSDKCreateListenerRuleInput(resLR.Spec, m.featureGates)
62+
func (m *defaultListenerRuleManager) Create(ctx context.Context, resLR *elbv2model.ListenerRule, desiredActionsAndConditions *resLRDesiredActionsAndConditionsPair) (elbv2model.ListenerRuleStatus, error) {
63+
req, err := buildSDKCreateListenerRuleInput(resLR.Spec, desiredActionsAndConditions, m.featureGates)
5964
if err != nil {
6065
return elbv2model.ListenerRuleStatus{}, err
6166
}
@@ -90,13 +95,17 @@ func (m *defaultListenerRuleManager) Create(ctx context.Context, resLR *elbv2mod
9095
return buildResListenerRuleStatus(sdkLR), nil
9196
}
9297

93-
func (m *defaultListenerRuleManager) Update(ctx context.Context, resLR *elbv2model.ListenerRule, sdkLR ListenerRuleWithTags) (elbv2model.ListenerRuleStatus, error) {
98+
func (m *defaultListenerRuleManager) UpdateRulesTags(ctx context.Context, resLR *elbv2model.ListenerRule, sdkLR ListenerRuleWithTags) (elbv2model.ListenerRuleStatus, error) {
9499
if m.featureGates.Enabled(config.ListenerRulesTagging) {
95100
if err := m.updateSDKListenerRuleWithTags(ctx, resLR, sdkLR); err != nil {
96101
return elbv2model.ListenerRuleStatus{}, err
97102
}
98103
}
99-
if err := m.updateSDKListenerRuleWithSettings(ctx, resLR, sdkLR); err != nil {
104+
return buildResListenerRuleStatus(sdkLR), nil
105+
}
106+
107+
func (m *defaultListenerRuleManager) UpdateRules(ctx context.Context, resLR *elbv2model.ListenerRule, sdkLR ListenerRuleWithTags, desiredActionsAndConditions *resLRDesiredActionsAndConditionsPair) (elbv2model.ListenerRuleStatus, error) {
108+
if err := m.updateSDKListenerRuleWithSettings(ctx, resLR, sdkLR, desiredActionsAndConditions); err != nil {
100109
return elbv2model.ListenerRuleStatus{}, err
101110
}
102111
return buildResListenerRuleStatus(sdkLR), nil
@@ -116,15 +125,28 @@ func (m *defaultListenerRuleManager) Delete(ctx context.Context, sdkLR ListenerR
116125
return nil
117126
}
118127

119-
func (m *defaultListenerRuleManager) updateSDKListenerRuleWithSettings(ctx context.Context, resLR *elbv2model.ListenerRule, sdkLR ListenerRuleWithTags) error {
120-
desiredActions, err := buildSDKActions(resLR.Spec.Actions, m.featureGates)
121-
if err != nil {
128+
func (m *defaultListenerRuleManager) SetRulePriorities(ctx context.Context, matchedResAndSDKLRsBySettings []resAndSDKListenerRulePair, unmatchedSDKLRs []ListenerRuleWithTags) error {
129+
req := buildSDKSetRulePrioritiesInput(matchedResAndSDKLRsBySettings, unmatchedSDKLRs)
130+
m.logger.Info("setting listener rule priorities",
131+
"rule priority pairs", req.RulePriorities)
132+
if _, err := m.elbv2Client.SetRulePrioritiesWithContext(ctx, req); err != nil {
122133
return err
123134
}
124-
desiredConditions := buildSDKRuleConditions(resLR.Spec.Conditions)
125-
if !isSDKListenerRuleSettingsDrifted(resLR.Spec, sdkLR, desiredActions, desiredConditions) {
126-
return nil
127-
}
135+
m.logger.Info("setting listener rule priorities complete",
136+
"rule priority pairs", req.RulePriorities)
137+
return nil
138+
}
139+
140+
func (m *defaultListenerRuleManager) updateSDKListenerRuleWithTags(ctx context.Context, resLR *elbv2model.ListenerRule, sdkLR ListenerRuleWithTags) error {
141+
desiredTags := m.trackingProvider.ResourceTags(resLR.Stack(), resLR, resLR.Spec.Tags)
142+
return m.taggingManager.ReconcileTags(ctx, awssdk.ToString(sdkLR.ListenerRule.RuleArn), desiredTags,
143+
WithCurrentTags(sdkLR.Tags),
144+
WithIgnoredTagKeys(m.externalManagedTags))
145+
}
146+
147+
func (m *defaultListenerRuleManager) updateSDKListenerRuleWithSettings(ctx context.Context, resLR *elbv2model.ListenerRule, sdkLR ListenerRuleWithTags, desiredActionsAndConditions *resLRDesiredActionsAndConditionsPair) error {
148+
desiredActions := desiredActionsAndConditions.desiredActions
149+
desiredConditions := desiredActionsAndConditions.desiredConditions
128150

129151
req := buildSDKModifyListenerRuleInput(resLR.Spec, desiredActions, desiredConditions)
130152
req.RuleArn = sdkLR.ListenerRule.RuleArn
@@ -142,27 +164,7 @@ func (m *defaultListenerRuleManager) updateSDKListenerRuleWithSettings(ctx conte
142164
return nil
143165
}
144166

145-
func (m *defaultListenerRuleManager) updateSDKListenerRuleWithTags(ctx context.Context, resLR *elbv2model.ListenerRule, sdkLR ListenerRuleWithTags) error {
146-
desiredTags := m.trackingProvider.ResourceTags(resLR.Stack(), resLR, resLR.Spec.Tags)
147-
return m.taggingManager.ReconcileTags(ctx, awssdk.ToString(sdkLR.ListenerRule.RuleArn), desiredTags,
148-
WithCurrentTags(sdkLR.Tags),
149-
WithIgnoredTagKeys(m.externalManagedTags))
150-
}
151-
152-
func isSDKListenerRuleSettingsDrifted(lrSpec elbv2model.ListenerRuleSpec, sdkLR ListenerRuleWithTags,
153-
desiredActions []elbv2types.Action, desiredConditions []elbv2types.RuleCondition) bool {
154-
155-
if !cmp.Equal(desiredActions, sdkLR.ListenerRule.Actions, elbv2equality.CompareOptionForActions()) {
156-
return true
157-
}
158-
if !cmp.Equal(desiredConditions, sdkLR.ListenerRule.Conditions, elbv2equality.CompareOptionForRuleConditions()) {
159-
return true
160-
}
161-
162-
return false
163-
}
164-
165-
func buildSDKCreateListenerRuleInput(lrSpec elbv2model.ListenerRuleSpec, featureGates config.FeatureGates) (*elbv2sdk.CreateRuleInput, error) {
167+
func buildSDKCreateListenerRuleInput(lrSpec elbv2model.ListenerRuleSpec, desiredActionsAndConditions *resLRDesiredActionsAndConditionsPair, featureGates config.FeatureGates) (*elbv2sdk.CreateRuleInput, error) {
166168
ctx := context.Background()
167169
lsARN, err := lrSpec.ListenerARN.Resolve(ctx)
168170
if err != nil {
@@ -171,12 +173,20 @@ func buildSDKCreateListenerRuleInput(lrSpec elbv2model.ListenerRuleSpec, feature
171173
sdkObj := &elbv2sdk.CreateRuleInput{}
172174
sdkObj.ListenerArn = awssdk.String(lsARN)
173175
sdkObj.Priority = awssdk.Int32(lrSpec.Priority)
174-
actions, err := buildSDKActions(lrSpec.Actions, featureGates)
175-
if err != nil {
176-
return nil, err
176+
if desiredActionsAndConditions != nil && desiredActionsAndConditions.desiredActions != nil {
177+
sdkObj.Actions = desiredActionsAndConditions.desiredActions
178+
} else {
179+
actions, err := buildSDKActions(lrSpec.Actions, featureGates)
180+
if err != nil {
181+
return nil, err
182+
}
183+
sdkObj.Actions = actions
184+
}
185+
if desiredActionsAndConditions != nil && desiredActionsAndConditions.desiredConditions != nil {
186+
sdkObj.Conditions = desiredActionsAndConditions.desiredConditions
187+
} else {
188+
sdkObj.Conditions = buildSDKRuleConditions(lrSpec.Conditions)
177189
}
178-
sdkObj.Actions = actions
179-
sdkObj.Conditions = buildSDKRuleConditions(lrSpec.Conditions)
180190
return sdkObj, nil
181191
}
182192

@@ -187,6 +197,41 @@ func buildSDKModifyListenerRuleInput(_ elbv2model.ListenerRuleSpec, desiredActio
187197
return sdkObj
188198
}
189199

200+
func buildSDKSetRulePrioritiesInput(matchedResAndSDKLRsBySettings []resAndSDKListenerRulePair, unmatchedSDKLRs []ListenerRuleWithTags) *elbv2sdk.SetRulePrioritiesInput {
201+
var rulePriorities []elbv2types.RulePriorityPair
202+
var lastAvailablePriority int32 = 50000
203+
var sdkLRs []ListenerRuleWithTags
204+
205+
// Sort the unmatched existing SDK rules based on their priority to be pushed down in same order
206+
sort.Slice(unmatchedSDKLRs, func(i, j int) bool {
207+
priorityI, _ := strconv.Atoi(awssdk.ToString(unmatchedSDKLRs[i].ListenerRule.Priority))
208+
priorityJ, _ := strconv.Atoi(awssdk.ToString(unmatchedSDKLRs[j].ListenerRule.Priority))
209+
return priorityI < priorityJ
210+
})
211+
// Push down all the unmatched existing SDK rules on load balancer so that updated rules can take their place
212+
for _, sdkLR := range slices.Backward(unmatchedSDKLRs) {
213+
sdkLR.ListenerRule.Priority = awssdk.String(strconv.Itoa(int(lastAvailablePriority)))
214+
sdkLRs = append(sdkLRs, sdkLR)
215+
lastAvailablePriority--
216+
}
217+
//Re-Prioritize matched rules by settings
218+
for _, resAndSDKLR := range matchedResAndSDKLRsBySettings {
219+
resAndSDKLR.sdkLR.ListenerRule.Priority = awssdk.String(strconv.Itoa(int(resAndSDKLR.resLR.Spec.Priority)))
220+
sdkLRs = append(sdkLRs, resAndSDKLR.sdkLR)
221+
}
222+
for _, sdkLR := range sdkLRs {
223+
p, _ := strconv.ParseInt(awssdk.ToString(sdkLR.ListenerRule.Priority), 10, 32)
224+
rulePriorityPair := elbv2types.RulePriorityPair{
225+
RuleArn: sdkLR.ListenerRule.RuleArn,
226+
Priority: awssdk.Int32(int32(p)),
227+
}
228+
rulePriorities = append(rulePriorities, rulePriorityPair)
229+
}
230+
sdkObj := &elbv2sdk.SetRulePrioritiesInput{
231+
RulePriorities: rulePriorities,
232+
}
233+
return sdkObj
234+
}
190235
func buildResListenerRuleStatus(sdkLR ListenerRuleWithTags) elbv2model.ListenerRuleStatus {
191236
return elbv2model.ListenerRuleStatus{
192237
RuleARN: awssdk.ToString(sdkLR.ListenerRule.RuleArn),

‎pkg/deploy/elbv2/listener_rule_manager_test.go

+422
Large diffs are not rendered by default.

‎pkg/deploy/elbv2/listener_rule_synthesizer.go

+89-18
Original file line numberDiff line numberDiff line change
@@ -3,21 +3,26 @@ package elbv2
33
import (
44
"context"
55
awssdk "github.com/aws/aws-sdk-go-v2/aws"
6+
"github.com/aws/aws-sdk-go-v2/service/elasticloadbalancingv2/types"
67
"github.com/go-logr/logr"
8+
"github.com/google/go-cmp/cmp"
79
"k8s.io/apimachinery/pkg/util/sets"
810
"sigs.k8s.io/aws-load-balancer-controller/pkg/aws/services"
11+
"sigs.k8s.io/aws-load-balancer-controller/pkg/config"
12+
elbv2equality "sigs.k8s.io/aws-load-balancer-controller/pkg/equality/elbv2"
913
"sigs.k8s.io/aws-load-balancer-controller/pkg/model/core"
1014
elbv2model "sigs.k8s.io/aws-load-balancer-controller/pkg/model/elbv2"
1115
"strconv"
1216
)
1317

1418
// NewListenerRuleSynthesizer constructs new listenerRuleSynthesizer.
1519
func NewListenerRuleSynthesizer(elbv2Client services.ELBV2, taggingManager TaggingManager,
16-
lrManager ListenerRuleManager, logger logr.Logger, stack core.Stack) *listenerRuleSynthesizer {
20+
lrManager ListenerRuleManager, logger logr.Logger, featureGates config.FeatureGates, stack core.Stack) *listenerRuleSynthesizer {
1721
return &listenerRuleSynthesizer{
1822
elbv2Client: elbv2Client,
1923
lrManager: lrManager,
2024
logger: logger,
25+
featureGates: featureGates,
2126
taggingManager: taggingManager,
2227
stack: stack,
2328
}
@@ -26,6 +31,7 @@ func NewListenerRuleSynthesizer(elbv2Client services.ELBV2, taggingManager Taggi
2631
type listenerRuleSynthesizer struct {
2732
elbv2Client services.ELBV2
2833
lrManager ListenerRuleManager
34+
featureGates config.FeatureGates
2935
logger logr.Logger
3036
taggingManager TaggingManager
3137

@@ -61,26 +67,60 @@ func (s *listenerRuleSynthesizer) PostSynthesize(ctx context.Context) error {
6167
}
6268

6369
func (s *listenerRuleSynthesizer) synthesizeListenerRulesOnListener(ctx context.Context, lsARN string, resLRs []*elbv2model.ListenerRule) error {
70+
// Find existing listener rules on the load balancer
6471
sdkLRs, err := s.findSDKListenersRulesOnLS(ctx, lsARN)
6572
if err != nil {
6673
return err
6774
}
68-
69-
matchedResAndSDKLRs, unmatchedResLRs, unmatchedSDKLRs := matchResAndSDKListenerRules(resLRs, sdkLRs)
70-
for _, sdkLR := range unmatchedSDKLRs {
71-
if err := s.lrManager.Delete(ctx, sdkLR); err != nil {
75+
// Build desired actions and conditions pairs for resource listener rules.
76+
resLRDesiredActionsAndConditionsPairs := make(map[*elbv2model.ListenerRule]*resLRDesiredActionsAndConditionsPair, len(resLRs))
77+
for _, resLR := range resLRs {
78+
resLRDesiredActionsAndConditionsPair, err := buildResLRDesiredActionsAndConditionsPair(resLR, s.featureGates)
79+
if err != nil {
80+
return err
81+
}
82+
resLRDesiredActionsAndConditionsPairs[resLR] = resLRDesiredActionsAndConditionsPair
83+
}
84+
// matchedResAndSDKLRsBySettings : A slice of matched resLR and SDKLR rule pairs that have matching settings like actions and conditions. These needs to be only reprioratized to their corresponding priorities
85+
// matchedResAndSDKLRsByPriority : A slice of matched resLR and SDKLR rule pairs that have matching priorities but not settings like actions and conditions. These needs to be modified in place to avoid any 503 errors
86+
// unmatchedResLRs : A slice of resLR that do not have a corresponding match in the sdkLRs. These rules need to be created on the load balancer.
87+
// unmatchedSDKLRs : A slice of sdkLRs that do not have a corresponding match in the resLRs. These rules need to be first pushed down in the priority so that the new rules are created/modified at higher priority first and then deleted from the load balancer to avoid any 503 errors.
88+
matchedResAndSDKLRsBySettings, matchedResAndSDKLRsByPriority, unmatchedResLRs, unmatchedSDKLRs, err := s.matchResAndSDKListenerRules(resLRs, sdkLRs, resLRDesiredActionsAndConditionsPairs)
89+
if err != nil {
90+
return err
91+
}
92+
// Re-prioritize matched listener rules.
93+
if len(matchedResAndSDKLRsBySettings) > 0 {
94+
err := s.lrManager.SetRulePriorities(ctx, matchedResAndSDKLRsBySettings, unmatchedSDKLRs)
95+
if err != nil {
96+
return err
97+
}
98+
}
99+
// Modify rules in place which are matching priorities
100+
for _, resAndSDKLR := range matchedResAndSDKLRsByPriority {
101+
lsStatus, err := s.lrManager.UpdateRules(ctx, resAndSDKLR.resLR, resAndSDKLR.sdkLR, resLRDesiredActionsAndConditionsPairs[resAndSDKLR.resLR])
102+
if err != nil {
72103
return err
73104
}
105+
resAndSDKLR.resLR.SetStatus(lsStatus)
74106
}
107+
// Create all the new rules on the LB
75108
for _, resLR := range unmatchedResLRs {
76-
lrStatus, err := s.lrManager.Create(ctx, resLR)
109+
lrStatus, err := s.lrManager.Create(ctx, resLR, resLRDesiredActionsAndConditionsPairs[resLR])
77110
if err != nil {
78111
return err
79112
}
80113
resLR.SetStatus(lrStatus)
81114
}
82-
for _, resAndSDKLR := range matchedResAndSDKLRs {
83-
lsStatus, err := s.lrManager.Update(ctx, resAndSDKLR.resLR, resAndSDKLR.sdkLR)
115+
// Delete all unmatched sdk LRs which were pushed down as new rules are either modified or created at higher priority
116+
for _, sdkLR := range unmatchedSDKLRs {
117+
if err := s.lrManager.Delete(ctx, sdkLR); err != nil {
118+
return err
119+
}
120+
}
121+
// Update existing listener rules on the load balancer for their tags
122+
for _, resAndSDKLR := range matchedResAndSDKLRsBySettings {
123+
lsStatus, err := s.lrManager.UpdateRulesTags(ctx, resAndSDKLR.resLR, resAndSDKLR.sdkLR)
84124
if err != nil {
85125
return err
86126
}
@@ -110,31 +150,62 @@ type resAndSDKListenerRulePair struct {
110150
sdkLR ListenerRuleWithTags
111151
}
112152

113-
func matchResAndSDKListenerRules(resLRs []*elbv2model.ListenerRule, sdkLRs []ListenerRuleWithTags) ([]resAndSDKListenerRulePair, []*elbv2model.ListenerRule, []ListenerRuleWithTags) {
114-
var matchedResAndSDKLRs []resAndSDKListenerRulePair
153+
type resLRDesiredActionsAndConditionsPair struct {
154+
desiredActions []types.Action
155+
desiredConditions []types.RuleCondition
156+
}
157+
158+
func (s *listenerRuleSynthesizer) matchResAndSDKListenerRules(resLRs []*elbv2model.ListenerRule, unmatchedSDKLRs []ListenerRuleWithTags, resLRDesiredActionsAndConditionsPairs map[*elbv2model.ListenerRule]*resLRDesiredActionsAndConditionsPair) ([]resAndSDKListenerRulePair, []resAndSDKListenerRulePair, []*elbv2model.ListenerRule, []ListenerRuleWithTags, error) {
159+
var matchedResAndSDKLRsBySettings []resAndSDKListenerRulePair
160+
var matchedResAndSDKLRsByPriority []resAndSDKListenerRulePair
115161
var unmatchedResLRs []*elbv2model.ListenerRule
116-
var unmatchedSDKLRs []ListenerRuleWithTags
162+
var resLRsToCreate []*elbv2model.ListenerRule
163+
var sdkLRsToDelete []ListenerRuleWithTags
117164

118-
resLRByPriority := mapResListenerRuleByPriority(resLRs)
119-
sdkLRByPriority := mapSDKListenerRuleByPriority(sdkLRs)
165+
for _, resLR := range resLRs {
166+
resLRDesiredActionsAndConditionsPair := resLRDesiredActionsAndConditionsPairs[resLR]
167+
found := false
168+
for i := 0; i < len(unmatchedSDKLRs); i++ {
169+
sdkLR := unmatchedSDKLRs[i]
170+
if cmp.Equal(resLRDesiredActionsAndConditionsPair.desiredActions, sdkLR.ListenerRule.Actions, elbv2equality.CompareOptionForActions()) &&
171+
cmp.Equal(resLRDesiredActionsAndConditionsPair.desiredConditions, sdkLR.ListenerRule.Conditions, elbv2equality.CompareOptionForRuleConditions()) {
172+
sdkLRPriority, _ := strconv.ParseInt(awssdk.ToString(sdkLR.ListenerRule.Priority), 10, 64)
173+
if resLR.Spec.Priority != int32(sdkLRPriority) {
174+
matchedResAndSDKLRsBySettings = append(matchedResAndSDKLRsBySettings, resAndSDKListenerRulePair{
175+
resLR: resLR,
176+
sdkLR: sdkLR,
177+
})
178+
}
179+
unmatchedSDKLRs = append(unmatchedSDKLRs[:i], unmatchedSDKLRs[i+1:]...)
180+
i--
181+
found = true
182+
break
183+
}
184+
}
185+
if !found {
186+
unmatchedResLRs = append(unmatchedResLRs, resLR)
187+
}
188+
}
189+
190+
resLRByPriority := mapResListenerRuleByPriority(unmatchedResLRs)
191+
sdkLRByPriority := mapSDKListenerRuleByPriority(unmatchedSDKLRs)
120192
resLRPriorities := sets.Int32KeySet(resLRByPriority)
121193
sdkLRPriorities := sets.Int32KeySet(sdkLRByPriority)
122194
for _, priority := range resLRPriorities.Intersection(sdkLRPriorities).List() {
123195
resLR := resLRByPriority[priority]
124196
sdkLR := sdkLRByPriority[priority]
125-
matchedResAndSDKLRs = append(matchedResAndSDKLRs, resAndSDKListenerRulePair{
197+
matchedResAndSDKLRsByPriority = append(matchedResAndSDKLRsByPriority, resAndSDKListenerRulePair{
126198
resLR: resLR,
127199
sdkLR: sdkLR,
128200
})
129201
}
130202
for _, priority := range resLRPriorities.Difference(sdkLRPriorities).List() {
131-
unmatchedResLRs = append(unmatchedResLRs, resLRByPriority[priority])
203+
resLRsToCreate = append(resLRsToCreate, resLRByPriority[priority])
132204
}
133205
for _, priority := range sdkLRPriorities.Difference(resLRPriorities).List() {
134-
unmatchedSDKLRs = append(unmatchedSDKLRs, sdkLRByPriority[priority])
206+
sdkLRsToDelete = append(sdkLRsToDelete, sdkLRByPriority[priority])
135207
}
136-
137-
return matchedResAndSDKLRs, unmatchedResLRs, unmatchedSDKLRs
208+
return matchedResAndSDKLRsBySettings, matchedResAndSDKLRsByPriority, resLRsToCreate, sdkLRsToDelete, nil
138209
}
139210

140211
func mapResListenerRuleByPriority(resLRs []*elbv2model.ListenerRule) map[int32]*elbv2model.ListenerRule {

‎pkg/deploy/elbv2/listener_rule_synthesizer_test.go

+1,280
Large diffs are not rendered by default.

‎pkg/deploy/elbv2/listener_utils.go

+12
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,18 @@ const (
1616
defaultWaitLSExistenceTimeout = 20 * time.Second
1717
)
1818

19+
func buildResLRDesiredActionsAndConditionsPair(resLR *elbv2model.ListenerRule, featureGates config.FeatureGates) (*resLRDesiredActionsAndConditionsPair, error) {
20+
desiredActions, err := buildSDKActions(resLR.Spec.Actions, featureGates)
21+
if err != nil {
22+
return nil, err
23+
}
24+
desiredConditions := buildSDKRuleConditions(resLR.Spec.Conditions)
25+
return &resLRDesiredActionsAndConditionsPair{
26+
desiredActions: desiredActions,
27+
desiredConditions: desiredConditions,
28+
}, err
29+
}
30+
1931
func buildSDKActions(modelActions []elbv2model.Action, featureGates config.FeatureGates) ([]elbv2types.Action, error) {
2032
var sdkActions []elbv2types.Action
2133
if len(modelActions) != 0 {

‎pkg/deploy/stack_deployer.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ func (d *defaultStackDeployer) Deploy(ctx context.Context, stack core.Stack) err
9393
elbv2.NewTargetGroupSynthesizer(d.cloud.ELBV2(), d.trackingProvider, d.elbv2TaggingManager, d.elbv2TGManager, d.logger, d.featureGates, stack),
9494
elbv2.NewLoadBalancerSynthesizer(d.cloud.ELBV2(), d.trackingProvider, d.elbv2TaggingManager, d.elbv2LBManager, d.logger, d.featureGates, d.controllerConfig, stack),
9595
elbv2.NewListenerSynthesizer(d.cloud.ELBV2(), d.elbv2TaggingManager, d.elbv2LSManager, d.logger, stack),
96-
elbv2.NewListenerRuleSynthesizer(d.cloud.ELBV2(), d.elbv2TaggingManager, d.elbv2LRManager, d.logger, stack),
96+
elbv2.NewListenerRuleSynthesizer(d.cloud.ELBV2(), d.elbv2TaggingManager, d.elbv2LRManager, d.logger, d.featureGates, stack),
9797
elbv2.NewTargetGroupBindingSynthesizer(d.k8sClient, d.trackingProvider, d.elbv2TGBManager, d.logger, stack),
9898
}
9999

0 commit comments

Comments
 (0)
Please sign in to comment.