sigs.k8s.io/cluster-api-provider-azure@v1.14.3/azure/services/virtualmachines/spec_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 virtualmachines
    18  
    19  import (
    20  	"context"
    21  	"testing"
    22  
    23  	"github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/compute/armcompute/v5"
    24  	"github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/network/armnetwork/v4"
    25  	"github.com/google/go-cmp/cmp"
    26  	. "github.com/onsi/gomega"
    27  	"k8s.io/utils/ptr"
    28  	infrav1 "sigs.k8s.io/cluster-api-provider-azure/api/v1beta1"
    29  	"sigs.k8s.io/cluster-api-provider-azure/azure"
    30  	"sigs.k8s.io/cluster-api-provider-azure/azure/services/resourceskus"
    31  	gomockinternal "sigs.k8s.io/cluster-api-provider-azure/internal/test/matchers/gomock"
    32  )
    33  
    34  var (
    35  	validSKU = resourceskus.SKU{
    36  		Name: ptr.To("Standard_D2v3"),
    37  		Kind: ptr.To(string(resourceskus.VirtualMachines)),
    38  		Locations: []*string{
    39  			ptr.To("test-location"),
    40  		},
    41  		Capabilities: []*armcompute.ResourceSKUCapabilities{
    42  			{
    43  				Name:  ptr.To(resourceskus.VCPUs),
    44  				Value: ptr.To("2"),
    45  			},
    46  			{
    47  				Name:  ptr.To(resourceskus.MemoryGB),
    48  				Value: ptr.To("4"),
    49  			},
    50  		},
    51  	}
    52  
    53  	validSKUWithEncryptionAtHost = resourceskus.SKU{
    54  		Name: ptr.To("Standard_D2v3"),
    55  		Kind: ptr.To(string(resourceskus.VirtualMachines)),
    56  		Locations: []*string{
    57  			ptr.To("test-location"),
    58  		},
    59  		Capabilities: []*armcompute.ResourceSKUCapabilities{
    60  			{
    61  				Name:  ptr.To(resourceskus.VCPUs),
    62  				Value: ptr.To("2"),
    63  			},
    64  			{
    65  				Name:  ptr.To(resourceskus.MemoryGB),
    66  				Value: ptr.To("4"),
    67  			},
    68  			{
    69  				Name:  ptr.To(resourceskus.EncryptionAtHost),
    70  				Value: ptr.To(string(resourceskus.CapabilitySupported)),
    71  			},
    72  		},
    73  	}
    74  
    75  	validSKUWithTrustedLaunchDisabled = resourceskus.SKU{
    76  		Name: ptr.To("Standard_D2v3"),
    77  		Kind: ptr.To(string(resourceskus.VirtualMachines)),
    78  		Locations: []*string{
    79  			ptr.To("test-location"),
    80  		},
    81  		Capabilities: []*armcompute.ResourceSKUCapabilities{
    82  			{
    83  				Name:  ptr.To(resourceskus.VCPUs),
    84  				Value: ptr.To("2"),
    85  			},
    86  			{
    87  				Name:  ptr.To(resourceskus.MemoryGB),
    88  				Value: ptr.To("4"),
    89  			},
    90  			{
    91  				Name:  ptr.To(resourceskus.TrustedLaunchDisabled),
    92  				Value: ptr.To(string(resourceskus.CapabilitySupported)),
    93  			},
    94  		},
    95  	}
    96  
    97  	validSKUWithConfidentialComputingType = resourceskus.SKU{
    98  		Name: ptr.To("Standard_D2v3"),
    99  		Kind: ptr.To(string(resourceskus.VirtualMachines)),
   100  		Locations: []*string{
   101  			ptr.To("test-location"),
   102  		},
   103  		Capabilities: []*armcompute.ResourceSKUCapabilities{
   104  			{
   105  				Name:  ptr.To(resourceskus.VCPUs),
   106  				Value: ptr.To("2"),
   107  			},
   108  			{
   109  				Name:  ptr.To(resourceskus.MemoryGB),
   110  				Value: ptr.To("4"),
   111  			},
   112  			{
   113  				Name:  ptr.To(resourceskus.ConfidentialComputingType),
   114  				Value: ptr.To(string(resourceskus.CapabilitySupported)),
   115  			},
   116  		},
   117  	}
   118  
   119  	validSKUWithEphemeralOS = resourceskus.SKU{
   120  		Name: ptr.To("Standard_D2v3"),
   121  		Kind: ptr.To(string(resourceskus.VirtualMachines)),
   122  		Locations: []*string{
   123  			ptr.To("test-location"),
   124  		},
   125  		Capabilities: []*armcompute.ResourceSKUCapabilities{
   126  			{
   127  				Name:  ptr.To(resourceskus.VCPUs),
   128  				Value: ptr.To("2"),
   129  			},
   130  			{
   131  				Name:  ptr.To(resourceskus.MemoryGB),
   132  				Value: ptr.To("4"),
   133  			},
   134  			{
   135  				Name:  ptr.To(resourceskus.EphemeralOSDisk),
   136  				Value: ptr.To("True"),
   137  			},
   138  		},
   139  	}
   140  
   141  	validSKUWithUltraSSD = resourceskus.SKU{
   142  		Name: ptr.To("Standard_D2v3"),
   143  		Kind: ptr.To(string(resourceskus.VirtualMachines)),
   144  		Locations: []*string{
   145  			ptr.To("test-location"),
   146  		},
   147  		LocationInfo: []*armcompute.ResourceSKULocationInfo{
   148  			{
   149  				Location: ptr.To("test-location"),
   150  				Zones:    []*string{ptr.To("1")},
   151  				ZoneDetails: []*armcompute.ResourceSKUZoneDetails{
   152  					{
   153  						Capabilities: []*armcompute.ResourceSKUCapabilities{
   154  							{
   155  								Name:  ptr.To("UltraSSDAvailable"),
   156  								Value: ptr.To("True"),
   157  							},
   158  						},
   159  						Name: []*string{ptr.To("1")},
   160  					},
   161  				},
   162  			},
   163  		},
   164  		Capabilities: []*armcompute.ResourceSKUCapabilities{
   165  			{
   166  				Name:  ptr.To(resourceskus.VCPUs),
   167  				Value: ptr.To("2"),
   168  			},
   169  			{
   170  				Name:  ptr.To(resourceskus.MemoryGB),
   171  				Value: ptr.To("4"),
   172  			},
   173  		},
   174  	}
   175  
   176  	invalidCPUSKU = resourceskus.SKU{
   177  		Name: ptr.To("Standard_D2v3"),
   178  		Kind: ptr.To(string(resourceskus.VirtualMachines)),
   179  		Locations: []*string{
   180  			ptr.To("test-location"),
   181  		},
   182  		Capabilities: []*armcompute.ResourceSKUCapabilities{
   183  			{
   184  				Name:  ptr.To(resourceskus.VCPUs),
   185  				Value: ptr.To("1"),
   186  			},
   187  			{
   188  				Name:  ptr.To(resourceskus.MemoryGB),
   189  				Value: ptr.To("4"),
   190  			},
   191  		},
   192  	}
   193  
   194  	invalidMemSKU = resourceskus.SKU{
   195  		Name: ptr.To("Standard_D2v3"),
   196  		Kind: ptr.To(string(resourceskus.VirtualMachines)),
   197  		Locations: []*string{
   198  			ptr.To("test-location"),
   199  		},
   200  		Capabilities: []*armcompute.ResourceSKUCapabilities{
   201  			{
   202  				Name:  ptr.To(resourceskus.VCPUs),
   203  				Value: ptr.To("2"),
   204  			},
   205  			{
   206  				Name:  ptr.To(resourceskus.MemoryGB),
   207  				Value: ptr.To("1"),
   208  			},
   209  		},
   210  	}
   211  
   212  	deletePolicy = infrav1.SpotEvictionPolicyDelete
   213  )
   214  
   215  func TestParameters(t *testing.T) {
   216  	testcases := []struct {
   217  		name          string
   218  		spec          *VMSpec
   219  		existing      interface{}
   220  		expect        func(g *WithT, result interface{})
   221  		expectedError string
   222  	}{
   223  		{
   224  			name:     "fails if existing is not a VirtualMachine",
   225  			spec:     &VMSpec{},
   226  			existing: armnetwork.VirtualNetwork{},
   227  			expect: func(g *WithT, result interface{}) {
   228  				g.Expect(result).To(BeNil())
   229  			},
   230  			expectedError: "armnetwork.VirtualNetwork is not an armcompute.VirtualMachine",
   231  		},
   232  		{
   233  			name:     "returns nil if vm already exists",
   234  			spec:     &VMSpec{},
   235  			existing: armcompute.VirtualMachine{},
   236  			expect: func(g *WithT, result interface{}) {
   237  				g.Expect(result).To(BeNil())
   238  			},
   239  			expectedError: "",
   240  		},
   241  		{
   242  			name: "fails if vm deleted out of band, should not recreate",
   243  			spec: &VMSpec{
   244  				ProviderID: "fake/vm/id",
   245  			},
   246  			existing: nil,
   247  			expect: func(g *WithT, result interface{}) {
   248  				g.Expect(result).To(BeNil())
   249  			},
   250  			expectedError: azure.VMDeletedError{ProviderID: "fake/vm/id"}.Error(),
   251  		},
   252  		{
   253  			name: "can create a vm with system assigned identity ",
   254  			spec: &VMSpec{
   255  				Name:       "my-vm",
   256  				Role:       infrav1.Node,
   257  				NICIDs:     []string{"my-nic"},
   258  				SSHKeyData: "fakesshpublickey",
   259  				Size:       "Standard_D2v3",
   260  				Zone:       "1",
   261  				Image:      &infrav1.Image{ID: ptr.To("fake-image-id")},
   262  				Identity:   infrav1.VMIdentitySystemAssigned,
   263  				SKU:        validSKU,
   264  			},
   265  			existing: nil,
   266  			expect: func(g *WithT, result interface{}) {
   267  				g.Expect(result).To(BeAssignableToTypeOf(armcompute.VirtualMachine{}))
   268  				g.Expect(result.(armcompute.VirtualMachine).Identity.Type).To(Equal(ptr.To(armcompute.ResourceIdentityTypeSystemAssigned)))
   269  				g.Expect(result.(armcompute.VirtualMachine).Identity.UserAssignedIdentities).To(BeEmpty())
   270  			},
   271  			expectedError: "",
   272  		},
   273  		{
   274  			name: "can create a vm with user assigned identity ",
   275  			spec: &VMSpec{
   276  				Name:                   "my-vm",
   277  				Role:                   infrav1.Node,
   278  				NICIDs:                 []string{"my-nic"},
   279  				SSHKeyData:             "fakesshpublickey",
   280  				Size:                   "Standard_D2v3",
   281  				Zone:                   "1",
   282  				Image:                  &infrav1.Image{ID: ptr.To("fake-image-id")},
   283  				Identity:               infrav1.VMIdentityUserAssigned,
   284  				UserAssignedIdentities: []infrav1.UserAssignedIdentity{{ProviderID: "my-user-id"}},
   285  				SKU:                    validSKU,
   286  			},
   287  			existing: nil,
   288  			expect: func(g *WithT, result interface{}) {
   289  				g.Expect(result).To(BeAssignableToTypeOf(armcompute.VirtualMachine{}))
   290  				g.Expect(result.(armcompute.VirtualMachine).Identity.Type).To(Equal(ptr.To(armcompute.ResourceIdentityTypeUserAssigned)))
   291  				g.Expect(result.(armcompute.VirtualMachine).Identity.UserAssignedIdentities).To(Equal(map[string]*armcompute.UserAssignedIdentitiesValue{"my-user-id": {}}))
   292  			},
   293  			expectedError: "",
   294  		},
   295  		{
   296  			name: "can create a spot vm",
   297  			spec: &VMSpec{
   298  				Name:          "my-vm",
   299  				Role:          infrav1.Node,
   300  				NICIDs:        []string{"my-nic"},
   301  				SSHKeyData:    "fakesshpublickey",
   302  				Size:          "Standard_D2v3",
   303  				Zone:          "1",
   304  				Image:         &infrav1.Image{ID: ptr.To("fake-image-id")},
   305  				SpotVMOptions: &infrav1.SpotVMOptions{},
   306  				SKU:           validSKU,
   307  			},
   308  			existing: nil,
   309  			expect: func(g *WithT, result interface{}) {
   310  				g.Expect(result).To(BeAssignableToTypeOf(armcompute.VirtualMachine{}))
   311  				g.Expect(result.(armcompute.VirtualMachine).Properties.Priority).To(Equal(ptr.To(armcompute.VirtualMachinePriorityTypesSpot)))
   312  				g.Expect(result.(armcompute.VirtualMachine).Properties.BillingProfile).To(BeNil())
   313  			},
   314  			expectedError: "",
   315  		},
   316  
   317  		{
   318  			name: "can create a spot vm with evictionPolicy delete",
   319  			spec: &VMSpec{
   320  				Name:          "my-vm",
   321  				Role:          infrav1.Node,
   322  				NICIDs:        []string{"my-nic"},
   323  				SSHKeyData:    "fakesshpublickey",
   324  				Size:          "Standard_D2v3",
   325  				Zone:          "1",
   326  				Image:         &infrav1.Image{ID: ptr.To("fake-image-id")},
   327  				SpotVMOptions: &infrav1.SpotVMOptions{EvictionPolicy: &deletePolicy},
   328  				SKU:           validSKU,
   329  			},
   330  			existing: nil,
   331  			expect: func(g *WithT, result interface{}) {
   332  				g.Expect(result).To(BeAssignableToTypeOf(armcompute.VirtualMachine{}))
   333  				g.Expect(result.(armcompute.VirtualMachine).Properties.Priority).To(Equal(ptr.To(armcompute.VirtualMachinePriorityTypesSpot)))
   334  				g.Expect(result.(armcompute.VirtualMachine).Properties.EvictionPolicy).To(Equal(ptr.To(armcompute.VirtualMachineEvictionPolicyTypesDelete)))
   335  				g.Expect(result.(armcompute.VirtualMachine).Properties.BillingProfile).To(BeNil())
   336  			},
   337  			expectedError: "",
   338  		},
   339  		{
   340  			name: "can create a windows vm",
   341  			spec: &VMSpec{
   342  				Name:       "my-vm",
   343  				Role:       infrav1.Node,
   344  				NICIDs:     []string{"my-nic"},
   345  				SSHKeyData: "fakesshpublickey",
   346  				Size:       "Standard_D2v3",
   347  				Zone:       "1",
   348  				Image:      &infrav1.Image{ID: ptr.To("fake-image-id")},
   349  				OSDisk: infrav1.OSDisk{
   350  					OSType:     "Windows",
   351  					DiskSizeGB: ptr.To[int32](128),
   352  					ManagedDisk: &infrav1.ManagedDiskParameters{
   353  						StorageAccountType: string(armcompute.StorageAccountTypesPremiumLRS),
   354  					},
   355  				},
   356  				SKU: validSKU,
   357  			},
   358  			existing: nil,
   359  			expect: func(g *WithT, result interface{}) {
   360  				g.Expect(result).To(BeAssignableToTypeOf(armcompute.VirtualMachine{}))
   361  				g.Expect(result.(armcompute.VirtualMachine).Properties.StorageProfile.OSDisk.OSType).To(Equal(ptr.To(armcompute.OperatingSystemTypesWindows)))
   362  				g.Expect(*result.(armcompute.VirtualMachine).Properties.OSProfile.AdminPassword).Should(HaveLen(123))
   363  				g.Expect(*result.(armcompute.VirtualMachine).Properties.OSProfile.AdminUsername).Should(Equal("capi"))
   364  				g.Expect(*result.(armcompute.VirtualMachine).Properties.OSProfile.WindowsConfiguration.EnableAutomaticUpdates).Should(BeFalse())
   365  			},
   366  			expectedError: "",
   367  		},
   368  		{
   369  			name: "can create a vm with encryption",
   370  			spec: &VMSpec{
   371  				Name:       "my-vm",
   372  				Role:       infrav1.Node,
   373  				NICIDs:     []string{"my-nic"},
   374  				SSHKeyData: "fakesshpublickey",
   375  				Size:       "Standard_D2v3",
   376  				Zone:       "1",
   377  				Image:      &infrav1.Image{ID: ptr.To("fake-image-id")},
   378  				OSDisk: infrav1.OSDisk{
   379  					ManagedDisk: &infrav1.ManagedDiskParameters{
   380  						StorageAccountType: string(armcompute.StorageAccountTypesPremiumLRS),
   381  						DiskEncryptionSet: &infrav1.DiskEncryptionSetParameters{
   382  							ID: "my-diskencryptionset-id",
   383  						},
   384  					},
   385  				},
   386  				SKU: validSKU,
   387  			},
   388  			existing: nil,
   389  			expect: func(g *WithT, result interface{}) {
   390  				g.Expect(result).To(BeAssignableToTypeOf(armcompute.VirtualMachine{}))
   391  				g.Expect(result.(armcompute.VirtualMachine).Properties.StorageProfile.OSDisk.ManagedDisk.DiskEncryptionSet.ID).To(Equal(ptr.To("my-diskencryptionset-id")))
   392  			},
   393  			expectedError: "",
   394  		},
   395  		{
   396  			name: "can create a vm with encryption at host",
   397  			spec: &VMSpec{
   398  				Name:            "my-vm",
   399  				Role:            infrav1.Node,
   400  				NICIDs:          []string{"my-nic"},
   401  				SSHKeyData:      "fakesshpublickey",
   402  				Size:            "Standard_D2v3",
   403  				Zone:            "1",
   404  				Image:           &infrav1.Image{ID: ptr.To("fake-image-id")},
   405  				SecurityProfile: &infrav1.SecurityProfile{EncryptionAtHost: ptr.To(true)},
   406  				SKU:             validSKUWithEncryptionAtHost,
   407  			},
   408  			existing: nil,
   409  			expect: func(g *WithT, result interface{}) {
   410  				g.Expect(result).To(BeAssignableToTypeOf(armcompute.VirtualMachine{}))
   411  				g.Expect(*result.(armcompute.VirtualMachine).Properties.SecurityProfile.EncryptionAtHost).To(BeTrue())
   412  			},
   413  			expectedError: "",
   414  		},
   415  		{
   416  			name: "can create a vm and assign it to an availability set",
   417  			spec: &VMSpec{
   418  				Name:              "my-vm",
   419  				Role:              infrav1.Node,
   420  				NICIDs:            []string{"my-nic"},
   421  				SSHKeyData:        "fakesshpublickey",
   422  				Size:              "Standard_D2v3",
   423  				AvailabilitySetID: "fake-availability-set-id",
   424  				Zone:              "",
   425  				Image:             &infrav1.Image{ID: ptr.To("fake-image-id")},
   426  				SKU:               validSKU,
   427  			},
   428  			existing: nil,
   429  			expect: func(g *WithT, result interface{}) {
   430  				g.Expect(result).To(BeAssignableToTypeOf(armcompute.VirtualMachine{}))
   431  				g.Expect(result.(armcompute.VirtualMachine).Zones).To(BeNil())
   432  				g.Expect(result.(armcompute.VirtualMachine).Properties.AvailabilitySet.ID).To(Equal(ptr.To("fake-availability-set-id")))
   433  			},
   434  			expectedError: "",
   435  		},
   436  		{
   437  			name: "can create a vm with EphemeralOSDisk",
   438  			spec: &VMSpec{
   439  				Name:       "my-vm",
   440  				Role:       infrav1.Node,
   441  				NICIDs:     []string{"my-nic"},
   442  				SSHKeyData: "fakesshpublickey",
   443  				Size:       "Standard_D2v3",
   444  				OSDisk: infrav1.OSDisk{
   445  					OSType:     "Linux",
   446  					DiskSizeGB: ptr.To[int32](128),
   447  					ManagedDisk: &infrav1.ManagedDiskParameters{
   448  						StorageAccountType: string(armcompute.StorageAccountTypesPremiumLRS),
   449  					},
   450  					DiffDiskSettings: &infrav1.DiffDiskSettings{
   451  						Option: string(armcompute.DiffDiskOptionsLocal),
   452  					},
   453  				},
   454  				Image: &infrav1.Image{ID: ptr.To("fake-image-id")},
   455  				SKU:   validSKUWithEphemeralOS,
   456  			},
   457  			existing: nil,
   458  			expect: func(g *WithT, result interface{}) {
   459  				g.Expect(result).To(BeAssignableToTypeOf(armcompute.VirtualMachine{}))
   460  				g.Expect(result.(armcompute.VirtualMachine).Properties.StorageProfile.OSDisk.DiffDiskSettings.Option).To(Equal(ptr.To(armcompute.DiffDiskOptionsLocal)))
   461  			},
   462  			expectedError: "",
   463  		},
   464  		{
   465  			name: "can create a trusted launch vm",
   466  			spec: &VMSpec{
   467  				Name:              "my-vm",
   468  				Role:              infrav1.Node,
   469  				NICIDs:            []string{"my-nic"},
   470  				SSHKeyData:        "fakesshpublickey",
   471  				Size:              "Standard_D2v3",
   472  				AvailabilitySetID: "fake-availability-set-id",
   473  				Zone:              "",
   474  				Image:             &infrav1.Image{ID: ptr.To("fake-image-id")},
   475  				SecurityProfile: &infrav1.SecurityProfile{
   476  					SecurityType: infrav1.SecurityTypesTrustedLaunch,
   477  					UefiSettings: &infrav1.UefiSettings{
   478  						SecureBootEnabled: ptr.To(true),
   479  						VTpmEnabled:       ptr.To(true),
   480  					},
   481  				},
   482  				SKU: validSKU,
   483  			},
   484  			existing: nil,
   485  			expect: func(g *WithT, result interface{}) {
   486  				g.Expect(result).To(BeAssignableToTypeOf(armcompute.VirtualMachine{}))
   487  				g.Expect(*result.(armcompute.VirtualMachine).Properties.SecurityProfile.UefiSettings.SecureBootEnabled).To(BeTrue())
   488  				g.Expect(*result.(armcompute.VirtualMachine).Properties.SecurityProfile.UefiSettings.VTpmEnabled).To(BeTrue())
   489  			},
   490  			expectedError: "",
   491  		},
   492  		{
   493  			name: "can create a confidential vm",
   494  			spec: &VMSpec{
   495  				Name:              "my-vm",
   496  				Role:              infrav1.Node,
   497  				NICIDs:            []string{"my-nic"},
   498  				SSHKeyData:        "fakesshpublickey",
   499  				Size:              "Standard_D2v3",
   500  				AvailabilitySetID: "fake-availability-set-id",
   501  				Zone:              "",
   502  				Image:             &infrav1.Image{ID: ptr.To("fake-image-id")},
   503  				OSDisk: infrav1.OSDisk{
   504  					OSType:     "Linux",
   505  					DiskSizeGB: ptr.To[int32](128),
   506  					ManagedDisk: &infrav1.ManagedDiskParameters{
   507  						StorageAccountType: string(armcompute.StorageAccountTypesPremiumLRS),
   508  						SecurityProfile: &infrav1.VMDiskSecurityProfile{
   509  							SecurityEncryptionType: infrav1.SecurityEncryptionTypeVMGuestStateOnly,
   510  						},
   511  					},
   512  				},
   513  				SecurityProfile: &infrav1.SecurityProfile{
   514  					SecurityType: infrav1.SecurityTypesConfidentialVM,
   515  					UefiSettings: &infrav1.UefiSettings{
   516  						SecureBootEnabled: ptr.To(false),
   517  						VTpmEnabled:       ptr.To(true),
   518  					},
   519  				},
   520  				SKU: validSKUWithConfidentialComputingType,
   521  			},
   522  			existing: nil,
   523  			expect: func(g *WithT, result interface{}) {
   524  				g.Expect(result).To(BeAssignableToTypeOf(armcompute.VirtualMachine{}))
   525  				g.Expect(result.(armcompute.VirtualMachine).Properties.StorageProfile.OSDisk.ManagedDisk.SecurityProfile.SecurityEncryptionType).To(Equal(ptr.To(armcompute.SecurityEncryptionTypesVMGuestStateOnly)))
   526  				g.Expect(*result.(armcompute.VirtualMachine).Properties.SecurityProfile.UefiSettings.VTpmEnabled).To(BeTrue())
   527  			},
   528  			expectedError: "",
   529  		},
   530  		{
   531  			name: "creating a confidential vm without the SecurityType set to ConfidentialVM fails",
   532  			spec: &VMSpec{
   533  				Name:              "my-vm",
   534  				Role:              infrav1.Node,
   535  				NICIDs:            []string{"my-nic"},
   536  				SSHKeyData:        "fakesshpublickey",
   537  				Size:              "Standard_D2v3",
   538  				AvailabilitySetID: "fake-availability-set-id",
   539  				Zone:              "",
   540  				Image:             &infrav1.Image{ID: ptr.To("fake-image-id")},
   541  				OSDisk: infrav1.OSDisk{
   542  					OSType:     "Linux",
   543  					DiskSizeGB: ptr.To[int32](128),
   544  					ManagedDisk: &infrav1.ManagedDiskParameters{
   545  						StorageAccountType: string(armcompute.StorageAccountTypesPremiumLRS),
   546  						SecurityProfile: &infrav1.VMDiskSecurityProfile{
   547  							SecurityEncryptionType: infrav1.SecurityEncryptionTypeVMGuestStateOnly,
   548  						},
   549  					},
   550  				},
   551  				SecurityProfile: &infrav1.SecurityProfile{
   552  					SecurityType: "",
   553  					UefiSettings: &infrav1.UefiSettings{
   554  						SecureBootEnabled: ptr.To(false),
   555  						VTpmEnabled:       ptr.To(true),
   556  					},
   557  				},
   558  				SKU: validSKUWithConfidentialComputingType,
   559  			},
   560  			existing: nil,
   561  			expect: func(g *WithT, result interface{}) {
   562  				g.Expect(result).To(BeNil())
   563  			},
   564  			expectedError: "reconcile error that cannot be recovered occurred: securityType should be set to ConfidentialVM when securityEncryptionType is set. Object will not be requeued",
   565  		},
   566  		{
   567  			name: "creating a vm with encryption at host enabled for unsupported VM type fails",
   568  			spec: &VMSpec{
   569  				Name:              "my-vm",
   570  				Role:              infrav1.Node,
   571  				NICIDs:            []string{"my-nic"},
   572  				SSHKeyData:        "fakesshpublickey",
   573  				Size:              "Standard_D2v3",
   574  				AvailabilitySetID: "fake-availability-set-id",
   575  				Zone:              "",
   576  				Image:             &infrav1.Image{ID: ptr.To("fake-image-id")},
   577  				SecurityProfile:   &infrav1.SecurityProfile{EncryptionAtHost: ptr.To(true)},
   578  				SKU:               validSKU,
   579  			},
   580  			existing: nil,
   581  			expect: func(g *WithT, result interface{}) {
   582  				g.Expect(result).To(BeNil())
   583  			},
   584  			expectedError: "reconcile error that cannot be recovered occurred: encryption at host is not supported for VM type Standard_D2v3. Object will not be requeued",
   585  		},
   586  		{
   587  			name: "creating a trusted launch vm without the SecurityType set to TrustedLaunch fails",
   588  			spec: &VMSpec{
   589  				Name:              "my-vm",
   590  				Role:              infrav1.Node,
   591  				NICIDs:            []string{"my-nic"},
   592  				SSHKeyData:        "fakesshpublickey",
   593  				Size:              "Standard_D2v3",
   594  				AvailabilitySetID: "fake-availability-set-id",
   595  				Zone:              "",
   596  				Image:             &infrav1.Image{ID: ptr.To("fake-image-id")},
   597  				OSDisk: infrav1.OSDisk{
   598  					OSType:     "Linux",
   599  					DiskSizeGB: ptr.To[int32](128),
   600  					ManagedDisk: &infrav1.ManagedDiskParameters{
   601  						StorageAccountType: string(armcompute.StorageAccountTypesPremiumLRS),
   602  					},
   603  				},
   604  				SecurityProfile: &infrav1.SecurityProfile{
   605  					SecurityType: "",
   606  					UefiSettings: &infrav1.UefiSettings{
   607  						SecureBootEnabled: ptr.To(false),
   608  						VTpmEnabled:       ptr.To(true),
   609  					},
   610  				},
   611  				SKU: validSKUWithConfidentialComputingType,
   612  			},
   613  			existing: nil,
   614  			expect: func(g *WithT, result interface{}) {
   615  				g.Expect(result).To(BeNil())
   616  			},
   617  			expectedError: "reconcile error that cannot be recovered occurred: securityType should be set to TrustedLaunch when vTpmEnabled is true. Object will not be requeued",
   618  		},
   619  		{
   620  			name: "creating a trusted launch vm with secure boot enabled on unsupported VM type fails",
   621  			spec: &VMSpec{
   622  				Name:              "my-vm",
   623  				Role:              infrav1.Node,
   624  				NICIDs:            []string{"my-nic"},
   625  				SSHKeyData:        "fakesshpublickey",
   626  				Size:              "Standard_D2v3",
   627  				AvailabilitySetID: "fake-availability-set-id",
   628  				Zone:              "",
   629  				Image:             &infrav1.Image{ID: ptr.To("fake-image-id")},
   630  				SecurityProfile: &infrav1.SecurityProfile{
   631  					SecurityType: infrav1.SecurityTypesTrustedLaunch,
   632  					UefiSettings: &infrav1.UefiSettings{
   633  						SecureBootEnabled: ptr.To(true),
   634  					},
   635  				},
   636  				SKU: validSKUWithTrustedLaunchDisabled,
   637  			},
   638  			existing: nil,
   639  			expect: func(g *WithT, result interface{}) {
   640  				g.Expect(result).To(BeNil())
   641  			},
   642  			expectedError: "reconcile error that cannot be recovered occurred: secure boot is not supported for VM type Standard_D2v3. Object will not be requeued",
   643  		},
   644  		{
   645  			name: "creating a trusted launch vm with vTPM enabled on unsupported VM type fails",
   646  			spec: &VMSpec{
   647  				Name:              "my-vm",
   648  				Role:              infrav1.Node,
   649  				NICIDs:            []string{"my-nic"},
   650  				SSHKeyData:        "fakesshpublickey",
   651  				Size:              "Standard_D2v3",
   652  				AvailabilitySetID: "fake-availability-set-id",
   653  				Zone:              "",
   654  				Image:             &infrav1.Image{ID: ptr.To("fake-image-id")},
   655  				SecurityProfile: &infrav1.SecurityProfile{
   656  					SecurityType: infrav1.SecurityTypesTrustedLaunch,
   657  					UefiSettings: &infrav1.UefiSettings{
   658  						VTpmEnabled: ptr.To(true),
   659  					},
   660  				},
   661  				SKU: validSKUWithTrustedLaunchDisabled,
   662  			},
   663  			existing: nil,
   664  			expect: func(g *WithT, result interface{}) {
   665  				g.Expect(result).To(BeNil())
   666  			},
   667  			expectedError: "reconcile error that cannot be recovered occurred: vTPM is not supported for VM type Standard_D2v3. Object will not be requeued",
   668  		},
   669  		{
   670  			name: "creating a confidential vm with securityTypeEncryption DiskWithVMGuestState and encryption at host enabled fails",
   671  			spec: &VMSpec{
   672  				Name:              "my-vm",
   673  				Role:              infrav1.Node,
   674  				NICIDs:            []string{"my-nic"},
   675  				SSHKeyData:        "fakesshpublickey",
   676  				Size:              "Standard_D2v3",
   677  				AvailabilitySetID: "fake-availability-set-id",
   678  				Zone:              "",
   679  				Image:             &infrav1.Image{ID: ptr.To("fake-image-id")},
   680  				OSDisk: infrav1.OSDisk{
   681  					OSType:     "Linux",
   682  					DiskSizeGB: ptr.To[int32](128),
   683  					ManagedDisk: &infrav1.ManagedDiskParameters{
   684  						StorageAccountType: string(armcompute.StorageAccountTypesPremiumLRS),
   685  						SecurityProfile: &infrav1.VMDiskSecurityProfile{
   686  							SecurityEncryptionType: infrav1.SecurityEncryptionTypeDiskWithVMGuestState,
   687  						},
   688  					},
   689  				},
   690  				SecurityProfile: &infrav1.SecurityProfile{
   691  					EncryptionAtHost: ptr.To(true),
   692  					SecurityType:     infrav1.SecurityTypesConfidentialVM,
   693  					UefiSettings: &infrav1.UefiSettings{
   694  						VTpmEnabled: ptr.To(true),
   695  					},
   696  				},
   697  				SKU: validSKUWithConfidentialComputingType,
   698  			},
   699  			existing: nil,
   700  			expect: func(g *WithT, result interface{}) {
   701  				g.Expect(result).To(BeNil())
   702  			},
   703  			expectedError: "reconcile error that cannot be recovered occurred: encryption at host is not supported when securityEncryptionType is set to DiskWithVMGuestState. Object will not be requeued",
   704  		},
   705  		{
   706  			name: "creating a confidential vm with DiskWithVMGuestState encryption type and secure boot disabled fails",
   707  			spec: &VMSpec{
   708  				Name:              "my-vm",
   709  				Role:              infrav1.Node,
   710  				NICIDs:            []string{"my-nic"},
   711  				SSHKeyData:        "fakesshpublickey",
   712  				Size:              "Standard_D2v3",
   713  				AvailabilitySetID: "fake-availability-set-id",
   714  				Zone:              "",
   715  				Image:             &infrav1.Image{ID: ptr.To("fake-image-id")},
   716  				OSDisk: infrav1.OSDisk{
   717  					OSType:     "Linux",
   718  					DiskSizeGB: ptr.To[int32](128),
   719  					ManagedDisk: &infrav1.ManagedDiskParameters{
   720  						StorageAccountType: string(armcompute.StorageAccountTypesPremiumLRS),
   721  						SecurityProfile: &infrav1.VMDiskSecurityProfile{
   722  							SecurityEncryptionType: infrav1.SecurityEncryptionTypeDiskWithVMGuestState,
   723  						},
   724  					},
   725  				},
   726  				SecurityProfile: &infrav1.SecurityProfile{
   727  					SecurityType: infrav1.SecurityTypesConfidentialVM,
   728  					UefiSettings: &infrav1.UefiSettings{
   729  						SecureBootEnabled: ptr.To(false),
   730  						VTpmEnabled:       ptr.To(true),
   731  					},
   732  				},
   733  				SKU: validSKUWithConfidentialComputingType,
   734  			},
   735  			existing: nil,
   736  			expect: func(g *WithT, result interface{}) {
   737  				g.Expect(result).To(BeNil())
   738  			},
   739  			expectedError: "reconcile error that cannot be recovered occurred: secureBootEnabled should be true when securityEncryptionType is set to DiskWithVMGuestState. Object will not be requeued",
   740  		},
   741  		{
   742  			name: "creating a confidential vm with vTPM disabled fails",
   743  			spec: &VMSpec{
   744  				Name:              "my-vm",
   745  				Role:              infrav1.Node,
   746  				NICIDs:            []string{"my-nic"},
   747  				SSHKeyData:        "fakesshpublickey",
   748  				Size:              "Standard_D2v3",
   749  				AvailabilitySetID: "fake-availability-set-id",
   750  				Zone:              "",
   751  				Image:             &infrav1.Image{ID: ptr.To("fake-image-id")},
   752  				OSDisk: infrav1.OSDisk{
   753  					OSType:     "Linux",
   754  					DiskSizeGB: ptr.To[int32](128),
   755  					ManagedDisk: &infrav1.ManagedDiskParameters{
   756  						StorageAccountType: string(armcompute.StorageAccountTypesPremiumLRS),
   757  						SecurityProfile: &infrav1.VMDiskSecurityProfile{
   758  							SecurityEncryptionType: infrav1.SecurityEncryptionTypeVMGuestStateOnly,
   759  						},
   760  					},
   761  				},
   762  				SecurityProfile: &infrav1.SecurityProfile{
   763  					SecurityType: infrav1.SecurityTypesConfidentialVM,
   764  					UefiSettings: &infrav1.UefiSettings{
   765  						VTpmEnabled: ptr.To(false),
   766  					},
   767  				},
   768  				SKU: validSKUWithConfidentialComputingType,
   769  			},
   770  			existing: nil,
   771  			expect: func(g *WithT, result interface{}) {
   772  				g.Expect(result).To(BeNil())
   773  			},
   774  			expectedError: "reconcile error that cannot be recovered occurred: vTpmEnabled should be true when securityEncryptionType is set. Object will not be requeued",
   775  		},
   776  		{
   777  			name: "creating a confidential vm with unsupported VM type fails",
   778  			spec: &VMSpec{
   779  				Name:              "my-vm",
   780  				Role:              infrav1.Node,
   781  				NICIDs:            []string{"my-nic"},
   782  				SSHKeyData:        "fakesshpublickey",
   783  				Size:              "Standard_D2v3",
   784  				AvailabilitySetID: "fake-availability-set-id",
   785  				Zone:              "",
   786  				Image:             &infrav1.Image{ID: ptr.To("fake-image-id")},
   787  				OSDisk: infrav1.OSDisk{
   788  					OSType:     "Linux",
   789  					DiskSizeGB: ptr.To[int32](128),
   790  					ManagedDisk: &infrav1.ManagedDiskParameters{
   791  						StorageAccountType: string(armcompute.StorageAccountTypesPremiumLRS),
   792  						SecurityProfile: &infrav1.VMDiskSecurityProfile{
   793  							SecurityEncryptionType: infrav1.SecurityEncryptionTypeVMGuestStateOnly,
   794  						},
   795  					},
   796  				},
   797  				SecurityProfile: &infrav1.SecurityProfile{
   798  					SecurityType: infrav1.SecurityTypesConfidentialVM,
   799  					UefiSettings: &infrav1.UefiSettings{
   800  						VTpmEnabled: ptr.To(true),
   801  					},
   802  				},
   803  				SKU: validSKU,
   804  			},
   805  			existing: nil,
   806  			expect: func(g *WithT, result interface{}) {
   807  				g.Expect(result).To(BeNil())
   808  			},
   809  			expectedError: "reconcile error that cannot be recovered occurred: VM size Standard_D2v3 does not support confidential computing. Select a different VM size or remove the security profile of the OS disk. Object will not be requeued",
   810  		},
   811  		{
   812  			name: "cannot create vm with EphemeralOSDisk if does not support ephemeral os",
   813  			spec: &VMSpec{
   814  				Name:       "my-vm",
   815  				Role:       infrav1.Node,
   816  				NICIDs:     []string{"my-nic"},
   817  				SSHKeyData: "fakesshpublickey",
   818  				Size:       "Standard_D2v3",
   819  				OSDisk: infrav1.OSDisk{
   820  					OSType:     "Linux",
   821  					DiskSizeGB: ptr.To[int32](128),
   822  					ManagedDisk: &infrav1.ManagedDiskParameters{
   823  						StorageAccountType: string(armcompute.StorageAccountTypesPremiumLRS),
   824  					},
   825  					DiffDiskSettings: &infrav1.DiffDiskSettings{
   826  						Option: string(armcompute.DiffDiskOptionsLocal),
   827  					},
   828  				},
   829  				Image: &infrav1.Image{ID: ptr.To("fake-image-id")},
   830  				SKU:   validSKU,
   831  			},
   832  			existing: nil,
   833  			expect: func(g *WithT, result interface{}) {
   834  				g.Expect(result).To(BeNil())
   835  			},
   836  			expectedError: "reconcile error that cannot be recovered occurred: VM size Standard_D2v3 does not support ephemeral os. Select a different VM size or disable ephemeral os. Object will not be requeued",
   837  		},
   838  		{
   839  			name: "cannot create vm if vCPU is less than 2",
   840  			spec: &VMSpec{
   841  				Name:       "my-vm",
   842  				Role:       infrav1.Node,
   843  				NICIDs:     []string{"my-nic"},
   844  				SSHKeyData: "fakesshpublickey",
   845  				Size:       "Standard_D2v3",
   846  				Image:      &infrav1.Image{ID: ptr.To("fake-image-id")},
   847  				SKU:        invalidCPUSKU,
   848  			},
   849  			existing: nil,
   850  			expect: func(g *WithT, result interface{}) {
   851  				g.Expect(result).To(BeNil())
   852  			},
   853  			expectedError: "reconcile error that cannot be recovered occurred: VM size should be bigger or equal to at least 2 vCPUs. Object will not be requeued",
   854  		},
   855  		{
   856  			name: "cannot create vm if memory is less than 2Gi",
   857  			spec: &VMSpec{
   858  				Name:       "my-vm",
   859  				Role:       infrav1.Node,
   860  				NICIDs:     []string{"my-nic"},
   861  				SSHKeyData: "fakesshpublickey",
   862  				Size:       "Standard_D2v3",
   863  				Image:      &infrav1.Image{ID: ptr.To("fake-image-id")},
   864  				SKU:        invalidMemSKU,
   865  			},
   866  			existing: nil,
   867  			expect: func(g *WithT, result interface{}) {
   868  				g.Expect(result).To(BeNil())
   869  			},
   870  			expectedError: "reconcile error that cannot be recovered occurred: VM memory should be bigger or equal to at least 2Gi. Object will not be requeued",
   871  		},
   872  		{
   873  			name: "can create a vm with a marketplace image using a plan",
   874  			spec: &VMSpec{
   875  				Name:       "my-vm",
   876  				Role:       infrav1.Node,
   877  				NICIDs:     []string{"my-nic"},
   878  				SSHKeyData: "fakesshpublickey",
   879  				Size:       "Standard_D2v3",
   880  				Image: &infrav1.Image{
   881  					Marketplace: &infrav1.AzureMarketplaceImage{
   882  						ImagePlan: infrav1.ImagePlan{
   883  							Publisher: "fake-publisher",
   884  							Offer:     "my-offer",
   885  							SKU:       "sku-id",
   886  						},
   887  						Version:         "1.0",
   888  						ThirdPartyImage: true,
   889  					},
   890  				},
   891  				SKU: validSKU,
   892  			},
   893  			existing: nil,
   894  			expect: func(g *WithT, result interface{}) {
   895  				g.Expect(result).To(BeAssignableToTypeOf(armcompute.VirtualMachine{}))
   896  				g.Expect(result.(armcompute.VirtualMachine).Properties.StorageProfile.ImageReference.Offer).To(Equal(ptr.To("my-offer")))
   897  				g.Expect(result.(armcompute.VirtualMachine).Properties.StorageProfile.ImageReference.Publisher).To(Equal(ptr.To("fake-publisher")))
   898  				g.Expect(result.(armcompute.VirtualMachine).Properties.StorageProfile.ImageReference.SKU).To(Equal(ptr.To("sku-id")))
   899  				g.Expect(result.(armcompute.VirtualMachine).Properties.StorageProfile.ImageReference.Version).To(Equal(ptr.To("1.0")))
   900  				g.Expect(result.(armcompute.VirtualMachine).Plan.Name).To(Equal(ptr.To("sku-id")))
   901  				g.Expect(result.(armcompute.VirtualMachine).Plan.Publisher).To(Equal(ptr.To("fake-publisher")))
   902  				g.Expect(result.(armcompute.VirtualMachine).Plan.Product).To(Equal(ptr.To("my-offer")))
   903  			},
   904  			expectedError: "",
   905  		},
   906  		{
   907  			name: "can create a vm with a SIG image using a plan",
   908  			spec: &VMSpec{
   909  				Name:       "my-vm",
   910  				Role:       infrav1.Node,
   911  				NICIDs:     []string{"my-nic"},
   912  				SSHKeyData: "fakesshpublickey",
   913  				Size:       "Standard_D2v3",
   914  				Image: &infrav1.Image{
   915  					SharedGallery: &infrav1.AzureSharedGalleryImage{
   916  						SubscriptionID: "fake-sub-id",
   917  						ResourceGroup:  "fake-rg",
   918  						Gallery:        "fake-gallery",
   919  						Name:           "fake-name",
   920  						Version:        "1.0",
   921  						Publisher:      ptr.To("fake-publisher"),
   922  						Offer:          ptr.To("my-offer"),
   923  						SKU:            ptr.To("sku-id"),
   924  					},
   925  				},
   926  				SKU: validSKU,
   927  			},
   928  			existing: nil,
   929  			expect: func(g *WithT, result interface{}) {
   930  				g.Expect(result).To(BeAssignableToTypeOf(armcompute.VirtualMachine{}))
   931  				g.Expect(result.(armcompute.VirtualMachine).Properties.StorageProfile.ImageReference.ID).To(Equal(ptr.To("/subscriptions/fake-sub-id/resourceGroups/fake-rg/providers/Microsoft.Compute/galleries/fake-gallery/images/fake-name/versions/1.0")))
   932  				g.Expect(result.(armcompute.VirtualMachine).Plan.Name).To(Equal(ptr.To("sku-id")))
   933  				g.Expect(result.(armcompute.VirtualMachine).Plan.Publisher).To(Equal(ptr.To("fake-publisher")))
   934  				g.Expect(result.(armcompute.VirtualMachine).Plan.Product).To(Equal(ptr.To("my-offer")))
   935  			},
   936  			expectedError: "",
   937  		},
   938  		{
   939  			name: "can create a vm with ultra disk enabled",
   940  			spec: &VMSpec{
   941  				Name:       "my-ultra-ssd-vm",
   942  				Role:       infrav1.Node,
   943  				NICIDs:     []string{"my-nic"},
   944  				SSHKeyData: "fakesshpublickey",
   945  				Size:       "Standard_D2v3",
   946  				Location:   "test-location",
   947  				Zone:       "1",
   948  				Image:      &infrav1.Image{ID: ptr.To("fake-image-id")},
   949  				DataDisks: []infrav1.DataDisk{
   950  					{
   951  						NameSuffix: "mydisk",
   952  						DiskSizeGB: 64,
   953  						Lun:        ptr.To[int32](0),
   954  					},
   955  					{
   956  						NameSuffix: "myDiskWithUltraDisk",
   957  						DiskSizeGB: 128,
   958  						Lun:        ptr.To[int32](1),
   959  						ManagedDisk: &infrav1.ManagedDiskParameters{
   960  							StorageAccountType: string(armcompute.StorageAccountTypesUltraSSDLRS),
   961  						},
   962  					},
   963  					{
   964  						NameSuffix: "myDiskWithManagedDisk",
   965  						DiskSizeGB: 128,
   966  						Lun:        ptr.To[int32](2),
   967  						ManagedDisk: &infrav1.ManagedDiskParameters{
   968  							StorageAccountType: string(armcompute.StorageAccountTypesPremiumLRS),
   969  						},
   970  					},
   971  					{
   972  						NameSuffix: "managedDiskWithEncryption",
   973  						DiskSizeGB: 128,
   974  						Lun:        ptr.To[int32](3),
   975  						ManagedDisk: &infrav1.ManagedDiskParameters{
   976  							StorageAccountType: string(armcompute.StorageAccountTypesPremiumLRS),
   977  							DiskEncryptionSet: &infrav1.DiskEncryptionSetParameters{
   978  								ID: "my_id",
   979  							},
   980  						},
   981  					},
   982  				},
   983  				SKU: validSKUWithUltraSSD,
   984  			},
   985  			existing: nil,
   986  			expect: func(g *WithT, result interface{}) {
   987  				g.Expect(result).To(BeAssignableToTypeOf(armcompute.VirtualMachine{}))
   988  				g.Expect(result.(armcompute.VirtualMachine).Properties.AdditionalCapabilities.UltraSSDEnabled).To(Equal(ptr.To(true)))
   989  				expectedDataDisks := []*armcompute.DataDisk{
   990  					{
   991  						Lun:          ptr.To[int32](0),
   992  						Name:         ptr.To("my-ultra-ssd-vm_mydisk"),
   993  						CreateOption: ptr.To(armcompute.DiskCreateOptionTypesEmpty),
   994  						DiskSizeGB:   ptr.To[int32](64),
   995  					},
   996  					{
   997  						Lun:          ptr.To[int32](1),
   998  						Name:         ptr.To("my-ultra-ssd-vm_myDiskWithUltraDisk"),
   999  						CreateOption: ptr.To(armcompute.DiskCreateOptionTypesEmpty),
  1000  						DiskSizeGB:   ptr.To[int32](128),
  1001  						ManagedDisk: &armcompute.ManagedDiskParameters{
  1002  							StorageAccountType: ptr.To(armcompute.StorageAccountTypesUltraSSDLRS),
  1003  						},
  1004  					},
  1005  					{
  1006  						Lun:          ptr.To[int32](2),
  1007  						Name:         ptr.To("my-ultra-ssd-vm_myDiskWithManagedDisk"),
  1008  						CreateOption: ptr.To(armcompute.DiskCreateOptionTypesEmpty),
  1009  						DiskSizeGB:   ptr.To[int32](128),
  1010  						ManagedDisk: &armcompute.ManagedDiskParameters{
  1011  							StorageAccountType: ptr.To(armcompute.StorageAccountTypesPremiumLRS),
  1012  						},
  1013  					},
  1014  					{
  1015  						Lun:          ptr.To[int32](3),
  1016  						Name:         ptr.To("my-ultra-ssd-vm_managedDiskWithEncryption"),
  1017  						CreateOption: ptr.To(armcompute.DiskCreateOptionTypesEmpty),
  1018  						DiskSizeGB:   ptr.To[int32](128),
  1019  						ManagedDisk: &armcompute.ManagedDiskParameters{
  1020  							StorageAccountType: ptr.To(armcompute.StorageAccountTypesPremiumLRS),
  1021  							DiskEncryptionSet: &armcompute.DiskEncryptionSetParameters{
  1022  								ID: ptr.To("my_id"),
  1023  							},
  1024  						},
  1025  					},
  1026  				}
  1027  				g.Expect(gomockinternal.DiffEq(expectedDataDisks).Matches(result.(armcompute.VirtualMachine).Properties.StorageProfile.DataDisks)).To(BeTrue(), cmp.Diff(expectedDataDisks, result.(armcompute.VirtualMachine).Properties.StorageProfile.DataDisks))
  1028  			},
  1029  			expectedError: "",
  1030  		},
  1031  		{
  1032  			name: "creating vm with ultra disk enabled in unsupported location fails",
  1033  			spec: &VMSpec{
  1034  				Name:       "my-vm",
  1035  				Role:       infrav1.Node,
  1036  				NICIDs:     []string{"my-nic"},
  1037  				SSHKeyData: "fakesshpublickey",
  1038  				Size:       "Standard_D2v3",
  1039  				Location:   "test-location",
  1040  				Zone:       "1",
  1041  				Image:      &infrav1.Image{ID: ptr.To("fake-image-id")},
  1042  				DataDisks: []infrav1.DataDisk{
  1043  					{
  1044  						NameSuffix: "myDiskWithUltraDisk",
  1045  						DiskSizeGB: 128,
  1046  						Lun:        ptr.To[int32](1),
  1047  						ManagedDisk: &infrav1.ManagedDiskParameters{
  1048  							StorageAccountType: string(armcompute.StorageAccountTypesUltraSSDLRS),
  1049  						},
  1050  					},
  1051  				},
  1052  				SKU: validSKU,
  1053  			},
  1054  			existing: nil,
  1055  			expect: func(g *WithT, result interface{}) {
  1056  				g.Expect(result).To(BeNil())
  1057  			},
  1058  			expectedError: "reconcile error that cannot be recovered occurred: VM size Standard_D2v3 does not support ultra disks in location test-location. Select a different VM size or disable ultra disks. Object will not be requeued",
  1059  		},
  1060  		{
  1061  			name: "creates a vm with AdditionalCapabilities.UltraSSDEnabled false, if an ultra disk is specified as data disk but AdditionalCapabilities.UltraSSDEnabled is false",
  1062  			spec: &VMSpec{
  1063  				Name:       "my-ultra-ssd-vm",
  1064  				Role:       infrav1.Node,
  1065  				NICIDs:     []string{"my-nic"},
  1066  				SSHKeyData: "fakesshpublickey",
  1067  				Size:       "Standard_D2v3",
  1068  				Location:   "test-location",
  1069  				Zone:       "1",
  1070  				Image:      &infrav1.Image{ID: ptr.To("fake-image-id")},
  1071  				AdditionalCapabilities: &infrav1.AdditionalCapabilities{
  1072  					UltraSSDEnabled: ptr.To(false),
  1073  				},
  1074  				DataDisks: []infrav1.DataDisk{
  1075  					{
  1076  						NameSuffix: "myDiskWithUltraDisk",
  1077  						DiskSizeGB: 128,
  1078  						Lun:        ptr.To[int32](1),
  1079  						ManagedDisk: &infrav1.ManagedDiskParameters{
  1080  							StorageAccountType: string(armcompute.StorageAccountTypesUltraSSDLRS),
  1081  						},
  1082  					},
  1083  				},
  1084  				SKU: validSKUWithUltraSSD,
  1085  			},
  1086  			existing: nil,
  1087  			expect: func(g *WithT, result interface{}) {
  1088  				g.Expect(result).To(BeAssignableToTypeOf(armcompute.VirtualMachine{}))
  1089  				g.Expect(result.(armcompute.VirtualMachine).Properties.AdditionalCapabilities.UltraSSDEnabled).To(Equal(ptr.To(false)))
  1090  				expectedDataDisks := []*armcompute.DataDisk{
  1091  					{
  1092  						Lun:          ptr.To[int32](1),
  1093  						Name:         ptr.To("my-ultra-ssd-vm_myDiskWithUltraDisk"),
  1094  						CreateOption: ptr.To(armcompute.DiskCreateOptionTypesEmpty),
  1095  						DiskSizeGB:   ptr.To[int32](128),
  1096  						ManagedDisk: &armcompute.ManagedDiskParameters{
  1097  							StorageAccountType: ptr.To(armcompute.StorageAccountTypesUltraSSDLRS),
  1098  						},
  1099  					},
  1100  				}
  1101  				g.Expect(gomockinternal.DiffEq(expectedDataDisks).Matches(result.(armcompute.VirtualMachine).Properties.StorageProfile.DataDisks)).To(BeTrue(), cmp.Diff(expectedDataDisks, result.(armcompute.VirtualMachine).Properties.StorageProfile.DataDisks))
  1102  			},
  1103  			expectedError: "",
  1104  		},
  1105  		{
  1106  			name: "creates a vm with AdditionalCapabilities.UltraSSDEnabled true, if an ultra disk is specified as data disk and no AdditionalCapabilities.UltraSSDEnabled is set",
  1107  			spec: &VMSpec{
  1108  				Name:       "my-ultra-ssd-vm",
  1109  				Role:       infrav1.Node,
  1110  				NICIDs:     []string{"my-nic"},
  1111  				SSHKeyData: "fakesshpublickey",
  1112  				Size:       "Standard_D2v3",
  1113  				Location:   "test-location",
  1114  				Zone:       "1",
  1115  				Image:      &infrav1.Image{ID: ptr.To("fake-image-id")},
  1116  				DataDisks: []infrav1.DataDisk{
  1117  					{
  1118  						NameSuffix: "myDiskWithUltraDisk",
  1119  						DiskSizeGB: 128,
  1120  						Lun:        ptr.To[int32](1),
  1121  						ManagedDisk: &infrav1.ManagedDiskParameters{
  1122  							StorageAccountType: string(armcompute.StorageAccountTypesUltraSSDLRS),
  1123  						},
  1124  					},
  1125  				},
  1126  				SKU: validSKUWithUltraSSD,
  1127  			},
  1128  			existing: nil,
  1129  			expect: func(g *WithT, result interface{}) {
  1130  				g.Expect(result).To(BeAssignableToTypeOf(armcompute.VirtualMachine{}))
  1131  				g.Expect(result.(armcompute.VirtualMachine).Properties.AdditionalCapabilities.UltraSSDEnabled).To(Equal(ptr.To(true)))
  1132  				expectedDataDisks := []*armcompute.DataDisk{
  1133  					{
  1134  						Lun:          ptr.To[int32](1),
  1135  						Name:         ptr.To("my-ultra-ssd-vm_myDiskWithUltraDisk"),
  1136  						CreateOption: ptr.To(armcompute.DiskCreateOptionTypesEmpty),
  1137  						DiskSizeGB:   ptr.To[int32](128),
  1138  						ManagedDisk: &armcompute.ManagedDiskParameters{
  1139  							StorageAccountType: ptr.To(armcompute.StorageAccountTypesUltraSSDLRS),
  1140  						},
  1141  					},
  1142  				}
  1143  				g.Expect(gomockinternal.DiffEq(expectedDataDisks).Matches(result.(armcompute.VirtualMachine).Properties.StorageProfile.DataDisks)).To(BeTrue(), cmp.Diff(expectedDataDisks, result.(armcompute.VirtualMachine).Properties.StorageProfile.DataDisks))
  1144  			},
  1145  			expectedError: "",
  1146  		},
  1147  		{
  1148  			name: "creates a vm with AdditionalCapabilities.UltraSSDEnabled true, if an ultra disk is specified as data disk and AdditionalCapabilities.UltraSSDEnabled is true",
  1149  			spec: &VMSpec{
  1150  				Name:       "my-ultra-ssd-vm",
  1151  				Role:       infrav1.Node,
  1152  				NICIDs:     []string{"my-nic"},
  1153  				SSHKeyData: "fakesshpublickey",
  1154  				Size:       "Standard_D2v3",
  1155  				Location:   "test-location",
  1156  				Zone:       "1",
  1157  				Image:      &infrav1.Image{ID: ptr.To("fake-image-id")},
  1158  				AdditionalCapabilities: &infrav1.AdditionalCapabilities{
  1159  					UltraSSDEnabled: ptr.To(true),
  1160  				},
  1161  				DataDisks: []infrav1.DataDisk{
  1162  					{
  1163  						NameSuffix: "myDiskWithUltraDisk",
  1164  						DiskSizeGB: 128,
  1165  						Lun:        ptr.To[int32](1),
  1166  						ManagedDisk: &infrav1.ManagedDiskParameters{
  1167  							StorageAccountType: string(armcompute.StorageAccountTypesUltraSSDLRS),
  1168  						},
  1169  					},
  1170  				},
  1171  				SKU: validSKUWithUltraSSD,
  1172  			},
  1173  			existing: nil,
  1174  			expect: func(g *WithT, result interface{}) {
  1175  				g.Expect(result).To(BeAssignableToTypeOf(armcompute.VirtualMachine{}))
  1176  				g.Expect(result.(armcompute.VirtualMachine).Properties.AdditionalCapabilities.UltraSSDEnabled).To(Equal(ptr.To(true)))
  1177  				expectedDataDisks := []*armcompute.DataDisk{
  1178  					{
  1179  						Lun:          ptr.To[int32](1),
  1180  						Name:         ptr.To("my-ultra-ssd-vm_myDiskWithUltraDisk"),
  1181  						CreateOption: ptr.To(armcompute.DiskCreateOptionTypesEmpty),
  1182  						DiskSizeGB:   ptr.To[int32](128),
  1183  						ManagedDisk: &armcompute.ManagedDiskParameters{
  1184  							StorageAccountType: ptr.To(armcompute.StorageAccountTypesUltraSSDLRS),
  1185  						},
  1186  					},
  1187  				}
  1188  				g.Expect(gomockinternal.DiffEq(expectedDataDisks).Matches(result.(armcompute.VirtualMachine).Properties.StorageProfile.DataDisks)).To(BeTrue(), cmp.Diff(expectedDataDisks, result.(armcompute.VirtualMachine).Properties.StorageProfile.DataDisks))
  1189  			},
  1190  			expectedError: "",
  1191  		},
  1192  		{
  1193  			name: "creates a vm with AdditionalCapabilities.UltraSSDEnabled true, if no ultra disk is specified as data disk and AdditionalCapabilities.UltraSSDEnabled is true",
  1194  			spec: &VMSpec{
  1195  				Name:       "my-ultra-ssd-vm",
  1196  				Role:       infrav1.Node,
  1197  				NICIDs:     []string{"my-nic"},
  1198  				SSHKeyData: "fakesshpublickey",
  1199  				Size:       "Standard_D2v3",
  1200  				Location:   "test-location",
  1201  				Zone:       "1",
  1202  				Image:      &infrav1.Image{ID: ptr.To("fake-image-id")},
  1203  				AdditionalCapabilities: &infrav1.AdditionalCapabilities{
  1204  					UltraSSDEnabled: ptr.To(true),
  1205  				},
  1206  				SKU: validSKUWithUltraSSD,
  1207  			},
  1208  			existing: nil,
  1209  			expect: func(g *WithT, result interface{}) {
  1210  				g.Expect(result).To(BeAssignableToTypeOf(armcompute.VirtualMachine{}))
  1211  				g.Expect(result.(armcompute.VirtualMachine).Properties.AdditionalCapabilities.UltraSSDEnabled).To(Equal(ptr.To(true)))
  1212  			},
  1213  			expectedError: "",
  1214  		},
  1215  		{
  1216  			name: "creates a vm with AdditionalCapabilities.UltraSSDEnabled false, if no ultra disk is specified as data disk and AdditionalCapabilities.UltraSSDEnabled is false",
  1217  			spec: &VMSpec{
  1218  				Name:       "my-ultra-ssd-vm",
  1219  				Role:       infrav1.Node,
  1220  				NICIDs:     []string{"my-nic"},
  1221  				SSHKeyData: "fakesshpublickey",
  1222  				Size:       "Standard_D2v3",
  1223  				Location:   "test-location",
  1224  				Zone:       "1",
  1225  				Image:      &infrav1.Image{ID: ptr.To("fake-image-id")},
  1226  				AdditionalCapabilities: &infrav1.AdditionalCapabilities{
  1227  					UltraSSDEnabled: ptr.To(false),
  1228  				},
  1229  				SKU: validSKUWithUltraSSD,
  1230  			},
  1231  			existing: nil,
  1232  			expect: func(g *WithT, result interface{}) {
  1233  				g.Expect(result).To(BeAssignableToTypeOf(armcompute.VirtualMachine{}))
  1234  				g.Expect(result.(armcompute.VirtualMachine).Properties.AdditionalCapabilities.UltraSSDEnabled).To(Equal(ptr.To(false)))
  1235  			},
  1236  			expectedError: "",
  1237  		},
  1238  		{
  1239  			name: "creates a vm with Diagnostics disabled",
  1240  			spec: &VMSpec{
  1241  				Name:       "my-ultra-ssd-vm",
  1242  				Role:       infrav1.Node,
  1243  				NICIDs:     []string{"my-nic"},
  1244  				SSHKeyData: "fakesshpublickey",
  1245  				Size:       "Standard_D2v3",
  1246  				Location:   "test-location",
  1247  				Zone:       "1",
  1248  				Image:      &infrav1.Image{ID: ptr.To("fake-image-id")},
  1249  				DiagnosticsProfile: &infrav1.Diagnostics{
  1250  					Boot: &infrav1.BootDiagnostics{
  1251  						StorageAccountType: infrav1.DisabledDiagnosticsStorage,
  1252  					},
  1253  				},
  1254  				SKU: validSKUWithUltraSSD,
  1255  			},
  1256  			existing: nil,
  1257  			expect: func(g *WithT, result interface{}) {
  1258  				g.Expect(result).To(BeAssignableToTypeOf(armcompute.VirtualMachine{}))
  1259  				g.Expect(result.(armcompute.VirtualMachine).Properties.DiagnosticsProfile.BootDiagnostics.Enabled).To(Equal(ptr.To(false)))
  1260  				g.Expect(result.(armcompute.VirtualMachine).Properties.DiagnosticsProfile.BootDiagnostics.StorageURI).To(BeNil())
  1261  			},
  1262  			expectedError: "",
  1263  		},
  1264  		{
  1265  			name: "creates a vm with Managed Diagnostics enabled",
  1266  			spec: &VMSpec{
  1267  				Name:       "my-ultra-ssd-vm",
  1268  				Role:       infrav1.Node,
  1269  				NICIDs:     []string{"my-nic"},
  1270  				SSHKeyData: "fakesshpublickey",
  1271  				Size:       "Standard_D2v3",
  1272  				Location:   "test-location",
  1273  				Zone:       "1",
  1274  				Image:      &infrav1.Image{ID: ptr.To("fake-image-id")},
  1275  				DiagnosticsProfile: &infrav1.Diagnostics{
  1276  					Boot: &infrav1.BootDiagnostics{
  1277  						StorageAccountType: infrav1.ManagedDiagnosticsStorage,
  1278  					},
  1279  				},
  1280  				SKU: validSKUWithUltraSSD,
  1281  			},
  1282  			existing: nil,
  1283  			expect: func(g *WithT, result interface{}) {
  1284  				g.Expect(result).To(BeAssignableToTypeOf(armcompute.VirtualMachine{}))
  1285  				g.Expect(result.(armcompute.VirtualMachine).Properties.DiagnosticsProfile.BootDiagnostics.Enabled).To(Equal(ptr.To(true)))
  1286  				g.Expect(result.(armcompute.VirtualMachine).Properties.DiagnosticsProfile.BootDiagnostics.StorageURI).To(BeNil())
  1287  			},
  1288  			expectedError: "",
  1289  		},
  1290  		{
  1291  			name: "creates a vm with User Managed Diagnostics enabled",
  1292  			spec: &VMSpec{
  1293  				Name:       "my-ultra-ssd-vm",
  1294  				Role:       infrav1.Node,
  1295  				NICIDs:     []string{"my-nic"},
  1296  				SSHKeyData: "fakesshpublickey",
  1297  				Size:       "Standard_D2v3",
  1298  				Location:   "test-location",
  1299  				Zone:       "1",
  1300  				Image:      &infrav1.Image{ID: ptr.To("fake-image-id")},
  1301  				DiagnosticsProfile: &infrav1.Diagnostics{
  1302  					Boot: &infrav1.BootDiagnostics{
  1303  						StorageAccountType: infrav1.UserManagedDiagnosticsStorage,
  1304  						UserManaged: &infrav1.UserManagedBootDiagnostics{
  1305  							StorageAccountURI: "aaa",
  1306  						},
  1307  					},
  1308  				},
  1309  				SKU: validSKUWithUltraSSD,
  1310  			},
  1311  			existing: nil,
  1312  			expect: func(g *WithT, result interface{}) {
  1313  				g.Expect(result).To(BeAssignableToTypeOf(armcompute.VirtualMachine{}))
  1314  				g.Expect(result.(armcompute.VirtualMachine).Properties.DiagnosticsProfile.BootDiagnostics.Enabled).To(Equal(ptr.To(true)))
  1315  				g.Expect(result.(armcompute.VirtualMachine).Properties.DiagnosticsProfile.BootDiagnostics.StorageURI).To(Equal(ptr.To("aaa")))
  1316  			},
  1317  			expectedError: "",
  1318  		},
  1319  		{
  1320  			name: "creates a vm with User Managed Diagnostics enabled, but missing StorageAccountURI",
  1321  			spec: &VMSpec{
  1322  				Name:       "my-ultra-ssd-vm",
  1323  				Role:       infrav1.Node,
  1324  				NICIDs:     []string{"my-nic"},
  1325  				SSHKeyData: "fakesshpublickey",
  1326  				Size:       "Standard_D2v3",
  1327  				Location:   "test-location",
  1328  				Zone:       "1",
  1329  				Image:      &infrav1.Image{ID: ptr.To("fake-image-id")},
  1330  				DiagnosticsProfile: &infrav1.Diagnostics{
  1331  					Boot: &infrav1.BootDiagnostics{
  1332  						StorageAccountType: infrav1.UserManagedDiagnosticsStorage,
  1333  						UserManaged: &infrav1.UserManagedBootDiagnostics{
  1334  							StorageAccountURI: "aaa",
  1335  						},
  1336  					},
  1337  				},
  1338  				SKU: validSKUWithUltraSSD,
  1339  			},
  1340  			existing: nil,
  1341  			expect: func(g *WithT, result interface{}) {
  1342  				g.Expect(result).To(BeAssignableToTypeOf(armcompute.VirtualMachine{}))
  1343  				g.Expect(result.(armcompute.VirtualMachine).Properties.DiagnosticsProfile.BootDiagnostics.Enabled).To(Equal(ptr.To(true)))
  1344  				g.Expect(result.(armcompute.VirtualMachine).Properties.DiagnosticsProfile.BootDiagnostics.StorageURI).To(Equal(ptr.To("aaa")))
  1345  			},
  1346  			expectedError: "",
  1347  		},
  1348  	}
  1349  	for _, tc := range testcases {
  1350  		tc := tc
  1351  		t.Run(tc.name, func(t *testing.T) {
  1352  			g := NewWithT(t)
  1353  			t.Parallel()
  1354  
  1355  			result, err := tc.spec.Parameters(context.TODO(), tc.existing)
  1356  			if tc.expectedError != "" {
  1357  				g.Expect(err).To(HaveOccurred())
  1358  				g.Expect(err).To(MatchError(tc.expectedError))
  1359  			} else {
  1360  				g.Expect(err).NotTo(HaveOccurred())
  1361  			}
  1362  			tc.expect(g, result)
  1363  		})
  1364  	}
  1365  }