in azure/azure_loadbalancer.go [641:781]
func (az *Cloud) ensurePublicIPExists(service *v1.Service, pipName string, domainNameLabel, clusterName string, shouldPIPExisted, foundDNSLabelAnnotation bool) (*network.PublicIPAddress, error) {
pipResourceGroup := az.getPublicIPAddressResourceGroup(service)
pip, existsPip, err := az.getPublicIPAddress(pipResourceGroup, pipName)
if err != nil {
return nil, err
}
serviceName := getServiceName(service)
var changed bool
if existsPip {
// ensure that the service tag is good for managed pips
owns, isUserAssignedPIP := serviceOwnsPublicIP(service, &pip, clusterName)
if owns && !isUserAssignedPIP {
changed, err = bindServicesToPIP(&pip, []string{serviceName}, false)
if err != nil {
return nil, err
}
}
if pip.Tags == nil {
pip.Tags = make(map[string]*string)
}
// return if pip exist and dns label is the same
if strings.EqualFold(getDomainNameLabel(&pip), domainNameLabel) {
if existingServiceName, ok := pip.Tags[serviceUsingDNSKey]; ok &&
strings.EqualFold(*existingServiceName, serviceName) {
klog.V(6).Infof("ensurePublicIPExists for service(%s): pip(%s) - "+
"the service is using the DNS label on the public IP", serviceName, pipName)
var rerr *retry.Error
if changed {
klog.V(2).Infof("ensurePublicIPExists: updating the PIP %s for the incoming service %s", pipName, serviceName)
err = az.CreateOrUpdatePIP(service, pipResourceGroup, pip)
if err != nil {
return nil, err
}
ctx, cancel := getContextWithCancel()
defer cancel()
pip, rerr = az.PublicIPAddressesClient.Get(ctx, pipResourceGroup, *pip.Name, "")
if rerr != nil {
return nil, rerr.Error()
}
}
return &pip, nil
}
}
klog.V(2).Infof("ensurePublicIPExists for service(%s): pip(%s) - updating", serviceName, *pip.Name)
if pip.PublicIPAddressPropertiesFormat == nil {
pip.PublicIPAddressPropertiesFormat = &network.PublicIPAddressPropertiesFormat{
PublicIPAllocationMethod: network.Static,
}
}
} else {
if shouldPIPExisted {
return nil, fmt.Errorf("PublicIP from annotation azure-pip-name=%s for service %s doesn't exist", pipName, serviceName)
}
pip.Name = to.StringPtr(pipName)
pip.Location = to.StringPtr(az.Location)
pip.PublicIPAddressPropertiesFormat = &network.PublicIPAddressPropertiesFormat{
PublicIPAllocationMethod: network.Static,
IPTags: getServiceIPTagRequestForPublicIP(service).IPTags,
}
pip.Tags = map[string]*string{
serviceTagKey: to.StringPtr(""),
clusterNameKey: &clusterName,
}
if _, err = bindServicesToPIP(&pip, []string{serviceName}, false); err != nil {
return nil, err
}
if az.useStandardLoadBalancer() {
pip.Sku = &network.PublicIPAddressSku{
Name: network.PublicIPAddressSkuNameStandard,
}
}
klog.V(2).Infof("ensurePublicIPExists for service(%s): pip(%s) - creating", serviceName, *pip.Name)
}
if foundDNSLabelAnnotation {
if existingServiceName, ok := pip.Tags[serviceUsingDNSKey]; ok {
if !strings.EqualFold(to.String(existingServiceName), serviceName) {
return nil, fmt.Errorf("ensurePublicIPExists for service(%s): pip(%s) - there is an existing service %s consuming the DNS label on the public IP, so the service cannot set the DNS label annotation with this value", serviceName, pipName, *existingServiceName)
}
}
if len(domainNameLabel) == 0 {
pip.PublicIPAddressPropertiesFormat.DNSSettings = nil
} else {
if pip.PublicIPAddressPropertiesFormat.DNSSettings == nil ||
pip.PublicIPAddressPropertiesFormat.DNSSettings.DomainNameLabel == nil {
klog.V(6).Infof("ensurePublicIPExists for service(%s): pip(%s) - no existing DNS label on the public IP, create one", serviceName, pipName)
pip.PublicIPAddressPropertiesFormat.DNSSettings = &network.PublicIPAddressDNSSettings{
DomainNameLabel: &domainNameLabel,
}
} else {
existingDNSLabel := pip.PublicIPAddressPropertiesFormat.DNSSettings.DomainNameLabel
if !strings.EqualFold(to.String(existingDNSLabel), domainNameLabel) {
return nil, fmt.Errorf("ensurePublicIPExists for service(%s): pip(%s) - there is an existing DNS label %s on the public IP", serviceName, pipName, *existingDNSLabel)
}
}
pip.Tags[serviceUsingDNSKey] = &serviceName
}
}
// use the same family as the clusterIP as we support IPv6 single stack as well
// as dual-stack clusters
ipv6 := utilnet.IsIPv6String(service.Spec.ClusterIP)
if ipv6 {
pip.PublicIPAddressVersion = network.IPv6
klog.V(2).Infof("service(%s): pip(%s) - creating as ipv6 for clusterIP:%v", serviceName, *pip.Name, service.Spec.ClusterIP)
pip.PublicIPAddressPropertiesFormat.PublicIPAllocationMethod = network.Dynamic
if az.useStandardLoadBalancer() {
// standard sku must have static allocation method for ipv6
pip.PublicIPAddressPropertiesFormat.PublicIPAllocationMethod = network.Static
}
} else {
pip.PublicIPAddressVersion = network.IPv4
klog.V(2).Infof("service(%s): pip(%s) - creating as ipv4 for clusterIP:%v", serviceName, *pip.Name, service.Spec.ClusterIP)
}
klog.V(2).Infof("CreateOrUpdatePIP(%s, %q): start", pipResourceGroup, *pip.Name)
err = az.CreateOrUpdatePIP(service, pipResourceGroup, pip)
if err != nil {
klog.V(2).Infof("ensure(%s) abort backoff: pip(%s)", serviceName, *pip.Name)
return nil, err
}
klog.V(10).Infof("CreateOrUpdatePIP(%s, %q): end", pipResourceGroup, *pip.Name)
ctx, cancel := getContextWithCancel()
defer cancel()
pip, rerr := az.PublicIPAddressesClient.Get(ctx, pipResourceGroup, *pip.Name, "")
if rerr != nil {
return nil, rerr.Error()
}
return &pip, nil
}