sigs.k8s.io/cluster-api-provider-azure@v1.17.0/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 vm with DiffDiskPlacement ResourceDisk",
   466  			spec: &VMSpec{
   467  				Name:       "my-vm",
   468  				Role:       infrav1.Node,
   469  				NICIDs:     []string{"my-nic"},
   470  				SSHKeyData: "fakesshpublickey",
   471  				Size:       "Standard_D2v3",
   472  				OSDisk: infrav1.OSDisk{
   473  					OSType:     "Linux",
   474  					DiskSizeGB: ptr.To[int32](128),
   475  					ManagedDisk: &infrav1.ManagedDiskParameters{
   476  						StorageAccountType: string(armcompute.StorageAccountTypesPremiumLRS),
   477  					},
   478  					DiffDiskSettings: &infrav1.DiffDiskSettings{
   479  						Option:    string(armcompute.DiffDiskOptionsLocal),
   480  						Placement: ptr.To(infrav1.DiffDiskPlacementResourceDisk),
   481  					},
   482  				},
   483  				Image: &infrav1.Image{ID: ptr.To("fake-image-id")},
   484  				SKU:   validSKUWithEphemeralOS,
   485  			},
   486  			existing: nil,
   487  			expect: func(g *WithT, result interface{}) {
   488  				g.Expect(result).To(BeAssignableToTypeOf(armcompute.VirtualMachine{}))
   489  				g.Expect(result.(armcompute.VirtualMachine).Properties.StorageProfile.OSDisk.DiffDiskSettings.Placement).To(Equal(ptr.To(armcompute.DiffDiskPlacementResourceDisk)))
   490  			},
   491  			expectedError: "",
   492  		},
   493  		{
   494  			name: "can create a trusted launch vm",
   495  			spec: &VMSpec{
   496  				Name:              "my-vm",
   497  				Role:              infrav1.Node,
   498  				NICIDs:            []string{"my-nic"},
   499  				SSHKeyData:        "fakesshpublickey",
   500  				Size:              "Standard_D2v3",
   501  				AvailabilitySetID: "fake-availability-set-id",
   502  				Zone:              "",
   503  				Image:             &infrav1.Image{ID: ptr.To("fake-image-id")},
   504  				SecurityProfile: &infrav1.SecurityProfile{
   505  					SecurityType: infrav1.SecurityTypesTrustedLaunch,
   506  					UefiSettings: &infrav1.UefiSettings{
   507  						SecureBootEnabled: ptr.To(true),
   508  						VTpmEnabled:       ptr.To(true),
   509  					},
   510  				},
   511  				SKU: validSKU,
   512  			},
   513  			existing: nil,
   514  			expect: func(g *WithT, result interface{}) {
   515  				g.Expect(result).To(BeAssignableToTypeOf(armcompute.VirtualMachine{}))
   516  				g.Expect(*result.(armcompute.VirtualMachine).Properties.SecurityProfile.UefiSettings.SecureBootEnabled).To(BeTrue())
   517  				g.Expect(*result.(armcompute.VirtualMachine).Properties.SecurityProfile.UefiSettings.VTpmEnabled).To(BeTrue())
   518  			},
   519  			expectedError: "",
   520  		},
   521  		{
   522  			name: "can create a confidential vm",
   523  			spec: &VMSpec{
   524  				Name:              "my-vm",
   525  				Role:              infrav1.Node,
   526  				NICIDs:            []string{"my-nic"},
   527  				SSHKeyData:        "fakesshpublickey",
   528  				Size:              "Standard_D2v3",
   529  				AvailabilitySetID: "fake-availability-set-id",
   530  				Zone:              "",
   531  				Image:             &infrav1.Image{ID: ptr.To("fake-image-id")},
   532  				OSDisk: infrav1.OSDisk{
   533  					OSType:     "Linux",
   534  					DiskSizeGB: ptr.To[int32](128),
   535  					ManagedDisk: &infrav1.ManagedDiskParameters{
   536  						StorageAccountType: string(armcompute.StorageAccountTypesPremiumLRS),
   537  						SecurityProfile: &infrav1.VMDiskSecurityProfile{
   538  							SecurityEncryptionType: infrav1.SecurityEncryptionTypeVMGuestStateOnly,
   539  						},
   540  					},
   541  				},
   542  				SecurityProfile: &infrav1.SecurityProfile{
   543  					SecurityType: infrav1.SecurityTypesConfidentialVM,
   544  					UefiSettings: &infrav1.UefiSettings{
   545  						SecureBootEnabled: ptr.To(false),
   546  						VTpmEnabled:       ptr.To(true),
   547  					},
   548  				},
   549  				SKU: validSKUWithConfidentialComputingType,
   550  			},
   551  			existing: nil,
   552  			expect: func(g *WithT, result interface{}) {
   553  				g.Expect(result).To(BeAssignableToTypeOf(armcompute.VirtualMachine{}))
   554  				g.Expect(result.(armcompute.VirtualMachine).Properties.StorageProfile.OSDisk.ManagedDisk.SecurityProfile.SecurityEncryptionType).To(Equal(ptr.To(armcompute.SecurityEncryptionTypesVMGuestStateOnly)))
   555  				g.Expect(*result.(armcompute.VirtualMachine).Properties.SecurityProfile.UefiSettings.VTpmEnabled).To(BeTrue())
   556  			},
   557  			expectedError: "",
   558  		},
   559  		{
   560  			name: "creating a confidential vm without the SecurityType set to ConfidentialVM fails",
   561  			spec: &VMSpec{
   562  				Name:              "my-vm",
   563  				Role:              infrav1.Node,
   564  				NICIDs:            []string{"my-nic"},
   565  				SSHKeyData:        "fakesshpublickey",
   566  				Size:              "Standard_D2v3",
   567  				AvailabilitySetID: "fake-availability-set-id",
   568  				Zone:              "",
   569  				Image:             &infrav1.Image{ID: ptr.To("fake-image-id")},
   570  				OSDisk: infrav1.OSDisk{
   571  					OSType:     "Linux",
   572  					DiskSizeGB: ptr.To[int32](128),
   573  					ManagedDisk: &infrav1.ManagedDiskParameters{
   574  						StorageAccountType: string(armcompute.StorageAccountTypesPremiumLRS),
   575  						SecurityProfile: &infrav1.VMDiskSecurityProfile{
   576  							SecurityEncryptionType: infrav1.SecurityEncryptionTypeVMGuestStateOnly,
   577  						},
   578  					},
   579  				},
   580  				SecurityProfile: &infrav1.SecurityProfile{
   581  					SecurityType: "",
   582  					UefiSettings: &infrav1.UefiSettings{
   583  						SecureBootEnabled: ptr.To(false),
   584  						VTpmEnabled:       ptr.To(true),
   585  					},
   586  				},
   587  				SKU: validSKUWithConfidentialComputingType,
   588  			},
   589  			existing: nil,
   590  			expect: func(g *WithT, result interface{}) {
   591  				g.Expect(result).To(BeNil())
   592  			},
   593  			expectedError: "reconcile error that cannot be recovered occurred: securityType should be set to ConfidentialVM when securityEncryptionType is set. Object will not be requeued",
   594  		},
   595  		{
   596  			name: "creating a vm with encryption at host enabled for unsupported VM type fails",
   597  			spec: &VMSpec{
   598  				Name:              "my-vm",
   599  				Role:              infrav1.Node,
   600  				NICIDs:            []string{"my-nic"},
   601  				SSHKeyData:        "fakesshpublickey",
   602  				Size:              "Standard_D2v3",
   603  				AvailabilitySetID: "fake-availability-set-id",
   604  				Zone:              "",
   605  				Image:             &infrav1.Image{ID: ptr.To("fake-image-id")},
   606  				SecurityProfile:   &infrav1.SecurityProfile{EncryptionAtHost: ptr.To(true)},
   607  				SKU:               validSKU,
   608  			},
   609  			existing: nil,
   610  			expect: func(g *WithT, result interface{}) {
   611  				g.Expect(result).To(BeNil())
   612  			},
   613  			expectedError: "reconcile error that cannot be recovered occurred: encryption at host is not supported for VM type Standard_D2v3. Object will not be requeued",
   614  		},
   615  		{
   616  			name: "creating a trusted launch vm without the SecurityType set to TrustedLaunch fails",
   617  			spec: &VMSpec{
   618  				Name:              "my-vm",
   619  				Role:              infrav1.Node,
   620  				NICIDs:            []string{"my-nic"},
   621  				SSHKeyData:        "fakesshpublickey",
   622  				Size:              "Standard_D2v3",
   623  				AvailabilitySetID: "fake-availability-set-id",
   624  				Zone:              "",
   625  				Image:             &infrav1.Image{ID: ptr.To("fake-image-id")},
   626  				OSDisk: infrav1.OSDisk{
   627  					OSType:     "Linux",
   628  					DiskSizeGB: ptr.To[int32](128),
   629  					ManagedDisk: &infrav1.ManagedDiskParameters{
   630  						StorageAccountType: string(armcompute.StorageAccountTypesPremiumLRS),
   631  					},
   632  				},
   633  				SecurityProfile: &infrav1.SecurityProfile{
   634  					SecurityType: "",
   635  					UefiSettings: &infrav1.UefiSettings{
   636  						SecureBootEnabled: ptr.To(false),
   637  						VTpmEnabled:       ptr.To(true),
   638  					},
   639  				},
   640  				SKU: validSKUWithConfidentialComputingType,
   641  			},
   642  			existing: nil,
   643  			expect: func(g *WithT, result interface{}) {
   644  				g.Expect(result).To(BeNil())
   645  			},
   646  			expectedError: "reconcile error that cannot be recovered occurred: securityType should be set to TrustedLaunch when vTpmEnabled is true. Object will not be requeued",
   647  		},
   648  		{
   649  			name: "creating a trusted launch vm with secure boot enabled on unsupported VM type fails",
   650  			spec: &VMSpec{
   651  				Name:              "my-vm",
   652  				Role:              infrav1.Node,
   653  				NICIDs:            []string{"my-nic"},
   654  				SSHKeyData:        "fakesshpublickey",
   655  				Size:              "Standard_D2v3",
   656  				AvailabilitySetID: "fake-availability-set-id",
   657  				Zone:              "",
   658  				Image:             &infrav1.Image{ID: ptr.To("fake-image-id")},
   659  				SecurityProfile: &infrav1.SecurityProfile{
   660  					SecurityType: infrav1.SecurityTypesTrustedLaunch,
   661  					UefiSettings: &infrav1.UefiSettings{
   662  						SecureBootEnabled: ptr.To(true),
   663  					},
   664  				},
   665  				SKU: validSKUWithTrustedLaunchDisabled,
   666  			},
   667  			existing: nil,
   668  			expect: func(g *WithT, result interface{}) {
   669  				g.Expect(result).To(BeNil())
   670  			},
   671  			expectedError: "reconcile error that cannot be recovered occurred: secure boot is not supported for VM type Standard_D2v3. Object will not be requeued",
   672  		},
   673  		{
   674  			name: "creating a trusted launch vm with vTPM enabled on unsupported VM type fails",
   675  			spec: &VMSpec{
   676  				Name:              "my-vm",
   677  				Role:              infrav1.Node,
   678  				NICIDs:            []string{"my-nic"},
   679  				SSHKeyData:        "fakesshpublickey",
   680  				Size:              "Standard_D2v3",
   681  				AvailabilitySetID: "fake-availability-set-id",
   682  				Zone:              "",
   683  				Image:             &infrav1.Image{ID: ptr.To("fake-image-id")},
   684  				SecurityProfile: &infrav1.SecurityProfile{
   685  					SecurityType: infrav1.SecurityTypesTrustedLaunch,
   686  					UefiSettings: &infrav1.UefiSettings{
   687  						VTpmEnabled: ptr.To(true),
   688  					},
   689  				},
   690  				SKU: validSKUWithTrustedLaunchDisabled,
   691  			},
   692  			existing: nil,
   693  			expect: func(g *WithT, result interface{}) {
   694  				g.Expect(result).To(BeNil())
   695  			},
   696  			expectedError: "reconcile error that cannot be recovered occurred: vTPM is not supported for VM type Standard_D2v3. Object will not be requeued",
   697  		},
   698  		{
   699  			name: "creating a confidential vm with securityTypeEncryption DiskWithVMGuestState and encryption at host enabled fails",
   700  			spec: &VMSpec{
   701  				Name:              "my-vm",
   702  				Role:              infrav1.Node,
   703  				NICIDs:            []string{"my-nic"},
   704  				SSHKeyData:        "fakesshpublickey",
   705  				Size:              "Standard_D2v3",
   706  				AvailabilitySetID: "fake-availability-set-id",
   707  				Zone:              "",
   708  				Image:             &infrav1.Image{ID: ptr.To("fake-image-id")},
   709  				OSDisk: infrav1.OSDisk{
   710  					OSType:     "Linux",
   711  					DiskSizeGB: ptr.To[int32](128),
   712  					ManagedDisk: &infrav1.ManagedDiskParameters{
   713  						StorageAccountType: string(armcompute.StorageAccountTypesPremiumLRS),
   714  						SecurityProfile: &infrav1.VMDiskSecurityProfile{
   715  							SecurityEncryptionType: infrav1.SecurityEncryptionTypeDiskWithVMGuestState,
   716  						},
   717  					},
   718  				},
   719  				SecurityProfile: &infrav1.SecurityProfile{
   720  					EncryptionAtHost: ptr.To(true),
   721  					SecurityType:     infrav1.SecurityTypesConfidentialVM,
   722  					UefiSettings: &infrav1.UefiSettings{
   723  						VTpmEnabled: ptr.To(true),
   724  					},
   725  				},
   726  				SKU: validSKUWithConfidentialComputingType,
   727  			},
   728  			existing: nil,
   729  			expect: func(g *WithT, result interface{}) {
   730  				g.Expect(result).To(BeNil())
   731  			},
   732  			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",
   733  		},
   734  		{
   735  			name: "creating a confidential vm with DiskWithVMGuestState encryption type and secure boot disabled fails",
   736  			spec: &VMSpec{
   737  				Name:              "my-vm",
   738  				Role:              infrav1.Node,
   739  				NICIDs:            []string{"my-nic"},
   740  				SSHKeyData:        "fakesshpublickey",
   741  				Size:              "Standard_D2v3",
   742  				AvailabilitySetID: "fake-availability-set-id",
   743  				Zone:              "",
   744  				Image:             &infrav1.Image{ID: ptr.To("fake-image-id")},
   745  				OSDisk: infrav1.OSDisk{
   746  					OSType:     "Linux",
   747  					DiskSizeGB: ptr.To[int32](128),
   748  					ManagedDisk: &infrav1.ManagedDiskParameters{
   749  						StorageAccountType: string(armcompute.StorageAccountTypesPremiumLRS),
   750  						SecurityProfile: &infrav1.VMDiskSecurityProfile{
   751  							SecurityEncryptionType: infrav1.SecurityEncryptionTypeDiskWithVMGuestState,
   752  						},
   753  					},
   754  				},
   755  				SecurityProfile: &infrav1.SecurityProfile{
   756  					SecurityType: infrav1.SecurityTypesConfidentialVM,
   757  					UefiSettings: &infrav1.UefiSettings{
   758  						SecureBootEnabled: ptr.To(false),
   759  						VTpmEnabled:       ptr.To(true),
   760  					},
   761  				},
   762  				SKU: validSKUWithConfidentialComputingType,
   763  			},
   764  			existing: nil,
   765  			expect: func(g *WithT, result interface{}) {
   766  				g.Expect(result).To(BeNil())
   767  			},
   768  			expectedError: "reconcile error that cannot be recovered occurred: secureBootEnabled should be true when securityEncryptionType is set to DiskWithVMGuestState. Object will not be requeued",
   769  		},
   770  		{
   771  			name: "creating a confidential vm with vTPM disabled fails",
   772  			spec: &VMSpec{
   773  				Name:              "my-vm",
   774  				Role:              infrav1.Node,
   775  				NICIDs:            []string{"my-nic"},
   776  				SSHKeyData:        "fakesshpublickey",
   777  				Size:              "Standard_D2v3",
   778  				AvailabilitySetID: "fake-availability-set-id",
   779  				Zone:              "",
   780  				Image:             &infrav1.Image{ID: ptr.To("fake-image-id")},
   781  				OSDisk: infrav1.OSDisk{
   782  					OSType:     "Linux",
   783  					DiskSizeGB: ptr.To[int32](128),
   784  					ManagedDisk: &infrav1.ManagedDiskParameters{
   785  						StorageAccountType: string(armcompute.StorageAccountTypesPremiumLRS),
   786  						SecurityProfile: &infrav1.VMDiskSecurityProfile{
   787  							SecurityEncryptionType: infrav1.SecurityEncryptionTypeVMGuestStateOnly,
   788  						},
   789  					},
   790  				},
   791  				SecurityProfile: &infrav1.SecurityProfile{
   792  					SecurityType: infrav1.SecurityTypesConfidentialVM,
   793  					UefiSettings: &infrav1.UefiSettings{
   794  						VTpmEnabled: ptr.To(false),
   795  					},
   796  				},
   797  				SKU: validSKUWithConfidentialComputingType,
   798  			},
   799  			existing: nil,
   800  			expect: func(g *WithT, result interface{}) {
   801  				g.Expect(result).To(BeNil())
   802  			},
   803  			expectedError: "reconcile error that cannot be recovered occurred: vTpmEnabled should be true when securityEncryptionType is set. Object will not be requeued",
   804  		},
   805  		{
   806  			name: "creating a confidential vm with unsupported VM type fails",
   807  			spec: &VMSpec{
   808  				Name:              "my-vm",
   809  				Role:              infrav1.Node,
   810  				NICIDs:            []string{"my-nic"},
   811  				SSHKeyData:        "fakesshpublickey",
   812  				Size:              "Standard_D2v3",
   813  				AvailabilitySetID: "fake-availability-set-id",
   814  				Zone:              "",
   815  				Image:             &infrav1.Image{ID: ptr.To("fake-image-id")},
   816  				OSDisk: infrav1.OSDisk{
   817  					OSType:     "Linux",
   818  					DiskSizeGB: ptr.To[int32](128),
   819  					ManagedDisk: &infrav1.ManagedDiskParameters{
   820  						StorageAccountType: string(armcompute.StorageAccountTypesPremiumLRS),
   821  						SecurityProfile: &infrav1.VMDiskSecurityProfile{
   822  							SecurityEncryptionType: infrav1.SecurityEncryptionTypeVMGuestStateOnly,
   823  						},
   824  					},
   825  				},
   826  				SecurityProfile: &infrav1.SecurityProfile{
   827  					SecurityType: infrav1.SecurityTypesConfidentialVM,
   828  					UefiSettings: &infrav1.UefiSettings{
   829  						VTpmEnabled: ptr.To(true),
   830  					},
   831  				},
   832  				SKU: validSKU,
   833  			},
   834  			existing: nil,
   835  			expect: func(g *WithT, result interface{}) {
   836  				g.Expect(result).To(BeNil())
   837  			},
   838  			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",
   839  		},
   840  		{
   841  			name: "cannot create vm with EphemeralOSDisk if does not support ephemeral os",
   842  			spec: &VMSpec{
   843  				Name:       "my-vm",
   844  				Role:       infrav1.Node,
   845  				NICIDs:     []string{"my-nic"},
   846  				SSHKeyData: "fakesshpublickey",
   847  				Size:       "Standard_D2v3",
   848  				OSDisk: infrav1.OSDisk{
   849  					OSType:     "Linux",
   850  					DiskSizeGB: ptr.To[int32](128),
   851  					ManagedDisk: &infrav1.ManagedDiskParameters{
   852  						StorageAccountType: string(armcompute.StorageAccountTypesPremiumLRS),
   853  					},
   854  					DiffDiskSettings: &infrav1.DiffDiskSettings{
   855  						Option: string(armcompute.DiffDiskOptionsLocal),
   856  					},
   857  				},
   858  				Image: &infrav1.Image{ID: ptr.To("fake-image-id")},
   859  				SKU:   validSKU,
   860  			},
   861  			existing: nil,
   862  			expect: func(g *WithT, result interface{}) {
   863  				g.Expect(result).To(BeNil())
   864  			},
   865  			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",
   866  		},
   867  		{
   868  			name: "cannot create vm if vCPU is less than 2",
   869  			spec: &VMSpec{
   870  				Name:       "my-vm",
   871  				Role:       infrav1.Node,
   872  				NICIDs:     []string{"my-nic"},
   873  				SSHKeyData: "fakesshpublickey",
   874  				Size:       "Standard_D2v3",
   875  				Image:      &infrav1.Image{ID: ptr.To("fake-image-id")},
   876  				SKU:        invalidCPUSKU,
   877  			},
   878  			existing: nil,
   879  			expect: func(g *WithT, result interface{}) {
   880  				g.Expect(result).To(BeNil())
   881  			},
   882  			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",
   883  		},
   884  		{
   885  			name: "cannot create vm if memory is less than 2Gi",
   886  			spec: &VMSpec{
   887  				Name:       "my-vm",
   888  				Role:       infrav1.Node,
   889  				NICIDs:     []string{"my-nic"},
   890  				SSHKeyData: "fakesshpublickey",
   891  				Size:       "Standard_D2v3",
   892  				Image:      &infrav1.Image{ID: ptr.To("fake-image-id")},
   893  				SKU:        invalidMemSKU,
   894  			},
   895  			existing: nil,
   896  			expect: func(g *WithT, result interface{}) {
   897  				g.Expect(result).To(BeNil())
   898  			},
   899  			expectedError: "reconcile error that cannot be recovered occurred: VM memory should be bigger or equal to at least 2Gi. Object will not be requeued",
   900  		},
   901  		{
   902  			name: "can create a vm with a marketplace image using a plan",
   903  			spec: &VMSpec{
   904  				Name:       "my-vm",
   905  				Role:       infrav1.Node,
   906  				NICIDs:     []string{"my-nic"},
   907  				SSHKeyData: "fakesshpublickey",
   908  				Size:       "Standard_D2v3",
   909  				Image: &infrav1.Image{
   910  					Marketplace: &infrav1.AzureMarketplaceImage{
   911  						ImagePlan: infrav1.ImagePlan{
   912  							Publisher: "fake-publisher",
   913  							Offer:     "my-offer",
   914  							SKU:       "sku-id",
   915  						},
   916  						Version:         "1.0",
   917  						ThirdPartyImage: true,
   918  					},
   919  				},
   920  				SKU: validSKU,
   921  			},
   922  			existing: nil,
   923  			expect: func(g *WithT, result interface{}) {
   924  				g.Expect(result).To(BeAssignableToTypeOf(armcompute.VirtualMachine{}))
   925  				g.Expect(result.(armcompute.VirtualMachine).Properties.StorageProfile.ImageReference.Offer).To(Equal(ptr.To("my-offer")))
   926  				g.Expect(result.(armcompute.VirtualMachine).Properties.StorageProfile.ImageReference.Publisher).To(Equal(ptr.To("fake-publisher")))
   927  				g.Expect(result.(armcompute.VirtualMachine).Properties.StorageProfile.ImageReference.SKU).To(Equal(ptr.To("sku-id")))
   928  				g.Expect(result.(armcompute.VirtualMachine).Properties.StorageProfile.ImageReference.Version).To(Equal(ptr.To("1.0")))
   929  				g.Expect(result.(armcompute.VirtualMachine).Plan.Name).To(Equal(ptr.To("sku-id")))
   930  				g.Expect(result.(armcompute.VirtualMachine).Plan.Publisher).To(Equal(ptr.To("fake-publisher")))
   931  				g.Expect(result.(armcompute.VirtualMachine).Plan.Product).To(Equal(ptr.To("my-offer")))
   932  			},
   933  			expectedError: "",
   934  		},
   935  		{
   936  			name: "can create a vm with a SIG image using a plan",
   937  			spec: &VMSpec{
   938  				Name:       "my-vm",
   939  				Role:       infrav1.Node,
   940  				NICIDs:     []string{"my-nic"},
   941  				SSHKeyData: "fakesshpublickey",
   942  				Size:       "Standard_D2v3",
   943  				Image: &infrav1.Image{
   944  					SharedGallery: &infrav1.AzureSharedGalleryImage{
   945  						SubscriptionID: "fake-sub-id",
   946  						ResourceGroup:  "fake-rg",
   947  						Gallery:        "fake-gallery",
   948  						Name:           "fake-name",
   949  						Version:        "1.0",
   950  						Publisher:      ptr.To("fake-publisher"),
   951  						Offer:          ptr.To("my-offer"),
   952  						SKU:            ptr.To("sku-id"),
   953  					},
   954  				},
   955  				SKU: validSKU,
   956  			},
   957  			existing: nil,
   958  			expect: func(g *WithT, result interface{}) {
   959  				g.Expect(result).To(BeAssignableToTypeOf(armcompute.VirtualMachine{}))
   960  				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")))
   961  				g.Expect(result.(armcompute.VirtualMachine).Plan.Name).To(Equal(ptr.To("sku-id")))
   962  				g.Expect(result.(armcompute.VirtualMachine).Plan.Publisher).To(Equal(ptr.To("fake-publisher")))
   963  				g.Expect(result.(armcompute.VirtualMachine).Plan.Product).To(Equal(ptr.To("my-offer")))
   964  			},
   965  			expectedError: "",
   966  		},
   967  		{
   968  			name: "can create a vm with ultra disk enabled",
   969  			spec: &VMSpec{
   970  				Name:       "my-ultra-ssd-vm",
   971  				Role:       infrav1.Node,
   972  				NICIDs:     []string{"my-nic"},
   973  				SSHKeyData: "fakesshpublickey",
   974  				Size:       "Standard_D2v3",
   975  				Location:   "test-location",
   976  				Zone:       "1",
   977  				Image:      &infrav1.Image{ID: ptr.To("fake-image-id")},
   978  				DataDisks: []infrav1.DataDisk{
   979  					{
   980  						NameSuffix: "mydisk",
   981  						DiskSizeGB: 64,
   982  						Lun:        ptr.To[int32](0),
   983  					},
   984  					{
   985  						NameSuffix: "myDiskWithUltraDisk",
   986  						DiskSizeGB: 128,
   987  						Lun:        ptr.To[int32](1),
   988  						ManagedDisk: &infrav1.ManagedDiskParameters{
   989  							StorageAccountType: string(armcompute.StorageAccountTypesUltraSSDLRS),
   990  						},
   991  					},
   992  					{
   993  						NameSuffix: "myDiskWithManagedDisk",
   994  						DiskSizeGB: 128,
   995  						Lun:        ptr.To[int32](2),
   996  						ManagedDisk: &infrav1.ManagedDiskParameters{
   997  							StorageAccountType: string(armcompute.StorageAccountTypesPremiumLRS),
   998  						},
   999  					},
  1000  					{
  1001  						NameSuffix: "managedDiskWithEncryption",
  1002  						DiskSizeGB: 128,
  1003  						Lun:        ptr.To[int32](3),
  1004  						ManagedDisk: &infrav1.ManagedDiskParameters{
  1005  							StorageAccountType: string(armcompute.StorageAccountTypesPremiumLRS),
  1006  							DiskEncryptionSet: &infrav1.DiskEncryptionSetParameters{
  1007  								ID: "my_id",
  1008  							},
  1009  						},
  1010  					},
  1011  				},
  1012  				SKU: validSKUWithUltraSSD,
  1013  			},
  1014  			existing: nil,
  1015  			expect: func(g *WithT, result interface{}) {
  1016  				g.Expect(result).To(BeAssignableToTypeOf(armcompute.VirtualMachine{}))
  1017  				g.Expect(result.(armcompute.VirtualMachine).Properties.AdditionalCapabilities.UltraSSDEnabled).To(Equal(ptr.To(true)))
  1018  				expectedDataDisks := []*armcompute.DataDisk{
  1019  					{
  1020  						Lun:          ptr.To[int32](0),
  1021  						Name:         ptr.To("my-ultra-ssd-vm_mydisk"),
  1022  						CreateOption: ptr.To(armcompute.DiskCreateOptionTypesEmpty),
  1023  						DiskSizeGB:   ptr.To[int32](64),
  1024  					},
  1025  					{
  1026  						Lun:          ptr.To[int32](1),
  1027  						Name:         ptr.To("my-ultra-ssd-vm_myDiskWithUltraDisk"),
  1028  						CreateOption: ptr.To(armcompute.DiskCreateOptionTypesEmpty),
  1029  						DiskSizeGB:   ptr.To[int32](128),
  1030  						ManagedDisk: &armcompute.ManagedDiskParameters{
  1031  							StorageAccountType: ptr.To(armcompute.StorageAccountTypesUltraSSDLRS),
  1032  						},
  1033  					},
  1034  					{
  1035  						Lun:          ptr.To[int32](2),
  1036  						Name:         ptr.To("my-ultra-ssd-vm_myDiskWithManagedDisk"),
  1037  						CreateOption: ptr.To(armcompute.DiskCreateOptionTypesEmpty),
  1038  						DiskSizeGB:   ptr.To[int32](128),
  1039  						ManagedDisk: &armcompute.ManagedDiskParameters{
  1040  							StorageAccountType: ptr.To(armcompute.StorageAccountTypesPremiumLRS),
  1041  						},
  1042  					},
  1043  					{
  1044  						Lun:          ptr.To[int32](3),
  1045  						Name:         ptr.To("my-ultra-ssd-vm_managedDiskWithEncryption"),
  1046  						CreateOption: ptr.To(armcompute.DiskCreateOptionTypesEmpty),
  1047  						DiskSizeGB:   ptr.To[int32](128),
  1048  						ManagedDisk: &armcompute.ManagedDiskParameters{
  1049  							StorageAccountType: ptr.To(armcompute.StorageAccountTypesPremiumLRS),
  1050  							DiskEncryptionSet: &armcompute.DiskEncryptionSetParameters{
  1051  								ID: ptr.To("my_id"),
  1052  							},
  1053  						},
  1054  					},
  1055  				}
  1056  				g.Expect(gomockinternal.DiffEq(expectedDataDisks).Matches(result.(armcompute.VirtualMachine).Properties.StorageProfile.DataDisks)).To(BeTrue(), cmp.Diff(expectedDataDisks, result.(armcompute.VirtualMachine).Properties.StorageProfile.DataDisks))
  1057  			},
  1058  			expectedError: "",
  1059  		},
  1060  		{
  1061  			name: "creating vm with ultra disk enabled in unsupported location fails",
  1062  			spec: &VMSpec{
  1063  				Name:       "my-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  				DataDisks: []infrav1.DataDisk{
  1072  					{
  1073  						NameSuffix: "myDiskWithUltraDisk",
  1074  						DiskSizeGB: 128,
  1075  						Lun:        ptr.To[int32](1),
  1076  						ManagedDisk: &infrav1.ManagedDiskParameters{
  1077  							StorageAccountType: string(armcompute.StorageAccountTypesUltraSSDLRS),
  1078  						},
  1079  					},
  1080  				},
  1081  				SKU: validSKU,
  1082  			},
  1083  			existing: nil,
  1084  			expect: func(g *WithT, result interface{}) {
  1085  				g.Expect(result).To(BeNil())
  1086  			},
  1087  			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",
  1088  		},
  1089  		{
  1090  			name: "creates a vm with AdditionalCapabilities.UltraSSDEnabled false, if an ultra disk is specified as data disk but AdditionalCapabilities.UltraSSDEnabled is false",
  1091  			spec: &VMSpec{
  1092  				Name:       "my-ultra-ssd-vm",
  1093  				Role:       infrav1.Node,
  1094  				NICIDs:     []string{"my-nic"},
  1095  				SSHKeyData: "fakesshpublickey",
  1096  				Size:       "Standard_D2v3",
  1097  				Location:   "test-location",
  1098  				Zone:       "1",
  1099  				Image:      &infrav1.Image{ID: ptr.To("fake-image-id")},
  1100  				AdditionalCapabilities: &infrav1.AdditionalCapabilities{
  1101  					UltraSSDEnabled: ptr.To(false),
  1102  				},
  1103  				DataDisks: []infrav1.DataDisk{
  1104  					{
  1105  						NameSuffix: "myDiskWithUltraDisk",
  1106  						DiskSizeGB: 128,
  1107  						Lun:        ptr.To[int32](1),
  1108  						ManagedDisk: &infrav1.ManagedDiskParameters{
  1109  							StorageAccountType: string(armcompute.StorageAccountTypesUltraSSDLRS),
  1110  						},
  1111  					},
  1112  				},
  1113  				SKU: validSKUWithUltraSSD,
  1114  			},
  1115  			existing: nil,
  1116  			expect: func(g *WithT, result interface{}) {
  1117  				g.Expect(result).To(BeAssignableToTypeOf(armcompute.VirtualMachine{}))
  1118  				g.Expect(result.(armcompute.VirtualMachine).Properties.AdditionalCapabilities.UltraSSDEnabled).To(Equal(ptr.To(false)))
  1119  				expectedDataDisks := []*armcompute.DataDisk{
  1120  					{
  1121  						Lun:          ptr.To[int32](1),
  1122  						Name:         ptr.To("my-ultra-ssd-vm_myDiskWithUltraDisk"),
  1123  						CreateOption: ptr.To(armcompute.DiskCreateOptionTypesEmpty),
  1124  						DiskSizeGB:   ptr.To[int32](128),
  1125  						ManagedDisk: &armcompute.ManagedDiskParameters{
  1126  							StorageAccountType: ptr.To(armcompute.StorageAccountTypesUltraSSDLRS),
  1127  						},
  1128  					},
  1129  				}
  1130  				g.Expect(gomockinternal.DiffEq(expectedDataDisks).Matches(result.(armcompute.VirtualMachine).Properties.StorageProfile.DataDisks)).To(BeTrue(), cmp.Diff(expectedDataDisks, result.(armcompute.VirtualMachine).Properties.StorageProfile.DataDisks))
  1131  			},
  1132  			expectedError: "",
  1133  		},
  1134  		{
  1135  			name: "creates a vm with AdditionalCapabilities.UltraSSDEnabled true, if an ultra disk is specified as data disk and no AdditionalCapabilities.UltraSSDEnabled is set",
  1136  			spec: &VMSpec{
  1137  				Name:       "my-ultra-ssd-vm",
  1138  				Role:       infrav1.Node,
  1139  				NICIDs:     []string{"my-nic"},
  1140  				SSHKeyData: "fakesshpublickey",
  1141  				Size:       "Standard_D2v3",
  1142  				Location:   "test-location",
  1143  				Zone:       "1",
  1144  				Image:      &infrav1.Image{ID: ptr.To("fake-image-id")},
  1145  				DataDisks: []infrav1.DataDisk{
  1146  					{
  1147  						NameSuffix: "myDiskWithUltraDisk",
  1148  						DiskSizeGB: 128,
  1149  						Lun:        ptr.To[int32](1),
  1150  						ManagedDisk: &infrav1.ManagedDiskParameters{
  1151  							StorageAccountType: string(armcompute.StorageAccountTypesUltraSSDLRS),
  1152  						},
  1153  					},
  1154  				},
  1155  				SKU: validSKUWithUltraSSD,
  1156  			},
  1157  			existing: nil,
  1158  			expect: func(g *WithT, result interface{}) {
  1159  				g.Expect(result).To(BeAssignableToTypeOf(armcompute.VirtualMachine{}))
  1160  				g.Expect(result.(armcompute.VirtualMachine).Properties.AdditionalCapabilities.UltraSSDEnabled).To(Equal(ptr.To(true)))
  1161  				expectedDataDisks := []*armcompute.DataDisk{
  1162  					{
  1163  						Lun:          ptr.To[int32](1),
  1164  						Name:         ptr.To("my-ultra-ssd-vm_myDiskWithUltraDisk"),
  1165  						CreateOption: ptr.To(armcompute.DiskCreateOptionTypesEmpty),
  1166  						DiskSizeGB:   ptr.To[int32](128),
  1167  						ManagedDisk: &armcompute.ManagedDiskParameters{
  1168  							StorageAccountType: ptr.To(armcompute.StorageAccountTypesUltraSSDLRS),
  1169  						},
  1170  					},
  1171  				}
  1172  				g.Expect(gomockinternal.DiffEq(expectedDataDisks).Matches(result.(armcompute.VirtualMachine).Properties.StorageProfile.DataDisks)).To(BeTrue(), cmp.Diff(expectedDataDisks, result.(armcompute.VirtualMachine).Properties.StorageProfile.DataDisks))
  1173  			},
  1174  			expectedError: "",
  1175  		},
  1176  		{
  1177  			name: "creates a vm with AdditionalCapabilities.UltraSSDEnabled true, if an ultra disk is specified as data disk and AdditionalCapabilities.UltraSSDEnabled is true",
  1178  			spec: &VMSpec{
  1179  				Name:       "my-ultra-ssd-vm",
  1180  				Role:       infrav1.Node,
  1181  				NICIDs:     []string{"my-nic"},
  1182  				SSHKeyData: "fakesshpublickey",
  1183  				Size:       "Standard_D2v3",
  1184  				Location:   "test-location",
  1185  				Zone:       "1",
  1186  				Image:      &infrav1.Image{ID: ptr.To("fake-image-id")},
  1187  				AdditionalCapabilities: &infrav1.AdditionalCapabilities{
  1188  					UltraSSDEnabled: ptr.To(true),
  1189  				},
  1190  				DataDisks: []infrav1.DataDisk{
  1191  					{
  1192  						NameSuffix: "myDiskWithUltraDisk",
  1193  						DiskSizeGB: 128,
  1194  						Lun:        ptr.To[int32](1),
  1195  						ManagedDisk: &infrav1.ManagedDiskParameters{
  1196  							StorageAccountType: string(armcompute.StorageAccountTypesUltraSSDLRS),
  1197  						},
  1198  					},
  1199  				},
  1200  				SKU: validSKUWithUltraSSD,
  1201  			},
  1202  			existing: nil,
  1203  			expect: func(g *WithT, result interface{}) {
  1204  				g.Expect(result).To(BeAssignableToTypeOf(armcompute.VirtualMachine{}))
  1205  				g.Expect(result.(armcompute.VirtualMachine).Properties.AdditionalCapabilities.UltraSSDEnabled).To(Equal(ptr.To(true)))
  1206  				expectedDataDisks := []*armcompute.DataDisk{
  1207  					{
  1208  						Lun:          ptr.To[int32](1),
  1209  						Name:         ptr.To("my-ultra-ssd-vm_myDiskWithUltraDisk"),
  1210  						CreateOption: ptr.To(armcompute.DiskCreateOptionTypesEmpty),
  1211  						DiskSizeGB:   ptr.To[int32](128),
  1212  						ManagedDisk: &armcompute.ManagedDiskParameters{
  1213  							StorageAccountType: ptr.To(armcompute.StorageAccountTypesUltraSSDLRS),
  1214  						},
  1215  					},
  1216  				}
  1217  				g.Expect(gomockinternal.DiffEq(expectedDataDisks).Matches(result.(armcompute.VirtualMachine).Properties.StorageProfile.DataDisks)).To(BeTrue(), cmp.Diff(expectedDataDisks, result.(armcompute.VirtualMachine).Properties.StorageProfile.DataDisks))
  1218  			},
  1219  			expectedError: "",
  1220  		},
  1221  		{
  1222  			name: "creates a vm with AdditionalCapabilities.UltraSSDEnabled true, if no ultra disk is specified as data disk and AdditionalCapabilities.UltraSSDEnabled is true",
  1223  			spec: &VMSpec{
  1224  				Name:       "my-ultra-ssd-vm",
  1225  				Role:       infrav1.Node,
  1226  				NICIDs:     []string{"my-nic"},
  1227  				SSHKeyData: "fakesshpublickey",
  1228  				Size:       "Standard_D2v3",
  1229  				Location:   "test-location",
  1230  				Zone:       "1",
  1231  				Image:      &infrav1.Image{ID: ptr.To("fake-image-id")},
  1232  				AdditionalCapabilities: &infrav1.AdditionalCapabilities{
  1233  					UltraSSDEnabled: ptr.To(true),
  1234  				},
  1235  				SKU: validSKUWithUltraSSD,
  1236  			},
  1237  			existing: nil,
  1238  			expect: func(g *WithT, result interface{}) {
  1239  				g.Expect(result).To(BeAssignableToTypeOf(armcompute.VirtualMachine{}))
  1240  				g.Expect(result.(armcompute.VirtualMachine).Properties.AdditionalCapabilities.UltraSSDEnabled).To(Equal(ptr.To(true)))
  1241  			},
  1242  			expectedError: "",
  1243  		},
  1244  		{
  1245  			name: "creates a vm with AdditionalCapabilities.UltraSSDEnabled false, if no ultra disk is specified as data disk and AdditionalCapabilities.UltraSSDEnabled is false",
  1246  			spec: &VMSpec{
  1247  				Name:       "my-ultra-ssd-vm",
  1248  				Role:       infrav1.Node,
  1249  				NICIDs:     []string{"my-nic"},
  1250  				SSHKeyData: "fakesshpublickey",
  1251  				Size:       "Standard_D2v3",
  1252  				Location:   "test-location",
  1253  				Zone:       "1",
  1254  				Image:      &infrav1.Image{ID: ptr.To("fake-image-id")},
  1255  				AdditionalCapabilities: &infrav1.AdditionalCapabilities{
  1256  					UltraSSDEnabled: ptr.To(false),
  1257  				},
  1258  				SKU: validSKUWithUltraSSD,
  1259  			},
  1260  			existing: nil,
  1261  			expect: func(g *WithT, result interface{}) {
  1262  				g.Expect(result).To(BeAssignableToTypeOf(armcompute.VirtualMachine{}))
  1263  				g.Expect(result.(armcompute.VirtualMachine).Properties.AdditionalCapabilities.UltraSSDEnabled).To(Equal(ptr.To(false)))
  1264  			},
  1265  			expectedError: "",
  1266  		},
  1267  		{
  1268  			name: "creates a vm with Diagnostics disabled",
  1269  			spec: &VMSpec{
  1270  				Name:       "my-ultra-ssd-vm",
  1271  				Role:       infrav1.Node,
  1272  				NICIDs:     []string{"my-nic"},
  1273  				SSHKeyData: "fakesshpublickey",
  1274  				Size:       "Standard_D2v3",
  1275  				Location:   "test-location",
  1276  				Zone:       "1",
  1277  				Image:      &infrav1.Image{ID: ptr.To("fake-image-id")},
  1278  				DiagnosticsProfile: &infrav1.Diagnostics{
  1279  					Boot: &infrav1.BootDiagnostics{
  1280  						StorageAccountType: infrav1.DisabledDiagnosticsStorage,
  1281  					},
  1282  				},
  1283  				SKU: validSKUWithUltraSSD,
  1284  			},
  1285  			existing: nil,
  1286  			expect: func(g *WithT, result interface{}) {
  1287  				g.Expect(result).To(BeAssignableToTypeOf(armcompute.VirtualMachine{}))
  1288  				g.Expect(result.(armcompute.VirtualMachine).Properties.DiagnosticsProfile.BootDiagnostics.Enabled).To(Equal(ptr.To(false)))
  1289  				g.Expect(result.(armcompute.VirtualMachine).Properties.DiagnosticsProfile.BootDiagnostics.StorageURI).To(BeNil())
  1290  			},
  1291  			expectedError: "",
  1292  		},
  1293  		{
  1294  			name: "creates a vm with Managed Diagnostics enabled",
  1295  			spec: &VMSpec{
  1296  				Name:       "my-ultra-ssd-vm",
  1297  				Role:       infrav1.Node,
  1298  				NICIDs:     []string{"my-nic"},
  1299  				SSHKeyData: "fakesshpublickey",
  1300  				Size:       "Standard_D2v3",
  1301  				Location:   "test-location",
  1302  				Zone:       "1",
  1303  				Image:      &infrav1.Image{ID: ptr.To("fake-image-id")},
  1304  				DiagnosticsProfile: &infrav1.Diagnostics{
  1305  					Boot: &infrav1.BootDiagnostics{
  1306  						StorageAccountType: infrav1.ManagedDiagnosticsStorage,
  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(BeNil())
  1316  			},
  1317  			expectedError: "",
  1318  		},
  1319  		{
  1320  			name: "creates a vm with User Managed Diagnostics enabled",
  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  			name: "creates a vm with User Managed Diagnostics enabled, but missing StorageAccountURI",
  1350  			spec: &VMSpec{
  1351  				Name:       "my-ultra-ssd-vm",
  1352  				Role:       infrav1.Node,
  1353  				NICIDs:     []string{"my-nic"},
  1354  				SSHKeyData: "fakesshpublickey",
  1355  				Size:       "Standard_D2v3",
  1356  				Location:   "test-location",
  1357  				Zone:       "1",
  1358  				Image:      &infrav1.Image{ID: ptr.To("fake-image-id")},
  1359  				DiagnosticsProfile: &infrav1.Diagnostics{
  1360  					Boot: &infrav1.BootDiagnostics{
  1361  						StorageAccountType: infrav1.UserManagedDiagnosticsStorage,
  1362  						UserManaged: &infrav1.UserManagedBootDiagnostics{
  1363  							StorageAccountURI: "aaa",
  1364  						},
  1365  					},
  1366  				},
  1367  				SKU: validSKUWithUltraSSD,
  1368  			},
  1369  			existing: nil,
  1370  			expect: func(g *WithT, result interface{}) {
  1371  				g.Expect(result).To(BeAssignableToTypeOf(armcompute.VirtualMachine{}))
  1372  				g.Expect(result.(armcompute.VirtualMachine).Properties.DiagnosticsProfile.BootDiagnostics.Enabled).To(Equal(ptr.To(true)))
  1373  				g.Expect(result.(armcompute.VirtualMachine).Properties.DiagnosticsProfile.BootDiagnostics.StorageURI).To(Equal(ptr.To("aaa")))
  1374  			},
  1375  			expectedError: "",
  1376  		},
  1377  		{
  1378  			name: "creates a vm and associate it with a capacity reservation group",
  1379  			spec: &VMSpec{
  1380  				Name:                       "my-vm",
  1381  				Role:                       infrav1.Node,
  1382  				NICIDs:                     []string{"my-nic"},
  1383  				SSHKeyData:                 "fakesshpublickey",
  1384  				Size:                       "Standard_D2v3",
  1385  				Location:                   "test-location",
  1386  				Zone:                       "1",
  1387  				Image:                      &infrav1.Image{ID: ptr.To("fake-image-id")},
  1388  				CapacityReservationGroupID: "my-crg-id",
  1389  				SKU:                        validSKU,
  1390  			},
  1391  			existing: nil,
  1392  			expect: func(g *WithT, result interface{}) {
  1393  				g.Expect(result).To(BeAssignableToTypeOf(armcompute.VirtualMachine{}))
  1394  				g.Expect(result.(armcompute.VirtualMachine).Properties.CapacityReservation.CapacityReservationGroup.ID).To(Equal(ptr.To("my-crg-id")))
  1395  			},
  1396  			expectedError: "",
  1397  		},
  1398  		{
  1399  			name: "creates a vm without capacity reservation group",
  1400  			spec: &VMSpec{
  1401  				Name:                       "my-vm",
  1402  				Role:                       infrav1.Node,
  1403  				NICIDs:                     []string{"my-nic"},
  1404  				SSHKeyData:                 "fakesshpublickey",
  1405  				Size:                       "Standard_D2v3",
  1406  				Location:                   "test-location",
  1407  				Zone:                       "1",
  1408  				Image:                      &infrav1.Image{ID: ptr.To("fake-image-id")},
  1409  				CapacityReservationGroupID: "",
  1410  				SKU:                        validSKU,
  1411  			},
  1412  			existing: nil,
  1413  			expect: func(g *WithT, result interface{}) {
  1414  				g.Expect(result).To(BeAssignableToTypeOf(armcompute.VirtualMachine{}))
  1415  				g.Expect(result.(armcompute.VirtualMachine).Properties.CapacityReservation).To(BeNil())
  1416  			},
  1417  			expectedError: "",
  1418  		},
  1419  	}
  1420  	for _, tc := range testcases {
  1421  		tc := tc
  1422  		t.Run(tc.name, func(t *testing.T) {
  1423  			g := NewWithT(t)
  1424  			t.Parallel()
  1425  
  1426  			result, err := tc.spec.Parameters(context.TODO(), tc.existing)
  1427  			if tc.expectedError != "" {
  1428  				g.Expect(err).To(HaveOccurred())
  1429  				g.Expect(err).To(MatchError(tc.expectedError))
  1430  			} else {
  1431  				g.Expect(err).NotTo(HaveOccurred())
  1432  			}
  1433  			tc.expect(g, result)
  1434  		})
  1435  	}
  1436  }