in pkg/loadbalancers/l4.go [187:321]
func (l *L4) EnsureInternalLoadBalancer(nodeNames []string, svc *corev1.Service) *L4LBSyncResult {
result := &L4LBSyncResult{
Annotations: make(map[string]string),
StartTime: time.Now(),
SyncType: SyncTypeCreate}
// If service already has an IP assigned, treat it as an update instead of a new Loadbalancer.
// This will also cover cases where an external LB is updated to an ILB, which is technically a create for ILB.
// But this is still the easiest way to identify create vs update in the common case.
if len(svc.Status.LoadBalancer.Ingress) > 0 {
result.SyncType = SyncTypeUpdate
}
l.Service = svc
// All resources use the L4Backend name, except forwarding rule.
name, ok := l.namer.L4Backend(l.Service.Namespace, l.Service.Name)
if !ok {
result.Error = fmt.Errorf("Namer does not support L4 VMIPNEGs")
return result
}
options := getILBOptions(l.Service)
// create healthcheck
sharedHC := !helpers.RequestsOnlyLocalTraffic(l.Service)
ensureHCFunc := func() (string, string, int32, string, error) {
if sharedHC {
// Take the lock when creating the shared healthcheck
l.sharedResourcesLock.Lock()
defer l.sharedResourcesLock.Unlock()
}
return healthchecks.EnsureL4HealthCheck(l.cloud, l.Service, l.namer, sharedHC, meta.Global, utils.ILB)
}
hcLink, hcFwName, hcPort, hcName, err := ensureHCFunc()
if err != nil {
result.GCEResourceInError = annotations.HealthcheckResource
result.Error = err
return result
}
result.Annotations[annotations.HealthcheckKey] = hcName
_, portRanges, _, protocol := utils.GetPortsAndProtocol(l.Service.Spec.Ports)
// ensure firewalls
sourceRanges, err := helpers.GetLoadBalancerSourceRanges(l.Service)
if err != nil {
result.Error = err
return result
}
// Add firewall rule for ILB traffic to nodes
nodesFWRParams := firewalls.FirewallParams{
PortRanges: portRanges,
SourceRanges: sourceRanges.StringSlice(),
Protocol: string(protocol),
Name: name,
NodeNames: nodeNames,
L4Type: utils.ILB,
}
if err := firewalls.EnsureL4LBFirewallForNodes(l.Service, &nodesFWRParams, l.cloud, l.recorder); err != nil {
result.GCEResourceInError = annotations.FirewallRuleResource
result.Error = err
return result
}
result.Annotations[annotations.FirewallRuleKey] = name
// Add firewall rule for healthchecks to nodes
hcFWRParams := firewalls.FirewallParams{
PortRanges: []string{strconv.Itoa(int(hcPort))},
SourceRanges: gce.L4LoadBalancerSrcRanges(),
Protocol: string(corev1.ProtocolTCP),
Name: hcFwName,
NodeNames: nodeNames,
L4Type: utils.ILB,
}
err = firewalls.EnsureL4LBFirewallForHc(l.Service, sharedHC, &hcFWRParams, l.cloud, l.sharedResourcesLock, l.recorder)
if err != nil {
result.GCEResourceInError = annotations.FirewallForHealthcheckResource
result.Error = err
return result
}
result.Annotations[annotations.FirewallRuleForHealthcheckKey] = hcFwName
// Check if protocol has changed for this service. In this case, forwarding rule should be deleted before
// the backend service can be updated.
existingBS, err := l.backendPool.Get(name, meta.VersionGA, l.scope)
err = utils.IgnoreHTTPNotFound(err)
if err != nil {
klog.Errorf("Failed to lookup existing backend service, ignoring err: %v", err)
}
existingFR := l.GetForwardingRule(l.GetFRName(), meta.VersionGA)
if existingBS != nil && existingBS.Protocol != string(protocol) {
klog.Infof("Protocol changed from %q to %q for service %s", existingBS.Protocol, string(protocol), l.NamespacedName)
// Delete forwarding rule if it exists
existingFR = l.GetForwardingRule(l.getFRNameWithProtocol(existingBS.Protocol), meta.VersionGA)
l.deleteForwardingRule(l.getFRNameWithProtocol(existingBS.Protocol), meta.VersionGA)
}
// ensure backend service
bs, err := l.backendPool.EnsureL4BackendService(name, hcLink, string(protocol), string(l.Service.Spec.SessionAffinity),
string(cloud.SchemeInternal), l.NamespacedName, meta.VersionGA)
if err != nil {
result.GCEResourceInError = annotations.BackendServiceResource
result.Error = err
return result
}
result.Annotations[annotations.BackendServiceKey] = name
// create fr rule
frName := l.GetFRName()
fr, err := l.ensureForwardingRule(frName, bs.SelfLink, options, existingFR)
if err != nil {
klog.Errorf("EnsureInternalLoadBalancer: Failed to create forwarding rule - %v", err)
result.GCEResourceInError = annotations.ForwardingRuleResource
result.Error = err
return result
}
if fr.IPProtocol == string(corev1.ProtocolTCP) {
result.Annotations[annotations.TCPForwardingRuleKey] = frName
} else {
result.Annotations[annotations.UDPForwardingRuleKey] = frName
}
result.MetricsState.InSuccess = true
if options.AllowGlobalAccess {
result.MetricsState.EnabledGlobalAccess = true
}
// SubnetName is overwritten to nil value if Alpha feature gate for custom subnet
// is not enabled. So, a non empty subnet name at this point implies that the
// feature is in use.
if options.SubnetName != "" {
result.MetricsState.EnabledCustomSubnet = true
}
result.Status = &corev1.LoadBalancerStatus{Ingress: []corev1.LoadBalancerIngress{{IP: fr.IPAddress}}}
return result
}