@Test public void attachRootVolumePositive() throws NoSuchFieldException, IllegalAccessException { thrown.expect(InvalidParameterValueException.class); _svc.attachVolumeToVM(2L, 6L, 0L); }
public Volume attachVolumeToVM(final Long vmId, final Long volumeId, final Long deviceId) { final Account caller = CallContext.current().getCallingAccount(); final VolumeInfo volumeToAttach = this.volFactory.getVolume(volumeId); if (volumeToAttach == null || !(volumeToAttach.getVolumeType() == VolumeType.DATADISK || volumeToAttach.getVolumeType() == VolumeType.ROOT)) { throw new InvalidParameterValueException("Please specify a volume with the valid type: " + VolumeType.ROOT.toString() + " or " + VolumeType.DATADISK.toString()); } if (volumeToAttach.getInstanceId() != null) { throw new InvalidParameterValueException("Please specify a volume that is not attached to any VM."); } if (volumeToAttach.getState() == Volume.State.Destroy) { throw new InvalidParameterValueException("Please specify a volume that is not destroyed."); } final UserVmVO vm = this._userVmDao.findById(vmId); if (vm == null || vm.getType() != VirtualMachineType.User) { throw new InvalidParameterValueException("Please specify a valid User VM."); } if (vm.getState() != State.Running && vm.getState() != State.Stopped) { throw new InvalidParameterValueException("Please specify a VM that is either running or stopped."); } if (vm.getDataCenterId() != volumeToAttach.getDataCenterId()) { throw new InvalidParameterValueException("Please specify a VM that is in the same zone as the volume."); } if (deviceId != null) { if (deviceId.longValue() == 0) { validateRootVolumeDetachAttach(this._volsDao.findById(volumeToAttach.getId()), vm); if (!this._volsDao.findByInstanceAndDeviceId(vm.getId(), 0).isEmpty()) { throw new InvalidParameterValueException("Vm already has root volume attached to it"); } if (volumeToAttach.getState() == Volume.State.Uploaded) { throw new InvalidParameterValueException("No support for Root volume attach in state " + Volume.State.Uploaded); } } } if (deviceId == null || deviceId.longValue() != 0) { final List<VolumeVO> existingDataVolumes = this._volsDao.findByInstanceAndType(vmId, VolumeType.DATADISK); final int maxDataVolumesSupported = getMaxDataVolumesSupported(vm); if (existingDataVolumes.size() >= maxDataVolumesSupported) { throw new InvalidParameterValueException("The specified VM already has the maximum number of data disks (" + maxDataVolumesSupported + "). Please specify another" + " VM."); } } final List<VMSnapshotVO> vmSnapshots = this._vmSnapshotDao.findByVm(vmId); if (vmSnapshots.size() > 0) { throw new InvalidParameterValueException("Unable to attach volume, please specify a VM that does not have VM snapshots"); } this._accountMgr.checkAccess(caller, null, true, volumeToAttach, vm); if (!(Volume.State.Allocated.equals(volumeToAttach.getState()) || Volume.State.Ready.equals(volumeToAttach.getState()) || Volume.State.Uploaded.equals(volumeToAttach .getState()))) { throw new InvalidParameterValueException("Volume state must be in Allocated, Ready or in Uploaded state"); } final Account owner = this._accountDao.findById(volumeToAttach.getAccountId()); if (!(volumeToAttach.getState() == Volume.State.Allocated || volumeToAttach.getState() == Volume.State.Ready)) { try { this._resourceLimitMgr.checkResourceLimit(owner, ResourceType.primary_storage, volumeToAttach.getSize()); } catch (final ResourceAllocationException e) { s_logger.error("primary storage resource limit check failed", e); throw new InvalidParameterValueException(e.getMessage()); } } final HypervisorType rootDiskHyperType = vm.getHypervisorType(); final HypervisorType volumeToAttachHyperType = this._volsDao.getHypervisorType(volumeToAttach.getId()); final StoragePoolVO volumeToAttachStoragePool = this._storagePoolDao.findById(volumeToAttach.getPoolId()); if (volumeToAttachStoragePool != null && !volumeToAttachStoragePool.isManaged()) { if (volumeToAttachHyperType != HypervisorType.None && rootDiskHyperType != volumeToAttachHyperType) { throw new InvalidParameterValueException("Can't attach a volume created by: " + volumeToAttachHyperType + " to a " + rootDiskHyperType + " vm"); } } final AsyncJobExecutionContext asyncExecutionContext = AsyncJobExecutionContext.getCurrentExecutionContext(); if (asyncExecutionContext != null) { final AsyncJob job = asyncExecutionContext.getJob(); if (s_logger.isInfoEnabled()) { s_logger.info("Trying to attaching volume " + volumeId + " to vm instance:" + vm.getId() + ", update async job-" + job.getId() + " progress status"); } this._jobMgr.updateAsyncJobAttachment(job.getId(), "Volume", volumeId); } final AsyncJobExecutionContext jobContext = AsyncJobExecutionContext.getCurrentExecutionContext(); if (jobContext.isJobDispatchedBy(VmWorkConstants.VM_WORK_JOB_DISPATCHER)) { final VmWorkJobVO placeHolder; placeHolder = createPlaceHolderWork(vmId); try { return orchestrateAttachVolumeToVM(vmId, volumeId, deviceId, volumeToAttach.getDiskController()); } finally { this._workJobDao.expunge(placeHolder.getId()); } } else { final Outcome<Volume> outcome = attachVolumeToVmThroughJobQueue(vmId, volumeId, deviceId, volumeToAttach.getDiskController()); Volume vol = null; try { outcome.get(); } catch (final InterruptedException e) { throw new RuntimeException("Operation is interrupted", e); } catch (final java.util.concurrent.ExecutionException e) { throw new RuntimeException("Execution excetion", e); } final Object jobResult = this._jobMgr.unmarshallResultObject(outcome.getJob()); if (jobResult != null) { if (jobResult instanceof ConcurrentOperationException) { throw (ConcurrentOperationException) jobResult; } else if (jobResult instanceof InvalidParameterValueException) { throw (InvalidParameterValueException) jobResult; } else if (jobResult instanceof RuntimeException) { throw (RuntimeException) jobResult; } else if (jobResult instanceof Throwable) { throw new RuntimeException("Unexpected exception", (Throwable) jobResult); } else if (jobResult instanceof Long) { vol = this._volsDao.findById((Long) jobResult); } } return vol; } }
VolumeApiServiceImpl extends ManagerBase implements VolumeApiService, VmWorkJobHandler { public Volume attachVolumeToVM(final Long vmId, final Long volumeId, final Long deviceId) { final Account caller = CallContext.current().getCallingAccount(); final VolumeInfo volumeToAttach = this.volFactory.getVolume(volumeId); if (volumeToAttach == null || !(volumeToAttach.getVolumeType() == VolumeType.DATADISK || volumeToAttach.getVolumeType() == VolumeType.ROOT)) { throw new InvalidParameterValueException("Please specify a volume with the valid type: " + VolumeType.ROOT.toString() + " or " + VolumeType.DATADISK.toString()); } if (volumeToAttach.getInstanceId() != null) { throw new InvalidParameterValueException("Please specify a volume that is not attached to any VM."); } if (volumeToAttach.getState() == Volume.State.Destroy) { throw new InvalidParameterValueException("Please specify a volume that is not destroyed."); } final UserVmVO vm = this._userVmDao.findById(vmId); if (vm == null || vm.getType() != VirtualMachineType.User) { throw new InvalidParameterValueException("Please specify a valid User VM."); } if (vm.getState() != State.Running && vm.getState() != State.Stopped) { throw new InvalidParameterValueException("Please specify a VM that is either running or stopped."); } if (vm.getDataCenterId() != volumeToAttach.getDataCenterId()) { throw new InvalidParameterValueException("Please specify a VM that is in the same zone as the volume."); } if (deviceId != null) { if (deviceId.longValue() == 0) { validateRootVolumeDetachAttach(this._volsDao.findById(volumeToAttach.getId()), vm); if (!this._volsDao.findByInstanceAndDeviceId(vm.getId(), 0).isEmpty()) { throw new InvalidParameterValueException("Vm already has root volume attached to it"); } if (volumeToAttach.getState() == Volume.State.Uploaded) { throw new InvalidParameterValueException("No support for Root volume attach in state " + Volume.State.Uploaded); } } } if (deviceId == null || deviceId.longValue() != 0) { final List<VolumeVO> existingDataVolumes = this._volsDao.findByInstanceAndType(vmId, VolumeType.DATADISK); final int maxDataVolumesSupported = getMaxDataVolumesSupported(vm); if (existingDataVolumes.size() >= maxDataVolumesSupported) { throw new InvalidParameterValueException("The specified VM already has the maximum number of data disks (" + maxDataVolumesSupported + "). Please specify another" + " VM."); } } final List<VMSnapshotVO> vmSnapshots = this._vmSnapshotDao.findByVm(vmId); if (vmSnapshots.size() > 0) { throw new InvalidParameterValueException("Unable to attach volume, please specify a VM that does not have VM snapshots"); } this._accountMgr.checkAccess(caller, null, true, volumeToAttach, vm); if (!(Volume.State.Allocated.equals(volumeToAttach.getState()) || Volume.State.Ready.equals(volumeToAttach.getState()) || Volume.State.Uploaded.equals(volumeToAttach .getState()))) { throw new InvalidParameterValueException("Volume state must be in Allocated, Ready or in Uploaded state"); } final Account owner = this._accountDao.findById(volumeToAttach.getAccountId()); if (!(volumeToAttach.getState() == Volume.State.Allocated || volumeToAttach.getState() == Volume.State.Ready)) { try { this._resourceLimitMgr.checkResourceLimit(owner, ResourceType.primary_storage, volumeToAttach.getSize()); } catch (final ResourceAllocationException e) { s_logger.error("primary storage resource limit check failed", e); throw new InvalidParameterValueException(e.getMessage()); } } final HypervisorType rootDiskHyperType = vm.getHypervisorType(); final HypervisorType volumeToAttachHyperType = this._volsDao.getHypervisorType(volumeToAttach.getId()); final StoragePoolVO volumeToAttachStoragePool = this._storagePoolDao.findById(volumeToAttach.getPoolId()); if (volumeToAttachStoragePool != null && !volumeToAttachStoragePool.isManaged()) { if (volumeToAttachHyperType != HypervisorType.None && rootDiskHyperType != volumeToAttachHyperType) { throw new InvalidParameterValueException("Can't attach a volume created by: " + volumeToAttachHyperType + " to a " + rootDiskHyperType + " vm"); } } final AsyncJobExecutionContext asyncExecutionContext = AsyncJobExecutionContext.getCurrentExecutionContext(); if (asyncExecutionContext != null) { final AsyncJob job = asyncExecutionContext.getJob(); if (s_logger.isInfoEnabled()) { s_logger.info("Trying to attaching volume " + volumeId + " to vm instance:" + vm.getId() + ", update async job-" + job.getId() + " progress status"); } this._jobMgr.updateAsyncJobAttachment(job.getId(), "Volume", volumeId); } final AsyncJobExecutionContext jobContext = AsyncJobExecutionContext.getCurrentExecutionContext(); if (jobContext.isJobDispatchedBy(VmWorkConstants.VM_WORK_JOB_DISPATCHER)) { final VmWorkJobVO placeHolder; placeHolder = createPlaceHolderWork(vmId); try { return orchestrateAttachVolumeToVM(vmId, volumeId, deviceId, volumeToAttach.getDiskController()); } finally { this._workJobDao.expunge(placeHolder.getId()); } } else { final Outcome<Volume> outcome = attachVolumeToVmThroughJobQueue(vmId, volumeId, deviceId, volumeToAttach.getDiskController()); Volume vol = null; try { outcome.get(); } catch (final InterruptedException e) { throw new RuntimeException("Operation is interrupted", e); } catch (final java.util.concurrent.ExecutionException e) { throw new RuntimeException("Execution excetion", e); } final Object jobResult = this._jobMgr.unmarshallResultObject(outcome.getJob()); if (jobResult != null) { if (jobResult instanceof ConcurrentOperationException) { throw (ConcurrentOperationException) jobResult; } else if (jobResult instanceof InvalidParameterValueException) { throw (InvalidParameterValueException) jobResult; } else if (jobResult instanceof RuntimeException) { throw (RuntimeException) jobResult; } else if (jobResult instanceof Throwable) { throw new RuntimeException("Unexpected exception", (Throwable) jobResult); } else if (jobResult instanceof Long) { vol = this._volsDao.findById((Long) jobResult); } } return vol; } } }
VolumeApiServiceImpl extends ManagerBase implements VolumeApiService, VmWorkJobHandler { public Volume attachVolumeToVM(final Long vmId, final Long volumeId, final Long deviceId) { final Account caller = CallContext.current().getCallingAccount(); final VolumeInfo volumeToAttach = this.volFactory.getVolume(volumeId); if (volumeToAttach == null || !(volumeToAttach.getVolumeType() == VolumeType.DATADISK || volumeToAttach.getVolumeType() == VolumeType.ROOT)) { throw new InvalidParameterValueException("Please specify a volume with the valid type: " + VolumeType.ROOT.toString() + " or " + VolumeType.DATADISK.toString()); } if (volumeToAttach.getInstanceId() != null) { throw new InvalidParameterValueException("Please specify a volume that is not attached to any VM."); } if (volumeToAttach.getState() == Volume.State.Destroy) { throw new InvalidParameterValueException("Please specify a volume that is not destroyed."); } final UserVmVO vm = this._userVmDao.findById(vmId); if (vm == null || vm.getType() != VirtualMachineType.User) { throw new InvalidParameterValueException("Please specify a valid User VM."); } if (vm.getState() != State.Running && vm.getState() != State.Stopped) { throw new InvalidParameterValueException("Please specify a VM that is either running or stopped."); } if (vm.getDataCenterId() != volumeToAttach.getDataCenterId()) { throw new InvalidParameterValueException("Please specify a VM that is in the same zone as the volume."); } if (deviceId != null) { if (deviceId.longValue() == 0) { validateRootVolumeDetachAttach(this._volsDao.findById(volumeToAttach.getId()), vm); if (!this._volsDao.findByInstanceAndDeviceId(vm.getId(), 0).isEmpty()) { throw new InvalidParameterValueException("Vm already has root volume attached to it"); } if (volumeToAttach.getState() == Volume.State.Uploaded) { throw new InvalidParameterValueException("No support for Root volume attach in state " + Volume.State.Uploaded); } } } if (deviceId == null || deviceId.longValue() != 0) { final List<VolumeVO> existingDataVolumes = this._volsDao.findByInstanceAndType(vmId, VolumeType.DATADISK); final int maxDataVolumesSupported = getMaxDataVolumesSupported(vm); if (existingDataVolumes.size() >= maxDataVolumesSupported) { throw new InvalidParameterValueException("The specified VM already has the maximum number of data disks (" + maxDataVolumesSupported + "). Please specify another" + " VM."); } } final List<VMSnapshotVO> vmSnapshots = this._vmSnapshotDao.findByVm(vmId); if (vmSnapshots.size() > 0) { throw new InvalidParameterValueException("Unable to attach volume, please specify a VM that does not have VM snapshots"); } this._accountMgr.checkAccess(caller, null, true, volumeToAttach, vm); if (!(Volume.State.Allocated.equals(volumeToAttach.getState()) || Volume.State.Ready.equals(volumeToAttach.getState()) || Volume.State.Uploaded.equals(volumeToAttach .getState()))) { throw new InvalidParameterValueException("Volume state must be in Allocated, Ready or in Uploaded state"); } final Account owner = this._accountDao.findById(volumeToAttach.getAccountId()); if (!(volumeToAttach.getState() == Volume.State.Allocated || volumeToAttach.getState() == Volume.State.Ready)) { try { this._resourceLimitMgr.checkResourceLimit(owner, ResourceType.primary_storage, volumeToAttach.getSize()); } catch (final ResourceAllocationException e) { s_logger.error("primary storage resource limit check failed", e); throw new InvalidParameterValueException(e.getMessage()); } } final HypervisorType rootDiskHyperType = vm.getHypervisorType(); final HypervisorType volumeToAttachHyperType = this._volsDao.getHypervisorType(volumeToAttach.getId()); final StoragePoolVO volumeToAttachStoragePool = this._storagePoolDao.findById(volumeToAttach.getPoolId()); if (volumeToAttachStoragePool != null && !volumeToAttachStoragePool.isManaged()) { if (volumeToAttachHyperType != HypervisorType.None && rootDiskHyperType != volumeToAttachHyperType) { throw new InvalidParameterValueException("Can't attach a volume created by: " + volumeToAttachHyperType + " to a " + rootDiskHyperType + " vm"); } } final AsyncJobExecutionContext asyncExecutionContext = AsyncJobExecutionContext.getCurrentExecutionContext(); if (asyncExecutionContext != null) { final AsyncJob job = asyncExecutionContext.getJob(); if (s_logger.isInfoEnabled()) { s_logger.info("Trying to attaching volume " + volumeId + " to vm instance:" + vm.getId() + ", update async job-" + job.getId() + " progress status"); } this._jobMgr.updateAsyncJobAttachment(job.getId(), "Volume", volumeId); } final AsyncJobExecutionContext jobContext = AsyncJobExecutionContext.getCurrentExecutionContext(); if (jobContext.isJobDispatchedBy(VmWorkConstants.VM_WORK_JOB_DISPATCHER)) { final VmWorkJobVO placeHolder; placeHolder = createPlaceHolderWork(vmId); try { return orchestrateAttachVolumeToVM(vmId, volumeId, deviceId, volumeToAttach.getDiskController()); } finally { this._workJobDao.expunge(placeHolder.getId()); } } else { final Outcome<Volume> outcome = attachVolumeToVmThroughJobQueue(vmId, volumeId, deviceId, volumeToAttach.getDiskController()); Volume vol = null; try { outcome.get(); } catch (final InterruptedException e) { throw new RuntimeException("Operation is interrupted", e); } catch (final java.util.concurrent.ExecutionException e) { throw new RuntimeException("Execution excetion", e); } final Object jobResult = this._jobMgr.unmarshallResultObject(outcome.getJob()); if (jobResult != null) { if (jobResult instanceof ConcurrentOperationException) { throw (ConcurrentOperationException) jobResult; } else if (jobResult instanceof InvalidParameterValueException) { throw (InvalidParameterValueException) jobResult; } else if (jobResult instanceof RuntimeException) { throw (RuntimeException) jobResult; } else if (jobResult instanceof Throwable) { throw new RuntimeException("Unexpected exception", (Throwable) jobResult); } else if (jobResult instanceof Long) { vol = this._volsDao.findById((Long) jobResult); } } return vol; } } protected  VolumeApiServiceImpl(); }
VolumeApiServiceImpl extends ManagerBase implements VolumeApiService, VmWorkJobHandler { public Volume attachVolumeToVM(final Long vmId, final Long volumeId, final Long deviceId) { final Account caller = CallContext.current().getCallingAccount(); final VolumeInfo volumeToAttach = this.volFactory.getVolume(volumeId); if (volumeToAttach == null || !(volumeToAttach.getVolumeType() == VolumeType.DATADISK || volumeToAttach.getVolumeType() == VolumeType.ROOT)) { throw new InvalidParameterValueException("Please specify a volume with the valid type: " + VolumeType.ROOT.toString() + " or " + VolumeType.DATADISK.toString()); } if (volumeToAttach.getInstanceId() != null) { throw new InvalidParameterValueException("Please specify a volume that is not attached to any VM."); } if (volumeToAttach.getState() == Volume.State.Destroy) { throw new InvalidParameterValueException("Please specify a volume that is not destroyed."); } final UserVmVO vm = this._userVmDao.findById(vmId); if (vm == null || vm.getType() != VirtualMachineType.User) { throw new InvalidParameterValueException("Please specify a valid User VM."); } if (vm.getState() != State.Running && vm.getState() != State.Stopped) { throw new InvalidParameterValueException("Please specify a VM that is either running or stopped."); } if (vm.getDataCenterId() != volumeToAttach.getDataCenterId()) { throw new InvalidParameterValueException("Please specify a VM that is in the same zone as the volume."); } if (deviceId != null) { if (deviceId.longValue() == 0) { validateRootVolumeDetachAttach(this._volsDao.findById(volumeToAttach.getId()), vm); if (!this._volsDao.findByInstanceAndDeviceId(vm.getId(), 0).isEmpty()) { throw new InvalidParameterValueException("Vm already has root volume attached to it"); } if (volumeToAttach.getState() == Volume.State.Uploaded) { throw new InvalidParameterValueException("No support for Root volume attach in state " + Volume.State.Uploaded); } } } if (deviceId == null || deviceId.longValue() != 0) { final List<VolumeVO> existingDataVolumes = this._volsDao.findByInstanceAndType(vmId, VolumeType.DATADISK); final int maxDataVolumesSupported = getMaxDataVolumesSupported(vm); if (existingDataVolumes.size() >= maxDataVolumesSupported) { throw new InvalidParameterValueException("The specified VM already has the maximum number of data disks (" + maxDataVolumesSupported + "). Please specify another" + " VM."); } } final List<VMSnapshotVO> vmSnapshots = this._vmSnapshotDao.findByVm(vmId); if (vmSnapshots.size() > 0) { throw new InvalidParameterValueException("Unable to attach volume, please specify a VM that does not have VM snapshots"); } this._accountMgr.checkAccess(caller, null, true, volumeToAttach, vm); if (!(Volume.State.Allocated.equals(volumeToAttach.getState()) || Volume.State.Ready.equals(volumeToAttach.getState()) || Volume.State.Uploaded.equals(volumeToAttach .getState()))) { throw new InvalidParameterValueException("Volume state must be in Allocated, Ready or in Uploaded state"); } final Account owner = this._accountDao.findById(volumeToAttach.getAccountId()); if (!(volumeToAttach.getState() == Volume.State.Allocated || volumeToAttach.getState() == Volume.State.Ready)) { try { this._resourceLimitMgr.checkResourceLimit(owner, ResourceType.primary_storage, volumeToAttach.getSize()); } catch (final ResourceAllocationException e) { s_logger.error("primary storage resource limit check failed", e); throw new InvalidParameterValueException(e.getMessage()); } } final HypervisorType rootDiskHyperType = vm.getHypervisorType(); final HypervisorType volumeToAttachHyperType = this._volsDao.getHypervisorType(volumeToAttach.getId()); final StoragePoolVO volumeToAttachStoragePool = this._storagePoolDao.findById(volumeToAttach.getPoolId()); if (volumeToAttachStoragePool != null && !volumeToAttachStoragePool.isManaged()) { if (volumeToAttachHyperType != HypervisorType.None && rootDiskHyperType != volumeToAttachHyperType) { throw new InvalidParameterValueException("Can't attach a volume created by: " + volumeToAttachHyperType + " to a " + rootDiskHyperType + " vm"); } } final AsyncJobExecutionContext asyncExecutionContext = AsyncJobExecutionContext.getCurrentExecutionContext(); if (asyncExecutionContext != null) { final AsyncJob job = asyncExecutionContext.getJob(); if (s_logger.isInfoEnabled()) { s_logger.info("Trying to attaching volume " + volumeId + " to vm instance:" + vm.getId() + ", update async job-" + job.getId() + " progress status"); } this._jobMgr.updateAsyncJobAttachment(job.getId(), "Volume", volumeId); } final AsyncJobExecutionContext jobContext = AsyncJobExecutionContext.getCurrentExecutionContext(); if (jobContext.isJobDispatchedBy(VmWorkConstants.VM_WORK_JOB_DISPATCHER)) { final VmWorkJobVO placeHolder; placeHolder = createPlaceHolderWork(vmId); try { return orchestrateAttachVolumeToVM(vmId, volumeId, deviceId, volumeToAttach.getDiskController()); } finally { this._workJobDao.expunge(placeHolder.getId()); } } else { final Outcome<Volume> outcome = attachVolumeToVmThroughJobQueue(vmId, volumeId, deviceId, volumeToAttach.getDiskController()); Volume vol = null; try { outcome.get(); } catch (final InterruptedException e) { throw new RuntimeException("Operation is interrupted", e); } catch (final java.util.concurrent.ExecutionException e) { throw new RuntimeException("Execution excetion", e); } final Object jobResult = this._jobMgr.unmarshallResultObject(outcome.getJob()); if (jobResult != null) { if (jobResult instanceof ConcurrentOperationException) { throw (ConcurrentOperationException) jobResult; } else if (jobResult instanceof InvalidParameterValueException) { throw (InvalidParameterValueException) jobResult; } else if (jobResult instanceof RuntimeException) { throw (RuntimeException) jobResult; } else if (jobResult instanceof Throwable) { throw new RuntimeException("Unexpected exception", (Throwable) jobResult); } else if (jobResult instanceof Long) { vol = this._volsDao.findById((Long) jobResult); } } return vol; } } protected  VolumeApiServiceImpl(); @Override @DB @ActionEvent(eventType = EventTypes.EVENT_VOLUME_CREATE, eventDescription = "creating volume", create = true) VolumeVO allocVolume(final CreateVolumeCmd cmd); boolean validateVolumeSizeRange(final long size); String getVolumeNameFromCommand(final CreateVolumeCmd cmd); String getRandomVolumeName(); @Override @DB @ActionEvent(eventType = EventTypes.EVENT_VOLUME_CREATE, eventDescription = "creating volume", async = true) VolumeVO createVolume(final CreateVolumeCmd cmd); Volume attachVolumeToVM(final Long vmId, final Long volumeId, final Long deviceId); Outcome<Volume> attachVolumeToVmThroughJobQueue(final Long vmId, final Long volumeId, final Long deviceId, final DiskControllerType diskController); @Override @DB @ActionEvent(eventType = EventTypes.EVENT_VOLUME_RESIZE, eventDescription = "resizing volume", async = true) VolumeVO resizeVolume(final ResizeVolumeCmd cmd); Outcome<Volume> resizeVolumeThroughJobQueue(final Long vmId, final long volumeId,
                                                       final long currentSize, final long newSize, final Long newMinIops, final Long newMaxIops, final Long newServiceOfferingId,
                                                       final boolean shrinkOk); @DB @Override @ActionEvent(eventType = EventTypes.EVENT_VOLUME_MIGRATE, eventDescription = "migrating volume", async = true) Volume migrateVolume(final MigrateVolumeCmd cmd); @Override @DB @ActionEvent(eventType = EventTypes.EVENT_VOLUME_UPLOAD, eventDescription = "uploading volume", async = true) VolumeVO uploadVolume(final UploadVolumeCmd cmd); @Override @ActionEvent(eventType = EventTypes.EVENT_VOLUME_UPLOAD, eventDescription = "uploading volume for post upload", async = true) GetUploadParamsResponse uploadVolume(final GetUploadParamsForVolumeCmd cmd); @Override @DB @ActionEvent(eventType = EventTypes.EVENT_VOLUME_DELETE, eventDescription = "deleting volume") boolean deleteVolume(final long volumeId, final Account caller); @Override @ActionEvent(eventType = EventTypes.EVENT_VOLUME_ATTACH, eventDescription = "attaching volume", async = true) Volume attachVolumeToVM(final AttachVolumeCmd command); @Override @ActionEvent(eventType = EventTypes.EVENT_VOLUME_DETACH, eventDescription = "detaching volume", async = true) Volume detachVolumeFromVM(final DetachVolumeCmd cmmd); Outcome<Volume> detachVolumeFromVmThroughJobQueue(final Long vmId, final Long volumeId); @Override @ActionEvent(eventType = EventTypes.EVENT_SNAPSHOT_CREATE, eventDescription = "taking snapshot", async = true) Snapshot takeSnapshot(final Long volumeId, final Long policyId, final Long snapshotId, final Account account, final boolean quiescevm); Outcome<Snapshot> takeVolumeSnapshotThroughJobQueue(final Long vmId, final Long volumeId,
                                                               final Long policyId, final Long snapshotId, final Long accountId, final boolean quiesceVm); @Override @ActionEvent(eventType = EventTypes.EVENT_SNAPSHOT_CREATE, eventDescription = "allocating snapshot", create = true) Snapshot allocSnapshot(final Long volumeId, final Long policyId, final String snapshotName); @Override Snapshot allocSnapshotForVm(final Long vmId, final Long volumeId, final String snapshotName); @Override @ActionEvent(eventType = EventTypes.EVENT_VOLUME_UPDATE, eventDescription = "updating volume", async = true) Volume updateVolume(final long volumeId, final String name, final String path, final String state, final Long storageId, final Boolean displayVolume, final String customId, final long
            entityOwnerId, final String chainInfo, final DiskControllerType diskControllerType); @Override @ActionEvent(eventType = EventTypes.EVENT_VOLUME_EXTRACT, eventDescription = "extracting volume", async = true) String extractVolume(final ExtractVolumeCmd cmd); Outcome<String> extractVolumeThroughJobQueue(final Long vmId, final long volumeId,
                                                        final long zoneId); @Override boolean isDisplayResourceEnabled(final Long id); @Override void updateDisplay(final Volume volume, final Boolean displayVolume); Outcome<Volume> migrateVolumeThroughJobQueue(final Long vmId, final long volumeId,
                                                        final long destPoolId, final boolean liveMigrate); @Override boolean configure(final String name, final Map<String, Object> params); List<StoragePoolAllocator> getStoragePoolAllocators(); @Inject void setStoragePoolAllocators(final List<StoragePoolAllocator> storagePoolAllocators); @Override Pair<JobInfo.Status, String> handleVmWorkJob(final VmWork work); }
VolumeApiServiceImpl extends ManagerBase implements VolumeApiService, VmWorkJobHandler { public Volume attachVolumeToVM(final Long vmId, final Long volumeId, final Long deviceId) { final Account caller = CallContext.current().getCallingAccount(); final VolumeInfo volumeToAttach = this.volFactory.getVolume(volumeId); if (volumeToAttach == null || !(volumeToAttach.getVolumeType() == VolumeType.DATADISK || volumeToAttach.getVolumeType() == VolumeType.ROOT)) { throw new InvalidParameterValueException("Please specify a volume with the valid type: " + VolumeType.ROOT.toString() + " or " + VolumeType.DATADISK.toString()); } if (volumeToAttach.getInstanceId() != null) { throw new InvalidParameterValueException("Please specify a volume that is not attached to any VM."); } if (volumeToAttach.getState() == Volume.State.Destroy) { throw new InvalidParameterValueException("Please specify a volume that is not destroyed."); } final UserVmVO vm = this._userVmDao.findById(vmId); if (vm == null || vm.getType() != VirtualMachineType.User) { throw new InvalidParameterValueException("Please specify a valid User VM."); } if (vm.getState() != State.Running && vm.getState() != State.Stopped) { throw new InvalidParameterValueException("Please specify a VM that is either running or stopped."); } if (vm.getDataCenterId() != volumeToAttach.getDataCenterId()) { throw new InvalidParameterValueException("Please specify a VM that is in the same zone as the volume."); } if (deviceId != null) { if (deviceId.longValue() == 0) { validateRootVolumeDetachAttach(this._volsDao.findById(volumeToAttach.getId()), vm); if (!this._volsDao.findByInstanceAndDeviceId(vm.getId(), 0).isEmpty()) { throw new InvalidParameterValueException("Vm already has root volume attached to it"); } if (volumeToAttach.getState() == Volume.State.Uploaded) { throw new InvalidParameterValueException("No support for Root volume attach in state " + Volume.State.Uploaded); } } } if (deviceId == null || deviceId.longValue() != 0) { final List<VolumeVO> existingDataVolumes = this._volsDao.findByInstanceAndType(vmId, VolumeType.DATADISK); final int maxDataVolumesSupported = getMaxDataVolumesSupported(vm); if (existingDataVolumes.size() >= maxDataVolumesSupported) { throw new InvalidParameterValueException("The specified VM already has the maximum number of data disks (" + maxDataVolumesSupported + "). Please specify another" + " VM."); } } final List<VMSnapshotVO> vmSnapshots = this._vmSnapshotDao.findByVm(vmId); if (vmSnapshots.size() > 0) { throw new InvalidParameterValueException("Unable to attach volume, please specify a VM that does not have VM snapshots"); } this._accountMgr.checkAccess(caller, null, true, volumeToAttach, vm); if (!(Volume.State.Allocated.equals(volumeToAttach.getState()) || Volume.State.Ready.equals(volumeToAttach.getState()) || Volume.State.Uploaded.equals(volumeToAttach .getState()))) { throw new InvalidParameterValueException("Volume state must be in Allocated, Ready or in Uploaded state"); } final Account owner = this._accountDao.findById(volumeToAttach.getAccountId()); if (!(volumeToAttach.getState() == Volume.State.Allocated || volumeToAttach.getState() == Volume.State.Ready)) { try { this._resourceLimitMgr.checkResourceLimit(owner, ResourceType.primary_storage, volumeToAttach.getSize()); } catch (final ResourceAllocationException e) { s_logger.error("primary storage resource limit check failed", e); throw new InvalidParameterValueException(e.getMessage()); } } final HypervisorType rootDiskHyperType = vm.getHypervisorType(); final HypervisorType volumeToAttachHyperType = this._volsDao.getHypervisorType(volumeToAttach.getId()); final StoragePoolVO volumeToAttachStoragePool = this._storagePoolDao.findById(volumeToAttach.getPoolId()); if (volumeToAttachStoragePool != null && !volumeToAttachStoragePool.isManaged()) { if (volumeToAttachHyperType != HypervisorType.None && rootDiskHyperType != volumeToAttachHyperType) { throw new InvalidParameterValueException("Can't attach a volume created by: " + volumeToAttachHyperType + " to a " + rootDiskHyperType + " vm"); } } final AsyncJobExecutionContext asyncExecutionContext = AsyncJobExecutionContext.getCurrentExecutionContext(); if (asyncExecutionContext != null) { final AsyncJob job = asyncExecutionContext.getJob(); if (s_logger.isInfoEnabled()) { s_logger.info("Trying to attaching volume " + volumeId + " to vm instance:" + vm.getId() + ", update async job-" + job.getId() + " progress status"); } this._jobMgr.updateAsyncJobAttachment(job.getId(), "Volume", volumeId); } final AsyncJobExecutionContext jobContext = AsyncJobExecutionContext.getCurrentExecutionContext(); if (jobContext.isJobDispatchedBy(VmWorkConstants.VM_WORK_JOB_DISPATCHER)) { final VmWorkJobVO placeHolder; placeHolder = createPlaceHolderWork(vmId); try { return orchestrateAttachVolumeToVM(vmId, volumeId, deviceId, volumeToAttach.getDiskController()); } finally { this._workJobDao.expunge(placeHolder.getId()); } } else { final Outcome<Volume> outcome = attachVolumeToVmThroughJobQueue(vmId, volumeId, deviceId, volumeToAttach.getDiskController()); Volume vol = null; try { outcome.get(); } catch (final InterruptedException e) { throw new RuntimeException("Operation is interrupted", e); } catch (final java.util.concurrent.ExecutionException e) { throw new RuntimeException("Execution excetion", e); } final Object jobResult = this._jobMgr.unmarshallResultObject(outcome.getJob()); if (jobResult != null) { if (jobResult instanceof ConcurrentOperationException) { throw (ConcurrentOperationException) jobResult; } else if (jobResult instanceof InvalidParameterValueException) { throw (InvalidParameterValueException) jobResult; } else if (jobResult instanceof RuntimeException) { throw (RuntimeException) jobResult; } else if (jobResult instanceof Throwable) { throw new RuntimeException("Unexpected exception", (Throwable) jobResult); } else if (jobResult instanceof Long) { vol = this._volsDao.findById((Long) jobResult); } } return vol; } } protected  VolumeApiServiceImpl(); @Override @DB @ActionEvent(eventType = EventTypes.EVENT_VOLUME_CREATE, eventDescription = "creating volume", create = true) VolumeVO allocVolume(final CreateVolumeCmd cmd); boolean validateVolumeSizeRange(final long size); String getVolumeNameFromCommand(final CreateVolumeCmd cmd); String getRandomVolumeName(); @Override @DB @ActionEvent(eventType = EventTypes.EVENT_VOLUME_CREATE, eventDescription = "creating volume", async = true) VolumeVO createVolume(final CreateVolumeCmd cmd); Volume attachVolumeToVM(final Long vmId, final Long volumeId, final Long deviceId); Outcome<Volume> attachVolumeToVmThroughJobQueue(final Long vmId, final Long volumeId, final Long deviceId, final DiskControllerType diskController); @Override @DB @ActionEvent(eventType = EventTypes.EVENT_VOLUME_RESIZE, eventDescription = "resizing volume", async = true) VolumeVO resizeVolume(final ResizeVolumeCmd cmd); Outcome<Volume> resizeVolumeThroughJobQueue(final Long vmId, final long volumeId,
                                                       final long currentSize, final long newSize, final Long newMinIops, final Long newMaxIops, final Long newServiceOfferingId,
                                                       final boolean shrinkOk); @DB @Override @ActionEvent(eventType = EventTypes.EVENT_VOLUME_MIGRATE, eventDescription = "migrating volume", async = true) Volume migrateVolume(final MigrateVolumeCmd cmd); @Override @DB @ActionEvent(eventType = EventTypes.EVENT_VOLUME_UPLOAD, eventDescription = "uploading volume", async = true) VolumeVO uploadVolume(final UploadVolumeCmd cmd); @Override @ActionEvent(eventType = EventTypes.EVENT_VOLUME_UPLOAD, eventDescription = "uploading volume for post upload", async = true) GetUploadParamsResponse uploadVolume(final GetUploadParamsForVolumeCmd cmd); @Override @DB @ActionEvent(eventType = EventTypes.EVENT_VOLUME_DELETE, eventDescription = "deleting volume") boolean deleteVolume(final long volumeId, final Account caller); @Override @ActionEvent(eventType = EventTypes.EVENT_VOLUME_ATTACH, eventDescription = "attaching volume", async = true) Volume attachVolumeToVM(final AttachVolumeCmd command); @Override @ActionEvent(eventType = EventTypes.EVENT_VOLUME_DETACH, eventDescription = "detaching volume", async = true) Volume detachVolumeFromVM(final DetachVolumeCmd cmmd); Outcome<Volume> detachVolumeFromVmThroughJobQueue(final Long vmId, final Long volumeId); @Override @ActionEvent(eventType = EventTypes.EVENT_SNAPSHOT_CREATE, eventDescription = "taking snapshot", async = true) Snapshot takeSnapshot(final Long volumeId, final Long policyId, final Long snapshotId, final Account account, final boolean quiescevm); Outcome<Snapshot> takeVolumeSnapshotThroughJobQueue(final Long vmId, final Long volumeId,
                                                               final Long policyId, final Long snapshotId, final Long accountId, final boolean quiesceVm); @Override @ActionEvent(eventType = EventTypes.EVENT_SNAPSHOT_CREATE, eventDescription = "allocating snapshot", create = true) Snapshot allocSnapshot(final Long volumeId, final Long policyId, final String snapshotName); @Override Snapshot allocSnapshotForVm(final Long vmId, final Long volumeId, final String snapshotName); @Override @ActionEvent(eventType = EventTypes.EVENT_VOLUME_UPDATE, eventDescription = "updating volume", async = true) Volume updateVolume(final long volumeId, final String name, final String path, final String state, final Long storageId, final Boolean displayVolume, final String customId, final long
            entityOwnerId, final String chainInfo, final DiskControllerType diskControllerType); @Override @ActionEvent(eventType = EventTypes.EVENT_VOLUME_EXTRACT, eventDescription = "extracting volume", async = true) String extractVolume(final ExtractVolumeCmd cmd); Outcome<String> extractVolumeThroughJobQueue(final Long vmId, final long volumeId,
                                                        final long zoneId); @Override boolean isDisplayResourceEnabled(final Long id); @Override void updateDisplay(final Volume volume, final Boolean displayVolume); Outcome<Volume> migrateVolumeThroughJobQueue(final Long vmId, final long volumeId,
                                                        final long destPoolId, final boolean liveMigrate); @Override boolean configure(final String name, final Map<String, Object> params); List<StoragePoolAllocator> getStoragePoolAllocators(); @Inject void setStoragePoolAllocators(final List<StoragePoolAllocator> storagePoolAllocators); @Override Pair<JobInfo.Status, String> handleVmWorkJob(final VmWork work); static final String VM_WORK_JOB_HANDLER; }