mirror of https://github.com/apache/cloudstack.git
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:
parent
c79b8270a8
commit
661088927d
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue