in azure/azure_loadbalancer.go [2175:2306]
func (az *Cloud) reconcilePublicIP(clusterName string, service *v1.Service, lbName string, wantLb bool) (*network.PublicIPAddress, error) {
isInternal := requiresInternalLoadBalancer(service)
serviceName := getServiceName(service)
serviceIPTagRequest := getServiceIPTagRequestForPublicIP(service)
var (
lb *network.LoadBalancer
desiredPipName string
err error
shouldPIPExisted bool
)
if !isInternal && wantLb {
desiredPipName, shouldPIPExisted, err = az.determinePublicIPName(clusterName, service)
if err != nil {
return nil, err
}
}
if lbName != "" {
loadBalancer, _, err := az.getAzureLoadBalancer(lbName, azcache.CacheReadTypeDefault)
if err != nil {
return nil, err
}
lb = &loadBalancer
}
pipResourceGroup := az.getPublicIPAddressResourceGroup(service)
pips, err := az.ListPIP(service, pipResourceGroup)
if err != nil {
return nil, err
}
var (
serviceAnnotationRequestsNamedPublicIP = shouldPIPExisted
discoveredDesiredPublicIP bool
deletedDesiredPublicIP bool
pipsToBeDeleted []*network.PublicIPAddress
pipsToBeUpdated []*network.PublicIPAddress
)
for i := range pips {
pip := pips[i]
pipName := *pip.Name
// If we've been told to use a specific public ip by the client, let's track whether or not it actually existed
// when we inspect the set in Azure.
discoveredDesiredPublicIP = discoveredDesiredPublicIP || wantLb && !isInternal && pipName == desiredPipName
// Now, let's perform additional analysis to determine if we should release the public ips we have found.
// We can only let them go if (a) they are owned by this service and (b) they meet the criteria for deletion.
owns, isUserAssignedPIP := serviceOwnsPublicIP(service, &pip, clusterName)
if owns {
var dirtyPIP, toBeDeleted bool
if !wantLb && !isUserAssignedPIP {
klog.V(2).Infof("reconcilePublicIP for service(%s): unbinding the service from pip %s", serviceName, *pip.Name)
err = unbindServiceFromPIP(&pip, serviceName)
if err != nil {
return nil, err
}
dirtyPIP = true
}
if !isUserAssignedPIP {
changed := az.ensurePIPTagged(service, &pip)
if changed {
dirtyPIP = true
}
}
if shouldReleaseExistingOwnedPublicIP(&pip, wantLb, isInternal, isUserAssignedPIP, desiredPipName, serviceIPTagRequest) {
// Then, release the public ip
pipsToBeDeleted = append(pipsToBeDeleted, &pip)
// Flag if we deleted the desired public ip
deletedDesiredPublicIP = deletedDesiredPublicIP || pipName == desiredPipName
// An aside: It would be unusual, but possible, for us to delete a public ip referred to explicitly by name
// in Service annotations (which is usually reserved for non-service-owned externals), if that IP is tagged as
// having been owned by a particular Kubernetes cluster.
// If the pip is going to be deleted, we do not need to update it
toBeDeleted = true
}
// Update tags of PIP only instead of deleting it.
if !toBeDeleted && dirtyPIP {
pipsToBeUpdated = append(pipsToBeUpdated, &pip)
}
}
}
if !isInternal && serviceAnnotationRequestsNamedPublicIP && !discoveredDesiredPublicIP && wantLb {
return nil, fmt.Errorf("reconcilePublicIP for service(%s): pip(%s) not found", serviceName, desiredPipName)
}
var deleteFuncs, updateFuncs []func() error
for _, pip := range pipsToBeUpdated {
pipCopy := *pip
updateFuncs = append(updateFuncs, func() error {
klog.V(2).Infof("reconcilePublicIP for service(%s): pip(%s) - updating", serviceName, *pip.Name)
return az.CreateOrUpdatePIP(service, pipResourceGroup, pipCopy)
})
}
errs := utilerrors.AggregateGoroutines(updateFuncs...)
if errs != nil {
return nil, utilerrors.Flatten(errs)
}
for _, pip := range pipsToBeDeleted {
pipCopy := *pip
deleteFuncs = append(deleteFuncs, func() error {
klog.V(2).Infof("reconcilePublicIP for service(%s): pip(%s) - deleting", serviceName, *pip.Name)
return az.safeDeletePublicIP(service, pipResourceGroup, &pipCopy, lb)
})
}
errs = utilerrors.AggregateGoroutines(deleteFuncs...)
if errs != nil {
return nil, utilerrors.Flatten(errs)
}
if !isInternal && wantLb {
// Confirm desired public ip resource exists
var pip *network.PublicIPAddress
domainNameLabel, found := getPublicIPDomainNameLabel(service)
errorIfPublicIPDoesNotExist := serviceAnnotationRequestsNamedPublicIP && discoveredDesiredPublicIP && !deletedDesiredPublicIP
if pip, err = az.ensurePublicIPExists(service, desiredPipName, domainNameLabel, clusterName, errorIfPublicIPDoesNotExist, found); err != nil {
return nil, err
}
return pip, nil
}
return nil, nil
}