diff --git a/api/src/main/java/com/cloud/deploy/DeploymentClusterPlanner.java b/api/src/main/java/com/cloud/deploy/DeploymentClusterPlanner.java index 2697311d2b94..23eb84b38702 100644 --- a/api/src/main/java/com/cloud/deploy/DeploymentClusterPlanner.java +++ b/api/src/main/java/com/cloud/deploy/DeploymentClusterPlanner.java @@ -68,6 +68,14 @@ public interface DeploymentClusterPlanner extends DeploymentPlanner { ConfigKey.Kind.Select, "random,firstfit,userdispersing,userconcentratedpod_random,userconcentratedpod_firstfit,firstfitleastconsumed"); + ConfigKey allowRoutersOnDedicatedResources = new ConfigKey<>( + "Advanced", + Boolean.class, + "allow.routers.on.dedicated.resources", + "false", + "Allow deploying virtual routers on dedicated Hosts, Clusters, Pods, and Zones", + true); + /** * This is called to determine list of possible clusters where a virtual * machine can be deployed. diff --git a/engine/schema/src/main/java/com/cloud/capacity/dao/CapacityDao.java b/engine/schema/src/main/java/com/cloud/capacity/dao/CapacityDao.java index 1bb79ce417aa..13c43a29bd3e 100644 --- a/engine/schema/src/main/java/com/cloud/capacity/dao/CapacityDao.java +++ b/engine/schema/src/main/java/com/cloud/capacity/dao/CapacityDao.java @@ -26,6 +26,7 @@ import com.cloud.utils.db.GenericDao; public interface CapacityDao extends GenericDao { + CapacityVO findByHostIdType(Long hostId, short capacityType); List listByHostIdTypes(Long hostId, List capacityTypes); @@ -40,7 +41,7 @@ public interface CapacityDao extends GenericDao { List findNonSharedStorageForClusterPodZone(Long zoneId, Long podId, Long clusterId); - Pair, Map> orderClustersByAggregateCapacity(long id, long vmId, short capacityType, boolean isZone); + Pair, Map> orderClustersByAggregateCapacity(long id, long vmId, short capacityType, boolean isVr, boolean allowRoutersOnDedicatedResources, boolean isZone); Ternary findCapacityByZoneAndHostTag(Long zoneId, String hostTag); diff --git a/engine/schema/src/main/java/com/cloud/capacity/dao/CapacityDaoImpl.java b/engine/schema/src/main/java/com/cloud/capacity/dao/CapacityDaoImpl.java index 5e7eee4566c1..3f216122c5be 100644 --- a/engine/schema/src/main/java/com/cloud/capacity/dao/CapacityDaoImpl.java +++ b/engine/schema/src/main/java/com/cloud/capacity/dao/CapacityDaoImpl.java @@ -87,6 +87,13 @@ public class CapacityDaoImpl extends GenericDaoBase implements "LEFT JOIN dedicated_resources dr_cluster ON dr_cluster.cluster_id IS NOT NULL AND dr_cluster.cluster_id = host.cluster_id " + "LEFT JOIN dedicated_resources dr_host ON dr_host.host_id IS NOT NULL AND dr_host.host_id = host.id "; + private static final String ORDER_CLUSTERS_BY_AGGREGATE_CAPACITY_INCLUDE_DEDICATED_TO_DOMAIN_JOIN_1 = + "JOIN host ON capacity.host_id = host.id " + + "LEFT JOIN (SELECT affinity_group.id, agvm.instance_id FROM affinity_group_vm_map agvm JOIN affinity_group ON agvm.affinity_group_id = affinity_group.id AND affinity_group.type='ExplicitDedication') AS ag ON ag.instance_id = ? " + + "LEFT JOIN dedicated_resources dr_pod ON dr_pod.pod_id IS NOT NULL AND dr_pod.pod_id = host.pod_id AND dr_pod.account_id IS NOT NULL " + + "LEFT JOIN dedicated_resources dr_cluster ON dr_cluster.cluster_id IS NOT NULL AND dr_cluster.cluster_id = host.cluster_id AND dr_cluster.account_id IS NOT NULL " + + "LEFT JOIN dedicated_resources dr_host ON dr_host.host_id IS NOT NULL AND dr_host.host_id = host.id AND dr_host.account_id IS NOT NULL "; + private static final String ORDER_CLUSTERS_BY_AGGREGATE_CAPACITY_JOIN_2 = " AND ((ag.id IS NULL AND dr_pod.pod_id IS NULL AND dr_cluster.cluster_id IS NULL AND dr_host.host_id IS NULL) OR " + "(dr_pod.affinity_group_id = ag.id OR dr_cluster.affinity_group_id = ag.id OR dr_host.affinity_group_id = ag.id))"; @@ -975,7 +982,7 @@ public boolean removeBy(Short capacityType, Long zoneId, Long podId, Long cluste } @Override - public Pair, Map> orderClustersByAggregateCapacity(long id, long vmId, short capacityTypeForOrdering, boolean isZone) { + public Pair, Map> orderClustersByAggregateCapacity(long id, long vmId, short capacityTypeForOrdering, boolean isVr, boolean allowRoutersOnDedicatedResources, boolean isZone) { TransactionLegacy txn = TransactionLegacy.currentTxn(); PreparedStatement pstmt = null; List result = new ArrayList(); @@ -987,7 +994,12 @@ public Pair, Map> orderClustersByAggregateCapacity(long sql.append(ORDER_CLUSTERS_BY_AGGREGATE_OVERCOMMIT_CAPACITY_PART1); } - sql.append(ORDER_CLUSTERS_BY_AGGREGATE_CAPACITY_JOIN_1); + if (isVr && allowRoutersOnDedicatedResources) { + sql.append(ORDER_CLUSTERS_BY_AGGREGATE_CAPACITY_INCLUDE_DEDICATED_TO_DOMAIN_JOIN_1); + } else { + sql.append(ORDER_CLUSTERS_BY_AGGREGATE_CAPACITY_JOIN_1); + } + if (isZone) { sql.append("WHERE capacity.capacity_state = 'Enabled' AND capacity.data_center_id = ?"); } else { @@ -1218,5 +1230,4 @@ public float findClusterConsumption(Long clusterId, short capacityType, long com } return 0; } - } diff --git a/plugins/deployment-planners/implicit-dedication/src/test/java/org/apache/cloudstack/implicitplanner/ImplicitPlannerTest.java b/plugins/deployment-planners/implicit-dedication/src/test/java/org/apache/cloudstack/implicitplanner/ImplicitPlannerTest.java index 2d2b4c78261e..cd3ec5e27514 100644 --- a/plugins/deployment-planners/implicit-dedication/src/test/java/org/apache/cloudstack/implicitplanner/ImplicitPlannerTest.java +++ b/plugins/deployment-planners/implicit-dedication/src/test/java/org/apache/cloudstack/implicitplanner/ImplicitPlannerTest.java @@ -366,7 +366,7 @@ private void initializeForTest(VirtualMachineProfileImpl vmProfile, DataCenterDe clusterCapacityMap.put(2L, 2048D); clusterCapacityMap.put(3L, 2048D); Pair, Map> clustersOrderedByCapacity = new Pair, Map>(clustersWithEnoughCapacity, clusterCapacityMap); - when(capacityDao.orderClustersByAggregateCapacity(dataCenterId, 12L, Capacity.CAPACITY_TYPE_CPU, true)).thenReturn(clustersOrderedByCapacity); + when(capacityDao.orderClustersByAggregateCapacity(dataCenterId, 12L, Capacity.CAPACITY_TYPE_CPU, false, false, true)).thenReturn(clustersOrderedByCapacity); List disabledClusters = new ArrayList(); List clustersWithDisabledPods = new ArrayList(); diff --git a/server/src/main/java/com/cloud/deploy/FirstFitPlanner.java b/server/src/main/java/com/cloud/deploy/FirstFitPlanner.java index abaf48400e23..9ca403139697 100644 --- a/server/src/main/java/com/cloud/deploy/FirstFitPlanner.java +++ b/server/src/main/java/com/cloud/deploy/FirstFitPlanner.java @@ -388,9 +388,10 @@ private List scanClustersForDestinationInZoneOrPod(long id, boolean isZone DataCenter dc = dcDao.findById(vm.getDataCenterId()); int requiredCpu = offering.getCpu() * offering.getSpeed(); long requiredRam = offering.getRamSize() * 1024L * 1024L; + boolean isVr = VirtualMachine.Type.DomainRouter.equals(vmProfile.getType()); //list clusters under this zone by cpu and ram capacity - Pair, Map> clusterCapacityInfo = listClustersByCapacity(id, vmProfile.getId(), requiredCpu, requiredRam, avoid, isZone); + Pair, Map> clusterCapacityInfo = listClustersByCapacity(id, vmProfile.getId(), requiredCpu, requiredRam, isVr, isZone); List prioritizedClusterIds = clusterCapacityInfo.first(); if (!prioritizedClusterIds.isEmpty()) { if (avoid.getClustersToAvoid() != null) { @@ -448,7 +449,7 @@ protected List reorderPods(Pair, Map> podCapacity return podIdsByCapacity; } - protected Pair, Map> listClustersByCapacity(long id, long vmId, int requiredCpu, long requiredRam, ExcludeList avoid, boolean isZone) { + protected Pair, Map> listClustersByCapacity(long id, long vmId, int requiredCpu, long requiredRam, boolean isVr, boolean isZone) { //look at the aggregate available cpu and ram per cluster //although an aggregate value may be false indicator that a cluster can host a vm, it will at the least eliminate those clusters which definitely cannot @@ -467,7 +468,7 @@ protected Pair, Map> listClustersByCapacity(long id, lo if (logger.isTraceEnabled()) { logger.trace("ClusterId List having enough CPU and RAM capacity: " + clusterIdswithEnoughCapacity); } - Pair, Map> result = capacityDao.orderClustersByAggregateCapacity(id, vmId, capacityType, isZone); + Pair, Map> result = capacityDao.orderClustersByAggregateCapacity(id, vmId, capacityType, isVr, allowRoutersOnDedicatedResources.value(), isZone); List clusterIdsOrderedByAggregateCapacity = result.first(); //only keep the clusters that have enough capacity to host this VM if (logger.isTraceEnabled()) { @@ -594,6 +595,6 @@ public String getConfigComponentName() { @Override public ConfigKey[] getConfigKeys() { - return new ConfigKey[] {ClusterCPUCapacityDisableThreshold, ClusterMemoryCapacityDisableThreshold, ClusterThresholdEnabled, VmAllocationAlgorithm}; + return new ConfigKey[] {ClusterCPUCapacityDisableThreshold, ClusterMemoryCapacityDisableThreshold, ClusterThresholdEnabled, VmAllocationAlgorithm, allowRoutersOnDedicatedResources}; } } diff --git a/server/src/test/java/com/cloud/vm/FirstFitPlannerTest.java b/server/src/test/java/com/cloud/vm/FirstFitPlannerTest.java index 7df4857f4fdf..369e38bc629e 100644 --- a/server/src/test/java/com/cloud/vm/FirstFitPlannerTest.java +++ b/server/src/test/java/com/cloud/vm/FirstFitPlannerTest.java @@ -304,7 +304,7 @@ private void initializeForTest(VirtualMachineProfileImpl vmProfile, DataCenterDe clusterCapacityMap.put(6L, 2048D); Pair, Map> clustersOrderedByCapacity = new Pair, Map>(clustersWithEnoughCapacity, clusterCapacityMap); - when(capacityDao.orderClustersByAggregateCapacity(dataCenterId, 12L, Capacity.CAPACITY_TYPE_CPU, true)).thenReturn(clustersOrderedByCapacity); + when(capacityDao.orderClustersByAggregateCapacity(dataCenterId, 12L, Capacity.CAPACITY_TYPE_CPU, false, false,true)).thenReturn(clustersOrderedByCapacity); List disabledClusters = new ArrayList(); List clustersWithDisabledPods = new ArrayList();