diff --git a/server/src/main/java/org/apache/cloudstack/backup/BackupManagerImpl.java b/server/src/main/java/org/apache/cloudstack/backup/BackupManagerImpl.java index ec87980e03a4..c4625ab85153 100644 --- a/server/src/main/java/org/apache/cloudstack/backup/BackupManagerImpl.java +++ b/server/src/main/java/org/apache/cloudstack/backup/BackupManagerImpl.java @@ -441,6 +441,13 @@ public boolean assignVMToBackupOffering(Long vmId, Long offeringId) { throw new CloudRuntimeException("VM is not in running or stopped state"); } + List volumes = volumeDao.findByInstance(vmId); + for (VolumeVO volume : volumes) { + if (volume != null && volume.getPassphraseId() != null) { + throw new CloudRuntimeException("VM has encrypted volumes, backup offering assignment is not allowed"); + } + } + validateBackupForZone(vm.getDataCenterId()); accountManager.checkAccess(CallContext.current().getCallingAccount(), null, true, vm); diff --git a/server/src/test/java/org/apache/cloudstack/backup/BackupManagerTest.java b/server/src/test/java/org/apache/cloudstack/backup/BackupManagerTest.java index db75602b600d..8acbed152597 100644 --- a/server/src/test/java/org/apache/cloudstack/backup/BackupManagerTest.java +++ b/server/src/test/java/org/apache/cloudstack/backup/BackupManagerTest.java @@ -1217,6 +1217,14 @@ public void testAssignVMToBackupOffering() { when(vm.getDataCenterId()).thenReturn(1L); when(vm.getBackupOfferingId()).thenReturn(null); when(offering.getProvider()).thenReturn("testbackupprovider"); + VolumeVO volume = mock(VolumeVO.class); + when(volumeDao.findByInstance(vmId)).thenReturn(List.of(volume)); + when(volume.getPassphraseId()).thenReturn(null); + Long diskOfferingId = 5L; + when(volume.getDiskOfferingId()).thenReturn(diskOfferingId); + DiskOfferingVO diskOffering = Mockito.mock(DiskOfferingVO.class); + Mockito.when(diskOffering.getUuid()).thenReturn("disk-offering-uuid"); + Mockito.when(diskOfferingDao.findById(diskOfferingId)).thenReturn(diskOffering); when(backupProvider.assignVMToBackupOffering(vm, offering)).thenReturn(true); when(vmInstanceDao.update(1L, vm)).thenReturn(true); @@ -1225,11 +1233,32 @@ public void testAssignVMToBackupOffering() { assertTrue(result); verify(vmInstanceDao, times(1)).findById(vmId); + verify(volumeDao, times(2)).findByInstance(vmId); verify(backupOfferingDao, times(1)).findById(offeringId); verify(backupManager, times(1)).getBackupProvider("testbackupprovider"); } } + @Test (expected = CloudRuntimeException.class) + public void testAssignVMToBackupOfferingForVMWithEncryptedVolumes() { + Long vmId = 1L; + Long offeringId = 2L; + + VMInstanceVO vm = mock(VMInstanceVO.class); + overrideBackupFrameworkConfigValue(); + + when(vmInstanceDao.findById(vmId)).thenReturn(vm); + when(vm.getState()).thenReturn(VirtualMachine.State.Running); + VolumeVO volume = mock(VolumeVO.class); + when(volumeDao.findByInstance(vmId)).thenReturn(List.of(volume)); + when(volume.getPassphraseId()).thenReturn(42L); + + try (MockedStatic ignored2 = Mockito.mockStatic(UsageEventUtils.class)) { + backupManager.assignVMToBackupOffering(vmId, offeringId); + verify(vmInstanceDao, times(1)).findById(vmId); + } + } + @Test public void testRemoveVMFromBackupOffering() { Long vmId = 1L;