return vol;
}
@DB
public boolean migrateVolumes(List<Volume> volumes, StoragePool destPool) throws ConcurrentOperationException {
Transaction txn = Transaction.currentTxn();
txn.start();
boolean transitResult = false;
long checkPointTaskId = -1;
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());
}
checkPointTaskId = _checkPointMgr.pushCheckPoint(new StorageMigrationCleanupMaid(StorageMigrationCleanupMaid.StorageMigrationState.MIGRATING, volIds));
transitResult = true;
} finally {
if (!transitResult) {
txn.rollback();
} else {
txn.commit();
}
}
// At this stage, nobody can modify volumes. Send the copyvolume command
List<Pair<StoragePoolVO, DestroyCommand>> destroyCmds = new ArrayList<Pair<StoragePoolVO, DestroyCommand>>();
List<CopyVolumeAnswer> answers = new ArrayList<CopyVolumeAnswer>();
try {
for (Volume volume : volumes) {
String secondaryStorageURL = getSecondaryStorageURL(volume.getDataCenterId());
StoragePoolVO srcPool = _storagePoolDao.findById(volume.getPoolId());
CopyVolumeCommand cvCmd = new CopyVolumeCommand(volume.getId(), volume.getPath(), srcPool, secondaryStorageURL, true, _copyvolumewait);
CopyVolumeAnswer cvAnswer;
try {
cvAnswer = (CopyVolumeAnswer) 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) 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<StoragePoolVO, 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());
}
}
_checkPointMgr.popCheckPoint(checkPointTaskId);
} 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;
try {
_checkPointMgr.popCheckPoint(checkPointTaskId);
} catch (Exception e) {
}
} finally {
if (!transitResult) {
txn.rollback();
} else {
txn.commit();
}
}
}
}