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

     1  /*
     2  Copyright 2021 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 v1beta1
    18  
    19  import (
    20  	"context"
    21  	"encoding/json"
    22  	"fmt"
    23  	"reflect"
    24  	"testing"
    25  
    26  	"github.com/google/uuid"
    27  	. "github.com/onsi/gomega"
    28  	"github.com/pkg/errors"
    29  	corev1 "k8s.io/api/core/v1"
    30  	"k8s.io/apimachinery/pkg/api/resource"
    31  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    32  	"k8s.io/utils/ptr"
    33  	clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1"
    34  	"sigs.k8s.io/controller-runtime/pkg/client"
    35  )
    36  
    37  func TestAzureMachineSpec_SetDefaultSSHPublicKey(t *testing.T) {
    38  	g := NewWithT(t)
    39  
    40  	type test struct {
    41  		machine *AzureMachine
    42  	}
    43  
    44  	existingPublicKey := "testpublickey"
    45  	publicKeyExistTest := test{machine: createMachineWithSSHPublicKey(existingPublicKey)}
    46  	publicKeyNotExistTest := test{machine: createMachineWithSSHPublicKey("")}
    47  
    48  	err := publicKeyExistTest.machine.Spec.SetDefaultSSHPublicKey()
    49  	g.Expect(err).NotTo(HaveOccurred())
    50  	g.Expect(publicKeyExistTest.machine.Spec.SSHPublicKey).To(Equal(existingPublicKey))
    51  
    52  	err = publicKeyNotExistTest.machine.Spec.SetDefaultSSHPublicKey()
    53  	g.Expect(err).NotTo(HaveOccurred())
    54  	g.Expect(publicKeyNotExistTest.machine.Spec.SSHPublicKey).To(Not(BeEmpty()))
    55  }
    56  
    57  func TestAzureMachineSpec_SetIdentityDefaults(t *testing.T) {
    58  	g := NewWithT(t)
    59  
    60  	type test struct {
    61  		machine *AzureMachine
    62  	}
    63  
    64  	fakeSubscriptionID := uuid.New().String()
    65  	fakeClusterName := "testcluster"
    66  	fakeRoleDefinitionID := "testroledefinitionid"
    67  	fakeScope := fmt.Sprintf("/subscriptions/%s/resourceGroups/%s", fakeSubscriptionID, fakeClusterName)
    68  	existingRoleAssignmentName := "42862306-e485-4319-9bf0-35dbc6f6fe9c"
    69  	roleAssignmentExistTest := test{machine: &AzureMachine{Spec: AzureMachineSpec{
    70  		Identity: VMIdentitySystemAssigned,
    71  		SystemAssignedIdentityRole: &SystemAssignedIdentityRole{
    72  			Name: existingRoleAssignmentName,
    73  		},
    74  	}}}
    75  	notSystemAssignedTest := test{machine: &AzureMachine{Spec: AzureMachineSpec{
    76  		Identity:                   VMIdentityUserAssigned,
    77  		SystemAssignedIdentityRole: &SystemAssignedIdentityRole{},
    78  	}}}
    79  	systemAssignedIdentityRoleExistTest := test{machine: &AzureMachine{Spec: AzureMachineSpec{
    80  		Identity: VMIdentitySystemAssigned,
    81  		SystemAssignedIdentityRole: &SystemAssignedIdentityRole{
    82  			Scope:        fakeScope,
    83  			DefinitionID: fakeRoleDefinitionID,
    84  		},
    85  	}}}
    86  	deprecatedRoleAssignmentNameTest := test{machine: &AzureMachine{Spec: AzureMachineSpec{
    87  		Identity:           VMIdentitySystemAssigned,
    88  		RoleAssignmentName: existingRoleAssignmentName,
    89  	}}}
    90  	emptyTest := test{machine: &AzureMachine{Spec: AzureMachineSpec{
    91  		Identity:                   VMIdentitySystemAssigned,
    92  		SystemAssignedIdentityRole: &SystemAssignedIdentityRole{},
    93  	}}}
    94  	bothDeprecatedRoleAssignmentNameAndSystemAssignedIdentityRoleTest := test{machine: &AzureMachine{Spec: AzureMachineSpec{
    95  		Identity:           VMIdentitySystemAssigned,
    96  		RoleAssignmentName: existingRoleAssignmentName,
    97  		SystemAssignedIdentityRole: &SystemAssignedIdentityRole{
    98  			Name: existingRoleAssignmentName,
    99  		},
   100  	}}}
   101  
   102  	roleAssignmentExistTest.machine.Spec.SetIdentityDefaults(fakeSubscriptionID)
   103  	g.Expect(roleAssignmentExistTest.machine.Spec.SystemAssignedIdentityRole.Name).To(Equal(existingRoleAssignmentName))
   104  
   105  	notSystemAssignedTest.machine.Spec.SetIdentityDefaults(fakeSubscriptionID)
   106  	g.Expect(notSystemAssignedTest.machine.Spec.SystemAssignedIdentityRole.Name).To(BeEmpty())
   107  
   108  	systemAssignedIdentityRoleExistTest.machine.Spec.SetIdentityDefaults(fakeSubscriptionID)
   109  	g.Expect(systemAssignedIdentityRoleExistTest.machine.Spec.SystemAssignedIdentityRole.Scope).To(Equal(fakeScope))
   110  	g.Expect(systemAssignedIdentityRoleExistTest.machine.Spec.SystemAssignedIdentityRole.DefinitionID).To(Equal(fakeRoleDefinitionID))
   111  
   112  	deprecatedRoleAssignmentNameTest.machine.Spec.SetIdentityDefaults(fakeSubscriptionID)
   113  	g.Expect(deprecatedRoleAssignmentNameTest.machine.Spec.SystemAssignedIdentityRole.Name).To(Equal(existingRoleAssignmentName))
   114  	g.Expect(deprecatedRoleAssignmentNameTest.machine.Spec.RoleAssignmentName).To(BeEmpty())
   115  
   116  	emptyTest.machine.Spec.SetIdentityDefaults(fakeSubscriptionID)
   117  	g.Expect(emptyTest.machine.Spec.SystemAssignedIdentityRole.Name).To(Not(BeEmpty()))
   118  	_, err := uuid.Parse(emptyTest.machine.Spec.SystemAssignedIdentityRole.Name)
   119  	g.Expect(err).To(Not(HaveOccurred()))
   120  	g.Expect(emptyTest.machine.Spec.SystemAssignedIdentityRole.Scope).To(Equal(fmt.Sprintf("/subscriptions/%s/", fakeSubscriptionID)))
   121  	g.Expect(emptyTest.machine.Spec.SystemAssignedIdentityRole.DefinitionID).To(Equal(fmt.Sprintf("/subscriptions/%s/providers/Microsoft.Authorization/roleDefinitions/%s", fakeSubscriptionID, ContributorRoleID)))
   122  
   123  	bothDeprecatedRoleAssignmentNameAndSystemAssignedIdentityRoleTest.machine.Spec.SetIdentityDefaults(fakeSubscriptionID)
   124  	g.Expect(bothDeprecatedRoleAssignmentNameAndSystemAssignedIdentityRoleTest.machine.Spec.RoleAssignmentName).To(Not(BeEmpty()))
   125  	g.Expect(bothDeprecatedRoleAssignmentNameAndSystemAssignedIdentityRoleTest.machine.Spec.SystemAssignedIdentityRole.Name).To(Not(BeEmpty()))
   126  }
   127  
   128  func TestAzureMachineSpec_SetSpotEvictionPolicyDefaults(t *testing.T) {
   129  	deallocatePolicy := SpotEvictionPolicyDeallocate
   130  	deletePolicy := SpotEvictionPolicyDelete
   131  
   132  	g := NewWithT(t)
   133  
   134  	type test struct {
   135  		machine *AzureMachine
   136  	}
   137  
   138  	spotVMOptionsExistTest := test{machine: &AzureMachine{Spec: AzureMachineSpec{
   139  		SpotVMOptions: &SpotVMOptions{
   140  			MaxPrice: &resource.Quantity{Format: "vmoptions-0"},
   141  		},
   142  	}}}
   143  
   144  	localDiffDiskSettingsExistTest := test{machine: &AzureMachine{Spec: AzureMachineSpec{
   145  		SpotVMOptions: &SpotVMOptions{
   146  			MaxPrice: &resource.Quantity{},
   147  		},
   148  		OSDisk: OSDisk{
   149  			DiffDiskSettings: &DiffDiskSettings{
   150  				Option: "Local",
   151  			},
   152  		},
   153  	}}}
   154  
   155  	spotVMOptionsExistTest.machine.Spec.SetSpotEvictionPolicyDefaults()
   156  	g.Expect(spotVMOptionsExistTest.machine.Spec.SpotVMOptions.EvictionPolicy).To(Equal(&deallocatePolicy))
   157  
   158  	localDiffDiskSettingsExistTest.machine.Spec.SetSpotEvictionPolicyDefaults()
   159  	g.Expect(localDiffDiskSettingsExistTest.machine.Spec.SpotVMOptions.EvictionPolicy).To(Equal(&deletePolicy))
   160  }
   161  
   162  func TestAzureMachineSpec_SetDataDisksDefaults(t *testing.T) {
   163  	cases := []struct {
   164  		name   string
   165  		disks  []DataDisk
   166  		output []DataDisk
   167  	}{
   168  		{
   169  			name:   "no disks",
   170  			disks:  []DataDisk{},
   171  			output: []DataDisk{},
   172  		},
   173  		{
   174  			name: "no LUNs specified",
   175  			disks: []DataDisk{
   176  				{
   177  					NameSuffix:  "testdisk1",
   178  					DiskSizeGB:  30,
   179  					CachingType: "ReadWrite",
   180  				},
   181  				{
   182  					NameSuffix:  "testdisk2",
   183  					DiskSizeGB:  30,
   184  					CachingType: "ReadWrite",
   185  				},
   186  			},
   187  			output: []DataDisk{
   188  				{
   189  					NameSuffix:  "testdisk1",
   190  					DiskSizeGB:  30,
   191  					Lun:         ptr.To[int32](0),
   192  					CachingType: "ReadWrite",
   193  				},
   194  				{
   195  					NameSuffix:  "testdisk2",
   196  					DiskSizeGB:  30,
   197  					Lun:         ptr.To[int32](1),
   198  					CachingType: "ReadWrite",
   199  				},
   200  			},
   201  		},
   202  		{
   203  			name: "All LUNs specified",
   204  			disks: []DataDisk{
   205  				{
   206  					NameSuffix:  "testdisk1",
   207  					DiskSizeGB:  30,
   208  					Lun:         ptr.To[int32](5),
   209  					CachingType: "ReadWrite",
   210  				},
   211  				{
   212  					NameSuffix:  "testdisk2",
   213  					DiskSizeGB:  30,
   214  					Lun:         ptr.To[int32](3),
   215  					CachingType: "ReadWrite",
   216  				},
   217  			},
   218  			output: []DataDisk{
   219  				{
   220  					NameSuffix:  "testdisk1",
   221  					DiskSizeGB:  30,
   222  					Lun:         ptr.To[int32](5),
   223  					CachingType: "ReadWrite",
   224  				},
   225  				{
   226  					NameSuffix:  "testdisk2",
   227  					DiskSizeGB:  30,
   228  					Lun:         ptr.To[int32](3),
   229  					CachingType: "ReadWrite",
   230  				},
   231  			},
   232  		},
   233  		{
   234  			name: "Some LUNs missing",
   235  			disks: []DataDisk{
   236  				{
   237  					NameSuffix:  "testdisk1",
   238  					DiskSizeGB:  30,
   239  					Lun:         ptr.To[int32](0),
   240  					CachingType: "ReadWrite",
   241  				},
   242  				{
   243  					NameSuffix:  "testdisk2",
   244  					DiskSizeGB:  30,
   245  					CachingType: "ReadWrite",
   246  				},
   247  				{
   248  					NameSuffix:  "testdisk3",
   249  					DiskSizeGB:  30,
   250  					Lun:         ptr.To[int32](1),
   251  					CachingType: "ReadWrite",
   252  				},
   253  				{
   254  					NameSuffix:  "testdisk4",
   255  					DiskSizeGB:  30,
   256  					CachingType: "ReadWrite",
   257  				},
   258  			},
   259  			output: []DataDisk{
   260  				{
   261  					NameSuffix:  "testdisk1",
   262  					DiskSizeGB:  30,
   263  					Lun:         ptr.To[int32](0),
   264  					CachingType: "ReadWrite",
   265  				},
   266  				{
   267  					NameSuffix:  "testdisk2",
   268  					DiskSizeGB:  30,
   269  					Lun:         ptr.To[int32](2),
   270  					CachingType: "ReadWrite",
   271  				},
   272  				{
   273  					NameSuffix:  "testdisk3",
   274  					DiskSizeGB:  30,
   275  					Lun:         ptr.To[int32](1),
   276  					CachingType: "ReadWrite",
   277  				},
   278  				{
   279  					NameSuffix:  "testdisk4",
   280  					DiskSizeGB:  30,
   281  					Lun:         ptr.To[int32](3),
   282  					CachingType: "ReadWrite",
   283  				},
   284  			},
   285  		},
   286  		{
   287  			name: "CachingType unspecified",
   288  			disks: []DataDisk{
   289  				{
   290  					NameSuffix: "testdisk1",
   291  					DiskSizeGB: 30,
   292  					Lun:        ptr.To[int32](0),
   293  				},
   294  				{
   295  					NameSuffix: "testdisk2",
   296  					DiskSizeGB: 30,
   297  					Lun:        ptr.To[int32](2),
   298  				},
   299  				{
   300  					NameSuffix: "testdisk3",
   301  					DiskSizeGB: 30,
   302  					ManagedDisk: &ManagedDiskParameters{
   303  						StorageAccountType: "UltraSSD_LRS",
   304  					},
   305  					Lun: ptr.To[int32](3),
   306  				},
   307  			},
   308  			output: []DataDisk{
   309  				{
   310  					NameSuffix:  "testdisk1",
   311  					DiskSizeGB:  30,
   312  					Lun:         ptr.To[int32](0),
   313  					CachingType: "ReadWrite",
   314  				},
   315  				{
   316  					NameSuffix:  "testdisk2",
   317  					DiskSizeGB:  30,
   318  					Lun:         ptr.To[int32](2),
   319  					CachingType: "ReadWrite",
   320  				},
   321  				{
   322  					NameSuffix: "testdisk3",
   323  					DiskSizeGB: 30,
   324  					Lun:        ptr.To[int32](3),
   325  					ManagedDisk: &ManagedDiskParameters{
   326  						StorageAccountType: "UltraSSD_LRS",
   327  					},
   328  					CachingType: "None",
   329  				},
   330  			},
   331  		},
   332  	}
   333  
   334  	for _, c := range cases {
   335  		tc := c
   336  		t.Run(tc.name, func(t *testing.T) {
   337  			t.Parallel()
   338  			machine := hardcodedAzureMachineWithSSHKey(generateSSHPublicKey(true))
   339  			machine.Spec.DataDisks = tc.disks
   340  			machine.Spec.SetDataDisksDefaults()
   341  			if !reflect.DeepEqual(machine.Spec.DataDisks, tc.output) {
   342  				expected, _ := json.MarshalIndent(tc.output, "", "\t")
   343  				actual, _ := json.MarshalIndent(machine.Spec.DataDisks, "", "\t")
   344  				t.Errorf("Expected %s, got %s", string(expected), string(actual))
   345  			}
   346  		})
   347  	}
   348  }
   349  
   350  func TestAzureMachineSpec_SetNetworkInterfacesDefaults(t *testing.T) {
   351  	tests := []struct {
   352  		name    string
   353  		machine *AzureMachine
   354  		want    *AzureMachine
   355  	}{
   356  		{
   357  			name: "defaulting webhook updates machine with deprecated subnetName field",
   358  			machine: &AzureMachine{
   359  				Spec: AzureMachineSpec{
   360  					SubnetName: "test-subnet",
   361  				},
   362  			},
   363  			want: &AzureMachine{
   364  				Spec: AzureMachineSpec{
   365  					SubnetName: "",
   366  					NetworkInterfaces: []NetworkInterface{
   367  						{
   368  							SubnetName:       "test-subnet",
   369  							PrivateIPConfigs: 1,
   370  						},
   371  					},
   372  				},
   373  			},
   374  		},
   375  		{
   376  			name: "defaulting webhook updates machine with deprecated subnetName field and empty NetworkInterfaces slice",
   377  			machine: &AzureMachine{
   378  				Spec: AzureMachineSpec{
   379  					SubnetName:        "test-subnet",
   380  					NetworkInterfaces: []NetworkInterface{},
   381  				},
   382  			},
   383  			want: &AzureMachine{
   384  				Spec: AzureMachineSpec{
   385  					SubnetName: "",
   386  					NetworkInterfaces: []NetworkInterface{
   387  						{
   388  							SubnetName:       "test-subnet",
   389  							PrivateIPConfigs: 1,
   390  						},
   391  					},
   392  				},
   393  			},
   394  		},
   395  		{
   396  			name: "defaulting webhook updates machine with deprecated acceleratedNetworking field",
   397  			machine: &AzureMachine{
   398  				Spec: AzureMachineSpec{
   399  					SubnetName:            "test-subnet",
   400  					AcceleratedNetworking: ptr.To(true),
   401  				},
   402  			},
   403  			want: &AzureMachine{
   404  				Spec: AzureMachineSpec{
   405  					SubnetName:            "",
   406  					AcceleratedNetworking: nil,
   407  					NetworkInterfaces: []NetworkInterface{
   408  						{
   409  							SubnetName:            "test-subnet",
   410  							PrivateIPConfigs:      1,
   411  							AcceleratedNetworking: ptr.To(true),
   412  						},
   413  					},
   414  				},
   415  			},
   416  		},
   417  		{
   418  			name: "defaulting webhook does nothing if both new and deprecated subnetName fields are set",
   419  			machine: &AzureMachine{
   420  				Spec: AzureMachineSpec{
   421  					SubnetName: "test-subnet",
   422  					NetworkInterfaces: []NetworkInterface{{
   423  						SubnetName: "test-subnet",
   424  					}},
   425  				},
   426  			},
   427  			want: &AzureMachine{
   428  				Spec: AzureMachineSpec{
   429  					SubnetName:            "test-subnet",
   430  					AcceleratedNetworking: nil,
   431  					NetworkInterfaces: []NetworkInterface{
   432  						{
   433  							SubnetName: "test-subnet",
   434  						},
   435  					},
   436  				},
   437  			},
   438  		},
   439  	}
   440  
   441  	for _, tc := range tests {
   442  		t.Run(tc.name, func(t *testing.T) {
   443  			g := NewWithT(t)
   444  			tc.machine.Spec.SetNetworkInterfacesDefaults()
   445  			g.Expect(tc.machine).To(Equal(tc.want))
   446  		})
   447  	}
   448  }
   449  
   450  func TestAzureMachineSpec_GetOwnerCluster(t *testing.T) {
   451  	tests := []struct {
   452  		name            string
   453  		maxAttempts     int
   454  		wantedName      string
   455  		wantedNamespace string
   456  		wantErr         bool
   457  	}{
   458  		{
   459  			name:            "ownerCluster is returned",
   460  			maxAttempts:     1,
   461  			wantedName:      "test-cluster",
   462  			wantedNamespace: "default",
   463  			wantErr:         false,
   464  		},
   465  		{
   466  			name:            "ownerCluster is returned after 2 attempts",
   467  			maxAttempts:     2,
   468  			wantedName:      "test-cluster",
   469  			wantedNamespace: "default",
   470  			wantErr:         false,
   471  		},
   472  		{
   473  			name:            "ownerCluster is not returned after 5 attempts",
   474  			maxAttempts:     5,
   475  			wantedName:      "test-cluster",
   476  			wantedNamespace: "default",
   477  			wantErr:         true,
   478  		},
   479  	}
   480  
   481  	for _, tc := range tests {
   482  		t.Run(tc.name, func(t *testing.T) {
   483  			g := NewWithT(t)
   484  			client := mockClient{ReturnError: tc.wantErr}
   485  			name, namespace, err := GetOwnerAzureClusterNameAndNamespace(client, "test-cluster", "default", tc.maxAttempts)
   486  			if tc.wantErr {
   487  				g.Expect(err).To(HaveOccurred())
   488  			} else {
   489  				g.Expect(err).NotTo(HaveOccurred())
   490  				g.Expect(name).To(Equal(tc.wantedName))
   491  				g.Expect(namespace).To(Equal(tc.wantedNamespace))
   492  			}
   493  		})
   494  	}
   495  }
   496  
   497  func TestAzureMachineSpec_GetSubscriptionID(t *testing.T) {
   498  	tests := []struct {
   499  		name                       string
   500  		maxAttempts                int
   501  		ownerAzureClusterName      string
   502  		ownerAzureClusterNamespace string
   503  		want                       string
   504  		wantErr                    bool
   505  	}{
   506  		{
   507  			name:                  "empty owner cluster name returns error",
   508  			maxAttempts:           1,
   509  			ownerAzureClusterName: "",
   510  			want:                  "test-subscription-id",
   511  			wantErr:               true,
   512  		},
   513  		{
   514  			name:                       "subscription ID is returned",
   515  			maxAttempts:                1,
   516  			ownerAzureClusterName:      "test-cluster",
   517  			ownerAzureClusterNamespace: "default",
   518  			want:                       "test-subscription-id",
   519  			wantErr:                    false,
   520  		},
   521  		{
   522  			name:                       "subscription ID is returned after 2 attempts",
   523  			maxAttempts:                2,
   524  			ownerAzureClusterName:      "test-cluster",
   525  			ownerAzureClusterNamespace: "default",
   526  			want:                       "test-subscription-id",
   527  			wantErr:                    false,
   528  		},
   529  		{
   530  			name:                       "subscription ID is not returned after 5 attempts",
   531  			maxAttempts:                5,
   532  			ownerAzureClusterName:      "test-cluster",
   533  			ownerAzureClusterNamespace: "default",
   534  			want:                       "",
   535  			wantErr:                    true,
   536  		},
   537  	}
   538  
   539  	for _, tc := range tests {
   540  		t.Run(tc.name, func(t *testing.T) {
   541  			g := NewWithT(t)
   542  			client := mockClient{ReturnError: tc.wantErr}
   543  			result, err := GetSubscriptionID(client, tc.ownerAzureClusterName, tc.ownerAzureClusterNamespace, tc.maxAttempts)
   544  			if tc.wantErr {
   545  				g.Expect(err).To(HaveOccurred())
   546  			} else {
   547  				g.Expect(err).NotTo(HaveOccurred())
   548  				g.Expect(result).To(Equal(tc.want))
   549  			}
   550  		})
   551  	}
   552  }
   553  
   554  type mockClient struct {
   555  	client.Client
   556  	ReturnError bool
   557  }
   558  
   559  func (m mockClient) Get(ctx context.Context, key client.ObjectKey, obj client.Object, opts ...client.GetOption) error {
   560  	if m.ReturnError {
   561  		return errors.New("AzureCluster not found: failed to find owner cluster for test-cluster")
   562  	}
   563  	// Check if we're calling Get on an AzureCluster or a Cluster
   564  	switch obj := obj.(type) {
   565  	case *AzureCluster:
   566  		obj.Spec.SubscriptionID = "test-subscription-id"
   567  	case *clusterv1.Cluster:
   568  		obj.Spec = clusterv1.ClusterSpec{
   569  			InfrastructureRef: &corev1.ObjectReference{
   570  				Kind:      AzureClusterKind,
   571  				Name:      "test-cluster",
   572  				Namespace: "default",
   573  			},
   574  			ClusterNetwork: &clusterv1.ClusterNetwork{
   575  				Services: &clusterv1.NetworkRanges{
   576  					CIDRBlocks: []string{"192.168.0.0/26"},
   577  				},
   578  			},
   579  		}
   580  	default:
   581  		return errors.New("unexpected object type")
   582  	}
   583  
   584  	return nil
   585  }
   586  
   587  func createMachineWithSSHPublicKey(sshPublicKey string) *AzureMachine {
   588  	machine := hardcodedAzureMachineWithSSHKey(sshPublicKey)
   589  	return machine
   590  }
   591  
   592  func createMachineWithUserAssignedIdentities(identitiesList []UserAssignedIdentity) *AzureMachine {
   593  	machine := hardcodedAzureMachineWithSSHKey(generateSSHPublicKey(true))
   594  	machine.Spec.Identity = VMIdentityUserAssigned
   595  	machine.Spec.UserAssignedIdentities = identitiesList
   596  	return machine
   597  }
   598  
   599  func hardcodedAzureMachineWithSSHKey(sshPublicKey string) *AzureMachine {
   600  	return &AzureMachine{
   601  		ObjectMeta: metav1.ObjectMeta{
   602  			Labels: map[string]string{
   603  				clusterv1.ClusterNameLabel: "test-cluster",
   604  			},
   605  		},
   606  		Spec: AzureMachineSpec{
   607  			SSHPublicKey: sshPublicKey,
   608  			OSDisk:       generateValidOSDisk(),
   609  			Image: &Image{
   610  				SharedGallery: &AzureSharedGalleryImage{
   611  					SubscriptionID: "SUB123",
   612  					ResourceGroup:  "RG123",
   613  					Name:           "NAME123",
   614  					Gallery:        "GALLERY1",
   615  					Version:        "1.0.0",
   616  				},
   617  			},
   618  		},
   619  	}
   620  }