diff --git a/api/src/com/cloud/storage/VolumeApiService.java b/api/src/com/cloud/storage/VolumeApiService.java index aa52cf74652..31b5c9501b8 100644 --- a/api/src/com/cloud/storage/VolumeApiService.java +++ b/api/src/com/cloud/storage/VolumeApiService.java @@ -58,7 +58,7 @@ public interface VolumeApiService { */ Volume resizeVolume(ResizeVolumeCmd cmd) throws ResourceAllocationException; - Volume migrateVolume(MigrateVolumeCmd cmd) throws ConcurrentOperationException; + Volume migrateVolume(MigrateVolumeCmd cmd); /** * Uploads the volume to secondary storage diff --git a/api/src/org/apache/cloudstack/api/command/user/volume/MigrateVolumeCmd.java b/api/src/org/apache/cloudstack/api/command/user/volume/MigrateVolumeCmd.java index ce40f0d2979..40e6123d0ec 100644 --- a/api/src/org/apache/cloudstack/api/command/user/volume/MigrateVolumeCmd.java +++ b/api/src/org/apache/cloudstack/api/command/user/volume/MigrateVolumeCmd.java @@ -98,18 +98,15 @@ public class MigrateVolumeCmd extends BaseAsyncCmd { @Override public void execute(){ - Volume result; - try { - result = _volumeService.migrateVolume(this); - if (result != null) { - VolumeResponse response = _responseGenerator.createVolumeResponse(result); - response.setResponseName(getCommandName()); - this.setResponseObject(response); - } - } catch (ConcurrentOperationException e) { - throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to migrate volume: "); - } - + Volume result; + result = _volumeService.migrateVolume(this); + if (result != null) { + VolumeResponse response = _responseGenerator.createVolumeResponse(result); + response.setResponseName(getCommandName()); + this.setResponseObject(response); + } else { + throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to migrate volume"); + } } } diff --git a/engine/schema/src/com/cloud/storage/VolumeVO.java b/engine/schema/src/com/cloud/storage/VolumeVO.java index a230991f42a..d939910a780 100755 --- a/engine/schema/src/com/cloud/storage/VolumeVO.java +++ b/engine/schema/src/com/cloud/storage/VolumeVO.java @@ -154,7 +154,7 @@ public class VolumeVO implements Volume { this.uuid = UUID.randomUUID().toString(); } - public VolumeVO(String name, long dcId, long podId, long accountId, long domainId, Long instanceId, String folder, String path, long size, Volume.Type vType) { + public VolumeVO(String name, Long dcId, Long podId, long accountId, long domainId, Long instanceId, String folder, String path, long size, Volume.Type vType) { this.name = name; this.accountId = accountId; this.domainId = domainId; diff --git a/engine/storage/cache/src/org/apache/cloudstack/storage/cache/allocator/StorageCacheRandomAllocator.java b/engine/storage/cache/src/org/apache/cloudstack/storage/cache/allocator/StorageCacheRandomAllocator.java index 462f13fca77..f8232b8987a 100644 --- a/engine/storage/cache/src/org/apache/cloudstack/storage/cache/allocator/StorageCacheRandomAllocator.java +++ b/engine/storage/cache/src/org/apache/cloudstack/storage/cache/allocator/StorageCacheRandomAllocator.java @@ -25,26 +25,30 @@ import javax.inject.Inject; import org.apache.cloudstack.engine.subsystem.api.storage.DataStore; import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreManager; import org.apache.cloudstack.engine.subsystem.api.storage.Scope; +import org.apache.log4j.Logger; import org.springframework.stereotype.Component; import com.cloud.storage.ScopeType; -import com.cloud.utils.exception.CloudRuntimeException; import edu.emory.mathcs.backport.java.util.Collections; @Component public class StorageCacheRandomAllocator implements StorageCacheAllocator { + private static final Logger s_logger = Logger + .getLogger(StorageCacheRandomAllocator.class); @Inject DataStoreManager dataStoreMgr; @Override public DataStore getCacheStore(Scope scope) { if (scope.getScopeType() != ScopeType.ZONE) { - throw new CloudRuntimeException("Can only support zone wide cache storage"); + s_logger.debug("Can only support zone wide cache storage"); + return null; } List cacheStores = dataStoreMgr.getImageCacheStores(scope); if (cacheStores.size() <= 0) { - throw new CloudRuntimeException("Can't find cache storage in zone: " + scope.getScopeId()); + s_logger.debug("Can't find cache storage in zone: " + scope.getScopeId()); + return null; } Collections.shuffle(cacheStores); diff --git a/engine/storage/datamotion/src/org/apache/cloudstack/storage/motion/AncientDataMotionStrategy.java b/engine/storage/datamotion/src/org/apache/cloudstack/storage/motion/AncientDataMotionStrategy.java index 1e99e9efbe2..65beb40c475 100644 --- a/engine/storage/datamotion/src/org/apache/cloudstack/storage/motion/AncientDataMotionStrategy.java +++ b/engine/storage/datamotion/src/org/apache/cloudstack/storage/motion/AncientDataMotionStrategy.java @@ -31,6 +31,7 @@ import org.apache.cloudstack.engine.subsystem.api.storage.DataObject; import org.apache.cloudstack.engine.subsystem.api.storage.DataStore; import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreManager; import org.apache.cloudstack.engine.subsystem.api.storage.HostScope; +import org.apache.cloudstack.engine.subsystem.api.storage.ObjectInDataStoreStateMachine.Event; import org.apache.cloudstack.engine.subsystem.api.storage.Scope; import org.apache.cloudstack.engine.subsystem.api.storage.ZoneScope; import org.apache.cloudstack.engine.subsystem.api.storage.EndPoint; @@ -39,11 +40,13 @@ import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotInfo; import org.apache.cloudstack.engine.subsystem.api.storage.StorageCacheManager; import org.apache.cloudstack.engine.subsystem.api.storage.VolumeInfo; import org.apache.cloudstack.framework.async.AsyncCompletionCallback; +import org.apache.cloudstack.storage.command.CopyCmdAnswer; import org.apache.cloudstack.storage.command.CopyCommand; import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao; import org.apache.cloudstack.storage.datastore.db.SnapshotDataStoreDao; import org.apache.cloudstack.storage.datastore.db.TemplateDataStoreDao; import org.apache.cloudstack.storage.datastore.db.VolumeDataStoreDao; +import org.apache.cloudstack.storage.image.datastore.ImageStoreEntity; import com.cloud.agent.api.Answer; import com.cloud.agent.api.to.DataObjectType; @@ -57,6 +60,7 @@ import com.cloud.exception.StorageUnavailableException; import com.cloud.host.Host; import com.cloud.host.dao.HostDao; import com.cloud.storage.DataStoreRole; +import com.cloud.storage.ImageStore; import com.cloud.storage.StorageManager; import com.cloud.storage.StoragePool; import com.cloud.storage.VolumeManager; @@ -136,6 +140,20 @@ public class AncientDataMotionStrategy implements DataMotionStrategy { } return true; } + + private Scope getZoneScope(Scope destScope) { + ZoneScope zoneScope = null; + if (destScope instanceof ClusterScope) { + ClusterScope clusterScope = (ClusterScope) destScope; + zoneScope = new ZoneScope(clusterScope.getZoneId()); + } else if (destScope instanceof HostScope) { + HostScope hostScope = (HostScope) destScope; + zoneScope = new ZoneScope(hostScope.getZoneId()); + } else { + zoneScope = (ZoneScope)destScope; + } + return zoneScope; + } protected Answer copyObject(DataObject srcData, DataObject destData) { String value = configDao.getValue(Config.PrimaryStorageDownloadWait.toString()); @@ -145,14 +163,7 @@ public class AncientDataMotionStrategy implements DataMotionStrategy { try { if (needCacheStorage(srcData, destData)) { // need to copy it to image cache store - Scope destScope = destData.getDataStore().getScope(); - if (destScope instanceof ClusterScope) { - ClusterScope clusterScope = (ClusterScope) destScope; - destScope = new ZoneScope(clusterScope.getZoneId()); - } else if (destScope instanceof HostScope) { - HostScope hostScope = (HostScope) destScope; - destScope = new ZoneScope(hostScope.getZoneId()); - } + Scope destScope = getZoneScope(destData.getDataStore().getScope()); cacheData = cacheMgr.createCacheObject(srcData, destScope); CopyCommand cmd = new CopyCommand(cacheData.getTO(), destData.getTO(), _primaryStorageDownloadWait); EndPoint ep = selector.select(cacheData, destData); @@ -248,11 +259,57 @@ public class AncientDataMotionStrategy implements DataMotionStrategy { int _copyvolumewait = NumbersUtil.parseInt(value, Integer.parseInt(Config.CopyVolumeWait.getDefaultValue())); - DataObject cacheData = cacheMgr.createCacheObject(srcData, destData.getDataStore().getScope()); - CopyCommand cmd = new CopyCommand(cacheData.getTO(), destData.getTO(), _copyvolumewait); - EndPoint ep = selector.select(cacheData, destData); - Answer answer = ep.sendMessage(cmd); - return answer; + Scope destScope = getZoneScope(destData.getDataStore().getScope()); + DataStore cacheStore = cacheMgr.getCacheStorage(destScope); + if (cacheStore == null) { + //need to find a nfs image store, assuming that can't copy volume directly to s3 + ImageStoreEntity imageStore = (ImageStoreEntity)this.dataStoreMgr.getImageStore(destScope.getScopeId()); + if (!imageStore.getProtocol().equalsIgnoreCase("nfs")) { + s_logger.debug("can't find a nfs image store"); + return null; + } + + DataObject objOnImageStore = imageStore.create(srcData); + objOnImageStore.processEvent(Event.CreateOnlyRequested); + + Answer answer = this.copyObject(srcData, objOnImageStore); + if (answer == null || !answer.getResult()) { + if (answer != null) { + s_logger.debug("copy to image store failed: " + answer.getDetails()); + } + objOnImageStore.processEvent(Event.OperationFailed); + imageStore.delete(objOnImageStore); + return answer; + } + + objOnImageStore.processEvent(Event.OperationSuccessed, answer); + + objOnImageStore.processEvent(Event.CopyingRequested); + + CopyCommand cmd = new CopyCommand(objOnImageStore.getTO(), destData.getTO(), _copyvolumewait); + EndPoint ep = selector.select(objOnImageStore, destData); + answer = ep.sendMessage(cmd); + + if (answer == null || !answer.getResult()) { + if (answer != null) { + s_logger.debug("copy to primary store failed: " + answer.getDetails()); + } + objOnImageStore.processEvent(Event.OperationFailed); + imageStore.delete(objOnImageStore); + return answer; + } + + objOnImageStore.processEvent(Event.OperationSuccessed); + imageStore.delete(objOnImageStore); + return answer; + } else { + DataObject cacheData = cacheMgr.createCacheObject(srcData, destScope); + CopyCommand cmd = new CopyCommand(cacheData.getTO(), destData.getTO(), _copyvolumewait); + EndPoint ep = selector.select(cacheData, destData); + Answer answer = ep.sendMessage(cmd); + return answer; + } + } @Override @@ -273,7 +330,7 @@ public class AncientDataMotionStrategy implements DataMotionStrategy { answer = cloneVolume(srcData, destData); } else if (destData.getType() == DataObjectType.VOLUME && srcData.getType() == DataObjectType.VOLUME && srcData.getDataStore().getRole() == DataStoreRole.Primary && destData.getDataStore().getRole() == DataStoreRole.Primary) { - answer = copyVolumeBetweenPools(srcData, destData); + answer = copyVolumeBetweenPools(srcData, destData); } else if (srcData.getType() == DataObjectType.SNAPSHOT && destData.getType() == DataObjectType.SNAPSHOT) { answer = copySnapshot(srcData, destData); diff --git a/engine/storage/volume/src/org/apache/cloudstack/storage/volume/VolumeObject.java b/engine/storage/volume/src/org/apache/cloudstack/storage/volume/VolumeObject.java index da5e80ba6c0..c5ba6dbe777 100644 --- a/engine/storage/volume/src/org/apache/cloudstack/storage/volume/VolumeObject.java +++ b/engine/storage/volume/src/org/apache/cloudstack/storage/volume/VolumeObject.java @@ -193,6 +193,9 @@ public class VolumeObject implements VolumeInfo { } if (this.dataStore.getRole() == DataStoreRole.Image) { objectInStoreMgr.update(this, event); + if (this.volumeVO.getState() == Volume.State.Migrating) { + return; + } if (event == ObjectInDataStoreStateMachine.Event.CreateRequested) { volEvent = Volume.Event.UploadRequested; } else if (event == ObjectInDataStoreStateMachine.Event.OperationSuccessed) { diff --git a/engine/storage/volume/src/org/apache/cloudstack/storage/volume/VolumeServiceImpl.java b/engine/storage/volume/src/org/apache/cloudstack/storage/volume/VolumeServiceImpl.java index ba4693cbfbe..a8d7103d0b9 100644 --- a/engine/storage/volume/src/org/apache/cloudstack/storage/volume/VolumeServiceImpl.java +++ b/engine/storage/volume/src/org/apache/cloudstack/storage/volume/VolumeServiceImpl.java @@ -615,7 +615,7 @@ public class VolumeServiceImpl implements VolumeService { .setContext(context); motionSrv.copyAsync(srcVolume, destVolume, caller); } catch (Exception e) { - s_logger.debug("Failed to copy volume", e); + s_logger.debug("Failed to copy volume" + e); res.setResult(e.toString()); future.complete(res); } diff --git a/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/XenServerStorageProcessor.java b/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/XenServerStorageProcessor.java index 29ffa4e26b7..399e2341b56 100644 --- a/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/XenServerStorageProcessor.java +++ b/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/XenServerStorageProcessor.java @@ -957,7 +957,8 @@ public class XenServerStorageProcessor implements StorageProcessor { try { SR primaryStoragePool = hypervisorResource.getStorageRepository(conn, primaryStore.getUuid()); String srUuid = primaryStoragePool.getUuid(conn); - String volumePath = nfsStore.getUrl() + ":" + srcVolume.getPath(); + URI uri = new URI(nfsStore.getUrl()); + String volumePath = uri.getHost() + ":" + uri.getPath() + File.separator + srcVolume.getPath(); String uuid = copy_vhd_from_secondarystorage(conn, volumePath, srUuid, wait ); VolumeObjectTO newVol = new VolumeObjectTO(); newVol.setPath(uuid); diff --git a/server/src/com/cloud/storage/VolumeManagerImpl.java b/server/src/com/cloud/storage/VolumeManagerImpl.java index e98939dd7ad..17d5ee8bb2b 100644 --- a/server/src/com/cloud/storage/VolumeManagerImpl.java +++ b/server/src/com/cloud/storage/VolumeManagerImpl.java @@ -719,7 +719,7 @@ public class VolumeManagerImpl extends ManagerBase implements VolumeManager { Transaction txn = Transaction.currentTxn(); txn.start(); - VolumeVO volume = new VolumeVO(volumeName, zoneId, -1, -1, -1, + VolumeVO volume = new VolumeVO(volumeName, zoneId, -1L, -1L, -1, new Long(-1), null, null, 0, Volume.Type.DATADISK); Account owner = (caller.getId() == ownerId) ? caller : _accountMgr .getActiveAccountById(ownerId); @@ -965,7 +965,7 @@ public class VolumeManagerImpl extends ManagerBase implements VolumeManager { Transaction txn = Transaction.currentTxn(); txn.start(); - VolumeVO volume = new VolumeVO(userSpecifiedName, -1, -1, -1, -1, + VolumeVO volume = new VolumeVO(userSpecifiedName, -1L, -1L, -1, -1, new Long(-1), null, null, 0, Volume.Type.DATADISK); volume.setPoolId(null); volume.setDataCenterId(zoneId); @@ -2095,7 +2095,7 @@ public class VolumeManagerImpl extends ManagerBase implements VolumeManager { try { VolumeApiResult result = future.get(); if (result.isFailed()) { - s_logger.debug("migrate volume failed:" + result.getResult()); + s_logger.error("migrate volume failed:" + result.getResult()); return null; } return result.getVolume();