mirror of
https://github.com/apache/cloudstack.git
synced 2025-10-26 08:42:29 +01:00
add copy volume and create volume from snapshot
This commit is contained in:
parent
621a779446
commit
020be66f9d
@ -21,6 +21,7 @@ package com.cloud.storage;
|
||||
import org.apache.cloudstack.api.command.user.volume.AttachVolumeCmd;
|
||||
import org.apache.cloudstack.api.command.user.volume.CreateVolumeCmd;
|
||||
import org.apache.cloudstack.api.command.user.volume.DetachVolumeCmd;
|
||||
import org.apache.cloudstack.api.command.user.volume.MigrateVolumeCmd;
|
||||
import org.apache.cloudstack.api.command.user.volume.ResizeVolumeCmd;
|
||||
import org.apache.cloudstack.api.command.user.volume.UploadVolumeCmd;
|
||||
|
||||
@ -61,7 +62,7 @@ public interface VolumeApiService {
|
||||
*/
|
||||
Volume resizeVolume(ResizeVolumeCmd cmd);
|
||||
|
||||
Volume migrateVolume(Long volumeId, Long storagePoolId) throws ConcurrentOperationException;
|
||||
Volume migrateVolume(MigrateVolumeCmd cmd) throws ConcurrentOperationException;
|
||||
|
||||
/**
|
||||
* Uploads the volume to secondary storage
|
||||
|
||||
@ -92,7 +92,7 @@ public class MigrateVolumeCmd extends BaseAsyncCmd {
|
||||
public void execute(){
|
||||
Volume result;
|
||||
try {
|
||||
result = _volumeService.migrateVolume(getVolumeId(), getStoragePoolId());
|
||||
result = _volumeService.migrateVolume(this);
|
||||
if (result != null) {
|
||||
VolumeResponse response = _responseGenerator.createVolumeResponse(result);
|
||||
response.setResponseName(getCommandName());
|
||||
|
||||
@ -329,6 +329,59 @@ public class AncientDataMotionStrategy implements DataMotionStrategy {
|
||||
|
||||
return errMsg;
|
||||
}
|
||||
|
||||
protected String copyVolumeBetweenPools(DataObject srcData, DataObject destData) {
|
||||
VolumeInfo volume = (VolumeInfo)srcData;
|
||||
VolumeInfo destVolume = (VolumeInfo)destData;
|
||||
String secondaryStorageURL = this.templateMgr.getSecondaryStorageURL(volume
|
||||
.getDataCenterId());
|
||||
StoragePool srcPool = (StoragePool)this.dataStoreMgr.getDataStore(volume
|
||||
.getPoolId(), DataStoreRole.Primary);
|
||||
|
||||
StoragePool destPool = (StoragePool)this.dataStoreMgr.getDataStore(destVolume.getPoolId(), DataStoreRole.Primary);
|
||||
|
||||
String value = this.configDao.getValue(Config.CopyVolumeWait.toString());
|
||||
int _copyvolumewait = NumbersUtil.parseInt(value,
|
||||
Integer.parseInt(Config.CopyVolumeWait.getDefaultValue()));
|
||||
CopyVolumeCommand cvCmd = new CopyVolumeCommand(volume.getId(),
|
||||
volume.getPath(), srcPool, secondaryStorageURL, true,
|
||||
_copyvolumewait);
|
||||
CopyVolumeAnswer cvAnswer;
|
||||
try {
|
||||
cvAnswer = (CopyVolumeAnswer) this.storagMgr.sendToPool(srcPool, cvCmd);
|
||||
} catch (StorageUnavailableException e1) {
|
||||
throw new CloudRuntimeException(
|
||||
"Failed to copy the volume from the source primary storage pool to secondary storage.",
|
||||
e1);
|
||||
}
|
||||
|
||||
if (cvAnswer == null || !cvAnswer.getResult()) {
|
||||
throw new CloudRuntimeException(
|
||||
"Failed to copy the volume from the source primary storage pool to secondary storage.");
|
||||
}
|
||||
|
||||
String secondaryStorageVolumePath = cvAnswer.getVolumePath();
|
||||
|
||||
cvCmd = new CopyVolumeCommand(volume.getId(),
|
||||
secondaryStorageVolumePath, destPool,
|
||||
secondaryStorageURL, false, _copyvolumewait);
|
||||
try {
|
||||
cvAnswer = (CopyVolumeAnswer) this.storagMgr.sendToPool(destPool, cvCmd);
|
||||
} catch (StorageUnavailableException e1) {
|
||||
throw new CloudRuntimeException(
|
||||
"Failed to copy the volume from secondary storage to the destination primary storage pool.");
|
||||
}
|
||||
|
||||
if (cvAnswer == null || !cvAnswer.getResult()) {
|
||||
throw new CloudRuntimeException(
|
||||
"Failed to copy the volume from secondary storage to the destination primary storage pool.");
|
||||
}
|
||||
|
||||
VolumeVO destVol = this.volDao.findById(destVolume.getId());
|
||||
destVol.setPath(cvAnswer.getVolumePath());
|
||||
this.volDao.update(destVol.getId(), destVol);
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void copyAsync(DataObject srcData, DataObject destData,
|
||||
@ -336,7 +389,7 @@ public class AncientDataMotionStrategy implements DataMotionStrategy {
|
||||
String errMsg = null;
|
||||
try {
|
||||
if (destData.getType() == DataObjectType.VOLUME
|
||||
&& srcData.getType() == DataObjectType.VOLUME) {
|
||||
&& srcData.getType() == DataObjectType.VOLUME && srcData.getDataStore().getRole() == DataStoreRole.Image) {
|
||||
errMsg = copyVolumeFromImage(srcData, destData);
|
||||
} else if (destData.getType() == DataObjectType.TEMPLATE
|
||||
&& srcData.getType() == DataObjectType.TEMPLATE) {
|
||||
@ -353,6 +406,9 @@ public class AncientDataMotionStrategy implements DataMotionStrategy {
|
||||
} else if (srcData.getType() == DataObjectType.TEMPLATE
|
||||
&& destData.getType() == DataObjectType.VOLUME) {
|
||||
errMsg = cloneVolume(srcData, destData);
|
||||
} else if (destData.getType() == DataObjectType.VOLUME
|
||||
&& srcData.getType() == DataObjectType.VOLUME && srcData.getDataStore().getRole() == DataStoreRole.Primary) {
|
||||
errMsg = copyVolumeBetweenPools(srcData, destData);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
s_logger.debug("copy failed", e);
|
||||
|
||||
@ -45,12 +45,14 @@ import org.apache.log4j.Logger;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import com.cloud.exception.ConcurrentOperationException;
|
||||
import com.cloud.storage.StoragePool;
|
||||
import com.cloud.storage.Volume;
|
||||
import com.cloud.storage.Volume.Type;
|
||||
import com.cloud.storage.VolumeVO;
|
||||
import com.cloud.storage.dao.VolumeDao;
|
||||
import com.cloud.storage.snapshot.SnapshotManager;
|
||||
import com.cloud.utils.db.DB;
|
||||
import com.cloud.utils.exception.CloudRuntimeException;
|
||||
import com.cloud.vm.VirtualMachine;
|
||||
import com.cloud.vm.dao.VMInstanceDao;
|
||||
|
||||
@ -420,14 +422,105 @@ public class VolumeServiceImpl implements VolumeService {
|
||||
@Override
|
||||
public AsyncCallFuture<VolumeApiResult> createVolumeFromSnapshot(
|
||||
VolumeInfo volume, DataStore store, SnapshotInfo snapshot) {
|
||||
// TODO Auto-generated method stub
|
||||
AsyncCallFuture<VolumeApiResult> future = new AsyncCallFuture<VolumeApiResult>();
|
||||
VolumeApiResult result = new VolumeApiResult(volume);
|
||||
return null;
|
||||
}
|
||||
|
||||
protected VolumeVO duplicateVolumeOnAnotherStorage(Volume volume, StoragePool pool) {
|
||||
Long lastPoolId = volume.getPoolId();
|
||||
VolumeVO newVol = new VolumeVO(volume);
|
||||
newVol.setPoolId(pool.getId());
|
||||
newVol.setFolder(pool.getPath());
|
||||
newVol.setPodId(pool.getPodId());
|
||||
newVol.setPoolId(pool.getId());
|
||||
newVol.setLastPoolId(lastPoolId);
|
||||
newVol.setPodId(pool.getPodId());
|
||||
return this.volDao.persist(newVol);
|
||||
}
|
||||
|
||||
|
||||
private class CopyVolumeContext<T> extends AsyncRpcConext<T> {
|
||||
final VolumeInfo srcVolume;
|
||||
final VolumeInfo destVolume;
|
||||
final DataStore destStore;
|
||||
final AsyncCallFuture<VolumeApiResult> future;
|
||||
/**
|
||||
* @param callback
|
||||
*/
|
||||
public CopyVolumeContext(AsyncCompletionCallback<T> callback, AsyncCallFuture<VolumeApiResult> future, VolumeInfo srcVolume, VolumeInfo destVolume,
|
||||
DataStore destStore) {
|
||||
super(callback);
|
||||
this.srcVolume = srcVolume;
|
||||
this.destVolume = destVolume;
|
||||
this.destStore = destStore;
|
||||
this.future = future;
|
||||
}
|
||||
|
||||
}
|
||||
@Override
|
||||
public AsyncCallFuture<VolumeApiResult> copyVolume(VolumeInfo srcVolume,
|
||||
DataStore destStore) {
|
||||
// TODO Auto-generated method stub
|
||||
AsyncCallFuture<VolumeApiResult> future = new AsyncCallFuture<VolumeApiResult>();
|
||||
VolumeApiResult res = new VolumeApiResult(srcVolume);
|
||||
try {
|
||||
if (!this.snapshotMgr.canOperateOnVolume(srcVolume)) {
|
||||
s_logger.debug(
|
||||
"There are snapshots creating on this volume, can not move this volume");
|
||||
|
||||
res.setResult("There are snapshots creating on this volume, can not move this volume");
|
||||
future.complete(res);
|
||||
return future;
|
||||
}
|
||||
|
||||
VolumeVO destVol = duplicateVolumeOnAnotherStorage(srcVolume, (StoragePool)destStore);
|
||||
VolumeInfo destVolume = this.volFactory.getVolume(destVol.getId(), destStore);
|
||||
destVolume.processEvent(Event.CreateOnlyRequested);
|
||||
srcVolume.processEvent(Event.CopyingRequested);
|
||||
|
||||
CopyVolumeContext<VolumeApiResult> context = new CopyVolumeContext<VolumeApiResult>(null, future, srcVolume,
|
||||
destVolume,
|
||||
destStore);
|
||||
AsyncCallbackDispatcher<VolumeServiceImpl, CopyCommandResult> caller = AsyncCallbackDispatcher.create(this);
|
||||
caller.setCallback(caller.getTarget().copyVolumeCallBack(null, null))
|
||||
.setContext(context);
|
||||
this.motionSrv.copyAsync(srcVolume, destVolume, caller);
|
||||
} catch (Exception e) {
|
||||
s_logger.debug("Failed to copy volume", e);
|
||||
res.setResult(e.toString());
|
||||
future.complete(res);
|
||||
}
|
||||
return future;
|
||||
}
|
||||
|
||||
protected Void copyVolumeCallBack(AsyncCallbackDispatcher<VolumeServiceImpl, CopyCommandResult> callback, CopyVolumeContext<VolumeApiResult> context) {
|
||||
VolumeInfo srcVolume = context.srcVolume;
|
||||
VolumeInfo destVolume = context.destVolume;
|
||||
CopyCommandResult result = callback.getResult();
|
||||
AsyncCallFuture<VolumeApiResult> future = context.future;
|
||||
VolumeApiResult res = new VolumeApiResult(destVolume);
|
||||
try {
|
||||
if (result.isFailed()) {
|
||||
res.setResult(result.getResult());
|
||||
destVolume.processEvent(Event.OperationFailed);
|
||||
srcVolume.processEvent(Event.OperationFailed);
|
||||
AsyncCallFuture<VolumeApiResult> destroyFuture = this.expungeVolumeAsync(destVolume);
|
||||
destroyFuture.get();
|
||||
future.complete(res);
|
||||
return null;
|
||||
}
|
||||
srcVolume.processEvent(Event.OperationSuccessed);
|
||||
destVolume.processEvent(Event.OperationSuccessed);
|
||||
AsyncCallFuture<VolumeApiResult> destroyFuture = this.expungeVolumeAsync(srcVolume);
|
||||
destroyFuture.get();
|
||||
future.complete(res);
|
||||
return null;
|
||||
} catch (Exception e) {
|
||||
s_logger.debug("Failed to process copy volume callback",e);
|
||||
res.setResult(e.toString());
|
||||
future.complete(res);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
@ -21,6 +21,7 @@ package com.cloud.storage;
|
||||
import org.apache.cloudstack.api.command.user.volume.AttachVolumeCmd;
|
||||
import org.apache.cloudstack.api.command.user.volume.CreateVolumeCmd;
|
||||
import org.apache.cloudstack.api.command.user.volume.DetachVolumeCmd;
|
||||
import org.apache.cloudstack.api.command.user.volume.MigrateVolumeCmd;
|
||||
import org.apache.cloudstack.api.command.user.volume.ResizeVolumeCmd;
|
||||
import org.apache.cloudstack.api.command.user.volume.UploadVolumeCmd;
|
||||
import org.apache.cloudstack.engine.subsystem.api.storage.VolumeInfo;
|
||||
@ -76,12 +77,11 @@ public interface VolumeManager extends VolumeApiService {
|
||||
|
||||
void cleanupVolumes(long vmId) throws ConcurrentOperationException;
|
||||
|
||||
Volume migrateVolume(Long volumeId, Long storagePoolId)
|
||||
throws ConcurrentOperationException;
|
||||
Volume migrateVolume(MigrateVolumeCmd cmd);
|
||||
|
||||
boolean StorageMigration(
|
||||
boolean storageMigration(
|
||||
VirtualMachineProfile<? extends VirtualMachine> vm,
|
||||
StoragePool destPool) throws ConcurrentOperationException;
|
||||
StoragePool destPool);
|
||||
|
||||
void prepareForMigration(
|
||||
VirtualMachineProfile<? extends VirtualMachine> vm,
|
||||
|
||||
@ -39,6 +39,7 @@ import org.apache.cloudstack.api.BaseCmd;
|
||||
import org.apache.cloudstack.api.command.user.volume.AttachVolumeCmd;
|
||||
import org.apache.cloudstack.api.command.user.volume.CreateVolumeCmd;
|
||||
import org.apache.cloudstack.api.command.user.volume.DetachVolumeCmd;
|
||||
import org.apache.cloudstack.api.command.user.volume.MigrateVolumeCmd;
|
||||
import org.apache.cloudstack.api.command.user.volume.ResizeVolumeCmd;
|
||||
import org.apache.cloudstack.api.command.user.volume.UploadVolumeCmd;
|
||||
import org.apache.cloudstack.engine.subsystem.api.storage.DataStore;
|
||||
@ -351,11 +352,9 @@ public class VolumeManagerImpl extends ManagerBase implements VolumeManager {
|
||||
throw new CloudRuntimeException(
|
||||
"Failed to find a storage pool with enough capacity to move the volume to.");
|
||||
}
|
||||
|
||||
List<Volume> vols = new ArrayList<Volume>();
|
||||
vols.add(volume);
|
||||
migrateVolumes(vols, destPool);
|
||||
return this.volFactory.getVolume(volume.getId());
|
||||
|
||||
Volume newVol = migrateVolume(volume, destPool);
|
||||
return this.volFactory.getVolume(newVol.getId());
|
||||
}
|
||||
|
||||
/*
|
||||
@ -1012,10 +1011,15 @@ public class VolumeManagerImpl extends ManagerBase implements VolumeManager {
|
||||
@DB
|
||||
@ActionEvent(eventType = EventTypes.EVENT_VOLUME_RESIZE, eventDescription = "resizing volume", async = true)
|
||||
public VolumeVO resizeVolume(ResizeVolumeCmd cmd) {
|
||||
VolumeVO volume = _volsDao.findById(cmd.getEntityId());
|
||||
Long newSize = null;
|
||||
boolean shrinkOk = cmd.getShrinkOk();
|
||||
boolean success = false;
|
||||
|
||||
VolumeVO volume = _volsDao.findById(cmd.getEntityId());
|
||||
if (volume == null) {
|
||||
throw new InvalidParameterValueException("No such volume");
|
||||
}
|
||||
|
||||
DiskOfferingVO diskOffering = _diskOfferingDao.findById(volume
|
||||
.getDiskOfferingId());
|
||||
DiskOfferingVO newDiskOffering = null;
|
||||
@ -1039,9 +1043,6 @@ public class VolumeManagerImpl extends ManagerBase implements VolumeManager {
|
||||
"Cloudstack currently only supports volumes marked as KVM or XenServer hypervisor for resize");
|
||||
}
|
||||
|
||||
if (volume == null) {
|
||||
throw new InvalidParameterValueException("No such volume");
|
||||
}
|
||||
|
||||
if (volume.getState() != Volume.State.Ready) {
|
||||
throw new InvalidParameterValueException(
|
||||
@ -1995,8 +1996,10 @@ public class VolumeManagerImpl extends ManagerBase implements VolumeManager {
|
||||
|
||||
@DB
|
||||
@Override
|
||||
public Volume migrateVolume(Long volumeId, Long storagePoolId)
|
||||
throws ConcurrentOperationException {
|
||||
public Volume migrateVolume(MigrateVolumeCmd cmd) {
|
||||
Long volumeId = cmd.getVolumeId();
|
||||
Long storagePoolId = cmd.getStoragePoolId();
|
||||
|
||||
VolumeVO vol = _volsDao.findById(volumeId);
|
||||
if (vol == null) {
|
||||
throw new InvalidParameterValueException(
|
||||
@ -2025,171 +2028,36 @@ public class VolumeManagerImpl extends ManagerBase implements VolumeManager {
|
||||
"Migration of volume from local storage pool is not supported");
|
||||
}
|
||||
|
||||
List<Volume> vols = new ArrayList<Volume>();
|
||||
vols.add(vol);
|
||||
|
||||
migrateVolumes(vols, destPool);
|
||||
return vol;
|
||||
Volume newVol = migrateVolume(vol, destPool);
|
||||
return newVol;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@DB
|
||||
public boolean migrateVolumes(List<Volume> volumes, StoragePool destPool)
|
||||
throws ConcurrentOperationException {
|
||||
Transaction txn = Transaction.currentTxn();
|
||||
txn.start();
|
||||
|
||||
boolean transitResult = false;
|
||||
long checkPointTaskId = -1;
|
||||
protected Volume migrateVolume(Volume volume, StoragePool destPool) {
|
||||
VolumeInfo vol = this.volFactory.getVolume(volume.getId());
|
||||
AsyncCallFuture<VolumeApiResult> future = this.volService.copyVolume(vol, (DataStore)destPool);
|
||||
try {
|
||||
List<Long> volIds = new ArrayList<Long>();
|
||||
for (Volume volume : volumes) {
|
||||
if (!_snapshotMgr.canOperateOnVolume((VolumeVO) volume)) {
|
||||
throw new CloudRuntimeException(
|
||||
"There are snapshots creating on this volume, can not move this volume");
|
||||
}
|
||||
|
||||
try {
|
||||
if (!stateTransitTo(volume, Volume.Event.MigrationRequested)) {
|
||||
throw new ConcurrentOperationException(
|
||||
"Failed to transit volume state");
|
||||
}
|
||||
} catch (NoTransitionException e) {
|
||||
s_logger.debug("Failed to set state into migrate: "
|
||||
+ e.toString());
|
||||
throw new CloudRuntimeException(
|
||||
"Failed to set state into migrate: " + e.toString());
|
||||
}
|
||||
volIds.add(volume.getId());
|
||||
}
|
||||
|
||||
transitResult = true;
|
||||
} finally {
|
||||
if (!transitResult) {
|
||||
txn.rollback();
|
||||
} else {
|
||||
txn.commit();
|
||||
VolumeApiResult result = future.get();
|
||||
if (result.isFailed()) {
|
||||
s_logger.debug("migrate volume failed:" + result.getResult());
|
||||
return null;
|
||||
}
|
||||
return result.getVolume();
|
||||
} catch (InterruptedException e) {
|
||||
s_logger.debug("migrate volume failed", e);
|
||||
return null;
|
||||
} catch (ExecutionException e) {
|
||||
s_logger.debug("migrate volume failed", e);
|
||||
return null;
|
||||
}
|
||||
|
||||
// At this stage, nobody can modify volumes. Send the copyvolume command
|
||||
List<Pair<StoragePool, DestroyCommand>> destroyCmds = new ArrayList<Pair<StoragePool, DestroyCommand>>();
|
||||
List<CopyVolumeAnswer> answers = new ArrayList<CopyVolumeAnswer>();
|
||||
try {
|
||||
for (Volume volume : volumes) {
|
||||
String secondaryStorageURL = this._tmpltMgr.getSecondaryStorageURL(volume
|
||||
.getDataCenterId());
|
||||
StoragePool srcPool = (StoragePool)this.dataStoreMgr.getDataStore(volume
|
||||
.getPoolId(), DataStoreRole.Primary);
|
||||
CopyVolumeCommand cvCmd = new CopyVolumeCommand(volume.getId(),
|
||||
volume.getPath(), srcPool, secondaryStorageURL, true,
|
||||
_copyvolumewait);
|
||||
CopyVolumeAnswer cvAnswer;
|
||||
try {
|
||||
cvAnswer = (CopyVolumeAnswer) this.storageMgr.sendToPool(srcPool, cvCmd);
|
||||
} catch (StorageUnavailableException e1) {
|
||||
throw new CloudRuntimeException(
|
||||
"Failed to copy the volume from the source primary storage pool to secondary storage.",
|
||||
e1);
|
||||
}
|
||||
|
||||
if (cvAnswer == null || !cvAnswer.getResult()) {
|
||||
throw new CloudRuntimeException(
|
||||
"Failed to copy the volume from the source primary storage pool to secondary storage.");
|
||||
}
|
||||
|
||||
String secondaryStorageVolumePath = cvAnswer.getVolumePath();
|
||||
|
||||
// Copy the volume from secondary storage to the destination
|
||||
// storage
|
||||
// pool
|
||||
cvCmd = new CopyVolumeCommand(volume.getId(),
|
||||
secondaryStorageVolumePath, destPool,
|
||||
secondaryStorageURL, false, _copyvolumewait);
|
||||
try {
|
||||
cvAnswer = (CopyVolumeAnswer) this.storageMgr.sendToPool(destPool, cvCmd);
|
||||
} catch (StorageUnavailableException e1) {
|
||||
throw new CloudRuntimeException(
|
||||
"Failed to copy the volume from secondary storage to the destination primary storage pool.");
|
||||
}
|
||||
|
||||
if (cvAnswer == null || !cvAnswer.getResult()) {
|
||||
throw new CloudRuntimeException(
|
||||
"Failed to copy the volume from secondary storage to the destination primary storage pool.");
|
||||
}
|
||||
|
||||
answers.add(cvAnswer);
|
||||
destroyCmds.add(new Pair<StoragePool, DestroyCommand>(
|
||||
srcPool, new DestroyCommand(srcPool, volume, null)));
|
||||
}
|
||||
} finally {
|
||||
if (answers.size() != volumes.size()) {
|
||||
// this means one of copying volume failed
|
||||
for (Volume volume : volumes) {
|
||||
try {
|
||||
stateTransitTo(volume, Volume.Event.OperationFailed);
|
||||
} catch (NoTransitionException e) {
|
||||
s_logger.debug("Failed to change volume state: "
|
||||
+ e.toString());
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Need a transaction, make sure all the volumes get migrated to
|
||||
// new storage pool
|
||||
txn = Transaction.currentTxn();
|
||||
txn.start();
|
||||
|
||||
transitResult = false;
|
||||
try {
|
||||
for (int i = 0; i < volumes.size(); i++) {
|
||||
CopyVolumeAnswer answer = answers.get(i);
|
||||
VolumeVO volume = (VolumeVO) volumes.get(i);
|
||||
Long oldPoolId = volume.getPoolId();
|
||||
volume.setPath(answer.getVolumePath());
|
||||
volume.setFolder(destPool.getPath());
|
||||
volume.setPodId(destPool.getPodId());
|
||||
volume.setPoolId(destPool.getId());
|
||||
volume.setLastPoolId(oldPoolId);
|
||||
volume.setPodId(destPool.getPodId());
|
||||
try {
|
||||
stateTransitTo(volume,
|
||||
Volume.Event.OperationSucceeded);
|
||||
} catch (NoTransitionException e) {
|
||||
s_logger.debug("Failed to change volume state: "
|
||||
+ e.toString());
|
||||
throw new CloudRuntimeException(
|
||||
"Failed to change volume state: "
|
||||
+ e.toString());
|
||||
}
|
||||
}
|
||||
transitResult = true;
|
||||
} finally {
|
||||
if (!transitResult) {
|
||||
txn.rollback();
|
||||
} else {
|
||||
txn.commit();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// all the volumes get migrated to new storage pool, need to delete the
|
||||
// copy on old storage pool
|
||||
for (Pair<StoragePool, DestroyCommand> cmd : destroyCmds) {
|
||||
try {
|
||||
Answer cvAnswer = this.storageMgr.sendToPool(cmd.first(), cmd.second());
|
||||
} catch (StorageUnavailableException e) {
|
||||
s_logger.debug("Unable to delete the old copy on storage pool: "
|
||||
+ e.toString());
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean StorageMigration(
|
||||
public boolean storageMigration(
|
||||
VirtualMachineProfile<? extends VirtualMachine> vm,
|
||||
StoragePool destPool) throws ConcurrentOperationException {
|
||||
StoragePool destPool) {
|
||||
List<VolumeVO> vols = _volsDao.findUsableVolumesForInstance(vm.getId());
|
||||
List<Volume> volumesNeedToMigrate = new ArrayList<Volume>();
|
||||
|
||||
@ -2215,7 +2083,13 @@ public class VolumeManagerImpl extends ManagerBase implements VolumeManager {
|
||||
return true;
|
||||
}
|
||||
|
||||
return migrateVolumes(volumesNeedToMigrate, destPool);
|
||||
for (Volume vol : volumesNeedToMigrate) {
|
||||
Volume result = migrateVolume(vol, destPool);
|
||||
if (result == null) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -2452,9 +2326,7 @@ public class VolumeManagerImpl extends ManagerBase implements VolumeManager {
|
||||
vol = task.volume;
|
||||
} else if (task.type == VolumeTaskType.MIGRATE) {
|
||||
pool = (StoragePool)dataStoreMgr.getDataStore(task.pool.getId(), DataStoreRole.Primary);
|
||||
List<Volume> volumes = new ArrayList<Volume>();
|
||||
volumes.add(task.volume);
|
||||
migrateVolumes(volumes, pool);
|
||||
migrateVolume(task.volume, pool);
|
||||
vol = task.volume;
|
||||
} else if (task.type == VolumeTaskType.RECREATE) {
|
||||
Pair<VolumeVO, DataStore> result = recreateVolume(task.volume, vm, dest);
|
||||
|
||||
@ -22,6 +22,7 @@ import com.cloud.exception.ResourceAllocationException;
|
||||
import com.cloud.host.HostVO;
|
||||
import com.cloud.storage.SnapshotPolicyVO;
|
||||
import com.cloud.storage.SnapshotVO;
|
||||
import com.cloud.storage.Volume;
|
||||
import com.cloud.storage.VolumeVO;
|
||||
import com.cloud.utils.db.Filter;
|
||||
|
||||
@ -138,5 +139,5 @@ public interface SnapshotManager {
|
||||
|
||||
void deleteSnapshotsDirForVolume(String secondaryStoragePoolUrl, Long dcId, Long accountId, Long volumeId);
|
||||
|
||||
boolean canOperateOnVolume(VolumeVO volume);
|
||||
boolean canOperateOnVolume(Volume volume);
|
||||
}
|
||||
|
||||
@ -1578,7 +1578,7 @@ public class SnapshotManagerImpl extends ManagerBase implements SnapshotManager,
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canOperateOnVolume(VolumeVO volume) {
|
||||
public boolean canOperateOnVolume(Volume volume) {
|
||||
List<SnapshotVO> snapshots = _snapshotDao.listByStatus(volume.getId(), Snapshot.State.Creating,
|
||||
Snapshot.State.CreatedOnPrimary, Snapshot.State.BackingUp);
|
||||
if (snapshots.size() > 0) {
|
||||
|
||||
@ -1226,7 +1226,7 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac
|
||||
VirtualMachineProfile<VMInstanceVO> profile = new VirtualMachineProfileImpl<VMInstanceVO>(vm);
|
||||
boolean migrationResult = false;
|
||||
try {
|
||||
migrationResult = this.volumeMgr.StorageMigration(profile, destPool);
|
||||
migrationResult = this.volumeMgr.storageMigration(profile, destPool);
|
||||
|
||||
if (migrationResult) {
|
||||
//if the vm is migrated to different pod in basic mode, need to reallocate ip
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user