@@ -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