package org.zstack.compute.allocator; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.transaction.annotation.Transactional; import org.zstack.core.cloudbus.CloudBus; import org.zstack.core.cloudbus.MessageSafe; import org.zstack.core.componentloader.PluginRegistry; import org.zstack.core.db.DatabaseFacade; import org.zstack.core.db.SimpleQuery; import org.zstack.core.db.SimpleQuery.Op; import org.zstack.core.errorcode.ErrorFacade; import org.zstack.header.AbstractService; import org.zstack.header.allocator.*; import org.zstack.header.cluster.ReportHostCapacityMessage; import org.zstack.header.core.ReturnValueCompletion; import org.zstack.header.core.workflow.Flow; import org.zstack.header.core.workflow.FlowRollback; import org.zstack.header.core.workflow.FlowTrigger; import org.zstack.header.errorcode.ErrorCode; import org.zstack.header.exception.CloudRuntimeException; import org.zstack.header.host.*; import org.zstack.header.image.APIGetCandidateBackupStorageForCreatingImageMsg; import org.zstack.header.image.APIGetCandidateBackupStorageForCreatingImageReply; import org.zstack.header.message.APIMessage; import org.zstack.header.message.Message; import org.zstack.header.message.MessageReply; import org.zstack.header.storage.backup.BackupStorageInventory; import org.zstack.header.storage.backup.BackupStorageState; import org.zstack.header.storage.backup.BackupStorageStatus; import org.zstack.header.storage.backup.BackupStorageVO; import org.zstack.header.storage.primary.PrimaryStorageVO; import org.zstack.header.vm.VmAbnormalLifeCycleExtensionPoint; import org.zstack.header.vm.VmAbnormalLifeCycleStruct; import org.zstack.header.vm.VmAbnormalLifeCycleStruct.VmAbnormalLifeCycleOperation; import org.zstack.header.vm.VmInstanceState; import org.zstack.utils.CollectionUtils; import org.zstack.utils.Utils; import org.zstack.utils.function.Function; import org.zstack.utils.logging.CLogger; import static org.zstack.core.Platform.operr; import javax.persistence.Tuple; import javax.persistence.TypedQuery; import java.text.DecimalFormat; import java.util.*; import java.util.concurrent.Callable; import static org.zstack.utils.CollectionDSL.list; public class HostAllocatorManagerImpl extends AbstractService implements HostAllocatorManager, VmAbnormalLifeCycleExtensionPoint { private static final CLogger logger = Utils.getLogger(HostAllocatorManagerImpl.class); private Map<String, HostAllocatorStrategyFactory> factories = Collections.synchronizedMap(new HashMap<String, HostAllocatorStrategyFactory>()); private Map<String, List<String>> backupStoragePrimaryStorageMetrics; private Map<String, List<String>> primaryStorageBackupStorageMetrics = new HashMap<>(); @Autowired private CloudBus bus; @Autowired private DatabaseFacade dbf; @Autowired private PluginRegistry pluginRgty; @Autowired private HostCapacityReserveManager reserveMgr; @Autowired private HostCapacityOverProvisioningManager ratioMgr; @Autowired private HostCpuOverProvisioningManager cpuRatioMgr; @Autowired private ErrorFacade errf; @Override @MessageSafe public void handleMessage(Message msg) { if (msg instanceof APIMessage) { handleApiMessage((APIMessage) msg); } else { handleLocalMessage(msg); } } private void handleLocalMessage(Message msg) { if (msg instanceof AllocateHostMsg) { handle((AllocateHostMsg) msg); } else if (msg instanceof ReportHostCapacityMessage) { handle((ReportHostCapacityMessage) msg); } else if (msg instanceof ReturnHostCapacityMsg) { handle((ReturnHostCapacityMsg) msg); } else if (msg instanceof RecalculateHostCapacityMsg) { handle((RecalculateHostCapacityMsg) msg); } else { bus.dealWithUnknownMessage(msg); } } @Transactional(readOnly = true) private void handle(APIGetCandidateBackupStorageForCreatingImageMsg msg) { PrimaryStorageVO ps; if (msg.getVolumeUuid() != null) { String sql = "select ps from PrimaryStorageVO ps, VolumeVO vol where ps.uuid = vol.primaryStorageUuid" + " and vol.uuid = :uuid"; TypedQuery<PrimaryStorageVO> q = dbf.getEntityManager().createQuery(sql, PrimaryStorageVO.class); q.setParameter("uuid", msg.getVolumeUuid()); List<PrimaryStorageVO> pss = q.getResultList(); ps = pss.isEmpty() ? null : pss.get(0); } else if (msg.getVolumeSnapshotUuid() != null) { String sql = "select ps from PrimaryStorageVO ps, VolumeSnapshotVO sp where ps.uuid = sp.primaryStorageUuid" + " and sp.uuid = :uuid"; TypedQuery<PrimaryStorageVO> q = dbf.getEntityManager().createQuery(sql, PrimaryStorageVO.class); q.setParameter("uuid", msg.getVolumeSnapshotUuid()); List<PrimaryStorageVO> pss = q.getResultList(); ps = pss.isEmpty() ? null : pss.get(0); } else { throw new CloudRuntimeException("cannot be there"); } if (ps == null) { throw new CloudRuntimeException("cannot find primary storage"); } List<String> backupStorageTypes = getBackupStorageTypesByPrimaryStorageTypeFromMetrics(ps.getType()); String sql = "select bs from BackupStorageVO bs, BackupStorageZoneRefVO ref, PrimaryStorageVO ps" + " where bs.uuid = ref.backupStorageUuid and ps.zoneUuid = ref.zoneUuid and ps.uuid = :psUuid" + " and bs.type in (:bsTypes) and bs.state = :bsState and bs.status = :bsStatus"; TypedQuery<BackupStorageVO> q = dbf.getEntityManager().createQuery(sql, BackupStorageVO.class); q.setParameter("psUuid", ps.getUuid()); q.setParameter("bsTypes", backupStorageTypes); q.setParameter("bsState", BackupStorageState.Enabled); q.setParameter("bsStatus", BackupStorageStatus.Connected); APIGetCandidateBackupStorageForCreatingImageReply reply = new APIGetCandidateBackupStorageForCreatingImageReply(); reply.setInventories(BackupStorageInventory.valueOf(q.getResultList())); bus.reply(msg, reply); } private void handle(RecalculateHostCapacityMsg msg) { final List<String> hostUuids = new ArrayList<>(); if (msg.getHostUuid() != null) { hostUuids.add(msg.getHostUuid()); } else { SimpleQuery<HostVO> q = dbf.createQuery(HostVO.class); q.select(HostVO_.uuid); q.add(HostVO_.zoneUuid, Op.EQ, msg.getZoneUuid()); hostUuids.addAll(q.listValue()); } if (hostUuids.isEmpty()) { return; } class HostUsedCpuMem { String hostUuid; Long usedMemory; Long usedCpu; } List<HostUsedCpuMem> hostUsedCpuMemList = new Callable<List<HostUsedCpuMem>>() { @Override @Transactional(readOnly = true) public List<HostUsedCpuMem> call() { String sql = "select sum(vm.memorySize), vm.hostUuid, sum(vm.cpuNum)" + " from VmInstanceVO vm" + " where vm.hostUuid in (:hostUuids)" + " and vm.state not in (:vmStates)" + " group by vm.hostUuid"; TypedQuery<Tuple> q = dbf.getEntityManager().createQuery(sql, Tuple.class); q.setParameter("hostUuids", hostUuids); q.setParameter("vmStates", list( VmInstanceState.Destroyed, VmInstanceState.Created, VmInstanceState.Destroying, VmInstanceState.Stopped)); List<Tuple> ts = q.getResultList(); List<HostUsedCpuMem> ret = new ArrayList<>(); for (Tuple t : ts) { HostUsedCpuMem s = new HostUsedCpuMem(); s.hostUuid = t.get(1, String.class); if (t.get(0, Long.class) == null) { continue; } s.usedMemory = ratioMgr.calculateMemoryByRatio(s.hostUuid, t.get(0, Long.class)); s.usedCpu = t.get(2, Long.class); ret.add(s); } return ret; } }.call(); List<String> hostHasVms = CollectionUtils.transformToList(hostUsedCpuMemList, new Function<String, HostUsedCpuMem>() { @Override public String call(HostUsedCpuMem arg) { return arg.hostUuid; } }); hostUuids.stream().filter(huuid -> !hostHasVms.contains(huuid)).forEach(huuid -> { HostUsedCpuMem s = new HostUsedCpuMem(); s.hostUuid = huuid; hostUsedCpuMemList.add(s); }); for (final HostUsedCpuMem s : hostUsedCpuMemList) { new HostCapacityUpdater(s.hostUuid).run(new HostCapacityUpdaterRunnable() { @Override public HostCapacityVO call(HostCapacityVO cap) { long before = cap.getAvailableMemory(); long avail = s.usedMemory == null ? cap.getTotalMemory() : cap.getTotalMemory() - s.usedMemory; cap.setAvailableMemory(avail); long totalCpu = cpuRatioMgr.calculateHostCpuByRatio(s.hostUuid, cap.getCpuNum()); long totalCpuBefore = cap.getTotalCpu(); cap.setTotalCpu(totalCpu); long beforeCpu = cap.getAvailableCpu(); long availCpu = s.usedCpu == null ? cap.getTotalCpu() : cap.getTotalCpu() - s.usedCpu; cap.setAvailableCpu(availCpu); logger.debug(String.format("re-calculated available capacity on the host[uuid:%s]:" + "\n[available memory] before: %s, now: %s" + "\n[total cpu] before: %s, now: %s" + "\n[available cpu] before: %s, now :%s", s.hostUuid, before, avail, totalCpuBefore, totalCpu, beforeCpu, availCpu)); return cap; } }); } } private void handle(ReturnHostCapacityMsg msg) { returnComputeResourceCapacity(msg.getHostUuid(), msg.getCpuCapacity(), msg.getMemoryCapacity()); } private void handle(ReportHostCapacityMessage msg) { long totalCpu = cpuRatioMgr.calculateHostCpuByRatio(msg.getHostUuid(), msg.getCpuNum()); long availMem = msg.getTotalMemory() - msg.getUsedMemory(); availMem = availMem > 0 ? availMem : 0; long availCpu = totalCpu - msg.getUsedCpu(); availCpu = availCpu > 0 ? availCpu : 0; HostCapacityVO vo = dbf.findByUuid(msg.getHostUuid(), HostCapacityVO.class); if (vo == null) { vo = new HostCapacityVO(); vo.setUuid(msg.getHostUuid()); vo.setTotalCpu(totalCpu); vo.setAvailableCpu(availCpu); vo.setTotalMemory(msg.getTotalMemory()); vo.setAvailableMemory(availMem); vo.setTotalPhysicalMemory(msg.getTotalMemory()); vo.setAvailablePhysicalMemory(availMem); vo.setCpuNum(msg.getCpuNum()); vo.setCpuSockets(msg.getCpuSockets()); HostCapacityStruct s = new HostCapacityStruct(); s.setCpuSockets(vo.getCpuSockets()); s.setCapacityVO(vo); s.setCpuNum(msg.getCpuNum()); s.setTotalCpu(totalCpu); s.setTotalMemory(msg.getTotalMemory()); s.setUsedCpu(msg.getUsedCpu()); s.setUsedMemory(msg.getUsedMemory()); s.setInit(true); for (ReportHostCapacityExtensionPoint ext : pluginRgty.getExtensionList(ReportHostCapacityExtensionPoint.class)) { vo = ext.reportHostCapacity(s); } dbf.persist(vo); } else { vo.setCpuNum(msg.getCpuNum()); vo.setTotalCpu(totalCpu); vo.setAvailableCpu(availCpu); vo.setTotalPhysicalMemory(msg.getTotalMemory()); vo.setAvailablePhysicalMemory(availMem); vo.setTotalMemory(msg.getTotalMemory()); vo.setCpuSockets(msg.getCpuSockets()); HostCapacityStruct s = new HostCapacityStruct(); s.setCapacityVO(vo); s.setCpuSockets(msg.getCpuSockets()); s.setTotalCpu(totalCpu); s.setTotalMemory(msg.getTotalMemory()); s.setUsedCpu(msg.getUsedCpu()); s.setUsedMemory(msg.getUsedMemory()); s.setInit(false); for (ReportHostCapacityExtensionPoint ext : pluginRgty.getExtensionList(ReportHostCapacityExtensionPoint.class)) { vo = ext.reportHostCapacity(s); } dbf.update(vo); } bus.reply(msg, new MessageReply()); } private void handle(final AllocateHostMsg msg) { HostAllocatorSpec spec = HostAllocatorSpec.fromAllocationMsg(msg); spec.setBackupStoragePrimaryStorageMetrics(backupStoragePrimaryStorageMetrics); String allocatorStrategyType = null; for (HostAllocatorStrategyExtensionPoint ext : pluginRgty.getExtensionList(HostAllocatorStrategyExtensionPoint.class)) { allocatorStrategyType = ext.getHostAllocatorStrategyName(spec); if (allocatorStrategyType != null) { logger.debug(String.format("%s returns allocator strategy type[%s]", ext.getClass(), allocatorStrategyType)); break; } } if (allocatorStrategyType == null) { allocatorStrategyType = msg.getAllocatorStrategy(); } HostAllocatorStrategyFactory factory = getHostAllocatorStrategyFactory(HostAllocatorStrategyType.valueOf(allocatorStrategyType)); HostAllocatorStrategy strategy = factory.getHostAllocatorStrategy(); factory.marshalSpec(spec, msg); if (msg.isDryRun()) { final AllocateHostDryRunReply reply = new AllocateHostDryRunReply(); strategy.dryRun(spec, new ReturnValueCompletion<List<HostInventory>>(msg) { @Override public void success(List<HostInventory> returnValue) { reply.setHosts(returnValue); bus.reply(msg, reply); } @Override public void fail(ErrorCode errorCode) { reply.setError(errorCode); bus.reply(msg, reply); } }); } else { final AllocateHostReply reply = new AllocateHostReply(); strategy.allocate(spec, new ReturnValueCompletion<HostInventory>(msg) { @Override public void success(HostInventory returnValue) { reply.setHost(returnValue); bus.reply(msg, reply); } @Override public void fail(ErrorCode errorCode) { reply.setError(errorCode); bus.reply(msg, reply); } }); } } private void handleApiMessage(APIMessage msg) { if (msg instanceof APIGetCpuMemoryCapacityMsg) { handle((APIGetCpuMemoryCapacityMsg) msg); } else if (msg instanceof APIGetHostAllocatorStrategiesMsg) { handle((APIGetHostAllocatorStrategiesMsg) msg); } else if (msg instanceof APIGetCandidateBackupStorageForCreatingImageMsg) { handle((APIGetCandidateBackupStorageForCreatingImageMsg) msg); } else { bus.dealWithUnknownMessage(msg); } } private void handle(APIGetHostAllocatorStrategiesMsg msg) { APIGetHostAllocatorStrategiesReply reply = new APIGetHostAllocatorStrategiesReply(); reply.setHostAllocatorStrategies(HostAllocatorStrategyType.getAllExposedTypeNames()); bus.reply(msg, reply); } private void handle(final APIGetCpuMemoryCapacityMsg msg) { APIGetCpuMemoryCapacityReply reply = new APIGetCpuMemoryCapacityReply(); Tuple ret = new Callable<Tuple>() { @Override @Transactional(readOnly = true) public Tuple call() { if (msg.getHostUuids() != null && !msg.getHostUuids().isEmpty()) { String sql = "select sum(hc.totalCpu), sum(hc.availableCpu), sum(hc.availableMemory), sum(hc.totalMemory)" + " from HostCapacityVO hc, HostVO host" + " where hc.uuid in (:hostUuids)" + " and hc.uuid = host.uuid" + " and host.state = :hstate" + " and host.status = :hstatus"; TypedQuery<Tuple> q = dbf.getEntityManager().createQuery(sql, Tuple.class); q.setParameter("hostUuids", msg.getHostUuids()); q.setParameter("hstate", HostState.Enabled); q.setParameter("hstatus", HostStatus.Connected); return q.getSingleResult(); } else if (msg.getClusterUuids() != null && !msg.getClusterUuids().isEmpty()) { String sql = "select sum(hc.totalCpu), sum(hc.availableCpu), sum(hc.availableMemory), sum(hc.totalMemory)" + " from HostCapacityVO hc, HostVO host" + " where hc.uuid = host.uuid" + " and host.clusterUuid in (:clusterUuids)" + " and host.state = :hstate" + " and host.status = :hstatus"; TypedQuery<Tuple> q = dbf.getEntityManager().createQuery(sql, Tuple.class); q.setParameter("clusterUuids", msg.getClusterUuids()); q.setParameter("hstate", HostState.Enabled); q.setParameter("hstatus", HostStatus.Connected); return q.getSingleResult(); } else if (msg.getZoneUuids() != null && !msg.getZoneUuids().isEmpty()) { String sql = "select sum(hc.totalCpu), sum(hc.availableCpu), sum(hc.availableMemory), sum(hc.totalMemory)" + " from HostCapacityVO hc, HostVO host" + " where hc.uuid = host.uuid" + " and host.zoneUuid in (:zoneUuids)" + " and host.state = :hstate" + " and host.status = :hstatus"; TypedQuery<Tuple> q = dbf.getEntityManager().createQuery(sql, Tuple.class); q.setParameter("zoneUuids", msg.getZoneUuids()); q.setParameter("hstate", HostState.Enabled); q.setParameter("hstatus", HostStatus.Connected); return q.getSingleResult(); } throw new CloudRuntimeException("should not be here"); } }.call(); long totalCpu = ret.get(0, Long.class) == null ? 0 : ret.get(0, Long.class); long availCpu = ret.get(1, Long.class) == null ? 0 : ret.get(1, Long.class); long availMemory = ret.get(2, Long.class) == null ? 0 : ret.get(2, Long.class); long totalMemory = ret.get(3, Long.class) == null ? 0 : ret.get(3, Long.class); ReservedHostCapacity rc; if (msg.getHostUuids() != null && !msg.getHostUuids().isEmpty()) { rc = reserveMgr.getReservedHostCapacityByHosts(msg.getHostUuids()); } else if (msg.getClusterUuids() != null && !msg.getClusterUuids().isEmpty()) { rc = reserveMgr.getReservedHostCapacityByClusters(msg.getClusterUuids()); } else if (msg.getZoneUuids() != null && !msg.getZoneUuids().isEmpty()) { rc = reserveMgr.getReservedHostCapacityByZones(msg.getZoneUuids()); } else { throw new CloudRuntimeException("should not be here"); } availMemory = availMemory - rc.getReservedMemoryCapacity(); availMemory = availMemory > 0 ? availMemory : 0; reply.setTotalCpu(totalCpu); reply.setTotalMemory(totalMemory); reply.setAvailableCpu(availCpu); reply.setAvailableMemory(availMemory); bus.reply(msg, reply); } @Override public String getId() { return bus.makeLocalServiceId(HostAllocatorConstant.SERVICE_ID); } private void populateHostAllocatorStrategyFactory() { for (HostAllocatorStrategyFactory ext : pluginRgty.getExtensionList(HostAllocatorStrategyFactory.class)) { HostAllocatorStrategyFactory old = factories.get(ext.getHostAllocatorStrategyType().toString()); if (old != null) { throw new CloudRuntimeException(String.format("duplicate HostAllocatorStrategyFactory[%s, %s] for type[%s]", old.getClass().getName(), ext.getClass().getName(), ext.getHostAllocatorStrategy())); } factories.put(ext.getHostAllocatorStrategyType().toString(), ext); } } @Override public boolean start() { populateHostAllocatorStrategyFactory(); populatePrimaryStorageBackupStorageMetrics(); return true; } private void populatePrimaryStorageBackupStorageMetrics() { for (Map.Entry<String, List<String>> e : backupStoragePrimaryStorageMetrics.entrySet()) { String bsType = e.getKey(); List<String> psTypes = e.getValue(); for (String psType : psTypes) { List<String> bsTypes = primaryStorageBackupStorageMetrics.get(psType); if (bsTypes == null) { bsTypes = new ArrayList<>(); primaryStorageBackupStorageMetrics.put(psType, bsTypes); } bsTypes.add(bsType); } } } @Override public boolean stop() { return true; } @Override public HostAllocatorStrategyFactory getHostAllocatorStrategyFactory(HostAllocatorStrategyType type) { HostAllocatorStrategyFactory factory = factories.get(type.toString()); if (factory == null) { throw new CloudRuntimeException(String.format("Unable to find HostAllocatorStrategyFactory with type[%s]", type)); } return factory; } @Override public void returnComputeResourceCapacity(final String hostUuid, final long cpu, final long memory) { new HostCapacityUpdater(hostUuid).run(new HostCapacityUpdaterRunnable() { @Override public HostCapacityVO call(HostCapacityVO cap) { { long availCpu = cap.getAvailableCpu() + cpu; availCpu = availCpu > cap.getTotalCpu() ? cap.getTotalCpu() : availCpu; /* if (availCpu > cap.getTotalCpu()) { throw new CloudRuntimeException(String.format("invalid cpu capacity of the host[uuid:%s], available cpu[%s]" + " is larger than the total cpu[%s]", hostUuid, availCpu, cap.getTotalCpu())); } */ cap.setAvailableCpu(availCpu); } { long deltaMemory = ratioMgr.calculateMemoryByRatio(hostUuid, memory); long availMemory = cap.getAvailableMemory() + deltaMemory; if (availMemory > cap.getTotalMemory()) { throw new CloudRuntimeException( String.format("invalid memory capacity of host[uuid:%s]," + " available memory[%s] is greater than total memory[%s]." + " Available Memory before is [%s], Delta Memory is [%s].", hostUuid, new DecimalFormat(",###").format(availMemory), new DecimalFormat(",###").format(cap.getTotalMemory()), new DecimalFormat(",###").format(cap.getAvailableMemory()), new DecimalFormat(",###").format(deltaMemory) ) ); } cap.setAvailableMemory(availMemory); } return cap; } }); } @Override public Flow createVmAbnormalLifeCycleHandlingFlow(final VmAbnormalLifeCycleStruct struct) { return new Flow() { String __name__ = "allocate-host-capacity"; VmAbnormalLifeCycleOperation operation = struct.getOperation(); Runnable rollback; @Override public void run(FlowTrigger trigger, Map data) { if (operation == VmAbnormalLifeCycleOperation.VmRunningOnTheHost) { vmRunningOnHost(trigger); } else if (operation == VmAbnormalLifeCycleOperation.VmMigrateToAnotherHost) { vmMigrateToAnotherHost(trigger); } else if (operation == VmAbnormalLifeCycleOperation.VmRunningFromIntermediateState) { vmRunningFromIntermediateState(trigger); } else if (operation == VmAbnormalLifeCycleOperation.VmStoppedOnTheSameHost) { vmStoppedOnTheSameHost(trigger); } else if (operation == VmAbnormalLifeCycleOperation.VmRunningFromUnknownStateHostChanged) { vmRunningFromUnknownStateHostChanged(trigger); } else { trigger.next(); } } private void vmRunningFromUnknownStateHostChanged(FlowTrigger trigger) { // resync the capacity on the current host resyncHostCapacity(); trigger.next(); } private void resyncHostCapacity() { //TODO } private void vmStoppedOnTheSameHost(FlowTrigger trigger) { // return the capacity to the current host returnComputeCapacity(struct.getCurrentHostUuid()); rollback = new Runnable() { @Override public void run() { long cpu = struct.getVmInstance().getCpuNum(); new HostAllocatorChain().reserveCapacity( struct.getCurrentHostUuid(), cpu, struct.getVmInstance().getMemorySize()); } }; trigger.next(); } private void returnComputeCapacity(String hostUuid) { ReturnHostCapacityMsg msg = new ReturnHostCapacityMsg(); msg.setCpuCapacity(struct.getVmInstance().getCpuNum()); msg.setMemoryCapacity(struct.getVmInstance().getMemorySize()); msg.setHostUuid(hostUuid); bus.makeLocalServiceId(msg, HostAllocatorConstant.SERVICE_ID); bus.send(msg); } private void vmRunningFromIntermediateState(FlowTrigger trigger) { // resync the capacity on the current host resyncHostCapacity(); trigger.next(); } private void vmMigrateToAnotherHost(FlowTrigger trigger) { // allocate the capacity on the current host // return the capacity to the original host try { final long cpu = struct.getVmInstance().getCpuNum(); new HostAllocatorChain().reserveCapacity( struct.getCurrentHostUuid(), cpu, struct.getVmInstance().getMemorySize()); returnComputeCapacity(struct.getOriginalHostUuid()); rollback = new Runnable() { @Override public void run() { returnComputeCapacity(struct.getCurrentHostUuid()); new HostAllocatorChain().reserveCapacity( struct.getOriginalHostUuid(), cpu, struct.getVmInstance().getMemorySize()); } }; trigger.next(); } catch (UnableToReserveHostCapacityException e) { trigger.fail(operr(e.getMessage())); } } private void vmRunningOnHost(FlowTrigger trigger) { // allocate capacity on the current host try { long cpu = struct.getVmInstance().getCpuNum(); new HostAllocatorChain().reserveCapacity( struct.getCurrentHostUuid(), cpu, struct.getVmInstance().getMemorySize()); rollback = new Runnable() { @Override public void run() { returnComputeCapacity(struct.getCurrentHostUuid()); } }; trigger.next(); } catch (UnableToReserveHostCapacityException e) { trigger.fail(operr(e.getMessage())); } } @Override public void rollback(FlowRollback trigger, Map data) { if (rollback != null) { rollback.run(); } trigger.rollback(); } }; } public void setBackupStoragePrimaryStorageMetrics(Map<String, List<String>> backupStoragePrimaryStorageMetrics) { this.backupStoragePrimaryStorageMetrics = backupStoragePrimaryStorageMetrics; } public Map<String, List<String>> getBackupStoragePrimaryStorageMetrics() { return backupStoragePrimaryStorageMetrics; } @Override public List<String> getPrimaryStorageTypesByBackupStorageTypeFromMetrics(String backupStorageType) { List<String> psTypes = backupStoragePrimaryStorageMetrics.get(backupStorageType); if (psTypes == null) { throw new CloudRuntimeException(String.format("cannot find supported primary storage types by the backup storage type[%s]", backupStorageType)); } return psTypes; } @Override public List<String> getBackupStorageTypesByPrimaryStorageTypeFromMetrics(String psType) { List<String> bsTypes = primaryStorageBackupStorageMetrics.get(psType); if (bsTypes == null) { throw new CloudRuntimeException(String.format("cannot find supported backup storage types by the primary storage type[%s]", psType)); } return bsTypes; } }