func()

in controllers/manager/gatewaylbconfiguration_controller.go [285:523]


func (r *GatewayLBConfigurationReconciler) reconcileLBRule(
	ctx context.Context,
	lbConfig *egressgatewayv1alpha1.GatewayLBConfiguration,
	needLB bool,
) (string, int32, error) {
	log := log.FromContext(ctx)
	frontendIP := ""
	var lbPort int32
	updateLB := false
	deleteFrontend := false

	// get LoadBalancer
	lb, err := r.getGatewayLB(ctx)
	if err != nil {
		log.Error(err, "failed to get LoadBalancer")
		return "", 0, err
	}
	if lb == nil {
		if !needLB {
			log.Info(fmt.Sprintf("gateway lb(%s) not found, no more clean up needed", r.LoadBalancerName()))
			return "", 0, nil
		} else {
			lb = &network.LoadBalancer{
				Name:     to.Ptr(r.LoadBalancerName()),
				Location: to.Ptr(r.Location()),
				SKU: &network.LoadBalancerSKU{
					Name: to.Ptr(network.LoadBalancerSKUNameStandard),
					Tier: to.Ptr(network.LoadBalancerSKUTierRegional),
				},
				Properties: &network.LoadBalancerPropertiesFormat{},
			}
			updateLB = true
		}
	}

	// get gateway VMSS
	// we need this because each gateway vmss needs one frontendConfig and one backendpool
	vmss, err := r.getGatewayVMSS(ctx, lbConfig)
	if err != nil {
		log.Error(err, "failed to get vmss")
		return "", 0, err
	}

	// get lbPropertyNames
	names, err := getLBPropertyName(lbConfig, vmss)
	if err != nil {
		log.Error(err, "failed to get LB property names")
		return "", 0, err
	}

	if lb.Properties == nil {
		return "", 0, fmt.Errorf("lb property is empty")
	}

	frontendID := r.GetLBFrontendIPConfigurationID(names.frontendName)
	frontendIP, err = findFrontendIP(lb, names.frontendName)
	if err != nil {
		return "", 0, err
	}
	if frontendIP == "" {
		if needLB {
			subnet, err := r.GetSubnet(ctx)
			if err != nil {
				log.Error(err, "failed to get subnet")
				return "", 0, err
			}
			lb.Properties.FrontendIPConfigurations =
				append(lb.Properties.FrontendIPConfigurations, getExpectedFrontendConfig(to.Ptr(names.frontendName), subnet.ID))
			updateLB = true
		}
	} else {
		log.Info("Found LB frontendIPConfiguration", "frontendIP", frontendIP)
	}

	backendID := r.GetLBBackendAddressPoolID(names.backendName)
	foundBackend := false
	for _, backendPool := range lb.Properties.BackendAddressPools {
		if strings.EqualFold(*backendPool.Name, names.backendName) &&
			strings.EqualFold(*backendPool.ID, *backendID) {
			log.Info("Found LB backendAddressPool", "backendName", names.backendName)
			foundBackend = true
			break
		}
	}
	if !foundBackend {
		if needLB {
			lb.Properties.BackendAddressPools =
				append(lb.Properties.BackendAddressPools, getExpectedBackendPool(to.Ptr(names.backendName)))
			updateLB = true
		}
	}

	probeID := r.GetLBProbeID(names.probeName)
	expectedLBRule := getExpectedLBRule(&names.lbRuleName, frontendID, backendID, probeID)
	expectedProbe := getExpectedLBProbe(&names.probeName, r.LBProbePort, lbConfig)

	lbRules := lb.Properties.LoadBalancingRules
	if needLB {
		foundRule := false
		for i := range lbRules {
			lbRule := lbRules[i]
			if strings.EqualFold(*lbRule.Name, *expectedLBRule.Name) {
				if lbRule.Properties == nil {
					log.Info("Found LB rule with empty properties, dropping")
					lbRules = append(lbRules[:i], lbRules[i+1:]...)
				} else if !sameLBRuleConfig(ctx, lbRule, expectedLBRule) {
					log.Info("Found LB rule with different configuration, dropping")
					lbRules = append(lbRules[:i], lbRules[i+1:]...)
				} else {
					log.Info("Found expected LB rule, keeping")
					foundRule = true
					lbPort = to.Val(lbRule.Properties.FrontendPort)
				}
				break
			}
		}
		if !foundRule {
			port, err := selectPortForLBRule(expectedLBRule, lbRules)
			if err != nil {
				return "", 0, err
			}
			log.Info("Creating new lbRule", "port", port)
			lbPort = port
			expectedLBRule.Properties.FrontendPort = &port
			expectedLBRule.Properties.BackendPort = &port
			lbRules = append(lbRules, expectedLBRule)
			lb.Properties.LoadBalancingRules = lbRules
			updateLB = true
		}
	} else {
		ruleRefCnt := 0
		for i := len(lbRules) - 1; i >= 0; i = i - 1 {
			lbRule := lbRules[i]
			if strings.EqualFold(*lbRule.Name, *expectedLBRule.Name) {
				log.Info("Found LB rule, dropping")
				lbRules = append(lbRules[:i], lbRules[i+1:]...)
				updateLB = true
				lb.Properties.LoadBalancingRules = lbRules
			} else if strings.EqualFold(to.Val(lbRule.Properties.FrontendIPConfiguration.ID), to.Val(frontendID)) {
				ruleRefCnt = ruleRefCnt + 1
			}
		}
		if ruleRefCnt == 0 {
			deleteFrontend = true
		}
	}

	probes := lb.Properties.Probes
	if needLB {
		foundProbe := false
		for i := range probes {
			probe := probes[i]
			if strings.EqualFold(*probe.Name, *expectedProbe.Name) {
				if probe.Properties == nil {
					log.Info("Found LB probe with empty properties, dropping")
					probes = append(probes[:i], probes[i+1:]...)
				}
				if to.Val(probe.Properties.RequestPath) != to.Val(expectedProbe.Properties.RequestPath) ||
					to.Val(probe.Properties.Port) != to.Val(expectedProbe.Properties.Port) ||
					*probe.Properties.Protocol != *expectedProbe.Properties.Protocol {
					log.Info("Found LB probe with different configuration, dropping")
					probes = append(probes[:i], probes[i+1:]...)
				} else {
					log.Info("Found expected LB probe, keeping")
					foundProbe = true
				}
				break
			}
		}
		if !foundProbe {
			log.Info("Creating new probe")
			probes = append(probes, expectedProbe)
			lb.Properties.Probes = probes
			updateLB = true
		}
	} else {
		for i := range probes {
			probe := probes[i]
			if strings.EqualFold(*probe.Name, *expectedProbe.Name) {
				log.Info("Found LB probe, dropping")
				probes = append(probes[:i], probes[i+1:]...)
				updateLB = true
				lb.Properties.Probes = probes
				break
			}
		}
	}

	if !needLB && deleteFrontend {
		log.Info(fmt.Sprintf("no more gateway profile referring vmss(%s), deleting frontend and backend", names.frontendName))
		frontends := lb.Properties.FrontendIPConfigurations
		for i, frontendConfig := range frontends {
			if strings.EqualFold(to.Val(frontendConfig.ID), to.Val(frontendID)) {
				frontends = append(frontends[:i], frontends[i+1:]...)
				updateLB = true
				lb.Properties.FrontendIPConfigurations = frontends
				break
			}
		}
		backends := lb.Properties.BackendAddressPools
		for i, backendPool := range backends {
			if strings.EqualFold(to.Val(backendPool.ID), to.Val(backendID)) {
				backends = append(backends[:i], backends[i+1:]...)
				updateLB = true
				lb.Properties.BackendAddressPools = backends
				break
			}
		}

		if len(lb.Properties.FrontendIPConfigurations) == 0 {
			log.Info("Deleting load balancer")
			if err := r.DeleteLB(ctx); err != nil {
				log.Error(err, "failed to delete LB")
				return "", 0, err
			}
			return "", 0, nil
		}
	}

	if updateLB {
		log.Info("Updating load balancer")
		updatedLB, err := r.CreateOrUpdateLB(ctx, *lb)
		if err != nil {
			log.Error(err, "failed to update LB")
			return "", 0, err
		}
		if needLB && frontendIP == "" {
			frontendIP, err = findFrontendIP(updatedLB, names.frontendName)
			if err != nil {
				log.Error(err, "failed to find frontend ip")
				return "", 0, err
			} else if frontendIP == "" {
				return "", 0, fmt.Errorf("frontend ip not found even after updating lb")
			}
		}
	}

	return frontendIP, lbPort, nil
}