Search in sources :

Example 31 with AsyncJobExecutionContext

use of org.apache.cloudstack.framework.jobs.AsyncJobExecutionContext in project cloudstack by apache.

the class VolumeApiServiceImpl method resizeVolume.

@Override
@DB
@ActionEvent(eventType = EventTypes.EVENT_VOLUME_RESIZE, eventDescription = "resizing volume", async = true)
public VolumeVO resizeVolume(ResizeVolumeCmd cmd) throws ResourceAllocationException {
    Long newSize = cmd.getSize();
    Long newMinIops = cmd.getMinIops();
    Long newMaxIops = cmd.getMaxIops();
    Integer newHypervisorSnapshotReserve = null;
    boolean shrinkOk = cmd.isShrinkOk();
    VolumeVO volume = _volsDao.findById(cmd.getEntityId());
    if (volume == null) {
        throw new InvalidParameterValueException("No such volume");
    }
    // checking if there are any ongoing snapshots on the volume which is to be resized
    List<SnapshotVO> ongoingSnapshots = _snapshotDao.listByStatus(cmd.getId(), Snapshot.State.Creating, Snapshot.State.CreatedOnPrimary, Snapshot.State.BackingUp);
    if (ongoingSnapshots.size() > 0) {
        throw new CloudRuntimeException("There is/are unbacked up snapshot(s) on this volume, resize volume is not permitted, please try again later.");
    }
    /* Does the caller have authority to act on this volume? */
    _accountMgr.checkAccess(CallContext.current().getCallingAccount(), null, true, volume);
    DiskOfferingVO diskOffering = _diskOfferingDao.findById(volume.getDiskOfferingId());
    DiskOfferingVO newDiskOffering = null;
    if (cmd.getNewDiskOfferingId() != null) {
        newDiskOffering = _diskOfferingDao.findById(cmd.getNewDiskOfferingId());
    }
    /* Only works for KVM/XenServer/VMware (or "Any") for now, and volumes with 'None' since they're just allocated in DB */
    HypervisorType hypervisorType = _volsDao.getHypervisorType(volume.getId());
    if (!SupportedHypervisorsForVolResize.contains(hypervisorType)) {
        throw new InvalidParameterValueException("Hypervisor " + hypervisorType + " does not support volume resize");
    }
    if (volume.getState() != Volume.State.Ready && volume.getState() != Volume.State.Allocated) {
        throw new InvalidParameterValueException("Volume should be in ready or allocated state before attempting a resize. Volume " + volume.getUuid() + " is in state " + volume.getState() + ".");
    }
    // if we are to use the existing disk offering
    if (newDiskOffering == null) {
        newHypervisorSnapshotReserve = volume.getHypervisorSnapshotReserve();
        // if the caller is looking to change the size of the volume
        if (newSize != null) {
            if (diskOffering.getDiskSizeStrictness()) {
                throw new InvalidParameterValueException(String.format("Resize of volume %s is not allowed, since disk size is strictly fixed as per the disk offering", volume.getUuid()));
            }
            if (isNotPossibleToResize(volume, diskOffering)) {
                throw new InvalidParameterValueException("Failed to resize Root volume. The service offering of this Volume has been configured with a root disk size; " + "on such case a Root Volume can only be resized when changing to another Service Offering with a Root disk size. " + "For more details please check out the Official Resizing Volumes documentation.");
            }
            // convert from bytes to GiB
            newSize = newSize << 30;
        } else {
            // no parameter provided; just use the original size of the volume
            newSize = volume.getSize();
        }
        newMinIops = cmd.getMinIops();
        if (newMinIops != null) {
            if (!volume.getVolumeType().equals(Volume.Type.ROOT) && (diskOffering.isCustomizedIops() == null || !diskOffering.isCustomizedIops())) {
                throw new InvalidParameterValueException("The current disk offering does not support customization of the 'Min IOPS' parameter.");
            }
        } else {
            // no parameter provided; just use the original min IOPS of the volume
            newMinIops = volume.getMinIops();
        }
        newMaxIops = cmd.getMaxIops();
        if (newMaxIops != null) {
            if (!volume.getVolumeType().equals(Volume.Type.ROOT) && (diskOffering.isCustomizedIops() == null || !diskOffering.isCustomizedIops())) {
                throw new InvalidParameterValueException("The current disk offering does not support customization of the 'Max IOPS' parameter.");
            }
        } else {
            // no parameter provided; just use the original max IOPS of the volume
            newMaxIops = volume.getMaxIops();
        }
        validateIops(newMinIops, newMaxIops, volume.getPoolType());
    } else {
        if (newDiskOffering.getRemoved() != null) {
            throw new InvalidParameterValueException("Requested disk offering has been removed.");
        }
        if (diskOffering.getDiskSizeStrictness() != newDiskOffering.getDiskSizeStrictness()) {
            throw new InvalidParameterValueException("Disk offering size strictness does not match with new disk offering");
        }
        if (diskOffering.getDiskSizeStrictness() && (diskOffering.getDiskSize() != newDiskOffering.getDiskSize())) {
            throw new InvalidParameterValueException(String.format("Resize volume for %s is not allowed since disk offering's size is fixed", volume.getName()));
        }
        Long instanceId = volume.getInstanceId();
        VMInstanceVO vmInstanceVO = _vmInstanceDao.findById(instanceId);
        if (volume.getVolumeType().equals(Volume.Type.ROOT)) {
            ServiceOfferingVO serviceOffering = _serviceOfferingDao.findById(vmInstanceVO.getServiceOfferingId());
            if (serviceOffering != null && serviceOffering.getDiskOfferingStrictness()) {
                throw new InvalidParameterValueException(String.format("Cannot resize ROOT volume [%s] with new disk offering since existing disk offering is strictly assigned to the ROOT volume.", volume.getName()));
            }
        }
        if (diskOffering.getTags() != null) {
            if (!com.cloud.utils.StringUtils.areTagsEqual(diskOffering.getTags(), newDiskOffering.getTags())) {
                throw new InvalidParameterValueException("The tags on the new and old disk offerings must match.");
            }
        } else if (newDiskOffering.getTags() != null) {
            throw new InvalidParameterValueException("There are no tags on the current disk offering. The new disk offering needs to have no tags, as well.");
        }
        _configMgr.checkDiskOfferingAccess(_accountMgr.getActiveAccountById(volume.getAccountId()), newDiskOffering, _dcDao.findById(volume.getDataCenterId()));
        if (newDiskOffering.getDiskSize() > 0 && !newDiskOffering.isComputeOnly()) {
            newSize = newDiskOffering.getDiskSize();
        } else if (newDiskOffering.isCustomized()) {
            newSize = cmd.getSize();
            if (newSize == null) {
                throw new InvalidParameterValueException("The new disk offering requires that a size be specified.");
            }
            // convert from GiB to bytes
            newSize = newSize << 30;
        } else {
            if (cmd.getSize() != null) {
                throw new InvalidParameterValueException("You cannnot pass in a custom disk size to a non-custom disk offering.");
            }
            newSize = newDiskOffering.getDiskSize();
        }
        checkIfVolumeIsRootAndVmIsRunning(newSize, volume, vmInstanceVO);
        if (newDiskOffering.isCustomizedIops() != null && newDiskOffering.isCustomizedIops()) {
            newMinIops = cmd.getMinIops() != null ? cmd.getMinIops() : volume.getMinIops();
            newMaxIops = cmd.getMaxIops() != null ? cmd.getMaxIops() : volume.getMaxIops();
            validateIops(newMinIops, newMaxIops, volume.getPoolType());
        } else {
            newMinIops = newDiskOffering.getMinIops();
            newMaxIops = newDiskOffering.getMaxIops();
        }
        // if the hypervisor snapshot reserve value is null, it must remain null (currently only KVM uses null and null is all KVM uses for a value here)
        newHypervisorSnapshotReserve = volume.getHypervisorSnapshotReserve() != null ? newDiskOffering.getHypervisorSnapshotReserve() : null;
    }
    long currentSize = volume.getSize();
    // if the caller is looking to change the size of the volume
    if (currentSize != newSize) {
        if (volume.getInstanceId() != null) {
            // Check that VM to which this volume is attached does not have VM snapshots
            if (_vmSnapshotDao.findByVm(volume.getInstanceId()).size() > 0) {
                throw new InvalidParameterValueException("A volume that is attached to a VM with any VM snapshots cannot be resized.");
            }
        }
        if (!validateVolumeSizeInBytes(newSize)) {
            throw new InvalidParameterValueException("Requested size out of range");
        }
        Long storagePoolId = volume.getPoolId();
        if (storagePoolId != null) {
            StoragePoolVO storagePoolVO = _storagePoolDao.findById(storagePoolId);
            if (storagePoolVO.isManaged()) {
                Long instanceId = volume.getInstanceId();
                if (instanceId != null) {
                    VMInstanceVO vmInstanceVO = _vmInstanceDao.findById(instanceId);
                    if (vmInstanceVO.getHypervisorType() == HypervisorType.KVM && vmInstanceVO.getState() != State.Stopped) {
                        throw new CloudRuntimeException("This kind of KVM disk cannot be resized while it is connected to a VM that's not in the Stopped state.");
                    }
                }
            }
        }
        /*
             * Let's make certain they (think they) know what they're doing if they
             * want to shrink by forcing them to provide the shrinkok parameter.
             * This will be checked again at the hypervisor level where we can see
             * the actual disk size.
             */
        if (currentSize > newSize && !shrinkOk) {
            throw new InvalidParameterValueException("Going from existing size of " + currentSize + " to size of " + newSize + " would shrink the volume." + "Need to sign off by supplying the shrinkok parameter with value of true.");
        }
        if (newSize > currentSize) {
            /* Check resource limit for this account on primary storage resource */
            _resourceLimitMgr.checkResourceLimit(_accountMgr.getAccount(volume.getAccountId()), ResourceType.primary_storage, volume.isDisplayVolume(), new Long(newSize - currentSize).longValue());
        }
    }
    // We need to publish this event to usage_volume table
    if (volume.getState() == Volume.State.Allocated) {
        s_logger.debug("Volume is in the allocated state, but has never been created. Simply updating database with new size and IOPS.");
        volume.setSize(newSize);
        volume.setMinIops(newMinIops);
        volume.setMaxIops(newMaxIops);
        volume.setHypervisorSnapshotReserve(newHypervisorSnapshotReserve);
        if (newDiskOffering != null) {
            volume.setDiskOfferingId(cmd.getNewDiskOfferingId());
        }
        _volsDao.update(volume.getId(), volume);
        UsageEventUtils.publishUsageEvent(EventTypes.EVENT_VOLUME_RESIZE, volume.getAccountId(), volume.getDataCenterId(), volume.getId(), volume.getName(), volume.getDiskOfferingId(), volume.getTemplateId(), volume.getSize(), Volume.class.getName(), volume.getUuid());
        return volume;
    }
    UserVmVO userVm = _userVmDao.findById(volume.getInstanceId());
    if (userVm != null) {
        // serialize VM operation
        AsyncJobExecutionContext jobContext = AsyncJobExecutionContext.getCurrentExecutionContext();
        if (jobContext.isJobDispatchedBy(VmWorkConstants.VM_WORK_JOB_DISPATCHER)) {
            // avoid re-entrance
            VmWorkJobVO placeHolder = null;
            placeHolder = createPlaceHolderWork(userVm.getId());
            try {
                return orchestrateResizeVolume(volume.getId(), currentSize, newSize, newMinIops, newMaxIops, newHypervisorSnapshotReserve, newDiskOffering != null ? cmd.getNewDiskOfferingId() : null, shrinkOk);
            } finally {
                _workJobDao.expunge(placeHolder.getId());
            }
        } else {
            Outcome<Volume> outcome = resizeVolumeThroughJobQueue(userVm.getId(), volume.getId(), currentSize, newSize, newMinIops, newMaxIops, newHypervisorSnapshotReserve, newDiskOffering != null ? cmd.getNewDiskOfferingId() : null, shrinkOk);
            try {
                outcome.get();
            } catch (InterruptedException e) {
                throw new RuntimeException("Operation was interrupted", e);
            } catch (java.util.concurrent.ExecutionException e) {
                throw new RuntimeException("Execution exception", e);
            }
            Object jobResult = _jobMgr.unmarshallResultObject(outcome.getJob());
            if (jobResult != null) {
                if (jobResult instanceof ConcurrentOperationException) {
                    throw (ConcurrentOperationException) jobResult;
                } else if (jobResult instanceof ResourceAllocationException) {
                    throw (ResourceAllocationException) 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) {
                    return _volsDao.findById((Long) jobResult);
                }
            }
            return volume;
        }
    }
    return orchestrateResizeVolume(volume.getId(), currentSize, newSize, newMinIops, newMaxIops, newHypervisorSnapshotReserve, newDiskOffering != null ? cmd.getNewDiskOfferingId() : null, shrinkOk);
}
Also used : UserVmVO(com.cloud.vm.UserVmVO) AsyncJobExecutionContext(org.apache.cloudstack.framework.jobs.AsyncJobExecutionContext) ServiceOfferingVO(com.cloud.service.ServiceOfferingVO) CloudRuntimeException(com.cloud.utils.exception.CloudRuntimeException) InvalidParameterValueException(com.cloud.exception.InvalidParameterValueException) CloudRuntimeException(com.cloud.utils.exception.CloudRuntimeException) StoragePoolVO(org.apache.cloudstack.storage.datastore.db.StoragePoolVO) ResourceAllocationException(com.cloud.exception.ResourceAllocationException) VMInstanceVO(com.cloud.vm.VMInstanceVO) ConcurrentOperationException(com.cloud.exception.ConcurrentOperationException) VmWorkJobVO(org.apache.cloudstack.framework.jobs.impl.VmWorkJobVO) HypervisorType(com.cloud.hypervisor.Hypervisor.HypervisorType) ExecutionException(java.util.concurrent.ExecutionException) VMSnapshotVO(com.cloud.vm.snapshot.VMSnapshotVO) VmWorkDetachVolume(com.cloud.vm.VmWorkDetachVolume) VmWorkMigrateVolume(com.cloud.vm.VmWorkMigrateVolume) VmWorkResizeVolume(com.cloud.vm.VmWorkResizeVolume) VmWorkAttachVolume(com.cloud.vm.VmWorkAttachVolume) VmWorkExtractVolume(com.cloud.vm.VmWorkExtractVolume) DataObject(org.apache.cloudstack.engine.subsystem.api.storage.DataObject) ActionEvent(com.cloud.event.ActionEvent) DB(com.cloud.utils.db.DB)

Example 32 with AsyncJobExecutionContext

use of org.apache.cloudstack.framework.jobs.AsyncJobExecutionContext in project cloudstack by apache.

the class AsyncJobManagerImpl method releaseSyncSource.

@Override
public void releaseSyncSource() {
    AsyncJobExecutionContext executionContext = AsyncJobExecutionContext.getCurrentExecutionContext();
    assert (executionContext != null);
    if (executionContext.getSyncSource() != null) {
        if (s_logger.isDebugEnabled()) {
            s_logger.debug("Release sync source for job-" + executionContext.getJob().getId() + " sync source: " + executionContext.getSyncSource().getContentType() + "-" + executionContext.getSyncSource().getContentId());
        }
        _queueMgr.purgeItem(executionContext.getSyncSource().getId());
        checkQueue(executionContext.getSyncSource().getQueueId());
    }
}
Also used : AsyncJobExecutionContext(org.apache.cloudstack.framework.jobs.AsyncJobExecutionContext)

Aggregations

AsyncJobExecutionContext (org.apache.cloudstack.framework.jobs.AsyncJobExecutionContext)32 VmWorkJobVO (org.apache.cloudstack.framework.jobs.impl.VmWorkJobVO)27 CloudRuntimeException (com.cloud.utils.exception.CloudRuntimeException)26 ConcurrentOperationException (com.cloud.exception.ConcurrentOperationException)14 InvalidParameterValueException (com.cloud.exception.InvalidParameterValueException)13 InsufficientCapacityException (com.cloud.exception.InsufficientCapacityException)10 ActionEvent (com.cloud.event.ActionEvent)8 Account (com.cloud.user.Account)8 ExecutionException (java.util.concurrent.ExecutionException)8 DataObject (org.apache.cloudstack.engine.subsystem.api.storage.DataObject)8 ResourceUnavailableException (com.cloud.exception.ResourceUnavailableException)7 UserVmVO (com.cloud.vm.UserVmVO)7 StoragePoolVO (org.apache.cloudstack.storage.datastore.db.StoragePoolVO)7 ResourceAllocationException (com.cloud.exception.ResourceAllocationException)5 VMInstanceVO (com.cloud.vm.VMInstanceVO)5 VmWorkAttachVolume (com.cloud.vm.VmWorkAttachVolume)5 VmWorkDetachVolume (com.cloud.vm.VmWorkDetachVolume)5 VmWorkExtractVolume (com.cloud.vm.VmWorkExtractVolume)5 VmWorkMigrateVolume (com.cloud.vm.VmWorkMigrateVolume)5 VmWorkResizeVolume (com.cloud.vm.VmWorkResizeVolume)5