Skip to content

Commit 414d9c1

Browse files
author
kunal.behbudzade
committed
KVM: fail unsupported disk-only snapshots cleanly
Move the VM snapshot create transition before host capability validation so validation failures can be marked failed instead of leaving allocated snapshots behind. Add regression coverage for the NVRAM capability validation path and verify that no agent command is sent after the early failure.
1 parent a4d9825 commit 414d9c1

2 files changed

Lines changed: 34 additions & 2 deletions

File tree

engine/storage/snapshot/src/main/java/org/apache/cloudstack/storage/vmsnapshot/KvmFileBasedStorageVmSnapshotStrategy.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -522,13 +522,13 @@ protected VMSnapshot takeVmSnapshotInternal(VMSnapshot vmSnapshot, Map<VolumeInf
522522

523523
logger.info("Starting disk-only VM snapshot process for VM [{}].", userVm.getUuid());
524524

525+
transitStateWithoutThrow(vmSnapshot, VMSnapshot.Event.CreateRequested);
526+
525527
Long hostId = pickHostForUefiNvramAwareDiskOnlySnapshot(userVm, "create");
526528
validateHostSupportsUefiNvramAwareDiskOnlySnapshots(hostId, userVm, "create");
527529
VMSnapshotVO vmSnapshotVO = (VMSnapshotVO) vmSnapshot;
528530
List<VolumeObjectTO> volumeTOs = vmSnapshotHelper.getVolumeTOList(userVm.getId());
529531

530-
transitStateWithoutThrow(vmSnapshot, VMSnapshot.Event.CreateRequested);
531-
532532
VMSnapshotTO parentSnapshotTo = null;
533533
VMSnapshotVO parentSnapshotVo = vmSnapshotDao.findCurrentSnapshotByVmId(userVm.getId());
534534
if (parentSnapshotVo != null) {

engine/storage/snapshot/src/test/java/org/apache/cloudstack/storage/vmsnapshot/KvmFileBasedStorageVmSnapshotStrategyTest.java

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
import static org.mockito.ArgumentMatchers.argThat;
2828
import static org.mockito.ArgumentMatchers.eq;
2929
import static org.mockito.Mockito.doNothing;
30+
import static org.mockito.Mockito.inOrder;
3031
import static org.mockito.Mockito.mock;
3132
import static org.mockito.Mockito.never;
3233
import static org.mockito.Mockito.verify;
@@ -49,6 +50,7 @@
4950
import org.junit.Before;
5051
import org.junit.Test;
5152
import org.mockito.ArgumentCaptor;
53+
import org.mockito.InOrder;
5254
import org.mockito.Mockito;
5355

5456
import com.cloud.agent.AgentManager;
@@ -385,6 +387,36 @@ public void testTakeVmSnapshotInternalFailsWhenHostLacksNvramAwareSnapshotCapabi
385387
strategy.takeVmSnapshotInternal(vmSnapshot, Collections.emptyMap());
386388
}
387389

390+
@Test(expected = CloudRuntimeException.class)
391+
public void testTakeVMSnapshotMarksSnapshotFailedWhenHostCapabilityValidationFails() throws Exception {
392+
long vmId = 10L;
393+
long hostId = 40L;
394+
395+
UserVmVO userVm = mock(UserVmVO.class);
396+
VMSnapshotVO vmSnapshot = mock(VMSnapshotVO.class);
397+
398+
when(vmSnapshot.getVmId()).thenReturn(vmId);
399+
when(userVm.getId()).thenReturn(vmId);
400+
when(userVm.getUuid()).thenReturn("vm-uuid");
401+
when(userVm.getState()).thenReturn(VirtualMachine.State.Running);
402+
when(strategy.userVmDao.findById(vmId)).thenReturn(userVm);
403+
when(vmSnapshotHelper.pickRunningHost(vmId)).thenReturn(hostId);
404+
when(strategy.vmInstanceDetailsDao.findDetail(vmId, ApiConstants.BootType.UEFI.toString()))
405+
.thenReturn(new VMInstanceDetailVO(vmId, ApiConstants.BootType.UEFI.toString(), "SECURE", true));
406+
when(hostDetailsDao.findDetail(hostId, Host.HOST_UEFI_ENABLE))
407+
.thenReturn(new DetailVO(hostId, Host.HOST_UEFI_ENABLE, Boolean.TRUE.toString()));
408+
when(hostDetailsDao.findDetail(hostId, Host.HOST_KVM_DISK_ONLY_VM_SNAPSHOT_NVRAM)).thenReturn(null);
409+
410+
try {
411+
strategy.takeVMSnapshot(vmSnapshot);
412+
} finally {
413+
InOrder inOrder = inOrder(vmSnapshotHelper);
414+
inOrder.verify(vmSnapshotHelper).vmSnapshotStateTransitTo(vmSnapshot, VMSnapshot.Event.CreateRequested);
415+
inOrder.verify(vmSnapshotHelper).vmSnapshotStateTransitTo(vmSnapshot, VMSnapshot.Event.OperationFailed);
416+
verify(agentMgr, never()).easySend(eq(hostId), any());
417+
}
418+
}
419+
388420
@Test(expected = CloudRuntimeException.class)
389421
public void testDeleteVMSnapshotFailsWhenHostLacksNvramAwareCleanupCapabilityForSidecarSnapshot() {
390422
long vmId = 10L;

0 commit comments

Comments
 (0)