diff --git a/pkg/cloudprovider/providers/azure/azure_loadbalancer.go b/pkg/cloudprovider/providers/azure/azure_loadbalancer.go index 1b767e732ac..a3828dd961f 100644 --- a/pkg/cloudprovider/providers/azure/azure_loadbalancer.go +++ b/pkg/cloudprovider/providers/azure/azure_loadbalancer.go @@ -117,14 +117,6 @@ func (az *Cloud) EnsureLoadBalancer(ctx context.Context, clusterName string, ser // Here we'll firstly ensure service do not lie in the opposite LB. serviceName := getServiceName(service) glog.V(5).Infof("ensureloadbalancer(%s): START clusterName=%q", serviceName, clusterName) - flippedService := flipServiceInternalAnnotation(service) - if _, err := az.reconcileLoadBalancer(clusterName, flippedService, nil, false /* wantLb */); err != nil { - return nil, err - } - - if _, err := az.reconcilePublicIP(clusterName, service, true /* wantLb */); err != nil { - return nil, err - } lb, err := az.reconcileLoadBalancer(clusterName, service, nodes, true /* wantLb */) if err != nil { @@ -145,6 +137,16 @@ func (az *Cloud) EnsureLoadBalancer(ctx context.Context, clusterName string, ser return nil, err } + updateService := updateServiceLoadBalancerIP(service, to.String(serviceIP)) + flippedService := flipServiceInternalAnnotation(updateService) + if _, err := az.reconcileLoadBalancer(clusterName, flippedService, nil, false /* wantLb */); err != nil { + return nil, err + } + + if _, err := az.reconcilePublicIP(clusterName, updateService, true /* wantLb */); err != nil { + return nil, err + } + return lbStatus, nil } @@ -223,7 +225,7 @@ func (az *Cloud) getServiceLoadBalancer(service *v1.Service, clusterName string, return nil, nil, false, err } if status == nil { - // service is not om this load balancer + // service is not on this load balancer continue } @@ -409,6 +411,14 @@ func flipServiceInternalAnnotation(service *v1.Service) *v1.Service { return copyService } +func updateServiceLoadBalancerIP(service *v1.Service, serviceIP string) *v1.Service { + copyService := service.DeepCopy() + if len(serviceIP) > 0 && copyService != nil { + copyService.Spec.LoadBalancerIP = serviceIP + } + return copyService +} + func (az *Cloud) findServiceIPAddress(ctx context.Context, clusterName string, service *v1.Service, isInternalLb bool) (string, error) { if len(service.Spec.LoadBalancerIP) > 0 { return service.Spec.LoadBalancerIP, nil @@ -502,6 +512,53 @@ func getIdleTimeout(s *v1.Service) (*int32, error) { return &to32, nil } +func (az *Cloud) isFrontendIPChanged(clusterName string, config network.FrontendIPConfiguration, service *v1.Service, lbFrontendIPConfigName string) (bool, error) { + if az.serviceOwnsFrontendIP(config, service) && !strings.EqualFold(to.String(config.Name), lbFrontendIPConfigName) { + return true, nil + } + if !strings.EqualFold(to.String(config.Name), lbFrontendIPConfigName) { + return false, nil + } + loadBalancerIP := service.Spec.LoadBalancerIP + isInternal := requiresInternalLoadBalancer(service) + if isInternal { + // Judge subnet + subnetName := subnet(service) + if subnetName != nil { + subnet, existsSubnet, err := az.getSubnet(az.VnetName, *subnetName) + if err != nil { + return false, err + } + if !existsSubnet { + return false, fmt.Errorf("failed to get subnet") + } + if config.Subnet != nil && !strings.EqualFold(to.String(config.Subnet.Name), to.String(subnet.Name)) { + return true, nil + } + } + if loadBalancerIP == "" { + return config.PrivateIPAllocationMethod == network.Static, nil + } + return config.PrivateIPAllocationMethod != network.Static || !strings.EqualFold(loadBalancerIP, to.String(config.PrivateIPAddress)), nil + } + if loadBalancerIP == "" { + return false, nil + } + pipName, err := az.determinePublicIPName(clusterName, service) + if err != nil { + return false, err + } + pipResourceGroup := az.getPublicIPAddressResourceGroup(service) + pip, existsPip, err := az.getPublicIPAddress(pipResourceGroup, pipName) + if err != nil { + return false, err + } + if !existsPip { + return true, nil + } + return config.PublicIPAddress != nil && !strings.EqualFold(to.String(pip.ID), to.String(config.PublicIPAddress.ID)), nil +} + // This ensures load balancer exists and the frontend ip config is setup. // This also reconciles the Service's Ports with the LoadBalancer config. // This entails adding rules/probes for expected Ports and removing stale rules/ports. @@ -574,14 +631,16 @@ func (az *Cloud) reconcileLoadBalancer(clusterName string, service *v1.Service, } } } else { - if isInternal { - for i := len(newConfigs) - 1; i >= 0; i-- { - config := newConfigs[i] - if az.serviceOwnsFrontendIP(config, service) && !strings.EqualFold(*config.Name, lbFrontendIPConfigName) { - glog.V(2).Infof("reconcileLoadBalancer for service (%s)(%t): lb frontendconfig(%s) - dropping", serviceName, wantLb, *config.Name) - newConfigs = append(newConfigs[:i], newConfigs[i+1:]...) - dirtyConfigs = true - } + for i := len(newConfigs) - 1; i >= 0; i-- { + config := newConfigs[i] + isFipChanged, err := az.isFrontendIPChanged(clusterName, config, service, lbFrontendIPConfigName) + if err != nil { + return nil, err + } + if isFipChanged { + glog.V(2).Infof("reconcileLoadBalancer for service (%s)(%t): lb frontendconfig(%s) - dropping", serviceName, wantLb, *config.Name) + newConfigs = append(newConfigs[:i], newConfigs[i+1:]...) + dirtyConfigs = true } } foundConfig := false