|
45 | 45 | import org.springframework.stereotype.Component; |
46 | 46 |
|
47 | 47 | import com.cloud.exception.ConcurrentOperationException; |
| 48 | +import com.cloud.storage.StoragePool; |
48 | 49 | import com.cloud.storage.Volume; |
49 | 50 | import com.cloud.storage.Volume.Type; |
50 | 51 | import com.cloud.storage.VolumeVO; |
51 | 52 | import com.cloud.storage.dao.VolumeDao; |
52 | 53 | import com.cloud.storage.snapshot.SnapshotManager; |
53 | 54 | import com.cloud.utils.db.DB; |
| 55 | +import com.cloud.utils.exception.CloudRuntimeException; |
54 | 56 | import com.cloud.vm.VirtualMachine; |
55 | 57 | import com.cloud.vm.dao.VMInstanceDao; |
56 | 58 |
|
@@ -420,14 +422,105 @@ public boolean destroyVolume(long volumeId) |
420 | 422 | @Override |
421 | 423 | public AsyncCallFuture<VolumeApiResult> createVolumeFromSnapshot( |
422 | 424 | 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); |
424 | 427 | return null; |
425 | 428 | } |
| 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 | + |
426 | 442 |
|
| 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 | + } |
427 | 461 | @Override |
428 | 462 | public AsyncCallFuture<VolumeApiResult> copyVolume(VolumeInfo srcVolume, |
429 | 463 | 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 | + |
431 | 524 | return null; |
432 | 525 | } |
433 | 526 |
|
|
0 commit comments