Skip to content

Commit a068f95

Browse files
committed
Implement multi forwardingRule in interanal case
1 parent 4d49b9a commit a068f95

File tree

1 file changed

+154
-54
lines changed

1 file changed

+154
-54
lines changed

providers/gce/gce_loadbalancer_internal.go

Lines changed: 154 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -182,57 +182,133 @@ func (g *Cloud) ensureInternalLoadBalancer(clusterName, clusterID string, svc *v
182182
if err != nil {
183183
return nil, err
184184
}
185-
newFwdRule := &compute.ForwardingRule{
186-
Name: loadBalancerName,
187-
Description: fwdRuleDescriptionString,
188-
IPAddress: ipToUse,
189-
BackendService: backendServiceLink,
190-
Ports: ports,
191-
IPProtocol: string(protocol),
192-
LoadBalancingScheme: string(scheme),
193-
// Given that CreateGCECloud will attempt to determine the subnet based off the network,
194-
// the subnetwork should rarely be unknown.
195-
Subnetwork: subnetworkURL,
196-
Network: g.networkURL,
197-
}
198-
if options.AllowGlobalAccess {
199-
newFwdRule.AllowGlobalAccess = options.AllowGlobalAccess
200-
}
201-
if len(ports) > maxL4ILBPorts {
202-
newFwdRule.Ports = nil
203-
newFwdRule.AllPorts = true
204-
}
205185

206-
fwdRuleDeleted := false
207-
if existingFwdRule != nil && !forwardingRulesEqual(existingFwdRule, newFwdRule) {
208-
// Delete existing forwarding rule before making changes to the backend service. For example - changing protocol
209-
// of backend service without first deleting forwarding rule will throw an error since the linked forwarding
210-
// rule would show the old protocol.
211-
if klogV := klog.V(2); klogV.Enabled() {
212-
frDiff := cmp.Diff(existingFwdRule, newFwdRule)
213-
klogV.Infof("ensureInternalLoadBalancer(%v): forwarding rule changed - Existing - %+v\n, New - %+v\n, Diff(-existing, +new) - %s\n. Deleting existing forwarding rule.", loadBalancerName, existingFwdRule, newFwdRule, frDiff)
186+
// Logic to handle multiple forwarding rules, one per protocol.
187+
// Based on the logic for external load balancers.
188+
189+
// Get all existing forwarding rules for this service.
190+
// A service can have a forwarding rule with the base name, or with a protocol suffix.
191+
existingFwdRules := make(map[string]*compute.ForwardingRule)
192+
// The `existingFwdRule` is the one with the base name, passed into this function.
193+
if existingFwdRule != nil {
194+
existingFwdRules[existingFwdRule.Name] = existingFwdRule
195+
}
196+
// Check for forwarding rules with protocol suffixes.
197+
if len(groupedPorts) > 1 {
198+
for protocol := range groupedPorts {
199+
frName := fmt.Sprintf("%s-%s", loadBalancerName, strings.ToLower(string(protocol)))
200+
if _, ok := existingFwdRules[frName]; ok {
201+
continue
202+
}
203+
fr, err := g.GetRegionForwardingRule(frName, g.region)
204+
if err != nil && !isNotFound(err) {
205+
return nil, err
206+
}
207+
if fr != nil {
208+
existingFwdRules[fr.Name] = fr
209+
}
214210
}
215-
if err = ignoreNotFound(g.DeleteRegionForwardingRule(loadBalancerName, g.region)); err != nil {
211+
}
212+
213+
desiredFwdRuleNames := sets.NewString()
214+
var desiredFwdRuleProtocols []v1.Protocol
215+
for protocol := range groupedPorts {
216+
desiredFwdRuleProtocols = append(desiredFwdRuleProtocols, protocol)
217+
}
218+
// Sort protocols to have a stable order for naming and processing.
219+
sort.Slice(desiredFwdRuleProtocols, func(i, j int) bool {
220+
return desiredFwdRuleProtocols[i] < desiredFwdRuleProtocols[j]
221+
})
222+
223+
var createdFwdRules []*compute.ForwardingRule
224+
var desiredBackendServices = make(map[string]bool)
225+
226+
for _, protocol := range desiredFwdRuleProtocols {
227+
portStruct := groupedPorts[protocol]
228+
ports := portStruct.portRanges
229+
230+
// Each protocol gets its own backend service.
231+
// The backend service name must be unique per protocol.
232+
// Pass a single-protocol map to makeBackendServiceName.
233+
singleProtocolGroupedPorts := map[v1.Protocol]ProtocolPorts{protocol: portStruct}
234+
backendServiceName := makeBackendServiceName(loadBalancerName, clusterID, sharedBackend, scheme, singleProtocolGroupedPorts, svc.Spec.SessionAffinity)
235+
desiredBackendServices[backendServiceName] = true
236+
backendServiceLink := g.getBackendServiceLink(backendServiceName)
237+
238+
bsDescription := makeBackendServiceDescription(nm, sharedBackend)
239+
err = g.ensureInternalBackendService(backendServiceName, bsDescription, svc.Spec.SessionAffinity, scheme, protocol, igLinks, hc.SelfLink)
240+
if err != nil {
216241
return nil, err
217242
}
218-
fwdRuleDeleted = true
219-
}
220243

221-
bsDescription := makeBackendServiceDescription(nm, sharedBackend)
222-
err = g.ensureInternalBackendService(backendServiceName, bsDescription, svc.Spec.SessionAffinity, scheme, protocol, igLinks, hc.SelfLink)
223-
if err != nil {
224-
return nil, err
244+
// Each protocol gets its own forwarding rule.
245+
// If there's only one protocol, the forwarding rule name is the load balancer name.
246+
// Otherwise, it's load-balancer-name-<protocol>.
247+
frName := loadBalancerName
248+
if len(groupedPorts) > 1 {
249+
frName = fmt.Sprintf("%s-%s", loadBalancerName, strings.ToLower(string(protocol)))
250+
}
251+
desiredFwdRuleNames.Insert(frName)
252+
253+
newFwdRule := &compute.ForwardingRule{
254+
Name: frName,
255+
Description: fwdRuleDescriptionString,
256+
IPAddress: ipToUse,
257+
BackendService: backendServiceLink,
258+
Ports: ports,
259+
IPProtocol: string(protocol),
260+
LoadBalancingScheme: string(scheme),
261+
Subnetwork: subnetworkURL,
262+
Network: g.networkURL,
263+
}
264+
if options.AllowGlobalAccess {
265+
newFwdRule.AllowGlobalAccess = options.AllowGlobalAccess
266+
}
267+
if len(ports) > maxL4ILBPorts {
268+
newFwdRule.Ports = nil
269+
newFwdRule.AllPorts = true
270+
}
271+
272+
// Check if a forwarding rule for this protocol already exists.
273+
var existingFwdRuleForProtocol *compute.ForwardingRule
274+
if fr, ok := existingFwdRules[frName]; ok {
275+
existingFwdRuleForProtocol = fr
276+
}
277+
278+
if err := g.ensureInternalForwardingRule(existingFwdRuleForProtocol, newFwdRule); err != nil {
279+
return nil, err
280+
}
281+
createdFwdRules = append(createdFwdRules, newFwdRule)
225282
}
226283

227-
if fwdRuleDeleted || existingFwdRule == nil {
228-
// existing rule has been deleted, pass in nil
229-
if err := g.ensureInternalForwardingRule(nil, newFwdRule); err != nil {
284+
// Delete any forwarding rules that are no longer needed.
285+
for frName, fr := range existingFwdRules {
286+
if desiredFwdRuleNames.Has(frName) {
287+
continue
288+
}
289+
klog.V(2).Infof("ensureInternalLoadBalancer(%v): deleting stale forwarding rule %s", loadBalancerName, frName)
290+
if err := ignoreNotFound(g.DeleteRegionForwardingRule(frName, g.region)); err != nil {
230291
return nil, err
231292
}
293+
// Also delete the associated backend service if it's not used by other forwarding rules.
294+
if fr.BackendService != "" {
295+
bsName := getNameFromLink(fr.BackendService)
296+
if !desiredBackendServices[bsName] {
297+
klog.V(2).Infof("ensureInternalLoadBalancer(%v): deleting stale backend service %s", loadBalancerName, bsName)
298+
if err := g.teardownInternalBackendService(bsName); err != nil {
299+
klog.Warningf("ensureInternalLoadBalancer: could not delete old backend service %s: %v", bsName, err)
300+
}
301+
}
302+
}
303+
}
304+
305+
if len(createdFwdRules) == 0 {
306+
klog.V(2).Infof("ensureInternalLoadBalancer(%v): no forwarding rules needed, all deleted.", loadBalancerName)
307+
return &v1.LoadBalancerStatus{}, nil
232308
}
233309

234310
// Get the most recent forwarding rule for the address.
235-
updatedFwdRule, err := g.GetRegionForwardingRule(loadBalancerName, g.region)
311+
updatedFwdRule, err := g.GetRegionForwardingRule(createdFwdRules[0].Name, g.region)
236312
if err != nil {
237313
return nil, err
238314
}
@@ -243,11 +319,6 @@ func (g *Cloud) ensureInternalLoadBalancer(clusterName, clusterID string, svc *v
243319
return nil, err
244320
}
245321

246-
// Delete the previous internal load balancer resources if necessary
247-
if existingBackendService != nil {
248-
g.clearPreviousInternalResources(svc, loadBalancerName, existingBackendService, backendServiceName, hcName)
249-
}
250-
251322
serviceState.InSuccess = true
252323
if options.AllowGlobalAccess {
253324
serviceState.EnabledGlobalAccess = true
@@ -365,9 +436,17 @@ func (g *Cloud) updateInternalLoadBalancer(clusterName, clusterID string, svc *v
365436
groupedPorts := getPortsAndProtocols(svc.Spec.Ports)
366437
scheme := cloud.SchemeInternal
367438
loadBalancerName := g.GetLoadBalancerName(context.TODO(), clusterName, svc)
368-
backendServiceName := makeBackendServiceName(loadBalancerName, clusterID, shareBackendService(svc), scheme, groupedPorts, svc.Spec.SessionAffinity)
369-
// Ensure the backend service has the proper backend/instance-group links
370-
return g.ensureInternalBackendServiceGroups(backendServiceName, igLinks)
439+
sharedBackend := shareBackendService(svc)
440+
441+
for protocol, portStruct := range groupedPorts {
442+
singleProtocolGroupedPorts := map[v1.Protocol]ProtocolPorts{protocol: portStruct}
443+
backendServiceName := makeBackendServiceName(loadBalancerName, clusterID, sharedBackend, scheme, singleProtocolGroupedPorts, svc.Spec.SessionAffinity)
444+
// Ensure the backend service has the proper backend/instance-group links
445+
if err := g.ensureInternalBackendServiceGroups(backendServiceName, igLinks); err != nil {
446+
return err
447+
}
448+
}
449+
return nil
371450
}
372451

373452
func (g *Cloud) ensureInternalLoadBalancerDeleted(clusterName, clusterID string, svc *v1.Service) error {
@@ -397,15 +476,36 @@ func (g *Cloud) ensureInternalLoadBalancerDeleted(clusterName, clusterID string,
397476
klog.V(2).Infof("ensureInternalLoadBalancerDeleted(%v): attempting delete of region internal address", loadBalancerName)
398477
ensureAddressDeleted(g, loadBalancerName, g.region)
399478

400-
klog.V(2).Infof("ensureInternalLoadBalancerDeleted(%v): deleting region internal forwarding rule", loadBalancerName)
401-
if err := ignoreNotFound(g.DeleteRegionForwardingRule(loadBalancerName, g.region)); err != nil {
402-
return err
479+
frNames := sets.NewString(loadBalancerName)
480+
if len(groupedPorts) > 1 {
481+
for protocol := range groupedPorts {
482+
frNames.Insert(fmt.Sprintf("%s-%s", loadBalancerName, strings.ToLower(string(protocol))))
483+
}
484+
}
485+
// Sort for deterministic deletion order.
486+
sortedFrNames := frNames.List()
487+
sort.Strings(sortedFrNames)
488+
for _, frName := range sortedFrNames {
489+
klog.V(2).Infof("ensureInternalLoadBalancerDeleted(%v): deleting region internal forwarding rule %s", loadBalancerName, frName)
490+
if err := ignoreNotFound(g.DeleteRegionForwardingRule(frName, g.region)); err != nil {
491+
return err
492+
}
403493
}
404494

405-
backendServiceName := makeBackendServiceName(loadBalancerName, clusterID, sharedBackend, scheme, groupedPorts, svc.Spec.SessionAffinity)
406-
klog.V(2).Infof("ensureInternalLoadBalancerDeleted(%v): deleting region backend service %v", loadBalancerName, backendServiceName)
407-
if err := g.teardownInternalBackendService(backendServiceName); err != nil {
408-
return err
495+
var protocols []v1.Protocol
496+
for p := range groupedPorts {
497+
protocols = append(protocols, p)
498+
}
499+
sort.Slice(protocols, func(i, j int) bool { return protocols[i] < protocols[j] })
500+
501+
for _, protocol := range protocols {
502+
portStruct := groupedPorts[protocol]
503+
singleProtocolGroupedPorts := map[v1.Protocol]ProtocolPorts{protocol: portStruct}
504+
backendServiceName := makeBackendServiceName(loadBalancerName, clusterID, sharedBackend, scheme, singleProtocolGroupedPorts, svc.Spec.SessionAffinity)
505+
klog.V(2).Infof("ensureInternalLoadBalancerDeleted(%v): deleting region backend service %v", loadBalancerName, backendServiceName)
506+
if err := g.teardownInternalBackendService(backendServiceName); err != nil {
507+
return err
508+
}
409509
}
410510

411511
deleteFunc := func(fwName string) error {

0 commit comments

Comments
 (0)