Skip to content

Commit 13c400d

Browse files
committed
fixup! Implement multi forwardingRule in interanal case
1 parent a068f95 commit 13c400d

File tree

1 file changed

+102
-86
lines changed

1 file changed

+102
-86
lines changed

providers/gce/gce_loadbalancer_internal.go

Lines changed: 102 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -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
225+
}
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+
}
266233
}
267-
if len(ports) > maxL4ILBPorts {
268-
newFwdRule.Ports = nil
269-
newFwdRule.AllPorts = true
234+
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+
}
270241
}
271242

272-
// Check if a forwarding rule for this protocol already exists.
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
}
@@ -881,43 +868,72 @@ func (g *Cloud) ensureInternalInstanceGroupsDeleted(name string) error {
881868
return nil
882869
}
883870

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-
}
871+
type ensureOperation struct {
872+
backendServiceDesired *compute.BackendService
873+
backendServiceActual *compute.BackendService
874+
forwardingRulesDesired []*compute.ForwardingRule
875+
forwardingRulesActual map[string]*compute.ForwardingRule
876+
}
890877

878+
func (g *Cloud) buildDesiredBackendServiceInternal(name, description string, affinityType v1.ServiceAffinity, scheme cloud.LbScheme, protocol string, igLinks []string, hcLink string, op *ensureOperation) error {
891879
backends := backendsFromGroupLinks(igLinks)
892-
expectedBS := &compute.BackendService{
880+
bs := &compute.BackendService{
893881
Name: name,
894-
Protocol: string(protocol),
882+
Protocol: protocol,
895883
Description: description,
896884
HealthChecks: []string{hcLink},
897885
Backends: backends,
898886
SessionAffinity: translateAffinityType(affinityType),
899887
LoadBalancingScheme: string(scheme),
900888
}
901889

890+
op.backendServiceDesired = bs
891+
return nil
892+
}
893+
894+
func (g *Cloud) findActualBackendServiceInternal(name string, op *ensureOperation) error {
895+
klog.V(2).Infof("findActualBackendServiceInternal(%v): checking existing backend services", name)
896+
897+
bs, err := g.GetRegionBackendService(name, g.region)
898+
if err != nil && !isNotFound(err) {
899+
return err
900+
}
901+
902+
op.backendServiceActual = bs
903+
return nil
904+
}
905+
906+
func (g *Cloud) ensureInternalBackendService(name string, op *ensureOperation) error {
902907
// Create backend service if none was found
903-
if bs == nil {
908+
if op.backendServiceActual == nil {
904909
klog.V(2).Infof("ensureInternalBackendService: creating backend service %v", name)
905-
err := g.CreateRegionBackendService(expectedBS, g.region)
910+
err := g.CreateRegionBackendService(op.backendServiceDesired, g.region)
906911
if err != nil {
907912
return err
908913
}
909914
klog.V(2).Infof("ensureInternalBackendService: created backend service %v successfully", name)
910915
return nil
911916
}
912917

913-
if backendSvcEqual(expectedBS, bs) {
918+
if backendSvcEqual(op.backendServiceActual, op.backendServiceDesired) {
914919
return nil
915920
}
916921

922+
// Delete existing forwarding rule before making changes to the backend service. For example - changing protocol
923+
// of backend service without first deleting forwarding rule will throw an error since the linked forwarding
924+
// rule would show the old protocol.
925+
for _, fr := range op.forwardingRulesActual {
926+
klog.V(2).Infof("ensureInternalBackendService: deleting forwarding rule %v", fr.Name)
927+
if err := g.DeleteRegionForwardingRule(fr.Name, g.region); ignoreNotFound(err) != nil {
928+
return err
929+
}
930+
}
931+
op.forwardingRulesActual = nil
932+
917933
klog.V(2).Infof("ensureInternalBackendService: updating backend service %v", name)
918934
// Set fingerprint for optimistic locking
919-
expectedBS.Fingerprint = bs.Fingerprint
920-
if err := g.UpdateRegionBackendService(expectedBS, g.region); err != nil {
935+
op.backendServiceDesired.Fingerprint = op.backendServiceActual.Fingerprint
936+
if err := g.UpdateRegionBackendService(op.backendServiceDesired, g.region); err != nil {
921937
return err
922938
}
923939
klog.V(2).Infof("ensureInternalBackendService: updated backend service %v successfully", name)

0 commit comments

Comments
 (0)