func()

in pkg/loadbalancers/forwarding_rules.go [198:297]


func (l *L4) ensureForwardingRule(loadBalancerName, bsLink string, options gce.ILBOptions, existingFwdRule *composite.ForwardingRule) (*composite.ForwardingRule, error) {
	key, err := l.CreateKey(loadBalancerName)
	if err != nil {
		return nil, err
	}
	// version used for creating the existing forwarding rule.
	version := meta.VersionGA

	if l.cloud.IsLegacyNetwork() {
		l.recorder.Event(l.Service, v1.EventTypeWarning, "ILBOptionsIgnored", "Internal LoadBalancer options are not supported with Legacy Networks.")
		options = gce.ILBOptions{}
	}
	subnetworkURL := l.cloud.SubnetworkURL()

	// Custom subnet feature is always enabled when running L4 controller.
	// Changes to subnet annotation will be picked up and reflected in the forwarding rule.
	// Removing the annotation will set the forwarding rule to use the default subnet.
	if options.SubnetName != "" {
		subnetKey := *key
		subnetKey.Name = options.SubnetName
		subnetworkURL = cloud.SelfLink(meta.VersionGA, l.cloud.NetworkProjectID(), "subnetworks", &subnetKey)
	}
	// Determine IP which will be used for this LB. If no forwarding rule has been established
	// or specified in the Service spec, then requestedIP = "".
	ipToUse := l4lbIPToUse(l.Service, existingFwdRule, subnetworkURL)
	klog.V(2).Infof("ensureForwardingRule(%v): Using subnet %q for LoadBalancer IP %s", loadBalancerName, subnetworkURL, ipToUse)

	var addrMgr *addressManager
	// If the network is not a legacy network, use the address manager
	if !l.cloud.IsLegacyNetwork() {
		nm := types.NamespacedName{Namespace: l.Service.Namespace, Name: l.Service.Name}.String()
		// ILB can be created only in Premium Tier
		addrMgr = newAddressManager(l.cloud, nm, l.cloud.Region(), subnetworkURL, loadBalancerName, ipToUse, cloud.SchemeInternal, cloud.NetworkTierPremium)
		ipToUse, err = addrMgr.HoldAddress()
		if err != nil {
			return nil, err
		}
		klog.V(2).Infof("ensureForwardingRule(%v): reserved IP %q for the forwarding rule", loadBalancerName, ipToUse)
		defer func() {
			// Release the address that was reserved, in all cases. If the forwarding rule was successfully created,
			// the ephemeral IP is not needed anymore. If it was not created, the address should be released to prevent leaks.
			if err := addrMgr.ReleaseAddress(); err != nil {
				klog.Errorf("ensureInternalLoadBalancer: failed to release address reservation, possibly causing an orphan: %v", err)
			}
		}()
	}

	ports, _, _, protocol := utils.GetPortsAndProtocol(l.Service.Spec.Ports)
	// Create the forwarding rule
	frDesc, err := utils.MakeL4LBServiceDescription(utils.ServiceKeyFunc(l.Service.Namespace, l.Service.Name), ipToUse,
		version, false, utils.ILB)
	if err != nil {
		return nil, fmt.Errorf("Failed to compute description for forwarding rule %s, err: %w", loadBalancerName,
			err)
	}

	fr := &composite.ForwardingRule{
		Name:                loadBalancerName,
		IPAddress:           ipToUse,
		Ports:               ports,
		IPProtocol:          string(protocol),
		LoadBalancingScheme: string(cloud.SchemeInternal),
		Subnetwork:          subnetworkURL,
		Network:             l.cloud.NetworkURL(),
		NetworkTier:         cloud.NetworkTierDefault.ToGCEValue(),
		Version:             version,
		BackendService:      bsLink,
		AllowGlobalAccess:   options.AllowGlobalAccess,
		Description:         frDesc,
	}
	if len(ports) > maxL4ILBPorts {
		fr.Ports = nil
		fr.AllPorts = true
	}

	if existingFwdRule != nil {
		equal, err := Equal(existingFwdRule, fr)
		if err != nil {
			return existingFwdRule, err
		}
		if equal {
			// nothing to do
			klog.V(2).Infof("ensureForwardingRule: Skipping update of unchanged forwarding rule - %s", fr.Name)
			return existingFwdRule, nil
		}
		frDiff := cmp.Diff(existingFwdRule, fr)
		// If the forwarding rule pointed to a backend service which does not match the controller naming scheme,
		// that resouce could be leaked. It is not being deleted here because that is a user-managed resource.
		klog.V(2).Infof("ensureForwardingRule: forwarding rule changed - Existing - %+v\n, New - %+v\n, Diff(-existing, +new) - %s\n. Deleting existing forwarding rule.", existingFwdRule, fr, frDiff)
		if err = utils.IgnoreHTTPNotFound(composite.DeleteForwardingRule(l.cloud, key, version)); err != nil {
			return nil, err
		}
		l.recorder.Eventf(l.Service, corev1.EventTypeNormal, events.SyncIngress, "ForwardingRule %q deleted", key.Name)
	}
	klog.V(2).Infof("ensureForwardingRule: Creating/Recreating forwarding rule - %s", fr.Name)
	if err = composite.CreateForwardingRule(l.cloud, key, fr); err != nil {
		return nil, err
	}
	return composite.GetForwardingRule(l.cloud, key, fr.Version)
}