CLOUDSTACK-2070: Anti-Affinity - When Vm deployment fails because of not being able to satisfy the anti-affinity rule , user should be provided with more informative message.

Changes:
- There is no good mechanism currently to figure out if the  deployment failed due to affinity groups only
- We can just hint the user that the deployment might have failed due to the affinity groups and ask to review the input
This commit is contained in:
Prachi Damle 2013-05-17 14:36:23 -07:00
parent 55c1e282e3
commit 31a67706e4
5 changed files with 72 additions and 14 deletions

View File

@ -27,6 +27,8 @@ public class InsufficientServerCapacityException extends InsufficientCapacityExc
private static final long serialVersionUID = SerialVersionUID.InsufficientServerCapacityException;
private boolean affinityGroupsApplied = false;
public InsufficientServerCapacityException(String msg, Long clusterId) {
this(msg, Cluster.class, clusterId);
}
@ -34,4 +36,13 @@ public class InsufficientServerCapacityException extends InsufficientCapacityExc
public InsufficientServerCapacityException(String msg, Class<?> scope, Long id) {
super(msg, scope, id);
}
public InsufficientServerCapacityException(String msg, Class<?> scope, Long id, boolean affinityGroupsApplied) {
super(msg, scope, id);
this.affinityGroupsApplied = affinityGroupsApplied;
}
public boolean isAffinityApplied() {
return affinityGroupsApplied;
}
}

View File

@ -51,6 +51,7 @@ import com.cloud.dc.DataCenter.NetworkType;
import com.cloud.event.EventTypes;
import com.cloud.exception.ConcurrentOperationException;
import com.cloud.exception.InsufficientCapacityException;
import com.cloud.exception.InsufficientServerCapacityException;
import com.cloud.exception.InvalidParameterValueException;
import com.cloud.exception.ResourceAllocationException;
import com.cloud.exception.ResourceUnavailableException;
@ -424,9 +425,15 @@ public class DeployVMCmd extends BaseAsyncCreateCmd {
s_logger.warn("Exception: ", ex);
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, ex.getMessage());
} catch (InsufficientCapacityException ex) {
StringBuilder message = new StringBuilder(ex.getMessage());
if (ex instanceof InsufficientServerCapacityException) {
if(((InsufficientServerCapacityException)ex).isAffinityApplied()){
message.append(", Please check the affinity groups provided, there may not be sufficient capacity to follow them");
}
}
s_logger.info(ex);
s_logger.info(ex.getMessage(), ex);
throw new ServerApiException(ApiErrorCode.INSUFFICIENT_CAPACITY_ERROR, ex.getMessage());
s_logger.info(message.toString(), ex);
throw new ServerApiException(ApiErrorCode.INSUFFICIENT_CAPACITY_ERROR, message.toString());
}
} else {
result = _userVmService.getUserVm(getEntityId());

View File

@ -30,10 +30,10 @@ import com.cloud.async.AsyncJob;
import com.cloud.event.EventTypes;
import com.cloud.exception.ConcurrentOperationException;
import com.cloud.exception.InsufficientCapacityException;
import com.cloud.exception.InsufficientServerCapacityException;
import com.cloud.exception.ResourceAllocationException;
import com.cloud.exception.ResourceUnavailableException;
import com.cloud.exception.StorageUnavailableException;
import com.cloud.hypervisor.Hypervisor.HypervisorType;
import com.cloud.user.Account;
import com.cloud.user.UserContext;
import com.cloud.uservm.UserVm;
@ -112,7 +112,7 @@ public class StartVMCmd extends BaseAsyncCmd {
}
@Override
public void execute() throws ResourceUnavailableException, InsufficientCapacityException, ResourceAllocationException {
public void execute() throws ResourceUnavailableException, ResourceAllocationException {
try {
UserContext.current().setEventDetails("Vm Id: " + getId());
@ -135,6 +135,16 @@ public class StartVMCmd extends BaseAsyncCmd {
} catch (ExecutionException ex) {
s_logger.warn("Exception: ", ex);
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, ex.getMessage());
} catch (InsufficientCapacityException ex) {
StringBuilder message = new StringBuilder(ex.getMessage());
if (ex instanceof InsufficientServerCapacityException) {
if (((InsufficientServerCapacityException) ex).isAffinityApplied()) {
message.append(", Please check the affinity groups provided, there may not be sufficient capacity to follow them");
}
}
s_logger.info(ex);
s_logger.info(message.toString(), ex);
throw new ServerApiException(ApiErrorCode.INSUFFICIENT_CAPACITY_ERROR, message.toString());
}
}

View File

@ -24,6 +24,7 @@ import java.util.UUID;
import javax.inject.Inject;
import org.apache.cloudstack.affinity.dao.AffinityGroupVMMapDao;
import org.apache.cloudstack.engine.cloud.entity.api.db.VMEntityVO;
import org.apache.cloudstack.engine.cloud.entity.api.db.VMReservationVO;
import org.apache.cloudstack.engine.cloud.entity.api.db.dao.VMEntityDao;
@ -60,6 +61,7 @@ import com.cloud.user.dao.AccountDao;
import com.cloud.user.dao.UserDao;
import com.cloud.utils.exception.CloudRuntimeException;
import com.cloud.vm.VMInstanceVO;
import com.cloud.vm.VirtualMachine;
import com.cloud.vm.VirtualMachineManager;
import com.cloud.vm.VirtualMachineProfile;
import com.cloud.vm.VirtualMachineProfileImpl;
@ -111,6 +113,9 @@ public class VMEntityManagerImpl implements VMEntityManager {
@Inject
DeploymentPlanningManager _dpMgr;
@Inject
protected AffinityGroupVMMapDao _affinityGroupVMMapDao;
@Override
public VMEntityVO loadVirtualMachine(String vmId) {
// TODO Auto-generated method stub
@ -123,6 +128,16 @@ public class VMEntityManagerImpl implements VMEntityManager {
}
protected boolean areAffinityGroupsAssociated(VirtualMachineProfile<? extends VirtualMachine> vmProfile) {
VirtualMachine vm = vmProfile.getVirtualMachine();
long vmGroupCount = _affinityGroupVMMapDao.countAffinityGroupsForVm(vm.getId());
if (vmGroupCount > 0) {
return true;
}
return false;
}
@Override
public String reserveVirtualMachine(VMEntityVO vmEntityVO, String plannerToUse, DeploymentPlan planToDeploy, ExcludeList exclude)
throws InsufficientCapacityException, ResourceUnavailableException {
@ -194,7 +209,8 @@ public class VMEntityManagerImpl implements VMEntityManager {
// call retry it.
return UUID.randomUUID().toString();
}else{
throw new InsufficientServerCapacityException("Unable to create a deployment for " + vmProfile, DataCenter.class, plan.getDataCenterId());
throw new InsufficientServerCapacityException("Unable to create a deployment for " + vmProfile,
DataCenter.class, plan.getDataCenterId(), areAffinityGroupsAssociated(vmProfile));
}
}

View File

@ -36,6 +36,7 @@ import javax.ejb.Local;
import javax.inject.Inject;
import javax.naming.ConfigurationException;
import org.apache.cloudstack.affinity.dao.AffinityGroupVMMapDao;
import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreManager;
import org.apache.cloudstack.engine.subsystem.api.storage.StoragePoolAllocator;
import org.apache.cloudstack.engine.subsystem.api.storage.VolumeDataFactory;
@ -253,6 +254,8 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac
protected ResourceLimitService _resourceLimitMgr;
@Inject
protected RulesManager rulesMgr;
@Inject
protected AffinityGroupVMMapDao _affinityGroupVMMapDao;
protected List<DeploymentPlanner> _planners;
public List<DeploymentPlanner> getPlanners() {
@ -666,6 +669,16 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac
}
}
protected boolean areAffinityGroupsAssociated(VirtualMachineProfile<? extends VirtualMachine> vmProfile) {
VirtualMachine vm = vmProfile.getVirtualMachine();
long vmGroupCount = _affinityGroupVMMapDao.countAffinityGroupsForVm(vm.getId());
if (vmGroupCount > 0) {
return true;
}
return false;
}
@Override
public <T extends VMInstanceVO> T advanceStart(T vm, Map<VirtualMachineProfile.Param, Object> params, User caller, Account account) throws InsufficientCapacityException,
ConcurrentOperationException, ResourceUnavailableException {
@ -797,7 +810,8 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac
reuseVolume = false;
continue;
}
throw new InsufficientServerCapacityException("Unable to create a deployment for " + vmProfile, DataCenter.class, plan.getDataCenterId());
throw new InsufficientServerCapacityException("Unable to create a deployment for " + vmProfile,
DataCenter.class, plan.getDataCenterId(), areAffinityGroupsAssociated(vmProfile));
}
if (dest != null) {
@ -1152,7 +1166,7 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac
}
vmGuru.prepareStop(profile);
StopCommand stop = new StopCommand(vm);
boolean stopped = false;
StopAnswer answer = null;
@ -2802,7 +2816,7 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac
VirtualMachineGuru<VMInstanceVO> vmGuru = getVmGuru(vmVO);
s_logger.debug("Plugging nic for vm " + vm + " in network " + network);
boolean result = false;
try{
result = vmGuru.plugNic(network, nicTO, vmTO, context, dest);
@ -2812,17 +2826,17 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac
// insert nic's Id into DB as resource_name
UsageEventUtils.publishUsageEvent(EventTypes.EVENT_NETWORK_OFFERING_ASSIGN, vmVO.getAccountId(),
vmVO.getDataCenterId(), vmVO.getId(), Long.toString(nic.getId()), nic.getNetworkId(),
null, isDefault, VirtualMachine.class.getName(), vmVO.getUuid());
null, isDefault, VirtualMachine.class.getName(), vmVO.getUuid());
return nic;
} else {
s_logger.warn("Failed to plug nic to the vm " + vm + " in network " + network);
return null;
}
}
}finally{
if(!result){
_networkMgr.removeNic(vmProfile, _nicsDao.findById(nic.getId()));
}
}
}
} else if (vm.getState() == State.Stopped) {
//1) allocate nic
return _networkMgr.createNicForVm(network, requested, context, vmProfile, false);
@ -2863,10 +2877,10 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac
s_logger.warn("Failed to remove nic from " + vm + " in " + network + ", nic is default.");
throw new CloudRuntimeException("Failed to remove nic from " + vm + " in " + network + ", nic is default.");
}
// if specified nic is associated with PF/LB/Static NAT
if(rulesMgr.listAssociatedRulesForGuestNic(nic).size() > 0){
throw new CloudRuntimeException("Failed to remove nic from " + vm + " in " + network
throw new CloudRuntimeException("Failed to remove nic from " + vm + " in " + network
+ ", nic has associated Port forwarding or Load balancer or Static NAT rules.");
}
@ -2884,7 +2898,7 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac
s_logger.debug("Nic is unplugged successfully for vm " + vm + " in network " + network );
long isDefault = (nic.isDefaultNic()) ? 1 : 0;
UsageEventUtils.publishUsageEvent(EventTypes.EVENT_NETWORK_OFFERING_REMOVE, vm.getAccountId(), vm.getDataCenterId(),
vm.getId(), Long.toString(nic.getId()), network.getNetworkOfferingId(), null,
vm.getId(), Long.toString(nic.getId()), network.getNetworkOfferingId(), null,
isDefault, VirtualMachine.class.getName(), vm.getUuid());
} else {
s_logger.warn("Failed to unplug nic for the vm " + vm + " from network " + network);