mirror of https://github.com/apache/cloudstack.git
CLOUDSTACK-2593: fix migrate volume between pools through secondary storage
This commit is contained in:
parent
98af424053
commit
3ec52807f1
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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<DataStore> 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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
Loading…
Reference in New Issue