From 89cc55af35c9199a983ba32bf3688ee6f5ca5ed9 Mon Sep 17 00:00:00 2001 From: Pearl Dsilva Date: Tue, 6 Oct 2020 16:49:37 +0530 Subject: [PATCH 1/3] support for handling incremental snaps (on DB entries) on xen --- .../orchestration/DataMigrationUtility.java | 17 +++-- .../orchestration/StorageOrchestrator.java | 4 +- .../datastore/db/SnapshotDataStoreVO.java | 4 ++ .../datastore/db/TemplateDataStoreVO.java | 3 + .../datastore/db/VolumeDataStoreVO.java | 4 ++ .../image/SecondaryStorageServiceImpl.java | 67 +++++++++++++++---- .../image/BaseImageStoreDriverImpl.java | 25 ++++--- .../PremiumSecondaryStorageManagerImpl.java | 2 +- .../resource/NfsSecondaryStorageResource.java | 4 +- 9 files changed, 94 insertions(+), 36 deletions(-) diff --git a/engine/orchestration/src/main/java/org/apache/cloudstack/engine/orchestration/DataMigrationUtility.java b/engine/orchestration/src/main/java/org/apache/cloudstack/engine/orchestration/DataMigrationUtility.java index 86b7350d138b..b978d8c6abb8 100644 --- a/engine/orchestration/src/main/java/org/apache/cloudstack/engine/orchestration/DataMigrationUtility.java +++ b/engine/orchestration/src/main/java/org/apache/cloudstack/engine/orchestration/DataMigrationUtility.java @@ -36,6 +36,7 @@ import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotInfo; import org.apache.cloudstack.engine.subsystem.api.storage.TemplateDataFactory; import org.apache.cloudstack.engine.subsystem.api.storage.VolumeDataFactory; +import org.apache.cloudstack.engine.subsystem.api.storage.VolumeInfo; import org.apache.cloudstack.storage.ImageStoreService; import org.apache.cloudstack.storage.datastore.db.SnapshotDataStoreDao; import org.apache.cloudstack.storage.datastore.db.SnapshotDataStoreVO; @@ -47,6 +48,7 @@ import com.cloud.host.HostVO; import com.cloud.host.Status; import com.cloud.host.dao.HostDao; +import com.cloud.hypervisor.Hypervisor; import com.cloud.storage.DataStoreRole; import com.cloud.storage.SnapshotVO; import com.cloud.storage.VMTemplateVO; @@ -79,7 +81,6 @@ public class DataMigrationUtility { HostDao hostDao; @Inject SnapshotDao snapshotDao; - /** * This function verifies if the given image store contains data objects that are not in any of the following states: * "Ready" "Allocated", "Destroying", "Destroyed", "Failed". If this is the case, and if the migration policy is complete, @@ -115,7 +116,7 @@ protected void checkIfCompleteMigrationPossible(ImageStoreService.MigrationPolic protected Long getFileSize(DataObject file, Map, Long>> snapshotChain) { Long size = file.getSize(); Pair, Long> chain = snapshotChain.get(file); - if (file instanceof SnapshotInfo && chain.first() != null) { + if (file instanceof SnapshotInfo && chain.first() != null && !chain.first().isEmpty()) { size = chain.second(); } return size; @@ -178,7 +179,8 @@ protected List getAllReadyTemplates(DataStore srcDataStore) { List templates = templateDataStoreDao.listByStoreId(srcDataStore.getId()); for (TemplateDataStoreVO template : templates) { VMTemplateVO templateVO = templateDao.findById(template.getTemplateId()); - if (template.getState() == ObjectInDataStoreStateMachine.State.Ready && !templateVO.isPublicTemplate()) { + if (template.getState() == ObjectInDataStoreStateMachine.State.Ready && !templateVO.isPublicTemplate() && + templateVO.getHypervisorType() != Hypervisor.HypervisorType.Simulator) { files.add(templateFactory.getTemplate(template.getTemplateId(), srcDataStore)); } } @@ -194,7 +196,9 @@ protected List getAllReadySnapshotsAndChains(DataStore srcDataStore, List snapshots = snapshotDataStoreDao.listByStoreId(srcDataStore.getId(), DataStoreRole.Image); for (SnapshotDataStoreVO snapshot : snapshots) { SnapshotVO snapshotVO = snapshotDao.findById(snapshot.getSnapshotId()); - if (snapshot.getState() == ObjectInDataStoreStateMachine.State.Ready && snapshot.getParentSnapshotId() == 0 ) { + if (snapshot.getState() == ObjectInDataStoreStateMachine.State.Ready && + snapshotVO.getHypervisorType() != Hypervisor.HypervisorType.Simulator + && snapshot.getParentSnapshotId() == 0 ) { SnapshotInfo snap = snapshotFactory.getSnapshot(snapshotVO.getSnapshotId(), DataStoreRole.Image); files.add(snap); } @@ -230,7 +234,10 @@ protected List getAllReadyVolumes(DataStore srcDataStore) { List volumes = volumeDataStoreDao.listByStoreId(srcDataStore.getId()); for (VolumeDataStoreVO volume : volumes) { if (volume.getState() == ObjectInDataStoreStateMachine.State.Ready) { - files.add(volumeFactory.getVolume(volume.getVolumeId(), srcDataStore)); + VolumeInfo volumeInfo = volumeFactory.getVolume(volume.getVolumeId(), srcDataStore); + if (volumeInfo != null && volumeInfo.getHypervisorType() != Hypervisor.HypervisorType.Simulator) { + files.add(volumeInfo); + } } } return files; diff --git a/engine/orchestration/src/main/java/org/apache/cloudstack/engine/orchestration/StorageOrchestrator.java b/engine/orchestration/src/main/java/org/apache/cloudstack/engine/orchestration/StorageOrchestrator.java index 85b182a3dc21..ab53fd464880 100644 --- a/engine/orchestration/src/main/java/org/apache/cloudstack/engine/orchestration/StorageOrchestrator.java +++ b/engine/orchestration/src/main/java/org/apache/cloudstack/engine/orchestration/StorageOrchestrator.java @@ -393,7 +393,6 @@ private boolean shouldMigrate(DataObject chosenFile, Long srcDatastoreId, Long d if (meanStdDevCurrent > threshold && storageCapacityBelowThreshold(storageCapacities, destDatastoreId)) { return true; } - return true; } else { if (storageCapacityBelowThreshold(storageCapacities, destDatastoreId)) { return true; @@ -404,7 +403,8 @@ private boolean shouldMigrate(DataObject chosenFile, Long srcDatastoreId, Long d private boolean storageCapacityBelowThreshold(Map> storageCapacities, Long destStoreId) { Pair imageStoreCapacity = storageCapacities.get(destStoreId); - if (imageStoreCapacity != null && (imageStoreCapacity.first() / (imageStoreCapacity.second() * 1.0)) <= imageStoreCapacityThreshold) { + long usedCapacity = imageStoreCapacity.second() - imageStoreCapacity.first(); + if (imageStoreCapacity != null && (usedCapacity / (imageStoreCapacity.second() * 1.0)) <= imageStoreCapacityThreshold) { s_logger.debug("image store: " + destStoreId + " has sufficient capacity to proceed with migration of file"); return true; } diff --git a/engine/schema/src/main/java/org/apache/cloudstack/storage/datastore/db/SnapshotDataStoreVO.java b/engine/schema/src/main/java/org/apache/cloudstack/storage/datastore/db/SnapshotDataStoreVO.java index 75b1d75dd6a3..f36216911b02 100644 --- a/engine/schema/src/main/java/org/apache/cloudstack/storage/datastore/db/SnapshotDataStoreVO.java +++ b/engine/schema/src/main/java/org/apache/cloudstack/storage/datastore/db/SnapshotDataStoreVO.java @@ -291,4 +291,8 @@ public Long getVolumeId() { public void setVolumeId(Long volumeId) { this.volumeId = volumeId; } + + public void setCreated(Date created) { + this.created = created; + } } diff --git a/engine/schema/src/main/java/org/apache/cloudstack/storage/datastore/db/TemplateDataStoreVO.java b/engine/schema/src/main/java/org/apache/cloudstack/storage/datastore/db/TemplateDataStoreVO.java index 024f05604c94..8647e9681272 100644 --- a/engine/schema/src/main/java/org/apache/cloudstack/storage/datastore/db/TemplateDataStoreVO.java +++ b/engine/schema/src/main/java/org/apache/cloudstack/storage/datastore/db/TemplateDataStoreVO.java @@ -402,4 +402,7 @@ public void setExtractUrlCreated(Date extractUrlCreated) { this.extractUrlCreated = extractUrlCreated; } + public void setCreated(Date created) { + this.created = created; + } } diff --git a/engine/schema/src/main/java/org/apache/cloudstack/storage/datastore/db/VolumeDataStoreVO.java b/engine/schema/src/main/java/org/apache/cloudstack/storage/datastore/db/VolumeDataStoreVO.java index 68baab28ae87..bb21abbe44b3 100644 --- a/engine/schema/src/main/java/org/apache/cloudstack/storage/datastore/db/VolumeDataStoreVO.java +++ b/engine/schema/src/main/java/org/apache/cloudstack/storage/datastore/db/VolumeDataStoreVO.java @@ -381,4 +381,8 @@ public Date getExtractUrlCreated() { public void setExtractUrlCreated(Date extractUrlCreated) { this.extractUrlCreated = extractUrlCreated; } + + public void setCreated(Date created) { + this.created = created; + } } diff --git a/engine/storage/image/src/main/java/org/apache/cloudstack/storage/image/SecondaryStorageServiceImpl.java b/engine/storage/image/src/main/java/org/apache/cloudstack/storage/image/SecondaryStorageServiceImpl.java index 5a9c4a9f12ea..919765585a0e 100644 --- a/engine/storage/image/src/main/java/org/apache/cloudstack/storage/image/SecondaryStorageServiceImpl.java +++ b/engine/storage/image/src/main/java/org/apache/cloudstack/storage/image/SecondaryStorageServiceImpl.java @@ -17,6 +17,7 @@ package org.apache.cloudstack.storage.image; +import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.concurrent.ExecutionException; @@ -88,11 +89,29 @@ public AsyncCallFuture migrateData(DataObject srcDataObject, D DataObject destDataObject = null; try { if (srcDataObject instanceof SnapshotInfo && snapshotChain != null && snapshotChain.containsKey(srcDataObject)) { + List parentSnapshotPaths = new ArrayList<>(); for (SnapshotInfo snapshotInfo : snapshotChain.get(srcDataObject).first()) { + if (!parentSnapshotPaths.isEmpty() && parentSnapshotPaths.contains(snapshotInfo.getPath())) { + parentSnapshotPaths.add(snapshotInfo.getPath()); + SnapshotDataStoreVO snapshotStore = snapshotStoreDao.findByStoreSnapshot(DataStoreRole.Image, srcDatastore.getId(), snapshotInfo.getSnapshotId()); + if (snapshotStore == null) { + res.setResult("Failed to find snapshot " + snapshotInfo.getUuid() + " on store: " + srcDatastore.getName()); + res.setSuccess(false); + future.complete(res); + break; + } + snapshotStore.setDataStoreId(destDatastore.getId()); + snapshotStoreDao.update(snapshotStore.getId(), snapshotStore); + continue; + } + parentSnapshotPaths.add(snapshotInfo.getPath()); destDataObject = destDatastore.create(snapshotInfo); snapshotInfo.processEvent(ObjectInDataStoreStateMachine.Event.MigrateDataRequested); destDataObject.processEvent(ObjectInDataStoreStateMachine.Event.MigrateDataRequested); migrateJob(future, snapshotInfo, destDataObject, destDatastore); + if (future.get() != null && future.get().isFailed()) { + break; + } } } else { // Check if template in destination store, if yes, do not proceed @@ -163,26 +182,13 @@ protected Void migrateDataCallBack(AsyncCallbackDispatcher eps, CopyCommand cmd) { Answer answer = null; EndPoint endPoint = null; - Long epId = ssvmWithLeastMigrateJobs(); + List epIds = ssvmWithLeastMigrateJobs(); + Long epId = null; + if (!epIds.isEmpty()) { + epId = epIds.get(0); + } if (epId == null) { Collections.shuffle(eps); endPoint = eps.get(0); } else { - List remainingEps = eps.stream().filter(ep -> ep.getId() != epId ).collect(Collectors.toList()); + List remainingEps = eps.stream().filter(ep -> !epIds.contains(ep.getId())).collect(Collectors.toList()); if (!remainingEps.isEmpty()) { Collections.shuffle(remainingEps); endPoint = remainingEps.get(0); @@ -495,27 +499,22 @@ public Void createDataDiskTemplateAsync(TemplateInfo dataDiskTemplate, String pa return null; } - private Integer getCopyCmdsCountToSpecificSSVM(Long ssvmId) { - return _cmdExecLogDao.getCopyCmdCountForSSVM(ssvmId); - } - - private Long ssvmWithLeastMigrateJobs() { + private List ssvmWithLeastMigrateJobs() { s_logger.debug("Picking ssvm from the pool with least commands running on it"); - String query = "select host_id, count(*) from cmd_exec_log group by host_id order by 2 limit 1;"; + String query = "select host_id, count(*) from cmd_exec_log group by host_id order by 2;"; TransactionLegacy txn = TransactionLegacy.currentTxn(); - Long epId = null; + List result = new ArrayList(); PreparedStatement pstmt = null; try { pstmt = txn.prepareAutoCloseStatement(query); ResultSet rs = pstmt.executeQuery(); - if (rs.getFetchSize() > 0) { - rs.absolute(1); - epId = (long) rs.getInt(1); + while (rs.next()) { + result.add((long) rs.getInt(1)); } } catch (SQLException e) { s_logger.debug("SQLException caught", e); } - return epId; + return result; } } diff --git a/services/secondary-storage/controller/src/main/java/org/apache/cloudstack/secondarystorage/PremiumSecondaryStorageManagerImpl.java b/services/secondary-storage/controller/src/main/java/org/apache/cloudstack/secondarystorage/PremiumSecondaryStorageManagerImpl.java index d21ec614f405..74d1b509e21f 100644 --- a/services/secondary-storage/controller/src/main/java/org/apache/cloudstack/secondarystorage/PremiumSecondaryStorageManagerImpl.java +++ b/services/secondary-storage/controller/src/main/java/org/apache/cloudstack/secondarystorage/PremiumSecondaryStorageManagerImpl.java @@ -191,7 +191,7 @@ else if (!copyCmdsInPipeline.isEmpty() && copyCmdsInPipeline.size() >= halfLimi private void scaleDownSSVMOnLoad(List alreadyRunning, List activeCmds, List copyCmdsInPipeline) { int halfLimit = Math.round((float) (alreadyRunning.size() * migrateCapPerSSVM) / 2); - if ((copyCmdsInPipeline.size() < halfLimit && alreadyRunning.size() * _capacityPerSSVM - activeCmds.size() > (_standbyCapacity + 5)) && alreadyRunning.size() > 1) { + if (alreadyRunning.size() > 1 && ( copyCmdsInPipeline.size() < halfLimit && (activeCmds.size() < (((alreadyRunning.size() -1) * _capacityPerSSVM)/2)) )) { Collections.reverse(alreadyRunning); for(SecondaryStorageVmVO vm : alreadyRunning) { long count = activeCmds.stream().filter(cmd -> cmd.getInstanceId() == vm.getId()).count(); diff --git a/services/secondary-storage/server/src/main/java/org/apache/cloudstack/storage/resource/NfsSecondaryStorageResource.java b/services/secondary-storage/server/src/main/java/org/apache/cloudstack/storage/resource/NfsSecondaryStorageResource.java index dd002a9a2367..150dcc92c2f5 100644 --- a/services/secondary-storage/server/src/main/java/org/apache/cloudstack/storage/resource/NfsSecondaryStorageResource.java +++ b/services/secondary-storage/server/src/main/java/org/apache/cloudstack/storage/resource/NfsSecondaryStorageResource.java @@ -1309,6 +1309,8 @@ protected Answer copyFromNfsToNfs(CopyCommand cmd) { File srcDir = null; if (srcFile.isFile() || srcFile.getName().contains(".")) { srcDir = new File(srcFile.getParent()); + } else if (!srcFile.isFile() && !srcFile.isDirectory()) { + srcDir = new File(srcFile.getParent()); } File destDir = null; if (destFile.isFile()) { @@ -1351,7 +1353,7 @@ protected Answer copyFromNfsToNfs(CopyCommand cmd) { if (srcFile.isFile()) { newVol.setPath(destData.getPath() + File.separator + srcFile.getName()); } else { - newVol.setPath(destData.getPath()); + newVol.setPath(srcData.getPath()); } newVol.setSize(getVirtualSize(srcFile, format)); retObj = newVol; From 64bca0ec2249faad7ac58f4eb881e68d55aa99fe Mon Sep 17 00:00:00 2001 From: Pearl Dsilva Date: Thu, 15 Oct 2020 17:55:22 +0530 Subject: [PATCH 2/3] Addressed comments --- .../engine/orchestration/DataMigrationUtility.java | 4 ++-- .../storage/image/SecondaryStorageServiceImpl.java | 10 ++++------ .../storage/image/BaseImageStoreDriverImpl.java | 9 +++------ .../storage/resource/NfsSecondaryStorageResource.java | 6 +++--- 4 files changed, 12 insertions(+), 17 deletions(-) diff --git a/engine/orchestration/src/main/java/org/apache/cloudstack/engine/orchestration/DataMigrationUtility.java b/engine/orchestration/src/main/java/org/apache/cloudstack/engine/orchestration/DataMigrationUtility.java index b978d8c6abb8..dd451f594654 100644 --- a/engine/orchestration/src/main/java/org/apache/cloudstack/engine/orchestration/DataMigrationUtility.java +++ b/engine/orchestration/src/main/java/org/apache/cloudstack/engine/orchestration/DataMigrationUtility.java @@ -179,7 +179,7 @@ protected List getAllReadyTemplates(DataStore srcDataStore) { List templates = templateDataStoreDao.listByStoreId(srcDataStore.getId()); for (TemplateDataStoreVO template : templates) { VMTemplateVO templateVO = templateDao.findById(template.getTemplateId()); - if (template.getState() == ObjectInDataStoreStateMachine.State.Ready && !templateVO.isPublicTemplate() && + if (template.getState() == ObjectInDataStoreStateMachine.State.Ready && templateVO != null && !templateVO.isPublicTemplate() && templateVO.getHypervisorType() != Hypervisor.HypervisorType.Simulator) { files.add(templateFactory.getTemplate(template.getTemplateId(), srcDataStore)); } @@ -197,7 +197,7 @@ protected List getAllReadySnapshotsAndChains(DataStore srcDataStore, for (SnapshotDataStoreVO snapshot : snapshots) { SnapshotVO snapshotVO = snapshotDao.findById(snapshot.getSnapshotId()); if (snapshot.getState() == ObjectInDataStoreStateMachine.State.Ready && - snapshotVO.getHypervisorType() != Hypervisor.HypervisorType.Simulator + snapshotVO != null && snapshotVO.getHypervisorType() != Hypervisor.HypervisorType.Simulator && snapshot.getParentSnapshotId() == 0 ) { SnapshotInfo snap = snapshotFactory.getSnapshot(snapshotVO.getSnapshotId(), DataStoreRole.Image); files.add(snap); diff --git a/engine/storage/image/src/main/java/org/apache/cloudstack/storage/image/SecondaryStorageServiceImpl.java b/engine/storage/image/src/main/java/org/apache/cloudstack/storage/image/SecondaryStorageServiceImpl.java index 919765585a0e..b73dc87df288 100644 --- a/engine/storage/image/src/main/java/org/apache/cloudstack/storage/image/SecondaryStorageServiceImpl.java +++ b/engine/storage/image/src/main/java/org/apache/cloudstack/storage/image/SecondaryStorageServiceImpl.java @@ -216,9 +216,7 @@ private void updateDataObject(DataObject srcData, DataObject destData) { } snapshotStoreDao.update(destSnapshotStore.getId(), destSnapshotStore); } - } - - if (destData instanceof VolumeInfo) { + } else if (destData instanceof VolumeInfo) { VolumeDataStoreVO srcVolume = volumeDataStoreDao.findByStoreVolume(srcData.getDataStore().getId(), srcData.getId()); VolumeDataStoreVO destVolume = volumeDataStoreDao.findByStoreVolume(destData.getDataStore().getId(), destData.getId()); if (srcVolume != null && destVolume != null) { @@ -226,15 +224,15 @@ private void updateDataObject(DataObject srcData, DataObject destData) { destVolume.setCreated(srcVolume.getCreated()); volumeDataStoreDao.update(destVolume.getId(), destVolume); } - } - - if (destData instanceof TemplateInfo) { + } else if (destData instanceof TemplateInfo) { TemplateDataStoreVO srcTemplate = templateStoreDao.findByStoreTemplate(srcData.getDataStore().getId(), srcData.getId()); TemplateDataStoreVO destTemplate = templateStoreDao.findByStoreTemplate(destData.getDataStore().getId(), destData.getId()); if (srcTemplate != null && destTemplate != null) { destTemplate.setCreated(srcTemplate.getCreated()); templateStoreDao.update(destTemplate.getId(), destTemplate); } + } else { + s_logger.debug("Unsupported data object type"); } } } diff --git a/engine/storage/src/main/java/org/apache/cloudstack/storage/image/BaseImageStoreDriverImpl.java b/engine/storage/src/main/java/org/apache/cloudstack/storage/image/BaseImageStoreDriverImpl.java index 5557920c9ba8..2341603803e3 100644 --- a/engine/storage/src/main/java/org/apache/cloudstack/storage/image/BaseImageStoreDriverImpl.java +++ b/engine/storage/src/main/java/org/apache/cloudstack/storage/image/BaseImageStoreDriverImpl.java @@ -392,11 +392,8 @@ private Answer sendToLeastBusyEndpoint(List eps, CopyCommand cmd) { Answer answer = null; EndPoint endPoint = null; List epIds = ssvmWithLeastMigrateJobs(); - Long epId = null; - if (!epIds.isEmpty()) { - epId = epIds.get(0); - } - if (epId == null) { + + if (epIds.isEmpty()) { Collections.shuffle(eps); endPoint = eps.get(0); } else { @@ -405,7 +402,7 @@ private Answer sendToLeastBusyEndpoint(List eps, CopyCommand cmd) { Collections.shuffle(remainingEps); endPoint = remainingEps.get(0); } else { - endPoint = _defaultEpSelector.getEndPointFromHostId(epId); + endPoint = _defaultEpSelector.getEndPointFromHostId(epIds.get(0)); } } CommandExecLogVO execLog = new CommandExecLogVO(endPoint.getId(), _secStorageVmDao.findByInstanceName(hostDao.findById(endPoint.getId()).getName()).getId(), "DataMigrationCommand", 1); diff --git a/services/secondary-storage/server/src/main/java/org/apache/cloudstack/storage/resource/NfsSecondaryStorageResource.java b/services/secondary-storage/server/src/main/java/org/apache/cloudstack/storage/resource/NfsSecondaryStorageResource.java index 150dcc92c2f5..a58afecc995f 100644 --- a/services/secondary-storage/server/src/main/java/org/apache/cloudstack/storage/resource/NfsSecondaryStorageResource.java +++ b/services/secondary-storage/server/src/main/java/org/apache/cloudstack/storage/resource/NfsSecondaryStorageResource.java @@ -1300,16 +1300,16 @@ protected Answer copyFromNfsToNfs(CopyCommand cmd) { try { File srcFile = new File(getDir(srcStore.getUrl(), _nfsVersion), srcData.getPath()); File destFile = new File(getDir(destStore.getUrl(), _nfsVersion), destData.getPath()); - ImageFormat format = getTemplateFormat(srcFile.getName()); if (srcFile == null) { - return new CopyCmdAnswer("Can't find src file:" + srcFile); + return new CopyCmdAnswer("Can't find source file at path: "+ srcData.getPath() +"on datastore: "+ srcDataStore.getUuid() +" to initiate file transfer"); } + ImageFormat format = getTemplateFormat(srcFile.getName()); if (srcData instanceof TemplateObjectTO || srcData instanceof VolumeObjectTO) { File srcDir = null; if (srcFile.isFile() || srcFile.getName().contains(".")) { srcDir = new File(srcFile.getParent()); - } else if (!srcFile.isFile() && !srcFile.isDirectory()) { + } else if (!srcFile.isDirectory()) { srcDir = new File(srcFile.getParent()); } File destDir = null; From 7332ce564d49b73928bf1ce2c817099ea246af64 Mon Sep 17 00:00:00 2001 From: Pearl Dsilva Date: Fri, 16 Oct 2020 10:50:47 +0530 Subject: [PATCH 3/3] Update NfsSecondaryStorageResource.java adjusted space in comment/ log --- .../storage/resource/NfsSecondaryStorageResource.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/secondary-storage/server/src/main/java/org/apache/cloudstack/storage/resource/NfsSecondaryStorageResource.java b/services/secondary-storage/server/src/main/java/org/apache/cloudstack/storage/resource/NfsSecondaryStorageResource.java index a58afecc995f..863376d33817 100644 --- a/services/secondary-storage/server/src/main/java/org/apache/cloudstack/storage/resource/NfsSecondaryStorageResource.java +++ b/services/secondary-storage/server/src/main/java/org/apache/cloudstack/storage/resource/NfsSecondaryStorageResource.java @@ -1302,7 +1302,7 @@ protected Answer copyFromNfsToNfs(CopyCommand cmd) { File destFile = new File(getDir(destStore.getUrl(), _nfsVersion), destData.getPath()); if (srcFile == null) { - return new CopyCmdAnswer("Can't find source file at path: "+ srcData.getPath() +"on datastore: "+ srcDataStore.getUuid() +" to initiate file transfer"); + return new CopyCmdAnswer("Can't find source file at path: "+ srcData.getPath() +" on datastore: "+ srcDataStore.getUuid() +" to initiate file transfer"); } ImageFormat format = getTemplateFormat(srcFile.getName()); if (srcData instanceof TemplateObjectTO || srcData instanceof VolumeObjectTO) {