Search in sources :

Example 26 with AsyncJobExecutionContext

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

the class VMSnapshotManagerImpl method revertToSnapshot.

@Override
@ActionEvent(eventType = EventTypes.EVENT_VM_SNAPSHOT_REVERT, eventDescription = "revert to VM snapshot", async = true)
public UserVm revertToSnapshot(Long vmSnapshotId) throws InsufficientCapacityException, ResourceUnavailableException, ConcurrentOperationException {
    // check if VM snapshot exists in DB
    VMSnapshotVO vmSnapshotVo = _vmSnapshotDao.findById(vmSnapshotId);
    if (vmSnapshotVo == null) {
        throw new InvalidParameterValueException("unable to find the vm snapshot with id " + vmSnapshotId);
    }
    Long vmId = vmSnapshotVo.getVmId();
    UserVmVO userVm = _userVMDao.findById(vmId);
    // check if VM exists
    if (userVm == null) {
        throw new InvalidParameterValueException("Revert vm to snapshot: " + vmSnapshotId + " failed due to vm: " + vmId + " is not found");
    }
    // check if there are other active VM snapshot tasks
    if (hasActiveVMSnapshotTasks(vmId)) {
        throw new InvalidParameterValueException("There is other active vm snapshot tasks on the instance, please try again later");
    }
    Account caller = getCaller();
    _accountMgr.checkAccess(caller, null, true, vmSnapshotVo);
    // VM should be in running or stopped states
    if (userVm.getState() != VirtualMachine.State.Running && userVm.getState() != VirtualMachine.State.Stopped) {
        throw new InvalidParameterValueException("VM Snapshot reverting failed due to vm is not in the state of Running or Stopped.");
    }
    if (userVm.getState() == VirtualMachine.State.Running && vmSnapshotVo.getType() == VMSnapshot.Type.Disk || userVm.getState() == VirtualMachine.State.Stopped && vmSnapshotVo.getType() == VMSnapshot.Type.DiskAndMemory) {
        throw new InvalidParameterValueException("VM Snapshot revert not allowed. This will result in VM state change. You can revert running VM to disk and memory type snapshot and stopped VM to disk type" + " snapshot");
    }
    // if snapshot is not created, error out
    if (vmSnapshotVo.getState() != VMSnapshot.State.Ready) {
        throw new InvalidParameterValueException("VM Snapshot reverting failed due to vm snapshot is not in the state of Created.");
    }
    // serialize VM operation
    AsyncJobExecutionContext jobContext = AsyncJobExecutionContext.getCurrentExecutionContext();
    if (jobContext.isJobDispatchedBy(VmWorkConstants.VM_WORK_JOB_DISPATCHER)) {
        // avoid re-entrance
        VmWorkJobVO placeHolder = null;
        placeHolder = createPlaceHolderWork(vmSnapshotVo.getVmId());
        try {
            return orchestrateRevertToVMSnapshot(vmSnapshotId);
        } finally {
            _workJobDao.expunge(placeHolder.getId());
        }
    } else {
        Outcome<VMSnapshot> outcome = revertToVMSnapshotThroughJobQueue(vmSnapshotVo.getVmId(), vmSnapshotId);
        VMSnapshot result = null;
        try {
            result = outcome.get();
        } catch (InterruptedException e) {
            throw new RuntimeException("Operation is interrupted", e);
        } catch (java.util.concurrent.ExecutionException e) {
            throw new RuntimeException("Execution excetion", e);
        }
        Object jobResult = _jobMgr.unmarshallResultObject(outcome.getJob());
        if (jobResult != null) {
            if (jobResult instanceof ConcurrentOperationException)
                throw (ConcurrentOperationException) jobResult;
            else if (jobResult instanceof InsufficientCapacityException)
                throw (InsufficientCapacityException) jobResult;
            else if (jobResult instanceof ResourceUnavailableException)
                throw (ResourceUnavailableException) jobResult;
            else if (jobResult instanceof Throwable)
                throw new RuntimeException("Unexpected exception", (Throwable) jobResult);
        }
        return userVm;
    }
}
Also used : Account(com.cloud.user.Account) UserVmVO(com.cloud.vm.UserVmVO) AsyncJobExecutionContext(org.apache.cloudstack.framework.jobs.AsyncJobExecutionContext) ConcurrentOperationException(com.cloud.exception.ConcurrentOperationException) VmWorkJobVO(org.apache.cloudstack.framework.jobs.impl.VmWorkJobVO) CloudRuntimeException(com.cloud.utils.exception.CloudRuntimeException) InvalidParameterValueException(com.cloud.exception.InvalidParameterValueException) ResourceUnavailableException(com.cloud.exception.ResourceUnavailableException) InsufficientCapacityException(com.cloud.exception.InsufficientCapacityException) ActionEvent(com.cloud.event.ActionEvent)

Example 27 with AsyncJobExecutionContext

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

the class VolumeApiServiceImpl method takeSnapshotInternal.

private Snapshot takeSnapshotInternal(Long volumeId, Long policyId, Long snapshotId, Account account, boolean quiescevm, Snapshot.LocationType locationType, boolean asyncBackup) throws ResourceAllocationException {
    Account caller = CallContext.current().getCallingAccount();
    VolumeInfo volume = volFactory.getVolume(volumeId);
    if (volume == null) {
        throw new InvalidParameterValueException("Creating snapshot failed due to volume:" + volumeId + " doesn't exist");
    }
    _accountMgr.checkAccess(caller, null, true, volume);
    if (volume.getState() != Volume.State.Ready) {
        throw new InvalidParameterValueException("VolumeId: " + volumeId + " is not in " + Volume.State.Ready + " state but " + volume.getState() + ". Cannot take snapshot.");
    }
    StoragePoolVO storagePoolVO = _storagePoolDao.findById(volume.getPoolId());
    if (storagePoolVO.isManaged() && locationType == null) {
        locationType = Snapshot.LocationType.PRIMARY;
    }
    VMInstanceVO vm = null;
    if (volume.getInstanceId() != null) {
        vm = _vmInstanceDao.findById(volume.getInstanceId());
    }
    if (vm != null) {
        _accountMgr.checkAccess(caller, null, true, vm);
        // serialize VM operation
        AsyncJobExecutionContext jobContext = AsyncJobExecutionContext.getCurrentExecutionContext();
        if (jobContext.isJobDispatchedBy(VmWorkConstants.VM_WORK_JOB_DISPATCHER)) {
            // avoid re-entrance
            VmWorkJobVO placeHolder = null;
            placeHolder = createPlaceHolderWork(vm.getId());
            try {
                return orchestrateTakeVolumeSnapshot(volumeId, policyId, snapshotId, account, quiescevm, locationType, asyncBackup);
            } finally {
                _workJobDao.expunge(placeHolder.getId());
            }
        } else {
            Outcome<Snapshot> outcome = takeVolumeSnapshotThroughJobQueue(vm.getId(), volumeId, policyId, snapshotId, account.getId(), quiescevm, locationType, asyncBackup);
            try {
                outcome.get();
            } catch (InterruptedException e) {
                throw new RuntimeException("Operation is interrupted", e);
            } catch (java.util.concurrent.ExecutionException e) {
                throw new RuntimeException("Execution excetion", 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 Throwable) {
                    throw new RuntimeException("Unexpected exception", (Throwable) jobResult);
                }
            }
            return _snapshotDao.findById(snapshotId);
        }
    } else {
        CreateSnapshotPayload payload = new CreateSnapshotPayload();
        payload.setSnapshotId(snapshotId);
        payload.setSnapshotPolicyId(policyId);
        payload.setAccount(account);
        payload.setQuiescevm(quiescevm);
        payload.setAsyncBackup(asyncBackup);
        volume.addPayload(payload);
        return volService.takeSnapshot(volume);
    }
}
Also used : Account(com.cloud.user.Account) AsyncJobExecutionContext(org.apache.cloudstack.framework.jobs.AsyncJobExecutionContext) VMInstanceVO(com.cloud.vm.VMInstanceVO) VolumeInfo(org.apache.cloudstack.engine.subsystem.api.storage.VolumeInfo) ConcurrentOperationException(com.cloud.exception.ConcurrentOperationException) VmWorkJobVO(org.apache.cloudstack.framework.jobs.impl.VmWorkJobVO) ExecutionException(java.util.concurrent.ExecutionException) VmWorkTakeVolumeSnapshot(com.cloud.vm.VmWorkTakeVolumeSnapshot) CloudRuntimeException(com.cloud.utils.exception.CloudRuntimeException) InvalidParameterValueException(com.cloud.exception.InvalidParameterValueException) StoragePoolVO(org.apache.cloudstack.storage.datastore.db.StoragePoolVO) DataObject(org.apache.cloudstack.engine.subsystem.api.storage.DataObject) ResourceAllocationException(com.cloud.exception.ResourceAllocationException)

Example 28 with AsyncJobExecutionContext

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

the class VolumeApiServiceImpl method detachVolumeFromVM.

@Override
@ActionEvent(eventType = EventTypes.EVENT_VOLUME_DETACH, eventDescription = "detaching volume", async = true)
public Volume detachVolumeFromVM(DetachVolumeCmd cmmd) {
    Account caller = CallContext.current().getCallingAccount();
    if ((cmmd.getId() == null && cmmd.getDeviceId() == null && cmmd.getVirtualMachineId() == null) || (cmmd.getId() != null && (cmmd.getDeviceId() != null || cmmd.getVirtualMachineId() != null)) || (cmmd.getId() == null && (cmmd.getDeviceId() == null || cmmd.getVirtualMachineId() == null))) {
        throw new InvalidParameterValueException("Please provide either a volume id, or a tuple(device id, instance id)");
    }
    Long volumeId = cmmd.getId();
    VolumeVO volume = null;
    if (volumeId != null) {
        volume = _volsDao.findById(volumeId);
    } else {
        volume = _volsDao.findByInstanceAndDeviceId(cmmd.getVirtualMachineId(), cmmd.getDeviceId()).get(0);
    }
    // Check that the volume ID is valid
    if (volume == null) {
        throw new InvalidParameterValueException("Unable to find volume with ID: " + volumeId);
    }
    Long vmId = null;
    if (cmmd.getVirtualMachineId() == null) {
        vmId = volume.getInstanceId();
    } else {
        vmId = cmmd.getVirtualMachineId();
    }
    // Permissions check
    _accountMgr.checkAccess(caller, null, true, volume);
    // Check that the volume is currently attached to a VM
    if (vmId == null) {
        throw new InvalidParameterValueException("The specified volume is not attached to a VM.");
    }
    // Check that the VM is in the correct state
    UserVmVO vm = _userVmDao.findById(vmId);
    if (vm.getState() != State.Running && vm.getState() != State.Stopped && vm.getState() != State.Destroyed) {
        throw new InvalidParameterValueException("Please specify a VM that is either running or stopped.");
    }
    // Check that the volume is a data/root volume
    if (!(volume.getVolumeType() == Volume.Type.ROOT || volume.getVolumeType() == Volume.Type.DATADISK)) {
        throw new InvalidParameterValueException("Please specify volume of type " + Volume.Type.DATADISK.toString() + " or " + Volume.Type.ROOT.toString());
    }
    // Root volume detach is allowed for following hypervisors: Xen/KVM/VmWare
    if (volume.getVolumeType() == Volume.Type.ROOT) {
        validateRootVolumeDetachAttach(volume, vm);
    }
    // Don't allow detach if target VM has associated VM snapshots
    List<VMSnapshotVO> vmSnapshots = _vmSnapshotDao.findByVm(vmId);
    if (vmSnapshots.size() > 0) {
        throw new InvalidParameterValueException("Unable to detach volume, please specify a VM that does not have VM snapshots");
    }
    if (vm.getBackupOfferingId() != null || vm.getBackupVolumeList().size() > 0) {
        throw new InvalidParameterValueException("Unable to detach volume, cannot detach volume from a VM that has backups. First remove the VM from the backup offering.");
    }
    AsyncJobExecutionContext asyncExecutionContext = AsyncJobExecutionContext.getCurrentExecutionContext();
    if (asyncExecutionContext != null) {
        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");
        }
        _jobMgr.updateAsyncJobAttachment(job.getId(), "Volume", volumeId);
    }
    AsyncJobExecutionContext jobContext = AsyncJobExecutionContext.getCurrentExecutionContext();
    if (jobContext.isJobDispatchedBy(VmWorkConstants.VM_WORK_JOB_DISPATCHER)) {
        // avoid re-entrance
        VmWorkJobVO placeHolder = null;
        placeHolder = createPlaceHolderWork(vmId);
        try {
            return orchestrateDetachVolumeFromVM(vmId, volumeId);
        } finally {
            _workJobDao.expunge(placeHolder.getId());
        }
    } else {
        Outcome<Volume> outcome = detachVolumeFromVmThroughJobQueue(vmId, volumeId);
        Volume vol = null;
        try {
            outcome.get();
        } catch (InterruptedException e) {
            throw new RuntimeException("Operation is interrupted", e);
        } catch (java.util.concurrent.ExecutionException e) {
            throw new RuntimeException("Execution excetion", e);
        }
        Object jobResult = _jobMgr.unmarshallResultObject(outcome.getJob());
        if (jobResult != null) {
            if (jobResult instanceof ConcurrentOperationException) {
                throw (ConcurrentOperationException) 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 = _volsDao.findById((Long) jobResult);
            }
        }
        return vol;
    }
}
Also used : Account(com.cloud.user.Account) UserVmVO(com.cloud.vm.UserVmVO) AsyncJobExecutionContext(org.apache.cloudstack.framework.jobs.AsyncJobExecutionContext) ConcurrentOperationException(com.cloud.exception.ConcurrentOperationException) AsyncJob(org.apache.cloudstack.framework.jobs.AsyncJob) VmWorkJobVO(org.apache.cloudstack.framework.jobs.impl.VmWorkJobVO) ExecutionException(java.util.concurrent.ExecutionException) VMSnapshotVO(com.cloud.vm.snapshot.VMSnapshotVO) CloudRuntimeException(com.cloud.utils.exception.CloudRuntimeException) InvalidParameterValueException(com.cloud.exception.InvalidParameterValueException) 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)

Example 29 with AsyncJobExecutionContext

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

the class VolumeApiServiceImpl method resizeVolumeInternal.

private VolumeVO resizeVolumeInternal(VolumeVO volume, DiskOfferingVO newDiskOffering, Long currentSize, Long newSize, Long newMinIops, Long newMaxIops, Integer newHypervisorSnapshotReserve, boolean shrinkOk) throws ResourceAllocationException {
    UserVmVO userVm = _userVmDao.findById(volume.getInstanceId());
    HypervisorType hypervisorType = _volsDao.getHypervisorType(volume.getId());
    if (userVm != null) {
        if (volume.getVolumeType().equals(Volume.Type.ROOT) && userVm.getPowerState() != VirtualMachine.PowerState.PowerOff && hypervisorType == HypervisorType.VMware) {
            s_logger.error(" For ROOT volume resize VM should be in Power Off state.");
            throw new InvalidParameterValueException("VM current state is : " + userVm.getPowerState() + ". But VM should be in " + VirtualMachine.PowerState.PowerOff + " state.");
        }
        // 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 ? newDiskOffering.getId() : null, shrinkOk);
            } finally {
                _workJobDao.expunge(placeHolder.getId());
            }
        } else {
            Outcome<Volume> outcome = resizeVolumeThroughJobQueue(userVm.getId(), volume.getId(), currentSize, newSize, newMinIops, newMaxIops, newHypervisorSnapshotReserve, newDiskOffering != null ? newDiskOffering.getId() : 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 ? newDiskOffering.getId() : null, shrinkOk);
}
Also used : UserVmVO(com.cloud.vm.UserVmVO) AsyncJobExecutionContext(org.apache.cloudstack.framework.jobs.AsyncJobExecutionContext) ConcurrentOperationException(com.cloud.exception.ConcurrentOperationException) VmWorkJobVO(org.apache.cloudstack.framework.jobs.impl.VmWorkJobVO) HypervisorType(com.cloud.hypervisor.Hypervisor.HypervisorType) ExecutionException(java.util.concurrent.ExecutionException) CloudRuntimeException(com.cloud.utils.exception.CloudRuntimeException) InvalidParameterValueException(com.cloud.exception.InvalidParameterValueException) 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) ResourceAllocationException(com.cloud.exception.ResourceAllocationException)

Example 30 with AsyncJobExecutionContext

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

the class VolumeApiServiceImpl method migrateVolume.

@DB
@Override
@ActionEvent(eventType = EventTypes.EVENT_VOLUME_MIGRATE, eventDescription = "migrating volume", async = true)
public Volume migrateVolume(MigrateVolumeCmd cmd) {
    Account caller = CallContext.current().getCallingAccount();
    Long volumeId = cmd.getVolumeId();
    Long storagePoolId = cmd.getStoragePoolId();
    VolumeVO vol = _volsDao.findById(volumeId);
    if (vol == null) {
        throw new InvalidParameterValueException("Failed to find the volume id: " + volumeId);
    }
    _accountMgr.checkAccess(caller, null, true, vol);
    if (vol.getState() != Volume.State.Ready) {
        throw new InvalidParameterValueException("Volume must be in ready state");
    }
    if (vol.getPoolId() == storagePoolId) {
        throw new InvalidParameterValueException("Volume " + vol + " is already on the destination storage pool");
    }
    boolean liveMigrateVolume = false;
    Long instanceId = vol.getInstanceId();
    Long srcClusterId = null;
    VMInstanceVO vm = null;
    if (instanceId != null) {
        vm = _vmInstanceDao.findById(instanceId);
    }
    // OfflineVmwareMigration: consider if this is needed and desirable
    if (vm != null && _vmSnapshotDao.findByVm(vm.getId()).size() > 0) {
        throw new InvalidParameterValueException("Volume cannot be migrated, please remove all VM snapshots for VM to which this volume is attached");
    }
    // OfflineVmwareMigration: extract this block as method and check if it is subject to regression
    if (vm != null && State.Running.equals(vm.getState())) {
        // Check if the VM is GPU enabled.
        if (_serviceOfferingDetailsDao.findDetail(vm.getServiceOfferingId(), GPU.Keys.pciDevice.toString()) != null) {
            throw new InvalidParameterValueException("Live Migration of GPU enabled VM is not supported");
        }
        StoragePoolVO storagePoolVO = _storagePoolDao.findById(vol.getPoolId());
        if (storagePoolVO.getPoolType() == Storage.StoragePoolType.PowerFlex) {
            throw new InvalidParameterValueException("Migrate volume of a running VM is unsupported on storage pool type " + storagePoolVO.getPoolType());
        }
        // Check if the underlying hypervisor supports storage motion.
        Long hostId = vm.getHostId();
        if (hostId != null) {
            HostVO host = _hostDao.findById(hostId);
            HypervisorCapabilitiesVO capabilities = null;
            if (host != null) {
                capabilities = _hypervisorCapabilitiesDao.findByHypervisorTypeAndVersion(host.getHypervisorType(), host.getHypervisorVersion());
                srcClusterId = host.getClusterId();
            }
            if (capabilities != null) {
                liveMigrateVolume = capabilities.isStorageMotionSupported();
            }
            if (liveMigrateVolume && HypervisorType.KVM.equals(host.getHypervisorType())) {
                throw new InvalidParameterValueException("KVM does not support volume live migration due to the limited possibility to refresh VM XML domain. " + "Therefore, to live migrate a volume between storage pools, one must migrate the VM to a different host as well to force the VM XML domain update. " + "Use 'migrateVirtualMachineWithVolumes' instead.");
            }
        }
        // If vm is running, and hypervisor doesn't support live migration, then return error
        if (!liveMigrateVolume) {
            throw new InvalidParameterValueException("Volume needs to be detached from VM");
        }
        if (!cmd.isLiveMigrate()) {
            throw new InvalidParameterValueException("The volume " + vol + "is attached to a vm and for migrating it " + "the parameter livemigrate should be specified");
        }
    }
    if (vm != null && HypervisorType.VMware.equals(vm.getHypervisorType()) && State.Stopped.equals(vm.getState())) {
        // For VMware, use liveMigrateVolume=true so that it follows VmwareStorageMotionStrategy
        liveMigrateVolume = true;
    }
    StoragePool destPool = (StoragePool) dataStoreMgr.getDataStore(storagePoolId, DataStoreRole.Primary);
    if (destPool == null) {
        throw new InvalidParameterValueException("Failed to find the destination storage pool: " + storagePoolId);
    } else if (destPool.isInMaintenance()) {
        throw new InvalidParameterValueException("Cannot migrate volume " + vol + "to the destination storage pool " + destPool.getName() + " as the storage pool is in maintenance mode.");
    }
    DiskOfferingVO diskOffering = _diskOfferingDao.findById(vol.getDiskOfferingId());
    if (diskOffering == null) {
        throw new CloudRuntimeException("volume '" + vol.getUuid() + "', has no diskoffering. Migration target cannot be checked.");
    }
    String poolUuid = destPool.getUuid();
    if (destPool.getPoolType() == Storage.StoragePoolType.DatastoreCluster) {
        DataCenter dc = _entityMgr.findById(DataCenter.class, vol.getDataCenterId());
        Pod destPoolPod = _entityMgr.findById(Pod.class, destPool.getPodId());
        destPool = _volumeMgr.findChildDataStoreInDataStoreCluster(dc, destPoolPod, destPool.getClusterId(), null, null, destPool.getId());
    }
    if (!storageMgr.storagePoolCompatibleWithVolumePool(destPool, (Volume) vol)) {
        throw new CloudRuntimeException("Storage pool " + destPool.getName() + " is not suitable to migrate volume " + vol.getName());
    }
    HypervisorType hypervisorType = _volsDao.getHypervisorType(volumeId);
    DiskProfile diskProfile = new DiskProfile(vol, diskOffering, hypervisorType);
    Pair<Volume, DiskProfile> volumeDiskProfilePair = new Pair<>(vol, diskProfile);
    if (!storageMgr.storagePoolHasEnoughSpace(Collections.singletonList(volumeDiskProfilePair), destPool)) {
        throw new CloudRuntimeException("Storage pool " + destPool.getName() + " does not have enough space to migrate volume " + vol.getName());
    }
    if (liveMigrateVolume && State.Running.equals(vm.getState()) && destPool.getClusterId() != null && srcClusterId != null) {
        if (!srcClusterId.equals(destPool.getClusterId())) {
            throw new InvalidParameterValueException("Cannot migrate a volume of a virtual machine to a storage pool in a different cluster");
        }
    }
    // In case of VMware, if ROOT volume is being cold-migrated, then ensure destination storage pool is in the same Datacenter as the VM.
    if (vm != null && vm.getHypervisorType().equals(HypervisorType.VMware)) {
        if (!liveMigrateVolume && vol.volumeType.equals(Volume.Type.ROOT)) {
            Long hostId = vm.getHostId() != null ? vm.getHostId() : vm.getLastHostId();
            HostVO host = _hostDao.findById(hostId);
            if (host != null) {
                srcClusterId = host.getClusterId();
            }
            if (srcClusterId != null && destPool.getClusterId() != null && !srcClusterId.equals(destPool.getClusterId())) {
                String srcDcName = _clusterDetailsDao.getVmwareDcName(srcClusterId);
                String destDcName = _clusterDetailsDao.getVmwareDcName(destPool.getClusterId());
                if (srcDcName != null && destDcName != null && !srcDcName.equals(destDcName)) {
                    throw new InvalidParameterValueException("Cannot migrate ROOT volume of a stopped VM to a storage pool in a different VMware datacenter");
                }
            }
            updateMissingRootDiskController(vm, vol.getChainInfo());
        }
    }
    if (hypervisorType.equals(HypervisorType.VMware)) {
        try {
            boolean isStoragePoolStoragepolicyComplaince = storageMgr.isStoragePoolCompliantWithStoragePolicy(Arrays.asList(volumeDiskProfilePair), destPool);
            if (!isStoragePoolStoragepolicyComplaince) {
                throw new CloudRuntimeException(String.format("Storage pool %s is not storage policy compliance with the volume %s", poolUuid, vol.getUuid()));
            }
        } catch (StorageUnavailableException e) {
            throw new CloudRuntimeException(String.format("Could not verify storage policy compliance against storage pool %s due to exception %s", destPool.getUuid(), e.getMessage()));
        }
    }
    DiskOfferingVO newDiskOffering = retrieveAndValidateNewDiskOffering(cmd);
    validateConditionsToReplaceDiskOfferingOfVolume(vol, newDiskOffering, destPool);
    if (vm != null) {
        // serialize VM operation
        AsyncJobExecutionContext jobContext = AsyncJobExecutionContext.getCurrentExecutionContext();
        if (jobContext.isJobDispatchedBy(VmWorkConstants.VM_WORK_JOB_DISPATCHER)) {
            // avoid re-entrance
            VmWorkJobVO placeHolder = null;
            placeHolder = createPlaceHolderWork(vm.getId());
            try {
                return orchestrateMigrateVolume(vol, destPool, liveMigrateVolume, newDiskOffering);
            } finally {
                _workJobDao.expunge(placeHolder.getId());
            }
        } else {
            Outcome<Volume> outcome = migrateVolumeThroughJobQueue(vm, vol, destPool, liveMigrateVolume, newDiskOffering);
            try {
                outcome.get();
            } catch (InterruptedException e) {
                throw new RuntimeException("Operation is interrupted", e);
            } catch (java.util.concurrent.ExecutionException e) {
                throw new RuntimeException("Execution excetion", e);
            }
            Object jobResult = _jobMgr.unmarshallResultObject(outcome.getJob());
            if (jobResult != null) {
                if (jobResult instanceof ConcurrentOperationException) {
                    throw (ConcurrentOperationException) jobResult;
                } else if (jobResult instanceof RuntimeException) {
                    throw (RuntimeException) jobResult;
                } else if (jobResult instanceof Throwable) {
                    throw new RuntimeException("Unexpected exception", (Throwable) jobResult);
                }
            }
            // retrieve the migrated new volume from job result
            if (jobResult != null && jobResult instanceof Long) {
                return _entityMgr.findById(VolumeVO.class, ((Long) jobResult));
            }
            return null;
        }
    }
    return orchestrateMigrateVolume(vol, destPool, liveMigrateVolume, newDiskOffering);
}
Also used : HypervisorCapabilitiesVO(com.cloud.hypervisor.HypervisorCapabilitiesVO) Account(com.cloud.user.Account) AsyncJobExecutionContext(org.apache.cloudstack.framework.jobs.AsyncJobExecutionContext) CloudRuntimeException(com.cloud.utils.exception.CloudRuntimeException) StorageUnavailableException(com.cloud.exception.StorageUnavailableException) InvalidParameterValueException(com.cloud.exception.InvalidParameterValueException) CloudRuntimeException(com.cloud.utils.exception.CloudRuntimeException) StoragePoolVO(org.apache.cloudstack.storage.datastore.db.StoragePoolVO) Pair(com.cloud.utils.Pair) Pod(com.cloud.dc.Pod) VMInstanceVO(com.cloud.vm.VMInstanceVO) DiskProfile(com.cloud.vm.DiskProfile) ConcurrentOperationException(com.cloud.exception.ConcurrentOperationException) HostVO(com.cloud.host.HostVO) VmWorkJobVO(org.apache.cloudstack.framework.jobs.impl.VmWorkJobVO) HypervisorType(com.cloud.hypervisor.Hypervisor.HypervisorType) ExecutionException(java.util.concurrent.ExecutionException) DataCenter(com.cloud.dc.DataCenter) 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)

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