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
}