github.com/openshift/installer@v1.4.17/pkg/infrastructure/azure/dns.go (about)

     1  package azure
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  
     7  	"github.com/Azure/azure-sdk-for-go/sdk/azcore/arm"
     8  	"github.com/Azure/azure-sdk-for-go/sdk/azcore/policy"
     9  	"github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/dns/armdns"
    10  	"github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/privatedns/armprivatedns"
    11  	"k8s.io/utils/ptr"
    12  	capz "sigs.k8s.io/cluster-api-provider-azure/api/v1beta1"
    13  	"sigs.k8s.io/controller-runtime/pkg/client"
    14  
    15  	"github.com/openshift/installer/pkg/asset/manifests/capiutils"
    16  	"github.com/openshift/installer/pkg/infrastructure/clusterapi"
    17  	"github.com/openshift/installer/pkg/types"
    18  )
    19  
    20  type recordListType string
    21  
    22  const (
    23  	cname      recordListType = "Cname"
    24  	arecord    recordListType = "ARecord"
    25  	aaaarecord recordListType = "AaaaRecord"
    26  )
    27  
    28  type recordList struct {
    29  	Name       string
    30  	RecordType armdns.RecordType
    31  	RecordSet  armdns.RecordSet
    32  }
    33  
    34  type recordPrivateList struct {
    35  	Name       string
    36  	RecordType armprivatedns.RecordType
    37  	RecordSet  armprivatedns.RecordSet
    38  }
    39  
    40  // Create DNS entries for azure.
    41  func createDNSEntries(ctx context.Context, in clusterapi.InfraReadyInput, extLBFQDN string, resourceGroup string) error {
    42  	private := in.InstallConfig.Config.Publish == types.InternalPublishingStrategy
    43  	baseDomainResourceGroup := in.InstallConfig.Config.Azure.BaseDomainResourceGroupName
    44  	zone := in.InstallConfig.Config.BaseDomain
    45  	privatezone := in.InstallConfig.Config.ClusterDomain()
    46  	apiExternalName := fmt.Sprintf("api.%s", in.InstallConfig.Config.ObjectMeta.Name)
    47  
    48  	if in.InstallConfig.Config.Azure.ResourceGroupName != "" {
    49  		resourceGroup = in.InstallConfig.Config.Azure.ResourceGroupName
    50  	}
    51  	azureTags := make(map[string]*string)
    52  	for k, v := range in.InstallConfig.Config.Azure.UserTags {
    53  		azureTags[k] = ptr.To(v)
    54  	}
    55  	azureCluster := &capz.AzureCluster{}
    56  	key := client.ObjectKey{
    57  		Name:      in.InfraID,
    58  		Namespace: capiutils.Namespace,
    59  	}
    60  	if err := in.Client.Get(ctx, key, azureCluster); err != nil && azureCluster != nil {
    61  		return fmt.Errorf("failed to get Azure cluster: %w", err)
    62  	}
    63  
    64  	if len(azureCluster.Spec.NetworkSpec.APIServerLB.FrontendIPs) == 0 {
    65  		return fmt.Errorf("failed to get Azure cluster LB frontend IPs")
    66  	}
    67  	ipIlb := azureCluster.Spec.NetworkSpec.APIServerLB.FrontendIPs[0].PrivateIPAddress
    68  	// useIPv6 := false
    69  	// for _, network := range in.InstallConfig.Config.Networking.ServiceNetwork {
    70  	// 	if network.IP.To4() == nil {
    71  	// 		useIPv6 = true
    72  	// 	}
    73  	// }
    74  
    75  	privateRecords := []recordPrivateList{}
    76  	ttl := int64(300)
    77  	recordType := arecord
    78  	// if useIPv6 {
    79  	// 	recordType = aaaarecord
    80  	// }
    81  	privateRecords = append(privateRecords, createPrivateRecordSet("api-int", azureTags, ttl, recordType, ipIlb, ""))
    82  	privateRecords = append(privateRecords, createPrivateRecordSet("api", azureTags, ttl, recordType, ipIlb, ""))
    83  
    84  	session, err := in.InstallConfig.Azure.Session()
    85  	if err != nil {
    86  		return fmt.Errorf("failed to create session: %w", err)
    87  	}
    88  	subscriptionID := session.Credentials.SubscriptionID
    89  	cloudConfiguration := session.CloudConfig
    90  
    91  	recordSetClient, err := armdns.NewRecordSetsClient(subscriptionID, session.TokenCreds,
    92  		&arm.ClientOptions{
    93  			ClientOptions: policy.ClientOptions{
    94  				Cloud: cloudConfiguration,
    95  			},
    96  		},
    97  	)
    98  	if err != nil {
    99  		return fmt.Errorf("failed to create public record client: %w", err)
   100  	}
   101  	privateRecordSetClient, err := armprivatedns.NewRecordSetsClient(subscriptionID, session.TokenCreds,
   102  		&arm.ClientOptions{
   103  			ClientOptions: policy.ClientOptions{
   104  				Cloud: cloudConfiguration,
   105  			},
   106  		},
   107  	)
   108  	if err != nil {
   109  		return fmt.Errorf("failed to create private record client: %w", err)
   110  	}
   111  
   112  	// Create the records for api and api-int in the private zone and api.<clustername> for public zone.
   113  	// CAPI currently creates a record called "apiserver" instead of "api" so creating "api" for the installer in the private zone.
   114  	if !private {
   115  		cnameRecordName := apiExternalName
   116  		// apiExternalNameV6 := fmt.Sprintf("v6-api.%s", infraID)
   117  		// if useIPv6 {
   118  		// 	cnameRecordName = apiExternalNameV6
   119  		// }
   120  		publicRecords := createRecordSet(cnameRecordName, azureTags, ttl, cname, "", extLBFQDN)
   121  		_, err = recordSetClient.CreateOrUpdate(ctx, baseDomainResourceGroup, zone, publicRecords.Name, publicRecords.RecordType, publicRecords.RecordSet, nil)
   122  		if err != nil {
   123  			return fmt.Errorf("failed to create public record set: %w", err)
   124  		}
   125  	}
   126  
   127  	for _, record := range privateRecords {
   128  		_, err = privateRecordSetClient.CreateOrUpdate(ctx, resourceGroup, privatezone, record.RecordType, record.Name, record.RecordSet, nil)
   129  		if err != nil {
   130  			return fmt.Errorf("failed to create private record set: %w", err)
   131  		}
   132  	}
   133  
   134  	return nil
   135  }
   136  
   137  func createPrivateRecordSet(lbType string, azureTags map[string]*string, ttl int64, rType recordListType, ipAddress string, recordName string) (record recordPrivateList) {
   138  	record = recordPrivateList{
   139  		Name: lbType,
   140  		RecordSet: armprivatedns.RecordSet{
   141  			Properties: &armprivatedns.RecordSetProperties{
   142  				TTL:      &ttl,
   143  				Metadata: azureTags,
   144  			},
   145  		},
   146  	}
   147  
   148  	switch rType {
   149  	case cname:
   150  		record.RecordType = armprivatedns.RecordTypeCNAME
   151  		record.RecordSet.Properties.CnameRecord = &armprivatedns.CnameRecord{
   152  			Cname: &recordName,
   153  		}
   154  	case arecord:
   155  		record.RecordType = armprivatedns.RecordTypeA
   156  		record.RecordSet.Properties.ARecords = []*armprivatedns.ARecord{
   157  			{
   158  				IPv4Address: &ipAddress,
   159  			},
   160  		}
   161  	case aaaarecord:
   162  		record.RecordType = armprivatedns.RecordTypeAAAA
   163  		record.RecordSet.Properties.AaaaRecords = []*armprivatedns.AaaaRecord{
   164  			{
   165  				IPv6Address: &ipAddress,
   166  			},
   167  		}
   168  	}
   169  	return record
   170  }
   171  
   172  func createRecordSet(lbType string, azureTags map[string]*string, ttl int64, rType recordListType, ipAddress string, recordName string) (record recordList) {
   173  	record = recordList{
   174  		Name: lbType,
   175  		RecordSet: armdns.RecordSet{
   176  			Properties: &armdns.RecordSetProperties{
   177  				TTL:      &ttl,
   178  				Metadata: azureTags,
   179  			},
   180  		},
   181  	}
   182  
   183  	switch rType {
   184  	case cname:
   185  		record.RecordType = armdns.RecordTypeCNAME
   186  		record.RecordSet.Properties.CnameRecord = &armdns.CnameRecord{
   187  			Cname: &recordName,
   188  		}
   189  	case arecord:
   190  		record.RecordType = armdns.RecordTypeA
   191  		record.RecordSet.Properties.ARecords = []*armdns.ARecord{
   192  			{
   193  				IPv4Address: &ipAddress,
   194  			},
   195  		}
   196  	case aaaarecord:
   197  		record.RecordType = armdns.RecordTypeAAAA
   198  		record.RecordSet.Properties.AaaaRecords = []*armdns.AaaaRecord{
   199  			{
   200  				IPv6Address: &ipAddress,
   201  			},
   202  		}
   203  	}
   204  	return record
   205  }