Skip to content

Commit 2340400

Browse files
CSTACKEX-18_2: add exception handling for any error coming from agent
1 parent 2abbed6 commit 2340400

File tree

1 file changed

+74
-15
lines changed

1 file changed

+74
-15
lines changed

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

Lines changed: 74 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -255,6 +255,16 @@ boolean allVolumesOnOntapManagedStorage(long vmId) {
255255
* the storage snapshot. The memory file is saved using virsh save, and the FlexVol
256256
* snapshot captures both disk and memory atomically. During revert, the FlexVol is
257257
* restored first, then the VM memory is restored using virsh restore.</p>
258+
*
259+
* <p><b>Protocol Support:</b></p>
260+
* <ul>
261+
* <li><b>NFS:</b> Supports both disk-only and memory snapshots. Memory files are
262+
* stored on the NFS mount alongside the disk images.</li>
263+
* <li><b>iSCSI:</b> Only supports disk-only (crash-consistent) snapshots. Memory
264+
* snapshots are not supported because iSCSI uses block devices which cannot
265+
* store arbitrary files. Attempting a memory snapshot on iSCSI will throw
266+
* a CloudRuntimeException with a clear error message.</li>
267+
* </ul>
258268
*/
259269
@Override
260270
public VMSnapshot takeVMSnapshot(VMSnapshot vmSnapshot) {
@@ -363,14 +373,30 @@ public VMSnapshot takeVMSnapshot(VMSnapshot vmSnapshot) {
363373
// For memory snapshots, we save the VM's memory state to a file on one of the
364374
// FlexVolumes. This file will be captured by the FlexVol snapshot, allowing
365375
// us to restore both disk and memory state atomically during revert.
376+
//
377+
// NOTE: Memory snapshots only work with NFS protocol because we need a file-system
378+
// path to save the memory file. iSCSI uses block devices which cannot store arbitrary files.
366379

367380
if (isMemorySnapshot && vmIsRunning) {
368381
// Pick the first FlexVol (typically ROOT disk) to store the memory file
369382
Map.Entry<String, FlexVolGroupInfo> firstFlexVol = flexVolGroups.entrySet().iterator().next();
370383
FlexVolGroupInfo memoryFlexVolGroup = firstFlexVol.getValue();
371384
memoryFilePoolId = memoryFlexVolGroup.poolId;
372385

373-
// Build the memory file path on the FlexVolume mount point
386+
// Check protocol - memory snapshots only supported for NFS
387+
String protocol = memoryFlexVolGroup.poolDetails.get(Constants.PROTOCOL);
388+
if (ProtocolType.ISCSI.name().equalsIgnoreCase(protocol)) {
389+
String errorMsg = String.format(
390+
"Memory snapshots (snapshotmemory=true) are not supported for VMs on iSCSI storage. " +
391+
"VM [%s] uses iSCSI protocol which does not support file-based memory storage. " +
392+
"Please use snapshotmemory=false for crash-consistent disk-only snapshots, or migrate " +
393+
"the VM to NFS storage to enable memory snapshots.",
394+
userVm.getInstanceName());
395+
logger.error("takeVMSnapshot: {}", errorMsg);
396+
throw new CloudRuntimeException(errorMsg);
397+
}
398+
399+
// Build the memory file path on the FlexVolume mount point (NFS only)
374400
// Memory file name: vmsnap_<vmSnapshotId>_<timestamp>.mem
375401
String memoryFileName = "vmsnap_" + vmSnapshot.getId() + "_" + System.currentTimeMillis() + ".mem";
376402
StoragePoolVO pool = storagePool.findById(memoryFilePoolId);
@@ -388,11 +414,24 @@ public VMSnapshot takeVMSnapshot(VMSnapshot vmSnapshot) {
388414
userVm.getInstanceName(), userVm.getUuid(), memoryFilePath, false);
389415

390416
try {
391-
SaveVMMemoryToFileAnswer saveMemAnswer = (SaveVMMemoryToFileAnswer) agentMgr.send(hostId, saveMemCmd);
392-
if (saveMemAnswer == null || !saveMemAnswer.getResult()) {
393-
String detail = (saveMemAnswer != null) ? saveMemAnswer.getDetails() : "no response from agent";
417+
com.cloud.agent.api.Answer rawAnswer = agentMgr.send(hostId, saveMemCmd);
418+
419+
// Check if agent supports this command
420+
if (rawAnswer instanceof com.cloud.agent.api.UnsupportedAnswer) {
421+
throw new CloudRuntimeException("Memory snapshots are not supported by this KVM agent. " +
422+
"Please ensure the agent is updated and restarted with memory snapshot support. " +
423+
"Alternatively, use snapshotmemory=false for disk-only snapshots.");
424+
}
425+
426+
if (!(rawAnswer instanceof SaveVMMemoryToFileAnswer)) {
427+
throw new CloudRuntimeException("Unexpected response from agent for SaveVMMemoryToFileCommand: " +
428+
(rawAnswer != null ? rawAnswer.getClass().getName() : "null"));
429+
}
430+
431+
SaveVMMemoryToFileAnswer saveMemAnswer = (SaveVMMemoryToFileAnswer) rawAnswer;
432+
if (!saveMemAnswer.getResult()) {
394433
throw new CloudRuntimeException("Failed to save VM memory for snapshot. " +
395-
"Ensure the VM is running and the storage is accessible. Details: " + detail);
434+
"Ensure the VM is running and the storage is accessible. Details: " + saveMemAnswer.getDetails());
396435
}
397436
memoryFileSaved = true;
398437
logger.info("takeVMSnapshot: VM [{}] memory saved successfully to [{}] (size: {} bytes)",
@@ -504,13 +543,23 @@ public VMSnapshot takeVMSnapshot(VMSnapshot vmSnapshot) {
504543
RestoreVMFromMemoryFileCommand restoreCmd = new RestoreVMFromMemoryFileCommand(
505544
userVm.getInstanceName(), userVm.getUuid(), memoryFilePath, false);
506545

507-
RestoreVMFromMemoryFileAnswer restoreAnswer =
508-
(RestoreVMFromMemoryFileAnswer) agentMgr.send(hostId, restoreCmd);
546+
com.cloud.agent.api.Answer rawRestoreAnswer = agentMgr.send(hostId, restoreCmd);
547+
548+
// Check if agent supports this command
549+
if (rawRestoreAnswer instanceof com.cloud.agent.api.UnsupportedAnswer) {
550+
throw new CloudRuntimeException("RestoreVMFromMemoryFile is not supported by this KVM agent. " +
551+
"Please ensure the agent is updated and restarted.");
552+
}
553+
554+
if (!(rawRestoreAnswer instanceof RestoreVMFromMemoryFileAnswer)) {
555+
throw new CloudRuntimeException("Unexpected response from agent for RestoreVMFromMemoryFileCommand: " +
556+
(rawRestoreAnswer != null ? rawRestoreAnswer.getClass().getName() : "null"));
557+
}
509558

510-
if (restoreAnswer == null || !restoreAnswer.getResult()) {
511-
String detail = (restoreAnswer != null) ? restoreAnswer.getDetails() : "no response from agent";
559+
RestoreVMFromMemoryFileAnswer restoreAnswer = (RestoreVMFromMemoryFileAnswer) rawRestoreAnswer;
560+
if (!restoreAnswer.getResult()) {
512561
throw new CloudRuntimeException("Failed to resume VM after memory snapshot. " +
513-
"The memory file was saved but VM could not be restored. Details: " + detail);
562+
"The memory file was saved but VM could not be restored. Details: " + restoreAnswer.getDetails());
514563
}
515564

516565
logger.info("takeVMSnapshot: VM [{}] resumed successfully from memory file, state: {}",
@@ -749,12 +798,22 @@ public boolean revertVMSnapshot(VMSnapshot vmSnapshot) {
749798
userVm.getInstanceName(), userVm.getUuid(), memoryFilePath, false);
750799

751800
try {
752-
RestoreVMFromMemoryFileAnswer restoreAnswer =
753-
(RestoreVMFromMemoryFileAnswer) agentMgr.send(hostId, restoreCmd);
801+
com.cloud.agent.api.Answer rawRestoreAnswer = agentMgr.send(hostId, restoreCmd);
802+
803+
// Check if agent supports this command
804+
if (rawRestoreAnswer instanceof com.cloud.agent.api.UnsupportedAnswer) {
805+
throw new CloudRuntimeException("RestoreVMFromMemoryFile is not supported by this KVM agent. " +
806+
"Please ensure the agent is updated and restarted.");
807+
}
808+
809+
if (!(rawRestoreAnswer instanceof RestoreVMFromMemoryFileAnswer)) {
810+
throw new CloudRuntimeException("Unexpected response from agent for RestoreVMFromMemoryFileCommand: " +
811+
(rawRestoreAnswer != null ? rawRestoreAnswer.getClass().getName() : "null"));
812+
}
754813

755-
if (restoreAnswer == null || !restoreAnswer.getResult()) {
756-
String detail = (restoreAnswer != null) ? restoreAnswer.getDetails() : "no response from agent";
757-
throw new CloudRuntimeException("Failed to restore VM from memory file during revert. Details: " + detail);
814+
RestoreVMFromMemoryFileAnswer restoreAnswer = (RestoreVMFromMemoryFileAnswer) rawRestoreAnswer;
815+
if (!restoreAnswer.getResult()) {
816+
throw new CloudRuntimeException("Failed to restore VM from memory file during revert. Details: " + restoreAnswer.getDetails());
758817
}
759818

760819
vmPowerState = restoreAnswer.getVmPowerState();

0 commit comments

Comments
 (0)