@@ -6,24 +6,29 @@ import (
6
6
elbv2sdk "github.com/aws/aws-sdk-go-v2/service/elasticloadbalancingv2"
7
7
elbv2types "github.com/aws/aws-sdk-go-v2/service/elasticloadbalancingv2/types"
8
8
"github.com/go-logr/logr"
9
- "github.com/google/go-cmp/cmp"
10
9
"github.com/pkg/errors"
11
10
"sigs.k8s.io/aws-load-balancer-controller/pkg/aws/services"
12
11
"sigs.k8s.io/aws-load-balancer-controller/pkg/config"
13
12
"sigs.k8s.io/aws-load-balancer-controller/pkg/deploy/tracking"
14
- elbv2equality "sigs.k8s.io/aws-load-balancer-controller/pkg/equality/elbv2"
15
13
elbv2model "sigs.k8s.io/aws-load-balancer-controller/pkg/model/elbv2"
16
14
"sigs.k8s.io/aws-load-balancer-controller/pkg/runtime"
15
+ "slices"
16
+ "sort"
17
+ "strconv"
17
18
"time"
18
19
)
19
20
20
21
// ListenerRuleManager is responsible for create/update/delete ListenerRule resources.
21
22
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 )
23
24
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 )
25
28
26
29
Delete (ctx context.Context , sdkLR ListenerRuleWithTags ) error
30
+
31
+ SetRulePriorities (ctx context.Context , matchedResAndSDKLRsBySettings []resAndSDKListenerRulePair , unmatchedSDKLRs []ListenerRuleWithTags ) error
27
32
}
28
33
29
34
// NewDefaultListenerRuleManager constructs new defaultListenerRuleManager.
@@ -54,8 +59,8 @@ type defaultListenerRuleManager struct {
54
59
waitLSExistenceTimeout time.Duration
55
60
}
56
61
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 )
59
64
if err != nil {
60
65
return elbv2model.ListenerRuleStatus {}, err
61
66
}
@@ -90,13 +95,17 @@ func (m *defaultListenerRuleManager) Create(ctx context.Context, resLR *elbv2mod
90
95
return buildResListenerRuleStatus (sdkLR ), nil
91
96
}
92
97
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 ) {
94
99
if m .featureGates .Enabled (config .ListenerRulesTagging ) {
95
100
if err := m .updateSDKListenerRuleWithTags (ctx , resLR , sdkLR ); err != nil {
96
101
return elbv2model.ListenerRuleStatus {}, err
97
102
}
98
103
}
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 {
100
109
return elbv2model.ListenerRuleStatus {}, err
101
110
}
102
111
return buildResListenerRuleStatus (sdkLR ), nil
@@ -116,15 +125,28 @@ func (m *defaultListenerRuleManager) Delete(ctx context.Context, sdkLR ListenerR
116
125
return nil
117
126
}
118
127
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 {
122
133
return err
123
134
}
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
128
150
129
151
req := buildSDKModifyListenerRuleInput (resLR .Spec , desiredActions , desiredConditions )
130
152
req .RuleArn = sdkLR .ListenerRule .RuleArn
@@ -142,27 +164,7 @@ func (m *defaultListenerRuleManager) updateSDKListenerRuleWithSettings(ctx conte
142
164
return nil
143
165
}
144
166
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 ) {
166
168
ctx := context .Background ()
167
169
lsARN , err := lrSpec .ListenerARN .Resolve (ctx )
168
170
if err != nil {
@@ -171,12 +173,20 @@ func buildSDKCreateListenerRuleInput(lrSpec elbv2model.ListenerRuleSpec, feature
171
173
sdkObj := & elbv2sdk.CreateRuleInput {}
172
174
sdkObj .ListenerArn = awssdk .String (lsARN )
173
175
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 )
177
189
}
178
- sdkObj .Actions = actions
179
- sdkObj .Conditions = buildSDKRuleConditions (lrSpec .Conditions )
180
190
return sdkObj , nil
181
191
}
182
192
@@ -187,6 +197,41 @@ func buildSDKModifyListenerRuleInput(_ elbv2model.ListenerRuleSpec, desiredActio
187
197
return sdkObj
188
198
}
189
199
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
+ }
190
235
func buildResListenerRuleStatus (sdkLR ListenerRuleWithTags ) elbv2model.ListenerRuleStatus {
191
236
return elbv2model.ListenerRuleStatus {
192
237
RuleARN : awssdk .ToString (sdkLR .ListenerRule .RuleArn ),
0 commit comments