Skip to content

Commit 020be66

Browse files
committed
add copy volume and create volume from snapshot
1 parent 621a779 commit 020be66

9 files changed

Lines changed: 205 additions & 182 deletions

File tree

api/src/com/cloud/storage/VolumeApiService.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
import org.apache.cloudstack.api.command.user.volume.AttachVolumeCmd;
2222
import org.apache.cloudstack.api.command.user.volume.CreateVolumeCmd;
2323
import org.apache.cloudstack.api.command.user.volume.DetachVolumeCmd;
24+
import org.apache.cloudstack.api.command.user.volume.MigrateVolumeCmd;
2425
import org.apache.cloudstack.api.command.user.volume.ResizeVolumeCmd;
2526
import org.apache.cloudstack.api.command.user.volume.UploadVolumeCmd;
2627

@@ -61,7 +62,7 @@ public interface VolumeApiService {
6162
*/
6263
Volume resizeVolume(ResizeVolumeCmd cmd);
6364

64-
Volume migrateVolume(Long volumeId, Long storagePoolId) throws ConcurrentOperationException;
65+
Volume migrateVolume(MigrateVolumeCmd cmd) throws ConcurrentOperationException;
6566

6667
/**
6768
* Uploads the volume to secondary storage

api/src/org/apache/cloudstack/api/command/user/volume/MigrateVolumeCmd.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ public String getEventDescription() {
9292
public void execute(){
9393
Volume result;
9494
try {
95-
result = _volumeService.migrateVolume(getVolumeId(), getStoragePoolId());
95+
result = _volumeService.migrateVolume(this);
9696
if (result != null) {
9797
VolumeResponse response = _responseGenerator.createVolumeResponse(result);
9898
response.setResponseName(getCommandName());

engine/storage/src/org/apache/cloudstack/storage/motion/AncientDataMotionStrategy.java

Lines changed: 57 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -329,14 +329,67 @@ protected String cloneVolume(DataObject template, DataObject volume) {
329329

330330
return errMsg;
331331
}
332+
333+
protected String copyVolumeBetweenPools(DataObject srcData, DataObject destData) {
334+
VolumeInfo volume = (VolumeInfo)srcData;
335+
VolumeInfo destVolume = (VolumeInfo)destData;
336+
String secondaryStorageURL = this.templateMgr.getSecondaryStorageURL(volume
337+
.getDataCenterId());
338+
StoragePool srcPool = (StoragePool)this.dataStoreMgr.getDataStore(volume
339+
.getPoolId(), DataStoreRole.Primary);
340+
341+
StoragePool destPool = (StoragePool)this.dataStoreMgr.getDataStore(destVolume.getPoolId(), DataStoreRole.Primary);
342+
343+
String value = this.configDao.getValue(Config.CopyVolumeWait.toString());
344+
int _copyvolumewait = NumbersUtil.parseInt(value,
345+
Integer.parseInt(Config.CopyVolumeWait.getDefaultValue()));
346+
CopyVolumeCommand cvCmd = new CopyVolumeCommand(volume.getId(),
347+
volume.getPath(), srcPool, secondaryStorageURL, true,
348+
_copyvolumewait);
349+
CopyVolumeAnswer cvAnswer;
350+
try {
351+
cvAnswer = (CopyVolumeAnswer) this.storagMgr.sendToPool(srcPool, cvCmd);
352+
} catch (StorageUnavailableException e1) {
353+
throw new CloudRuntimeException(
354+
"Failed to copy the volume from the source primary storage pool to secondary storage.",
355+
e1);
356+
}
357+
358+
if (cvAnswer == null || !cvAnswer.getResult()) {
359+
throw new CloudRuntimeException(
360+
"Failed to copy the volume from the source primary storage pool to secondary storage.");
361+
}
362+
363+
String secondaryStorageVolumePath = cvAnswer.getVolumePath();
364+
365+
cvCmd = new CopyVolumeCommand(volume.getId(),
366+
secondaryStorageVolumePath, destPool,
367+
secondaryStorageURL, false, _copyvolumewait);
368+
try {
369+
cvAnswer = (CopyVolumeAnswer) this.storagMgr.sendToPool(destPool, cvCmd);
370+
} catch (StorageUnavailableException e1) {
371+
throw new CloudRuntimeException(
372+
"Failed to copy the volume from secondary storage to the destination primary storage pool.");
373+
}
374+
375+
if (cvAnswer == null || !cvAnswer.getResult()) {
376+
throw new CloudRuntimeException(
377+
"Failed to copy the volume from secondary storage to the destination primary storage pool.");
378+
}
379+
380+
VolumeVO destVol = this.volDao.findById(destVolume.getId());
381+
destVol.setPath(cvAnswer.getVolumePath());
382+
this.volDao.update(destVol.getId(), destVol);
383+
return null;
384+
}
332385

333386
@Override
334387
public Void copyAsync(DataObject srcData, DataObject destData,
335388
AsyncCompletionCallback<CopyCommandResult> callback) {
336389
String errMsg = null;
337390
try {
338391
if (destData.getType() == DataObjectType.VOLUME
339-
&& srcData.getType() == DataObjectType.VOLUME) {
392+
&& srcData.getType() == DataObjectType.VOLUME && srcData.getDataStore().getRole() == DataStoreRole.Image) {
340393
errMsg = copyVolumeFromImage(srcData, destData);
341394
} else if (destData.getType() == DataObjectType.TEMPLATE
342395
&& srcData.getType() == DataObjectType.TEMPLATE) {
@@ -353,6 +406,9 @@ public Void copyAsync(DataObject srcData, DataObject destData,
353406
} else if (srcData.getType() == DataObjectType.TEMPLATE
354407
&& destData.getType() == DataObjectType.VOLUME) {
355408
errMsg = cloneVolume(srcData, destData);
409+
} else if (destData.getType() == DataObjectType.VOLUME
410+
&& srcData.getType() == DataObjectType.VOLUME && srcData.getDataStore().getRole() == DataStoreRole.Primary) {
411+
errMsg = copyVolumeBetweenPools(srcData, destData);
356412
}
357413
} catch (Exception e) {
358414
s_logger.debug("copy failed", e);

engine/storage/volume/src/org/apache/cloudstack/storage/volume/VolumeServiceImpl.java

Lines changed: 95 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,12 +45,14 @@
4545
import org.springframework.stereotype.Component;
4646

4747
import com.cloud.exception.ConcurrentOperationException;
48+
import com.cloud.storage.StoragePool;
4849
import com.cloud.storage.Volume;
4950
import com.cloud.storage.Volume.Type;
5051
import com.cloud.storage.VolumeVO;
5152
import com.cloud.storage.dao.VolumeDao;
5253
import com.cloud.storage.snapshot.SnapshotManager;
5354
import com.cloud.utils.db.DB;
55+
import com.cloud.utils.exception.CloudRuntimeException;
5456
import com.cloud.vm.VirtualMachine;
5557
import com.cloud.vm.dao.VMInstanceDao;
5658

@@ -420,14 +422,105 @@ public boolean destroyVolume(long volumeId)
420422
@Override
421423
public AsyncCallFuture<VolumeApiResult> createVolumeFromSnapshot(
422424
VolumeInfo volume, DataStore store, SnapshotInfo snapshot) {
423-
// TODO Auto-generated method stub
425+
AsyncCallFuture<VolumeApiResult> future = new AsyncCallFuture<VolumeApiResult>();
426+
VolumeApiResult result = new VolumeApiResult(volume);
424427
return null;
425428
}
429+
430+
protected VolumeVO duplicateVolumeOnAnotherStorage(Volume volume, StoragePool pool) {
431+
Long lastPoolId = volume.getPoolId();
432+
VolumeVO newVol = new VolumeVO(volume);
433+
newVol.setPoolId(pool.getId());
434+
newVol.setFolder(pool.getPath());
435+
newVol.setPodId(pool.getPodId());
436+
newVol.setPoolId(pool.getId());
437+
newVol.setLastPoolId(lastPoolId);
438+
newVol.setPodId(pool.getPodId());
439+
return this.volDao.persist(newVol);
440+
}
441+
426442

443+
private class CopyVolumeContext<T> extends AsyncRpcConext<T> {
444+
final VolumeInfo srcVolume;
445+
final VolumeInfo destVolume;
446+
final DataStore destStore;
447+
final AsyncCallFuture<VolumeApiResult> future;
448+
/**
449+
* @param callback
450+
*/
451+
public CopyVolumeContext(AsyncCompletionCallback<T> callback, AsyncCallFuture<VolumeApiResult> future, VolumeInfo srcVolume, VolumeInfo destVolume,
452+
DataStore destStore) {
453+
super(callback);
454+
this.srcVolume = srcVolume;
455+
this.destVolume = destVolume;
456+
this.destStore = destStore;
457+
this.future = future;
458+
}
459+
460+
}
427461
@Override
428462
public AsyncCallFuture<VolumeApiResult> copyVolume(VolumeInfo srcVolume,
429463
DataStore destStore) {
430-
// TODO Auto-generated method stub
464+
AsyncCallFuture<VolumeApiResult> future = new AsyncCallFuture<VolumeApiResult>();
465+
VolumeApiResult res = new VolumeApiResult(srcVolume);
466+
try {
467+
if (!this.snapshotMgr.canOperateOnVolume(srcVolume)) {
468+
s_logger.debug(
469+
"There are snapshots creating on this volume, can not move this volume");
470+
471+
res.setResult("There are snapshots creating on this volume, can not move this volume");
472+
future.complete(res);
473+
return future;
474+
}
475+
476+
VolumeVO destVol = duplicateVolumeOnAnotherStorage(srcVolume, (StoragePool)destStore);
477+
VolumeInfo destVolume = this.volFactory.getVolume(destVol.getId(), destStore);
478+
destVolume.processEvent(Event.CreateOnlyRequested);
479+
srcVolume.processEvent(Event.CopyingRequested);
480+
481+
CopyVolumeContext<VolumeApiResult> context = new CopyVolumeContext<VolumeApiResult>(null, future, srcVolume,
482+
destVolume,
483+
destStore);
484+
AsyncCallbackDispatcher<VolumeServiceImpl, CopyCommandResult> caller = AsyncCallbackDispatcher.create(this);
485+
caller.setCallback(caller.getTarget().copyVolumeCallBack(null, null))
486+
.setContext(context);
487+
this.motionSrv.copyAsync(srcVolume, destVolume, caller);
488+
} catch (Exception e) {
489+
s_logger.debug("Failed to copy volume", e);
490+
res.setResult(e.toString());
491+
future.complete(res);
492+
}
493+
return future;
494+
}
495+
496+
protected Void copyVolumeCallBack(AsyncCallbackDispatcher<VolumeServiceImpl, CopyCommandResult> callback, CopyVolumeContext<VolumeApiResult> context) {
497+
VolumeInfo srcVolume = context.srcVolume;
498+
VolumeInfo destVolume = context.destVolume;
499+
CopyCommandResult result = callback.getResult();
500+
AsyncCallFuture<VolumeApiResult> future = context.future;
501+
VolumeApiResult res = new VolumeApiResult(destVolume);
502+
try {
503+
if (result.isFailed()) {
504+
res.setResult(result.getResult());
505+
destVolume.processEvent(Event.OperationFailed);
506+
srcVolume.processEvent(Event.OperationFailed);
507+
AsyncCallFuture<VolumeApiResult> destroyFuture = this.expungeVolumeAsync(destVolume);
508+
destroyFuture.get();
509+
future.complete(res);
510+
return null;
511+
}
512+
srcVolume.processEvent(Event.OperationSuccessed);
513+
destVolume.processEvent(Event.OperationSuccessed);
514+
AsyncCallFuture<VolumeApiResult> destroyFuture = this.expungeVolumeAsync(srcVolume);
515+
destroyFuture.get();
516+
future.complete(res);
517+
return null;
518+
} catch (Exception e) {
519+
s_logger.debug("Failed to process copy volume callback",e);
520+
res.setResult(e.toString());
521+
future.complete(res);
522+
}
523+
431524
return null;
432525
}
433526

server/src/com/cloud/storage/VolumeManager.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
import org.apache.cloudstack.api.command.user.volume.AttachVolumeCmd;
2222
import org.apache.cloudstack.api.command.user.volume.CreateVolumeCmd;
2323
import org.apache.cloudstack.api.command.user.volume.DetachVolumeCmd;
24+
import org.apache.cloudstack.api.command.user.volume.MigrateVolumeCmd;
2425
import org.apache.cloudstack.api.command.user.volume.ResizeVolumeCmd;
2526
import org.apache.cloudstack.api.command.user.volume.UploadVolumeCmd;
2627
import org.apache.cloudstack.engine.subsystem.api.storage.VolumeInfo;
@@ -76,12 +77,11 @@ boolean deleteVolume(long volumeId, Account caller)
7677

7778
void cleanupVolumes(long vmId) throws ConcurrentOperationException;
7879

79-
Volume migrateVolume(Long volumeId, Long storagePoolId)
80-
throws ConcurrentOperationException;
80+
Volume migrateVolume(MigrateVolumeCmd cmd);
8181

82-
boolean StorageMigration(
82+
boolean storageMigration(
8383
VirtualMachineProfile<? extends VirtualMachine> vm,
84-
StoragePool destPool) throws ConcurrentOperationException;
84+
StoragePool destPool);
8585

8686
void prepareForMigration(
8787
VirtualMachineProfile<? extends VirtualMachine> vm,

0 commit comments

Comments
 (0)