sigs.k8s.io/cluster-api-provider-azure@v1.17.0/api/v1beta1/azuremachine_webhook_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  	"testing"
    22  
    23  	"github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/compute/armcompute/v5"
    24  	. "github.com/onsi/gomega"
    25  	"github.com/pkg/errors"
    26  	corev1 "k8s.io/api/core/v1"
    27  	"k8s.io/apimachinery/pkg/api/resource"
    28  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    29  	"k8s.io/utils/ptr"
    30  	clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1"
    31  	"sigs.k8s.io/controller-runtime/pkg/client"
    32  )
    33  
    34  var (
    35  	validSSHPublicKey = generateSSHPublicKey(true)
    36  	validOSDisk       = generateValidOSDisk()
    37  )
    38  
    39  func TestAzureMachine_ValidateCreate(t *testing.T) {
    40  	tests := []struct {
    41  		name    string
    42  		machine *AzureMachine
    43  		wantErr bool
    44  	}{
    45  		{
    46  			name:    "azuremachine with marketplace image - full",
    47  			machine: createMachineWithMarketPlaceImage("PUB1234", "OFFER1234", "SKU1234", "1.0.0"),
    48  			wantErr: false,
    49  		},
    50  		{
    51  			name:    "azuremachine with marketplace image - missing publisher",
    52  			machine: createMachineWithMarketPlaceImage("", "OFFER1235", "SKU1235", "2.0.0"),
    53  			wantErr: true,
    54  		},
    55  		{
    56  			name:    "azuremachine with shared gallery image - full",
    57  			machine: createMachineWithSharedImage("SUB123", "RG123", "NAME123", "GALLERY1", "1.0.0"),
    58  			wantErr: false,
    59  		},
    60  		{
    61  			name:    "azuremachine with marketplace image - missing subscription",
    62  			machine: createMachineWithSharedImage("", "RG124", "NAME124", "GALLERY1", "2.0.0"),
    63  			wantErr: true,
    64  		},
    65  		{
    66  			name:    "azuremachine with image by - with id",
    67  			machine: createMachineWithImageByID("ID123"),
    68  			wantErr: false,
    69  		},
    70  		{
    71  			name:    "azuremachine with image by - without id",
    72  			machine: createMachineWithImageByID(""),
    73  			wantErr: true,
    74  		},
    75  		{
    76  			name:    "azuremachine with valid SSHPublicKey",
    77  			machine: createMachineWithSSHPublicKey(validSSHPublicKey),
    78  			wantErr: false,
    79  		},
    80  		{
    81  			name:    "azuremachine without SSHPublicKey",
    82  			machine: createMachineWithSSHPublicKey(""),
    83  			wantErr: true,
    84  		},
    85  		{
    86  			name:    "azuremachine with invalid SSHPublicKey",
    87  			machine: createMachineWithSSHPublicKey("invalid ssh key"),
    88  			wantErr: true,
    89  		},
    90  		{
    91  			name: "azuremachine with list of user-assigned identities",
    92  			machine: createMachineWithUserAssignedIdentities([]UserAssignedIdentity{
    93  				{ProviderID: "azure:///subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/my-resource-group/providers/Microsoft.Compute/virtualMachines/default-12345-control-plane-9d5x5"},
    94  				{ProviderID: "azure:///subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/my-resource-group/providers/Microsoft.Compute/virtualMachines/default-12345-control-plane-a1b2c"},
    95  			}),
    96  			wantErr: false,
    97  		},
    98  		{
    99  			name: "azuremachine with list of user-assigned identities with wrong identity type",
   100  			machine: createMachineWithUserAssignedIdentitiesWithBadIdentity([]UserAssignedIdentity{
   101  				{ProviderID: "azure:///subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/my-resource-group/providers/Microsoft.Compute/virtualMachines/default-12345-control-plane-9d5x5"},
   102  				{ProviderID: "azure:///subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/my-resource-group/providers/Microsoft.Compute/virtualMachines/default-12345-control-plane-a1b2c"},
   103  			}),
   104  			wantErr: true,
   105  		},
   106  		{
   107  			name:    "azuremachine with empty list of user-assigned identities",
   108  			machine: createMachineWithUserAssignedIdentities([]UserAssignedIdentity{}),
   109  			wantErr: true,
   110  		},
   111  		{
   112  			name:    "azuremachine with valid osDisk cache type",
   113  			machine: createMachineWithOsDiskCacheType(string(armcompute.PossibleCachingTypesValues()[1])),
   114  			wantErr: false,
   115  		},
   116  		{
   117  			name:    "azuremachine with invalid osDisk cache type",
   118  			machine: createMachineWithOsDiskCacheType("invalid_cache_type"),
   119  			wantErr: true,
   120  		},
   121  		{
   122  			name:    "azuremachinepool with managed diagnostics profile",
   123  			machine: createMachineWithDiagnostics(ManagedDiagnosticsStorage, nil),
   124  			wantErr: false,
   125  		},
   126  		{
   127  			name:    "azuremachine with disabled diagnostics profile",
   128  			machine: createMachineWithDiagnostics(ManagedDiagnosticsStorage, nil),
   129  			wantErr: false,
   130  		},
   131  		{
   132  			name:    "azuremachine with user managed diagnostics profile and defined user managed storage account",
   133  			machine: createMachineWithDiagnostics(UserManagedDiagnosticsStorage, &UserManagedBootDiagnostics{StorageAccountURI: "https://fakeurl"}),
   134  			wantErr: false,
   135  		},
   136  		{
   137  			name:    "azuremachine with empty diagnostics profile",
   138  			machine: createMachineWithDiagnostics("", nil),
   139  			wantErr: false,
   140  		},
   141  		{
   142  			name:    "azuremachine with user managed diagnostics profile, but empty user managed storage account",
   143  			machine: createMachineWithDiagnostics(UserManagedDiagnosticsStorage, nil),
   144  			wantErr: true,
   145  		},
   146  		{
   147  			name:    "azuremachine with invalid network configuration",
   148  			machine: createMachineWithNetworkConfig("subnet", nil, []NetworkInterface{{SubnetName: "subnet1"}}),
   149  			wantErr: true,
   150  		},
   151  		{
   152  			name:    "azuremachine with valid legacy network configuration",
   153  			machine: createMachineWithNetworkConfig("subnet", nil, []NetworkInterface{}),
   154  			wantErr: false,
   155  		},
   156  		{
   157  			name:    "azuremachine with valid network configuration",
   158  			machine: createMachineWithNetworkConfig("", nil, []NetworkInterface{{SubnetName: "subnet", PrivateIPConfigs: 1}}),
   159  			wantErr: false,
   160  		},
   161  		{
   162  			name:    "azuremachine without confidential compute properties and encryption at host enabled",
   163  			machine: createMachineWithConfidentialCompute("", "", true, false, false),
   164  			wantErr: false,
   165  		},
   166  		{
   167  			name:    "azuremachine with confidential compute VMGuestStateOnly encryption and encryption at host enabled",
   168  			machine: createMachineWithConfidentialCompute(SecurityEncryptionTypeVMGuestStateOnly, SecurityTypesConfidentialVM, true, false, false),
   169  			wantErr: true,
   170  		},
   171  		{
   172  			name:    "azuremachine with confidential compute DiskWithVMGuestState encryption and encryption at host enabled",
   173  			machine: createMachineWithConfidentialCompute(SecurityEncryptionTypeDiskWithVMGuestState, SecurityTypesConfidentialVM, true, true, true),
   174  			wantErr: true,
   175  		},
   176  		{
   177  			name:    "azuremachine with confidential compute VMGuestStateOnly encryption, vTPM and SecureBoot enabled",
   178  			machine: createMachineWithConfidentialCompute(SecurityEncryptionTypeVMGuestStateOnly, SecurityTypesConfidentialVM, false, true, true),
   179  			wantErr: false,
   180  		},
   181  		{
   182  			name:    "azuremachine with confidential compute VMGuestStateOnly encryption enabled, vTPM enabled and SecureBoot disabled",
   183  			machine: createMachineWithConfidentialCompute(SecurityEncryptionTypeVMGuestStateOnly, SecurityTypesConfidentialVM, false, true, false),
   184  			wantErr: false,
   185  		},
   186  		{
   187  			name:    "azuremachine with confidential compute VMGuestStateOnly encryption enabled, vTPM disabled and SecureBoot enabled",
   188  			machine: createMachineWithConfidentialCompute(SecurityEncryptionTypeVMGuestStateOnly, SecurityTypesConfidentialVM, false, false, true),
   189  			wantErr: true,
   190  		},
   191  		{
   192  			name:    "azuremachine with confidential compute VMGuestStateOnly encryption enabled, vTPM enabled, SecureBoot disabled and SecurityType empty",
   193  			machine: createMachineWithConfidentialCompute(SecurityEncryptionTypeVMGuestStateOnly, "", false, true, false),
   194  			wantErr: true,
   195  		},
   196  		{
   197  			name:    "azuremachine with confidential compute VMGuestStateOnly encryption enabled, vTPM and SecureBoot empty",
   198  			machine: createMachineWithConfidentialCompute(SecurityEncryptionTypeVMGuestStateOnly, SecurityTypesConfidentialVM, false, false, false),
   199  			wantErr: true,
   200  		},
   201  		{
   202  			name:    "azuremachine with confidential compute DiskWithVMGuestState encryption, vTPM and SecureBoot enabled",
   203  			machine: createMachineWithConfidentialCompute(SecurityEncryptionTypeDiskWithVMGuestState, SecurityTypesConfidentialVM, false, true, true),
   204  			wantErr: false,
   205  		},
   206  		{
   207  			name:    "azuremachine with confidential compute DiskWithVMGuestState encryption enabled, vTPM enabled and SecureBoot disabled",
   208  			machine: createMachineWithConfidentialCompute(SecurityEncryptionTypeDiskWithVMGuestState, SecurityTypesConfidentialVM, false, true, false),
   209  			wantErr: true,
   210  		},
   211  		{
   212  			name:    "azuremachine with confidential compute DiskWithVMGuestState encryption enabled, vTPM disabled and SecureBoot enabled",
   213  			machine: createMachineWithConfidentialCompute(SecurityEncryptionTypeDiskWithVMGuestState, SecurityTypesConfidentialVM, false, false, true),
   214  			wantErr: true,
   215  		},
   216  		{
   217  			name:    "azuremachine with confidential compute DiskWithVMGuestState encryption enabled, vTPM disabled and SecureBoot disabled",
   218  			machine: createMachineWithConfidentialCompute(SecurityEncryptionTypeDiskWithVMGuestState, SecurityTypesConfidentialVM, false, false, false),
   219  			wantErr: true,
   220  		},
   221  		{
   222  			name:    "azuremachine with confidential compute DiskWithVMGuestState encryption enabled, vTPM enabled, SecureBoot disabled and SecurityType empty",
   223  			machine: createMachineWithConfidentialCompute(SecurityEncryptionTypeDiskWithVMGuestState, "", false, true, false),
   224  			wantErr: true,
   225  		},
   226  		{
   227  			name:    "azuremachine with empty capacity reservation group id",
   228  			machine: createMachineWithCapacityReservaionGroupID(""),
   229  			wantErr: false,
   230  		},
   231  		{
   232  			name:    "azuremachine with valid capacity reservation group id",
   233  			machine: createMachineWithCapacityReservaionGroupID("azure:///subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/my-resource-group/providers/Microsoft.Compute/capacityReservationGroups/capacity-reservation-group-name"),
   234  			wantErr: false,
   235  		},
   236  		{
   237  			name:    "azuremachine with invalid capacity reservation group id",
   238  			machine: createMachineWithCapacityReservaionGroupID("invalid-capacity-group-id"),
   239  			wantErr: true,
   240  		},
   241  		{
   242  			name:    "azuremachine with DisableExtensionOperations true and without VMExtensions",
   243  			machine: createMachineWithDisableExtenionOperations(),
   244  			wantErr: false,
   245  		},
   246  		{
   247  			name:    "azuremachine with DisableExtensionOperations true and with VMExtension",
   248  			machine: createMachineWithDisableExtenionOperationsAndHasExtension(),
   249  			wantErr: true,
   250  		},
   251  	}
   252  	for _, tc := range tests {
   253  		t.Run(tc.name, func(t *testing.T) {
   254  			g := NewWithT(t)
   255  			mw := &azureMachineWebhook{}
   256  			_, err := mw.ValidateCreate(context.Background(), tc.machine)
   257  			if tc.wantErr {
   258  				g.Expect(err).To(HaveOccurred())
   259  			} else {
   260  				g.Expect(err).NotTo(HaveOccurred())
   261  			}
   262  		})
   263  	}
   264  }
   265  
   266  func TestAzureMachine_ValidateUpdate(t *testing.T) {
   267  	tests := []struct {
   268  		name       string
   269  		oldMachine *AzureMachine
   270  		newMachine *AzureMachine
   271  		wantErr    bool
   272  	}{
   273  		{
   274  			name: "invalidTest: azuremachine.spec.image is immutable",
   275  			oldMachine: &AzureMachine{
   276  				Spec: AzureMachineSpec{
   277  					Image: &Image{
   278  						ID: ptr.To("imageID-1"),
   279  					},
   280  				},
   281  			},
   282  			newMachine: &AzureMachine{
   283  				Spec: AzureMachineSpec{
   284  					Image: &Image{
   285  						ID: ptr.To("imageID-2"),
   286  					},
   287  				},
   288  			},
   289  			wantErr: true,
   290  		},
   291  		{
   292  			name: "validTest: azuremachine.spec.image is immutable",
   293  			oldMachine: &AzureMachine{
   294  				Spec: AzureMachineSpec{
   295  					Image: &Image{
   296  						ID: ptr.To("imageID-1"),
   297  					},
   298  				},
   299  			},
   300  			newMachine: &AzureMachine{
   301  				Spec: AzureMachineSpec{
   302  					Image: &Image{
   303  						ID: ptr.To("imageID-1"),
   304  					},
   305  				},
   306  			},
   307  			wantErr: false,
   308  		},
   309  		{
   310  			name: "invalidTest: azuremachine.spec.Identity is immutable",
   311  			oldMachine: &AzureMachine{
   312  				Spec: AzureMachineSpec{
   313  					Identity: VMIdentityUserAssigned,
   314  				},
   315  			},
   316  			newMachine: &AzureMachine{
   317  				Spec: AzureMachineSpec{
   318  					Identity: VMIdentityNone,
   319  				},
   320  			},
   321  			wantErr: true,
   322  		},
   323  		{
   324  			name: "validTest: azuremachine.spec.Identity is immutable",
   325  			oldMachine: &AzureMachine{
   326  				Spec: AzureMachineSpec{
   327  					Identity: VMIdentityNone,
   328  				},
   329  			},
   330  			newMachine: &AzureMachine{
   331  				Spec: AzureMachineSpec{
   332  					Identity: VMIdentityNone,
   333  				},
   334  			},
   335  			wantErr: false,
   336  		},
   337  		{
   338  			name: "invalidTest: azuremachine.spec.UserAssignedIdentities is immutable",
   339  			oldMachine: &AzureMachine{
   340  				Spec: AzureMachineSpec{
   341  					UserAssignedIdentities: []UserAssignedIdentity{
   342  						{ProviderID: "providerID-1"},
   343  					},
   344  				},
   345  			},
   346  			newMachine: &AzureMachine{
   347  				Spec: AzureMachineSpec{
   348  					UserAssignedIdentities: []UserAssignedIdentity{
   349  						{ProviderID: "providerID-2"},
   350  					},
   351  				},
   352  			},
   353  			wantErr: true,
   354  		},
   355  		{
   356  			name: "validTest: azuremachine.spec.UserAssignedIdentities is immutable",
   357  			oldMachine: &AzureMachine{
   358  				Spec: AzureMachineSpec{
   359  					UserAssignedIdentities: []UserAssignedIdentity{
   360  						{ProviderID: "providerID-1"},
   361  					},
   362  				},
   363  			},
   364  			newMachine: &AzureMachine{
   365  				Spec: AzureMachineSpec{
   366  					UserAssignedIdentities: []UserAssignedIdentity{
   367  						{ProviderID: "providerID-1"},
   368  					},
   369  				},
   370  			},
   371  			wantErr: false,
   372  		},
   373  		{
   374  			name: "invalidTest: azuremachine.spec.RoleAssignmentName is immutable",
   375  			oldMachine: &AzureMachine{
   376  				Spec: AzureMachineSpec{
   377  					RoleAssignmentName: "role",
   378  				},
   379  			},
   380  			newMachine: &AzureMachine{
   381  				Spec: AzureMachineSpec{
   382  					RoleAssignmentName: "not-role",
   383  				},
   384  			},
   385  			wantErr: true,
   386  		},
   387  		{
   388  			name: "validTest: azuremachine.spec.RoleAssignmentName is immutable",
   389  			oldMachine: &AzureMachine{
   390  				Spec: AzureMachineSpec{
   391  					RoleAssignmentName: "role",
   392  				},
   393  			},
   394  			newMachine: &AzureMachine{
   395  				Spec: AzureMachineSpec{
   396  					RoleAssignmentName: "role",
   397  				},
   398  			},
   399  			wantErr: false,
   400  		},
   401  		{
   402  			name: "invalidTest: azuremachine.spec.RoleAssignmentName is immutable",
   403  			oldMachine: &AzureMachine{
   404  				Spec: AzureMachineSpec{
   405  					SystemAssignedIdentityRole: &SystemAssignedIdentityRole{
   406  						Name:         "role",
   407  						Scope:        "scope",
   408  						DefinitionID: "definitionID",
   409  					},
   410  				},
   411  			},
   412  			newMachine: &AzureMachine{
   413  				Spec: AzureMachineSpec{
   414  					SystemAssignedIdentityRole: &SystemAssignedIdentityRole{
   415  						Name:         "not-role",
   416  						Scope:        "scope",
   417  						DefinitionID: "definitionID",
   418  					},
   419  				},
   420  			},
   421  			wantErr: true,
   422  		},
   423  		{
   424  			name: "validTest: azuremachine.spec.SystemAssignedIdentityRole is immutable",
   425  			oldMachine: &AzureMachine{
   426  				Spec: AzureMachineSpec{
   427  					SystemAssignedIdentityRole: &SystemAssignedIdentityRole{
   428  						Name:         "role",
   429  						Scope:        "scope",
   430  						DefinitionID: "definitionID",
   431  					},
   432  				},
   433  			},
   434  			newMachine: &AzureMachine{
   435  				Spec: AzureMachineSpec{
   436  					SystemAssignedIdentityRole: &SystemAssignedIdentityRole{
   437  						Name:         "role",
   438  						Scope:        "scope",
   439  						DefinitionID: "definitionID",
   440  					},
   441  				},
   442  			},
   443  			wantErr: false,
   444  		},
   445  		{
   446  			name: "invalidTest: azuremachine.spec.OSDisk is immutable",
   447  			oldMachine: &AzureMachine{
   448  				Spec: AzureMachineSpec{
   449  					OSDisk: OSDisk{
   450  						OSType: "osType-0",
   451  					},
   452  				},
   453  			},
   454  			newMachine: &AzureMachine{
   455  				Spec: AzureMachineSpec{
   456  					OSDisk: OSDisk{
   457  						OSType: "osType-1",
   458  					},
   459  				},
   460  			},
   461  			wantErr: true,
   462  		},
   463  		{
   464  			name: "validTest: azuremachine.spec.OSDisk is immutable",
   465  			oldMachine: &AzureMachine{
   466  				Spec: AzureMachineSpec{
   467  					OSDisk: OSDisk{
   468  						OSType: "osType-1",
   469  					},
   470  				},
   471  			},
   472  			newMachine: &AzureMachine{
   473  				Spec: AzureMachineSpec{
   474  					OSDisk: OSDisk{
   475  						OSType: "osType-1",
   476  					},
   477  				},
   478  			},
   479  			wantErr: false,
   480  		},
   481  		{
   482  			name: "invalidTest: azuremachine.spec.DataDisks is immutable",
   483  			oldMachine: &AzureMachine{
   484  				Spec: AzureMachineSpec{
   485  					DataDisks: []DataDisk{
   486  						{
   487  							DiskSizeGB: 128,
   488  						},
   489  					},
   490  				},
   491  			},
   492  			newMachine: &AzureMachine{
   493  				Spec: AzureMachineSpec{
   494  					DataDisks: []DataDisk{
   495  						{
   496  							DiskSizeGB: 64,
   497  						},
   498  					},
   499  				},
   500  			},
   501  			wantErr: true,
   502  		},
   503  		{
   504  			name: "validTest: azuremachine.spec.DataDisks is immutable",
   505  			oldMachine: &AzureMachine{
   506  				Spec: AzureMachineSpec{
   507  					DataDisks: []DataDisk{
   508  						{
   509  							DiskSizeGB: 128,
   510  						},
   511  					},
   512  				},
   513  			},
   514  			newMachine: &AzureMachine{
   515  				Spec: AzureMachineSpec{
   516  					DataDisks: []DataDisk{
   517  						{
   518  							DiskSizeGB: 128,
   519  						},
   520  					},
   521  				},
   522  			},
   523  			wantErr: false,
   524  		},
   525  		{
   526  			name: "invalidTest: azuremachine.spec.SSHPublicKey is immutable",
   527  			oldMachine: &AzureMachine{
   528  				Spec: AzureMachineSpec{
   529  					SSHPublicKey: "validKey",
   530  				},
   531  			},
   532  			newMachine: &AzureMachine{
   533  				Spec: AzureMachineSpec{
   534  					SSHPublicKey: "invalidKey",
   535  				},
   536  			},
   537  			wantErr: true,
   538  		},
   539  		{
   540  			name: "validTest: azuremachine.spec.SSHPublicKey is immutable",
   541  			oldMachine: &AzureMachine{
   542  				Spec: AzureMachineSpec{
   543  					SSHPublicKey: "validKey",
   544  				},
   545  			},
   546  			newMachine: &AzureMachine{
   547  				Spec: AzureMachineSpec{
   548  					SSHPublicKey: "validKey",
   549  				},
   550  			},
   551  			wantErr: false,
   552  		},
   553  		{
   554  			name: "invalidTest: azuremachine.spec.AllocatePublicIP is immutable",
   555  			oldMachine: &AzureMachine{
   556  				Spec: AzureMachineSpec{
   557  					AllocatePublicIP: true,
   558  				},
   559  			},
   560  			newMachine: &AzureMachine{
   561  				Spec: AzureMachineSpec{
   562  					AllocatePublicIP: false,
   563  				},
   564  			},
   565  			wantErr: true,
   566  		},
   567  		{
   568  			name: "validTest: azuremachine.spec.AllocatePublicIP is immutable",
   569  			oldMachine: &AzureMachine{
   570  				Spec: AzureMachineSpec{
   571  					AllocatePublicIP: true,
   572  				},
   573  			},
   574  			newMachine: &AzureMachine{
   575  				Spec: AzureMachineSpec{
   576  					AllocatePublicIP: true,
   577  				},
   578  			},
   579  			wantErr: false,
   580  		},
   581  		{
   582  			name: "invalidTest: azuremachine.spec.EnableIPForwarding is immutable",
   583  			oldMachine: &AzureMachine{
   584  				Spec: AzureMachineSpec{
   585  					EnableIPForwarding: true,
   586  				},
   587  			},
   588  			newMachine: &AzureMachine{
   589  				Spec: AzureMachineSpec{
   590  					EnableIPForwarding: false,
   591  				},
   592  			},
   593  			wantErr: true,
   594  		},
   595  		{
   596  			name: "validTest: azuremachine.spec.EnableIPForwarding is immutable",
   597  			oldMachine: &AzureMachine{
   598  				Spec: AzureMachineSpec{
   599  					EnableIPForwarding: true,
   600  				},
   601  			},
   602  			newMachine: &AzureMachine{
   603  				Spec: AzureMachineSpec{
   604  					EnableIPForwarding: true,
   605  				},
   606  			},
   607  			wantErr: false,
   608  		},
   609  		{
   610  			name: "invalidTest: azuremachine.spec.AcceleratedNetworking is immutable",
   611  			oldMachine: &AzureMachine{
   612  				Spec: AzureMachineSpec{
   613  					AcceleratedNetworking: ptr.To(true),
   614  				},
   615  			},
   616  			newMachine: &AzureMachine{
   617  				Spec: AzureMachineSpec{
   618  					AcceleratedNetworking: ptr.To(false),
   619  				},
   620  			},
   621  			wantErr: true,
   622  		},
   623  		{
   624  			name: "validTest: azuremachine.spec.AcceleratedNetworking is immutable",
   625  			oldMachine: &AzureMachine{
   626  				Spec: AzureMachineSpec{
   627  					AcceleratedNetworking: ptr.To(true),
   628  				},
   629  			},
   630  			newMachine: &AzureMachine{
   631  				Spec: AzureMachineSpec{
   632  					AcceleratedNetworking: ptr.To(true),
   633  				},
   634  			},
   635  			wantErr: false,
   636  		},
   637  		{
   638  			name: "validTest: azuremachine.spec.AcceleratedNetworking transition(from true) to nil is acceptable",
   639  			oldMachine: &AzureMachine{
   640  				Spec: AzureMachineSpec{
   641  					AcceleratedNetworking: ptr.To(true),
   642  				},
   643  			},
   644  			newMachine: &AzureMachine{
   645  				Spec: AzureMachineSpec{
   646  					AcceleratedNetworking: nil,
   647  				},
   648  			},
   649  			wantErr: false,
   650  		},
   651  		{
   652  			name: "validTest: azuremachine.spec.AcceleratedNetworking transition(from false) to nil is acceptable",
   653  			oldMachine: &AzureMachine{
   654  				Spec: AzureMachineSpec{
   655  					AcceleratedNetworking: ptr.To(false),
   656  				},
   657  			},
   658  			newMachine: &AzureMachine{
   659  				Spec: AzureMachineSpec{
   660  					AcceleratedNetworking: nil,
   661  				},
   662  			},
   663  			wantErr: false,
   664  		},
   665  		{
   666  			name: "invalidTest: azuremachine.spec.SpotVMOptions is immutable",
   667  			oldMachine: &AzureMachine{
   668  				Spec: AzureMachineSpec{
   669  					SpotVMOptions: &SpotVMOptions{
   670  						MaxPrice: &resource.Quantity{Format: "vmoptions-0"},
   671  					},
   672  				},
   673  			},
   674  			newMachine: &AzureMachine{
   675  				Spec: AzureMachineSpec{
   676  					SpotVMOptions: &SpotVMOptions{
   677  						MaxPrice: &resource.Quantity{Format: "vmoptions-1"},
   678  					},
   679  				},
   680  			},
   681  			wantErr: true,
   682  		},
   683  		{
   684  			name: "validTest: azuremachine.spec.SpotVMOptions is immutable",
   685  			oldMachine: &AzureMachine{
   686  				Spec: AzureMachineSpec{
   687  					SpotVMOptions: &SpotVMOptions{
   688  						MaxPrice: &resource.Quantity{Format: "vmoptions-1"},
   689  					},
   690  				},
   691  			},
   692  			newMachine: &AzureMachine{
   693  				Spec: AzureMachineSpec{
   694  					SpotVMOptions: &SpotVMOptions{
   695  						MaxPrice: &resource.Quantity{Format: "vmoptions-1"},
   696  					},
   697  				},
   698  			},
   699  			wantErr: false,
   700  		},
   701  		{
   702  			name: "invalidTest: azuremachine.spec.SecurityProfile is immutable",
   703  			oldMachine: &AzureMachine{
   704  				Spec: AzureMachineSpec{
   705  					SecurityProfile: &SecurityProfile{EncryptionAtHost: ptr.To(true)},
   706  				},
   707  			},
   708  			newMachine: &AzureMachine{
   709  				Spec: AzureMachineSpec{
   710  					SecurityProfile: &SecurityProfile{EncryptionAtHost: ptr.To(false)},
   711  				},
   712  			},
   713  			wantErr: true,
   714  		},
   715  		{
   716  			name: "validTest: azuremachine.spec.SecurityProfile is immutable",
   717  			oldMachine: &AzureMachine{
   718  				Spec: AzureMachineSpec{
   719  					SecurityProfile: &SecurityProfile{EncryptionAtHost: ptr.To(true)},
   720  				},
   721  			},
   722  			newMachine: &AzureMachine{
   723  				Spec: AzureMachineSpec{
   724  					SecurityProfile: &SecurityProfile{EncryptionAtHost: ptr.To(true)},
   725  				},
   726  			},
   727  			wantErr: false,
   728  		},
   729  		{
   730  			name: "invalidTest: azuremachine.spec.Diagnostics is immutable",
   731  			oldMachine: &AzureMachine{
   732  				Spec: AzureMachineSpec{
   733  					Diagnostics: &Diagnostics{Boot: &BootDiagnostics{StorageAccountType: DisabledDiagnosticsStorage}},
   734  				},
   735  			},
   736  			newMachine: &AzureMachine{
   737  				Spec: AzureMachineSpec{
   738  					Diagnostics: &Diagnostics{Boot: &BootDiagnostics{StorageAccountType: ManagedDiagnosticsStorage}},
   739  				},
   740  			},
   741  			wantErr: true,
   742  		},
   743  		{
   744  			name: "validTest: azuremachine.spec.Diagnostics is immutable",
   745  			oldMachine: &AzureMachine{
   746  				Spec: AzureMachineSpec{
   747  					Diagnostics: &Diagnostics{Boot: &BootDiagnostics{StorageAccountType: DisabledDiagnosticsStorage}},
   748  				},
   749  			},
   750  			newMachine: &AzureMachine{
   751  				Spec: AzureMachineSpec{
   752  					Diagnostics: &Diagnostics{Boot: &BootDiagnostics{StorageAccountType: DisabledDiagnosticsStorage}},
   753  				},
   754  			},
   755  			wantErr: false,
   756  		},
   757  		{
   758  			name: "validTest: azuremachine.spec.Diagnostics should not error on updating nil diagnostics",
   759  			oldMachine: &AzureMachine{
   760  				Spec: AzureMachineSpec{},
   761  			},
   762  			newMachine: &AzureMachine{
   763  				Spec: AzureMachineSpec{
   764  					Diagnostics: &Diagnostics{Boot: &BootDiagnostics{StorageAccountType: ManagedDiagnosticsStorage}},
   765  				},
   766  			},
   767  			wantErr: false,
   768  		},
   769  		{
   770  			name: "invalidTest: azuremachine.spec.Diagnostics is immutable",
   771  			oldMachine: &AzureMachine{
   772  				Spec: AzureMachineSpec{
   773  					Diagnostics: &Diagnostics{},
   774  				},
   775  			},
   776  			newMachine: &AzureMachine{
   777  				Spec: AzureMachineSpec{
   778  					Diagnostics: &Diagnostics{Boot: &BootDiagnostics{StorageAccountType: ManagedDiagnosticsStorage}},
   779  				},
   780  			},
   781  			wantErr: true,
   782  		},
   783  		{
   784  			name: "invalidTest: azuremachine.spec.Diagnostics is immutable",
   785  			oldMachine: &AzureMachine{
   786  				Spec: AzureMachineSpec{
   787  					Diagnostics: &Diagnostics{
   788  						Boot: &BootDiagnostics{},
   789  					},
   790  				},
   791  			},
   792  			newMachine: &AzureMachine{
   793  				Spec: AzureMachineSpec{
   794  					Diagnostics: &Diagnostics{Boot: &BootDiagnostics{StorageAccountType: ManagedDiagnosticsStorage}},
   795  				},
   796  			},
   797  			wantErr: true,
   798  		},
   799  		{
   800  			name: "invalidTest: azuremachine.spec.disableExtensionOperations is immutable",
   801  			oldMachine: &AzureMachine{
   802  				Spec: AzureMachineSpec{
   803  					DisableExtensionOperations: ptr.To(true),
   804  				},
   805  			},
   806  			newMachine: &AzureMachine{
   807  				Spec: AzureMachineSpec{
   808  					DisableExtensionOperations: ptr.To(false),
   809  				},
   810  			},
   811  			wantErr: true,
   812  		},
   813  		{
   814  			name: "validTest: azuremachine.spec.disableExtensionOperations is immutable",
   815  			oldMachine: &AzureMachine{
   816  				Spec: AzureMachineSpec{
   817  					DisableExtensionOperations: ptr.To(true),
   818  				},
   819  			},
   820  			newMachine: &AzureMachine{
   821  				Spec: AzureMachineSpec{
   822  					DisableExtensionOperations: ptr.To(true),
   823  				},
   824  			},
   825  			wantErr: false,
   826  		},
   827  		{
   828  			name: "validTest: azuremachine.spec.networkInterfaces is immutable",
   829  			oldMachine: &AzureMachine{
   830  				Spec: AzureMachineSpec{
   831  					NetworkInterfaces: []NetworkInterface{{SubnetName: "subnet"}},
   832  				},
   833  			},
   834  			newMachine: &AzureMachine{
   835  				Spec: AzureMachineSpec{
   836  					NetworkInterfaces: []NetworkInterface{{SubnetName: "subnet"}},
   837  				},
   838  			},
   839  			wantErr: false,
   840  		},
   841  		{
   842  			name: "invalidtest: azuremachine.spec.networkInterfaces is immutable",
   843  			oldMachine: &AzureMachine{
   844  				Spec: AzureMachineSpec{
   845  					NetworkInterfaces: []NetworkInterface{{SubnetName: "subnet1"}},
   846  				},
   847  			},
   848  			newMachine: &AzureMachine{
   849  				Spec: AzureMachineSpec{
   850  					NetworkInterfaces: []NetworkInterface{{SubnetName: "subnet2"}},
   851  				},
   852  			},
   853  			wantErr: true,
   854  		},
   855  		{
   856  			name: "invalidtest: updating subnet name from empty to non empty",
   857  			oldMachine: &AzureMachine{
   858  				Spec: AzureMachineSpec{
   859  					NetworkInterfaces: []NetworkInterface{{SubnetName: ""}},
   860  				},
   861  			},
   862  			newMachine: &AzureMachine{
   863  				Spec: AzureMachineSpec{
   864  					NetworkInterfaces: []NetworkInterface{{SubnetName: "subnet1"}},
   865  				},
   866  			},
   867  			wantErr: true,
   868  		},
   869  		{
   870  			name: "invalidTest: azuremachine.spec.capacityReservationGroupID is immutable",
   871  			oldMachine: &AzureMachine{
   872  				Spec: AzureMachineSpec{
   873  					CapacityReservationGroupID: ptr.To("capacityReservationGroupID-1"),
   874  				},
   875  			},
   876  			newMachine: &AzureMachine{
   877  				Spec: AzureMachineSpec{
   878  					CapacityReservationGroupID: ptr.To("capacityReservationGroupID-2"),
   879  				},
   880  			},
   881  			wantErr: true,
   882  		},
   883  		{
   884  			name: "invalidTest: updating azuremachine.spec.capacityReservationGroupID from empty to non-empty",
   885  			oldMachine: &AzureMachine{
   886  				Spec: AzureMachineSpec{
   887  					CapacityReservationGroupID: nil,
   888  				},
   889  			},
   890  			newMachine: &AzureMachine{
   891  				Spec: AzureMachineSpec{
   892  					CapacityReservationGroupID: ptr.To("capacityReservationGroupID-1"),
   893  				},
   894  			},
   895  			wantErr: true,
   896  		},
   897  		{
   898  			name: "invalidTest: updating azuremachine.spec.capacityReservationGroupID from non-empty to empty",
   899  			oldMachine: &AzureMachine{
   900  				Spec: AzureMachineSpec{
   901  					CapacityReservationGroupID: ptr.To("capacityReservationGroupID-1"),
   902  				},
   903  			},
   904  			newMachine: &AzureMachine{
   905  				Spec: AzureMachineSpec{
   906  					CapacityReservationGroupID: nil,
   907  				},
   908  			},
   909  			wantErr: true,
   910  		},
   911  		{
   912  			name: "validTest: azuremachine.spec.capacityReservationGroupID is immutable",
   913  			oldMachine: &AzureMachine{
   914  				Spec: AzureMachineSpec{
   915  					CapacityReservationGroupID: ptr.To("capacityReservationGroupID-1"),
   916  				},
   917  			},
   918  			newMachine: &AzureMachine{
   919  				Spec: AzureMachineSpec{
   920  					CapacityReservationGroupID: ptr.To("capacityReservationGroupID-1"),
   921  				},
   922  			},
   923  			wantErr: false,
   924  		},
   925  	}
   926  
   927  	for _, tc := range tests {
   928  		t.Run(tc.name, func(t *testing.T) {
   929  			g := NewWithT(t)
   930  			mw := &azureMachineWebhook{}
   931  			_, err := mw.ValidateUpdate(context.Background(), tc.oldMachine, tc.newMachine)
   932  			if tc.wantErr {
   933  				g.Expect(err).To(HaveOccurred())
   934  			} else {
   935  				g.Expect(err).NotTo(HaveOccurred())
   936  			}
   937  		})
   938  	}
   939  }
   940  
   941  type mockDefaultClient struct {
   942  	client.Client
   943  	SubscriptionID string
   944  }
   945  
   946  func (m mockDefaultClient) Get(ctx context.Context, key client.ObjectKey, obj client.Object, opts ...client.GetOption) error {
   947  	switch obj := obj.(type) {
   948  	case *AzureCluster:
   949  		obj.Spec.SubscriptionID = m.SubscriptionID
   950  	case *clusterv1.Cluster:
   951  		obj.Spec.InfrastructureRef = &corev1.ObjectReference{
   952  			Kind: AzureClusterKind,
   953  			Name: "test-cluster",
   954  		}
   955  	default:
   956  		return errors.New("invalid object type")
   957  	}
   958  	return nil
   959  }
   960  
   961  func TestAzureMachine_Default(t *testing.T) {
   962  	g := NewWithT(t)
   963  
   964  	type test struct {
   965  		machine *AzureMachine
   966  	}
   967  
   968  	testSubscriptionID := "test-subscription-id"
   969  	mockClient := mockDefaultClient{SubscriptionID: testSubscriptionID}
   970  	existingPublicKey := validSSHPublicKey
   971  	publicKeyExistTest := test{machine: createMachineWithSSHPublicKey(existingPublicKey)}
   972  	publicKeyNotExistTest := test{machine: createMachineWithSSHPublicKey("")}
   973  	testObjectMeta := metav1.ObjectMeta{
   974  		Labels: map[string]string{
   975  			clusterv1.ClusterNameLabel: "test-cluster",
   976  		},
   977  	}
   978  
   979  	mw := &azureMachineWebhook{
   980  		Client: mockClient,
   981  	}
   982  
   983  	err := mw.Default(context.Background(), publicKeyExistTest.machine)
   984  	g.Expect(err).NotTo(HaveOccurred())
   985  	g.Expect(publicKeyExistTest.machine.Spec.SSHPublicKey).To(Equal(existingPublicKey))
   986  
   987  	err = mw.Default(context.Background(), publicKeyNotExistTest.machine)
   988  	g.Expect(err).NotTo(HaveOccurred())
   989  	g.Expect(publicKeyNotExistTest.machine.Spec.SSHPublicKey).To(Not(BeEmpty()))
   990  
   991  	cacheTypeNotSpecifiedTest := test{machine: &AzureMachine{ObjectMeta: testObjectMeta, Spec: AzureMachineSpec{OSDisk: OSDisk{CachingType: ""}}}}
   992  	err = mw.Default(context.Background(), cacheTypeNotSpecifiedTest.machine)
   993  	g.Expect(err).NotTo(HaveOccurred())
   994  	g.Expect(cacheTypeNotSpecifiedTest.machine.Spec.OSDisk.CachingType).To(Equal("None"))
   995  
   996  	for _, possibleCachingType := range armcompute.PossibleCachingTypesValues() {
   997  		cacheTypeSpecifiedTest := test{machine: &AzureMachine{ObjectMeta: testObjectMeta, Spec: AzureMachineSpec{OSDisk: OSDisk{CachingType: string(possibleCachingType)}}}}
   998  		err = mw.Default(context.Background(), cacheTypeSpecifiedTest.machine)
   999  		g.Expect(err).NotTo(HaveOccurred())
  1000  		g.Expect(cacheTypeSpecifiedTest.machine.Spec.OSDisk.CachingType).To(Equal(string(possibleCachingType)))
  1001  	}
  1002  }
  1003  
  1004  func createMachineWithNetworkConfig(subnetName string, acceleratedNetworking *bool, interfaces []NetworkInterface) *AzureMachine {
  1005  	return &AzureMachine{
  1006  		Spec: AzureMachineSpec{
  1007  			SubnetName:            subnetName,
  1008  			NetworkInterfaces:     interfaces,
  1009  			AcceleratedNetworking: acceleratedNetworking,
  1010  			OSDisk:                validOSDisk,
  1011  			SSHPublicKey:          validSSHPublicKey,
  1012  		},
  1013  	}
  1014  }
  1015  
  1016  func createMachineWithSharedImage(subscriptionID, resourceGroup, name, gallery, version string) *AzureMachine {
  1017  	image := &Image{
  1018  		SharedGallery: &AzureSharedGalleryImage{
  1019  			SubscriptionID: subscriptionID,
  1020  			ResourceGroup:  resourceGroup,
  1021  			Name:           name,
  1022  			Gallery:        gallery,
  1023  			Version:        version,
  1024  		},
  1025  	}
  1026  
  1027  	return &AzureMachine{
  1028  		Spec: AzureMachineSpec{
  1029  			Image:        image,
  1030  			SSHPublicKey: validSSHPublicKey,
  1031  			OSDisk:       validOSDisk,
  1032  		},
  1033  	}
  1034  }
  1035  
  1036  func createMachineWithMarketPlaceImage(publisher, offer, sku, version string) *AzureMachine {
  1037  	image := &Image{
  1038  		Marketplace: &AzureMarketplaceImage{
  1039  			ImagePlan: ImagePlan{
  1040  				Publisher: publisher,
  1041  				Offer:     offer,
  1042  				SKU:       sku,
  1043  			},
  1044  			Version: version,
  1045  		},
  1046  	}
  1047  
  1048  	return &AzureMachine{
  1049  		Spec: AzureMachineSpec{
  1050  			Image:        image,
  1051  			SSHPublicKey: validSSHPublicKey,
  1052  			OSDisk:       validOSDisk,
  1053  		},
  1054  	}
  1055  }
  1056  
  1057  func createMachineWithImageByID(imageID string) *AzureMachine {
  1058  	image := &Image{
  1059  		ID: &imageID,
  1060  	}
  1061  
  1062  	return &AzureMachine{
  1063  		Spec: AzureMachineSpec{
  1064  			Image:        image,
  1065  			SSHPublicKey: validSSHPublicKey,
  1066  			OSDisk:       validOSDisk,
  1067  		},
  1068  	}
  1069  }
  1070  
  1071  func createMachineWithOsDiskCacheType(cacheType string) *AzureMachine {
  1072  	machine := &AzureMachine{
  1073  		Spec: AzureMachineSpec{
  1074  			SSHPublicKey: validSSHPublicKey,
  1075  			OSDisk:       validOSDisk,
  1076  		},
  1077  	}
  1078  	machine.Spec.OSDisk.CachingType = cacheType
  1079  	return machine
  1080  }
  1081  
  1082  func createMachineWithSystemAssignedIdentityRoleName() *AzureMachine {
  1083  	machine := &AzureMachine{
  1084  		Spec: AzureMachineSpec{
  1085  			SSHPublicKey: validSSHPublicKey,
  1086  			OSDisk:       validOSDisk,
  1087  			Identity:     VMIdentitySystemAssigned,
  1088  			SystemAssignedIdentityRole: &SystemAssignedIdentityRole{
  1089  				Name:         "c6e3443d-bc11-4335-8819-ab6637b10586",
  1090  				Scope:        "test-scope",
  1091  				DefinitionID: "test-definition-id",
  1092  			},
  1093  		},
  1094  	}
  1095  	return machine
  1096  }
  1097  
  1098  func createMachineWithoutSystemAssignedIdentityRoleName() *AzureMachine {
  1099  	machine := &AzureMachine{
  1100  		Spec: AzureMachineSpec{
  1101  			SSHPublicKey: validSSHPublicKey,
  1102  			OSDisk:       validOSDisk,
  1103  			Identity:     VMIdentitySystemAssigned,
  1104  			SystemAssignedIdentityRole: &SystemAssignedIdentityRole{
  1105  				Scope:        "test-scope",
  1106  				DefinitionID: "test-definition-id",
  1107  			},
  1108  		},
  1109  	}
  1110  	return machine
  1111  }
  1112  
  1113  func createMachineWithoutRoleAssignmentName() *AzureMachine {
  1114  	machine := &AzureMachine{
  1115  		Spec: AzureMachineSpec{
  1116  			SSHPublicKey: validSSHPublicKey,
  1117  			OSDisk:       validOSDisk,
  1118  		},
  1119  	}
  1120  	return machine
  1121  }
  1122  
  1123  func createMachineWithRoleAssignmentName() *AzureMachine {
  1124  	machine := &AzureMachine{
  1125  		Spec: AzureMachineSpec{
  1126  			SSHPublicKey:       validSSHPublicKey,
  1127  			OSDisk:             validOSDisk,
  1128  			RoleAssignmentName: "test-role-assignment",
  1129  		},
  1130  	}
  1131  	return machine
  1132  }
  1133  
  1134  func createMachineWithDiagnostics(diagnosticsType BootDiagnosticsStorageAccountType, userManaged *UserManagedBootDiagnostics) *AzureMachine {
  1135  	var diagnostics *Diagnostics
  1136  
  1137  	if diagnosticsType != "" {
  1138  		diagnostics = &Diagnostics{
  1139  			Boot: &BootDiagnostics{
  1140  				StorageAccountType: diagnosticsType,
  1141  			},
  1142  		}
  1143  	}
  1144  
  1145  	if userManaged != nil {
  1146  		diagnostics.Boot.UserManaged = userManaged
  1147  	}
  1148  
  1149  	return &AzureMachine{
  1150  		Spec: AzureMachineSpec{
  1151  			SSHPublicKey: validSSHPublicKey,
  1152  			OSDisk:       validOSDisk,
  1153  			Diagnostics:  diagnostics,
  1154  		},
  1155  	}
  1156  }
  1157  
  1158  func createMachineWithConfidentialCompute(securityEncryptionType SecurityEncryptionType, securityType SecurityTypes, encryptionAtHost, vTpmEnabled, secureBootEnabled bool) *AzureMachine {
  1159  	securityProfile := &SecurityProfile{
  1160  		EncryptionAtHost: &encryptionAtHost,
  1161  		SecurityType:     securityType,
  1162  		UefiSettings: &UefiSettings{
  1163  			VTpmEnabled:       &vTpmEnabled,
  1164  			SecureBootEnabled: &secureBootEnabled,
  1165  		},
  1166  	}
  1167  
  1168  	osDisk := OSDisk{
  1169  		DiskSizeGB: ptr.To[int32](30),
  1170  		OSType:     LinuxOS,
  1171  		ManagedDisk: &ManagedDiskParameters{
  1172  			StorageAccountType: "Premium_LRS",
  1173  			SecurityProfile: &VMDiskSecurityProfile{
  1174  				SecurityEncryptionType: securityEncryptionType,
  1175  			},
  1176  		},
  1177  		CachingType: string(armcompute.PossibleCachingTypesValues()[0]),
  1178  	}
  1179  
  1180  	return &AzureMachine{
  1181  		Spec: AzureMachineSpec{
  1182  			SSHPublicKey:    validSSHPublicKey,
  1183  			OSDisk:          osDisk,
  1184  			SecurityProfile: securityProfile,
  1185  		},
  1186  	}
  1187  }
  1188  
  1189  func createMachineWithCapacityReservaionGroupID(capacityReservationGroupID string) *AzureMachine {
  1190  	var strPtr *string
  1191  	if capacityReservationGroupID != "" {
  1192  		strPtr = ptr.To(capacityReservationGroupID)
  1193  	}
  1194  
  1195  	return &AzureMachine{
  1196  		Spec: AzureMachineSpec{
  1197  			SSHPublicKey:               validSSHPublicKey,
  1198  			OSDisk:                     validOSDisk,
  1199  			CapacityReservationGroupID: strPtr,
  1200  		},
  1201  	}
  1202  }
  1203  
  1204  func createMachineWithDisableExtenionOperationsAndHasExtension() *AzureMachine {
  1205  	return &AzureMachine{
  1206  		Spec: AzureMachineSpec{
  1207  			SSHPublicKey:               validSSHPublicKey,
  1208  			OSDisk:                     validOSDisk,
  1209  			DisableExtensionOperations: ptr.To(true),
  1210  			VMExtensions: []VMExtension{{
  1211  				Name:      "test-extension",
  1212  				Publisher: "test-publiher",
  1213  				Version:   "v0.0.1-test",
  1214  			}},
  1215  		},
  1216  	}
  1217  }
  1218  
  1219  func createMachineWithDisableExtenionOperations() *AzureMachine {
  1220  	return &AzureMachine{
  1221  		Spec: AzureMachineSpec{
  1222  			SSHPublicKey:               validSSHPublicKey,
  1223  			OSDisk:                     validOSDisk,
  1224  			DisableExtensionOperations: ptr.To(true),
  1225  		},
  1226  	}
  1227  }