mike-tutkowski commented on a change in pull request #2298: CLOUDSTACK-9620: 
Enhancements for managed storage
URL: https://github.com/apache/cloudstack/pull/2298#discussion_r161302812
 
 

 ##########
 File path: 
engine/storage/datamotion/src/org/apache/cloudstack/storage/motion/StorageSystemDataMotionStrategy.java
 ##########
 @@ -179,123 +242,320 @@ private boolean canHandle(DataObject dataObject) {
 
     @Override
     public StrategyPriority canHandle(Map<VolumeInfo, DataStore> volumeMap, 
Host srcHost, Host destHost) {
+        if (HypervisorType.KVM.equals(srcHost.getHypervisorType())) {
+            Set<VolumeInfo> volumeInfoSet = volumeMap.keySet();
+
+            for (VolumeInfo volumeInfo : volumeInfoSet) {
+                StoragePoolVO storagePoolVO = 
_storagePoolDao.findById(volumeInfo.getPoolId());
+
+                if (storagePoolVO.isManaged()) {
+                    return StrategyPriority.HIGHEST;
+                }
+            }
+
+            Collection<DataStore> dataStores = volumeMap.values();
+
+            for (DataStore dataStore : dataStores) {
+                StoragePoolVO storagePoolVO = 
_storagePoolDao.findById(dataStore.getId());
+
+                if (storagePoolVO.isManaged()) {
+                    return StrategyPriority.HIGHEST;
+                }
+            }
+        }
+
         return StrategyPriority.CANT_HANDLE;
     }
 
     @Override
     public void copyAsync(DataObject srcData, DataObject destData, Host 
destHost, AsyncCompletionCallback<CopyCommandResult> callback) {
         if (srcData instanceof SnapshotInfo) {
-            SnapshotInfo snapshotInfo = (SnapshotInfo)srcData;
+            SnapshotInfo srcSnapshotInfo = (SnapshotInfo)srcData;
 
-            validate(snapshotInfo);
+            handleCopyAsyncForSnapshot(srcSnapshotInfo, destData, callback);
+        } else if (srcData instanceof TemplateInfo && destData instanceof 
VolumeInfo) {
+            TemplateInfo srcTemplateInfo = (TemplateInfo)srcData;
+            VolumeInfo destVolumeInfo = (VolumeInfo)destData;
 
-            boolean canHandleSrc = canHandle(srcData);
+            handleCopyAsyncForTemplateAndVolume(srcTemplateInfo, 
destVolumeInfo, callback);
+        } else if (srcData instanceof VolumeInfo && destData instanceof 
VolumeInfo) {
+            VolumeInfo srcVolumeInfo = (VolumeInfo)srcData;
+            VolumeInfo destVolumeInfo = (VolumeInfo)destData;
 
-            if (canHandleSrc && (destData instanceof TemplateInfo || destData 
instanceof SnapshotInfo) &&
-                    (destData.getDataStore().getRole() == DataStoreRole.Image 
|| destData.getDataStore().getRole() == DataStoreRole.ImageCache)) {
-                handleCopyDataToSecondaryStorage(snapshotInfo, destData, 
callback);
+            handleCopyAsyncForVolumes(srcVolumeInfo, destVolumeInfo, callback);
+        } else if (srcData instanceof VolumeInfo && destData instanceof 
TemplateInfo &&
+                (destData.getDataStore().getRole() == DataStoreRole.Image || 
destData.getDataStore().getRole() == DataStoreRole.ImageCache)) {
+            VolumeInfo srcVolumeInfo = (VolumeInfo)srcData;
+            TemplateInfo destTemplateInfo = (TemplateInfo)destData;
 
-                return;
-            }
+            handleCreateTemplateFromVolume(srcVolumeInfo, destTemplateInfo, 
callback);
+        }
+        else {
+            handleError(OPERATION_NOT_SUPPORTED, callback);
+        }
+    }
 
-            if (destData instanceof VolumeInfo) {
-                VolumeInfo volumeInfo = (VolumeInfo)destData;
+    private void handleCopyAsyncForSnapshot(SnapshotInfo srcSnapshotInfo, 
DataObject destData, AsyncCompletionCallback<CopyCommandResult> callback) {
+        verifyFormat(srcSnapshotInfo);
 
-                boolean canHandleDest = canHandle(destData);
+        boolean canHandleSrc = canHandle(srcSnapshotInfo);
 
-                if (canHandleSrc && canHandleDest) {
-                    if (snapshotInfo.getDataStore().getId() == 
volumeInfo.getDataStore().getId()) {
-                        
handleCreateVolumeFromSnapshotBothOnStorageSystem(snapshotInfo, volumeInfo, 
callback);
-                        return;
-                    }
-                    else {
-                        String errMsg = "This operation is not supported 
(DataStoreCapabilities.STORAGE_SYSTEM_SNAPSHOT " +
-                                "not supported by source or destination 
storage plug-in). " + getSrcDestDataStoreMsg(srcData, destData);
+        if (canHandleSrc && (destData instanceof TemplateInfo || destData 
instanceof SnapshotInfo) &&
+                (destData.getDataStore().getRole() == DataStoreRole.Image || 
destData.getDataStore().getRole() == DataStoreRole.ImageCache)) {
+            handleCopyDataToSecondaryStorage(srcSnapshotInfo, destData, 
callback);
+        } else if (destData instanceof VolumeInfo) {
+            handleCopyAsyncForSnapshotToVolume(srcSnapshotInfo, 
(VolumeInfo)destData, callback);
+        } else {
+            handleError(OPERATION_NOT_SUPPORTED, callback);
+        }
+    }
 
-                        LOGGER.warn(errMsg);
+    private void handleCopyAsyncForSnapshotToVolume(SnapshotInfo 
srcSnapshotInfo, VolumeInfo destVolumeInfo,
+                                                    
AsyncCompletionCallback<CopyCommandResult> callback) {
+        boolean canHandleDest = canHandle(destVolumeInfo);
 
-                        throw new UnsupportedOperationException(errMsg);
-                    }
-                }
+        if (!canHandleDest) {
+            handleError(OPERATION_NOT_SUPPORTED, callback);
+        }
 
-                if (canHandleDest) {
-                    
handleCreateVolumeFromSnapshotOnSecondaryStorage(snapshotInfo, volumeInfo, 
callback);
+        boolean canHandleSrc = canHandle(srcSnapshotInfo);
 
-                    return;
-                }
+        if (!canHandleSrc) {
+            handleCreateVolumeFromSnapshotOnSecondaryStorage(srcSnapshotInfo, 
destVolumeInfo, callback);
+        }
+
+        if (srcSnapshotInfo.getDataStore().getId() == 
destVolumeInfo.getDataStore().getId()) {
+            handleCreateVolumeFromSnapshotBothOnStorageSystem(srcSnapshotInfo, 
destVolumeInfo, callback);
+        } else {
+            String errMsg = "To perform this operation, the source and 
destination primary storages must be the same.";
 
-                if (canHandleSrc) {
-                    String errMsg = "This operation is not supported 
(DataStoreCapabilities.STORAGE_SYSTEM_SNAPSHOT " +
-                            "not supported by source storage plug-in). " + 
getSrcDataStoreMsg(srcData);
+            handleError(errMsg, callback);
+        }
+    }
 
-                    LOGGER.warn(errMsg);
+    private void handleCopyAsyncForTemplateAndVolume(TemplateInfo 
srcTemplateInfo, VolumeInfo destVolumeInfo, 
AsyncCompletionCallback<CopyCommandResult> callback) {
+        boolean canHandleSrc = canHandle(srcTemplateInfo);
 
-                    throw new UnsupportedOperationException(errMsg);
-                }
-            }
-        } else if (srcData instanceof TemplateInfo && destData instanceof 
VolumeInfo) {
-            boolean canHandleSrc = canHandle(srcData);
+        if (!canHandleSrc) {
+            handleError(OPERATION_NOT_SUPPORTED, callback);
+        }
+
+        handleCreateVolumeFromTemplateBothOnStorageSystem(srcTemplateInfo, 
destVolumeInfo, callback);
+    }
 
-            if (!canHandleSrc) {
-                String errMsg = "This operation is not supported 
(DataStoreCapabilities.STORAGE_CAN_CREATE_VOLUME_FROM_VOLUME " +
-                        "not supported by destination storage plug-in). " + 
getDestDataStoreMsg(destData);
+    private void handleCopyAsyncForVolumes(VolumeInfo srcVolumeInfo, 
VolumeInfo destVolumeInfo, AsyncCompletionCallback<CopyCommandResult> callback) 
{
+        if (srcVolumeInfo.getState() == Volume.State.Migrating) {
+            if (isVolumeOnManagedStorage(srcVolumeInfo)) {
+                if (destVolumeInfo.getDataStore().getRole() == 
DataStoreRole.Image || destVolumeInfo.getDataStore().getRole() == 
DataStoreRole.ImageCache) {
+                    
handleVolumeCopyFromManagedStorageToSecondaryStorage(srcVolumeInfo, 
destVolumeInfo, callback);
+                } else if (!isVolumeOnManagedStorage(destVolumeInfo)) {
+                    
handleVolumeMigrationFromManagedStorageToNonManagedStorage(srcVolumeInfo, 
destVolumeInfo, callback);
+                } else {
+                    String errMsg = "The source volume to migrate and the 
destination volume are both on managed storage. " +
+                            "Migration in this case is not yet supported.";
 
-                LOGGER.warn(errMsg);
+                    handleError(errMsg, callback);
+                }
+            } else if (!isVolumeOnManagedStorage(destVolumeInfo)) {
+                String errMsg = "The 'StorageSystemDataMotionStrategy' does 
not support this migration use case.";
 
-                throw new UnsupportedOperationException(errMsg);
+                handleError(errMsg, callback);
+            } else {
+                
handleVolumeMigrationFromNonManagedStorageToManagedStorage(srcVolumeInfo, 
destVolumeInfo, callback);
             }
+        } else if (srcVolumeInfo.getState() == Volume.State.Uploaded &&
+                (srcVolumeInfo.getDataStore().getRole() == DataStoreRole.Image 
|| srcVolumeInfo.getDataStore().getRole() == DataStoreRole.ImageCache) &&
+                destVolumeInfo.getDataStore().getRole() == 
DataStoreRole.Primary) {
+            ImageFormat imageFormat = destVolumeInfo.getFormat();
 
-            
handleCreateVolumeFromTemplateBothOnStorageSystem((TemplateInfo)srcData, 
(VolumeInfo)destData, callback);
+            if (!ImageFormat.QCOW2.equals(imageFormat)) {
+                String errMsg = "The 'StorageSystemDataMotionStrategy' does 
not support this upload use case (non KVM).";
+
+                handleError(errMsg, callback);
+            }
 
-            return;
+            handleCreateVolumeFromVolumeOnSecondaryStorage(srcVolumeInfo, 
destVolumeInfo, destVolumeInfo.getDataCenterId(), HypervisorType.KVM, callback);
+        } else {
+            handleError(OPERATION_NOT_SUPPORTED, callback);
         }
+    }
+
+    private void handleError(String errMsg, 
AsyncCompletionCallback<CopyCommandResult> callback) {
+        LOGGER.warn(errMsg);
+
+        invokeCallback(errMsg, callback);
 
-        throw new UnsupportedOperationException("This operation is not 
supported.");
+        throw new UnsupportedOperationException(errMsg);
     }
 
-    private String getSrcDestDataStoreMsg(DataObject srcData, DataObject 
destData) {
-        Preconditions.checkArgument(srcData != null, "Passing 'null' to 
srcData of getSrcDestDataStoreMsg(DataObject, DataObject) is not supported.");
-        Preconditions.checkArgument(destData != null, "Passing 'null' to 
destData of getSrcDestDataStoreMsg(DataObject, DataObject) is not supported.");
+    private void invokeCallback(String errMsg, 
AsyncCompletionCallback<CopyCommandResult> callback) {
+        CopyCmdAnswer copyCmdAnswer = new CopyCmdAnswer(errMsg);
+
+        CopyCommandResult result = new CopyCommandResult(null, copyCmdAnswer);
+
+        result.setResult(errMsg);
 
-        return "Source data store = " + srcData.getDataStore().getName() + "; 
" + "Destination data store = " + destData.getDataStore().getName() + ".";
+        callback.complete(result);
     }
 
-    private String getSrcDataStoreMsg(DataObject srcData) {
-        Preconditions.checkArgument(srcData != null, "Passing 'null' to 
srcData of getSrcDataStoreMsg(DataObject) is not supported.");
+    private void 
handleVolumeCopyFromManagedStorageToSecondaryStorage(VolumeInfo srcVolumeInfo, 
VolumeInfo destVolumeInfo,
+                                                                      
AsyncCompletionCallback<CopyCommandResult> callback) {
+        String errMsg = null;
+        String volumePath = null;
+
+        try {
+            if (!ImageFormat.QCOW2.equals(srcVolumeInfo.getFormat())) {
+                throw new CloudRuntimeException("Currently, only the KVM 
hypervisor type is supported for the migration of a volume " +
+                        "from managed storage to non-managed storage.");
+            }
+
+            HypervisorType hypervisorType = HypervisorType.KVM;
+            VirtualMachine vm = srcVolumeInfo.getAttachedVM();
+
+            if (vm != null && vm.getState() != VirtualMachine.State.Stopped) {
+                throw new CloudRuntimeException("Currently, if a volume to 
copy from managed storage to secondary storage is attached to " +
+                        "a VM, the VM must be in the Stopped state.");
+            }
+
+            long srcStoragePoolId = srcVolumeInfo.getPoolId();
+            StoragePoolVO srcStoragePoolVO = 
_storagePoolDao.findById(srcStoragePoolId);
+
+            HostVO hostVO;
+
+            if (srcStoragePoolVO.getClusterId() != null) {
+                hostVO = getHostInCluster(srcStoragePoolVO.getClusterId());
+            }
+            else {
+                hostVO = getHost(srcVolumeInfo.getDataCenterId(), 
hypervisorType, false);
+            }
+
+            volumePath = copyVolumeToSecondaryStorage(srcVolumeInfo, 
destVolumeInfo, hostVO,
+                    "Unable to copy the volume from managed storage to 
secondary storage");
+        }
+        catch (Exception ex) {
 
 Review comment:
   The KVM migration can occasionally return an exception that extends 
RuntimeException. I wanted to lean on the safe side: Catch any non-system 
exception here.

----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on GitHub and use the
URL above to go to the specific comment.
 
For queries about this service, please contact Infrastructure at:
[email protected]


With regards,
Apache Git Services

Reply via email to