Skip to content

Commit ac3ac89

Browse files
Merge pull request #8115 from patrickdillon/azure-capi-lb
CORS-3195: Azure CAPI Supplemental Load Balancers
2 parents e2dafac + 1eb9d4f commit ac3ac89

File tree

152 files changed

+107027
-8
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

152 files changed

+107027
-8
lines changed

go.mod

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ require (
1313
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/dns/armdns v1.2.0
1414
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/msi/armmsi v1.2.0
1515
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/network/armnetwork v1.0.0
16+
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/network/armnetwork/v2 v2.2.1
1617
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/privatedns/armprivatedns v1.2.0
1718
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resourcegraph/armresourcegraph v0.8.2
1819
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resources/armresources v1.1.1

go.sum

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1192,6 +1192,8 @@ github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/msi/armmsi v1.2.0 h1:z4Yei
11921192
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/msi/armmsi v1.2.0/go.mod h1:rko9SzMxcMk0NJsNAxALEGaTYyy79bNRwxgJfrH0Spw=
11931193
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/network/armnetwork v1.0.0 h1:nBy98uKOIfun5z6wx6jwWLrULcM0+cjBalBFZlEZ7CA=
11941194
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/network/armnetwork v1.0.0/go.mod h1:243D9iHbcQXoFUtgHJwL7gl2zx1aDuDMjvBZVGr2uW0=
1195+
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/network/armnetwork/v2 v2.2.1 h1:bWh0Z2rOEDfB/ywv/l0iHN1JgyazE6kW/aIA89+CEK0=
1196+
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/network/armnetwork/v2 v2.2.1/go.mod h1:Bzf34hhAE9NSxailk8xVeLEZbUjOXcC+GnU1mMKdhLw=
11951197
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/privatedns/armprivatedns v1.2.0 h1:9Eih8XcEeQnFD0ntMlUDleKMzfeCeUfa+VbnDCI4AZs=
11961198
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/privatedns/armprivatedns v1.2.0/go.mod h1:wGPyTi+aURdqPAGMZDQqnNs9IrShADF8w2WZb6bKeq0=
11971199
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resourcegraph/armresourcegraph v0.8.2 h1:f9lam+D19V0TDn17+aFhrVhWPpfsF5zaGHeqDGJZAVc=

pkg/infrastructure/azure/azure.go

Lines changed: 136 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ package azure
33
import (
44
"context"
55
"fmt"
6-
"log"
76
"math/rand"
87
"net/http"
98
"strings"
@@ -13,31 +12,37 @@ import (
1312
"github.com/Azure/azure-sdk-for-go/sdk/azcore/policy"
1413
"github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/compute/armcompute/v4"
1514
"github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/msi/armmsi"
15+
"github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/network/armnetwork/v2"
1616
"github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resources/armresources"
1717
"github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage"
1818
"github.com/coreos/stream-metadata-go/arch"
1919
"github.com/sirupsen/logrus"
2020
"k8s.io/utils/ptr"
21+
capz "sigs.k8s.io/cluster-api-provider-azure/api/v1beta1"
22+
"sigs.k8s.io/controller-runtime/pkg/client"
2123

24+
"github.com/openshift/installer/pkg/asset/manifests/capiutils"
2225
"github.com/openshift/installer/pkg/infrastructure/clusterapi"
2326
"github.com/openshift/installer/pkg/rhcos"
27+
"github.com/openshift/installer/pkg/types"
2428
aztypes "github.com/openshift/installer/pkg/types/azure"
2529
)
2630

2731
// Provider implements Azure CAPI installation.
2832
type Provider struct {
29-
clusterapi.InfraProvider
3033
ResourceGroupName string
3134
StorageAccountName string
3235
StorageURL string
3336
StorageAccount *armstorage.Account
3437
StorageClientFactory *armstorage.ClientFactory
3538
StorageAccountKeys []armstorage.AccountKey
3639
Tags map[string]*string
40+
lbBackendAddressPool *armnetwork.BackendAddressPool
3741
}
3842

3943
var _ clusterapi.PreProvider = (*Provider)(nil)
4044
var _ clusterapi.InfraReadyProvider = (*Provider)(nil)
45+
var _ clusterapi.PostProvider = (*Provider)(nil)
4146

4247
// Name returns the name of the provider.
4348
func (p *Provider) Name() string {
@@ -158,7 +163,7 @@ func (p *Provider) InfraReady(ctx context.Context, in clusterapi.InfraReadyInput
158163
userAssignedIdentityName := fmt.Sprintf("%s-identity", in.InfraID)
159164
armmsiClientFactory, err := armmsi.NewClientFactory(subscriptionID, tokenCredential, nil)
160165
if err != nil {
161-
log.Fatalf("failed to create armmsi client: %v", err)
166+
return fmt.Errorf("failed to create armmsi client: %w", err)
162167
}
163168
userAssignedIdentity, err := armmsiClientFactory.NewUserAssignedIdentitiesClient().CreateOrUpdate(
164169
ctx,
@@ -171,7 +176,7 @@ func (p *Provider) InfraReady(ctx context.Context, in clusterapi.InfraReadyInput
171176
nil,
172177
)
173178
if err != nil {
174-
log.Fatalf("failed to create user assigned identity %s: %v", userAssignedIdentityName, err)
179+
return fmt.Errorf("failed to create user assigned identity %s: %w", userAssignedIdentityName, err)
175180
}
176181
principalID := *userAssignedIdentity.Properties.PrincipalID
177182

@@ -316,15 +321,141 @@ func (p *Provider) InfraReady(ctx context.Context, in clusterapi.InfraReadyInput
316321
return err
317322
}
318323

324+
networkClientFactory, err := armnetwork.NewClientFactory(subscriptionID, session.TokenCreds, nil)
325+
if err != nil {
326+
return fmt.Errorf("error creating network client factory: %w", err)
327+
}
328+
329+
lbClient := networkClientFactory.NewLoadBalancersClient()
330+
331+
lbInput := &lbInput{
332+
infraID: in.InfraID,
333+
region: in.InstallConfig.Config.Azure.Region,
334+
resourceGroup: resourceGroupName,
335+
subscriptionID: session.Credentials.SubscriptionID,
336+
lbClient: lbClient,
337+
pipClient: networkClientFactory.NewPublicIPAddressesClient(),
338+
}
339+
340+
intLoadBalancer, err := updateInternalLoadBalancer(ctx, lbInput)
341+
if err != nil {
342+
return fmt.Errorf("failed to update internal load balancer: %w", err)
343+
}
344+
logrus.Debugf("updated internal load balancer: %s", *intLoadBalancer.ID)
345+
346+
var lbBap *armnetwork.BackendAddressPool
347+
var extLBFQDN string
348+
if in.InstallConfig.Config.Publish == types.ExternalPublishingStrategy {
349+
publicIP, err := createPublicIP(ctx, lbInput)
350+
if err != nil {
351+
return fmt.Errorf("failed to create public ip: %w", err)
352+
}
353+
logrus.Debugf("created public ip: %s", *publicIP.ID)
354+
355+
loadBalancer, err := createExternalLoadBalancer(ctx, publicIP, lbInput)
356+
if err != nil {
357+
return fmt.Errorf("failed to create load balancer: %w", err)
358+
}
359+
logrus.Debugf("created load balancer: %s", *loadBalancer.ID)
360+
lbBap = loadBalancer.Properties.BackendAddressPools[0]
361+
extLBFQDN = *publicIP.Properties.DNSSettings.Fqdn
362+
}
363+
319364
// Save context for other hooks
320365
p.ResourceGroupName = resourceGroupName
321366
p.StorageAccountName = storageAccountName
322367
p.StorageURL = storageURL
323368
p.StorageAccount = storageAccount
324369
p.StorageClientFactory = storageClientFactory
325370
p.StorageAccountKeys = storageAccountKeys
371+
p.lbBackendAddressPool = lbBap
372+
373+
if err := createDNSEntries(ctx, in, extLBFQDN); err != nil {
374+
return fmt.Errorf("error creating DNS records: %w", err)
375+
}
376+
377+
return nil
378+
}
379+
380+
// PostProvision provisions an external Load Balancer (when appropriate), and adds configuration
381+
// for the MCS to the CAPI-provisioned internal LB.
382+
func (p *Provider) PostProvision(ctx context.Context, in clusterapi.PostProvisionInput) error {
383+
ssn, err := in.InstallConfig.Azure.Session()
384+
if err != nil {
385+
return fmt.Errorf("error retrieving Azure session: %w", err)
386+
}
387+
subscriptionID := ssn.Credentials.SubscriptionID
388+
389+
if in.InstallConfig.Config.Publish == types.ExternalPublishingStrategy {
390+
vmClient, err := armcompute.NewVirtualMachinesClient(subscriptionID, ssn.TokenCreds, nil)
391+
if err != nil {
392+
return fmt.Errorf("error creating vm client: %w", err)
393+
}
394+
nicClient, err := armnetwork.NewInterfacesClient(ssn.Credentials.SubscriptionID, ssn.TokenCreds, nil)
395+
if err != nil {
396+
return fmt.Errorf("error creating nic client: %w", err)
397+
}
398+
399+
vmIDs, err := getControlPlaneIDs(in.Client, in.InstallConfig.Config.ControlPlane.Replicas, in.InfraID)
400+
if err != nil {
401+
return fmt.Errorf("failed to get control plane VM IDs: %w", err)
402+
}
403+
404+
vmInput := &vmInput{
405+
infraID: in.InfraID,
406+
resourceGroup: p.ResourceGroupName,
407+
vmClient: vmClient,
408+
nicClient: nicClient,
409+
ids: vmIDs,
410+
bap: p.lbBackendAddressPool,
411+
}
412+
413+
if err = associateVMToBackendPool(ctx, *vmInput); err != nil {
414+
return fmt.Errorf("failed to associate control plane VMs with external load balancer: %w", err)
415+
}
416+
}
417+
418+
return nil
419+
}
420+
421+
func getControlPlaneIDs(cl client.Client, replicas *int64, infraID string) ([]string, error) {
422+
res := []string{}
423+
total := int64(1)
424+
if replicas != nil {
425+
total = *replicas
426+
}
427+
for i := int64(0); i < total; i++ {
428+
machineName := fmt.Sprintf("%s-master-%d", infraID, i)
429+
key := client.ObjectKey{
430+
Name: machineName,
431+
Namespace: capiutils.Namespace,
432+
}
433+
azureMachine := &capz.AzureMachine{}
434+
if err := cl.Get(context.Background(), key, azureMachine); err != nil {
435+
return nil, fmt.Errorf("failed to get AzureMachine: %w", err)
436+
}
437+
if vmID := azureMachine.Spec.ProviderID; vmID != nil && len(*vmID) != 0 {
438+
res = append(res, *azureMachine.Spec.ProviderID)
439+
} else {
440+
return nil, fmt.Errorf("%s .Spec.ProviderID is empty", machineName)
441+
}
442+
}
326443

327-
return createDNSEntries(ctx, in)
444+
bootstrapName := capiutils.GenerateBoostrapMachineName(infraID)
445+
key := client.ObjectKey{
446+
Name: bootstrapName,
447+
Namespace: capiutils.Namespace,
448+
}
449+
azureMachine := &capz.AzureMachine{}
450+
if err := cl.Get(context.Background(), key, azureMachine); err != nil {
451+
return nil, fmt.Errorf("failed to get AzureMachine: %w", err)
452+
}
453+
if vmID := azureMachine.Spec.ProviderID; vmID != nil && len(*vmID) != 0 {
454+
res = append(res, *azureMachine.Spec.ProviderID)
455+
} else {
456+
return nil, fmt.Errorf("%s .Spec.ProviderID is empty", bootstrapName)
457+
}
458+
return res, nil
328459
}
329460

330461
func randomString(length int) string {

pkg/infrastructure/azure/dns.go

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ type recordPrivateList struct {
3737
}
3838

3939
// Create DNS entries for azure.
40-
func createDNSEntries(ctx context.Context, in clusterapi.InfraReadyInput) error {
40+
func createDNSEntries(ctx context.Context, in clusterapi.InfraReadyInput, extLBFQDN string) error {
4141
private := in.InstallConfig.Config.Publish == types.InternalPublishingStrategy
4242
baseDomainResourceGroup := in.InstallConfig.Config.Azure.BaseDomainResourceGroupName
4343
zone := in.InstallConfig.Config.BaseDomain
@@ -107,8 +107,7 @@ func createDNSEntries(ctx context.Context, in clusterapi.InfraReadyInput) error
107107
// if useIPv6 {
108108
// cnameRecordName = apiExternalNameV6
109109
// }
110-
// TODO: Populate with public LB FQDN. Placeholder text as value.
111-
publicRecords := createRecordSet(cnameRecordName, azureTags, ttl, cname, "", in.InstallConfig.Config.ClusterDomain())
110+
publicRecords := createRecordSet(cnameRecordName, azureTags, ttl, cname, "", extLBFQDN)
112111
_, err = recordSetClient.CreateOrUpdate(ctx, baseDomainResourceGroup, zone, publicRecords.Name, publicRecords.RecordType, publicRecords.RecordSet, nil)
113112
if err != nil {
114113
return fmt.Errorf("failed to create public record set: %w", err)

0 commit comments

Comments
 (0)