diff --git a/server/src/main/java/com/cloud/network/router/NetworkHelperImpl.java b/server/src/main/java/com/cloud/network/router/NetworkHelperImpl.java index 934336066cc..56860499ae0 100644 --- a/server/src/main/java/com/cloud/network/router/NetworkHelperImpl.java +++ b/server/src/main/java/com/cloud/network/router/NetworkHelperImpl.java @@ -21,6 +21,7 @@ import java.util.Arrays; import java.util.HashMap; import java.util.Iterator; import java.util.LinkedHashMap; +import java.util.LinkedHashSet; import java.util.List; import java.util.Map; @@ -35,6 +36,7 @@ import org.apache.cloudstack.framework.config.ConfigKey; import org.apache.cloudstack.framework.config.dao.ConfigurationDao; import org.apache.cloudstack.network.router.deployment.RouterDeploymentDefinition; import org.apache.cloudstack.utils.CloudStackVersion; +import org.apache.commons.collections.CollectionUtils; import org.apache.log4j.Logger; import com.cloud.agent.AgentManager; @@ -42,6 +44,7 @@ import com.cloud.agent.api.Answer; import com.cloud.agent.api.to.NicTO; import com.cloud.agent.manager.Commands; import com.cloud.alert.AlertManager; +import com.cloud.capacity.CapacityManager; import com.cloud.configuration.Config; import com.cloud.dc.ClusterVO; import com.cloud.dc.DataCenter; @@ -167,6 +170,8 @@ public class NetworkHelperImpl implements NetworkHelper { RouterHealthCheckResultDao _routerHealthCheckResultDao; @Inject Ipv6Service ipv6Service; + @Inject + CapacityManager capacityMgr; protected final Map> hypervisorsMap = new HashMap<>(); @@ -502,12 +507,12 @@ public class NetworkHelperImpl implements NetworkHelper { // failed both times, throw the exception up final List hypervisors = getHypervisors(routerDeploymentDefinition); - int allocateRetry = 0; - int startRetry = 0; DomainRouterVO router = null; for (final Iterator iter = hypervisors.iterator(); iter.hasNext();) { final HypervisorType hType = iter.next(); try { + checkIfZoneHasCapacity(routerDeploymentDefinition.getDest().getDataCenter(), hType, routerOffering); + final long id = _routerDao.getNextInSequence(Long.class, "id"); if (s_logger.isDebugEnabled()) { s_logger.debug(String.format("Allocating the VR with id=%s in datacenter %s with the hypervisor type %s", id, routerDeploymentDefinition.getDest() @@ -547,14 +552,12 @@ public class NetworkHelperImpl implements NetworkHelper { reallocateRouterNetworks(routerDeploymentDefinition, router, template, null); router = _routerDao.findById(router.getId()); } catch (final InsufficientCapacityException ex) { - if (allocateRetry < 2 && iter.hasNext()) { + if (iter.hasNext()) { s_logger.debug("Failed to allocate the VR with hypervisor type " + hType + ", retrying one more time"); continue; } else { throw ex; } - } finally { - allocateRetry++; } if (startRouter) { @@ -562,7 +565,7 @@ public class NetworkHelperImpl implements NetworkHelper { router = startVirtualRouter(router, _accountMgr.getSystemUser(), _accountMgr.getSystemAccount(), routerDeploymentDefinition.getParams()); break; } catch (final InsufficientCapacityException ex) { - if (startRetry < 2 && iter.hasNext()) { + if (iter.hasNext()) { s_logger.debug("Failed to start the VR " + router + " with hypervisor type " + hType + ", " + "destroying it and recreating one more time"); // destroy the router destroyRouter(router.getId(), _accountMgr.getAccount(Account.ACCOUNT_ID_SYSTEM), User.UID_SYSTEM); @@ -570,8 +573,6 @@ public class NetworkHelperImpl implements NetworkHelper { } else { throw ex; } - } finally { - startRetry++; } } else { // return stopped router @@ -582,6 +583,25 @@ public class NetworkHelperImpl implements NetworkHelper { return router; } + private void checkIfZoneHasCapacity(final DataCenter zone, final HypervisorType hypervisorType, final ServiceOfferingVO routerOffering) throws InsufficientServerCapacityException { + List hosts = _hostDao.listByDataCenterIdAndHypervisorType(zone.getId(), hypervisorType); + if (CollectionUtils.isEmpty(hosts)) { + String msg = String.format("Zone %s has no %s host available which is enabled and in Up state", zone.getName(), hypervisorType); + s_logger.debug(msg); + throw new InsufficientServerCapacityException(msg, DataCenter.class, zone.getId()); + } + for (HostVO host : hosts) { + Pair cpuCapabilityAndCapacity = capacityMgr.checkIfHostHasCpuCapabilityAndCapacity(host, routerOffering, false); + if (cpuCapabilityAndCapacity.first() && cpuCapabilityAndCapacity.second()) { + s_logger.debug("Host " + host + " has enough capacity for the router"); + return; + } + } + String msg = String.format("Zone %s has no %s host which has enough capacity", zone.getName(), hypervisorType); + s_logger.debug(msg); + throw new InsufficientServerCapacityException(msg, DataCenter.class, zone.getId()); + } + protected void filterSupportedHypervisors(final List hypervisors) { // For non vpc we keep them all assuming all types in the list are // supported @@ -618,7 +638,7 @@ public class NetworkHelperImpl implements NetworkHelper { throw new InsufficientServerCapacityException("Unable to create virtual router, there are no clusters in the zone." + getNoHypervisorsErrMsgDetails(), DataCenter.class, dest.getDataCenter().getId()); } - return hypervisors; + return new ArrayList(new LinkedHashSet<>(hypervisors)); } /*