diff --git a/plugins/storage/volume/linstor/src/main/java/org/apache/cloudstack/storage/datastore/driver/LinstorPrimaryDataStoreDriverImpl.java b/plugins/storage/volume/linstor/src/main/java/org/apache/cloudstack/storage/datastore/driver/LinstorPrimaryDataStoreDriverImpl.java index 328b3d21d0a1..9634bff11d63 100644 --- a/plugins/storage/volume/linstor/src/main/java/org/apache/cloudstack/storage/datastore/driver/LinstorPrimaryDataStoreDriverImpl.java +++ b/plugins/storage/volume/linstor/src/main/java/org/apache/cloudstack/storage/datastore/driver/LinstorPrimaryDataStoreDriverImpl.java @@ -798,6 +798,15 @@ private static boolean canCopyTemplateCond(DataObject srcData, DataObject dstDat || srcData.getDataStore().getRole() == DataStoreRole.ImageCache); } + private static boolean canCopyVolumeCond(DataObject srcData, DataObject dstData) { + // Volume download from Linstor primary storage + return srcData.getType() == DataObjectType.VOLUME + && (dstData.getType() == DataObjectType.VOLUME || dstData.getType() == DataObjectType.TEMPLATE) + && srcData.getDataStore().getRole() == DataStoreRole.Primary + && (dstData.getDataStore().getRole() == DataStoreRole.Image + || dstData.getDataStore().getRole() == DataStoreRole.ImageCache); + } + @Override public boolean canCopy(DataObject srcData, DataObject dstData) { @@ -814,6 +823,10 @@ public boolean canCopy(DataObject srcData, DataObject dstData) return storagePoolVO != null && storagePoolVO.getPoolType() == Storage.StoragePoolType.Linstor && tInfo.getSize() != null; + } else if (canCopyVolumeCond(srcData, dstData)) { + VolumeInfo srcVolInfo = (VolumeInfo) srcData; + StoragePoolVO storagePool = _storagePoolDao.findById(srcVolInfo.getPoolId()); + return storagePool.getStorageProviderName().equals(LinstorUtil.PROVIDER_NAME); } return false; } @@ -844,6 +857,9 @@ public void copyAsync(DataObject srcData, DataObject dstData, AsyncCompletionCal } else if (canCopyTemplateCond(srcData, dstData)) { Answer answer = copyTemplate(srcData, dstData); res = new CopyCommandResult(null, answer); + } else if (canCopyVolumeCond(srcData, dstData)) { + Answer answer = copyVolume(srcData, dstData); + res = new CopyCommandResult(null, answer); } else { Answer answer = new Answer(null, false, "noimpl"); res = new CopyCommandResult(null, answer); @@ -965,6 +981,36 @@ private Answer copyTemplate(DataObject srcData, DataObject dstData) { return answer; } + private Answer copyVolume(DataObject srcData, DataObject dstData) { + VolumeInfo srcVolInfo = (VolumeInfo) srcData; + final StoragePoolVO pool = _storagePoolDao.findById(srcVolInfo.getDataStore().getId()); + final DevelopersApi api = LinstorUtil.getLinstorAPI(pool.getHostAddress()); + final String rscName = LinstorUtil.RSC_PREFIX + srcVolInfo.getUuid(); + + int nMaxExecutionMinutes = NumbersUtil.parseInt( + _configDao.getValue(Config.SecStorageCmdExecutionTimeMax.key()), 30); + CopyCommand cmd = new CopyCommand( + srcData.getTO(), + dstData.getTO(), + nMaxExecutionMinutes * 60 * 1000, + VirtualMachineManager.ExecuteInSequence.value()); + Answer answer; + + try { + Optional optEP = getLinstorEP(api, rscName); + if (optEP.isPresent()) { + answer = optEP.get().sendMessage(cmd); + } + else { + answer = new Answer(cmd, false, "Unable to get matching Linstor endpoint."); + } + } catch (ApiException exc) { + s_logger.error("copy volume failed: ", exc); + throw new CloudRuntimeException(exc.getBestMessage()); + } + return answer; + } + /** * Create a temporary resource from the snapshot to backup, so we can copy the data on a diskless agent * @param api Linstor Developer api object