2121import java .util .HashMap ;
2222import java .util .Iterator ;
2323import java .util .LinkedHashMap ;
24+ import java .util .LinkedHashSet ;
2425import java .util .List ;
2526import java .util .Map ;
2627
3536import org .apache .cloudstack .framework .config .dao .ConfigurationDao ;
3637import org .apache .cloudstack .network .router .deployment .RouterDeploymentDefinition ;
3738import org .apache .cloudstack .utils .CloudStackVersion ;
39+ import org .apache .commons .collections .CollectionUtils ;
3840import org .apache .log4j .Logger ;
3941
4042import com .cloud .agent .AgentManager ;
4143import com .cloud .agent .api .Answer ;
4244import com .cloud .agent .api .to .NicTO ;
4345import com .cloud .agent .manager .Commands ;
4446import com .cloud .alert .AlertManager ;
47+ import com .cloud .capacity .CapacityManager ;
4548import com .cloud .configuration .Config ;
4649import com .cloud .dc .ClusterVO ;
4750import com .cloud .dc .DataCenter ;
@@ -167,6 +170,8 @@ public class NetworkHelperImpl implements NetworkHelper {
167170 RouterHealthCheckResultDao _routerHealthCheckResultDao ;
168171 @ Inject
169172 Ipv6Service ipv6Service ;
173+ @ Inject
174+ CapacityManager capacityMgr ;
170175
171176 protected final Map <HypervisorType , ConfigKey <String >> hypervisorsMap = new HashMap <>();
172177
@@ -502,12 +507,12 @@ public DomainRouterVO deployRouter(final RouterDeploymentDefinition routerDeploy
502507 // failed both times, throw the exception up
503508 final List <HypervisorType > hypervisors = getHypervisors (routerDeploymentDefinition );
504509
505- int allocateRetry = 0 ;
506- int startRetry = 0 ;
507510 DomainRouterVO router = null ;
508511 for (final Iterator <HypervisorType > iter = hypervisors .iterator (); iter .hasNext ();) {
509512 final HypervisorType hType = iter .next ();
510513 try {
514+ checkIfZoneHasCapacity (routerDeploymentDefinition .getDest ().getDataCenter (), hType , routerOffering );
515+
511516 final long id = _routerDao .getNextInSequence (Long .class , "id" );
512517 if (s_logger .isDebugEnabled ()) {
513518 s_logger .debug (String .format ("Allocating the VR with id=%s in datacenter %s with the hypervisor type %s" , id , routerDeploymentDefinition .getDest ()
@@ -547,31 +552,27 @@ public DomainRouterVO deployRouter(final RouterDeploymentDefinition routerDeploy
547552 reallocateRouterNetworks (routerDeploymentDefinition , router , template , null );
548553 router = _routerDao .findById (router .getId ());
549554 } catch (final InsufficientCapacityException ex ) {
550- if (allocateRetry < 2 && iter .hasNext ()) {
555+ if (iter .hasNext ()) {
551556 s_logger .debug ("Failed to allocate the VR with hypervisor type " + hType + ", retrying one more time" );
552557 continue ;
553558 } else {
554559 throw ex ;
555560 }
556- } finally {
557- allocateRetry ++;
558561 }
559562
560563 if (startRouter ) {
561564 try {
562565 router = startVirtualRouter (router , _accountMgr .getSystemUser (), _accountMgr .getSystemAccount (), routerDeploymentDefinition .getParams ());
563566 break ;
564567 } catch (final InsufficientCapacityException ex ) {
565- if (startRetry < 2 && iter .hasNext ()) {
568+ if (iter .hasNext ()) {
566569 s_logger .debug ("Failed to start the VR " + router + " with hypervisor type " + hType + ", " + "destroying it and recreating one more time" );
567570 // destroy the router
568571 destroyRouter (router .getId (), _accountMgr .getAccount (Account .ACCOUNT_ID_SYSTEM ), User .UID_SYSTEM );
569572 continue ;
570573 } else {
571574 throw ex ;
572575 }
573- } finally {
574- startRetry ++;
575576 }
576577 } else {
577578 // return stopped router
@@ -582,6 +583,25 @@ public DomainRouterVO deployRouter(final RouterDeploymentDefinition routerDeploy
582583 return router ;
583584 }
584585
586+ private void checkIfZoneHasCapacity (final DataCenter zone , final HypervisorType hypervisorType , final ServiceOfferingVO routerOffering ) throws InsufficientServerCapacityException {
587+ List <HostVO > hosts = _hostDao .listByDataCenterIdAndHypervisorType (zone .getId (), hypervisorType );
588+ if (CollectionUtils .isEmpty (hosts )) {
589+ String msg = String .format ("Zone %s has no %s host available which is enabled and in Up state" , zone .getName (), hypervisorType );
590+ s_logger .debug (msg );
591+ throw new InsufficientServerCapacityException (msg , DataCenter .class , zone .getId ());
592+ }
593+ for (HostVO host : hosts ) {
594+ Pair <Boolean , Boolean > cpuCapabilityAndCapacity = capacityMgr .checkIfHostHasCpuCapabilityAndCapacity (host , routerOffering , false );
595+ if (cpuCapabilityAndCapacity .first () && cpuCapabilityAndCapacity .second ()) {
596+ s_logger .debug ("Host " + host + " has enough capacity for the router" );
597+ return ;
598+ }
599+ }
600+ String msg = String .format ("Zone %s has no %s host which has enough capacity" , zone .getName (), hypervisorType );
601+ s_logger .debug (msg );
602+ throw new InsufficientServerCapacityException (msg , DataCenter .class , zone .getId ());
603+ }
604+
585605 protected void filterSupportedHypervisors (final List <HypervisorType > hypervisors ) {
586606 // For non vpc we keep them all assuming all types in the list are
587607 // supported
@@ -618,7 +638,7 @@ protected List<HypervisorType> getHypervisors(final RouterDeploymentDefinition r
618638 throw new InsufficientServerCapacityException ("Unable to create virtual router, there are no clusters in the zone." + getNoHypervisorsErrMsgDetails (),
619639 DataCenter .class , dest .getDataCenter ().getId ());
620640 }
621- return hypervisors ;
641+ return new ArrayList ( new LinkedHashSet <>( hypervisors )) ;
622642 }
623643
624644 /*
0 commit comments