@@ -29,7 +29,6 @@ import (
2929
3030 "github.com/GoogleCloudPlatform/k8s-cloud-provider/pkg/cloud"
3131 "github.com/GoogleCloudPlatform/k8s-cloud-provider/pkg/cloud/meta"
32- "github.com/google/go-cmp/cmp"
3332 compute "google.golang.org/api/compute/v1"
3433 v1 "k8s.io/api/core/v1"
3534 "k8s.io/apimachinery/pkg/types"
@@ -188,121 +187,109 @@ func (g *Cloud) ensureInternalLoadBalancer(clusterName, clusterID string, svc *v
188187
189188 // Get all existing forwarding rules for this service.
190189 // 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- }
190+ // TODO: Remove existingFwdRules and use the one from the function.
196191 // 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- }
210- }
211- }
192+ op := & ensureOperation {}
193+ g .findActualBackendServiceInternal (backendServiceName , op )
212194
213- desiredFwdRuleNames := sets .NewString ()
214- var desiredFwdRuleProtocols []v1.Protocol
215- for protocol := range groupedPorts {
216- desiredFwdRuleProtocols = append (desiredFwdRuleProtocols , protocol )
195+ existingForwardingRules , err := g .getExistingForwardingRules (loadBalancerName )
196+ if err != nil {
197+ return nil , err
217198 }
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- })
199+ op .forwardingRulesActual = existingForwardingRules
222200
223201 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 {
241- return nil , err
242- }
243202
203+ var desiredForwardingRules []* compute.ForwardingRule
204+ for protocol , protocolPorts := range groupedPorts {
244205 // Each protocol gets its own forwarding rule.
245206 // If there's only one protocol, the forwarding rule name is the load balancer name.
246207 // Otherwise, it's load-balancer-name-<protocol>.
247208 frName := loadBalancerName
248209 if len (groupedPorts ) > 1 {
249210 frName = fmt .Sprintf ("%s-%s" , loadBalancerName , strings .ToLower (string (protocol )))
250211 }
251- desiredFwdRuleNames .Insert (frName )
252212
253- newFwdRule := & compute.ForwardingRule {
213+ forwardingRule := & compute.ForwardingRule {
254214 Name : frName ,
255215 Description : fwdRuleDescriptionString ,
256216 IPAddress : ipToUse ,
257217 BackendService : backendServiceLink ,
258- Ports : ports ,
259218 IPProtocol : string (protocol ),
260219 LoadBalancingScheme : string (scheme ),
261220 Subnetwork : subnetworkURL ,
262221 Network : g .networkURL ,
263222 }
264223 if options .AllowGlobalAccess {
265- newFwdRule .AllowGlobalAccess = options .AllowGlobalAccess
224+ forwardingRule .AllowGlobalAccess = options .AllowGlobalAccess
266225 }
267- if len (ports ) > maxL4ILBPorts {
268- newFwdRule .Ports = nil
269- newFwdRule .AllPorts = true
226+ if len (protocolPorts .ports ) > maxL4ILBPorts {
227+ forwardingRule .Ports = nil
228+ forwardingRule .AllPorts = true
229+ } else {
230+ for _ , port := range protocolPorts .ports {
231+ forwardingRule .Ports = append (forwardingRule .Ports , strconv .Itoa (port ))
232+ }
270233 }
271234
272- // Check if a forwarding rule for this protocol already exists.
235+ // Check if a forwarding rule for this protocol already exists; reuse the same name if possible.
236+ for _ , existingFwdRule := range existingForwardingRules {
237+ if existingFwdRule .IPProtocol == forwardingRule .IPProtocol {
238+ forwardingRule .Name = existingFwdRule .Name
239+ break
240+ }
241+ }
242+
243+ desiredForwardingRules = append (desiredForwardingRules , forwardingRule )
244+ }
245+ op .forwardingRulesDesired = desiredForwardingRules
246+
247+ bsDescription := makeBackendServiceDescription (nm , sharedBackend )
248+ backendServiceProtocol := "UNSPECIFIED"
249+ if len (desiredForwardingRules ) == 1 {
250+ backendServiceProtocol = desiredForwardingRules [0 ].IPProtocol
251+ }
252+ g .buildDesiredBackendServiceInternal (backendServiceName , bsDescription , svc .Spec .SessionAffinity , scheme , backendServiceProtocol , igLinks , hc .SelfLink , op )
253+
254+ if err := g .ensureInternalBackendService (backendServiceName , op ); err != nil {
255+ return nil , err
256+ }
257+
258+ for _ , desiredForwardingRule := range desiredForwardingRules {
273259 var existingFwdRuleForProtocol * compute.ForwardingRule
274- if fr , ok := existingFwdRules [frName ]; ok {
275- existingFwdRuleForProtocol = fr
260+ for _ , existingFwdRule := range existingForwardingRules {
261+ if existingFwdRule .IPProtocol == desiredForwardingRule .IPProtocol {
262+ existingFwdRuleForProtocol = existingFwdRule
263+ break
264+ }
276265 }
277266
278- if err := g .ensureInternalForwardingRule (existingFwdRuleForProtocol , newFwdRule ); err != nil {
267+ if err := g .ensureInternalForwardingRule (existingFwdRuleForProtocol , desiredForwardingRule ); err != nil {
279268 return nil , err
280269 }
281- createdFwdRules = append (createdFwdRules , newFwdRule )
270+ createdFwdRules = append (createdFwdRules , desiredForwardingRule )
282271 }
283272
284273 // Delete any forwarding rules that are no longer needed.
285- for frName , fr := range existingFwdRules {
286- if desiredFwdRuleNames .Has (frName ) {
274+ for frName , fr := range existingForwardingRules {
275+ var matching * compute.ForwardingRule
276+ for _ , desiredForwardingRule := range desiredForwardingRules {
277+ if desiredForwardingRule .Name == fr .Name {
278+ matching = desiredForwardingRule
279+ continue
280+ }
281+ }
282+ if matching != nil {
287283 continue
288284 }
285+
289286 klog .V (2 ).Infof ("ensureInternalLoadBalancer(%v): deleting stale forwarding rule %s" , loadBalancerName , frName )
290287 if err := ignoreNotFound (g .DeleteRegionForwardingRule (frName , g .region )); err != nil {
291288 return nil , err
292289 }
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- }
303290 }
304291
305- if len (createdFwdRules ) == 0 {
292+ if len (desiredForwardingRules ) == 0 {
306293 klog .V (2 ).Infof ("ensureInternalLoadBalancer(%v): no forwarding rules needed, all deleted." , loadBalancerName )
307294 return & v1.LoadBalancerStatus {}, nil
308295 }
@@ -438,14 +425,12 @@ func (g *Cloud) updateInternalLoadBalancer(clusterName, clusterID string, svc *v
438425 loadBalancerName := g .GetLoadBalancerName (context .TODO (), clusterName , svc )
439426 sharedBackend := shareBackendService (svc )
440427
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- }
428+ backendServiceName := makeBackendServiceName (loadBalancerName , clusterID , sharedBackend , scheme , groupedPorts , svc .Spec .SessionAffinity )
429+ // Ensure the backend service has the proper backend/instance-group links
430+ if err := g .ensureInternalBackendServiceGroups (backendServiceName , igLinks ); err != nil {
431+ return err
448432 }
433+
449434 return nil
450435}
451436
@@ -476,36 +461,25 @@ func (g *Cloud) ensureInternalLoadBalancerDeleted(clusterName, clusterID string,
476461 klog .V (2 ).Infof ("ensureInternalLoadBalancerDeleted(%v): attempting delete of region internal address" , loadBalancerName )
477462 ensureAddressDeleted (g , loadBalancerName , g .region )
478463
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- }
464+ // Get existing forwarding rules.
465+ existingForwardingRules , err := g .getExistingForwardingRules (loadBalancerName )
466+ if err != nil {
467+ return err
484468 }
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 {
469+
470+ // Delete existing forwarding rules.
471+ for _ , existingForwardingRule := range existingForwardingRules {
472+ klog .V (2 ).Infof ("ensureInternalLoadBalancerDeleted(%v): deleting region internal forwarding rule %s" , loadBalancerName , existingForwardingRule .Name )
473+ if err := ignoreNotFound (g .DeleteRegionForwardingRule (existingForwardingRule .Name , g .region )); err != nil {
491474 return err
492475 }
493476 }
494477
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- }
478+ // Delete existing backend service.
479+ backendServiceName := makeBackendServiceName (loadBalancerName , clusterID , sharedBackend , scheme , groupedPorts , svc .Spec .SessionAffinity )
480+ klog .V (2 ).Infof ("ensureInternalLoadBalancerDeleted(%v): deleting region backend service %v" , loadBalancerName , backendServiceName )
481+ if err := g .teardownInternalBackendService (backendServiceName ); err != nil {
482+ return err
509483 }
510484
511485 deleteFunc := func (fwName string ) error {
@@ -881,43 +855,72 @@ func (g *Cloud) ensureInternalInstanceGroupsDeleted(name string) error {
881855 return nil
882856}
883857
884- func ( g * Cloud ) ensureInternalBackendService ( name , description string , affinityType v1. ServiceAffinity , scheme cloud. LbScheme , protocol v1. Protocol , igLinks [] string , hcLink string ) error {
885- klog . V ( 2 ). Infof ( "ensureInternalBackendService(%v, %v, %v): checking existing backend service with %d groups" , name , scheme , protocol , len ( igLinks ))
886- bs , err := g . GetRegionBackendService ( name , g . region )
887- if err != nil && ! isNotFound ( err ) {
888- return err
889- }
858+ type ensureOperation struct {
859+ backendServiceDesired * compute. BackendService
860+ backendServiceActual * compute. BackendService
861+ forwardingRulesDesired [] * compute. ForwardingRule
862+ forwardingRulesActual map [ string ] * compute. ForwardingRule
863+ }
890864
865+ func (g * Cloud ) buildDesiredBackendServiceInternal (name , description string , affinityType v1.ServiceAffinity , scheme cloud.LbScheme , protocol string , igLinks []string , hcLink string , op * ensureOperation ) error {
891866 backends := backendsFromGroupLinks (igLinks )
892- expectedBS := & compute.BackendService {
867+ bs := & compute.BackendService {
893868 Name : name ,
894- Protocol : string ( protocol ) ,
869+ Protocol : protocol ,
895870 Description : description ,
896871 HealthChecks : []string {hcLink },
897872 Backends : backends ,
898873 SessionAffinity : translateAffinityType (affinityType ),
899874 LoadBalancingScheme : string (scheme ),
900875 }
901876
877+ op .backendServiceDesired = bs
878+ return nil
879+ }
880+
881+ func (g * Cloud ) findActualBackendServiceInternal (name string , op * ensureOperation ) error {
882+ klog .V (2 ).Infof ("findActualBackendServiceInternal(%v): checking existing backend services" , name )
883+
884+ bs , err := g .GetRegionBackendService (name , g .region )
885+ if err != nil && ! isNotFound (err ) {
886+ return err
887+ }
888+
889+ op .backendServiceActual = bs
890+ return nil
891+ }
892+
893+ func (g * Cloud ) ensureInternalBackendService (name string , op * ensureOperation ) error {
902894 // Create backend service if none was found
903- if bs == nil {
895+ if op . backendServiceActual == nil {
904896 klog .V (2 ).Infof ("ensureInternalBackendService: creating backend service %v" , name )
905- err := g .CreateRegionBackendService (expectedBS , g .region )
897+ err := g .CreateRegionBackendService (op . backendServiceDesired , g .region )
906898 if err != nil {
907899 return err
908900 }
909901 klog .V (2 ).Infof ("ensureInternalBackendService: created backend service %v successfully" , name )
910902 return nil
911903 }
912904
913- if backendSvcEqual (expectedBS , bs ) {
905+ if backendSvcEqual (op . backendServiceActual , op . backendServiceDesired ) {
914906 return nil
915907 }
916908
909+ // Delete existing forwarding rule before making changes to the backend service. For example - changing protocol
910+ // of backend service without first deleting forwarding rule will throw an error since the linked forwarding
911+ // rule would show the old protocol.
912+ for _ , fr := range op .forwardingRulesActual {
913+ klog .V (2 ).Infof ("ensureInternalBackendService: deleting forwarding rule %v" , fr .Name )
914+ if err := g .DeleteRegionForwardingRule (fr .Name , g .region ); ignoreNotFound (err ) != nil {
915+ return err
916+ }
917+ }
918+ op .forwardingRulesActual = nil
919+
917920 klog .V (2 ).Infof ("ensureInternalBackendService: updating backend service %v" , name )
918921 // Set fingerprint for optimistic locking
919- expectedBS . Fingerprint = bs .Fingerprint
920- if err := g .UpdateRegionBackendService (expectedBS , g .region ); err != nil {
922+ op . backendServiceDesired . Fingerprint = op . backendServiceActual .Fingerprint
923+ if err := g .UpdateRegionBackendService (op . backendServiceDesired , g .region ); err != nil {
921924 return err
922925 }
923926 klog .V (2 ).Infof ("ensureInternalBackendService: updated backend service %v successfully" , name )
0 commit comments