CLOUDSTACK-2155 Anti-Affinity -When Vm deployment is done in parallel , anti-affinity rule is not honored.

Changes to check if the destination found does not conflict with any vm reservation
This commit is contained in:
Prachi Damle 2013-07-12 13:39:24 -07:00
parent c79b8270a8
commit 661088927d
24 changed files with 139 additions and 32 deletions

View File

@ -16,6 +16,7 @@
// under the License.
package org.apache.cloudstack.affinity;
import com.cloud.deploy.DeployDestination;
import com.cloud.deploy.DeploymentPlan;
import com.cloud.deploy.DeploymentPlanner.ExcludeList;
import com.cloud.exception.AffinityConflictException;
@ -46,4 +47,16 @@ public interface AffinityGroupProcessor extends Adapter {
* @return String Affinity/Anti-affinity type
*/
String getType();
/**
* check() is called to see if the planned destination fits the group
* requirements
*
* @param vm
* virtual machine.
* @param plannedDestination
* deployment destination where VM is planned to be deployed
*/
boolean check(VirtualMachineProfile<? extends VirtualMachine> vm, DeployDestination plannedDestination)
throws AffinityConflictException;
}

View File

@ -16,6 +16,7 @@
// under the License.
package org.apache.cloudstack.affinity;
import com.cloud.deploy.DeployDestination;
import com.cloud.deploy.DeploymentPlan;
import com.cloud.deploy.DeploymentPlanner.ExcludeList;
import com.cloud.exception.AffinityConflictException;
@ -41,4 +42,10 @@ public class AffinityProcessorBase extends AdapterBase implements AffinityGroupP
public void setType(String type) {
_type = type;
}
@Override
public boolean check(VirtualMachineProfile<? extends VirtualMachine> vm, DeployDestination plannedDestination)
throws AffinityConflictException {
return true;
}
}

View File

@ -16,7 +16,6 @@
// under the License.
package org.apache.cloudstack.engine.cloud.entity.api;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@ -181,38 +180,49 @@ public class VMEntityManagerImpl implements VMEntityManager {
}
DeployDestination dest;
try {
dest = _dpMgr.planDeployment(vmProfile, plan, exclude);
} catch (AffinityConflictException e) {
throw new CloudRuntimeException("Unable to create deployment, affinity rules associted to the VM conflict");
}
if (dest != null) {
//save destination with VMEntityVO
VMReservationVO vmReservation = new VMReservationVO(vm.getId(), dest.getDataCenter().getId(), dest.getPod().getId(), dest.getCluster().getId(), dest.getHost().getId());
Map<Long,Long> volumeReservationMap = new HashMap<Long,Long>();
if (vm.getHypervisorType() != HypervisorType.BareMetal) {
for(Volume vo : dest.getStorageForDisks().keySet()){
volumeReservationMap.put(vo.getId(), dest.getStorageForDisks().get(vo).getId());
}
vmReservation.setVolumeReservation(volumeReservationMap);
while (true) {
DeployDestination dest = null;
try {
dest = _dpMgr.planDeployment(vmProfile, plan, exclude);
} catch (AffinityConflictException e) {
throw new CloudRuntimeException(
"Unable to create deployment, affinity rules associted to the VM conflict");
}
vmEntityVO.setVmReservation(vmReservation);
_vmEntityDao.persist(vmEntityVO);
if (dest != null) {
if (_dpMgr.finalizeReservation(dest, vmProfile, plan, exclude)) {
// save destination with VMEntityVO
VMReservationVO vmReservation = new VMReservationVO(vm.getId(), dest.getDataCenter().getId(), dest
.getPod().getId(), dest.getCluster().getId(), dest.getHost().getId());
Map<Long, Long> volumeReservationMap = new HashMap<Long, Long>();
return vmReservation.getUuid();
} else if (planChangedByReadyVolume) {
// we could not reserve in the Volume's cluster - let the deploy
// call retry it.
return UUID.randomUUID().toString();
}else{
throw new InsufficientServerCapacityException("Unable to create a deployment for " + vmProfile,
DataCenter.class, plan.getDataCenterId(), areAffinityGroupsAssociated(vmProfile));
if (vm.getHypervisorType() != HypervisorType.BareMetal) {
for (Volume vo : dest.getStorageForDisks().keySet()) {
volumeReservationMap.put(vo.getId(), dest.getStorageForDisks().get(vo).getId());
}
vmReservation.setVolumeReservation(volumeReservationMap);
}
vmEntityVO.setVmReservation(vmReservation);
_vmEntityDao.persist(vmEntityVO);
return vmReservation.getUuid();
} else {
try {
Thread.sleep(10000);
} catch (final InterruptedException e) {
}
continue;
}
} else if (planChangedByReadyVolume) {
// we could not reserve in the Volume's cluster - let the deploy
// call retry it.
return UUID.randomUUID().toString();
} else {
throw new InsufficientServerCapacityException("Unable to create a deployment for " + vmProfile,
DataCenter.class, plan.getDataCenterId(), areAffinityGroupsAssociated(vmProfile));
}
}
}
@Override

View File

@ -5,7 +5,7 @@
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
@ -181,10 +181,10 @@ public class VMEntityVO implements VirtualMachine, FiniteStateObject<State, Virt
@Column(name="disk_offering_id")
protected Long diskOfferingId;
@Transient
private VMReservationVO vmReservation;
public VMEntityVO(long id,
long serviceOfferingId,

View File

@ -25,16 +25,21 @@ import javax.naming.ConfigurationException;
import org.apache.cloudstack.affinity.dao.AffinityGroupDao;
import org.apache.cloudstack.affinity.dao.AffinityGroupVMMapDao;
import org.apache.cloudstack.engine.cloud.entity.api.db.VMReservationVO;
import org.apache.cloudstack.engine.cloud.entity.api.db.dao.VMReservationDao;
import org.apache.cloudstack.framework.messagebus.MessageSubscriber;
import org.apache.log4j.Logger;
import com.cloud.configuration.Config;
import com.cloud.configuration.dao.ConfigurationDao;
import com.cloud.deploy.DeployDestination;
import com.cloud.deploy.DeploymentPlan;
import com.cloud.deploy.DeploymentPlanner.ExcludeList;
import com.cloud.exception.AffinityConflictException;
import com.cloud.utils.DateUtil;
import com.cloud.utils.NumbersUtil;
import com.cloud.utils.db.DB;
import com.cloud.utils.db.Transaction;
import com.cloud.vm.VMInstanceVO;
import com.cloud.vm.VirtualMachine;
import com.cloud.vm.VirtualMachineProfile;
@ -57,6 +62,9 @@ public class HostAntiAffinityProcessor extends AffinityProcessorBase implements
@Inject
protected ConfigurationDao _configDao;
@Inject
protected VMReservationDao _reservationDao;
@Override
public void process(VirtualMachineProfile<? extends VirtualMachine> vmProfile, DeploymentPlan plan,
ExcludeList avoid)
@ -109,4 +117,47 @@ public class HostAntiAffinityProcessor extends AffinityProcessorBase implements
return true;
}
@DB
@Override
public boolean check(VirtualMachineProfile<? extends VirtualMachine> vmProfile, DeployDestination plannedDestination)
throws AffinityConflictException {
if (plannedDestination.getHost() == null) {
return true;
}
long plannedHostId = plannedDestination.getHost().getId();
VirtualMachine vm = vmProfile.getVirtualMachine();
List<AffinityGroupVMMapVO> vmGroupMappings = _affinityGroupVMMapDao.findByVmIdType(vm.getId(), getType());
for (AffinityGroupVMMapVO vmGroupMapping : vmGroupMappings) {
final Transaction txn = Transaction.currentTxn();
try {
txn.start();
// lock the group
AffinityGroupVO group = _affinityGroupDao.lockRow(vmGroupMapping.getAffinityGroupId(), true);
// if more than 1 VM's are present in the group then check for
// conflict due to parallel deployment
List<Long> groupVMIds = _affinityGroupVMMapDao.listVmIdsByAffinityGroup(vmGroupMapping
.getAffinityGroupId());
groupVMIds.remove(vm.getId());
for (Long groupVMId : groupVMIds) {
VMReservationVO vmReservation = _reservationDao.findByVmId(groupVMId);
if (vmReservation.getHostId() != null && vmReservation.getHostId().equals(plannedHostId)) {
return false;
}
}
return true;
} finally {
txn.commit();
}
}
return true;
}
}

View File

@ -42,4 +42,8 @@ public interface DeploymentPlanningManager extends Manager {
*/
DeployDestination planDeployment(VirtualMachineProfile<? extends VirtualMachine> vmProfile, DeploymentPlan plan,
ExcludeList avoids) throws InsufficientServerCapacityException, AffinityConflictException;
boolean finalizeReservation(DeployDestination plannedDestination,
VirtualMachineProfile<? extends VirtualMachine> vmProfile, DeploymentPlan plan, ExcludeList avoids)
throws InsufficientServerCapacityException, AffinityConflictException;
}

View File

@ -1181,4 +1181,26 @@ public class DeploymentPlanningManagerImpl extends ManagerBase implements Deploy
}
return false;
}
@Override
public boolean finalizeReservation(DeployDestination plannedDestination,
VirtualMachineProfile<? extends VirtualMachine> vmProfile, DeploymentPlan plan, ExcludeList avoids)
throws InsufficientServerCapacityException, AffinityConflictException {
VirtualMachine vm = vmProfile.getVirtualMachine();
long vmGroupCount = _affinityGroupVMMapDao.countAffinityGroupsForVm(vm.getId());
DataCenter dc = _dcDao.findById(vm.getDataCenterId());
if (vmGroupCount > 0) {
// uses affinity groups. For every group check if processor flags
// that the destination is ok
for (AffinityGroupProcessor processor : _affinityProcessors) {
if (!processor.check(vmProfile, plannedDestination)) {
return false;
}
}
}
return true;
}
}