@@ -58,7 +58,7 @@ func (r *AWSCluster) ValidateCreate() (admission.Warnings, error) {
58
58
allErrs = append (allErrs , r .Spec .AdditionalTags .Validate ()... )
59
59
allErrs = append (allErrs , r .Spec .S3Bucket .Validate ()... )
60
60
allErrs = append (allErrs , r .validateNetwork ()... )
61
- allErrs = append (allErrs , r .validateControlPlaneLB ()... )
61
+ allErrs = append (allErrs , r .validateControlPlaneLBs ()... )
62
62
63
63
return nil , aggregateObjErrors (r .GroupVersionKind ().GroupKind (), r .Name , allErrs )
64
64
}
@@ -85,51 +85,18 @@ func (r *AWSCluster) ValidateUpdate(old runtime.Object) (admission.Warnings, err
85
85
)
86
86
}
87
87
88
- newLoadBalancer := & AWSLoadBalancerSpec {}
89
- existingLoadBalancer := & AWSLoadBalancerSpec {}
90
-
91
- if r .Spec .ControlPlaneLoadBalancer != nil {
92
- newLoadBalancer = r .Spec .ControlPlaneLoadBalancer .DeepCopy ()
88
+ // Validate the control plane load balancers.
89
+ lbs := map [* AWSLoadBalancerSpec ]* AWSLoadBalancerSpec {
90
+ oldC .Spec .ControlPlaneLoadBalancer : r .Spec .ControlPlaneLoadBalancer ,
91
+ oldC .Spec .SecondaryControlPlaneLoadBalancer : r .Spec .SecondaryControlPlaneLoadBalancer ,
93
92
}
94
93
95
- if oldC .Spec .ControlPlaneLoadBalancer != nil {
96
- existingLoadBalancer = oldC .Spec .ControlPlaneLoadBalancer .DeepCopy ()
97
- }
98
- if oldC .Spec .ControlPlaneLoadBalancer == nil {
99
- // If old scheme was nil, the only value accepted here is the default value: internet-facing
100
- if newLoadBalancer .Scheme != nil && newLoadBalancer .Scheme .String () != ELBSchemeInternetFacing .String () {
101
- allErrs = append (allErrs ,
102
- field .Invalid (field .NewPath ("spec" , "controlPlaneLoadBalancer" , "scheme" ),
103
- r .Spec .ControlPlaneLoadBalancer .Scheme , "field is immutable, default value was set to internet-facing" ),
104
- )
105
- }
106
- } else {
107
- // If old scheme was not nil, the new scheme should be the same.
108
- if ! cmp .Equal (existingLoadBalancer .Scheme , newLoadBalancer .Scheme ) {
109
- allErrs = append (allErrs ,
110
- field .Invalid (field .NewPath ("spec" , "controlPlaneLoadBalancer" , "scheme" ),
111
- r .Spec .ControlPlaneLoadBalancer .Scheme , "field is immutable" ),
112
- )
113
- }
114
- // The name must be defined when the AWSCluster is created. If it is not defined,
115
- // then the controller generates a default name at runtime, but does not store it,
116
- // so the name remains nil. In either case, the name cannot be changed.
117
- if ! cmp .Equal (existingLoadBalancer .Name , newLoadBalancer .Name ) {
118
- allErrs = append (allErrs ,
119
- field .Invalid (field .NewPath ("spec" , "controlPlaneLoadBalancer" , "name" ),
120
- r .Spec .ControlPlaneLoadBalancer .Name , "field is immutable" ),
121
- )
94
+ for oldLB , newLB := range lbs {
95
+ if oldLB == nil && newLB == nil {
96
+ continue
122
97
}
123
- }
124
98
125
- // Block the update for Protocol :
126
- // - if it was not set in old spec but added in new spec
127
- // - if it was set in old spec but changed in new spec
128
- if ! cmp .Equal (newLoadBalancer .HealthCheckProtocol , existingLoadBalancer .HealthCheckProtocol ) {
129
- allErrs = append (allErrs ,
130
- field .Invalid (field .NewPath ("spec" , "controlPlaneLoadBalancer" , "healthCheckProtocol" ),
131
- newLoadBalancer .HealthCheckProtocol , "field is immutable once set" ),
132
- )
99
+ allErrs = append (allErrs , r .validateControlPlaneLoadBalancerUpdate (oldLB , newLB )... )
133
100
}
134
101
135
102
if ! cmp .Equal (oldC .Spec .ControlPlaneEndpoint , clusterv1.APIEndpoint {}) &&
@@ -174,6 +141,49 @@ func (r *AWSCluster) ValidateUpdate(old runtime.Object) (admission.Warnings, err
174
141
return nil , aggregateObjErrors (r .GroupVersionKind ().GroupKind (), r .Name , allErrs )
175
142
}
176
143
144
+ func (r * AWSCluster ) validateControlPlaneLoadBalancerUpdate (oldlb , newlb * AWSLoadBalancerSpec ) field.ErrorList {
145
+ var allErrs field.ErrorList
146
+
147
+ if oldlb == nil {
148
+ // If old scheme was nil, the only value accepted here is the default value: internet-facing
149
+ if newlb .Scheme != nil && newlb .Scheme .String () != ELBSchemeInternetFacing .String () {
150
+ allErrs = append (allErrs ,
151
+ field .Invalid (field .NewPath ("spec" , "controlPlaneLoadBalancer" , "scheme" ),
152
+ newlb .Scheme , "field is immutable, default value was set to internet-facing" ),
153
+ )
154
+ }
155
+ } else {
156
+ // If old scheme was not nil, the new scheme should be the same.
157
+ if ! cmp .Equal (oldlb .Scheme , newlb .Scheme ) {
158
+ allErrs = append (allErrs ,
159
+ field .Invalid (field .NewPath ("spec" , "controlPlaneLoadBalancer" , "scheme" ),
160
+ newlb .Scheme , "field is immutable" ),
161
+ )
162
+ }
163
+ // The name must be defined when the AWSCluster is created. If it is not defined,
164
+ // then the controller generates a default name at runtime, but does not store it,
165
+ // so the name remains nil. In either case, the name cannot be changed.
166
+ if ! cmp .Equal (oldlb .Name , newlb .Name ) {
167
+ allErrs = append (allErrs ,
168
+ field .Invalid (field .NewPath ("spec" , "controlPlaneLoadBalancer" , "name" ),
169
+ newlb .Name , "field is immutable" ),
170
+ )
171
+ }
172
+ }
173
+
174
+ // Block the update for Protocol :
175
+ // - if it was not set in old spec but added in new spec
176
+ // - if it was set in old spec but changed in new spec
177
+ if ! cmp .Equal (newlb .HealthCheckProtocol , oldlb .HealthCheckProtocol ) {
178
+ allErrs = append (allErrs ,
179
+ field .Invalid (field .NewPath ("spec" , "controlPlaneLoadBalancer" , "healthCheckProtocol" ),
180
+ newlb .HealthCheckProtocol , "field is immutable once set" ),
181
+ )
182
+ }
183
+
184
+ return allErrs
185
+ }
186
+
177
187
// Default satisfies the defaulting webhook interface.
178
188
func (r * AWSCluster ) Default () {
179
189
SetObjectDefaults_AWSCluster (r )
@@ -243,26 +253,48 @@ func (r *AWSCluster) validateNetwork() field.ErrorList {
243
253
allErrs = append (allErrs , field .Invalid (field .NewPath ("additionalControlPlaneIngressRules" ), r .Spec .NetworkSpec .AdditionalControlPlaneIngressRules , "CIDR blocks and security group IDs or security group roles cannot be used together" ))
244
254
}
245
255
}
256
+
246
257
return allErrs
247
258
}
248
259
249
- func (r * AWSCluster ) validateControlPlaneLB () field.ErrorList {
260
+ func (r * AWSCluster ) validateControlPlaneLBs () field.ErrorList {
250
261
var allErrs field.ErrorList
251
262
252
- if r .Spec .ControlPlaneLoadBalancer == nil {
253
- return allErrs
263
+ // If the secondary is defined, check that the name is not empty and different from the primary.
264
+ // Also, ensure that the secondary load balancer is an NLB
265
+ if r .Spec .SecondaryControlPlaneLoadBalancer != nil {
266
+ if r .Spec .SecondaryControlPlaneLoadBalancer .Name == nil || * r .Spec .SecondaryControlPlaneLoadBalancer .Name == "" {
267
+ allErrs = append (allErrs , field .Invalid (field .NewPath ("spec" , "secondaryControlPlaneLoadBalancer" , "name" ), r .Spec .SecondaryControlPlaneLoadBalancer .Name , "secondary controlPlaneLoadBalancer.name cannot be empty" ))
268
+ }
269
+
270
+ if r .Spec .SecondaryControlPlaneLoadBalancer .Name == r .Spec .ControlPlaneLoadBalancer .Name {
271
+ allErrs = append (allErrs , field .Invalid (field .NewPath ("spec" , "secondaryControlPlaneLoadBalancer" , "name" ), r .Spec .SecondaryControlPlaneLoadBalancer .Name , "field must be different from controlPlaneLoadBalancer.name" ))
272
+ }
273
+
274
+ if r .Spec .SecondaryControlPlaneLoadBalancer .Scheme .Equals (r .Spec .ControlPlaneLoadBalancer .Scheme ) {
275
+ allErrs = append (allErrs , field .Invalid (field .NewPath ("spec" , "secondaryControlPlaneLoadBalancer" , "scheme" ), r .Spec .SecondaryControlPlaneLoadBalancer .Scheme , "control plane load balancers must have different schemes" ))
276
+ }
277
+
278
+ if r .Spec .SecondaryControlPlaneLoadBalancer .LoadBalancerType != LoadBalancerTypeNLB {
279
+ allErrs = append (allErrs , field .Invalid (field .NewPath ("spec" , "secondaryControlPlaneLoadBalancer" , "loadBalancerType" ), r .Spec .SecondaryControlPlaneLoadBalancer .LoadBalancerType , "secondary control plane load balancer must be a Network Load Balancer" ))
280
+ }
254
281
}
255
282
256
283
// Additional listeners are only supported for NLBs.
257
- if len ( r . Spec . ControlPlaneLoadBalancer . AdditionalListeners ) > 0 {
258
- if r . Spec . ControlPlaneLoadBalancer . LoadBalancerType != LoadBalancerTypeNLB {
259
- allErrs = append ( allErrs , field . Invalid ( field . NewPath ( "spec" , "controlPlaneLoadBalancer" , "additionalListeners" ), r .Spec .ControlPlaneLoadBalancer . AdditionalListeners , "additional listeners are only supported for NLB load balancers" ))
260
- }
284
+ // Validate the control plane load balancers.
285
+ loadBalancers := [] * AWSLoadBalancerSpec {
286
+ r .Spec .ControlPlaneLoadBalancer ,
287
+ r . Spec . SecondaryControlPlaneLoadBalancer ,
261
288
}
289
+ for _ , cp := range loadBalancers {
290
+ if cp == nil {
291
+ continue
292
+ }
262
293
263
- for _ , rule := range r .Spec .ControlPlaneLoadBalancer .IngressRules {
264
- if (rule .CidrBlocks != nil || rule .IPv6CidrBlocks != nil ) && (rule .SourceSecurityGroupIDs != nil || rule .SourceSecurityGroupRoles != nil ) {
265
- allErrs = append (allErrs , field .Invalid (field .NewPath ("spec" , "controlPlaneLoadBalancer" , "ingressRules" ), r .Spec .ControlPlaneLoadBalancer .IngressRules , "CIDR blocks and security group IDs or security group roles cannot be used together" ))
294
+ for _ , rule := range cp .IngressRules {
295
+ if (rule .CidrBlocks != nil || rule .IPv6CidrBlocks != nil ) && (rule .SourceSecurityGroupIDs != nil || rule .SourceSecurityGroupRoles != nil ) {
296
+ allErrs = append (allErrs , field .Invalid (field .NewPath ("spec" , "controlPlaneLoadBalancer" , "ingressRules" ), r .Spec .ControlPlaneLoadBalancer .IngressRules , "CIDR blocks and security group IDs or security group roles cannot be used together" ))
297
+ }
266
298
}
267
299
}
268
300
0 commit comments