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
This commit is contained in:
prachi 2012-02-16 17:20:54 -08:00
parent 4b7543f9a6
commit 8516186db1
2 changed files with 61 additions and 58 deletions

View File

@ -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)){

View File

@ -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<VolumeVO> 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<VolumeVO> 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<T> vmProfile = new VirtualMachineProfileImpl<T>(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);