@@ -11,11 +11,13 @@ import (
1111 "github.com/Azure/go-autorest/autorest"
1212 "github.com/golang/mock/gomock"
1313 . "github.com/onsi/gomega"
14+ configv1 "github.com/openshift/api/config/v1"
1415 machinev1 "github.com/openshift/api/machine/v1beta1"
1516 machinecontroller "github.com/openshift/machine-api-operator/pkg/controller/machine"
1617 "github.com/openshift/machine-api-provider-azure/pkg/cloud/azure"
1718 "github.com/openshift/machine-api-provider-azure/pkg/cloud/azure/actuators"
1819 mock_azure "github.com/openshift/machine-api-provider-azure/pkg/cloud/azure/mock"
20+ "github.com/openshift/machine-api-provider-azure/pkg/cloud/azure/services/disks"
1921 "github.com/openshift/machine-api-provider-azure/pkg/cloud/azure/services/networkinterfaces"
2022 "k8s.io/apimachinery/pkg/api/resource"
2123 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
@@ -205,9 +207,11 @@ func TestSetMachineCloudProviderSpecificsTable(t *testing.T) {
205207 expectedSpecLabels map [string ]string
206208 }{
207209 {
208- name : "with a blank vm" ,
209- scope : func (t * testing.T ) * actuators.MachineScope { return newFakeScope (t , "worker" ) },
210- vm : armcompute.VirtualMachine {},
210+ name : "with a blank vm" ,
211+ scope : func (t * testing.T ) * actuators.MachineScope {
212+ return newFakeMachineScope (t , "worker" , string (configv1 .AzurePublicCloud ))
213+ },
214+ vm : armcompute.VirtualMachine {},
211215 expectedLabels : map [string ]string {
212216 actuators .MachineRoleLabel : "worker" ,
213217 machinev1 .MachineClusterIDLabel : "clusterID" ,
@@ -218,8 +222,10 @@ func TestSetMachineCloudProviderSpecificsTable(t *testing.T) {
218222 expectedSpecLabels : nil ,
219223 },
220224 {
221- name : "with a running vm" ,
222- scope : func (t * testing.T ) * actuators.MachineScope { return newFakeScope (t , "good-worker" ) },
225+ name : "with a running vm" ,
226+ scope : func (t * testing.T ) * actuators.MachineScope {
227+ return newFakeMachineScope (t , "good-worker" , string (configv1 .AzurePublicCloud ))
228+ },
223229 vm : armcompute.VirtualMachine {
224230 Properties : & armcompute.VirtualMachineProperties {
225231 ProvisioningState : ptr.To [string ]("Running" ),
@@ -235,8 +241,10 @@ func TestSetMachineCloudProviderSpecificsTable(t *testing.T) {
235241 expectedSpecLabels : nil ,
236242 },
237243 {
238- name : "with a VMSize set vm" ,
239- scope : func (t * testing.T ) * actuators.MachineScope { return newFakeScope (t , "sized-worker" ) },
244+ name : "with a VMSize set vm" ,
245+ scope : func (t * testing.T ) * actuators.MachineScope {
246+ return newFakeMachineScope (t , "sized-worker" , string (configv1 .AzurePublicCloud ))
247+ },
240248 vm : armcompute.VirtualMachine {
241249 Properties : & armcompute.VirtualMachineProperties {
242250 HardwareProfile : & armcompute.HardwareProfile {
@@ -255,8 +263,10 @@ func TestSetMachineCloudProviderSpecificsTable(t *testing.T) {
255263 expectedSpecLabels : nil ,
256264 },
257265 {
258- name : "with a vm location" ,
259- scope : func (t * testing.T ) * actuators.MachineScope { return newFakeScope (t , "located-worker" ) },
266+ name : "with a vm location" ,
267+ scope : func (t * testing.T ) * actuators.MachineScope {
268+ return newFakeMachineScope (t , "located-worker" , string (configv1 .AzurePublicCloud ))
269+ },
260270 vm : armcompute.VirtualMachine {
261271 Location : ptr.To [string ]("nowhere" ),
262272 },
@@ -271,8 +281,10 @@ func TestSetMachineCloudProviderSpecificsTable(t *testing.T) {
271281 expectedSpecLabels : nil ,
272282 },
273283 {
274- name : "with a vm with zones" ,
275- scope : func (t * testing.T ) * actuators.MachineScope { return newFakeScope (t , "zoned-worker" ) },
284+ name : "with a vm with zones" ,
285+ scope : func (t * testing.T ) * actuators.MachineScope {
286+ return newFakeMachineScope (t , "zoned-worker" , string (configv1 .AzurePublicCloud ))
287+ },
276288 vm : armcompute.VirtualMachine {
277289 Zones : abcZones ,
278290 },
@@ -287,8 +299,10 @@ func TestSetMachineCloudProviderSpecificsTable(t *testing.T) {
287299 expectedSpecLabels : nil ,
288300 },
289301 {
290- name : "with a vm with a faultdomain set" ,
291- scope : func (t * testing.T ) * actuators.MachineScope { return newFakeScope (t , "availabilityset-worker" ) },
302+ name : "with a vm with a faultdomain set" ,
303+ scope : func (t * testing.T ) * actuators.MachineScope {
304+ return newFakeMachineScope (t , "availabilityset-worker" , string (configv1 .AzurePublicCloud ))
305+ },
292306 vm : armcompute.VirtualMachine {
293307 Properties : & armcompute.VirtualMachineProperties {
294308 InstanceView : & armcompute.VirtualMachineInstanceView {
@@ -309,7 +323,7 @@ func TestSetMachineCloudProviderSpecificsTable(t *testing.T) {
309323 {
310324 name : "with a vm on spot" ,
311325 scope : func (t * testing.T ) * actuators.MachineScope {
312- scope := newFakeScope (t , "spot-worker" )
326+ scope := newFakeMachineScope (t , "spot-worker" , string ( configv1 . AzurePublicCloud ) )
313327 scope .MachineConfig .SpotVMOptions = & machinev1.SpotVMOptions {}
314328 return scope
315329 },
@@ -708,7 +722,9 @@ func TestMachineUpdateWithProvisionsngFailedNic(t *testing.T) {
708722
709723 testCtx := context .TODO ()
710724
711- scope := func (t * testing.T ) * actuators.MachineScope { return newFakeScope (t , "worker" ) }
725+ scope := func (t * testing.T ) * actuators.MachineScope {
726+ return newFakeMachineScope (t , "worker" , string (configv1 .AzurePublicCloud ))
727+ }
712728 r := newFakeReconcilerWithScope (t , scope (t ))
713729 r .networkInterfacesSvc = networkSvc
714730
@@ -744,3 +760,155 @@ func TestMachineUpdateWithProvisionsngFailedNic(t *testing.T) {
744760 })
745761 }
746762}
763+
764+ // TestStackHubDataDiskDeletion tests that data disks with DeletionPolicy=Delete are manually deleted on Azure Stack Hub
765+ func TestStackHubDataDiskDeletion (t * testing.T ) {
766+ testCases := []struct {
767+ name string
768+ isStackHub bool
769+ dataDisks []machinev1.DataDisk
770+ }{
771+ {
772+ name : "Stack Hub with single data disk with Delete policy" ,
773+ isStackHub : true ,
774+ dataDisks : []machinev1.DataDisk {
775+ {
776+ NameSuffix : "disk1" ,
777+ DiskSizeGB : 128 ,
778+ Lun : 0 ,
779+ DeletionPolicy : machinev1 .DiskDeletionPolicyTypeDelete ,
780+ ManagedDisk : machinev1.DataDiskManagedDiskParameters {StorageAccountType : machinev1 .StorageAccountPremiumLRS },
781+ },
782+ },
783+ },
784+ {
785+ name : "Stack Hub with multiple data disks with Delete policy" ,
786+ isStackHub : true ,
787+ dataDisks : []machinev1.DataDisk {
788+ {
789+ NameSuffix : "disk1" ,
790+ DiskSizeGB : 128 ,
791+ Lun : 0 ,
792+ DeletionPolicy : machinev1 .DiskDeletionPolicyTypeDelete ,
793+ ManagedDisk : machinev1.DataDiskManagedDiskParameters {StorageAccountType : machinev1 .StorageAccountPremiumLRS },
794+ },
795+ {
796+ NameSuffix : "disk2" ,
797+ DiskSizeGB : 256 ,
798+ Lun : 1 ,
799+ DeletionPolicy : machinev1 .DiskDeletionPolicyTypeDelete ,
800+ ManagedDisk : machinev1.DataDiskManagedDiskParameters {StorageAccountType : machinev1 .StorageAccountPremiumLRS },
801+ },
802+ },
803+ },
804+ {
805+ name : "Stack Hub with data disk with Detach policy" ,
806+ isStackHub : true ,
807+ dataDisks : []machinev1.DataDisk {
808+ {
809+ NameSuffix : "disk1" ,
810+ DiskSizeGB : 128 ,
811+ Lun : 0 ,
812+ DeletionPolicy : machinev1 .DiskDeletionPolicyTypeDetach ,
813+ ManagedDisk : machinev1.DataDiskManagedDiskParameters {StorageAccountType : machinev1 .StorageAccountPremiumLRS },
814+ },
815+ },
816+ },
817+ {
818+ name : "Stack Hub with mixed deletion policies" ,
819+ isStackHub : true ,
820+ dataDisks : []machinev1.DataDisk {
821+ {
822+ NameSuffix : "disk1" ,
823+ DiskSizeGB : 128 ,
824+ Lun : 0 ,
825+ DeletionPolicy : machinev1 .DiskDeletionPolicyTypeDelete ,
826+ ManagedDisk : machinev1.DataDiskManagedDiskParameters {StorageAccountType : machinev1 .StorageAccountPremiumLRS },
827+ },
828+ {
829+ NameSuffix : "disk2" ,
830+ DiskSizeGB : 256 ,
831+ Lun : 1 ,
832+ DeletionPolicy : machinev1 .DiskDeletionPolicyTypeDetach ,
833+ ManagedDisk : machinev1.DataDiskManagedDiskParameters {StorageAccountType : machinev1 .StorageAccountPremiumLRS },
834+ },
835+ },
836+ },
837+ {
838+ name : "Non-Stack Hub with data disks" ,
839+ isStackHub : false ,
840+ dataDisks : []machinev1.DataDisk {
841+ {
842+ NameSuffix : "disk1" ,
843+ DiskSizeGB : 128 ,
844+ Lun : 0 ,
845+ DeletionPolicy : machinev1 .DiskDeletionPolicyTypeDelete ,
846+ ManagedDisk : machinev1.DataDiskManagedDiskParameters {StorageAccountType : machinev1 .StorageAccountPremiumLRS },
847+ },
848+ },
849+ },
850+ }
851+
852+ for _ , tc := range testCases {
853+ t .Run (tc .name , func (t * testing.T ) {
854+ g := NewWithT (t )
855+ mockCtrl := gomock .NewController (t )
856+
857+ vmSvc := mock_azure .NewMockService (mockCtrl )
858+ disksSvc := mock_azure .NewMockService (mockCtrl )
859+ networkSvc := mock_azure .NewMockService (mockCtrl )
860+ availabilitySetsSvc := mock_azure .NewMockService (mockCtrl )
861+
862+ testCtx := context .TODO ()
863+
864+ platformType := string (configv1 .AzureStackCloud )
865+ if ! tc .isStackHub {
866+ platformType = string (configv1 .AzurePublicCloud )
867+ }
868+ scope := newFakeMachineScope (t , "worker" , platformType )
869+ scope .MachineConfig .DataDisks = tc .dataDisks
870+
871+ r := & Reconciler {
872+ scope : scope ,
873+ virtualMachinesSvc : vmSvc ,
874+ disksSvc : disksSvc ,
875+ networkInterfacesSvc : networkSvc ,
876+ availabilitySetsSvc : availabilitySetsSvc ,
877+ }
878+
879+ // Expect VM deletion
880+ vmSvc .EXPECT ().Delete (testCtx , gomock .Any ()).Return (nil ).Times (1 )
881+
882+ // Expect OS disk deletion - always happens
883+ expectedOSDiskName := azure .GenerateOSDiskName (scope .Machine .Name )
884+ disksSvc .EXPECT ().Delete (testCtx , gomock .Any ()).DoAndReturn (
885+ func (ctx context.Context , spec azure.Spec ) error {
886+ diskSpec , ok := spec .(* disks.Spec )
887+ g .Expect (ok ).To (BeTrue (), "spec should be a disk spec" )
888+ g .Expect (diskSpec .Name ).To (Equal (expectedOSDiskName ), "OS disk name should match" )
889+ return nil
890+ },
891+ ).Times (1 )
892+
893+ // Expect data disk deletions only for disks with Delete policy on Stack Hub
894+ if tc .isStackHub {
895+ for _ , disk := range tc .dataDisks {
896+ if disk .DeletionPolicy == machinev1 .DiskDeletionPolicyTypeDelete {
897+ expectedDataDiskName := azure .GenerateDataDiskName (scope .Machine .Name , disk .NameSuffix )
898+ disksSvc .EXPECT ().Delete (testCtx , gomock .Any ()).DoAndReturn (
899+ func (ctx context.Context , spec azure.Spec ) error {
900+ diskSpec , ok := spec .(* disks.Spec )
901+ g .Expect (ok ).To (BeTrue (), "spec should be a disk spec" )
902+ g .Expect (diskSpec .Name ).To (Equal (expectedDataDiskName ), "data disk name should match" )
903+ return nil
904+ },
905+ ).Times (1 )
906+ }
907+ }
908+ }
909+
910+ err := r .Delete (testCtx )
911+ g .Expect (err ).To (BeNil ())
912+ })
913+ }
914+ }
0 commit comments