Search in sources :

Example 41 with DiskProfile

use of com.cloud.vm.DiskProfile in project cloudstack by apache.

the class OvmResourceBase method execute.

protected CreateAnswer execute(CreateCommand cmd) {
    StorageFilerTO primaryStorage = cmd.getPool();
    DiskProfile disk = cmd.getDiskCharacteristics();
    try {
        OvmVolume.Details vol = null;
        if (cmd.getTemplateUrl() != null) {
            vol = OvmVolume.createFromTemplate(_conn, primaryStorage.getUuid(), cmd.getTemplateUrl());
        } else {
            vol = OvmVolume.createDataDsik(_conn, primaryStorage.getUuid(), Long.toString(disk.getSize()), disk.getType() == Volume.Type.ROOT);
        }
        VolumeTO volume = new VolumeTO(cmd.getVolumeId(), disk.getType(), primaryStorage.getType(), primaryStorage.getUuid(), primaryStorage.getPath(), vol.name, vol.path, vol.size, null);
        return new CreateAnswer(cmd, volume);
    } catch (Exception e) {
        s_logger.debug("CreateCommand failed", e);
        return new CreateAnswer(cmd, e.getMessage());
    }
}
Also used : CreateAnswer(com.cloud.agent.api.storage.CreateAnswer) VolumeTO(com.cloud.agent.api.to.VolumeTO) StorageFilerTO(com.cloud.agent.api.to.StorageFilerTO) DiskProfile(com.cloud.vm.DiskProfile) XmlRpcException(org.apache.xmlrpc.XmlRpcException) CloudRuntimeException(com.cloud.utils.exception.CloudRuntimeException) IOException(java.io.IOException) URISyntaxException(java.net.URISyntaxException) ConfigurationException(javax.naming.ConfigurationException) OvmVolume(com.cloud.ovm.object.OvmVolume)

Example 42 with DiskProfile

use of com.cloud.vm.DiskProfile in project cloudstack by apache.

the class StorageManagerImpl method isStoragePoolCompliantWithStoragePolicy.

@Override
public boolean isStoragePoolCompliantWithStoragePolicy(List<Pair<Volume, DiskProfile>> volumes, StoragePool pool) throws StorageUnavailableException {
    if (CollectionUtils.isEmpty(volumes)) {
        return false;
    }
    List<Pair<Volume, Answer>> answers = new ArrayList<Pair<Volume, Answer>>();
    for (Pair<Volume, DiskProfile> volumeDiskProfilePair : volumes) {
        String storagePolicyId = null;
        Volume volume = volumeDiskProfilePair.first();
        DiskProfile diskProfile = volumeDiskProfilePair.second();
        if (volume.getVolumeType() == Type.ROOT) {
            Long vmId = volume.getInstanceId();
            if (vmId != null) {
                VMInstanceVO vm = _vmInstanceDao.findByIdIncludingRemoved(vmId);
                storagePolicyId = _serviceOfferingDetailsDao.getDetail(vm.getServiceOfferingId(), ApiConstants.STORAGE_POLICY);
            }
        } else {
            storagePolicyId = _diskOfferingDetailsDao.getDetail(diskProfile.getDiskOfferingId(), ApiConstants.STORAGE_POLICY);
        }
        if (StringUtils.isNotEmpty(storagePolicyId)) {
            VsphereStoragePolicyVO storagePolicyVO = _vsphereStoragePolicyDao.findById(Long.parseLong(storagePolicyId));
            List<Long> hostIds = getUpHostsInPool(pool.getId());
            Collections.shuffle(hostIds);
            if (hostIds == null || hostIds.isEmpty()) {
                throw new StorageUnavailableException("Unable to send command to the pool " + pool.getName() + " due to there is no enabled hosts up in this cluster", pool.getId());
            }
            try {
                StorageFilerTO storageFilerTO = new StorageFilerTO(pool);
                CheckDataStoreStoragePolicyComplainceCommand cmd = new CheckDataStoreStoragePolicyComplainceCommand(storagePolicyVO.getPolicyId(), storageFilerTO);
                long targetHostId = _hvGuruMgr.getGuruProcessedCommandTargetHost(hostIds.get(0), cmd);
                Answer answer = _agentMgr.send(targetHostId, cmd);
                answers.add(new Pair<>(volume, answer));
            } catch (AgentUnavailableException e) {
                s_logger.debug("Unable to send storage pool command to " + pool + " via " + hostIds.get(0), e);
                throw new StorageUnavailableException("Unable to send command to the pool ", pool.getId());
            } catch (OperationTimedoutException e) {
                s_logger.debug("Failed to process storage pool command to " + pool + " via " + hostIds.get(0), e);
                throw new StorageUnavailableException("Failed to process storage command to the pool ", pool.getId());
            }
        }
    }
    // check cummilative result for all volumes
    for (Pair<Volume, Answer> answer : answers) {
        if (!answer.second().getResult()) {
            s_logger.debug(String.format("Storage pool %s is not compliance with storage policy for volume %s", pool.getUuid(), answer.first().getName()));
            return false;
        }
    }
    return true;
}
Also used : OperationTimedoutException(com.cloud.exception.OperationTimedoutException) CheckDataStoreStoragePolicyComplainceCommand(org.apache.cloudstack.storage.command.CheckDataStoreStoragePolicyComplainceCommand) ArrayList(java.util.ArrayList) VMInstanceVO(com.cloud.vm.VMInstanceVO) DiskProfile(com.cloud.vm.DiskProfile) StorageFilerTO(com.cloud.agent.api.to.StorageFilerTO) ModifyStoragePoolAnswer(com.cloud.agent.api.ModifyStoragePoolAnswer) GetVolumeStatsAnswer(com.cloud.agent.api.GetVolumeStatsAnswer) Answer(com.cloud.agent.api.Answer) SyncVolumePathAnswer(org.apache.cloudstack.storage.command.SyncVolumePathAnswer) GetStoragePoolCapabilitiesAnswer(com.cloud.agent.api.GetStoragePoolCapabilitiesAnswer) GetStorageStatsAnswer(com.cloud.agent.api.GetStorageStatsAnswer) StorageUnavailableException(com.cloud.exception.StorageUnavailableException) AgentUnavailableException(com.cloud.exception.AgentUnavailableException) VsphereStoragePolicyVO(com.cloud.dc.VsphereStoragePolicyVO) Pair(com.cloud.utils.Pair)

Example 43 with DiskProfile

use of com.cloud.vm.DiskProfile 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)

Example 44 with DiskProfile

use of com.cloud.vm.DiskProfile in project cloudstack by apache.

the class StorageManagerImpl method storagePoolHasEnoughSpace.

@Override
public boolean storagePoolHasEnoughSpace(List<Pair<Volume, DiskProfile>> volumeDiskProfilesList, StoragePool pool, Long clusterId) {
    if (CollectionUtils.isEmpty(volumeDiskProfilesList)) {
        return false;
    }
    if (!checkUsagedSpace(pool)) {
        return false;
    }
    // allocated space includes templates
    if (s_logger.isDebugEnabled()) {
        s_logger.debug("Destination pool id: " + pool.getId());
    }
    // allocated space includes templates
    final StoragePoolVO poolVO = _storagePoolDao.findById(pool.getId());
    long allocatedSizeWithTemplate = _capacityMgr.getAllocatedPoolCapacity(poolVO, null);
    long totalAskingSize = 0;
    for (Pair<Volume, DiskProfile> volumeDiskProfilePair : volumeDiskProfilesList) {
        // refreshing the volume from the DB to get latest hv_ss_reserve (hypervisor snapshot reserve) field
        // I could have just assigned this to "volume", but decided to make a new variable for it so that it
        // might be clearer that this "volume" in "volumeDiskProfilesList" still might have an old value for hv_ss_reverse.
        Volume volume = volumeDiskProfilePair.first();
        DiskProfile diskProfile = volumeDiskProfilePair.second();
        VolumeVO volumeVO = _volumeDao.findById(volume.getId());
        if (volumeVO.getHypervisorSnapshotReserve() == null) {
            // update the volume's hv_ss_reserve (hypervisor snapshot reserve) from a disk offering (used for managed storage)
            volService.updateHypervisorSnapshotReserveForVolume(getDiskOfferingVO(volumeVO), volumeVO.getId(), getHypervisorType(volumeVO));
            // hv_ss_reserve field might have been updated; refresh from DB to make use of it in getDataObjectSizeIncludingHypervisorSnapshotReserve
            volumeVO = _volumeDao.findById(volume.getId());
        }
        // to leverage a template)
        if (volume.getTemplateId() != null) {
            VMTemplateVO tmpl = _templateDao.findByIdIncludingRemoved(volume.getTemplateId());
            if (tmpl != null && !ImageFormat.ISO.equals(tmpl.getFormat())) {
                allocatedSizeWithTemplate = _capacityMgr.getAllocatedPoolCapacity(poolVO, tmpl);
            }
        }
        if (s_logger.isDebugEnabled()) {
            s_logger.debug("Pool ID for the volume with ID " + volumeVO.getId() + " is " + volumeVO.getPoolId());
        }
        // In case the volume is moving across pools or is not ready yet, the asking size has to be computed.
        if ((volumeVO.getState() != Volume.State.Ready) || (volumeVO.getPoolId() != pool.getId())) {
            totalAskingSize += getDataObjectSizeIncludingHypervisorSnapshotReserve(volumeVO, diskProfile, poolVO);
            totalAskingSize += getAskingSizeForTemplateBasedOnClusterAndStoragePool(volumeVO.getTemplateId(), clusterId, poolVO);
        }
    }
    return checkPoolforSpace(pool, allocatedSizeWithTemplate, totalAskingSize);
}
Also used : StoragePoolVO(org.apache.cloudstack.storage.datastore.db.StoragePoolVO) DiskProfile(com.cloud.vm.DiskProfile)

Example 45 with DiskProfile

use of com.cloud.vm.DiskProfile in project cloudstack by apache.

the class ManagementServerImpl method listHostsForMigrationOfVM.

@Override
public Ternary<Pair<List<? extends Host>, Integer>, List<? extends Host>, Map<Host, Boolean>> listHostsForMigrationOfVM(final Long vmId, final Long startIndex, final Long pageSize, final String keyword) {
    final Account caller = getCaller();
    if (!_accountMgr.isRootAdmin(caller.getId())) {
        if (s_logger.isDebugEnabled()) {
            s_logger.debug("Caller is not a root admin, permission denied to migrate the VM");
        }
        throw new PermissionDeniedException("No permission to migrate VM, Only Root Admin can migrate a VM!");
    }
    final VMInstanceVO vm = _vmInstanceDao.findById(vmId);
    if (vm == null) {
        final InvalidParameterValueException ex = new InvalidParameterValueException("Unable to find the VM with given id");
        throw ex;
    }
    if (vm.getState() != State.Running) {
        if (s_logger.isDebugEnabled()) {
            s_logger.debug("VM is not running, cannot migrate the vm" + vm);
        }
        final InvalidParameterValueException ex = new InvalidParameterValueException("VM is not Running, cannot " + "migrate the vm with specified id");
        ex.addProxyObject(vm.getUuid(), "vmId");
        throw ex;
    }
    UserVmDetailVO userVmDetailVO = _UserVmDetailsDao.findDetail(vm.getId(), ApiConstants.BootType.UEFI.toString());
    if (userVmDetailVO != null) {
        s_logger.info(" Live Migration of UEFI enabled VM : " + vm.getInstanceName() + " is not supported");
        if ("legacy".equalsIgnoreCase(userVmDetailVO.getValue()) || "secure".equalsIgnoreCase(userVmDetailVO.getValue())) {
            // Return empty list.
            return new Ternary<Pair<List<? extends Host>, Integer>, List<? extends Host>, Map<Host, Boolean>>(new Pair<List<? extends Host>, Integer>(new ArrayList<HostVO>(), new Integer(0)), new ArrayList<Host>(), new HashMap<Host, Boolean>());
        }
    }
    if (_serviceOfferingDetailsDao.findDetail(vm.getServiceOfferingId(), GPU.Keys.pciDevice.toString()) != null) {
        s_logger.info(" Live Migration of GPU enabled VM : " + vm.getInstanceName() + " is not supported");
        // Return empty list.
        return new Ternary<Pair<List<? extends Host>, Integer>, List<? extends Host>, Map<Host, Boolean>>(new Pair<List<? extends Host>, Integer>(new ArrayList<HostVO>(), new Integer(0)), new ArrayList<Host>(), new HashMap<Host, Boolean>());
    }
    if (!vm.getHypervisorType().equals(HypervisorType.XenServer) && !vm.getHypervisorType().equals(HypervisorType.VMware) && !vm.getHypervisorType().equals(HypervisorType.KVM) && !vm.getHypervisorType().equals(HypervisorType.Ovm) && !vm.getHypervisorType().equals(HypervisorType.Hyperv) && !vm.getHypervisorType().equals(HypervisorType.LXC) && !vm.getHypervisorType().equals(HypervisorType.Simulator) && !vm.getHypervisorType().equals(HypervisorType.Ovm3)) {
        if (s_logger.isDebugEnabled()) {
            s_logger.debug(vm + " is not XenServer/VMware/KVM/Ovm/Hyperv/Ovm3, cannot migrate this VM.");
        }
        throw new InvalidParameterValueException("Unsupported Hypervisor Type for VM migration, we support " + "XenServer/VMware/KVM/Ovm/Hyperv/Ovm3 only");
    }
    if (vm.getType().equals(VirtualMachine.Type.User) && vm.getHypervisorType().equals(HypervisorType.LXC)) {
        throw new InvalidParameterValueException("Unsupported Hypervisor Type for User VM migration, we support XenServer/VMware/KVM/Ovm/Hyperv/Ovm3 only");
    }
    final long srcHostId = vm.getHostId();
    final Host srcHost = _hostDao.findById(srcHostId);
    if (srcHost == null) {
        if (s_logger.isDebugEnabled()) {
            s_logger.debug("Unable to find the host with id: " + srcHostId + " of this VM:" + vm);
        }
        final InvalidParameterValueException ex = new InvalidParameterValueException("Unable to find the host (with specified id) of VM with specified id");
        ex.addProxyObject(String.valueOf(srcHostId), "hostId");
        ex.addProxyObject(vm.getUuid(), "vmId");
        throw ex;
    }
    String srcHostVersion = srcHost.getHypervisorVersion();
    if (HypervisorType.KVM.equals(srcHost.getHypervisorType()) && srcHostVersion == null) {
        srcHostVersion = "";
    }
    // Check if the vm can be migrated with storage.
    boolean canMigrateWithStorage = false;
    if (VirtualMachine.Type.User.equals(vm.getType()) || HypervisorType.VMware.equals(vm.getHypervisorType())) {
        canMigrateWithStorage = _hypervisorCapabilitiesDao.isStorageMotionSupported(srcHost.getHypervisorType(), srcHostVersion);
    }
    // Check if the vm is using any disks on local storage.
    final VirtualMachineProfile vmProfile = new VirtualMachineProfileImpl(vm, null, _offeringDao.findById(vm.getId(), vm.getServiceOfferingId()), null, null);
    final List<VolumeVO> volumes = _volumeDao.findCreatedByInstance(vmProfile.getId());
    boolean usesLocal = false;
    for (final VolumeVO volume : volumes) {
        final DiskOfferingVO diskOffering = _diskOfferingDao.findById(volume.getDiskOfferingId());
        final DiskProfile diskProfile = new DiskProfile(volume, diskOffering, vmProfile.getHypervisorType());
        if (diskProfile.useLocalStorage()) {
            usesLocal = true;
            break;
        }
    }
    if (!canMigrateWithStorage && usesLocal) {
        throw new InvalidParameterValueException("Unsupported operation, VM uses Local storage, cannot migrate");
    }
    final Type hostType = srcHost.getType();
    Pair<List<HostVO>, Integer> allHostsPair = null;
    List<HostVO> allHosts = null;
    List<HostVO> hostsForMigrationWithStorage = null;
    final Map<Host, Boolean> requiresStorageMotion = new HashMap<Host, Boolean>();
    DataCenterDeployment plan = null;
    if (canMigrateWithStorage) {
        Long podId = !VirtualMachine.Type.User.equals(vm.getType()) ? srcHost.getPodId() : null;
        allHostsPair = searchForServers(startIndex, pageSize, null, hostType, null, srcHost.getDataCenterId(), podId, null, null, keyword, null, null, srcHost.getHypervisorType(), null, srcHost.getId());
        allHosts = allHostsPair.first();
        hostsForMigrationWithStorage = new ArrayList<>(allHosts);
        for (final VolumeVO volume : volumes) {
            StoragePool storagePool = _poolDao.findById(volume.getPoolId());
            Long volClusterId = storagePool.getClusterId();
            for (Iterator<HostVO> iterator = hostsForMigrationWithStorage.iterator(); iterator.hasNext(); ) {
                final Host host = iterator.next();
                String hostVersion = host.getHypervisorVersion();
                if (HypervisorType.KVM.equals(host.getHypervisorType()) && hostVersion == null) {
                    hostVersion = "";
                }
                if (volClusterId != null) {
                    if (storagePool.isLocal() || !host.getClusterId().equals(volClusterId) || usesLocal) {
                        if (storagePool.isManaged()) {
                            // At the time being, we do not support storage migration of a volume from managed storage unless the managed storage
                            // is at the zone level and the source and target storage pool is the same.
                            // If the source and target storage pool is the same and it is managed, then we still have to perform a storage migration
                            // because we need to create a new target volume and copy the contents of the source volume into it before deleting the
                            // source volume.
                            iterator.remove();
                        } else {
                            boolean hostSupportsStorageMigration = (srcHostVersion != null && srcHostVersion.equals(hostVersion)) || _hypervisorCapabilitiesDao.isStorageMotionSupported(host.getHypervisorType(), hostVersion);
                            if (hostSupportsStorageMigration && hasSuitablePoolsForVolume(volume, host, vmProfile)) {
                                requiresStorageMotion.put(host, true);
                            } else {
                                iterator.remove();
                            }
                        }
                    }
                } else {
                    if (storagePool.isManaged()) {
                        if (srcHost.getClusterId() != host.getClusterId()) {
                            if (storagePool.getPoolType() == Storage.StoragePoolType.PowerFlex) {
                                // Simply, changing volume access to host should work: grant access on dest host and revoke access on source host
                                continue;
                            }
                            // If the volume's storage pool is managed and at the zone level, then we still have to perform a storage migration
                            // because we need to create a new target volume and copy the contents of the source volume into it before deleting
                            // the source volume.
                            requiresStorageMotion.put(host, true);
                        }
                    }
                }
            }
        }
        plan = new DataCenterDeployment(srcHost.getDataCenterId(), podId, null, null, null, null);
    } else {
        final Long cluster = srcHost.getClusterId();
        if (s_logger.isDebugEnabled()) {
            s_logger.debug("Searching for all hosts in cluster " + cluster + " for migrating VM " + vm);
        }
        allHostsPair = searchForServers(startIndex, pageSize, null, hostType, null, null, null, cluster, null, keyword, null, null, null, null, srcHost.getId());
        allHosts = allHostsPair.first();
        plan = new DataCenterDeployment(srcHost.getDataCenterId(), srcHost.getPodId(), srcHost.getClusterId(), null, null, null);
    }
    final Pair<List<? extends Host>, Integer> otherHosts = new Pair<List<? extends Host>, Integer>(allHosts, allHostsPair.second());
    List<Host> suitableHosts = new ArrayList<Host>();
    final ExcludeList excludes = new ExcludeList();
    excludes.addHost(srcHostId);
    if (dpdkHelper.isVMDpdkEnabled(vm.getId())) {
        excludeNonDPDKEnabledHosts(plan, excludes);
    }
    // call affinitygroup chain
    final long vmGroupCount = _affinityGroupVMMapDao.countAffinityGroupsForVm(vm.getId());
    if (vmGroupCount > 0) {
        for (final AffinityGroupProcessor processor : _affinityProcessors) {
            processor.process(vmProfile, plan, excludes);
        }
    }
    if (vm.getType() == VirtualMachine.Type.User || vm.getType() == VirtualMachine.Type.DomainRouter) {
        final DataCenterVO dc = _dcDao.findById(srcHost.getDataCenterId());
        _dpMgr.checkForNonDedicatedResources(vmProfile, dc, excludes);
    }
    for (final HostAllocator allocator : hostAllocators) {
        if (canMigrateWithStorage) {
            suitableHosts = allocator.allocateTo(vmProfile, plan, Host.Type.Routing, excludes, hostsForMigrationWithStorage, HostAllocator.RETURN_UPTO_ALL, false);
        } else {
            suitableHosts = allocator.allocateTo(vmProfile, plan, Host.Type.Routing, excludes, HostAllocator.RETURN_UPTO_ALL, false);
        }
        if (suitableHosts != null && !suitableHosts.isEmpty()) {
            break;
        }
    }
    if (s_logger.isDebugEnabled()) {
        if (suitableHosts.isEmpty()) {
            s_logger.debug("No suitable hosts found");
        } else {
            s_logger.debug("Hosts having capacity and suitable for migration: " + suitableHosts);
        }
    }
    return new Ternary<Pair<List<? extends Host>, Integer>, List<? extends Host>, Map<Host, Boolean>>(otherHosts, suitableHosts, requiresStorageMotion);
}
Also used : Account(com.cloud.user.Account) StoragePool(com.cloud.storage.StoragePool) HashMap(java.util.HashMap) ArrayList(java.util.ArrayList) HostAllocator(com.cloud.agent.manager.allocator.HostAllocator) VolumeVO(com.cloud.storage.VolumeVO) InvalidParameterValueException(com.cloud.exception.InvalidParameterValueException) DiskOfferingVO(com.cloud.storage.DiskOfferingVO) ArrayList(java.util.ArrayList) ExcludeList(com.cloud.deploy.DeploymentPlanner.ExcludeList) List(java.util.List) AffinityGroupProcessor(org.apache.cloudstack.affinity.AffinityGroupProcessor) Pair(com.cloud.utils.Pair) SSHKeyPair(com.cloud.user.SSHKeyPair) ExcludeList(com.cloud.deploy.DeploymentPlanner.ExcludeList) DataCenterVO(com.cloud.dc.DataCenterVO) DataCenterDeployment(com.cloud.deploy.DataCenterDeployment) Ternary(com.cloud.utils.Ternary) VirtualMachineProfileImpl(com.cloud.vm.VirtualMachineProfileImpl) VMInstanceVO(com.cloud.vm.VMInstanceVO) Host(com.cloud.host.Host) DiskProfile(com.cloud.vm.DiskProfile) HostVO(com.cloud.host.HostVO) UserVmDetailVO(com.cloud.vm.UserVmDetailVO) ResourceObjectType(com.cloud.server.ResourceTag.ResourceObjectType) VlanType(com.cloud.dc.Vlan.VlanType) JoinType(com.cloud.utils.db.JoinBuilder.JoinType) ScopeType(com.cloud.storage.ScopeType) HypervisorType(com.cloud.hypervisor.Hypervisor.HypervisorType) Type(com.cloud.host.Host.Type) PermissionDeniedException(com.cloud.exception.PermissionDeniedException) VirtualMachineProfile(com.cloud.vm.VirtualMachineProfile)

Aggregations

DiskProfile (com.cloud.vm.DiskProfile)49 StoragePool (com.cloud.storage.StoragePool)26 CloudRuntimeException (com.cloud.utils.exception.CloudRuntimeException)18 StorageFilerTO (com.cloud.agent.api.to.StorageFilerTO)16 DataCenterDeployment (com.cloud.deploy.DataCenterDeployment)16 ExcludeList (com.cloud.deploy.DeploymentPlanner.ExcludeList)16 Test (org.junit.Test)16 Volume (com.cloud.storage.Volume)15 VirtualMachineProfile (com.cloud.vm.VirtualMachineProfile)14 Answer (com.cloud.agent.api.Answer)12 DiskOfferingVO (com.cloud.storage.DiskOfferingVO)12 ArrayList (java.util.ArrayList)12 StoragePoolAllocator (org.apache.cloudstack.engine.subsystem.api.storage.StoragePoolAllocator)12 CreateAnswer (com.cloud.agent.api.storage.CreateAnswer)11 StoragePoolVO (org.apache.cloudstack.storage.datastore.db.StoragePoolVO)11 Pair (com.cloud.utils.Pair)10 VolumeTO (com.cloud.agent.api.to.VolumeTO)9 VolumeVO (com.cloud.storage.VolumeVO)9 HashSet (java.util.HashSet)9 CreateCommand (com.cloud.agent.api.storage.CreateCommand)8