@@ -3,7 +3,6 @@ package azure
33import (
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.
2832type 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
3943var _ clusterapi.PreProvider = (* Provider )(nil )
4044var _ clusterapi.InfraReadyProvider = (* Provider )(nil )
45+ var _ clusterapi.PostProvider = (* Provider )(nil )
4146
4247// Name returns the name of the provider.
4348func (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
330461func randomString (length int ) string {
0 commit comments