sigs.k8s.io/cluster-api-provider-azure@v1.14.3/azure/scope/machine_test.go (about)

     1  /*
     2  Copyright 2018 The Kubernetes Authors.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package scope
    18  
    19  import (
    20  	"context"
    21  	"reflect"
    22  	"testing"
    23  
    24  	"github.com/Azure/azure-sdk-for-go/sdk/azidentity"
    25  	"github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/authorization/armauthorization/v2"
    26  	azureautorest "github.com/Azure/go-autorest/autorest/azure"
    27  	"github.com/Azure/go-autorest/autorest/azure/auth"
    28  	"github.com/google/go-cmp/cmp"
    29  	. "github.com/onsi/gomega"
    30  	"go.uber.org/mock/gomock"
    31  	"k8s.io/apimachinery/pkg/api/resource"
    32  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    33  	"k8s.io/utils/ptr"
    34  	infrav1 "sigs.k8s.io/cluster-api-provider-azure/api/v1beta1"
    35  	"sigs.k8s.io/cluster-api-provider-azure/azure"
    36  	"sigs.k8s.io/cluster-api-provider-azure/azure/mock_azure"
    37  	"sigs.k8s.io/cluster-api-provider-azure/azure/services/disks"
    38  	"sigs.k8s.io/cluster-api-provider-azure/azure/services/inboundnatrules"
    39  	"sigs.k8s.io/cluster-api-provider-azure/azure/services/networkinterfaces"
    40  	"sigs.k8s.io/cluster-api-provider-azure/azure/services/publicips"
    41  	"sigs.k8s.io/cluster-api-provider-azure/azure/services/resourceskus"
    42  	"sigs.k8s.io/cluster-api-provider-azure/azure/services/roleassignments"
    43  	"sigs.k8s.io/cluster-api-provider-azure/azure/services/virtualmachineimages"
    44  	"sigs.k8s.io/cluster-api-provider-azure/azure/services/virtualmachineimages/mock_virtualmachineimages"
    45  	"sigs.k8s.io/cluster-api-provider-azure/azure/services/vmextensions"
    46  	clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1"
    47  )
    48  
    49  func TestMachineScope_Name(t *testing.T) {
    50  	tests := []struct {
    51  		name         string
    52  		machineScope MachineScope
    53  		want         string
    54  		testLength   bool
    55  	}{
    56  		{
    57  			name: "if provider ID exists, use it",
    58  			machineScope: MachineScope{
    59  				AzureMachine: &infrav1.AzureMachine{
    60  					ObjectMeta: metav1.ObjectMeta{
    61  						Name: "machine-with-a-long-name",
    62  					},
    63  					Spec: infrav1.AzureMachineSpec{
    64  						ProviderID: ptr.To("azure:///subscriptions/1234-5678/resourceGroups/my-cluster/providers/Microsoft.Compute/virtualMachines/machine-name"),
    65  						OSDisk: infrav1.OSDisk{
    66  							OSType: "Windows",
    67  						},
    68  					},
    69  				},
    70  			},
    71  			want: "machine-name",
    72  		},
    73  		{
    74  			name: "linux can be any length",
    75  			machineScope: MachineScope{
    76  				AzureMachine: &infrav1.AzureMachine{
    77  					ObjectMeta: metav1.ObjectMeta{
    78  						Name: "machine-with-really-really-long-name",
    79  					},
    80  					Spec: infrav1.AzureMachineSpec{
    81  						OSDisk: infrav1.OSDisk{
    82  							OSType: "Linux",
    83  						},
    84  					},
    85  				},
    86  			},
    87  			want: "machine-with-really-really-long-name",
    88  		},
    89  		{
    90  			name: "Windows name with long MachineName and short cluster name",
    91  			machineScope: MachineScope{
    92  				ClusterScoper: &ClusterScope{
    93  					Cluster: &clusterv1.Cluster{
    94  						ObjectMeta: metav1.ObjectMeta{
    95  							Name: "cluster",
    96  						},
    97  					},
    98  				},
    99  				AzureMachine: &infrav1.AzureMachine{
   100  					TypeMeta: metav1.TypeMeta{},
   101  					ObjectMeta: metav1.ObjectMeta{
   102  						Name: "machine-90123456",
   103  					},
   104  					Spec: infrav1.AzureMachineSpec{
   105  						OSDisk: infrav1.OSDisk{
   106  							OSType: "Windows",
   107  						},
   108  					},
   109  					Status: infrav1.AzureMachineStatus{},
   110  				},
   111  			},
   112  			want:       "machine-9-23456",
   113  			testLength: true,
   114  		},
   115  		{
   116  			name: "Windows name with long MachineName and long cluster name",
   117  			machineScope: MachineScope{
   118  				ClusterScoper: &ClusterScope{
   119  					Cluster: &clusterv1.Cluster{
   120  						ObjectMeta: metav1.ObjectMeta{
   121  							Name: "cluster8901234",
   122  						},
   123  					},
   124  				},
   125  				AzureMachine: &infrav1.AzureMachine{
   126  					TypeMeta: metav1.TypeMeta{},
   127  					ObjectMeta: metav1.ObjectMeta{
   128  						Name: "machine-90123456",
   129  					},
   130  					Spec: infrav1.AzureMachineSpec{
   131  						OSDisk: infrav1.OSDisk{
   132  							OSType: "Windows",
   133  						},
   134  					},
   135  					Status: infrav1.AzureMachineStatus{},
   136  				},
   137  			},
   138  			want:       "machine-9-23456",
   139  			testLength: true,
   140  		},
   141  	}
   142  	for _, tt := range tests {
   143  		t.Run(tt.name, func(t *testing.T) {
   144  			got := tt.machineScope.Name()
   145  			if got != tt.want {
   146  				t.Errorf("MachineScope.Name() = %v, want %v", got, tt.want)
   147  			}
   148  
   149  			if tt.testLength && len(got) > 15 {
   150  				t.Errorf("Length of MachineScope.Name() = %v, want less than %v", len(got), 15)
   151  			}
   152  		})
   153  	}
   154  }
   155  
   156  func TestMachineScope_GetVMID(t *testing.T) {
   157  	tests := []struct {
   158  		name         string
   159  		machineScope MachineScope
   160  		want         string
   161  	}{
   162  		{
   163  			name: "returns the vm name from provider ID",
   164  			machineScope: MachineScope{
   165  				AzureMachine: &infrav1.AzureMachine{
   166  					ObjectMeta: metav1.ObjectMeta{
   167  						Name: "not-this-name",
   168  					},
   169  					Spec: infrav1.AzureMachineSpec{
   170  						ProviderID: ptr.To("azure:///subscriptions/1234-5678/resourceGroups/my-cluster/providers/Microsoft.Compute/virtualMachines/machine-name"),
   171  					},
   172  				},
   173  			},
   174  			want: "machine-name",
   175  		},
   176  		{
   177  			name: "returns empty if provider ID is invalid",
   178  			machineScope: MachineScope{
   179  				AzureMachine: &infrav1.AzureMachine{
   180  					ObjectMeta: metav1.ObjectMeta{
   181  						Name: "machine-name",
   182  					},
   183  					Spec: infrav1.AzureMachineSpec{
   184  						ProviderID: ptr.To("foo"),
   185  					},
   186  				},
   187  			},
   188  			want: "",
   189  		},
   190  	}
   191  	for _, tt := range tests {
   192  		t.Run(tt.name, func(t *testing.T) {
   193  			got := tt.machineScope.GetVMID()
   194  			if got != tt.want {
   195  				t.Errorf("MachineScope.GetVMID() = %v, want %v", got, tt.want)
   196  			}
   197  		})
   198  	}
   199  }
   200  
   201  func TestMachineScope_ProviderID(t *testing.T) {
   202  	tests := []struct {
   203  		name         string
   204  		machineScope MachineScope
   205  		want         string
   206  	}{
   207  		{
   208  			name: "returns the entire provider ID",
   209  			machineScope: MachineScope{
   210  				AzureMachine: &infrav1.AzureMachine{
   211  					ObjectMeta: metav1.ObjectMeta{
   212  						Name: "not-this-name",
   213  					},
   214  					Spec: infrav1.AzureMachineSpec{
   215  						ProviderID: ptr.To("azure:///subscriptions/1234-5678/resourceGroups/my-cluster/providers/Microsoft.Compute/virtualMachines/machine-name"),
   216  					},
   217  				},
   218  			},
   219  			want: "azure:///subscriptions/1234-5678/resourceGroups/my-cluster/providers/Microsoft.Compute/virtualMachines/machine-name",
   220  		},
   221  		{
   222  			name: "returns empty if provider ID is empty",
   223  			machineScope: MachineScope{
   224  				AzureMachine: &infrav1.AzureMachine{
   225  					ObjectMeta: metav1.ObjectMeta{
   226  						Name: "machine-name",
   227  					},
   228  					Spec: infrav1.AzureMachineSpec{
   229  						ProviderID: ptr.To(""),
   230  					},
   231  				},
   232  			},
   233  			want: "",
   234  		},
   235  	}
   236  	for _, tt := range tests {
   237  		t.Run(tt.name, func(t *testing.T) {
   238  			got := tt.machineScope.ProviderID()
   239  			if got != tt.want {
   240  				t.Errorf("MachineScope.ProviderID() = %v, want %v", got, tt.want)
   241  			}
   242  		})
   243  	}
   244  }
   245  
   246  func TestMachineScope_PublicIPSpecs(t *testing.T) {
   247  	tests := []struct {
   248  		name         string
   249  		machineScope MachineScope
   250  		want         []azure.ResourceSpecGetter
   251  	}{
   252  		{
   253  			name: "returns nil if AllocatePublicIP is false",
   254  			machineScope: MachineScope{
   255  				AzureMachine: &infrav1.AzureMachine{
   256  					ObjectMeta: metav1.ObjectMeta{
   257  						Name: "machine-name",
   258  					},
   259  					Spec: infrav1.AzureMachineSpec{
   260  						AllocatePublicIP: false,
   261  					},
   262  				},
   263  			},
   264  			want: nil,
   265  		},
   266  		{
   267  			name: "appends to PublicIPSpec for node if AllocatePublicIP is true",
   268  			machineScope: MachineScope{
   269  				AzureMachine: &infrav1.AzureMachine{
   270  					ObjectMeta: metav1.ObjectMeta{
   271  						Name: "machine-name",
   272  					},
   273  					Spec: infrav1.AzureMachineSpec{
   274  						AllocatePublicIP: true,
   275  					},
   276  				},
   277  				ClusterScoper: &ClusterScope{
   278  					Cluster: &clusterv1.Cluster{
   279  						ObjectMeta: metav1.ObjectMeta{
   280  							Name: "my-cluster",
   281  							// Note: m.ClusterName() takes the value from the Cluster object, not the AzureCluster object
   282  						},
   283  					},
   284  					AzureCluster: &infrav1.AzureCluster{
   285  						ObjectMeta: metav1.ObjectMeta{
   286  							Name: "my-cluster",
   287  						},
   288  						Status: infrav1.AzureClusterStatus{
   289  							FailureDomains: map[string]clusterv1.FailureDomainSpec{
   290  								"failure-domain-id-1": {},
   291  								"failure-domain-id-2": {},
   292  								"failure-domain-id-3": {},
   293  							},
   294  						},
   295  						Spec: infrav1.AzureClusterSpec{
   296  							ResourceGroup: "my-rg",
   297  							AzureClusterClassSpec: infrav1.AzureClusterClassSpec{
   298  								SubscriptionID: "123",
   299  								Location:       "centralIndia",
   300  								AdditionalTags: infrav1.Tags{
   301  									"Name": "my-publicip-ipv6",
   302  									"sigs.k8s.io_cluster-api-provider-azure_cluster_my-cluster": "owned",
   303  								},
   304  							},
   305  							NetworkSpec: infrav1.NetworkSpec{
   306  								APIServerLB: infrav1.LoadBalancerSpec{
   307  									LoadBalancerClassSpec: infrav1.LoadBalancerClassSpec{
   308  										Type: infrav1.Internal,
   309  									},
   310  								},
   311  							},
   312  						},
   313  					},
   314  				},
   315  			},
   316  			want: []azure.ResourceSpecGetter{
   317  				&publicips.PublicIPSpec{
   318  					Name:           "pip-machine-name",
   319  					ResourceGroup:  "my-rg",
   320  					DNSName:        "",
   321  					IsIPv6:         false,
   322  					ClusterName:    "my-cluster",
   323  					Location:       "centralIndia",
   324  					FailureDomains: []*string{ptr.To("failure-domain-id-1"), ptr.To("failure-domain-id-2"), ptr.To("failure-domain-id-3")},
   325  					AdditionalTags: infrav1.Tags{
   326  						"Name": "my-publicip-ipv6",
   327  						"sigs.k8s.io_cluster-api-provider-azure_cluster_my-cluster": "owned",
   328  					},
   329  				},
   330  			},
   331  		},
   332  	}
   333  	for _, tt := range tests {
   334  		t.Run(tt.name, func(t *testing.T) {
   335  			if got := tt.machineScope.PublicIPSpecs(); !reflect.DeepEqual(got, tt.want) {
   336  				t.Errorf("PublicIPSpecs() expected but got: %s", cmp.Diff(tt.want, got))
   337  			}
   338  		})
   339  	}
   340  }
   341  
   342  func TestMachineScope_InboundNatSpecs(t *testing.T) {
   343  	tests := []struct {
   344  		name         string
   345  		machineScope MachineScope
   346  		want         []azure.ResourceSpecGetter
   347  	}{
   348  		{
   349  			name: "returns empty when infra is not control plane",
   350  			machineScope: MachineScope{
   351  				Machine: &clusterv1.Machine{},
   352  				AzureMachine: &infrav1.AzureMachine{
   353  					ObjectMeta: metav1.ObjectMeta{
   354  						Name: "machine-name",
   355  					},
   356  				},
   357  			},
   358  			want: []azure.ResourceSpecGetter{},
   359  		},
   360  		{
   361  			name: "returns InboundNatSpec when infra is control plane",
   362  			machineScope: MachineScope{
   363  				Machine: &clusterv1.Machine{
   364  					ObjectMeta: metav1.ObjectMeta{
   365  						Labels: map[string]string{
   366  							clusterv1.MachineControlPlaneLabel: "",
   367  						},
   368  					},
   369  				},
   370  				AzureMachine: &infrav1.AzureMachine{
   371  					ObjectMeta: metav1.ObjectMeta{
   372  						Name: "machine-name",
   373  					},
   374  				},
   375  				ClusterScoper: &ClusterScope{
   376  					AzureClients: AzureClients{
   377  						EnvironmentSettings: auth.EnvironmentSettings{
   378  							Values: map[string]string{
   379  								auth.SubscriptionID: "123",
   380  							},
   381  						},
   382  					},
   383  					AzureCluster: &infrav1.AzureCluster{
   384  						Spec: infrav1.AzureClusterSpec{
   385  							ResourceGroup: "my-rg",
   386  							AzureClusterClassSpec: infrav1.AzureClusterClassSpec{
   387  								SubscriptionID: "123",
   388  							},
   389  							NetworkSpec: infrav1.NetworkSpec{
   390  								APIServerLB: infrav1.LoadBalancerSpec{
   391  									Name: "foo-loadbalancer",
   392  									FrontendIPs: []infrav1.FrontendIP{
   393  										{
   394  											Name: "foo-frontend-ip",
   395  										},
   396  									},
   397  								},
   398  							},
   399  						},
   400  					},
   401  				},
   402  			},
   403  			want: []azure.ResourceSpecGetter{
   404  				&inboundnatrules.InboundNatSpec{
   405  					Name:                      "machine-name",
   406  					LoadBalancerName:          "foo-loadbalancer",
   407  					ResourceGroup:             "my-rg",
   408  					FrontendIPConfigurationID: ptr.To(azure.FrontendIPConfigID("123", "my-rg", "foo-loadbalancer", "foo-frontend-ip")),
   409  				},
   410  			},
   411  		},
   412  	}
   413  	for _, tt := range tests {
   414  		tt := tt
   415  		t.Run(tt.name, func(t *testing.T) {
   416  			t.Parallel()
   417  			if got := tt.machineScope.InboundNatSpecs(); !reflect.DeepEqual(got, tt.want) {
   418  				t.Errorf("InboundNatSpecs() = %s, want %s", specArrayToString(got), specArrayToString(tt.want))
   419  			}
   420  		})
   421  	}
   422  }
   423  
   424  func TestMachineScope_RoleAssignmentSpecs(t *testing.T) {
   425  	tests := []struct {
   426  		name         string
   427  		machineScope MachineScope
   428  		want         []azure.ResourceSpecGetter
   429  	}{
   430  		{
   431  			name: "returns empty if VM identity is not system assigned",
   432  			machineScope: MachineScope{
   433  				Machine: &clusterv1.Machine{},
   434  				AzureMachine: &infrav1.AzureMachine{
   435  					ObjectMeta: metav1.ObjectMeta{
   436  						Name: "machine-name",
   437  					},
   438  				},
   439  			},
   440  			want: []azure.ResourceSpecGetter{},
   441  		},
   442  		{
   443  			name: "returns RoleAssignmentSpec if VM identity is system assigned",
   444  			machineScope: MachineScope{
   445  				Machine: &clusterv1.Machine{},
   446  				AzureMachine: &infrav1.AzureMachine{
   447  					ObjectMeta: metav1.ObjectMeta{
   448  						Name: "machine-name",
   449  					},
   450  					Spec: infrav1.AzureMachineSpec{
   451  						Identity: infrav1.VMIdentitySystemAssigned,
   452  						SystemAssignedIdentityRole: &infrav1.SystemAssignedIdentityRole{
   453  							Name: "azure-role-assignment-name",
   454  						},
   455  					},
   456  				},
   457  				ClusterScoper: &ClusterScope{
   458  					AzureClients: AzureClients{
   459  						EnvironmentSettings: auth.EnvironmentSettings{
   460  							Values: map[string]string{
   461  								auth.SubscriptionID: "123",
   462  							},
   463  						},
   464  					},
   465  					AzureCluster: &infrav1.AzureCluster{
   466  						Spec: infrav1.AzureClusterSpec{
   467  							ResourceGroup: "my-rg",
   468  							AzureClusterClassSpec: infrav1.AzureClusterClassSpec{
   469  								Location: "westus",
   470  							},
   471  						},
   472  					},
   473  				},
   474  			},
   475  			want: []azure.ResourceSpecGetter{
   476  				&roleassignments.RoleAssignmentSpec{
   477  					ResourceType:  azure.VirtualMachine,
   478  					MachineName:   "machine-name",
   479  					Name:          "azure-role-assignment-name",
   480  					ResourceGroup: "my-rg",
   481  					PrincipalID:   ptr.To("fakePrincipalID"),
   482  					PrincipalType: armauthorization.PrincipalTypeServicePrincipal,
   483  				},
   484  			},
   485  		},
   486  		{
   487  			name: "returns RoleAssignmentSpec with specified scope and role assignment id",
   488  			machineScope: MachineScope{
   489  				Machine: &clusterv1.Machine{},
   490  				AzureMachine: &infrav1.AzureMachine{
   491  					ObjectMeta: metav1.ObjectMeta{
   492  						Name: "machine-name",
   493  					},
   494  					Spec: infrav1.AzureMachineSpec{
   495  						Identity: infrav1.VMIdentitySystemAssigned,
   496  						SystemAssignedIdentityRole: &infrav1.SystemAssignedIdentityRole{
   497  							Name:         "azure-role-assignment-name",
   498  							Scope:        "/subscriptions/123/resourceGroups/my-rg",
   499  							DefinitionID: "/subscriptions/123/resourceGroups/my-rg/providers/Microsoft.Authorization/roleAssignments/123",
   500  						},
   501  					},
   502  				},
   503  				ClusterScoper: &ClusterScope{
   504  					AzureClients: AzureClients{
   505  						EnvironmentSettings: auth.EnvironmentSettings{
   506  							Values: map[string]string{
   507  								auth.SubscriptionID: "123",
   508  							},
   509  						},
   510  					},
   511  					AzureCluster: &infrav1.AzureCluster{
   512  						Spec: infrav1.AzureClusterSpec{
   513  							ResourceGroup: "my-rg",
   514  							AzureClusterClassSpec: infrav1.AzureClusterClassSpec{
   515  								Location: "westus",
   516  							},
   517  						},
   518  					},
   519  				},
   520  			},
   521  			want: []azure.ResourceSpecGetter{
   522  				&roleassignments.RoleAssignmentSpec{
   523  					ResourceType:     azure.VirtualMachine,
   524  					MachineName:      "machine-name",
   525  					Name:             "azure-role-assignment-name",
   526  					ResourceGroup:    "my-rg",
   527  					Scope:            "/subscriptions/123/resourceGroups/my-rg",
   528  					RoleDefinitionID: "/subscriptions/123/resourceGroups/my-rg/providers/Microsoft.Authorization/roleAssignments/123",
   529  					PrincipalID:      ptr.To("fakePrincipalID"),
   530  					PrincipalType:    armauthorization.PrincipalTypeServicePrincipal,
   531  				},
   532  			},
   533  		},
   534  	}
   535  	for _, tt := range tests {
   536  		t.Run(tt.name, func(t *testing.T) {
   537  			if got := tt.machineScope.RoleAssignmentSpecs(ptr.To("fakePrincipalID")); !reflect.DeepEqual(got, tt.want) {
   538  				t.Errorf("RoleAssignmentSpecs() = %v, want %v", got, tt.want)
   539  			}
   540  		})
   541  	}
   542  }
   543  
   544  func TestMachineScope_VMExtensionSpecs(t *testing.T) {
   545  	tests := []struct {
   546  		name         string
   547  		machineScope MachineScope
   548  		want         []azure.ResourceSpecGetter
   549  	}{
   550  		{
   551  			name: "If OS type is Linux and cloud is AzurePublicCloud, it returns ExtensionSpec",
   552  			machineScope: MachineScope{
   553  				Machine: &clusterv1.Machine{},
   554  				AzureMachine: &infrav1.AzureMachine{
   555  					ObjectMeta: metav1.ObjectMeta{
   556  						Name: "machine-name",
   557  					},
   558  					Spec: infrav1.AzureMachineSpec{
   559  						OSDisk: infrav1.OSDisk{
   560  							OSType: "Linux",
   561  						},
   562  					},
   563  				},
   564  				ClusterScoper: &ClusterScope{
   565  					AzureClients: AzureClients{
   566  						EnvironmentSettings: auth.EnvironmentSettings{
   567  							Environment: azureautorest.Environment{
   568  								Name: azureautorest.PublicCloud.Name,
   569  							},
   570  						},
   571  					},
   572  					AzureCluster: &infrav1.AzureCluster{
   573  						Spec: infrav1.AzureClusterSpec{
   574  							ResourceGroup: "my-rg",
   575  							AzureClusterClassSpec: infrav1.AzureClusterClassSpec{
   576  								Location: "westus",
   577  							},
   578  						},
   579  					},
   580  				},
   581  				cache: &MachineCache{
   582  					VMSKU: resourceskus.SKU{},
   583  				},
   584  			},
   585  			want: []azure.ResourceSpecGetter{
   586  				&vmextensions.VMExtensionSpec{
   587  					ExtensionSpec: azure.ExtensionSpec{
   588  						Name:      "CAPZ.Linux.Bootstrapping",
   589  						VMName:    "machine-name",
   590  						Publisher: "Microsoft.Azure.ContainerUpstream",
   591  						Version:   "1.0",
   592  						ProtectedSettings: map[string]string{
   593  							"commandToExecute": azure.LinuxBootstrapExtensionCommand,
   594  						},
   595  					},
   596  					ResourceGroup: "my-rg",
   597  					Location:      "westus",
   598  				},
   599  			},
   600  		},
   601  		{
   602  			name: "If OS type is Linux and cloud is not AzurePublicCloud, it returns empty",
   603  			machineScope: MachineScope{
   604  				Machine: &clusterv1.Machine{},
   605  				AzureMachine: &infrav1.AzureMachine{
   606  					ObjectMeta: metav1.ObjectMeta{
   607  						Name: "machine-name",
   608  					},
   609  					Spec: infrav1.AzureMachineSpec{
   610  						OSDisk: infrav1.OSDisk{
   611  							OSType: "Linux",
   612  						},
   613  					},
   614  				},
   615  				ClusterScoper: &ClusterScope{
   616  					AzureClients: AzureClients{
   617  						EnvironmentSettings: auth.EnvironmentSettings{
   618  							Environment: azureautorest.Environment{
   619  								Name: azureautorest.USGovernmentCloud.Name,
   620  							},
   621  						},
   622  					},
   623  					AzureCluster: &infrav1.AzureCluster{
   624  						Spec: infrav1.AzureClusterSpec{
   625  							ResourceGroup: "my-rg",
   626  							AzureClusterClassSpec: infrav1.AzureClusterClassSpec{
   627  								Location: "westus",
   628  							},
   629  						},
   630  					},
   631  				},
   632  				cache: &MachineCache{
   633  					VMSKU: resourceskus.SKU{},
   634  				},
   635  			},
   636  			want: []azure.ResourceSpecGetter{},
   637  		},
   638  		{
   639  			name: "If OS type is Windows and cloud is AzurePublicCloud, it returns ExtensionSpec",
   640  			machineScope: MachineScope{
   641  				Machine: &clusterv1.Machine{},
   642  				AzureMachine: &infrav1.AzureMachine{
   643  					ObjectMeta: metav1.ObjectMeta{
   644  						Name: "machine-name",
   645  					},
   646  					Spec: infrav1.AzureMachineSpec{
   647  						OSDisk: infrav1.OSDisk{
   648  							OSType: "Windows",
   649  						},
   650  					},
   651  				},
   652  				ClusterScoper: &ClusterScope{
   653  					AzureClients: AzureClients{
   654  						EnvironmentSettings: auth.EnvironmentSettings{
   655  							Environment: azureautorest.Environment{
   656  								Name: azureautorest.PublicCloud.Name,
   657  							},
   658  						},
   659  					},
   660  					AzureCluster: &infrav1.AzureCluster{
   661  						Spec: infrav1.AzureClusterSpec{
   662  							ResourceGroup: "my-rg",
   663  							AzureClusterClassSpec: infrav1.AzureClusterClassSpec{
   664  								Location: "westus",
   665  							},
   666  						},
   667  					},
   668  				},
   669  				cache: &MachineCache{
   670  					VMSKU: resourceskus.SKU{},
   671  				},
   672  			},
   673  			want: []azure.ResourceSpecGetter{
   674  				&vmextensions.VMExtensionSpec{
   675  					ExtensionSpec: azure.ExtensionSpec{
   676  						Name:      "CAPZ.Windows.Bootstrapping",
   677  						VMName:    "machine-name",
   678  						Publisher: "Microsoft.Azure.ContainerUpstream",
   679  						Version:   "1.0",
   680  						ProtectedSettings: map[string]string{
   681  							"commandToExecute": azure.WindowsBootstrapExtensionCommand,
   682  						},
   683  					},
   684  					ResourceGroup: "my-rg",
   685  					Location:      "westus",
   686  				},
   687  			},
   688  		},
   689  		{
   690  			name: "If OS type is Windows and cloud is not AzurePublicCloud, it returns empty",
   691  			machineScope: MachineScope{
   692  				Machine: &clusterv1.Machine{},
   693  				AzureMachine: &infrav1.AzureMachine{
   694  					ObjectMeta: metav1.ObjectMeta{
   695  						Name: "machine-name",
   696  					},
   697  					Spec: infrav1.AzureMachineSpec{
   698  						OSDisk: infrav1.OSDisk{
   699  							OSType: "Windows",
   700  						},
   701  					},
   702  				},
   703  				ClusterScoper: &ClusterScope{
   704  					AzureClients: AzureClients{
   705  						EnvironmentSettings: auth.EnvironmentSettings{
   706  							Environment: azureautorest.Environment{
   707  								Name: azureautorest.USGovernmentCloud.Name,
   708  							},
   709  						},
   710  					},
   711  					AzureCluster: &infrav1.AzureCluster{
   712  						Spec: infrav1.AzureClusterSpec{
   713  							ResourceGroup: "my-rg",
   714  							AzureClusterClassSpec: infrav1.AzureClusterClassSpec{
   715  								Location: "westus",
   716  							},
   717  						},
   718  					},
   719  				},
   720  				cache: &MachineCache{
   721  					VMSKU: resourceskus.SKU{},
   722  				},
   723  			},
   724  			want: []azure.ResourceSpecGetter{},
   725  		},
   726  		{
   727  			name: "If OS type is not Linux or Windows and cloud is AzurePublicCloud, it returns empty",
   728  			machineScope: MachineScope{
   729  				Machine: &clusterv1.Machine{},
   730  				AzureMachine: &infrav1.AzureMachine{
   731  					ObjectMeta: metav1.ObjectMeta{
   732  						Name: "machine-name",
   733  					},
   734  					Spec: infrav1.AzureMachineSpec{
   735  						OSDisk: infrav1.OSDisk{
   736  							OSType: "Other",
   737  						},
   738  					},
   739  				},
   740  				ClusterScoper: &ClusterScope{
   741  					AzureClients: AzureClients{
   742  						EnvironmentSettings: auth.EnvironmentSettings{
   743  							Environment: azureautorest.Environment{
   744  								Name: azureautorest.PublicCloud.Name,
   745  							},
   746  						},
   747  					},
   748  					AzureCluster: &infrav1.AzureCluster{
   749  						Spec: infrav1.AzureClusterSpec{
   750  							ResourceGroup: "my-rg",
   751  							AzureClusterClassSpec: infrav1.AzureClusterClassSpec{
   752  								Location: "westus",
   753  							},
   754  						},
   755  					},
   756  				},
   757  				cache: &MachineCache{
   758  					VMSKU: resourceskus.SKU{},
   759  				},
   760  			},
   761  			want: []azure.ResourceSpecGetter{},
   762  		},
   763  		{
   764  			name: "If OS type is not Windows or Linux and cloud is not AzurePublicCloud, it returns empty",
   765  			machineScope: MachineScope{
   766  				Machine: &clusterv1.Machine{},
   767  				AzureMachine: &infrav1.AzureMachine{
   768  					ObjectMeta: metav1.ObjectMeta{
   769  						Name: "machine-name",
   770  					},
   771  					Spec: infrav1.AzureMachineSpec{
   772  						OSDisk: infrav1.OSDisk{
   773  							OSType: "Other",
   774  						},
   775  					},
   776  				},
   777  				ClusterScoper: &ClusterScope{
   778  					AzureClients: AzureClients{
   779  						EnvironmentSettings: auth.EnvironmentSettings{
   780  							Environment: azureautorest.Environment{
   781  								Name: azureautorest.USGovernmentCloud.Name,
   782  							},
   783  						},
   784  					},
   785  					AzureCluster: &infrav1.AzureCluster{
   786  						Spec: infrav1.AzureClusterSpec{
   787  							ResourceGroup: "my-rg",
   788  							AzureClusterClassSpec: infrav1.AzureClusterClassSpec{
   789  								Location: "westus",
   790  							},
   791  						},
   792  					},
   793  				},
   794  				cache: &MachineCache{
   795  					VMSKU: resourceskus.SKU{},
   796  				},
   797  			},
   798  			want: []azure.ResourceSpecGetter{},
   799  		},
   800  		{
   801  			name: "If a custom VM extension is specified, it returns the custom VM extension",
   802  			machineScope: MachineScope{
   803  				Machine: &clusterv1.Machine{},
   804  				AzureMachine: &infrav1.AzureMachine{
   805  					ObjectMeta: metav1.ObjectMeta{
   806  						Name: "machine-name",
   807  					},
   808  					Spec: infrav1.AzureMachineSpec{
   809  						OSDisk: infrav1.OSDisk{
   810  							OSType: "Linux",
   811  						},
   812  						VMExtensions: []infrav1.VMExtension{
   813  							{
   814  								Name:      "custom-vm-extension",
   815  								Publisher: "Microsoft.Azure.Extensions",
   816  								Version:   "2.0",
   817  								Settings: map[string]string{
   818  									"timestamp": "1234567890",
   819  								},
   820  								ProtectedSettings: map[string]string{
   821  									"commandToExecute": "echo hello world",
   822  								},
   823  							},
   824  						},
   825  					},
   826  				},
   827  				ClusterScoper: &ClusterScope{
   828  					AzureClients: AzureClients{
   829  						EnvironmentSettings: auth.EnvironmentSettings{
   830  							Environment: azureautorest.Environment{
   831  								Name: azureautorest.PublicCloud.Name,
   832  							},
   833  						},
   834  					},
   835  					AzureCluster: &infrav1.AzureCluster{
   836  						Spec: infrav1.AzureClusterSpec{
   837  							ResourceGroup: "my-rg",
   838  							AzureClusterClassSpec: infrav1.AzureClusterClassSpec{
   839  								Location: "westus",
   840  							},
   841  						},
   842  					},
   843  				},
   844  				cache: &MachineCache{
   845  					VMSKU: resourceskus.SKU{},
   846  				},
   847  			},
   848  			want: []azure.ResourceSpecGetter{
   849  				&vmextensions.VMExtensionSpec{
   850  					ExtensionSpec: azure.ExtensionSpec{
   851  						Name:      "custom-vm-extension",
   852  						VMName:    "machine-name",
   853  						Publisher: "Microsoft.Azure.Extensions",
   854  						Version:   "2.0",
   855  						Settings: map[string]string{
   856  							"timestamp": "1234567890",
   857  						},
   858  						ProtectedSettings: map[string]string{
   859  							"commandToExecute": "echo hello world",
   860  						},
   861  					},
   862  					ResourceGroup: "my-rg",
   863  					Location:      "westus",
   864  				},
   865  				&vmextensions.VMExtensionSpec{
   866  					ExtensionSpec: azure.ExtensionSpec{
   867  						Name:      "CAPZ.Linux.Bootstrapping",
   868  						VMName:    "machine-name",
   869  						Publisher: "Microsoft.Azure.ContainerUpstream",
   870  						Version:   "1.0",
   871  						ProtectedSettings: map[string]string{
   872  							"commandToExecute": azure.LinuxBootstrapExtensionCommand,
   873  						},
   874  					},
   875  					ResourceGroup: "my-rg",
   876  					Location:      "westus",
   877  				},
   878  			},
   879  		},
   880  	}
   881  	for _, tt := range tests {
   882  		t.Run(tt.name, func(t *testing.T) {
   883  			if got := tt.machineScope.VMExtensionSpecs(); !reflect.DeepEqual(got, tt.want) {
   884  				t.Errorf("VMExtensionSpecs() = \n%s, want \n%s", specArrayToString(got), specArrayToString(tt.want))
   885  			}
   886  		})
   887  	}
   888  }
   889  
   890  func TestMachineScope_Subnet(t *testing.T) {
   891  	tests := []struct {
   892  		name         string
   893  		machineScope MachineScope
   894  		want         infrav1.SubnetSpec
   895  	}{
   896  		{
   897  			name: "returns empty if no subnet is found at cluster scope",
   898  			machineScope: MachineScope{
   899  				AzureMachine: &infrav1.AzureMachine{
   900  					ObjectMeta: metav1.ObjectMeta{
   901  						Name: "machine-name",
   902  					},
   903  					Spec: infrav1.AzureMachineSpec{
   904  						SubnetName: "machine-name-subnet",
   905  					},
   906  				},
   907  				ClusterScoper: &ClusterScope{
   908  					AzureCluster: &infrav1.AzureCluster{
   909  						Spec: infrav1.AzureClusterSpec{
   910  							NetworkSpec: infrav1.NetworkSpec{
   911  								Subnets: []infrav1.SubnetSpec{},
   912  							},
   913  						},
   914  					},
   915  				},
   916  			},
   917  			want: infrav1.SubnetSpec{},
   918  		},
   919  		{
   920  			name: "returns the machine subnet name if the same is present in the cluster scope",
   921  			machineScope: MachineScope{
   922  				AzureMachine: &infrav1.AzureMachine{
   923  					ObjectMeta: metav1.ObjectMeta{
   924  						Name: "machine-name",
   925  					},
   926  					Spec: infrav1.AzureMachineSpec{
   927  						NetworkInterfaces: []infrav1.NetworkInterface{{
   928  							SubnetName: "machine-name-subnet",
   929  						}},
   930  					},
   931  				},
   932  				ClusterScoper: &ClusterScope{
   933  					AzureCluster: &infrav1.AzureCluster{
   934  						Spec: infrav1.AzureClusterSpec{
   935  							NetworkSpec: infrav1.NetworkSpec{
   936  								Subnets: []infrav1.SubnetSpec{
   937  									{
   938  										SubnetClassSpec: infrav1.SubnetClassSpec{
   939  											Name: "machine-name-subnet",
   940  										},
   941  									},
   942  									{
   943  										SubnetClassSpec: infrav1.SubnetClassSpec{
   944  											Name: "another-machine-name-subnet",
   945  										},
   946  									},
   947  								},
   948  							},
   949  						},
   950  					},
   951  				},
   952  			},
   953  			want: infrav1.SubnetSpec{
   954  				SubnetClassSpec: infrav1.SubnetClassSpec{
   955  					Name: "machine-name-subnet",
   956  				},
   957  			},
   958  		},
   959  		{
   960  			name: "returns empty if machine subnet name is not present in the cluster scope",
   961  			machineScope: MachineScope{
   962  				AzureMachine: &infrav1.AzureMachine{
   963  					ObjectMeta: metav1.ObjectMeta{
   964  						Name: "machine-name",
   965  					},
   966  					Spec: infrav1.AzureMachineSpec{
   967  						SubnetName: "machine-name-subnet",
   968  					},
   969  				},
   970  				ClusterScoper: &ClusterScope{
   971  					AzureCluster: &infrav1.AzureCluster{
   972  						Spec: infrav1.AzureClusterSpec{
   973  							NetworkSpec: infrav1.NetworkSpec{},
   974  						},
   975  					},
   976  				},
   977  			},
   978  			want: infrav1.SubnetSpec{},
   979  		},
   980  	}
   981  	for _, tt := range tests {
   982  		t.Run(tt.name, func(t *testing.T) {
   983  			if got := tt.machineScope.Subnet(); !reflect.DeepEqual(got, tt.want) {
   984  				t.Errorf("Subnet() = %v, want %v", got, tt.want)
   985  			}
   986  		})
   987  	}
   988  }
   989  
   990  func TestMachineScope_AvailabilityZone(t *testing.T) {
   991  	tests := []struct {
   992  		name         string
   993  		machineScope MachineScope
   994  		want         string
   995  	}{
   996  		{
   997  			name: "returns empty if no failure domain is present",
   998  			machineScope: MachineScope{
   999  				Machine: &clusterv1.Machine{
  1000  					Spec: clusterv1.MachineSpec{},
  1001  				},
  1002  				AzureMachine: &infrav1.AzureMachine{
  1003  					ObjectMeta: metav1.ObjectMeta{
  1004  						Name: "machine-name",
  1005  					},
  1006  					Spec: infrav1.AzureMachineSpec{},
  1007  				},
  1008  			},
  1009  			want: "",
  1010  		},
  1011  		{
  1012  			name: "returns failure domain from the machine spec",
  1013  			machineScope: MachineScope{
  1014  				Machine: &clusterv1.Machine{
  1015  					Spec: clusterv1.MachineSpec{
  1016  						FailureDomain: ptr.To("dummy-failure-domain-from-machine-spec"),
  1017  					},
  1018  				},
  1019  				AzureMachine: &infrav1.AzureMachine{
  1020  					ObjectMeta: metav1.ObjectMeta{
  1021  						Name: "machine-name",
  1022  					},
  1023  					Spec: infrav1.AzureMachineSpec{
  1024  						FailureDomain: ptr.To("dummy-failure-domain-from-azuremachine-spec"),
  1025  					},
  1026  				},
  1027  			},
  1028  			want: "dummy-failure-domain-from-machine-spec",
  1029  		},
  1030  		{
  1031  			name: "returns failure domain from the azuremachine spec",
  1032  			machineScope: MachineScope{
  1033  				Machine: &clusterv1.Machine{
  1034  					Spec: clusterv1.MachineSpec{},
  1035  				},
  1036  				AzureMachine: &infrav1.AzureMachine{
  1037  					ObjectMeta: metav1.ObjectMeta{
  1038  						Name: "machine-name",
  1039  					},
  1040  					Spec: infrav1.AzureMachineSpec{
  1041  						FailureDomain: ptr.To("dummy-failure-domain-from-azuremachine-spec"),
  1042  					},
  1043  				},
  1044  			},
  1045  			want: "dummy-failure-domain-from-azuremachine-spec",
  1046  		},
  1047  	}
  1048  	for _, tt := range tests {
  1049  		t.Run(tt.name, func(t *testing.T) {
  1050  			if got := tt.machineScope.AvailabilityZone(); got != tt.want {
  1051  				t.Errorf("AvailabilityZone() = %v, want %v", got, tt.want)
  1052  			}
  1053  		})
  1054  	}
  1055  }
  1056  
  1057  func TestMachineScope_Namespace(t *testing.T) {
  1058  	tests := []struct {
  1059  		name         string
  1060  		machineScope MachineScope
  1061  		want         string
  1062  	}{
  1063  		{
  1064  			name: "returns azure machine namespace",
  1065  			machineScope: MachineScope{
  1066  				AzureMachine: &infrav1.AzureMachine{
  1067  					ObjectMeta: metav1.ObjectMeta{
  1068  						Name:      "machine-name",
  1069  						Namespace: "foo",
  1070  					},
  1071  				},
  1072  			},
  1073  			want: "foo",
  1074  		},
  1075  		{
  1076  			name: "returns azure machine namespace as empty if namespace is no specified",
  1077  			machineScope: MachineScope{
  1078  				AzureMachine: &infrav1.AzureMachine{
  1079  					ObjectMeta: metav1.ObjectMeta{
  1080  						Name: "machine-name",
  1081  					},
  1082  				},
  1083  			},
  1084  			want: "",
  1085  		},
  1086  	}
  1087  	for _, tt := range tests {
  1088  		t.Run(tt.name, func(t *testing.T) {
  1089  			if got := tt.machineScope.Namespace(); got != tt.want {
  1090  				t.Errorf("Namespace() = %v, want %v", got, tt.want)
  1091  			}
  1092  		})
  1093  	}
  1094  }
  1095  
  1096  func TestMachineScope_IsControlPlane(t *testing.T) {
  1097  	tests := []struct {
  1098  		name         string
  1099  		machineScope MachineScope
  1100  		want         bool
  1101  	}{
  1102  		{
  1103  			name: "returns false when machine is not control plane",
  1104  			machineScope: MachineScope{
  1105  				Machine: &clusterv1.Machine{},
  1106  				AzureMachine: &infrav1.AzureMachine{
  1107  					ObjectMeta: metav1.ObjectMeta{
  1108  						Name: "machine-name",
  1109  					},
  1110  				},
  1111  			},
  1112  			want: false,
  1113  		},
  1114  		{
  1115  			name: "returns true when machine is control plane",
  1116  			machineScope: MachineScope{
  1117  				Machine: &clusterv1.Machine{
  1118  					ObjectMeta: metav1.ObjectMeta{
  1119  						Labels: map[string]string{
  1120  							clusterv1.MachineControlPlaneLabel: "",
  1121  						},
  1122  					},
  1123  				},
  1124  				AzureMachine: &infrav1.AzureMachine{
  1125  					ObjectMeta: metav1.ObjectMeta{
  1126  						Name: "machine-name",
  1127  					},
  1128  				},
  1129  			},
  1130  			want: true,
  1131  		},
  1132  	}
  1133  	for _, tt := range tests {
  1134  		t.Run(tt.name, func(t *testing.T) {
  1135  			if got := tt.machineScope.IsControlPlane(); got != tt.want {
  1136  				t.Errorf("IsControlPlane() = %v, want %v", got, tt.want)
  1137  			}
  1138  		})
  1139  	}
  1140  }
  1141  
  1142  func TestMachineScope_Role(t *testing.T) {
  1143  	tests := []struct {
  1144  		name         string
  1145  		machineScope MachineScope
  1146  		want         string
  1147  	}{
  1148  		{
  1149  			name: "returns node when machine is worker",
  1150  			machineScope: MachineScope{
  1151  				Machine: &clusterv1.Machine{},
  1152  				AzureMachine: &infrav1.AzureMachine{
  1153  					ObjectMeta: metav1.ObjectMeta{
  1154  						Name: "machine-name",
  1155  					},
  1156  				},
  1157  			},
  1158  			want: infrav1.Node,
  1159  		},
  1160  		{
  1161  			name: "returns control-plane when machine is control plane",
  1162  			machineScope: MachineScope{
  1163  				Machine: &clusterv1.Machine{
  1164  					ObjectMeta: metav1.ObjectMeta{
  1165  						Labels: map[string]string{
  1166  							clusterv1.MachineControlPlaneLabel: "",
  1167  						},
  1168  					},
  1169  				},
  1170  				AzureMachine: &infrav1.AzureMachine{
  1171  					ObjectMeta: metav1.ObjectMeta{
  1172  						Name: "machine-name",
  1173  					},
  1174  				},
  1175  			},
  1176  			want: infrav1.ControlPlane,
  1177  		},
  1178  	}
  1179  	for _, tt := range tests {
  1180  		t.Run(tt.name, func(t *testing.T) {
  1181  			if got := tt.machineScope.Role(); got != tt.want {
  1182  				t.Errorf("Role() = %v, want %v", got, tt.want)
  1183  			}
  1184  		})
  1185  	}
  1186  }
  1187  
  1188  func TestMachineScope_AvailabilitySet(t *testing.T) {
  1189  	tests := []struct {
  1190  		name                         string
  1191  		machineScope                 MachineScope
  1192  		wantAvailabilitySetName      string
  1193  		wantAvailabilitySetExistence bool
  1194  	}{
  1195  		{
  1196  			name: "returns empty and false if availability set is not enabled",
  1197  			machineScope: MachineScope{
  1198  				ClusterScoper: &ClusterScope{
  1199  					Cluster: &clusterv1.Cluster{
  1200  						ObjectMeta: metav1.ObjectMeta{
  1201  							Name: "cluster",
  1202  						},
  1203  					},
  1204  					AzureCluster: &infrav1.AzureCluster{
  1205  						Status: infrav1.AzureClusterStatus{
  1206  							FailureDomains: clusterv1.FailureDomains{
  1207  								"foo-failure-domain": clusterv1.FailureDomainSpec{},
  1208  							},
  1209  						},
  1210  					},
  1211  				},
  1212  				Machine:      &clusterv1.Machine{},
  1213  				AzureMachine: &infrav1.AzureMachine{},
  1214  			},
  1215  			wantAvailabilitySetName:      "",
  1216  			wantAvailabilitySetExistence: false,
  1217  		},
  1218  		{
  1219  			name: "returns AvailabilitySet name and true if availability set is enabled and machine is control plane",
  1220  			machineScope: MachineScope{
  1221  
  1222  				ClusterScoper: &ClusterScope{
  1223  					Cluster: &clusterv1.Cluster{
  1224  						ObjectMeta: metav1.ObjectMeta{
  1225  							Name: "cluster",
  1226  						},
  1227  					},
  1228  					AzureCluster: &infrav1.AzureCluster{
  1229  						Status: infrav1.AzureClusterStatus{},
  1230  					},
  1231  				},
  1232  				Machine: &clusterv1.Machine{
  1233  					ObjectMeta: metav1.ObjectMeta{
  1234  						Labels: map[string]string{
  1235  							clusterv1.MachineControlPlaneLabel: "",
  1236  						},
  1237  					},
  1238  				},
  1239  				AzureMachine: &infrav1.AzureMachine{},
  1240  			},
  1241  			wantAvailabilitySetName:      "cluster_control-plane-as",
  1242  			wantAvailabilitySetExistence: true,
  1243  		},
  1244  		{
  1245  			name: "returns AvailabilitySet name and true if AvailabilitySet is enabled for worker machine which is part of machine deployment",
  1246  			machineScope: MachineScope{
  1247  
  1248  				ClusterScoper: &ClusterScope{
  1249  					Cluster: &clusterv1.Cluster{
  1250  						ObjectMeta: metav1.ObjectMeta{
  1251  							Name: "cluster",
  1252  						},
  1253  					},
  1254  					AzureCluster: &infrav1.AzureCluster{
  1255  						Status: infrav1.AzureClusterStatus{},
  1256  					},
  1257  				},
  1258  				Machine: &clusterv1.Machine{
  1259  					ObjectMeta: metav1.ObjectMeta{
  1260  						Labels: map[string]string{
  1261  							clusterv1.MachineDeploymentNameLabel: "foo-machine-deployment",
  1262  						},
  1263  					},
  1264  				},
  1265  				AzureMachine: &infrav1.AzureMachine{},
  1266  			},
  1267  			wantAvailabilitySetName:      "cluster_foo-machine-deployment-as",
  1268  			wantAvailabilitySetExistence: true,
  1269  		},
  1270  		{
  1271  			name: "returns empty and false if machine is using spot instances",
  1272  			machineScope: MachineScope{
  1273  				ClusterScoper: &ClusterScope{
  1274  					Cluster: &clusterv1.Cluster{
  1275  						ObjectMeta: metav1.ObjectMeta{
  1276  							Name: "cluster",
  1277  						},
  1278  					},
  1279  					AzureCluster: &infrav1.AzureCluster{
  1280  						Status: infrav1.AzureClusterStatus{},
  1281  					},
  1282  				},
  1283  				Machine: &clusterv1.Machine{
  1284  					ObjectMeta: metav1.ObjectMeta{
  1285  						Labels: map[string]string{
  1286  							clusterv1.MachineDeploymentNameLabel: "foo-machine-deployment",
  1287  						},
  1288  					},
  1289  				},
  1290  				AzureMachine: &infrav1.AzureMachine{
  1291  					Spec: infrav1.AzureMachineSpec{
  1292  						SpotVMOptions: &infrav1.SpotVMOptions{MaxPrice: resource.NewQuantity(-1, resource.DecimalSI)},
  1293  					},
  1294  				},
  1295  			},
  1296  			wantAvailabilitySetName:      "",
  1297  			wantAvailabilitySetExistence: false,
  1298  		},
  1299  		{
  1300  			name: "returns AvailabilitySet name and true if AvailabilitySet is enabled for worker machine which is part of machine set",
  1301  			machineScope: MachineScope{
  1302  
  1303  				ClusterScoper: &ClusterScope{
  1304  					Cluster: &clusterv1.Cluster{
  1305  						ObjectMeta: metav1.ObjectMeta{
  1306  							Name: "cluster",
  1307  						},
  1308  					},
  1309  					AzureCluster: &infrav1.AzureCluster{
  1310  						Status: infrav1.AzureClusterStatus{},
  1311  					},
  1312  				},
  1313  				Machine: &clusterv1.Machine{
  1314  					ObjectMeta: metav1.ObjectMeta{
  1315  						Labels: map[string]string{
  1316  							clusterv1.MachineSetNameLabel: "foo-machine-set",
  1317  						},
  1318  					},
  1319  				},
  1320  				AzureMachine: &infrav1.AzureMachine{},
  1321  			},
  1322  			wantAvailabilitySetName:      "cluster_foo-machine-set-as",
  1323  			wantAvailabilitySetExistence: true,
  1324  		},
  1325  		{
  1326  			name: "returns AvailabilitySet name and true if AvailabilitySet is enabled for worker machine and machine deployment name takes precedence over machine set name",
  1327  			machineScope: MachineScope{
  1328  
  1329  				ClusterScoper: &ClusterScope{
  1330  					Cluster: &clusterv1.Cluster{
  1331  						ObjectMeta: metav1.ObjectMeta{
  1332  							Name: "cluster",
  1333  						},
  1334  					},
  1335  					AzureCluster: &infrav1.AzureCluster{
  1336  						Status: infrav1.AzureClusterStatus{},
  1337  					},
  1338  				},
  1339  				Machine: &clusterv1.Machine{
  1340  					ObjectMeta: metav1.ObjectMeta{
  1341  						Labels: map[string]string{
  1342  							clusterv1.MachineDeploymentNameLabel: "foo-machine-deployment",
  1343  							clusterv1.MachineSetNameLabel:        "foo-machine-set",
  1344  						},
  1345  					},
  1346  				},
  1347  				AzureMachine: &infrav1.AzureMachine{},
  1348  			},
  1349  			wantAvailabilitySetName:      "cluster_foo-machine-deployment-as",
  1350  			wantAvailabilitySetExistence: true,
  1351  		},
  1352  		{
  1353  			name: "returns empty and false if AvailabilitySet is enabled but worker machine is not part of machine deployment or machine set",
  1354  			machineScope: MachineScope{
  1355  
  1356  				ClusterScoper: &ClusterScope{
  1357  					Cluster: &clusterv1.Cluster{
  1358  						ObjectMeta: metav1.ObjectMeta{
  1359  							Name: "cluster",
  1360  						},
  1361  					},
  1362  					AzureCluster: &infrav1.AzureCluster{
  1363  						Status: infrav1.AzureClusterStatus{},
  1364  					},
  1365  				},
  1366  				Machine: &clusterv1.Machine{
  1367  					ObjectMeta: metav1.ObjectMeta{
  1368  						Labels: map[string]string{},
  1369  					},
  1370  				},
  1371  				AzureMachine: &infrav1.AzureMachine{},
  1372  			},
  1373  			wantAvailabilitySetName:      "",
  1374  			wantAvailabilitySetExistence: false,
  1375  		},
  1376  	}
  1377  	for _, tt := range tests {
  1378  		t.Run(tt.name, func(t *testing.T) {
  1379  			gotAvailabilitySetName, gotAvailabilitySetExistence := tt.machineScope.AvailabilitySet()
  1380  			if gotAvailabilitySetName != tt.wantAvailabilitySetName {
  1381  				t.Errorf("AvailabilitySet() gotAvailabilitySetName = %v, wantAvailabilitySetName %v", gotAvailabilitySetName, tt.wantAvailabilitySetName)
  1382  			}
  1383  			if gotAvailabilitySetExistence != tt.wantAvailabilitySetExistence {
  1384  				t.Errorf("AvailabilitySet() gotAvailabilitySetExistence = %v, wantAvailabilitySetExistence %v", gotAvailabilitySetExistence, tt.wantAvailabilitySetExistence)
  1385  			}
  1386  		})
  1387  	}
  1388  }
  1389  
  1390  func TestMachineScope_VMState(t *testing.T) {
  1391  	tests := []struct {
  1392  		name         string
  1393  		machineScope MachineScope
  1394  		want         infrav1.ProvisioningState
  1395  	}{
  1396  		{
  1397  			name: "returns the VMState if present in AzureMachine status",
  1398  			machineScope: MachineScope{
  1399  				AzureMachine: &infrav1.AzureMachine{
  1400  					ObjectMeta: metav1.ObjectMeta{
  1401  						Name: "machine-name",
  1402  					},
  1403  					Status: infrav1.AzureMachineStatus{
  1404  						VMState: func() *infrav1.ProvisioningState {
  1405  							provisioningState := infrav1.Creating
  1406  							return &provisioningState
  1407  						}(),
  1408  					},
  1409  				},
  1410  			},
  1411  			want: infrav1.Creating,
  1412  		},
  1413  		{
  1414  			name: "returns empty if VMState is not present in AzureMachine status",
  1415  			machineScope: MachineScope{
  1416  				AzureMachine: &infrav1.AzureMachine{
  1417  					ObjectMeta: metav1.ObjectMeta{
  1418  						Name: "machine-name",
  1419  					},
  1420  					Status: infrav1.AzureMachineStatus{},
  1421  				},
  1422  			},
  1423  			want: "",
  1424  		},
  1425  	}
  1426  	for _, tt := range tests {
  1427  		t.Run(tt.name, func(t *testing.T) {
  1428  			if got := tt.machineScope.VMState(); got != tt.want {
  1429  				t.Errorf("VMState() = %v, want %v", got, tt.want)
  1430  			}
  1431  		})
  1432  	}
  1433  }
  1434  
  1435  func TestMachineScope_GetVMImage(t *testing.T) {
  1436  	mockCtrl := gomock.NewController(t)
  1437  	defer mockCtrl.Finish()
  1438  
  1439  	clusterMock := mock_azure.NewMockClusterScoper(mockCtrl)
  1440  	clusterMock.EXPECT().Location().AnyTimes()
  1441  	clusterMock.EXPECT().SubscriptionID().AnyTimes()
  1442  	clusterMock.EXPECT().CloudEnvironment().AnyTimes()
  1443  	clusterMock.EXPECT().Token().Return(&azidentity.DefaultAzureCredential{}).AnyTimes()
  1444  	svc := virtualmachineimages.Service{Client: mock_virtualmachineimages.NewMockClient(mockCtrl)}
  1445  
  1446  	tests := []struct {
  1447  		name         string
  1448  		machineScope MachineScope
  1449  		want         *infrav1.Image
  1450  		expectedErr  string
  1451  	}{
  1452  		{
  1453  			name: "returns AzureMachine image is found if present in the AzureMachine spec",
  1454  			machineScope: MachineScope{
  1455  				AzureMachine: &infrav1.AzureMachine{
  1456  					ObjectMeta: metav1.ObjectMeta{
  1457  						Name: "machine-name",
  1458  					},
  1459  					Spec: infrav1.AzureMachineSpec{
  1460  						Image: &infrav1.Image{
  1461  							ID: ptr.To("1"),
  1462  						},
  1463  					},
  1464  				},
  1465  			},
  1466  			want: &infrav1.Image{
  1467  				ID: ptr.To("1"),
  1468  			},
  1469  			expectedErr: "",
  1470  		},
  1471  		{
  1472  			name: "if no image is specified and os specified is windows with version below 1.22, returns windows dockershim image",
  1473  			machineScope: MachineScope{
  1474  				Machine: &clusterv1.Machine{
  1475  					ObjectMeta: metav1.ObjectMeta{
  1476  						Name: "machine-name",
  1477  					},
  1478  					Spec: clusterv1.MachineSpec{
  1479  						Version: ptr.To("1.20.1"),
  1480  					},
  1481  				},
  1482  				AzureMachine: &infrav1.AzureMachine{
  1483  					ObjectMeta: metav1.ObjectMeta{
  1484  						Name: "machine-name",
  1485  					},
  1486  					Spec: infrav1.AzureMachineSpec{
  1487  						OSDisk: infrav1.OSDisk{
  1488  							OSType: azure.WindowsOS,
  1489  						},
  1490  					},
  1491  				},
  1492  				ClusterScoper: clusterMock,
  1493  			},
  1494  			want: func() *infrav1.Image {
  1495  				image, _ := svc.GetDefaultWindowsImage(context.TODO(), "", "1.20.1", "dockershim", "")
  1496  				return image
  1497  			}(),
  1498  			expectedErr: "",
  1499  		},
  1500  		{
  1501  			name: "if no image is specified and os specified is windows with version is 1.22+ with no annotation, returns windows containerd image",
  1502  			machineScope: MachineScope{
  1503  				Machine: &clusterv1.Machine{
  1504  					ObjectMeta: metav1.ObjectMeta{
  1505  						Name: "machine-name",
  1506  					},
  1507  					Spec: clusterv1.MachineSpec{
  1508  						Version: ptr.To("1.22.1"),
  1509  					},
  1510  				},
  1511  				AzureMachine: &infrav1.AzureMachine{
  1512  					ObjectMeta: metav1.ObjectMeta{
  1513  						Name: "machine-name",
  1514  					},
  1515  					Spec: infrav1.AzureMachineSpec{
  1516  						OSDisk: infrav1.OSDisk{
  1517  							OSType: azure.WindowsOS,
  1518  						},
  1519  					},
  1520  				},
  1521  				ClusterScoper: clusterMock,
  1522  			},
  1523  			want: func() *infrav1.Image {
  1524  				image, _ := svc.GetDefaultWindowsImage(context.TODO(), "", "1.22.1", "containerd", "")
  1525  				return image
  1526  			}(),
  1527  			expectedErr: "",
  1528  		},
  1529  		{
  1530  			name: "if no image is specified and os specified is windows with version is 1.22+ with annotation dockershim, returns windows dockershim image",
  1531  			machineScope: MachineScope{
  1532  				Machine: &clusterv1.Machine{
  1533  					ObjectMeta: metav1.ObjectMeta{
  1534  						Name: "machine-name",
  1535  					},
  1536  					Spec: clusterv1.MachineSpec{
  1537  						Version: ptr.To("1.22.1"),
  1538  					},
  1539  				},
  1540  				AzureMachine: &infrav1.AzureMachine{
  1541  					ObjectMeta: metav1.ObjectMeta{
  1542  						Name: "machine-name",
  1543  						Annotations: map[string]string{
  1544  							"runtime": "dockershim",
  1545  						},
  1546  					},
  1547  					Spec: infrav1.AzureMachineSpec{
  1548  						OSDisk: infrav1.OSDisk{
  1549  							OSType: azure.WindowsOS,
  1550  						},
  1551  					},
  1552  				},
  1553  				ClusterScoper: clusterMock,
  1554  			},
  1555  			want: func() *infrav1.Image {
  1556  				image, _ := svc.GetDefaultWindowsImage(context.TODO(), "", "1.22.1", "dockershim", "")
  1557  				return image
  1558  			}(),
  1559  			expectedErr: "",
  1560  		},
  1561  		{
  1562  			name: "if no image is specified and os specified is windows with version is less and 1.22 with annotation dockershim, returns windows dockershim image",
  1563  			machineScope: MachineScope{
  1564  				Machine: &clusterv1.Machine{
  1565  					ObjectMeta: metav1.ObjectMeta{
  1566  						Name: "machine-name",
  1567  					},
  1568  					Spec: clusterv1.MachineSpec{
  1569  						Version: ptr.To("1.21.1"),
  1570  					},
  1571  				},
  1572  				AzureMachine: &infrav1.AzureMachine{
  1573  					ObjectMeta: metav1.ObjectMeta{
  1574  						Name: "machine-name",
  1575  						Annotations: map[string]string{
  1576  							"runtime": "dockershim",
  1577  						},
  1578  					},
  1579  					Spec: infrav1.AzureMachineSpec{
  1580  						OSDisk: infrav1.OSDisk{
  1581  							OSType: azure.WindowsOS,
  1582  						},
  1583  					},
  1584  				},
  1585  				ClusterScoper: clusterMock,
  1586  			},
  1587  			want: func() *infrav1.Image {
  1588  				image, _ := svc.GetDefaultWindowsImage(context.TODO(), "", "1.21.1", "dockershim", "")
  1589  				return image
  1590  			}(),
  1591  			expectedErr: "",
  1592  		},
  1593  		{
  1594  			name: "if no image is specified and os specified is windows with version is less and 1.22 with annotation containerd, returns error",
  1595  			machineScope: MachineScope{
  1596  				Machine: &clusterv1.Machine{
  1597  					ObjectMeta: metav1.ObjectMeta{
  1598  						Name: "machine-name",
  1599  					},
  1600  					Spec: clusterv1.MachineSpec{
  1601  						Version: ptr.To("1.21.1"),
  1602  					},
  1603  				},
  1604  				AzureMachine: &infrav1.AzureMachine{
  1605  					ObjectMeta: metav1.ObjectMeta{
  1606  						Name: "machine-name",
  1607  						Annotations: map[string]string{
  1608  							"runtime": "containerd",
  1609  						},
  1610  					},
  1611  					Spec: infrav1.AzureMachineSpec{
  1612  						OSDisk: infrav1.OSDisk{
  1613  							OSType: azure.WindowsOS,
  1614  						},
  1615  					},
  1616  				},
  1617  				ClusterScoper: clusterMock,
  1618  			},
  1619  			want:        nil,
  1620  			expectedErr: "containerd image only supported in 1.22+",
  1621  		},
  1622  		{
  1623  			name: "if no image is specified and os specified is windows with windowsServerVersion annotation set to 2019, retrurns 2019 image",
  1624  			machineScope: MachineScope{
  1625  				Machine: &clusterv1.Machine{
  1626  					ObjectMeta: metav1.ObjectMeta{
  1627  						Name: "machine-name",
  1628  					},
  1629  					Spec: clusterv1.MachineSpec{
  1630  						Version: ptr.To("1.23.3"),
  1631  					},
  1632  				},
  1633  				AzureMachine: &infrav1.AzureMachine{
  1634  					ObjectMeta: metav1.ObjectMeta{
  1635  						Name: "machine-name",
  1636  						Annotations: map[string]string{
  1637  							"windowsServerVersion": "windows-2019",
  1638  						},
  1639  					},
  1640  					Spec: infrav1.AzureMachineSpec{
  1641  						OSDisk: infrav1.OSDisk{
  1642  							OSType: azure.WindowsOS,
  1643  						},
  1644  					},
  1645  				},
  1646  				ClusterScoper: clusterMock,
  1647  			},
  1648  			want: func() *infrav1.Image {
  1649  				image, _ := svc.GetDefaultWindowsImage(context.TODO(), "", "1.23.3", "", "windows-2019")
  1650  				return image
  1651  			}(),
  1652  			expectedErr: "",
  1653  		},
  1654  		{
  1655  			name: "if no image is specified and os specified is windows with windowsServerVersion annotation set to 2022, retrurns 2022 image",
  1656  			machineScope: MachineScope{
  1657  				Machine: &clusterv1.Machine{
  1658  					ObjectMeta: metav1.ObjectMeta{
  1659  						Name: "machine-name",
  1660  					},
  1661  					Spec: clusterv1.MachineSpec{
  1662  						Version: ptr.To("1.23.3"),
  1663  					},
  1664  				},
  1665  				AzureMachine: &infrav1.AzureMachine{
  1666  					ObjectMeta: metav1.ObjectMeta{
  1667  						Name: "machine-name",
  1668  						Annotations: map[string]string{
  1669  							"windowsServerVersion": "windows-2022",
  1670  						},
  1671  					},
  1672  					Spec: infrav1.AzureMachineSpec{
  1673  						OSDisk: infrav1.OSDisk{
  1674  							OSType: azure.WindowsOS,
  1675  						},
  1676  					},
  1677  				},
  1678  				ClusterScoper: clusterMock,
  1679  			},
  1680  			want: func() *infrav1.Image {
  1681  				image, _ := svc.GetDefaultWindowsImage(context.TODO(), "", "1.23.3", "", "windows-2022")
  1682  				return image
  1683  			}(),
  1684  			expectedErr: "",
  1685  		},
  1686  		{
  1687  			name: "if no image and OS is specified, returns linux image",
  1688  			machineScope: MachineScope{
  1689  				Machine: &clusterv1.Machine{
  1690  					ObjectMeta: metav1.ObjectMeta{
  1691  						Name: "machine-name",
  1692  					},
  1693  					Spec: clusterv1.MachineSpec{
  1694  						Version: ptr.To("1.20.1"),
  1695  					},
  1696  				},
  1697  				AzureMachine: &infrav1.AzureMachine{
  1698  					ObjectMeta: metav1.ObjectMeta{
  1699  						Name: "machine-name",
  1700  					},
  1701  				},
  1702  				ClusterScoper: clusterMock,
  1703  			},
  1704  			want: func() *infrav1.Image {
  1705  				image, _ := svc.GetDefaultUbuntuImage(context.TODO(), "", "1.20.1")
  1706  				return image
  1707  			}(),
  1708  			expectedErr: "",
  1709  		},
  1710  	}
  1711  	for _, tt := range tests {
  1712  		t.Run(tt.name, func(t *testing.T) {
  1713  			gotImage, err := tt.machineScope.GetVMImage(context.TODO())
  1714  			if (err == nil && tt.expectedErr != "") || (err != nil && tt.expectedErr != err.Error()) {
  1715  				t.Errorf("expected error %v, got %v", tt.expectedErr, err)
  1716  			}
  1717  			if !reflect.DeepEqual(gotImage, tt.want) {
  1718  				t.Errorf("GetVMImage(), gotImage = %v, wantImage %v", gotImage, tt.want)
  1719  			}
  1720  		})
  1721  	}
  1722  }
  1723  
  1724  func TestMachineScope_NICSpecs(t *testing.T) {
  1725  	tests := []struct {
  1726  		name         string
  1727  		machineScope MachineScope
  1728  		want         []azure.ResourceSpecGetter
  1729  	}{
  1730  		{
  1731  			name: "Node Machine with no NAT gateway and no public IP address",
  1732  			machineScope: MachineScope{
  1733  				ClusterScoper: &ClusterScope{
  1734  					AzureClients: AzureClients{
  1735  						EnvironmentSettings: auth.EnvironmentSettings{
  1736  							Values: map[string]string{
  1737  								auth.SubscriptionID: "123",
  1738  							},
  1739  						},
  1740  					},
  1741  					Cluster: &clusterv1.Cluster{
  1742  						ObjectMeta: metav1.ObjectMeta{
  1743  							Name:      "cluster",
  1744  							Namespace: "default",
  1745  						},
  1746  					},
  1747  					AzureCluster: &infrav1.AzureCluster{
  1748  						ObjectMeta: metav1.ObjectMeta{
  1749  							Name:      "cluster",
  1750  							Namespace: "default",
  1751  							OwnerReferences: []metav1.OwnerReference{
  1752  								{
  1753  									APIVersion: "cluster.x-k8s.io/v1beta1",
  1754  									Kind:       "Cluster",
  1755  									Name:       "cluster",
  1756  								},
  1757  							},
  1758  						},
  1759  						Spec: infrav1.AzureClusterSpec{
  1760  							ResourceGroup: "my-rg",
  1761  							AzureClusterClassSpec: infrav1.AzureClusterClassSpec{
  1762  								Location: "westus",
  1763  							},
  1764  							NetworkSpec: infrav1.NetworkSpec{
  1765  								Vnet: infrav1.VnetSpec{
  1766  									Name:          "vnet1",
  1767  									ResourceGroup: "rg1",
  1768  								},
  1769  								Subnets: []infrav1.SubnetSpec{
  1770  									{
  1771  										SubnetClassSpec: infrav1.SubnetClassSpec{
  1772  											Role: infrav1.SubnetNode,
  1773  											Name: "subnet1",
  1774  										},
  1775  									},
  1776  								},
  1777  								NodeOutboundLB: &infrav1.LoadBalancerSpec{
  1778  									Name: "outbound-lb",
  1779  									BackendPool: infrav1.BackendPool{
  1780  										Name: "outbound-lb-outboundBackendPool",
  1781  									},
  1782  								},
  1783  							},
  1784  						},
  1785  					},
  1786  				},
  1787  				AzureMachine: &infrav1.AzureMachine{
  1788  					ObjectMeta: metav1.ObjectMeta{
  1789  						Name: "machine",
  1790  					},
  1791  					Spec: infrav1.AzureMachineSpec{
  1792  						ProviderID: ptr.To("azure:///subscriptions/1234-5678/resourceGroups/my-cluster/providers/Microsoft.Compute/virtualMachines/machine-name"),
  1793  						NetworkInterfaces: []infrav1.NetworkInterface{{
  1794  							SubnetName:       "subnet1",
  1795  							PrivateIPConfigs: 1,
  1796  						}},
  1797  					},
  1798  				},
  1799  				Machine: &clusterv1.Machine{
  1800  					ObjectMeta: metav1.ObjectMeta{
  1801  						Name:   "machine",
  1802  						Labels: map[string]string{
  1803  							// clusterv1.MachineControlPlaneLabel: "true",
  1804  						},
  1805  					},
  1806  				},
  1807  			},
  1808  			want: []azure.ResourceSpecGetter{
  1809  				&networkinterfaces.NICSpec{
  1810  					Name:                      "machine-name-nic",
  1811  					ResourceGroup:             "my-rg",
  1812  					Location:                  "westus",
  1813  					SubscriptionID:            "123",
  1814  					MachineName:               "machine-name",
  1815  					SubnetName:                "subnet1",
  1816  					IPConfigs:                 []networkinterfaces.IPConfig{{}},
  1817  					VNetName:                  "vnet1",
  1818  					VNetResourceGroup:         "rg1",
  1819  					PublicLBName:              "outbound-lb",
  1820  					PublicLBAddressPoolName:   "outbound-lb-outboundBackendPool",
  1821  					PublicLBNATRuleName:       "",
  1822  					InternalLBName:            "",
  1823  					InternalLBAddressPoolName: "",
  1824  					PublicIPName:              "",
  1825  					AcceleratedNetworking:     nil,
  1826  					DNSServers:                nil,
  1827  					IPv6Enabled:               false,
  1828  					EnableIPForwarding:        false,
  1829  					SKU:                       nil,
  1830  					ClusterName:               "cluster",
  1831  					AdditionalTags: infrav1.Tags{
  1832  						"kubernetes.io_cluster_cluster": "owned",
  1833  					},
  1834  				},
  1835  			},
  1836  		},
  1837  		{
  1838  			name: "Node Machine with no NAT gateway and no public IP address and SKU is in machine cache",
  1839  			machineScope: MachineScope{
  1840  				ClusterScoper: &ClusterScope{
  1841  					AzureClients: AzureClients{
  1842  						EnvironmentSettings: auth.EnvironmentSettings{
  1843  							Values: map[string]string{
  1844  								auth.SubscriptionID: "123",
  1845  							},
  1846  						},
  1847  					},
  1848  					Cluster: &clusterv1.Cluster{
  1849  						ObjectMeta: metav1.ObjectMeta{
  1850  							Name:      "cluster",
  1851  							Namespace: "default",
  1852  						},
  1853  					},
  1854  					AzureCluster: &infrav1.AzureCluster{
  1855  						ObjectMeta: metav1.ObjectMeta{
  1856  							Name:      "cluster",
  1857  							Namespace: "default",
  1858  							OwnerReferences: []metav1.OwnerReference{
  1859  								{
  1860  									APIVersion: "cluster.x-k8s.io/v1beta1",
  1861  									Kind:       "Cluster",
  1862  									Name:       "cluster",
  1863  								},
  1864  							},
  1865  						},
  1866  						Spec: infrav1.AzureClusterSpec{
  1867  							ResourceGroup: "my-rg",
  1868  							AzureClusterClassSpec: infrav1.AzureClusterClassSpec{
  1869  								Location: "westus",
  1870  							},
  1871  							NetworkSpec: infrav1.NetworkSpec{
  1872  								Vnet: infrav1.VnetSpec{
  1873  									Name:          "vnet1",
  1874  									ResourceGroup: "rg1",
  1875  								},
  1876  								Subnets: []infrav1.SubnetSpec{
  1877  									{
  1878  										SubnetClassSpec: infrav1.SubnetClassSpec{
  1879  											Role: infrav1.SubnetNode,
  1880  											Name: "subnet1",
  1881  										},
  1882  									},
  1883  								},
  1884  								NodeOutboundLB: &infrav1.LoadBalancerSpec{
  1885  									Name: "outbound-lb",
  1886  									BackendPool: infrav1.BackendPool{
  1887  										Name: "outbound-lb-outboundBackendPool",
  1888  									},
  1889  								},
  1890  							},
  1891  						},
  1892  					},
  1893  				},
  1894  				AzureMachine: &infrav1.AzureMachine{
  1895  					ObjectMeta: metav1.ObjectMeta{
  1896  						Name: "machine",
  1897  					},
  1898  					Spec: infrav1.AzureMachineSpec{
  1899  						ProviderID: ptr.To("azure:///subscriptions/1234-5678/resourceGroups/my-cluster/providers/Microsoft.Compute/virtualMachines/machine-name"),
  1900  						NetworkInterfaces: []infrav1.NetworkInterface{{
  1901  							SubnetName:       "subnet1",
  1902  							PrivateIPConfigs: 1,
  1903  						}},
  1904  					},
  1905  				},
  1906  				Machine: &clusterv1.Machine{
  1907  					ObjectMeta: metav1.ObjectMeta{
  1908  						Name:   "machine",
  1909  						Labels: map[string]string{
  1910  							// clusterv1.MachineControlPlaneLabel: "true",
  1911  						},
  1912  					},
  1913  				},
  1914  				cache: &MachineCache{
  1915  					VMSKU: resourceskus.SKU{
  1916  						Name: ptr.To("Standard_D2v2"),
  1917  					},
  1918  				},
  1919  			},
  1920  			want: []azure.ResourceSpecGetter{
  1921  				&networkinterfaces.NICSpec{
  1922  					Name:                      "machine-name-nic",
  1923  					ResourceGroup:             "my-rg",
  1924  					Location:                  "westus",
  1925  					SubscriptionID:            "123",
  1926  					MachineName:               "machine-name",
  1927  					SubnetName:                "subnet1",
  1928  					IPConfigs:                 []networkinterfaces.IPConfig{{}},
  1929  					VNetName:                  "vnet1",
  1930  					VNetResourceGroup:         "rg1",
  1931  					PublicLBName:              "outbound-lb",
  1932  					PublicLBAddressPoolName:   "outbound-lb-outboundBackendPool",
  1933  					PublicLBNATRuleName:       "",
  1934  					InternalLBName:            "",
  1935  					InternalLBAddressPoolName: "",
  1936  					PublicIPName:              "",
  1937  					AcceleratedNetworking:     nil,
  1938  					DNSServers:                nil,
  1939  					IPv6Enabled:               false,
  1940  					EnableIPForwarding:        false,
  1941  					SKU: &resourceskus.SKU{
  1942  						Name: ptr.To("Standard_D2v2"),
  1943  					},
  1944  					ClusterName: "cluster",
  1945  					AdditionalTags: infrav1.Tags{
  1946  						"kubernetes.io_cluster_cluster": "owned",
  1947  					},
  1948  				},
  1949  			},
  1950  		},
  1951  		{
  1952  			name: "Node Machine with NAT gateway",
  1953  			machineScope: MachineScope{
  1954  				ClusterScoper: &ClusterScope{
  1955  					AzureClients: AzureClients{
  1956  						EnvironmentSettings: auth.EnvironmentSettings{
  1957  							Values: map[string]string{
  1958  								auth.SubscriptionID: "123",
  1959  							},
  1960  						},
  1961  					},
  1962  					Cluster: &clusterv1.Cluster{
  1963  						ObjectMeta: metav1.ObjectMeta{
  1964  							Name:      "cluster",
  1965  							Namespace: "default",
  1966  						},
  1967  					},
  1968  					AzureCluster: &infrav1.AzureCluster{
  1969  						ObjectMeta: metav1.ObjectMeta{
  1970  							Name:      "cluster",
  1971  							Namespace: "default",
  1972  							OwnerReferences: []metav1.OwnerReference{
  1973  								{
  1974  									APIVersion: "cluster.x-k8s.io/v1beta1",
  1975  									Kind:       "Cluster",
  1976  									Name:       "cluster",
  1977  								},
  1978  							},
  1979  						},
  1980  						Spec: infrav1.AzureClusterSpec{
  1981  							ResourceGroup: "my-rg",
  1982  							AzureClusterClassSpec: infrav1.AzureClusterClassSpec{
  1983  								Location: "westus",
  1984  							},
  1985  							NetworkSpec: infrav1.NetworkSpec{
  1986  								Vnet: infrav1.VnetSpec{
  1987  									Name:          "vnet1",
  1988  									ResourceGroup: "rg1",
  1989  								},
  1990  								Subnets: []infrav1.SubnetSpec{
  1991  									{
  1992  										SubnetClassSpec: infrav1.SubnetClassSpec{
  1993  											Role: infrav1.SubnetNode,
  1994  											Name: "subnet1",
  1995  										},
  1996  										NatGateway: infrav1.NatGateway{
  1997  											NatGatewayClassSpec: infrav1.NatGatewayClassSpec{
  1998  												Name: "natgw",
  1999  											},
  2000  										},
  2001  									},
  2002  								},
  2003  								NodeOutboundLB: &infrav1.LoadBalancerSpec{
  2004  									Name: "outbound-lb",
  2005  								},
  2006  							},
  2007  						},
  2008  					},
  2009  				},
  2010  				AzureMachine: &infrav1.AzureMachine{
  2011  					ObjectMeta: metav1.ObjectMeta{
  2012  						Name: "machine",
  2013  					},
  2014  					Spec: infrav1.AzureMachineSpec{
  2015  						ProviderID: ptr.To("azure:///subscriptions/1234-5678/resourceGroups/my-cluster/providers/Microsoft.Compute/virtualMachines/machine-name"),
  2016  						NetworkInterfaces: []infrav1.NetworkInterface{{
  2017  							SubnetName:       "subnet1",
  2018  							PrivateIPConfigs: 1,
  2019  						}},
  2020  					},
  2021  				},
  2022  				Machine: &clusterv1.Machine{
  2023  					ObjectMeta: metav1.ObjectMeta{
  2024  						Name:   "machine",
  2025  						Labels: map[string]string{
  2026  							// clusterv1.MachineControlPlaneLabel: "true",
  2027  						},
  2028  					},
  2029  				},
  2030  			},
  2031  			want: []azure.ResourceSpecGetter{
  2032  				&networkinterfaces.NICSpec{
  2033  					Name:                      "machine-name-nic",
  2034  					ResourceGroup:             "my-rg",
  2035  					Location:                  "westus",
  2036  					SubscriptionID:            "123",
  2037  					MachineName:               "machine-name",
  2038  					SubnetName:                "subnet1",
  2039  					IPConfigs:                 []networkinterfaces.IPConfig{{}},
  2040  					VNetName:                  "vnet1",
  2041  					VNetResourceGroup:         "rg1",
  2042  					PublicLBName:              "",
  2043  					PublicLBAddressPoolName:   "",
  2044  					PublicLBNATRuleName:       "",
  2045  					InternalLBName:            "",
  2046  					InternalLBAddressPoolName: "",
  2047  					PublicIPName:              "",
  2048  					AcceleratedNetworking:     nil,
  2049  					DNSServers:                nil,
  2050  					IPv6Enabled:               false,
  2051  					EnableIPForwarding:        false,
  2052  					SKU:                       nil,
  2053  					ClusterName:               "cluster",
  2054  					AdditionalTags: infrav1.Tags{
  2055  						"kubernetes.io_cluster_cluster": "owned",
  2056  					},
  2057  				},
  2058  			},
  2059  		},
  2060  		{
  2061  			name: "Node Machine with public IP address",
  2062  			machineScope: MachineScope{
  2063  				ClusterScoper: &ClusterScope{
  2064  					AzureClients: AzureClients{
  2065  						EnvironmentSettings: auth.EnvironmentSettings{
  2066  							Values: map[string]string{
  2067  								auth.SubscriptionID: "123",
  2068  							},
  2069  						},
  2070  					},
  2071  					Cluster: &clusterv1.Cluster{
  2072  						ObjectMeta: metav1.ObjectMeta{
  2073  							Name:      "cluster",
  2074  							Namespace: "default",
  2075  						},
  2076  					},
  2077  					AzureCluster: &infrav1.AzureCluster{
  2078  						ObjectMeta: metav1.ObjectMeta{
  2079  							Name:      "cluster",
  2080  							Namespace: "default",
  2081  							OwnerReferences: []metav1.OwnerReference{
  2082  								{
  2083  									APIVersion: "cluster.x-k8s.io/v1beta1",
  2084  									Kind:       "Cluster",
  2085  									Name:       "cluster",
  2086  								},
  2087  							},
  2088  						},
  2089  						Spec: infrav1.AzureClusterSpec{
  2090  							ResourceGroup: "my-rg",
  2091  							AzureClusterClassSpec: infrav1.AzureClusterClassSpec{
  2092  								Location: "westus",
  2093  							},
  2094  							NetworkSpec: infrav1.NetworkSpec{
  2095  								Vnet: infrav1.VnetSpec{
  2096  									Name:          "vnet1",
  2097  									ResourceGroup: "rg1",
  2098  								},
  2099  								Subnets: []infrav1.SubnetSpec{
  2100  									{
  2101  										SubnetClassSpec: infrav1.SubnetClassSpec{
  2102  											Role: infrav1.SubnetNode,
  2103  											Name: "subnet1",
  2104  										},
  2105  									},
  2106  								},
  2107  								NodeOutboundLB: &infrav1.LoadBalancerSpec{
  2108  									Name: "outbound-lb",
  2109  								},
  2110  							},
  2111  						},
  2112  					},
  2113  				},
  2114  				AzureMachine: &infrav1.AzureMachine{
  2115  					ObjectMeta: metav1.ObjectMeta{
  2116  						Name: "machine",
  2117  					},
  2118  					Spec: infrav1.AzureMachineSpec{
  2119  						ProviderID: ptr.To("azure:///subscriptions/1234-5678/resourceGroups/my-cluster/providers/Microsoft.Compute/virtualMachines/machine-name"),
  2120  						NetworkInterfaces: []infrav1.NetworkInterface{{
  2121  							SubnetName:       "subnet1",
  2122  							PrivateIPConfigs: 1,
  2123  						}},
  2124  						AllocatePublicIP: true,
  2125  					},
  2126  				},
  2127  				Machine: &clusterv1.Machine{
  2128  					ObjectMeta: metav1.ObjectMeta{
  2129  						Name:   "machine",
  2130  						Labels: map[string]string{
  2131  							// clusterv1.MachineControlPlaneLabel: "true",
  2132  						},
  2133  					},
  2134  				},
  2135  			},
  2136  			want: []azure.ResourceSpecGetter{
  2137  				&networkinterfaces.NICSpec{
  2138  					Name:                      "machine-name-nic",
  2139  					ResourceGroup:             "my-rg",
  2140  					Location:                  "westus",
  2141  					SubscriptionID:            "123",
  2142  					MachineName:               "machine-name",
  2143  					SubnetName:                "subnet1",
  2144  					IPConfigs:                 []networkinterfaces.IPConfig{{}},
  2145  					VNetName:                  "vnet1",
  2146  					VNetResourceGroup:         "rg1",
  2147  					PublicLBName:              "",
  2148  					PublicLBAddressPoolName:   "",
  2149  					PublicLBNATRuleName:       "",
  2150  					InternalLBName:            "",
  2151  					InternalLBAddressPoolName: "",
  2152  					PublicIPName:              "pip-machine-name",
  2153  					AcceleratedNetworking:     nil,
  2154  					DNSServers:                nil,
  2155  					IPv6Enabled:               false,
  2156  					EnableIPForwarding:        false,
  2157  					SKU:                       nil,
  2158  					ClusterName:               "cluster",
  2159  					AdditionalTags: infrav1.Tags{
  2160  						"kubernetes.io_cluster_cluster": "owned",
  2161  					},
  2162  				},
  2163  			},
  2164  		},
  2165  		{
  2166  			name: "Control Plane Machine with private LB",
  2167  			machineScope: MachineScope{
  2168  				ClusterScoper: &ClusterScope{
  2169  					AzureClients: AzureClients{
  2170  						EnvironmentSettings: auth.EnvironmentSettings{
  2171  							Values: map[string]string{
  2172  								auth.SubscriptionID: "123",
  2173  							},
  2174  						},
  2175  					},
  2176  					Cluster: &clusterv1.Cluster{
  2177  						ObjectMeta: metav1.ObjectMeta{
  2178  							Name:      "cluster",
  2179  							Namespace: "default",
  2180  						},
  2181  					},
  2182  					AzureCluster: &infrav1.AzureCluster{
  2183  						ObjectMeta: metav1.ObjectMeta{
  2184  							Name:      "cluster",
  2185  							Namespace: "default",
  2186  							OwnerReferences: []metav1.OwnerReference{
  2187  								{
  2188  									APIVersion: "cluster.x-k8s.io/v1beta1",
  2189  									Kind:       "Cluster",
  2190  									Name:       "cluster",
  2191  								},
  2192  							},
  2193  						},
  2194  						Spec: infrav1.AzureClusterSpec{
  2195  							ResourceGroup: "my-rg",
  2196  							AzureClusterClassSpec: infrav1.AzureClusterClassSpec{
  2197  								Location: "westus",
  2198  							},
  2199  							NetworkSpec: infrav1.NetworkSpec{
  2200  								Vnet: infrav1.VnetSpec{
  2201  									Name:          "vnet1",
  2202  									ResourceGroup: "rg1",
  2203  								},
  2204  								Subnets: []infrav1.SubnetSpec{
  2205  									{
  2206  										SubnetClassSpec: infrav1.SubnetClassSpec{
  2207  											Role: infrav1.SubnetNode,
  2208  											Name: "subnet1",
  2209  										},
  2210  									},
  2211  								},
  2212  								APIServerLB: infrav1.LoadBalancerSpec{
  2213  									Name: "api-lb",
  2214  									LoadBalancerClassSpec: infrav1.LoadBalancerClassSpec{
  2215  										Type: infrav1.Internal,
  2216  									},
  2217  									BackendPool: infrav1.BackendPool{
  2218  										Name: "api-lb-backendPool",
  2219  									},
  2220  								},
  2221  								NodeOutboundLB: &infrav1.LoadBalancerSpec{
  2222  									Name: "outbound-lb",
  2223  								},
  2224  							},
  2225  						},
  2226  					},
  2227  				},
  2228  				AzureMachine: &infrav1.AzureMachine{
  2229  					ObjectMeta: metav1.ObjectMeta{
  2230  						Name: "machine",
  2231  					},
  2232  					Spec: infrav1.AzureMachineSpec{
  2233  						ProviderID: ptr.To("azure:///subscriptions/1234-5678/resourceGroups/my-cluster/providers/Microsoft.Compute/virtualMachines/machine-name"),
  2234  						NetworkInterfaces: []infrav1.NetworkInterface{{
  2235  							SubnetName:       "subnet1",
  2236  							PrivateIPConfigs: 1,
  2237  						}},
  2238  					},
  2239  				},
  2240  				Machine: &clusterv1.Machine{
  2241  					ObjectMeta: metav1.ObjectMeta{
  2242  						Name: "machine",
  2243  						Labels: map[string]string{
  2244  							clusterv1.MachineControlPlaneLabel: "true",
  2245  						},
  2246  					},
  2247  				},
  2248  			},
  2249  			want: []azure.ResourceSpecGetter{
  2250  				&networkinterfaces.NICSpec{
  2251  					Name:                      "machine-name-nic",
  2252  					ResourceGroup:             "my-rg",
  2253  					Location:                  "westus",
  2254  					SubscriptionID:            "123",
  2255  					MachineName:               "machine-name",
  2256  					SubnetName:                "subnet1",
  2257  					IPConfigs:                 []networkinterfaces.IPConfig{{}},
  2258  					VNetName:                  "vnet1",
  2259  					VNetResourceGroup:         "rg1",
  2260  					PublicLBName:              "",
  2261  					PublicLBAddressPoolName:   "",
  2262  					PublicLBNATRuleName:       "",
  2263  					InternalLBName:            "api-lb",
  2264  					InternalLBAddressPoolName: "api-lb-backendPool",
  2265  					PublicIPName:              "",
  2266  					AcceleratedNetworking:     nil,
  2267  					DNSServers:                nil,
  2268  					IPv6Enabled:               false,
  2269  					EnableIPForwarding:        false,
  2270  					SKU:                       nil,
  2271  					ClusterName:               "cluster",
  2272  					AdditionalTags: infrav1.Tags{
  2273  						"kubernetes.io_cluster_cluster": "owned",
  2274  					},
  2275  				},
  2276  			},
  2277  		},
  2278  		{
  2279  			name: "Control Plane Machine with public LB",
  2280  			machineScope: MachineScope{
  2281  				ClusterScoper: &ClusterScope{
  2282  					AzureClients: AzureClients{
  2283  						EnvironmentSettings: auth.EnvironmentSettings{
  2284  							Values: map[string]string{
  2285  								auth.SubscriptionID: "123",
  2286  							},
  2287  						},
  2288  					},
  2289  					Cluster: &clusterv1.Cluster{
  2290  						ObjectMeta: metav1.ObjectMeta{
  2291  							Name:      "cluster",
  2292  							Namespace: "default",
  2293  						},
  2294  					},
  2295  					AzureCluster: &infrav1.AzureCluster{
  2296  						ObjectMeta: metav1.ObjectMeta{
  2297  							Name:      "cluster",
  2298  							Namespace: "default",
  2299  							OwnerReferences: []metav1.OwnerReference{
  2300  								{
  2301  									APIVersion: "cluster.x-k8s.io/v1beta1",
  2302  									Kind:       "Cluster",
  2303  									Name:       "cluster",
  2304  								},
  2305  							},
  2306  						},
  2307  						Spec: infrav1.AzureClusterSpec{
  2308  							ResourceGroup: "my-rg",
  2309  							AzureClusterClassSpec: infrav1.AzureClusterClassSpec{
  2310  								Location: "westus",
  2311  							},
  2312  							NetworkSpec: infrav1.NetworkSpec{
  2313  								Vnet: infrav1.VnetSpec{
  2314  									Name:          "vnet1",
  2315  									ResourceGroup: "rg1",
  2316  								},
  2317  								Subnets: []infrav1.SubnetSpec{
  2318  									{
  2319  										SubnetClassSpec: infrav1.SubnetClassSpec{
  2320  											Role: infrav1.SubnetNode,
  2321  											Name: "subnet1",
  2322  										},
  2323  									},
  2324  								},
  2325  								APIServerLB: infrav1.LoadBalancerSpec{
  2326  									Name: "api-lb",
  2327  									BackendPool: infrav1.BackendPool{
  2328  										Name: "api-lb-backendPool",
  2329  									},
  2330  								},
  2331  								NodeOutboundLB: &infrav1.LoadBalancerSpec{
  2332  									Name: "outbound-lb",
  2333  								},
  2334  							},
  2335  						},
  2336  					},
  2337  				},
  2338  				AzureMachine: &infrav1.AzureMachine{
  2339  					ObjectMeta: metav1.ObjectMeta{
  2340  						Name: "machine",
  2341  					},
  2342  					Spec: infrav1.AzureMachineSpec{
  2343  						ProviderID: ptr.To("azure:///subscriptions/1234-5678/resourceGroups/my-cluster/providers/Microsoft.Compute/virtualMachines/machine-name"),
  2344  						NetworkInterfaces: []infrav1.NetworkInterface{{
  2345  							SubnetName:       "subnet1",
  2346  							PrivateIPConfigs: 1,
  2347  						}},
  2348  					},
  2349  				},
  2350  				Machine: &clusterv1.Machine{
  2351  					ObjectMeta: metav1.ObjectMeta{
  2352  						Name: "machine",
  2353  						Labels: map[string]string{
  2354  							clusterv1.MachineControlPlaneLabel: "true",
  2355  						},
  2356  					},
  2357  				},
  2358  			},
  2359  			want: []azure.ResourceSpecGetter{
  2360  				&networkinterfaces.NICSpec{
  2361  					Name:                      "machine-name-nic",
  2362  					ResourceGroup:             "my-rg",
  2363  					Location:                  "westus",
  2364  					SubscriptionID:            "123",
  2365  					MachineName:               "machine-name",
  2366  					SubnetName:                "subnet1",
  2367  					IPConfigs:                 []networkinterfaces.IPConfig{{}},
  2368  					VNetName:                  "vnet1",
  2369  					VNetResourceGroup:         "rg1",
  2370  					PublicLBName:              "api-lb",
  2371  					PublicLBAddressPoolName:   "api-lb-backendPool",
  2372  					PublicLBNATRuleName:       "machine-name",
  2373  					InternalLBName:            "",
  2374  					InternalLBAddressPoolName: "",
  2375  					PublicIPName:              "",
  2376  					AcceleratedNetworking:     nil,
  2377  					DNSServers:                nil,
  2378  					IPv6Enabled:               false,
  2379  					EnableIPForwarding:        false,
  2380  					SKU:                       nil,
  2381  					ClusterName:               "cluster",
  2382  					AdditionalTags: infrav1.Tags{
  2383  						"kubernetes.io_cluster_cluster": "owned",
  2384  					},
  2385  				},
  2386  			},
  2387  		},
  2388  		{
  2389  			name: "Control Plane Machine with public LB and Custom DNS Servers",
  2390  			machineScope: MachineScope{
  2391  				ClusterScoper: &ClusterScope{
  2392  					AzureClients: AzureClients{
  2393  						EnvironmentSettings: auth.EnvironmentSettings{
  2394  							Values: map[string]string{
  2395  								auth.SubscriptionID: "123",
  2396  							},
  2397  						},
  2398  					},
  2399  					Cluster: &clusterv1.Cluster{
  2400  						ObjectMeta: metav1.ObjectMeta{
  2401  							Name:      "cluster",
  2402  							Namespace: "default",
  2403  						},
  2404  					},
  2405  					AzureCluster: &infrav1.AzureCluster{
  2406  						ObjectMeta: metav1.ObjectMeta{
  2407  							Name:      "cluster",
  2408  							Namespace: "default",
  2409  							OwnerReferences: []metav1.OwnerReference{
  2410  								{
  2411  									APIVersion: "cluster.x-k8s.io/v1beta1",
  2412  									Kind:       "Cluster",
  2413  									Name:       "cluster",
  2414  								},
  2415  							},
  2416  						},
  2417  						Spec: infrav1.AzureClusterSpec{
  2418  							ResourceGroup: "my-rg",
  2419  							AzureClusterClassSpec: infrav1.AzureClusterClassSpec{
  2420  								Location: "westus",
  2421  							},
  2422  							NetworkSpec: infrav1.NetworkSpec{
  2423  								Vnet: infrav1.VnetSpec{
  2424  									Name:          "vnet1",
  2425  									ResourceGroup: "rg1",
  2426  								},
  2427  								Subnets: []infrav1.SubnetSpec{
  2428  									{
  2429  										SubnetClassSpec: infrav1.SubnetClassSpec{
  2430  											Role: infrav1.SubnetNode,
  2431  											Name: "subnet1",
  2432  										},
  2433  									},
  2434  								},
  2435  								APIServerLB: infrav1.LoadBalancerSpec{
  2436  									Name: "api-lb",
  2437  									BackendPool: infrav1.BackendPool{
  2438  										Name: "api-lb-backendPool",
  2439  									},
  2440  								},
  2441  								NodeOutboundLB: &infrav1.LoadBalancerSpec{
  2442  									Name: "outbound-lb",
  2443  								},
  2444  							},
  2445  						},
  2446  					},
  2447  				},
  2448  				AzureMachine: &infrav1.AzureMachine{
  2449  					ObjectMeta: metav1.ObjectMeta{
  2450  						Name: "machine",
  2451  					},
  2452  					Spec: infrav1.AzureMachineSpec{
  2453  						ProviderID: ptr.To("azure:///subscriptions/1234-5678/resourceGroups/my-cluster/providers/Microsoft.Compute/virtualMachines/machine-name"),
  2454  						NetworkInterfaces: []infrav1.NetworkInterface{{
  2455  							SubnetName:       "subnet1",
  2456  							PrivateIPConfigs: 1,
  2457  						}},
  2458  						DNSServers: []string{"123.123.123.123", "124.124.124.124"},
  2459  					},
  2460  				},
  2461  				Machine: &clusterv1.Machine{
  2462  					ObjectMeta: metav1.ObjectMeta{
  2463  						Name: "machine",
  2464  						Labels: map[string]string{
  2465  							clusterv1.MachineControlPlaneLabel: "true",
  2466  						},
  2467  					},
  2468  				},
  2469  			},
  2470  			want: []azure.ResourceSpecGetter{
  2471  				&networkinterfaces.NICSpec{
  2472  					Name:                      "machine-name-nic",
  2473  					ResourceGroup:             "my-rg",
  2474  					Location:                  "westus",
  2475  					SubscriptionID:            "123",
  2476  					MachineName:               "machine-name",
  2477  					SubnetName:                "subnet1",
  2478  					IPConfigs:                 []networkinterfaces.IPConfig{{}},
  2479  					VNetName:                  "vnet1",
  2480  					VNetResourceGroup:         "rg1",
  2481  					PublicLBName:              "api-lb",
  2482  					PublicLBAddressPoolName:   "api-lb-backendPool",
  2483  					PublicLBNATRuleName:       "machine-name",
  2484  					InternalLBName:            "",
  2485  					InternalLBAddressPoolName: "",
  2486  					PublicIPName:              "",
  2487  					AcceleratedNetworking:     nil,
  2488  					DNSServers:                []string{"123.123.123.123", "124.124.124.124"},
  2489  					IPv6Enabled:               false,
  2490  					EnableIPForwarding:        false,
  2491  					SKU:                       nil,
  2492  					ClusterName:               "cluster",
  2493  					AdditionalTags: infrav1.Tags{
  2494  						"kubernetes.io_cluster_cluster": "owned",
  2495  					},
  2496  				},
  2497  			},
  2498  		},
  2499  		{
  2500  			name: "Node Machine with multiple Network Interfaces",
  2501  			machineScope: MachineScope{
  2502  				ClusterScoper: &ClusterScope{
  2503  					AzureClients: AzureClients{
  2504  						EnvironmentSettings: auth.EnvironmentSettings{
  2505  							Values: map[string]string{
  2506  								auth.SubscriptionID: "123",
  2507  							},
  2508  						},
  2509  					},
  2510  					Cluster: &clusterv1.Cluster{
  2511  						ObjectMeta: metav1.ObjectMeta{
  2512  							Name:      "cluster",
  2513  							Namespace: "default",
  2514  						},
  2515  					},
  2516  					AzureCluster: &infrav1.AzureCluster{
  2517  						ObjectMeta: metav1.ObjectMeta{
  2518  							Name:      "cluster",
  2519  							Namespace: "default",
  2520  							OwnerReferences: []metav1.OwnerReference{
  2521  								{
  2522  									APIVersion: "cluster.x-k8s.io/v1beta1",
  2523  									Kind:       "Cluster",
  2524  									Name:       "cluster",
  2525  								},
  2526  							},
  2527  						},
  2528  						Spec: infrav1.AzureClusterSpec{
  2529  							ResourceGroup: "my-rg",
  2530  							AzureClusterClassSpec: infrav1.AzureClusterClassSpec{
  2531  								Location: "westus",
  2532  							},
  2533  							NetworkSpec: infrav1.NetworkSpec{
  2534  								Vnet: infrav1.VnetSpec{
  2535  									Name:          "vnet1",
  2536  									ResourceGroup: "rg1",
  2537  								},
  2538  								Subnets: []infrav1.SubnetSpec{
  2539  									{
  2540  										SubnetClassSpec: infrav1.SubnetClassSpec{
  2541  											Role: infrav1.SubnetNode,
  2542  											Name: "subnet1",
  2543  										},
  2544  									},
  2545  								},
  2546  								APIServerLB: infrav1.LoadBalancerSpec{
  2547  									Name: "api-lb",
  2548  								},
  2549  								NodeOutboundLB: &infrav1.LoadBalancerSpec{
  2550  									Name: "outbound-lb",
  2551  									BackendPool: infrav1.BackendPool{
  2552  										Name: "outbound-lb-outboundBackendPool",
  2553  									},
  2554  								},
  2555  							},
  2556  						},
  2557  					},
  2558  				},
  2559  				AzureMachine: &infrav1.AzureMachine{
  2560  					ObjectMeta: metav1.ObjectMeta{
  2561  						Name: "machine",
  2562  					},
  2563  					Spec: infrav1.AzureMachineSpec{
  2564  						ProviderID: ptr.To("azure:///subscriptions/1234-5678/resourceGroups/my-cluster/providers/Microsoft.Compute/virtualMachines/machine-name"),
  2565  						NetworkInterfaces: []infrav1.NetworkInterface{
  2566  							{
  2567  								SubnetName:            "subnet1",
  2568  								AcceleratedNetworking: ptr.To(true),
  2569  								PrivateIPConfigs:      1,
  2570  							},
  2571  							{
  2572  								SubnetName:            "subnet2",
  2573  								AcceleratedNetworking: ptr.To(true),
  2574  								PrivateIPConfigs:      2,
  2575  							},
  2576  						},
  2577  					},
  2578  				},
  2579  				Machine: &clusterv1.Machine{
  2580  					ObjectMeta: metav1.ObjectMeta{
  2581  						Name:   "machine",
  2582  						Labels: map[string]string{},
  2583  					},
  2584  				},
  2585  			},
  2586  			want: []azure.ResourceSpecGetter{
  2587  				&networkinterfaces.NICSpec{
  2588  					Name:                      "machine-name-nic-0",
  2589  					ResourceGroup:             "my-rg",
  2590  					Location:                  "westus",
  2591  					SubscriptionID:            "123",
  2592  					MachineName:               "machine-name",
  2593  					SubnetName:                "subnet1",
  2594  					IPConfigs:                 []networkinterfaces.IPConfig{{}},
  2595  					VNetName:                  "vnet1",
  2596  					VNetResourceGroup:         "rg1",
  2597  					PublicLBName:              "outbound-lb",
  2598  					PublicLBAddressPoolName:   "outbound-lb-outboundBackendPool",
  2599  					PublicLBNATRuleName:       "",
  2600  					InternalLBName:            "",
  2601  					InternalLBAddressPoolName: "",
  2602  					PublicIPName:              "",
  2603  					AcceleratedNetworking:     ptr.To(true),
  2604  					IPv6Enabled:               false,
  2605  					EnableIPForwarding:        false,
  2606  					SKU:                       nil,
  2607  					ClusterName:               "cluster",
  2608  					AdditionalTags: map[string]string{
  2609  						"kubernetes.io_cluster_cluster": "owned",
  2610  					},
  2611  				},
  2612  				&networkinterfaces.NICSpec{
  2613  					Name:                      "machine-name-nic-1",
  2614  					ResourceGroup:             "my-rg",
  2615  					Location:                  "westus",
  2616  					SubscriptionID:            "123",
  2617  					MachineName:               "machine-name",
  2618  					SubnetName:                "subnet2",
  2619  					IPConfigs:                 []networkinterfaces.IPConfig{{}, {}},
  2620  					VNetName:                  "vnet1",
  2621  					VNetResourceGroup:         "rg1",
  2622  					PublicLBName:              "",
  2623  					PublicLBAddressPoolName:   "",
  2624  					PublicLBNATRuleName:       "",
  2625  					InternalLBName:            "",
  2626  					InternalLBAddressPoolName: "",
  2627  					PublicIPName:              "",
  2628  					AcceleratedNetworking:     ptr.To(true),
  2629  					IPv6Enabled:               false,
  2630  					EnableIPForwarding:        false,
  2631  					SKU:                       nil,
  2632  					ClusterName:               "cluster",
  2633  					AdditionalTags: map[string]string{
  2634  						"kubernetes.io_cluster_cluster": "owned",
  2635  					},
  2636  				},
  2637  			},
  2638  		},
  2639  		{
  2640  			name: "Node Machine with multiple Network Interfaces and Public IP Allocation enabled",
  2641  			machineScope: MachineScope{
  2642  				ClusterScoper: &ClusterScope{
  2643  					AzureClients: AzureClients{
  2644  						EnvironmentSettings: auth.EnvironmentSettings{
  2645  							Values: map[string]string{
  2646  								auth.SubscriptionID: "123",
  2647  							},
  2648  						},
  2649  					},
  2650  					Cluster: &clusterv1.Cluster{
  2651  						ObjectMeta: metav1.ObjectMeta{
  2652  							Name:      "cluster",
  2653  							Namespace: "default",
  2654  						},
  2655  					},
  2656  					AzureCluster: &infrav1.AzureCluster{
  2657  						ObjectMeta: metav1.ObjectMeta{
  2658  							Name:      "cluster",
  2659  							Namespace: "default",
  2660  							OwnerReferences: []metav1.OwnerReference{
  2661  								{
  2662  									APIVersion: "cluster.x-k8s.io/v1beta1",
  2663  									Kind:       "Cluster",
  2664  									Name:       "cluster",
  2665  								},
  2666  							},
  2667  						},
  2668  						Spec: infrav1.AzureClusterSpec{
  2669  							ResourceGroup: "my-rg",
  2670  							AzureClusterClassSpec: infrav1.AzureClusterClassSpec{
  2671  								Location: "westus",
  2672  							},
  2673  							NetworkSpec: infrav1.NetworkSpec{
  2674  								Vnet: infrav1.VnetSpec{
  2675  									Name:          "vnet1",
  2676  									ResourceGroup: "rg1",
  2677  								},
  2678  								Subnets: []infrav1.SubnetSpec{
  2679  									{
  2680  										SubnetClassSpec: infrav1.SubnetClassSpec{
  2681  											Role: infrav1.SubnetNode,
  2682  											Name: "subnet1",
  2683  										},
  2684  									},
  2685  								},
  2686  								APIServerLB: infrav1.LoadBalancerSpec{
  2687  									Name: "api-lb",
  2688  								},
  2689  								NodeOutboundLB: &infrav1.LoadBalancerSpec{
  2690  									Name: "outbound-lb",
  2691  								},
  2692  							},
  2693  						},
  2694  					},
  2695  				},
  2696  				AzureMachine: &infrav1.AzureMachine{
  2697  					ObjectMeta: metav1.ObjectMeta{
  2698  						Name: "machine",
  2699  					},
  2700  					Spec: infrav1.AzureMachineSpec{
  2701  						ProviderID:       ptr.To("azure:///subscriptions/1234-5678/resourceGroups/my-cluster/providers/Microsoft.Compute/virtualMachines/machine-name"),
  2702  						AllocatePublicIP: true,
  2703  						NetworkInterfaces: []infrav1.NetworkInterface{
  2704  							{
  2705  								SubnetName:            "subnet1",
  2706  								AcceleratedNetworking: ptr.To(true),
  2707  								PrivateIPConfigs:      1,
  2708  							},
  2709  							{
  2710  								SubnetName:            "subnet2",
  2711  								AcceleratedNetworking: ptr.To(true),
  2712  								PrivateIPConfigs:      2,
  2713  							},
  2714  						},
  2715  					},
  2716  				},
  2717  				Machine: &clusterv1.Machine{
  2718  					ObjectMeta: metav1.ObjectMeta{
  2719  						Name:   "machine",
  2720  						Labels: map[string]string{},
  2721  					},
  2722  				},
  2723  			},
  2724  			want: []azure.ResourceSpecGetter{
  2725  				&networkinterfaces.NICSpec{
  2726  					Name:                      "machine-name-nic-0",
  2727  					ResourceGroup:             "my-rg",
  2728  					Location:                  "westus",
  2729  					SubscriptionID:            "123",
  2730  					MachineName:               "machine-name",
  2731  					SubnetName:                "subnet1",
  2732  					IPConfigs:                 []networkinterfaces.IPConfig{{}},
  2733  					VNetName:                  "vnet1",
  2734  					VNetResourceGroup:         "rg1",
  2735  					PublicLBName:              "",
  2736  					PublicLBAddressPoolName:   "",
  2737  					PublicLBNATRuleName:       "",
  2738  					InternalLBName:            "",
  2739  					InternalLBAddressPoolName: "",
  2740  					PublicIPName:              "pip-machine-name",
  2741  					AcceleratedNetworking:     ptr.To(true),
  2742  					IPv6Enabled:               false,
  2743  					EnableIPForwarding:        false,
  2744  					SKU:                       nil,
  2745  					ClusterName:               "cluster",
  2746  					AdditionalTags: map[string]string{
  2747  						"kubernetes.io_cluster_cluster": "owned",
  2748  					},
  2749  				},
  2750  				&networkinterfaces.NICSpec{
  2751  					Name:                      "machine-name-nic-1",
  2752  					ResourceGroup:             "my-rg",
  2753  					Location:                  "westus",
  2754  					SubscriptionID:            "123",
  2755  					MachineName:               "machine-name",
  2756  					SubnetName:                "subnet2",
  2757  					IPConfigs:                 []networkinterfaces.IPConfig{{}, {}},
  2758  					VNetName:                  "vnet1",
  2759  					VNetResourceGroup:         "rg1",
  2760  					PublicLBName:              "",
  2761  					PublicLBAddressPoolName:   "",
  2762  					PublicLBNATRuleName:       "",
  2763  					InternalLBName:            "",
  2764  					InternalLBAddressPoolName: "",
  2765  					PublicIPName:              "",
  2766  					AcceleratedNetworking:     ptr.To(true),
  2767  					IPv6Enabled:               false,
  2768  					EnableIPForwarding:        false,
  2769  					SKU:                       nil,
  2770  					ClusterName:               "cluster",
  2771  					AdditionalTags: map[string]string{
  2772  						"kubernetes.io_cluster_cluster": "owned",
  2773  					},
  2774  				},
  2775  			},
  2776  		},
  2777  		{
  2778  			name: "Node Machine with multiple IPConfigs",
  2779  			machineScope: MachineScope{
  2780  				ClusterScoper: &ClusterScope{
  2781  					AzureClients: AzureClients{
  2782  						EnvironmentSettings: auth.EnvironmentSettings{
  2783  							Values: map[string]string{
  2784  								auth.SubscriptionID: "123",
  2785  							},
  2786  						},
  2787  					},
  2788  					Cluster: &clusterv1.Cluster{
  2789  						ObjectMeta: metav1.ObjectMeta{
  2790  							Name:      "cluster",
  2791  							Namespace: "default",
  2792  						},
  2793  					},
  2794  					AzureCluster: &infrav1.AzureCluster{
  2795  						ObjectMeta: metav1.ObjectMeta{
  2796  							Name:      "cluster",
  2797  							Namespace: "default",
  2798  							OwnerReferences: []metav1.OwnerReference{
  2799  								{
  2800  									APIVersion: "cluster.x-k8s.io/v1beta1",
  2801  									Kind:       "Cluster",
  2802  									Name:       "cluster",
  2803  								},
  2804  							},
  2805  						},
  2806  						Spec: infrav1.AzureClusterSpec{
  2807  							ResourceGroup: "my-rg",
  2808  							AzureClusterClassSpec: infrav1.AzureClusterClassSpec{
  2809  								Location: "westus",
  2810  							},
  2811  							NetworkSpec: infrav1.NetworkSpec{
  2812  								Vnet: infrav1.VnetSpec{
  2813  									Name:          "vnet1",
  2814  									ResourceGroup: "rg1",
  2815  								},
  2816  								Subnets: []infrav1.SubnetSpec{
  2817  									{
  2818  										SubnetClassSpec: infrav1.SubnetClassSpec{
  2819  											Role: infrav1.SubnetNode,
  2820  											Name: "subnet1",
  2821  										},
  2822  									},
  2823  								},
  2824  								APIServerLB: infrav1.LoadBalancerSpec{
  2825  									Name: "api-lb",
  2826  								},
  2827  								NodeOutboundLB: &infrav1.LoadBalancerSpec{
  2828  									Name: "outbound-lb",
  2829  									BackendPool: infrav1.BackendPool{
  2830  										Name: "outbound-lb-outboundBackendPool",
  2831  									},
  2832  								},
  2833  							},
  2834  						},
  2835  					},
  2836  				},
  2837  				AzureMachine: &infrav1.AzureMachine{
  2838  					ObjectMeta: metav1.ObjectMeta{
  2839  						Name: "machine",
  2840  					},
  2841  					Spec: infrav1.AzureMachineSpec{
  2842  						ProviderID: ptr.To("azure:///subscriptions/1234-5678/resourceGroups/my-cluster/providers/Microsoft.Compute/virtualMachines/machine-name"),
  2843  						NetworkInterfaces: []infrav1.NetworkInterface{
  2844  							{
  2845  								SubnetName:            "subnet1",
  2846  								AcceleratedNetworking: ptr.To(true),
  2847  								PrivateIPConfigs:      10,
  2848  							},
  2849  						},
  2850  					},
  2851  				},
  2852  				Machine: &clusterv1.Machine{
  2853  					ObjectMeta: metav1.ObjectMeta{
  2854  						Name:   "machine",
  2855  						Labels: map[string]string{},
  2856  					},
  2857  				},
  2858  			},
  2859  			want: []azure.ResourceSpecGetter{
  2860  				&networkinterfaces.NICSpec{
  2861  					Name:                      "machine-name-nic",
  2862  					ResourceGroup:             "my-rg",
  2863  					Location:                  "westus",
  2864  					SubscriptionID:            "123",
  2865  					MachineName:               "machine-name",
  2866  					SubnetName:                "subnet1",
  2867  					IPConfigs:                 []networkinterfaces.IPConfig{{}, {}, {}, {}, {}, {}, {}, {}, {}, {}},
  2868  					VNetName:                  "vnet1",
  2869  					VNetResourceGroup:         "rg1",
  2870  					PublicLBName:              "outbound-lb",
  2871  					PublicLBAddressPoolName:   "outbound-lb-outboundBackendPool",
  2872  					PublicLBNATRuleName:       "",
  2873  					InternalLBName:            "",
  2874  					InternalLBAddressPoolName: "",
  2875  					PublicIPName:              "",
  2876  					AcceleratedNetworking:     ptr.To(true),
  2877  					IPv6Enabled:               false,
  2878  					EnableIPForwarding:        false,
  2879  					SKU:                       nil,
  2880  					ClusterName:               "cluster",
  2881  					AdditionalTags: map[string]string{
  2882  						"kubernetes.io_cluster_cluster": "owned",
  2883  					},
  2884  				},
  2885  			},
  2886  		},
  2887  	}
  2888  	for _, tt := range tests {
  2889  		t.Run(tt.name, func(t *testing.T) {
  2890  			g := NewWithT(t)
  2891  			gotNicSpecs := tt.machineScope.NICSpecs()
  2892  			if !reflect.DeepEqual(gotNicSpecs, tt.want) {
  2893  				g.Expect(gotNicSpecs).To(BeEquivalentTo(tt.want))
  2894  				t.Errorf("NICSpecs(), gotNicSpecs = %s, want %s", specArrayToString(gotNicSpecs), specArrayToString(tt.want))
  2895  			}
  2896  		})
  2897  	}
  2898  }
  2899  
  2900  func TestDiskSpecs(t *testing.T) {
  2901  	testcases := []struct {
  2902  		name         string
  2903  		machineScope MachineScope
  2904  		want         []azure.ResourceSpecGetter
  2905  	}{
  2906  		{
  2907  			name: "only os disk",
  2908  			machineScope: MachineScope{
  2909  				ClusterScoper: &ClusterScope{
  2910  					Cluster: &clusterv1.Cluster{
  2911  						ObjectMeta: metav1.ObjectMeta{
  2912  							Name: "cluster",
  2913  						},
  2914  					},
  2915  					AzureCluster: &infrav1.AzureCluster{
  2916  						ObjectMeta: metav1.ObjectMeta{
  2917  							Name: "cluster",
  2918  						},
  2919  						Spec: infrav1.AzureClusterSpec{
  2920  							ResourceGroup: "my-rg",
  2921  						},
  2922  					},
  2923  				},
  2924  				AzureMachine: &infrav1.AzureMachine{
  2925  					ObjectMeta: metav1.ObjectMeta{
  2926  						Name: "my-azure-machine",
  2927  					},
  2928  					Spec: infrav1.AzureMachineSpec{
  2929  						OSDisk: infrav1.OSDisk{
  2930  							DiskSizeGB: ptr.To[int32](30),
  2931  							OSType:     "Linux",
  2932  						},
  2933  					},
  2934  				},
  2935  				Machine: &clusterv1.Machine{
  2936  					ObjectMeta: metav1.ObjectMeta{
  2937  						Name: "machine",
  2938  					},
  2939  				},
  2940  			},
  2941  			want: []azure.ResourceSpecGetter{
  2942  				&disks.DiskSpec{
  2943  					Name:          "my-azure-machine_OSDisk",
  2944  					ResourceGroup: "my-rg",
  2945  				},
  2946  			},
  2947  		},
  2948  		{
  2949  			name: "os and data disks",
  2950  			machineScope: MachineScope{
  2951  				ClusterScoper: &ClusterScope{
  2952  					Cluster: &clusterv1.Cluster{
  2953  						ObjectMeta: metav1.ObjectMeta{
  2954  							Name: "cluster",
  2955  						},
  2956  					},
  2957  					AzureCluster: &infrav1.AzureCluster{
  2958  						ObjectMeta: metav1.ObjectMeta{
  2959  							Name: "cluster",
  2960  						},
  2961  						Spec: infrav1.AzureClusterSpec{
  2962  							ResourceGroup: "my-rg",
  2963  						},
  2964  					},
  2965  				},
  2966  				AzureMachine: &infrav1.AzureMachine{
  2967  					ObjectMeta: metav1.ObjectMeta{
  2968  						Name: "my-azure-machine",
  2969  					},
  2970  					Spec: infrav1.AzureMachineSpec{
  2971  						OSDisk: infrav1.OSDisk{
  2972  							DiskSizeGB: ptr.To[int32](30),
  2973  							OSType:     "Linux",
  2974  						},
  2975  						DataDisks: []infrav1.DataDisk{
  2976  							{
  2977  								NameSuffix: "etcddisk",
  2978  							},
  2979  						},
  2980  					},
  2981  				},
  2982  				Machine: &clusterv1.Machine{
  2983  					ObjectMeta: metav1.ObjectMeta{
  2984  						Name: "machine",
  2985  					},
  2986  				},
  2987  			},
  2988  			want: []azure.ResourceSpecGetter{
  2989  				&disks.DiskSpec{
  2990  					Name:          "my-azure-machine_OSDisk",
  2991  					ResourceGroup: "my-rg",
  2992  				},
  2993  				&disks.DiskSpec{
  2994  					Name:          "my-azure-machine_etcddisk",
  2995  					ResourceGroup: "my-rg",
  2996  				},
  2997  			},
  2998  		}, {
  2999  			name: "os and multiple data disks",
  3000  			machineScope: MachineScope{
  3001  				ClusterScoper: &ClusterScope{
  3002  					Cluster: &clusterv1.Cluster{
  3003  						ObjectMeta: metav1.ObjectMeta{
  3004  							Name: "cluster",
  3005  						},
  3006  					},
  3007  					AzureCluster: &infrav1.AzureCluster{
  3008  						ObjectMeta: metav1.ObjectMeta{
  3009  							Name: "cluster",
  3010  						},
  3011  						Spec: infrav1.AzureClusterSpec{
  3012  							ResourceGroup: "my-rg",
  3013  						},
  3014  					},
  3015  				},
  3016  				AzureMachine: &infrav1.AzureMachine{
  3017  					ObjectMeta: metav1.ObjectMeta{
  3018  						Name: "my-azure-machine",
  3019  					},
  3020  					Spec: infrav1.AzureMachineSpec{
  3021  						OSDisk: infrav1.OSDisk{
  3022  							DiskSizeGB: ptr.To[int32](30),
  3023  							OSType:     "Linux",
  3024  						},
  3025  						DataDisks: []infrav1.DataDisk{
  3026  							{
  3027  								NameSuffix: "etcddisk",
  3028  							},
  3029  							{
  3030  								NameSuffix: "otherdisk",
  3031  							},
  3032  						},
  3033  					},
  3034  				},
  3035  				Machine: &clusterv1.Machine{
  3036  					ObjectMeta: metav1.ObjectMeta{
  3037  						Name: "machine",
  3038  					},
  3039  				},
  3040  			},
  3041  			want: []azure.ResourceSpecGetter{
  3042  				&disks.DiskSpec{
  3043  					Name:          "my-azure-machine_OSDisk",
  3044  					ResourceGroup: "my-rg",
  3045  				},
  3046  				&disks.DiskSpec{
  3047  					Name:          "my-azure-machine_etcddisk",
  3048  					ResourceGroup: "my-rg",
  3049  				},
  3050  				&disks.DiskSpec{
  3051  					Name:          "my-azure-machine_otherdisk",
  3052  					ResourceGroup: "my-rg",
  3053  				},
  3054  			},
  3055  		},
  3056  	}
  3057  
  3058  	for _, tt := range testcases {
  3059  		tt := tt
  3060  		t.Run(tt.name, func(t *testing.T) {
  3061  			g := NewWithT(t)
  3062  
  3063  			t.Parallel()
  3064  			result := tt.machineScope.DiskSpecs()
  3065  			g.Expect(result).To(BeEquivalentTo(tt.want))
  3066  		})
  3067  	}
  3068  }