CLOUDSTACK-2593: fix migrate volume between pools through secondary storage

This commit is contained in:
Edison Su 2013-05-23 18:25:25 -07:00
parent 98af424053
commit 3ec52807f1
9 changed files with 98 additions and 36 deletions

View File

@ -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

View File

@ -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");
}
}
}

View File

@ -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;

View File

@ -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);

View File

@ -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);

View File

@ -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) {

View File

@ -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);
}

View File

@ -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);

View File

@ -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();