@Override public Flow marshalVmOperationFlow( String previousFlowName, String nextFlowName, FlowChain chain, VmInstanceSpec spec) { if (VmAllocatePrimaryStorageFlow.class.getName().equals(nextFlowName)) { if (spec.getCurrentVmOperation() == VmOperation.NewCreate) { if (getLocalStorageInCluster(spec.getDestHost().getClusterUuid()) != null) { return new LocalStorageAllocateCapacityFlow(); } } } else if (spec.getCurrentVmOperation() == VmOperation.AttachVolume) { VolumeInventory volume = spec.getDestDataVolumes().get(0); if (VolumeStatus.NotInstantiated.toString().equals(volume.getStatus()) && VmAllocatePrimaryStorageForAttachingDiskFlow.class.getName().equals(nextFlowName)) { if (isRootVolumeOnLocalStorage(spec.getVmInventory().getRootVolumeUuid())) { return new LocalStorageAllocateCapacityForAttachingVolumeFlow(); } } } else if (spec.getCurrentVmOperation() == VmOperation.Migrate && isRootVolumeOnLocalStorage(spec.getVmInventory().getRootVolumeUuid()) && VmMigrateOnHypervisorFlow.class.getName().equals(nextFlowName)) { if (KVMConstant.KVM_HYPERVISOR_TYPE.equals(spec.getVmInventory().getHypervisorType())) { return new LocalStorageKvmMigrateVmFlow(); } else { throw new OperationFailureException( errf.stringToOperationError( String.format( "local storage doesn't support live migration for hypervisor[%s]", spec.getVmInventory().getHypervisorType()))); } } return null; }
@Override public void preRecoverDataVolume(VolumeInventory vol) { if (vol.getPrimaryStorageUuid() == null) { return; } SimpleQuery<PrimaryStorageVO> q = dbf.createQuery(PrimaryStorageVO.class); q.select(PrimaryStorageVO_.type); q.add(PrimaryStorageVO_.uuid, Op.EQ, vol.getPrimaryStorageUuid()); String type = q.findValue(); if (!LocalStorageConstants.LOCAL_STORAGE_TYPE.equals(type)) { return; } SimpleQuery<LocalStorageResourceRefVO> rq = dbf.createQuery(LocalStorageResourceRefVO.class); rq.add(LocalStorageResourceRefVO_.resourceUuid, Op.EQ, vol.getUuid()); rq.add(LocalStorageResourceRefVO_.resourceType, Op.EQ, VolumeVO.class.getSimpleName()); if (!rq.isExists()) { throw new OperationFailureException( errf.stringToOperationError( String.format( "the data volume[name:%s, uuid:%s] is on the local storage[uuid:%s]; however," + "the host on which the data volume is has been deleted. Unable to recover this volume", vol.getName(), vol.getUuid(), vol.getPrimaryStorageUuid()))); } }
@Override public void preAttachVolume(VmInstanceInventory vm, final VolumeInventory volume) { SimpleQuery<LocalStorageResourceRefVO> q = dbf.createQuery(LocalStorageResourceRefVO.class); q.add( LocalStorageResourceRefVO_.resourceUuid, Op.IN, list(vm.getRootVolumeUuid(), volume.getUuid())); q.groupBy(LocalStorageResourceRefVO_.hostUuid); long count = q.count(); if (count < 2) { return; } q = dbf.createQuery(LocalStorageResourceRefVO.class); q.select(LocalStorageResourceRefVO_.hostUuid); q.add(LocalStorageResourceRefVO_.resourceUuid, Op.EQ, vm.getRootVolumeUuid()); String rootHost = q.findValue(); q = dbf.createQuery(LocalStorageResourceRefVO.class); q.select(LocalStorageResourceRefVO_.hostUuid); q.add(LocalStorageResourceRefVO_.resourceUuid, Op.EQ, volume.getUuid()); String dataHost = q.findValue(); if (!rootHost.equals(dataHost)) { throw new OperationFailureException( errf.stringToOperationError( String.format( "cannot attach the data volume[uuid:%s] to the vm[uuid:%s]. Both vm's root volume and the data volume are" + " on local primary storage, but they are on different hosts. The root volume[uuid:%s] is on the host[uuid:%s] but the data volume[uuid: %s]" + " is on the host[uuid: %s]", volume.getUuid(), vm.getUuid(), vm.getRootVolumeUuid(), rootHost, volume.getUuid(), dataHost))); } }
@Override @Transactional(readOnly = true) public List<VmInstanceVO> returnAttachableVms( VolumeInventory vol, List<VmInstanceVO> candidates) { String sql = "select ref.hostUuid from LocalStorageResourceRefVO ref where ref.resourceUuid = :uuid" + " and ref.resourceType = :rtype"; TypedQuery<String> q = dbf.getEntityManager().createQuery(sql, String.class); q.setParameter("uuid", vol.getUuid()); q.setParameter("rtype", VolumeVO.class.getSimpleName()); List<String> ret = q.getResultList(); if (ret.isEmpty()) { return candidates; } String hostUuid = ret.get(0); List<String> vmRootVolumeUuids = CollectionUtils.transformToList( candidates, new Function<String, VmInstanceVO>() { @Override public String call(VmInstanceVO arg) { return arg.getRootVolumeUuid(); } }); sql = "select ref.resourceUuid from LocalStorageResourceRefVO ref where ref.hostUuid = :huuid" + " and ref.resourceUuid in (:rootVolumeUuids) and ref.resourceType = :rtype"; q = dbf.getEntityManager().createQuery(sql, String.class); q.setParameter("huuid", hostUuid); q.setParameter("rootVolumeUuids", vmRootVolumeUuids); q.setParameter("rtype", VolumeVO.class.getSimpleName()); final List<String> toInclude = q.getResultList(); candidates = CollectionUtils.transformToList( candidates, new Function<VmInstanceVO, VmInstanceVO>() { @Override public VmInstanceVO call(VmInstanceVO arg) { return toInclude.contains(arg.getRootVolumeUuid()) ? arg : null; } }); return candidates; }