Skip to content

Commit 7c3419e

Browse files
CSTACKEX-18_2: fixes for vm snapshot workflow
1 parent 7a0d61e commit 7c3419e

File tree

2 files changed

+61
-0
lines changed

2 files changed

+61
-0
lines changed

plugins/storage/volume/ontap/src/main/java/org/apache/cloudstack/storage/vmsnapshot/OntapVMSnapshotStrategy.java

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,34 @@ private boolean allVolumesOnOntapManagedStorage(long vmId) {
190190
return true;
191191
}
192192

193+
// ──────────────────────────────────────────────────────────────────────────
194+
// Per-Volume Snapshot (quiesce override)
195+
// ──────────────────────────────────────────────────────────────────────────
196+
197+
/**
198+
* Creates a per-volume disk snapshot as part of a VM snapshot operation.
199+
*
200+
* <p>Overrides the parent to ensure {@code quiescevm} is always {@code false}
201+
* in the per-volume snapshot payload. ONTAP handles quiescing at the VM level
202+
* via QEMU guest agent freeze/thaw in {@link #takeVMSnapshot}, so the
203+
* individual volume snapshot must not request quiescing again. Without this
204+
* override, {@link org.apache.cloudstack.storage.snapshot.DefaultSnapshotStrategy#takeSnapshot}
205+
* would reject the request with "can't handle quiescevm equal true for volume snapshot"
206+
* when the user selects the quiesce option in the UI.</p>
207+
*/
208+
@Override
209+
protected SnapshotInfo createDiskSnapshot(VMSnapshot vmSnapshot, List<SnapshotInfo> forRollback, VolumeInfo vol) {
210+
// Temporarily override the quiesce option to false for the per-volume snapshot
211+
VMSnapshotVO vmSnapshotVO = (VMSnapshotVO) vmSnapshot;
212+
VMSnapshotOptions originalOptions = vmSnapshotVO.getOptions();
213+
try {
214+
vmSnapshotVO.setOptions(new VMSnapshotOptions(false));
215+
return super.createDiskSnapshot(vmSnapshot, forRollback, vol);
216+
} finally {
217+
vmSnapshotVO.setOptions(originalOptions);
218+
}
219+
}
220+
193221
// ──────────────────────────────────────────────────────────────────────────
194222
// Take VM Snapshot
195223
// ──────────────────────────────────────────────────────────────────────────

plugins/storage/volume/ontap/src/test/java/org/apache/cloudstack/storage/vmsnapshot/OntapVMSnapshotStrategyTest.java

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -713,6 +713,39 @@ void testTakeVMSnapshot_QuiesceOverriddenToTrue() throws Exception {
713713
verify(agentMgr, times(2)).send(eq(HOST_ID), any(FreezeThawVMCommand.class));
714714
}
715715

716+
@Test
717+
void testTakeVMSnapshot_WithQuiesceTrue_SucceedsWithoutPayloadRejection() throws Exception {
718+
VMSnapshotVO vmSnapshot = createTakeSnapshotVmSnapshot();
719+
// Explicitly set quiesce to TRUE — this is the scenario that was failing
720+
VMSnapshotOptions options = new VMSnapshotOptions(true);
721+
when(vmSnapshot.getOptions()).thenReturn(options);
722+
723+
setupTakeSnapshotCommon(vmSnapshot);
724+
setupSingleVolumeForTakeSnapshot();
725+
726+
FreezeThawVMAnswer freezeAnswer = mock(FreezeThawVMAnswer.class);
727+
when(freezeAnswer.getResult()).thenReturn(true);
728+
FreezeThawVMAnswer thawAnswer = mock(FreezeThawVMAnswer.class);
729+
when(thawAnswer.getResult()).thenReturn(true);
730+
when(agentMgr.send(eq(HOST_ID), any(FreezeThawVMCommand.class)))
731+
.thenReturn(freezeAnswer)
732+
.thenReturn(thawAnswer);
733+
734+
SnapshotInfo snapshotInfo = mock(SnapshotInfo.class);
735+
doReturn(snapshotInfo).when(strategy).createDiskSnapshot(any(), any(), any());
736+
doNothing().when(strategy).processAnswer(any(), any(), any(), any());
737+
doNothing().when(strategy).publishUsageEvent(any(String.class), any(VMSnapshot.class), any(), any(VolumeObjectTO.class));
738+
doNothing().when(strategy).publishUsageEvent(any(String.class), any(VMSnapshot.class), any(), anyLong(), anyLong());
739+
740+
VMSnapshot result = strategy.takeVMSnapshot(vmSnapshot);
741+
742+
// Snapshot should succeed with quiesce=true because ONTAP overrides quiesce
743+
// to false in the per-volume createDiskSnapshot payload (freeze/thaw is at VM level)
744+
assertNotNull(result);
745+
verify(agentMgr, times(2)).send(eq(HOST_ID), any(FreezeThawVMCommand.class));
746+
verify(strategy).createDiskSnapshot(any(), any(), any());
747+
}
748+
716749
// ══════════════════════════════════════════════════════════════════════════
717750
// Tests: Parent snapshot chain
718751
// ══════════════════════════════════════════════════════════════════════════

0 commit comments

Comments
 (0)