diff --git a/api/src/com/cloud/agent/manager/allocator/HostAllocator.java b/api/src/com/cloud/agent/manager/allocator/HostAllocator.java index 14525aa52de..f21455eeb31 100755 --- a/api/src/com/cloud/agent/manager/allocator/HostAllocator.java +++ b/api/src/com/cloud/agent/manager/allocator/HostAllocator.java @@ -38,7 +38,7 @@ public interface HostAllocator extends Adapter { /** * Determines which physical hosts are suitable to * allocate the guest virtual machines on - * + * * @param VirtualMachineProfile vmProfile * @param DeploymentPlan plan * @param GuestType type @@ -46,35 +46,57 @@ public interface HostAllocator extends Adapter { * @param int returnUpTo (use -1 to return all possible hosts) * @return List List of hosts that are suitable for VM allocation **/ - + public List allocateTo(VirtualMachineProfile vmProfile, DeploymentPlan plan, Type type, ExcludeList avoid, int returnUpTo); - + /** - * Determines which physical hosts are suitable to - * allocate the guest virtual machines on - * - * @param VirtualMachineProfile vmProfile - * @param DeploymentPlan plan - * @param GuestType type - * @param ExcludeList avoid - * @param int returnUpTo (use -1 to return all possible hosts) - * @param boolean considerReservedCapacity (default should be true, set to false if host capacity calculation should not look at reserved capacity) - * @return List List of hosts that are suitable for VM allocation - **/ - + * Determines which physical hosts are suitable to allocate the guest + * virtual machines on + * + * Allocators must set any other hosts not considered for allocation in the + * ExcludeList avoid. Thus the avoid set and the list of hosts suitable, + * together must cover the entire host set in the cluster. + * + * @param VirtualMachineProfile + * vmProfile + * @param DeploymentPlan + * plan + * @param GuestType + * type + * @param ExcludeList + * avoid + * @param int returnUpTo (use -1 to return all possible hosts) + * @param boolean considerReservedCapacity (default should be true, set to + * false if host capacity calculation should not look at reserved + * capacity) + * @return List List of hosts that are suitable for VM allocation + **/ + public List allocateTo(VirtualMachineProfile vmProfile, DeploymentPlan plan, Type type, ExcludeList avoid, int returnUpTo, boolean considerReservedCapacity); /** - * Determines which physical hosts are suitable to - * allocate the guest virtual machines on + * Determines which physical hosts are suitable to allocate the guest + * virtual machines on * - * @param VirtualMachineProfile vmProfile - * @param DeploymentPlan plan - * @param GuestType type - * @param ExcludeList avoid - * @param List hosts + * Allocators must set any other hosts not considered for allocation in the + * ExcludeList avoid. Thus the avoid set and the list of hosts suitable, + * together must cover the entire host set in the cluster. + * + * + * @param VirtualMachineProfile + * vmProfile + * @param DeploymentPlan + * plan + * @param GuestType + * type + * @param ExcludeList + * avoid + * @param List + * hosts * @param int returnUpTo (use -1 to return all possible hosts) - * @param boolean considerReservedCapacity (default should be true, set to false if host capacity calculation should not look at reserved capacity) + * @param boolean considerReservedCapacity (default should be true, set to + * false if host capacity calculation should not look at reserved + * capacity) * @return List List of hosts that are suitable for VM allocation **/ public List allocateTo(VirtualMachineProfile vmProfile, DeploymentPlan plan, Type type, ExcludeList avoid, List hosts, diff --git a/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/StoragePoolAllocator.java b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/StoragePoolAllocator.java index 54808c195c5..e8ade44f475 100644 --- a/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/StoragePoolAllocator.java +++ b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/StoragePoolAllocator.java @@ -30,6 +30,11 @@ import com.cloud.vm.VirtualMachineProfile; public interface StoragePoolAllocator extends Adapter { /** * Determines which storage pools are suitable for the guest virtual machine + * and returns a list of pools suitable. + * + * Allocators must set any other pools not considered for allocation in the + * ExcludeList avoid. Thus the avoid set and the list of pools suitable, + * together must cover the entire pool set in the cluster. * * @param DiskProfile * dskCh diff --git a/server/src/com/cloud/deploy/DeploymentPlanningManagerImpl.java b/server/src/com/cloud/deploy/DeploymentPlanningManagerImpl.java index e79e8e3883f..f268957636f 100644 --- a/server/src/com/cloud/deploy/DeploymentPlanningManagerImpl.java +++ b/server/src/com/cloud/deploy/DeploymentPlanningManagerImpl.java @@ -864,6 +864,7 @@ public class DeploymentPlanningManagerImpl extends ManagerBase implements Deploy DataCenterDeployment potentialPlan = new DataCenterDeployment(plan.getDataCenterId(), clusterVO.getPodId(), clusterVO.getId(), null, plan.getPoolId(), null, plan.getReservationContext()); + // find suitable hosts under this cluster, need as many hosts as we // get. List suitableHosts = findSuitableHosts(vmProfile, potentialPlan, avoid, HostAllocator.RETURN_UPTO_ALL); @@ -906,7 +907,7 @@ public class DeploymentPlanningManagerImpl extends ManagerBase implements Deploy s_logger.debug("No suitable hosts found under this Cluster: " + clusterId); } - if (canAvoidCluster(clusterVO, avoid, PlannerAvoidOutput)) { + if (canAvoidCluster(clusterVO, avoid, PlannerAvoidOutput, vmProfile)) { avoid.addCluster(clusterVO.getId()); } } @@ -914,7 +915,8 @@ public class DeploymentPlanningManagerImpl extends ManagerBase implements Deploy return null; } - private boolean canAvoidCluster(Cluster clusterVO, ExcludeList avoids, ExcludeList plannerAvoidOutput) { + private boolean canAvoidCluster(Cluster clusterVO, ExcludeList avoids, ExcludeList plannerAvoidOutput, + VirtualMachineProfile vmProfile) { ExcludeList allocatorAvoidOutput = new ExcludeList(avoids.getDataCentersToAvoid(), avoids.getPodsToAvoid(), avoids.getClustersToAvoid(), avoids.getHostsToAvoid(), avoids.getPoolsToAvoid()); @@ -938,26 +940,27 @@ public class DeploymentPlanningManagerImpl extends ManagerBase implements Deploy } } + // all hosts in avoid set, avoid the cluster. Otherwise check the pools + if (avoidAllHosts) { + return true; + } + // Cluster can be put in avoid set in following scenarios: // 1. If storage allocators haven't put any pools in avoid set means either no pools in cluster - // or pools not suitable for the allocators to handle. + // or pools not suitable for the allocators to handle or there is no + // linkage of any suitable host to any of the pools in cluster // 2. If all 'shared' or 'local' pools are in avoid set if (allocatorAvoidOutput.getPoolsToAvoid() != null && !allocatorAvoidOutput.getPoolsToAvoid().isEmpty()) { - // check shared pools - List allPoolsInCluster = _storagePoolDao.findPoolsByTags(clusterVO.getDataCenterId(), - clusterVO.getPodId(), clusterVO.getId(), null); - for (StoragePoolVO pool : allPoolsInCluster) { - if (!allocatorAvoidOutput.shouldAvoid(pool)) { - // there's some pool in the cluster that is not yet in avoid set - avoidAllPools = false; - break; - } - } - if (avoidAllPools) { - // check local pools - List allLocalPoolsInCluster = _storagePoolDao.findLocalStoragePoolsByTags(clusterVO.getDataCenterId(), + + Pair storageRequirements = findVMStorageRequirements(vmProfile); + boolean vmRequiresSharedStorage = storageRequirements.first(); + boolean vmRequiresLocalStorege = storageRequirements.second(); + + if (vmRequiresSharedStorage) { + // check shared pools + List allPoolsInCluster = _storagePoolDao.findPoolsByTags(clusterVO.getDataCenterId(), clusterVO.getPodId(), clusterVO.getId(), null); - for (StoragePoolVO pool : allLocalPoolsInCluster) { + for (StoragePoolVO pool : allPoolsInCluster) { if (!allocatorAvoidOutput.shouldAvoid(pool)) { // there's some pool in the cluster that is not yet in avoid set avoidAllPools = false; @@ -965,6 +968,20 @@ public class DeploymentPlanningManagerImpl extends ManagerBase implements Deploy } } } + + if (vmRequiresLocalStorege) { + // check local pools + List allLocalPoolsInCluster = _storagePoolDao.findLocalStoragePoolsByTags( + clusterVO.getDataCenterId(), clusterVO.getPodId(), clusterVO.getId(), null); + for (StoragePoolVO pool : allLocalPoolsInCluster) { + if (!allocatorAvoidOutput.shouldAvoid(pool)) { + // there's some pool in the cluster that is not yet + // in avoid set + avoidAllPools = false; + break; + } + } + } } if (avoidAllHosts || avoidAllPools) { @@ -973,6 +990,27 @@ public class DeploymentPlanningManagerImpl extends ManagerBase implements Deploy return false; } + private Pair findVMStorageRequirements(VirtualMachineProfile vmProfile) { + + boolean requiresShared = false, requiresLocal = false; + + List volumesTobeCreated = _volsDao.findUsableVolumesForInstance(vmProfile.getId()); + + // for each volume find whether shared or local pool is required + for (VolumeVO toBeCreated : volumesTobeCreated) { + DiskOfferingVO diskOffering = _diskOfferingDao.findById(toBeCreated.getDiskOfferingId()); + + if (diskOffering != null) { + if (diskOffering.getUseLocalStorage()) { + requiresLocal = true; + } else { + requiresShared = true; + } + } + } + + return new Pair(requiresShared, requiresLocal); + } protected Pair> findPotentialDeploymentResources(List suitableHosts, Map> suitableVolumeStoragePools, ExcludeList avoid, DeploymentPlanner.PlannerResourceUsage resourceUsageRequired) {