@@ -52,9 +52,9 @@ const (
52
52
// IP address, a firewall rule, a target pool, and a forwarding rule. This
53
53
// function has to manage all of them.
54
54
//
55
- // Due to an interesting series of design decisions, this handles both creating
56
- // new load balancers and updating existing load balancers, recognizing when
57
- // each is needed .
55
+ // This function handles both creating new load balancers and updating existing load balancers,
56
+ // recognizing when each is needed.
57
+ // This approach is resilient, for example if we are interrupted part-way during creation .
58
58
func (g * Cloud ) ensureExternalLoadBalancer (clusterName string , clusterID string , apiService * v1.Service , existingFwdRule * compute.ForwardingRule , nodes []* v1.Node ) (* v1.LoadBalancerStatus , error ) {
59
59
// Process services with LoadBalancerClass "networking.gke.io/l4-regional-external-legacy" used for this controller.
60
60
// LoadBalancerClass can't be updated so we know this controller should process the NetLB.
@@ -112,134 +112,23 @@ func (g *Cloud) ensureExternalLoadBalancer(clusterName string, clusterID string,
112
112
g .deleteWrongNetworkTieredResources (loadBalancerName , lbRefStr , netTier )
113
113
}
114
114
115
- // If the feature gate is not enabled, we check for multiple protocols and error out.
116
- if ! g .AlphaFeatureGate .Enabled (AlphaFeatureMultiProtocolLB ) {
117
- fwdRuleExists , fwdRuleNeedsUpdate , fwdRuleIP , err := g .forwardingRuleNeedsUpdate (loadBalancerName , g .region , requestedIP , ports )
118
- if err != nil {
119
- return nil , err
120
- }
121
- if ! fwdRuleExists {
122
- klog .V (2 ).Infof ("ensureExternalLoadBalancer(%s): Forwarding rule %v doesn't exist." , lbRefStr , loadBalancerName )
123
- }
124
- // Single-protocol logic
125
- ipAddressToUse , isSafeToReleaseIP , err := g .ensureIPAddress (loadBalancerName , lbRefStr , apiService .Spec .LoadBalancerIP , fwdRuleIP , netTier )
126
- if err != nil {
127
- return nil , err
128
- }
129
- defer func () {
130
- if isSafeToReleaseIP {
131
- if err := g .DeleteRegionAddress (loadBalancerName , g .region ); err != nil && ! isNotFound (err ) {
132
- klog .Errorf ("ensureExternalLoadBalancer(%s): Failed to release static IP %s in region %v: %v." , lbRefStr , ipAddressToUse , g .region , err )
133
- } else if isNotFound (err ) {
134
- klog .V (2 ).Infof ("ensureExternalLoadBalancer(%s): IP address %s is not reserved." , lbRefStr , ipAddressToUse )
135
- } else {
136
- klog .Infof ("ensureExternalLoadBalancer(%s): Released static IP %s." , lbRefStr , ipAddressToUse )
137
- }
138
- } else {
139
- klog .Warningf ("ensureExternalLoadBalancer(%s): Orphaning static IP %s in region %v: %v." , lbRefStr , ipAddressToUse , g .region , err )
140
- }
141
- }()
142
-
143
- sourceRanges , err := servicehelpers .GetLoadBalancerSourceRanges (apiService )
144
- if err != nil {
145
- return nil , err
146
- }
147
-
148
- firewallExists , firewallNeedsUpdate , err := g .firewallNeedsUpdate (loadBalancerName , serviceName .String (), ipAddressToUse , ports , sourceRanges )
149
- if err != nil {
150
- return nil , err
151
- }
152
-
153
- if firewallNeedsUpdate {
154
- desc := makeFirewallDescription (serviceName .String (), ipAddressToUse )
155
- if firewallExists {
156
- klog .Infof ("ensureExternalLoadBalancer(%s): Updating firewall." , lbRefStr )
157
- if err := g .updateFirewall (apiService , MakeFirewallName (loadBalancerName ), desc , ipAddressToUse , sourceRanges , ports , hosts ); err != nil {
158
- return nil , err
159
- }
160
- klog .Infof ("ensureExternalLoadBalancer(%s): Updated firewall." , lbRefStr )
161
- } else {
162
- klog .Infof ("ensureExternalLoadBalancer(%s): Creating firewall." , lbRefStr )
163
- if err := g .createFirewall (apiService , MakeFirewallName (loadBalancerName ), desc , ipAddressToUse , sourceRanges , ports , hosts ); err != nil {
164
- return nil , err
165
- }
166
- klog .Infof ("ensureExternalLoadBalancer(%s): Created firewall." , lbRefStr )
167
- }
168
- }
169
-
170
- tpExists , tpNeedsRecreation , err := g .targetPoolNeedsRecreation (loadBalancerName , g .region , apiService .Spec .SessionAffinity )
171
- if err != nil {
172
- return nil , err
173
- }
174
- if ! tpExists {
175
- klog .Infof ("ensureExternalLoadBalancer(%s): Target pool for service doesn't exist." , lbRefStr )
176
- }
177
-
178
- var hcToCreate , hcToDelete * compute.HttpHealthCheck
179
- hcLocalTrafficExisting , err := g .GetHTTPHealthCheck (loadBalancerName )
180
- if err != nil && ! isHTTPErrorCode (err , http .StatusNotFound ) {
181
- return nil , fmt .Errorf ("error checking HTTP health check for load balancer (%s): %v" , lbRefStr , err )
182
- }
183
- if path , healthCheckNodePort := servicehelpers .GetServiceHealthCheckPathPort (apiService ); path != "" {
184
- klog .V (4 ).Infof ("ensureExternalLoadBalancer(%s): Service needs local traffic health checks on: %d%s." , lbRefStr , healthCheckNodePort , path )
185
- if hcLocalTrafficExisting == nil {
186
- klog .V (2 ).Infof ("ensureExternalLoadBalancer(%s): Updating from nodes health checks to local traffic health checks." , lbRefStr )
187
- hcToDelete = makeHTTPHealthCheck (MakeNodesHealthCheckName (clusterID ), GetNodesHealthCheckPath (), GetNodesHealthCheckPort ())
188
- tpNeedsRecreation = true
189
- }
190
- hcToCreate = makeHTTPHealthCheck (loadBalancerName , path , healthCheckNodePort )
191
- } else {
192
- klog .V (4 ).Infof ("ensureExternalLoadBalancer(%s): Service needs nodes health checks." , lbRefStr )
193
- if hcLocalTrafficExisting != nil {
194
- klog .V (2 ).Infof ("ensureExternalLoadBalancer(%s): Updating from local traffic health checks to nodes health checks." , lbRefStr )
195
- hcToDelete = hcLocalTrafficExisting
196
- tpNeedsRecreation = true
197
- }
198
- hcToCreate = makeHTTPHealthCheck (MakeNodesHealthCheckName (clusterID ), GetNodesHealthCheckPath (), GetNodesHealthCheckPort ())
199
- }
200
-
201
- if fwdRuleExists && (fwdRuleNeedsUpdate || tpNeedsRecreation ) {
202
- isSafeToReleaseIP = false
203
- if err := g .DeleteRegionForwardingRule (loadBalancerName , g .region ); err != nil && ! isNotFound (err ) {
204
- return nil , fmt .Errorf ("failed to delete existing forwarding rule for load balancer (%s) update: %v" , lbRefStr , err )
205
- }
206
- klog .Infof ("ensureExternalLoadBalancer(%s): Deleted forwarding rule." , lbRefStr )
207
- }
208
-
209
- if err := g .ensureTargetPoolAndHealthCheck (tpExists , tpNeedsRecreation , apiService , loadBalancerName , clusterID , ipAddressToUse , hosts , hcToCreate , hcToDelete ); err != nil {
210
- return nil , err
211
- }
212
-
213
- if tpNeedsRecreation || fwdRuleNeedsUpdate {
214
- klog .Infof ("ensureExternalLoadBalancer(%s): Creating forwarding rule, IP %s (tier: %s)." , lbRefStr , ipAddressToUse , netTier )
215
- if err := createForwardingRule (g , loadBalancerName , serviceName .String (), g .region , ipAddressToUse , g .targetPoolURL (loadBalancerName ), ports , netTier , g .enableDiscretePortForwarding ); err != nil {
216
- return nil , fmt .Errorf ("failed to create forwarding rule for load balancer (%s): %v" , lbRefStr , err )
217
- }
218
- isSafeToReleaseIP = true
219
- klog .Infof ("ensureExternalLoadBalancer(%s): Created forwarding rule, IP %s." , lbRefStr , ipAddressToUse )
220
- }
221
-
222
- status := & v1.LoadBalancerStatus {}
223
- status .Ingress = []v1.LoadBalancerIngress {{IP : ipAddressToUse }}
224
-
225
- return status , nil
226
- }
227
-
228
115
// Multi-protocol logic starts here
229
116
groupedPorts := groupPortsByProtocol (ports )
230
117
var fwdRuleIP string
231
118
232
119
// We need to determine the IP address for all forwarding rules.
233
120
// We check if any of the forwarding rules already exist and use their IP.
234
- for protocol := range groupedPorts {
235
- frName := g .getProtocolForwardingRuleName (loadBalancerName , protocol )
236
- fwd , err := g .GetRegionForwardingRule (frName , g .region )
237
- if err != nil && ! isNotFound (err ) {
238
- return nil , err
239
- }
240
- if fwd != nil {
241
- fwdRuleIP = fwd .IPAddress
242
- break
121
+ if ! g .AlphaFeatureGate .Enabled (AlphaFeatureMultiProtocolLB ) {
122
+ for protocol := range groupedPorts {
123
+ frName := g .getProtocolForwardingRuleName (loadBalancerName , protocol )
124
+ fwd , err := g .GetRegionForwardingRule (frName , g .region )
125
+ if err != nil && ! isNotFound (err ) {
126
+ return nil , err
127
+ }
128
+ if fwd != nil {
129
+ fwdRuleIP = fwd .IPAddress
130
+ break
131
+ }
243
132
}
244
133
}
245
134
// If no forwarding rule exists, check for the old one.
@@ -456,7 +345,6 @@ func (g *Cloud) ensureIPAddress(loadBalancerName, lbRefStr, requestedIP, fwdRule
456
345
return ipAddressToUse , isSafeToReleaseIP , nil
457
346
}
458
347
459
-
460
348
// updateExternalLoadBalancer is the external implementation of LoadBalancer.UpdateLoadBalancer.
461
349
func (g * Cloud ) updateExternalLoadBalancer (clusterName string , service * v1.Service , nodes []* v1.Node ) error {
462
350
// Process services with LoadBalancerClass "networking.gke.io/l4-regional-external-legacy" used for this controller.
@@ -534,8 +422,13 @@ func (g *Cloud) ensureExternalLoadBalancerDeleted(clusterName, clusterID string,
534
422
},
535
423
func () error {
536
424
klog .Infof ("ensureExternalLoadBalancerDeleted(%s): Deleting forwarding rules." , lbRefStr )
537
- // The forwarding rule must be deleted before either the target pool can,
538
- // unfortunately, so we have to do these two serially.
425
+ // The forwarding rule must be deleted before the target pool can be deleted,
426
+ // unfortunately, so we have to delete forwarding rules then target pools serially.
427
+ if err := ignoreNotFound (g .DeleteRegionForwardingRule (loadBalancerName , g .region )); err != nil {
428
+ return err
429
+ }
430
+
431
+ // TODO: Always or just with alpha feature flag?
539
432
frs , err := g .ListRegionForwardingRules (g .region )
540
433
if err != nil {
541
434
return err
@@ -1125,8 +1018,7 @@ func equalPorts(existingPorts, newPorts []string, existingPortRange, newPortRang
1125
1018
1126
1019
func groupPortsByProtocol (ports []v1.ServicePort ) map [v1.Protocol ][]v1.ServicePort {
1127
1020
grouped := make (map [v1.Protocol ][]v1.ServicePort )
1128
- for _ , p := range ports {
1129
- port := p
1021
+ for _ , port := range ports {
1130
1022
grouped [port .Protocol ] = append (grouped [port .Protocol ], port )
1131
1023
}
1132
1024
return grouped
@@ -1195,7 +1087,6 @@ func (g *Cloud) firewallNeedsUpdate(name, serviceName, ipAddress string, ports [
1195
1087
return true , false , nil
1196
1088
}
1197
1089
1198
-
1199
1090
func (g * Cloud ) ensureHTTPHealthCheckFirewall (svc * v1.Service , serviceName , ipAddress , region , clusterID string , hosts []* gceInstance , hcName string , hcPort int32 , isNodesHealthCheck bool ) error {
1200
1091
// Prepare the firewall params for creating / checking.
1201
1092
desc := fmt .Sprintf (`{"kubernetes.io/cluster-id":"%s"}` , clusterID )
0 commit comments