From 2b809cb128ee6ea114e8180c7ee8fba4dd73f377 Mon Sep 17 00:00:00 2001 From: Rene Peinthor Date: Fri, 13 Oct 2023 12:07:12 +0200 Subject: [PATCH] linstor: create template cache image before host copy Create the template image resource before the host gets the copy command. This allowes to tag(set property) in linstor to which template this resource belongs to and we can maybe in future reduce the linstor managing code in the storagepoolAdaptor class. --- .../LinstorPrimaryDataStoreDriverImpl.java | 91 ++++++++++++++++--- 1 file changed, 80 insertions(+), 11 deletions(-) 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(