From 4ad9ac5e71a42b09cd699ee9aa84e254aa7b8b64 Mon Sep 17 00:00:00 2001 From: prachi Date: Thu, 8 Sep 2011 18:07:52 -0700 Subject: [PATCH] Bug 11200 - maximum number of guests per host Changes: To make sure migration does not attempt to pick a host that has running VMs more than the max guest VM's limit: - Changed manual migration to call host allocators to return a list of hosts suitable for migration. Host allocators check for the max guest VM limit. - Earlier we returned hosts with enough capacity but now Host Allocators make other checks along with capacity. So the list of hosts returned are hosts that have enough capacity AND satisfy all other conditions like host tags, max guests limit etc. Or in other words Allocators dont return the hosts that dont satisfy all conditions even if they have capacity. -Therefore, now we mark the list of hosts returned for manual migration as 'suitable' hosts instead of 'hasenoughCapacity' in the HostResponse. - HA migration already calls allocators, so no change is needed there. --- .../com/cloud/api/commands/ListHostsCmd.java | 14 +++--- .../com/cloud/api/response/HostResponse.java | 11 ++++ .../com/cloud/server/ManagementService.java | 6 +-- .../xen/resource/CitrixResourceBase.java | 3 ++ .../manager/allocator/HostAllocator.java | 19 +++++++ .../allocator/impl/FirstFitAllocator.java | 17 ++++--- .../allocator/impl/RandomAllocator.java | 17 ++++--- .../allocator/impl/TestingAllocator.java | 8 ++- .../com/cloud/capacity/CapacityManager.java | 12 ++++- .../cloud/capacity/CapacityManagerImpl.java | 27 +++++++--- .../com/cloud/deploy/BareMetalPlanner.java | 4 +- .../src/com/cloud/deploy/FirstFitPlanner.java | 11 ++-- .../dao/HypervisorCapabilitiesDaoImpl.java | 23 +++++++-- .../cloud/server/ManagementServerImpl.java | 50 +++++++++++++------ .../allocator/StoragePoolAllocator.java | 4 +- .../cloud/vm/VirtualMachineManagerImpl.java | 4 +- 16 files changed, 166 insertions(+), 64 deletions(-) diff --git a/api/src/com/cloud/api/commands/ListHostsCmd.java b/api/src/com/cloud/api/commands/ListHostsCmd.java index c84aecd13e2..c52df4cafc0 100644 --- a/api/src/com/cloud/api/commands/ListHostsCmd.java +++ b/api/src/com/cloud/api/commands/ListHostsCmd.java @@ -127,16 +127,16 @@ public class ListHostsCmd extends BaseListCmd { @Override public void execute(){ List result = new ArrayList(); - List hostIdsWithCapacity = new ArrayList(); + List hostsWithCapacity = new ArrayList(); if(getVirtualMachineId() != null){ UserVm userVm = _userVmService.getUserVm(getVirtualMachineId()); if (userVm == null) { throw new InvalidParameterValueException("Unable to find the VM by id=" + getVirtualMachineId()); } - Pair, List> hostsForMigration = _mgr.listHostsForMigrationOfVM(userVm, this.getStartIndex(), this.getPageSizeVal()); + Pair, List> hostsForMigration = _mgr.listHostsForMigrationOfVM(userVm, this.getStartIndex(), this.getPageSizeVal()); result = hostsForMigration.first(); - hostIdsWithCapacity = hostsForMigration.second(); + hostsWithCapacity = hostsForMigration.second(); }else{ result = _mgr.searchForServers(this); } @@ -145,11 +145,11 @@ public class ListHostsCmd extends BaseListCmd { List hostResponses = new ArrayList(); for (Host host : result) { HostResponse hostResponse = _responseGenerator.createHostResponse(host); - Boolean hasEnoughCapacity = false; - if(hostIdsWithCapacity.contains(host.getId())){ - hasEnoughCapacity = true; + Boolean suitableForMigration = false; + if(hostsWithCapacity.contains(host)){ + suitableForMigration = true; } - hostResponse.setHasEnoughCapacity(hasEnoughCapacity); + hostResponse.setSuitableForMigration(suitableForMigration); hostResponse.setObjectName("host"); hostResponses.add(hostResponse); } diff --git a/api/src/com/cloud/api/response/HostResponse.java b/api/src/com/cloud/api/response/HostResponse.java index 5d6b06a350d..c7526a11824 100755 --- a/api/src/com/cloud/api/response/HostResponse.java +++ b/api/src/com/cloud/api/response/HostResponse.java @@ -150,6 +150,9 @@ public class HostResponse extends BaseResponse { @SerializedName("hasEnoughCapacity") @Param(description="true if this host has enough CPU and RAM capacity to migrate a VM to it, false otherwise") private Boolean hasEnoughCapacity; + @SerializedName("suitableForMigration") @Param(description="true if this host is suitable(has enough capacity and satisfies all conditions like hosttags, max guests vm limit etc) to migrate a VM to it , false otherwise") + private Boolean suitableForMigration; + @SerializedName("allocationstate") @Param(description="the allocation state of the host") private String allocationState; @@ -485,6 +488,14 @@ public class HostResponse extends BaseResponse { public void setHasEnoughCapacity(Boolean hasEnoughCapacity) { this.hasEnoughCapacity = hasEnoughCapacity; } + + public Boolean isSuitableForMigration() { + return suitableForMigration; + } + + public void setSuitableForMigration(Boolean suitableForMigration) { + this.suitableForMigration = suitableForMigration; + } public String getAllocationState() { return allocationState; diff --git a/api/src/com/cloud/server/ManagementService.java b/api/src/com/cloud/server/ManagementService.java index 123f56597a2..e81a6e437d4 100755 --- a/api/src/com/cloud/server/ManagementService.java +++ b/api/src/com/cloud/server/ManagementService.java @@ -501,13 +501,13 @@ public interface ManagementService { /** * List hosts for migrating the given VM. The API returns list of all hosts in the VM's cluster minus the current host and - * also a list of hostIds that seem to have enough CPU and RAM capacity to host this VM. + * also a list of hosts that seem to have enough CPU and RAM capacity to host this VM. * * @param UserVm * vm The VM to migrate - * @return Pair, List> List of all Hosts in VM's cluster and list of HostIds with enough capacity + * @return Pair, List> List of all Hosts in VM's cluster and list of Hosts with enough capacity */ - Pair, List> listHostsForMigrationOfVM(UserVm vm, Long startIndex, Long pageSize); + Pair, List> listHostsForMigrationOfVM(UserVm vm, Long startIndex, Long pageSize); String[] listEventTypes(); diff --git a/core/src/com/cloud/hypervisor/xen/resource/CitrixResourceBase.java b/core/src/com/cloud/hypervisor/xen/resource/CitrixResourceBase.java index 2e4e93296d3..712b5e32ba3 100644 --- a/core/src/com/cloud/hypervisor/xen/resource/CitrixResourceBase.java +++ b/core/src/com/cloud/hypervisor/xen/resource/CitrixResourceBase.java @@ -4879,6 +4879,9 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe details.put("product_version", hr.softwareVersion.get("product_version")); if( hr.softwareVersion.get("product_version_text_short") != null ) { details.put("product_version_text_short", hr.softwareVersion.get("product_version_text_short")); + cmd.setHypervisorVersion(hr.softwareVersion.get("product_version_text_short")); + }else{ + cmd.setHypervisorVersion(hr.softwareVersion.get("product_version")); } if (_privateNetworkName != null) { details.put("private.network.device", _privateNetworkName); diff --git a/server/src/com/cloud/agent/manager/allocator/HostAllocator.java b/server/src/com/cloud/agent/manager/allocator/HostAllocator.java index 77828c0a1ad..1ee8a7dc765 100755 --- a/server/src/com/cloud/agent/manager/allocator/HostAllocator.java +++ b/server/src/com/cloud/agent/manager/allocator/HostAllocator.java @@ -18,6 +18,7 @@ package com.cloud.agent.manager.allocator; import java.util.List; + import com.cloud.deploy.DeploymentPlan; import com.cloud.deploy.DeploymentPlanner.ExcludeList; import com.cloud.host.Host; @@ -51,5 +52,23 @@ public interface HostAllocator extends Adapter { **/ 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 Type 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); + + + public static int RETURN_UPTO_ALL = -1; } diff --git a/server/src/com/cloud/agent/manager/allocator/impl/FirstFitAllocator.java b/server/src/com/cloud/agent/manager/allocator/impl/FirstFitAllocator.java index 201a8fc4b90..b591dcb8ff3 100755 --- a/server/src/com/cloud/agent/manager/allocator/impl/FirstFitAllocator.java +++ b/server/src/com/cloud/agent/manager/allocator/impl/FirstFitAllocator.java @@ -82,11 +82,17 @@ public class FirstFitAllocator implements HostAllocator { protected String _allocationAlgorithm = "random"; @Inject CapacityManager _capacityMgr; + @Override public List allocateTo(VirtualMachineProfile vmProfile, DeploymentPlan plan, Type type, ExcludeList avoid, int returnUpTo) { - - long dcId = plan.getDataCenterId(); + return allocateTo(vmProfile, plan, type, avoid, returnUpTo, true); + } + + @Override + public List allocateTo(VirtualMachineProfile vmProfile, DeploymentPlan plan, Type type, ExcludeList avoid, int returnUpTo, boolean considerReservedCapacity) { + + long dcId = plan.getDataCenterId(); Long podId = plan.getPodId(); Long clusterId = plan.getClusterId(); ServiceOffering offering = vmProfile.getServiceOffering(); @@ -150,10 +156,10 @@ public class FirstFitAllocator implements HostAllocator { } - return allocateTo(offering, template, avoid, clusterHosts, returnUpTo); + return allocateTo(offering, template, avoid, clusterHosts, returnUpTo, considerReservedCapacity); } - protected List allocateTo(ServiceOffering offering, VMTemplateVO template, ExcludeList avoid, List hosts, int returnUpTo) { + protected List allocateTo(ServiceOffering offering, VMTemplateVO template, ExcludeList avoid, List hosts, int returnUpTo, boolean considerReservedCapacity) { if (_allocationAlgorithm.equals("random")) { // Shuffle this so that we don't check the hosts in the same order. Collections.shuffle(hosts); @@ -208,7 +214,7 @@ public class FirstFitAllocator implements HostAllocator { boolean numCpusGood = host.getCpus().intValue() >= offering.getCpu(); int cpu_requested = offering.getCpu() * offering.getSpeed(); long ram_requested = offering.getRamSize() * 1024L * 1024L; - boolean hostHasCapacity = _capacityMgr.checkIfHostHasCapacity(host.getId(), cpu_requested, ram_requested, false, _factor); + boolean hostHasCapacity = _capacityMgr.checkIfHostHasCapacity(host.getId(), cpu_requested, ram_requested, false, _factor, considerReservedCapacity); if (numCpusGood && hostHasCapacity) { if (s_logger.isDebugEnabled()) { @@ -382,5 +388,4 @@ public class FirstFitAllocator implements HostAllocator { return true; } - } diff --git a/server/src/com/cloud/agent/manager/allocator/impl/RandomAllocator.java b/server/src/com/cloud/agent/manager/allocator/impl/RandomAllocator.java index f6a70d4bce8..72f889ec3de 100755 --- a/server/src/com/cloud/agent/manager/allocator/impl/RandomAllocator.java +++ b/server/src/com/cloud/agent/manager/allocator/impl/RandomAllocator.java @@ -21,22 +21,19 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Map; -import java.util.Set; import javax.ejb.Local; import org.apache.log4j.Logger; -import com.cloud.host.HostVO; -import com.cloud.host.Host.Type; + import com.cloud.agent.manager.allocator.HostAllocator; -import com.cloud.dc.DataCenterVO; -import com.cloud.dc.HostPodVO; import com.cloud.deploy.DeploymentPlan; import com.cloud.deploy.DeploymentPlanner.ExcludeList; import com.cloud.host.Host; +import com.cloud.host.Host.Type; +import com.cloud.host.HostVO; import com.cloud.host.dao.HostDao; import com.cloud.offering.ServiceOffering; -import com.cloud.storage.VMTemplateVO; import com.cloud.uservm.UserVm; import com.cloud.utils.component.ComponentLocator; import com.cloud.vm.VirtualMachine; @@ -50,7 +47,13 @@ public class RandomAllocator implements HostAllocator { @Override public List allocateTo(VirtualMachineProfile vmProfile, DeploymentPlan plan, Type type, - ExcludeList avoid, int returnUpTo) { + ExcludeList avoid, int returnUpTo) { + return allocateTo(vmProfile, plan, type, avoid, returnUpTo, true); + } + + @Override + public List allocateTo(VirtualMachineProfile vmProfile, DeploymentPlan plan, Type type, + ExcludeList avoid, int returnUpTo, boolean considerReservedCapacity) { long dcId = plan.getDataCenterId(); Long podId = plan.getPodId(); diff --git a/server/src/com/cloud/agent/manager/allocator/impl/TestingAllocator.java b/server/src/com/cloud/agent/manager/allocator/impl/TestingAllocator.java index 4b0f8e22287..02220ffd72e 100755 --- a/server/src/com/cloud/agent/manager/allocator/impl/TestingAllocator.java +++ b/server/src/com/cloud/agent/manager/allocator/impl/TestingAllocator.java @@ -49,7 +49,13 @@ public class TestingAllocator implements HostAllocator { @Override public List allocateTo(VirtualMachineProfile vmProfile, DeploymentPlan plan, Type type, - ExcludeList avoid, int returnUpTo) { + ExcludeList avoid, int returnUpTo) { + return allocateTo(vmProfile, plan, type, avoid, returnUpTo, true); + } + + @Override + public List allocateTo(VirtualMachineProfile vmProfile, DeploymentPlan plan, Type type, + ExcludeList avoid, int returnUpTo, boolean considerReservedCapacity) { List availableHosts = new ArrayList(); Host host = null; if (type == Host.Type.Routing && _routingHost != null) { diff --git a/server/src/com/cloud/capacity/CapacityManager.java b/server/src/com/cloud/capacity/CapacityManager.java index 0149599e19e..5edbd77d25b 100755 --- a/server/src/com/cloud/capacity/CapacityManager.java +++ b/server/src/com/cloud/capacity/CapacityManager.java @@ -32,7 +32,15 @@ public interface CapacityManager extends Manager { void allocateVmCapacity(VirtualMachine vm, boolean fromLastHost); - boolean checkIfHostHasCapacity(long hostId, Integer cpu, long ram, boolean checkFromReservedCapacity, float cpuOverprovisioningFactor); - + /** + * @param hostId Id of the host to check capacity + * @param cpu required CPU + * @param ram required RAM + * @param checkFromReservedCapacity set to true if ONLY reserved capacity of the host should be looked at + * @param cpuOverprovisioningFactor factor to apply to the actual host cpu + * @param considerReservedCapacity (default should be true, set to false if host capacity calculation should not look at reserved capacity at all) + */ + boolean checkIfHostHasCapacity(long hostId, Integer cpu, long ram, boolean checkFromReservedCapacity, float cpuOverprovisioningFactor, boolean considerReservedCapacity); + void updateCapacityForHost(HostVO host); } diff --git a/server/src/com/cloud/capacity/CapacityManagerImpl.java b/server/src/com/cloud/capacity/CapacityManagerImpl.java index c4e2bd767c9..31ec150d6c4 100755 --- a/server/src/com/cloud/capacity/CapacityManagerImpl.java +++ b/server/src/com/cloud/capacity/CapacityManagerImpl.java @@ -293,7 +293,7 @@ public class CapacityManagerImpl implements CapacityManager, StateListener _hostAllocators; - private static int RETURN_UPTO_ALL = -1; @Override public DeployDestination plan(VirtualMachineProfile vmProfile, @@ -144,7 +143,7 @@ public class FirstFitPlanner extends PlannerBase implements DeploymentPlanner { //search for storage under the zone, pod, cluster of the host. DataCenterDeployment lastPlan = new DataCenterDeployment(host.getDataCenterId(), host.getPodId(), host.getClusterId(), hostIdSpecified, plan.getPoolId()); - Pair>, List> result = findSuitablePoolsForVolumes(vmProfile, lastPlan, avoid, RETURN_UPTO_ALL); + Pair>, List> result = findSuitablePoolsForVolumes(vmProfile, lastPlan, avoid, HostAllocator.RETURN_UPTO_ALL); Map> suitableVolumeStoragePools = result.first(); List readyAndReusedVolumes = result.second(); @@ -179,12 +178,12 @@ public class FirstFitPlanner extends PlannerBase implements DeploymentPlanner { s_logger.debug("The last host of this VM cannot be found"); }else{ if (host.getStatus() == Status.Up && host.getHostAllocationState() == Host.HostAllocationState.Enabled) { - if(_capacityMgr.checkIfHostHasCapacity(host.getId(), cpu_requested, ram_requested, true, cpuOverprovisioningFactor)){ + if(_capacityMgr.checkIfHostHasCapacity(host.getId(), cpu_requested, ram_requested, true, cpuOverprovisioningFactor, true)){ s_logger.debug("The last host of this VM is UP and has enough capacity"); s_logger.debug("Now checking for suitable pools under zone: "+host.getDataCenterId() +", pod: "+ host.getPodId()+", cluster: "+ host.getClusterId()); //search for storage under the zone, pod, cluster of the last host. DataCenterDeployment lastPlan = new DataCenterDeployment(host.getDataCenterId(), host.getPodId(), host.getClusterId(), host.getId(), plan.getPoolId()); - Pair>, List> result = findSuitablePoolsForVolumes(vmProfile, lastPlan, avoid, RETURN_UPTO_ALL); + Pair>, List> result = findSuitablePoolsForVolumes(vmProfile, lastPlan, avoid, HostAllocator.RETURN_UPTO_ALL); Map> suitableVolumeStoragePools = result.first(); List readyAndReusedVolumes = result.second(); //choose the potential pool for this VM for this host @@ -362,7 +361,7 @@ public class FirstFitPlanner extends PlannerBase implements DeploymentPlanner { DataCenterDeployment potentialPlan = new DataCenterDeployment(plan.getDataCenterId(), clusterVO.getPodId(), clusterVO.getId(), null, plan.getPoolId()); //find suitable hosts under this cluster, need as many hosts as we get. - List suitableHosts = findSuitableHosts(vmProfile, potentialPlan, avoid, RETURN_UPTO_ALL); + List suitableHosts = findSuitableHosts(vmProfile, potentialPlan, avoid, HostAllocator.RETURN_UPTO_ALL); //if found suitable hosts in this cluster, find suitable storage pools for each volume of the VM if(suitableHosts != null && !suitableHosts.isEmpty()){ if (vmProfile.getHypervisorType() == HypervisorType.BareMetal) { @@ -374,7 +373,7 @@ public class FirstFitPlanner extends PlannerBase implements DeploymentPlanner { if (_allocationAlgorithm != null && _allocationAlgorithm.equalsIgnoreCase("random")) { Collections.shuffle(suitableHosts); } - Pair>, List> result = findSuitablePoolsForVolumes(vmProfile, potentialPlan, avoid, RETURN_UPTO_ALL); + Pair>, List> result = findSuitablePoolsForVolumes(vmProfile, potentialPlan, avoid, StoragePoolAllocator.RETURN_UPTO_ALL); Map> suitableVolumeStoragePools = result.first(); List readyAndReusedVolumes = result.second(); diff --git a/server/src/com/cloud/hypervisor/dao/HypervisorCapabilitiesDaoImpl.java b/server/src/com/cloud/hypervisor/dao/HypervisorCapabilitiesDaoImpl.java index a277547c137..79d76fcf4e1 100644 --- a/server/src/com/cloud/hypervisor/dao/HypervisorCapabilitiesDaoImpl.java +++ b/server/src/com/cloud/hypervisor/dao/HypervisorCapabilitiesDaoImpl.java @@ -22,6 +22,9 @@ public class HypervisorCapabilitiesDaoImpl extends GenericDaoBase HypervisorTypeAndVersionSearch; protected final GenericSearchBuilder MaxGuestLimitByHypervisorSearch; + //we insert a record for each hypervisor type with version 'default' to ensure we dont face errors in case hypervisor version is missing or does not match. + private static final String DEFAULT_VERSION = "default"; + protected HypervisorCapabilitiesDaoImpl() { HypervisorTypeSearch = createSearchBuilder(); HypervisorTypeSearch.and("hypervisorType", HypervisorTypeSearch.entity().getHypervisorType(), SearchCriteria.Op.EQ); @@ -58,15 +61,27 @@ public class HypervisorCapabilitiesDaoImpl extends GenericDaoBase sc = MaxGuestLimitByHypervisorSearch.create(); sc.setParameters("hypervisorType", hypervisorType); sc.setParameters("hypervisorVersion", hypervisorVersion); - result = customSearch(sc, null).get(0); + List limitList = customSearch(sc, null); + if(!limitList.isEmpty()){ + result = limitList.get(0); + }else{ + useDefault = true; + } }else{ - List capabilities = listAllByHypervisorType(hypervisorType); - if(!capabilities.isEmpty()){ - result = capabilities.get(0).getMaxGuestsLimit(); + useDefault = true; + } + if(useDefault){ + SearchCriteria sc = MaxGuestLimitByHypervisorSearch.create(); + sc.setParameters("hypervisorType", hypervisorType); + sc.setParameters("hypervisorVersion", DEFAULT_VERSION); + List limitList = customSearch(sc, null); + if(!limitList.isEmpty()){ + result = limitList.get(0); } } if(result == null){ diff --git a/server/src/com/cloud/server/ManagementServerImpl.java b/server/src/com/cloud/server/ManagementServerImpl.java index 561469ef596..0ebae8c614a 100755 --- a/server/src/com/cloud/server/ManagementServerImpl.java +++ b/server/src/com/cloud/server/ManagementServerImpl.java @@ -59,6 +59,7 @@ import com.cloud.agent.api.GetVncPortAnswer; import com.cloud.agent.api.GetVncPortCommand; import com.cloud.agent.api.storage.CopyVolumeAnswer; import com.cloud.agent.api.storage.CopyVolumeCommand; +import com.cloud.agent.manager.allocator.HostAllocator; import com.cloud.alert.Alert; import com.cloud.alert.AlertVO; import com.cloud.alert.dao.AlertDao; @@ -151,6 +152,8 @@ import com.cloud.dc.dao.DataCenterIpAddressDao; import com.cloud.dc.dao.HostPodDao; import com.cloud.dc.dao.PodVlanMapDao; import com.cloud.dc.dao.VlanDao; +import com.cloud.deploy.DataCenterDeployment; +import com.cloud.deploy.DeploymentPlanner.ExcludeList; import com.cloud.domain.Domain; import com.cloud.domain.DomainVO; import com.cloud.domain.dao.DomainDao; @@ -266,6 +269,8 @@ import com.cloud.vm.VMInstanceVO; import com.cloud.vm.VirtualMachine; import com.cloud.vm.VirtualMachine.State; import com.cloud.vm.VirtualMachineManager; +import com.cloud.vm.VirtualMachineProfile; +import com.cloud.vm.VirtualMachineProfileImpl; import com.cloud.vm.dao.ConsoleProxyDao; import com.cloud.vm.dao.DomainRouterDao; import com.cloud.vm.dao.InstanceGroupDao; @@ -335,6 +340,7 @@ public class ManagementServerImpl implements ManagementServer { private final SSHKeyPairDao _sshKeyPairDao; private final LoadBalancerDao _loadbalancerDao; private final HypervisorCapabilitiesDao _hypervisorCapabilitiesDao; + private final Adapters _hostAllocators; private final KeystoreManager _ksMgr; @@ -410,6 +416,11 @@ public class ManagementServerImpl implements ManagementServer { s_logger.error("Unable to find an user authenticator."); } + _hostAllocators = locator.getAdapters(HostAllocator.class); + if (_hostAllocators == null || !_hostAllocators.isSet()) { + s_logger.error("Unable to find HostAllocators"); + } + _templateMgr = locator.getManager(TemplateManager.class); String value = _configs.get("account.cleanup.interval"); @@ -1250,7 +1261,7 @@ public class ManagementServerImpl implements ManagementServer { } @Override - public Pair, List> listHostsForMigrationOfVM(UserVm vm, Long startIndex, Long pageSize) { + public Pair, List> listHostsForMigrationOfVM(UserVm vm, Long startIndex, Long pageSize) { // access check - only root admin can migrate VM Account caller = UserContext.current().getCaller(); if (caller.getType() != Account.ACCOUNT_TYPE_ADMIN) { @@ -1302,25 +1313,36 @@ public class ManagementServerImpl implements ManagementServer { s_logger.debug("Other Hosts in this cluster: " + allHostsInCluster); } - int requiredCpu = svcOffering.getCpu() * svcOffering.getSpeed(); - long requiredRam = svcOffering.getRamSize() * 1024L * 1024L; - if (s_logger.isDebugEnabled()) { - s_logger.debug("Searching for hosts in cluster: " + cluster + " having required CPU: " + requiredCpu + " and RAM:" + requiredRam); + s_logger.debug("Calling HostAllocators to search for hosts in cluster: " + cluster + " having enough capacity and suitable for migration"); } - String opFactor = _configDao.getValue(Config.CPUOverprovisioningFactor.key()); - float cpuOverprovisioningFactor = NumbersUtil.parseFloat(opFactor, 1); - if (s_logger.isDebugEnabled()) { - s_logger.debug("CPUOverprovisioningFactor considered: " + cpuOverprovisioningFactor); - } - List hostsWithCapacity = _capacityDao.listHostsWithEnoughCapacity(requiredCpu, requiredRam, cluster, hostType.name(), cpuOverprovisioningFactor); + + List suitableHosts = new ArrayList(); + Enumeration enHost = _hostAllocators.enumeration(); + UserVmVO vmVO = (UserVmVO)vm; + VirtualMachineProfile vmProfile = new VirtualMachineProfileImpl(vmVO); - if (s_logger.isDebugEnabled()) { - s_logger.debug("Hosts having capacity: " + hostsWithCapacity); + DataCenterDeployment plan = new DataCenterDeployment(srcHost.getDataCenterId(), srcHost.getPodId(), srcHost.getClusterId(), null, null); + ExcludeList excludes = new ExcludeList(); + excludes.addHost(srcHostId); + while (enHost.hasMoreElements()) { + final HostAllocator allocator = enHost.nextElement(); + suitableHosts = allocator.allocateTo(vmProfile, plan, Host.Type.Routing, excludes, HostAllocator.RETURN_UPTO_ALL, false); + if (suitableHosts != null && !suitableHosts.isEmpty()) { + break; + } } - return new Pair, List>(allHostsInCluster, hostsWithCapacity); + if(suitableHosts.isEmpty()){ + s_logger.debug("No suitable hosts found"); + }else{ + if (s_logger.isDebugEnabled()) { + s_logger.debug("Hosts having capacity and suitable for migration: " + suitableHosts); + } + } + + return new Pair, List>(allHostsInCluster, suitableHosts); } private List searchForServers(Long startIndex, Long pageSize, Object name, Object type, Object state, Object zone, Object pod, Object cluster, Object id, Object keyword, diff --git a/server/src/com/cloud/storage/allocator/StoragePoolAllocator.java b/server/src/com/cloud/storage/allocator/StoragePoolAllocator.java index 5b6f61db6cd..8d611cdf343 100644 --- a/server/src/com/cloud/storage/allocator/StoragePoolAllocator.java +++ b/server/src/com/cloud/storage/allocator/StoragePoolAllocator.java @@ -19,6 +19,7 @@ package com.cloud.storage.allocator; import java.util.List; import java.util.Set; + import com.cloud.deploy.DeploymentPlan; import com.cloud.deploy.DeploymentPlanner.ExcludeList; import com.cloud.host.Host; @@ -27,7 +28,6 @@ import com.cloud.template.VirtualMachineTemplate; import com.cloud.utils.component.Adapter; import com.cloud.vm.DiskProfile; import com.cloud.vm.VirtualMachine; -import com.cloud.vm.VirtualMachineProfile; /** * Allocator for a disk. This determines which StoragePool should @@ -51,4 +51,6 @@ public interface StoragePoolAllocator extends Adapter { * @return List List of storage pools that are suitable for the VM **/ List allocateToPool(DiskProfile dskCh, VirtualMachineTemplate VMtemplate, DeploymentPlan plan, ExcludeList avoid, int returnUpTo); + + public static int RETURN_UPTO_ALL = -1; } diff --git a/server/src/com/cloud/vm/VirtualMachineManagerImpl.java b/server/src/com/cloud/vm/VirtualMachineManagerImpl.java index 552fc246b4c..f5d8d3a19c9 100755 --- a/server/src/com/cloud/vm/VirtualMachineManagerImpl.java +++ b/server/src/com/cloud/vm/VirtualMachineManagerImpl.java @@ -218,7 +218,7 @@ public class VirtualMachineManagerImpl implements VirtualMachineManager, Listene protected Adapters _planners; @Inject(adapter = HostAllocator.class) - protected Adapters _hostAllocators; + protected Adapters _hostAllocators; Map> _vmGurus = new HashMap>(); protected StateMachine2 _stateMachine; @@ -1122,7 +1122,7 @@ public class VirtualMachineManagerImpl implements VirtualMachineManager, Listene if (s_logger.isDebugEnabled()) { s_logger.debug("VM is not Running, unable to migrate the vm " + vm); } - throw new VirtualMachineMigrationException("VM is not Running, unable to migrate the vm currently " + vm); + throw new VirtualMachineMigrationException("VM is not Running, unable to migrate the vm currently " + vm + " , current state: " + vm.getState().toString()); } short alertType = AlertManager.ALERT_TYPE_USERVM_MIGRATE;