From 8516186db1823f183875c8944d64626388453026 Mon Sep 17 00:00:00 2001 From: prachi Date: Thu, 16 Feb 2012 17:20:54 -0800 Subject: [PATCH] Bug 13824 - VM Deployment: If Root Volume is Ready, Planner should reuse the storagepool until cluster has capacity Reviewed-By: Alex Changes: - Reuse the same storagepool where the Volume is ready on each retry of VM deployment until the cluster where the volume is has capacity - After the cluster is out of capacity, we look in other clusters and find a new storagepool. - At this point if the volume is recreatable on the new storagepool, depoyment will succeed provided everytyhing else goes through - But if the volume is not recreatable and its cluster is out of capacity, we will still fail to deploy the VM Conflicts: server/src/com/cloud/vm/VirtualMachineManagerImpl.java --- .../src/com/cloud/deploy/FirstFitPlanner.java | 2 + .../cloud/vm/VirtualMachineManagerImpl.java | 117 +++++++++--------- 2 files changed, 61 insertions(+), 58 deletions(-) diff --git a/server/src/com/cloud/deploy/FirstFitPlanner.java b/server/src/com/cloud/deploy/FirstFitPlanner.java index c56b51a7bc8..113b56310ce 100755 --- a/server/src/com/cloud/deploy/FirstFitPlanner.java +++ b/server/src/com/cloud/deploy/FirstFitPlanner.java @@ -177,6 +177,8 @@ public class FirstFitPlanner extends PlannerBase implements DeploymentPlanner { HostVO host = _hostDao.findById(vm.getLastHostId()); if(host == null){ s_logger.debug("The last host of this VM cannot be found"); + }else if(avoid.shouldAvoid(host)){ + s_logger.debug("The last host of this VM is in avoid set"); }else{ if (host.getStatus() == Status.Up && host.getHostAllocationState() == Host.HostAllocationState.Enabled) { if(_capacityMgr.checkIfHostHasCapacity(host.getId(), cpu_requested, ram_requested, true, cpuOverprovisioningFactor)){ diff --git a/server/src/com/cloud/vm/VirtualMachineManagerImpl.java b/server/src/com/cloud/vm/VirtualMachineManagerImpl.java index 12865a2282c..f54703c3b2a 100755 --- a/server/src/com/cloud/vm/VirtualMachineManagerImpl.java +++ b/server/src/com/cloud/vm/VirtualMachineManagerImpl.java @@ -129,7 +129,6 @@ import com.cloud.user.User; import com.cloud.user.dao.AccountDao; import com.cloud.user.dao.UserDao; import com.cloud.uservm.UserVm; -import com.cloud.utils.DateUtil; import com.cloud.utils.Journal; import com.cloud.utils.NumbersUtil; import com.cloud.utils.Pair; @@ -645,60 +644,59 @@ public class VirtualMachineManagerImpl implements VirtualMachineManager, Listene + ", clusters: " + avoids.getClustersToAvoid() + ", hosts: " + avoids.getHostsToAvoid()); } - - // edit plan if this vm's ROOT volume is in READY state already - List vols = _volsDao.findReadyRootVolumesByInstance(vm.getId()); - boolean planChangedByVolume = false; - boolean rootVolumeisRecreatable = false; - DataCenterDeployment originalPlan = plan; - for (VolumeVO vol : vols) { - // make sure if the templateId is unchanged. If it is changed, let planner - // reassign pool for the volume even if it ready. - Long volTemplateId = vol.getTemplateId(); - if (volTemplateId != null && volTemplateId.longValue() != template.getId()) { - if (s_logger.isDebugEnabled()) { - s_logger.debug(vol + " of " + vm + " is READY, but template ids don't match, let the planner reassign a new pool"); - } - continue; - } - StoragePoolVO pool = _storagePoolDao.findById(vol.getPoolId()); - if (!pool.isInMaintenance()) { - if (s_logger.isDebugEnabled()) { - s_logger.debug("Root volume is ready, need to place VM in volume's cluster"); - } - long rootVolDcId = pool.getDataCenterId(); - Long rootVolPodId = pool.getPodId(); - Long rootVolClusterId = pool.getClusterId(); - if(planToDeploy != null && planToDeploy.getDataCenterId() != 0){ - Long clusterIdSpecified = planToDeploy.getClusterId(); - if(clusterIdSpecified != null && rootVolClusterId != null){ - if(rootVolClusterId.longValue() != clusterIdSpecified.longValue()){ - //cannot satisfy the plan passed in to the planner - if (s_logger.isDebugEnabled()) { - s_logger.debug("Cannot satisfy the deployment plan passed in since the ready Root volume is in different cluster. volume's cluster: "+rootVolClusterId + ", cluster specified: "+clusterIdSpecified); - } - throw new ResourceUnavailableException("Root volume is ready in different cluster, Deployment plan provided cannot be satisfied, unable to create a deployment for " + vm, Cluster.class, clusterIdSpecified); - } - } - plan = new DataCenterDeployment(planToDeploy.getDataCenterId(), planToDeploy.getPodId(), planToDeploy.getClusterId(), planToDeploy.getHostId(), vol.getPoolId()); - }else{ - plan = new DataCenterDeployment(rootVolDcId, rootVolPodId, rootVolClusterId, null, vol.getPoolId()); - if (s_logger.isDebugEnabled()) { - s_logger.debug(vol + " is READY, changing deployment plan to use this pool's dcId: " + rootVolDcId + " , podId: " + rootVolPodId + " , and clusterId: " + rootVolClusterId); - } - planChangedByVolume = true; - if(vol.isRecreatable()){ - rootVolumeisRecreatable = true; - } - - } - } - } - + boolean planChangedByVolume = false; + boolean reuseVolume = true; + DataCenterDeployment originalPlan = plan; + int retry = _retry; while (retry-- != 0) { // It's != so that it can match -1. + if(reuseVolume){ + // edit plan if this vm's ROOT volume is in READY state already + List vols = _volsDao.findReadyRootVolumesByInstance(vm.getId()); + for (VolumeVO vol : vols) { + // make sure if the templateId is unchanged. If it is changed, let planner + // reassign pool for the volume even if it ready. + Long volTemplateId = vol.getTemplateId(); + if (volTemplateId != null && volTemplateId.longValue() != template.getId()) { + if (s_logger.isDebugEnabled()) { + s_logger.debug(vol + " of " + vm + " is READY, but template ids don't match, let the planner reassign a new pool"); + } + continue; + } + + StoragePoolVO pool = _storagePoolDao.findById(vol.getPoolId()); + if (!pool.isInMaintenance()) { + if (s_logger.isDebugEnabled()) { + s_logger.debug("Root volume is ready, need to place VM in volume's cluster"); + } + long rootVolDcId = pool.getDataCenterId(); + Long rootVolPodId = pool.getPodId(); + Long rootVolClusterId = pool.getClusterId(); + if(planToDeploy != null && planToDeploy.getDataCenterId() != 0){ + Long clusterIdSpecified = planToDeploy.getClusterId(); + if(clusterIdSpecified != null && rootVolClusterId != null){ + if(rootVolClusterId.longValue() != clusterIdSpecified.longValue()){ + //cannot satisfy the plan passed in to the planner + if (s_logger.isDebugEnabled()) { + s_logger.debug("Cannot satisfy the deployment plan passed in since the ready Root volume is in different cluster. volume's cluster: "+rootVolClusterId + ", cluster specified: "+clusterIdSpecified); + } + throw new ResourceUnavailableException("Root volume is ready in different cluster, Deployment plan provided cannot be satisfied, unable to create a deployment for " + vm, Cluster.class, clusterIdSpecified); + } + } + plan = new DataCenterDeployment(planToDeploy.getDataCenterId(), planToDeploy.getPodId(), planToDeploy.getClusterId(), planToDeploy.getHostId(), vol.getPoolId()); + }else{ + plan = new DataCenterDeployment(rootVolDcId, rootVolPodId, rootVolClusterId, null, vol.getPoolId()); + if (s_logger.isDebugEnabled()) { + s_logger.debug(vol + " is READY, changing deployment plan to use this pool's dcId: " + rootVolDcId + " , podId: " + rootVolPodId + " , and clusterId: " + rootVolClusterId); + } + planChangedByVolume = true; + } + } + } + } + VirtualMachineProfileImpl vmProfile = new VirtualMachineProfileImpl(vm, template, offering, account, params); DeployDestination dest = null; for (DeploymentPlanner planner : _planners) { @@ -715,12 +713,12 @@ public class VirtualMachineManagerImpl implements VirtualMachineManager, Listene } if (dest == null) { - if(planChangedByVolume){ - if(rootVolumeisRecreatable){ - plan = originalPlan; - planChangedByVolume = false; - continue; - } + if (planChangedByVolume) { + plan = originalPlan; + planChangedByVolume = false; + //do not enter volume reuse for next retry, since we want to look for resorces outside the volume's cluster + reuseVolume = false; + continue; } throw new InsufficientServerCapacityException("Unable to create a deployment for " + vmProfile, DataCenter.class, plan.getDataCenterId()); } @@ -744,7 +742,10 @@ public class VirtualMachineManagerImpl implements VirtualMachineManager, Listene if (vm.getHypervisorType() != HypervisorType.BareMetal) { _storageMgr.prepare(vmProfile, dest); } - + //since StorageMgr succeeded in volume creation, resue Volume for further tries until current cluster has capacity + if(!reuseVolume){ + reuseVolume = true; + } vmGuru.finalizeVirtualMachineProfile(vmProfile, dest, ctx); VirtualMachineTO vmTO = hvGuru.implement(vmProfile);