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 Project: http://git-wip-us.apache.org/repos/asf/cloudstack/repo Commit: http://git-wip-us.apache.org/repos/asf/cloudstack/commit/31a67706 Tree: http://git-wip-us.apache.org/repos/asf/cloudstack/tree/31a67706 Diff: http://git-wip-us.apache.org/repos/asf/cloudstack/diff/31a67706 Branch: refs/heads/vmware-datamodel Commit: 31a67706e402fc73c592f871291223107ed0c21c Parents: 55c1e28 Author: Prachi Damle <pra...@cloud.com> Authored: Fri May 17 14:36:23 2013 -0700 Committer: Prachi Damle <pra...@cloud.com> Committed: Fri May 17 14:36:23 2013 -0700 ---------------------------------------------------------------------- .../InsufficientServerCapacityException.java | 11 +++++ .../api/command/user/vm/DeployVMCmd.java | 11 ++++- .../cloudstack/api/command/user/vm/StartVMCmd.java | 14 +++++- .../cloud/entity/api/VMEntityManagerImpl.java | 18 ++++++++- .../com/cloud/vm/VirtualMachineManagerImpl.java | 32 ++++++++++---- 5 files changed, 72 insertions(+), 14 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/cloudstack/blob/31a67706/api/src/com/cloud/exception/InsufficientServerCapacityException.java ---------------------------------------------------------------------- diff --git a/api/src/com/cloud/exception/InsufficientServerCapacityException.java b/api/src/com/cloud/exception/InsufficientServerCapacityException.java index af34e57..8f889fe 100755 --- a/api/src/com/cloud/exception/InsufficientServerCapacityException.java +++ b/api/src/com/cloud/exception/InsufficientServerCapacityException.java @@ -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; + } } http://git-wip-us.apache.org/repos/asf/cloudstack/blob/31a67706/api/src/org/apache/cloudstack/api/command/user/vm/DeployVMCmd.java ---------------------------------------------------------------------- diff --git a/api/src/org/apache/cloudstack/api/command/user/vm/DeployVMCmd.java b/api/src/org/apache/cloudstack/api/command/user/vm/DeployVMCmd.java index b5cf9f9..63198a4 100755 --- a/api/src/org/apache/cloudstack/api/command/user/vm/DeployVMCmd.java +++ b/api/src/org/apache/cloudstack/api/command/user/vm/DeployVMCmd.java @@ -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()); http://git-wip-us.apache.org/repos/asf/cloudstack/blob/31a67706/api/src/org/apache/cloudstack/api/command/user/vm/StartVMCmd.java ---------------------------------------------------------------------- diff --git a/api/src/org/apache/cloudstack/api/command/user/vm/StartVMCmd.java b/api/src/org/apache/cloudstack/api/command/user/vm/StartVMCmd.java index 3012780..09b34d4 100644 --- a/api/src/org/apache/cloudstack/api/command/user/vm/StartVMCmd.java +++ b/api/src/org/apache/cloudstack/api/command/user/vm/StartVMCmd.java @@ -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()); } } http://git-wip-us.apache.org/repos/asf/cloudstack/blob/31a67706/engine/orchestration/src/org/apache/cloudstack/engine/cloud/entity/api/VMEntityManagerImpl.java ---------------------------------------------------------------------- diff --git a/engine/orchestration/src/org/apache/cloudstack/engine/cloud/entity/api/VMEntityManagerImpl.java b/engine/orchestration/src/org/apache/cloudstack/engine/cloud/entity/api/VMEntityManagerImpl.java index 25e7423..38ed7e6 100755 --- a/engine/orchestration/src/org/apache/cloudstack/engine/cloud/entity/api/VMEntityManagerImpl.java +++ b/engine/orchestration/src/org/apache/cloudstack/engine/cloud/entity/api/VMEntityManagerImpl.java @@ -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)); } } http://git-wip-us.apache.org/repos/asf/cloudstack/blob/31a67706/server/src/com/cloud/vm/VirtualMachineManagerImpl.java ---------------------------------------------------------------------- diff --git a/server/src/com/cloud/vm/VirtualMachineManagerImpl.java b/server/src/com/cloud/vm/VirtualMachineManagerImpl.java index d153bb2..cea0567 100755 --- a/server/src/com/cloud/vm/VirtualMachineManagerImpl.java +++ b/server/src/com/cloud/vm/VirtualMachineManagerImpl.java @@ -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);