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 42f6c5d5c3f3..fbad0301aead 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 @@ -61,6 +61,7 @@ import com.cloud.storage.DataStoreRole; import com.cloud.storage.ResizeVolumePayload; import com.cloud.storage.SnapshotVO; +import com.cloud.storage.Storage; import com.cloud.storage.StorageManager; import com.cloud.storage.StoragePool; import com.cloud.storage.VMTemplateStoragePoolVO; @@ -420,27 +421,46 @@ private void applyAuxProps(DevelopersApi api, String rscName, String dispName, S } } - private String createResource(VolumeInfo vol, StoragePoolVO storagePoolVO) - { - DevelopersApi linstorApi = LinstorUtil.getLinstorAPI(storagePoolVO.getHostAddress()); - final String rscGrp = storagePoolVO.getUserInfo() != null && !storagePoolVO.getUserInfo().isEmpty() ? + private String getRscGrp(StoragePoolVO storagePoolVO) { + return storagePoolVO.getUserInfo() != null && !storagePoolVO.getUserInfo().isEmpty() ? storagePoolVO.getUserInfo() : "DfltRscGrp"; + } + private String createResourceBase( + String rscName, long sizeInBytes, String volName, String vmName, DevelopersApi api, String rscGrp) { ResourceGroupSpawn rscGrpSpawn = new ResourceGroupSpawn(); - final String rscName = LinstorUtil.RSC_PREFIX + vol.getUuid(); rscGrpSpawn.setResourceDefinitionName(rscName); - rscGrpSpawn.addVolumeSizesItem(vol.getSize() / 1024); + rscGrpSpawn.addVolumeSizesItem(sizeInBytes / 1024); try { s_logger.info("Linstor: Spawn resource " + rscName); - ApiCallRcList answers = linstorApi.resourceGroupSpawn(rscGrp, rscGrpSpawn); + ApiCallRcList answers = api.resourceGroupSpawn(rscGrp, rscGrpSpawn); checkLinstorAnswersThrow(answers); - applyAuxProps(linstorApi, rscName, vol.getName(), vol.getAttachedVmName()); + applyAuxProps(api, rscName, volName, vmName); + + return getDeviceName(api, rscName); + } catch (ApiException apiEx) + { + s_logger.error("Linstor: ApiEx - " + apiEx.getMessage()); + throw new CloudRuntimeException(apiEx.getBestMessage(), apiEx); + } + } + + private String createResource(VolumeInfo vol, StoragePoolVO storagePoolVO) { + DevelopersApi linstorApi = LinstorUtil.getLinstorAPI(storagePoolVO.getHostAddress()); + final String rscGrp = getRscGrp(storagePoolVO); + + final String rscName = LinstorUtil.RSC_PREFIX + vol.getUuid(); + String deviceName = createResourceBase( + rscName, vol.getSize(), vol.getName(), vol.getAttachedVmName(), linstorApi, rscGrp); + + try + { applyQoSSettings(storagePoolVO, linstorApi, rscName, vol.getMaxIops()); - return getDeviceName(linstorApi, rscName); + return deviceName; } catch (ApiException apiEx) { s_logger.error("Linstor: ApiEx - " + apiEx.getMessage()); @@ -505,8 +525,7 @@ private String cloneResource(long csCloneId, VolumeInfo volumeInfo, StoragePoolV } private String createResourceFromSnapshot(long csSnapshotId, String rscName, StoragePoolVO storagePoolVO) { - final String rscGrp = storagePoolVO.getUserInfo() != null && !storagePoolVO.getUserInfo().isEmpty() ? - storagePoolVO.getUserInfo() : "DfltRscGrp"; + final String rscGrp = getRscGrp(storagePoolVO); final DevelopersApi linstorApi = LinstorUtil.getLinstorAPI(storagePoolVO.getHostAddress()); SnapshotVO snapshotVO = _snapshotDao.findById(csSnapshotId); @@ -757,6 +776,13 @@ private static boolean canCopySnapshotCond(DataObject srcData, DataObject dstDat || dstData.getDataStore().getRole() == DataStoreRole.ImageCache); } + private static boolean canCopyTemplateCond(DataObject srcData, DataObject dstData) { + return srcData.getType() == DataObjectType.TEMPLATE && dstData.getType() == DataObjectType.TEMPLATE + && dstData.getDataStore().getRole() == DataStoreRole.Primary + && (srcData.getDataStore().getRole() == DataStoreRole.Image + || srcData.getDataStore().getRole() == DataStoreRole.ImageCache); + } + @Override public boolean canCopy(DataObject srcData, DataObject dstData) { @@ -767,6 +793,9 @@ public boolean canCopy(DataObject srcData, DataObject dstData) VolumeInfo volume = sinfo.getBaseVolume(); StoragePoolVO storagePool = _storagePoolDao.findById(volume.getPoolId()); return storagePool.getStorageProviderName().equals(LinstorUtil.PROVIDER_NAME); + } else if (canCopyTemplateCond(srcData, dstData)) { + StoragePoolVO storagePoolVO = _storagePoolDao.findById(dstData.getDataStore().getId()); + return storagePoolVO != null && storagePoolVO.getPoolType() == Storage.StoragePoolType.Linstor; } return false; } @@ -794,6 +823,9 @@ public void copyAsync(DataObject srcData, DataObject dstData, AsyncCompletionCal } res = new CopyCommandResult(null, answer); res.setResult(errMsg); + } else if (canCopyTemplateCond(srcData, dstData)) { + Answer answer = copyTemplate(srcData, dstData); + res = new CopyCommandResult(null, answer); } else { Answer answer = new Answer(null, false, "noimpl"); res = new CopyCommandResult(null, answer); @@ -821,6 +853,43 @@ private Optional getDiskfullEP(DevelopersApi api, String rsc return Optional.empty(); } + private Answer copyTemplate(DataObject srcData, DataObject dstData) { + TemplateInfo tInfo = (TemplateInfo) dstData; + final StoragePoolVO pool = _storagePoolDao.findById(dstData.getDataStore().getId()); + final DevelopersApi api = LinstorUtil.getLinstorAPI(pool.getHostAddress()); + final String rscName = LinstorUtil.RSC_PREFIX + dstData.getUuid(); + createResourceBase( + LinstorUtil.RSC_PREFIX + dstData.getUuid(), + dstData.getSize(), + tInfo.getName(), + "", + api, + getRscGrp(pool)); + + 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 = getDiskfullEP(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 template failed: ", exc); + throw new CloudRuntimeException(exc.getBestMessage()); + } + return answer; + } + protected Answer copySnapshot(DataObject srcData, DataObject destData) { String value = _configDao.getValue(Config.BackupSnapshotWait.toString()); int _backupsnapshotwait = NumbersUtil.parseInt(