GaOrtiga commented on code in PR #7214:
URL: https://github.com/apache/cloudstack/pull/7214#discussion_r1409224353


##########
server/src/main/java/com/cloud/agent/manager/allocator/impl/FirstFitAllocator.java:
##########
@@ -205,6 +206,8 @@ public List<Host> allocateTo(VirtualMachineProfile 
vmProfile, DeploymentPlan pla
         // add all hosts that we are not considering to the avoid list
         List<HostVO> allhostsInCluster = 
_hostDao.listAllUpAndEnabledNonHAHosts(type, clusterId, podId, dcId, null);
         allhostsInCluster.removeAll(clusterHosts);
+        s_logger.debug(String.format("Adding hosts [%s] to the avoid set 
because these hosts does not support HA.",

Review Comment:
   ```suggestion
           s_logger.debug(String.format("Adding hosts [%s] to the avoid set 
because these hosts do not support HA.",
   ```



##########
server/src/main/java/com/cloud/deploy/DeploymentPlanningManagerImpl.java:
##########
@@ -808,109 +850,101 @@ public void 
checkForNonDedicatedResources(VirtualMachineProfile vmProfile, DataC
 
         //Only when the type is instance VM and not explicitly dedicated.
         if (vm.getType() == VirtualMachine.Type.User && !isExplicit) {
-            //add explicitly dedicated resources in avoidList
-            if (s_logger.isDebugEnabled()) {
-                s_logger.debug("Adding pods to avoid lists for non-explicit VM 
deployment: " + allPodsInDc);
-            }
-            avoids.addPodList(allPodsInDc);
-            if (s_logger.isDebugEnabled()) {
-                s_logger.debug("Adding clusters to avoid lists for 
non-explicit VM deployment: " + allClustersInDc);
-            }
-            avoids.addClusterList(allClustersInDc);
-            if (s_logger.isDebugEnabled()) {
-                s_logger.debug("Adding hosts to avoid lists for non-explicit 
VM deployment: " + allHostsInDc);
-            }
-            avoids.addHostList(allHostsInDc);
+            findAvoidSetForNonExplicitUserVM(avoids, isExplicit, vm, 
allPodsInDc, allClustersInDc, allHostsInDc);
         }
 
         //Handle the Virtual Router Case
         //No need to check the isExplicit. As both the cases are handled.
         if (vm.getType() == VirtualMachine.Type.DomainRouter) {
-            long vmAccountId = vm.getAccountId();
-            long vmDomainId = vm.getDomainId();
-
-            //Lists all explicitly dedicated resources from vm account ID or 
domain ID.
-            List<Long> allPodsFromDedicatedID = new ArrayList<Long>();
-            List<Long> allClustersFromDedicatedID = new ArrayList<Long>();
-            List<Long> allHostsFromDedicatedID = new ArrayList<Long>();
+            findAvoiSetForRouterVM(avoids, vm, allPodsInDc, allClustersInDc, 
allHostsInDc);
+        }
+    }
 
-            //Whether the dedicated resources belong to Domain or not. If not, 
it may belongs to Account or no dedication.
-            List<AffinityGroupDomainMapVO> domainGroupMappings = 
_affinityGroupDomainMapDao.listByDomain(vmDomainId);
+    private void findAvoiSetForRouterVM(ExcludeList avoids, VirtualMachine vm, 
List<Long> allPodsInDc, List<Long> allClustersInDc, List<Long> allHostsInDc) {
+        long vmAccountId = vm.getAccountId();
+        long vmDomainId = vm.getDomainId();
 
-            //For temporary storage and indexing.
-            List<DedicatedResourceVO> tempStorage;
+        List<Long> allPodsFromDedicatedID = new ArrayList<Long>();
+        List<Long> allClustersFromDedicatedID = new ArrayList<Long>();
+        List<Long> allHostsFromDedicatedID = new ArrayList<Long>();
 
-            if (domainGroupMappings == null || domainGroupMappings.isEmpty()) {
-                //The dedicated resource belongs to VM Account ID.
+        List<AffinityGroupDomainMapVO> domainGroupMappings = 
_affinityGroupDomainMapDao.listByDomain(vmDomainId);
 
-                tempStorage = _dedicatedDao.searchDedicatedPods(null, 
vmDomainId, vmAccountId, null, new Filter(DedicatedResourceVO.class, "id", 
true, 0L, 1L)).first();
+        List<DedicatedResourceVO> tempStorage;
 
-                for(DedicatedResourceVO vo : tempStorage) {
-                    allPodsFromDedicatedID.add(vo.getPodId());
-                }
+        if (domainGroupMappings == null || domainGroupMappings.isEmpty()) {
+            tempStorage = _dedicatedDao.searchDedicatedPods(null, vmDomainId, 
vmAccountId, null,
+                    new Filter(DedicatedResourceVO.class, "id", true, 0L, 
1L)).first();
 
-                tempStorage.clear();
-                tempStorage = _dedicatedDao.searchDedicatedClusters(null, 
vmDomainId, vmAccountId, null, new Filter(DedicatedResourceVO.class, "id", 
true, 0L, 1L)).first();
+            for (DedicatedResourceVO vo : tempStorage) {
+                allPodsFromDedicatedID.add(vo.getPodId());
+            }
 
-                for(DedicatedResourceVO vo : tempStorage) {
-                    allClustersFromDedicatedID.add(vo.getClusterId());
-                }
+            tempStorage.clear();
+            tempStorage = _dedicatedDao.searchDedicatedClusters(null, 
vmDomainId, vmAccountId, null,
+                    new Filter(DedicatedResourceVO.class, "id", true, 0L, 
1L)).first();
 
-                tempStorage.clear();
-                tempStorage = _dedicatedDao.searchDedicatedHosts(null, 
vmDomainId, vmAccountId, null, new Filter(DedicatedResourceVO.class, "id", 
true, 0L, 1L)).first();
+            for (DedicatedResourceVO vo : tempStorage) {
+                allClustersFromDedicatedID.add(vo.getClusterId());
+            }
 
-                for(DedicatedResourceVO vo : tempStorage) {
-                    allHostsFromDedicatedID.add(vo.getHostId());
-                }
+            tempStorage.clear();
+            tempStorage = _dedicatedDao.searchDedicatedHosts(null, vmDomainId, 
vmAccountId, null,
+                    new Filter(DedicatedResourceVO.class, "id", true, 0L, 
1L)).first();
 
-                //Remove the dedicated ones from main list
-                allPodsInDc.removeAll(allPodsFromDedicatedID);
-                allClustersInDc.removeAll(allClustersFromDedicatedID);
-                allHostsInDc.removeAll(allHostsFromDedicatedID);
+            for (DedicatedResourceVO vo : tempStorage) {
+                allHostsFromDedicatedID.add(vo.getHostId());
             }
-            else {
-                //The dedicated resource belongs to VM Domain ID or No 
dedication.
-
-                tempStorage = _dedicatedDao.searchDedicatedPods(null, 
vmDomainId, null, null, new Filter(DedicatedResourceVO.class, "id", true, 0L, 
1L)).first();
 
-                for(DedicatedResourceVO vo : tempStorage) {
-                    allPodsFromDedicatedID.add(vo.getPodId());
-                }
+            allPodsInDc.removeAll(allPodsFromDedicatedID);
+            allClustersInDc.removeAll(allClustersFromDedicatedID);
+            allHostsInDc.removeAll(allHostsFromDedicatedID);
+        } else {
+            tempStorage = _dedicatedDao.searchDedicatedPods(null, vmDomainId, 
null, null,
+                    new Filter(DedicatedResourceVO.class, "id", true, 0L, 
1L)).first();
 
-                tempStorage.clear();
-                tempStorage = _dedicatedDao.searchDedicatedClusters(null, 
vmDomainId, null, null, new Filter(DedicatedResourceVO.class, "id", true, 0L, 
1L)).first();
+            for (DedicatedResourceVO vo : tempStorage) {
+                allPodsFromDedicatedID.add(vo.getPodId());
+            }
 
-                for(DedicatedResourceVO vo : tempStorage) {
-                    allClustersFromDedicatedID.add(vo.getClusterId());
-                }
+            tempStorage.clear();
+            tempStorage = _dedicatedDao.searchDedicatedClusters(null, 
vmDomainId, null, null,
+                    new Filter(DedicatedResourceVO.class, "id", true, 0L, 
1L)).first();
 
-                tempStorage.clear();
-                tempStorage = _dedicatedDao.searchDedicatedHosts(null, 
vmDomainId, null, null, new Filter(DedicatedResourceVO.class, "id", true, 0L, 
1L)).first();
+            for (DedicatedResourceVO vo : tempStorage) {
+                allClustersFromDedicatedID.add(vo.getClusterId());
+            }
 
-                for(DedicatedResourceVO vo : tempStorage) {
-                    allHostsFromDedicatedID.add(vo.getHostId());
-                }
+            tempStorage.clear();
+            tempStorage = _dedicatedDao.searchDedicatedHosts(null, vmDomainId, 
null, null,
+                    new Filter(DedicatedResourceVO.class, "id", true, 0L, 
1L)).first();
 
-                //Remove the dedicated ones from main list
-                allPodsInDc.removeAll(allPodsFromDedicatedID);
-                allClustersInDc.removeAll(allClustersFromDedicatedID);
-                allHostsInDc.removeAll(allHostsFromDedicatedID);
+            for (DedicatedResourceVO vo : tempStorage) {
+                allHostsFromDedicatedID.add(vo.getHostId());
             }
 
-            //Add in avoid list or no addition if no dedication
-            if (s_logger.isDebugEnabled()) {
-                s_logger.debug("Adding pods to avoid lists: " + allPodsInDc);
-            }
-            avoids.addPodList(allPodsInDc);
-            if (s_logger.isDebugEnabled()) {
-                s_logger.debug("Adding clusters to avoid lists: " + 
allClustersInDc);
-            }
-            avoids.addClusterList(allClustersInDc);
-            if (s_logger.isDebugEnabled()) {
-                s_logger.debug("Adding hosts to avoid lists: " + allHostsInDc);
-            }
-            avoids.addHostList(allHostsInDc);
+            allPodsInDc.removeAll(allPodsFromDedicatedID);
+            allClustersInDc.removeAll(allClustersFromDedicatedID);
+            allHostsInDc.removeAll(allHostsFromDedicatedID);
         }
+
+        s_logger.debug(LogUtils.logGsonWithoutException(
+                "Adding pods [%s], clusters [%s] and hosts [%s] to the avoid 
list in the deploy process of VR VM [%s], "
+                        + "because this VM is not dedicated to this 
components.",
+                allPodsInDc, allClustersInDc, allHostsInDc, vm.getUuid()));
+        avoids.addPodList(allPodsInDc);
+        avoids.addClusterList(allClustersInDc);
+        avoids.addHostList(allHostsInDc);
+    }
+
+    private void findAvoidSetForNonExplicitUserVM(ExcludeList avoids, boolean 
isExplicit, VirtualMachine vm, List<Long> allPodsInDc, List<Long> 
allClustersInDc, List<Long> allHostsInDc) {
+        s_logger.debug(LogUtils.logGsonWithoutException(
+                "Adding pods [%s], clusters [%s] and hosts [%s] to the avoid 
list in the deploy process of user VM [%s], "
+                        + "because this VM is not explicit dedicated to this 
components.",

Review Comment:
   ```suggestion
                           + "because this VM is not explicitly dedicated to 
this components.",
   ```



##########
server/src/main/java/com/cloud/deploy/DeploymentPlanningManagerImpl.java:
##########
@@ -614,6 +455,200 @@ public DeployDestination 
planDeployment(VirtualMachineProfile vmProfile, Deploym
         return dest;
     }
 
+    private DeployDestination deployInVmLastHost(VirtualMachineProfile 
vmProfile, DeploymentPlan plan, ExcludeList avoids,
+            DeploymentPlanner planner, VirtualMachine vm, DataCenter dc, 
ServiceOffering offering, int cpuRequested, long ramRequested,
+            boolean volumesRequireEncryption) throws 
InsufficientServerCapacityException {
+        HostVO host = _hostDao.findById(vm.getLastHostId());
+        _hostDao.loadHostTags(host);
+        _hostDao.loadDetails(host);
+
+        if (canUseLastHost(host, avoids, plan, vm, offering, 
volumesRequireEncryption)) {
+            if (host.getStatus() != Status.Up) {
+                s_logger.debug(String.format("Cannot deploy VM [%s] to the 
last host [%s] because this host is not in UP state or is not enabled. Host 
current status [%s] and resource status [%s].",
+                        vm.getUuid(), host.getUuid(), host.getState().name(), 
host.getResourceState()));
+                return null;
+            }
+            if (checkVmProfileAndHost(vmProfile, host)) {
+                long cluster_id = host.getClusterId();
+                ClusterDetailsVO cluster_detail_cpu = 
_clusterDetailsDao.findDetail(cluster_id, "cpuOvercommitRatio");
+                ClusterDetailsVO cluster_detail_ram = 
_clusterDetailsDao.findDetail(cluster_id, "memoryOvercommitRatio");
+                Float cpuOvercommitRatio = 
Float.parseFloat(cluster_detail_cpu.getValue());
+                Float memoryOvercommitRatio = 
Float.parseFloat(cluster_detail_ram.getValue());
+
+                boolean hostHasCpuCapability, hostHasCapacity = false;
+                hostHasCpuCapability = 
_capacityMgr.checkIfHostHasCpuCapability(host.getId(), offering.getCpu(), 
offering.getSpeed());
+
+                if (hostHasCpuCapability) {
+                    // first check from reserved capacity
+                    hostHasCapacity = 
_capacityMgr.checkIfHostHasCapacity(host.getId(), cpuRequested, ramRequested, 
true, cpuOvercommitRatio, memoryOvercommitRatio, true);
+
+                    // if not reserved, check the free capacity
+                    if (!hostHasCapacity)
+                        hostHasCapacity = 
_capacityMgr.checkIfHostHasCapacity(host.getId(), cpuRequested, ramRequested, 
false, cpuOvercommitRatio, memoryOvercommitRatio, true);
+                    }
+
+                boolean displayStorage = 
getDisplayStorageFromVmProfile(vmProfile);
+                if (!hostHasCapacity || !hostHasCpuCapability) {
+                    s_logger.debug(String.format("Cannot deploy VM [%s] to the 
last host [%s] because this host does not have enough capacity to deploy this 
VM.", vm.getUuid(), host.getUuid()));
+                    return null;
+                }
+                s_logger.debug(String.format("Last host [%s] of VM [%s] is UP 
and has enough capacity. Checking for suitable pools for this host under zone 
[%s], pod [%s] and cluster [%s].",
+                        host.getUuid(), vm.getUuid(), host.getDataCenterId(), 
host.getPodId(), host.getClusterId()));
+
+                Pod pod = _podDao.findById(host.getPodId());
+                Cluster cluster = _clusterDao.findById(host.getClusterId());
+                if (vm.getHypervisorType() == HypervisorType.BareMetal) {
+                    DeployDestination dest = new DeployDestination(dc, pod, 
cluster, host, new HashMap<Volume, StoragePool>(), displayStorage);
+                    s_logger.debug("Returning Deployment Destination: " + 
dest);
+                    return dest;
+                }
+
+                // search for storage under the zone, pod, cluster
+                // of
+                // the last host.
+                DataCenterDeployment lastPlan = new 
DataCenterDeployment(host.getDataCenterId(),
+                        host.getPodId(), host.getClusterId(), host.getId(), 
plan.getPoolId(), null);
+                Pair<Map<Volume, List<StoragePool>>, List<Volume>> result = 
findSuitablePoolsForVolumes(
+                        vmProfile, lastPlan, avoids, 
HostAllocator.RETURN_UPTO_ALL);
+                Map<Volume, List<StoragePool>> suitableVolumeStoragePools = 
result.first();
+                List<Volume> readyAndReusedVolumes = result.second();
+
+                // choose the potential pool for this VM for this
+                // host
+                if (suitableVolumeStoragePools.isEmpty()) {
+                    s_logger.debug(String.format("Cannot find suitable storage 
pools in host [%s] to deploy VM [%s]", host.getUuid(), vm.getUuid()));
+                    return null;
+                }
+                List<Host> suitableHosts = new ArrayList<Host>();
+                suitableHosts.add(host);
+                Pair<Host, Map<Volume, StoragePool>> potentialResources = 
findPotentialDeploymentResources(
+                        suitableHosts, suitableVolumeStoragePools, avoids,
+                        getPlannerUsage(planner, vmProfile, plan, avoids), 
readyAndReusedVolumes, plan.getPreferredHosts(), vm);
+                if (potentialResources != null) {
+                    Map<Volume, StoragePool> storageVolMap = 
potentialResources.second();
+                    // remove the reused vol<->pool from
+                    // destination, since we don't have to
+                    // prepare
+                    // this volume.
+                    for (Volume vol : readyAndReusedVolumes) {
+                        storageVolMap.remove(vol);
+                    }
+                    DeployDestination dest = new DeployDestination(dc, pod, 
cluster, host, storageVolMap, displayStorage);
+                    s_logger.debug("Returning Deployment Destination: " + 
dest);
+                    return dest;
+                }
+            }
+        }
+        s_logger.debug(String.format("Cannot choose the last host to deploy 
this VM %s", vm));
+        return null;
+    }
+
+    private boolean canUseLastHost(HostVO host, ExcludeList avoids, 
DeploymentPlan plan, VirtualMachine vm, ServiceOffering offering, boolean 
volumesRequireEncryption) {
+        if (host == null) {
+            s_logger.warn(String.format("Could not find last host of VM [%s] 
with id [%s]. Skipping this and trying other available hosts.", vm.getUuid(), 
vm.getLastHostId()));
+            return false;
+        }
+
+        if (avoids.shouldAvoid(host)) {
+            s_logger.warn(String.format("The last host [%s] of VM [%s] is in 
the avoid set. Skipping this and trying other available hosts.", 
host.getUuid(), vm.getUuid()));
+            return false;
+        }
+
+        if (plan.getClusterId() != null && host.getClusterId() != null && 
!plan.getClusterId().equals(host.getClusterId())) {
+            s_logger.debug(String.format("The last host [%s] of VM [%s] cannot 
be picked, as the plan [%s] specifies a different cluster [%s] to deploy this 
VM. Skipping this and trying other available hosts.",
+                    
ReflectionToStringBuilderUtils.reflectOnlySelectedFields(host, "uuid", 
"clusterId"), vm.getUuid(), plan.getClass().getSimpleName(), 
plan.getClusterId()));
+            return false;
+        }
+
+        if (_capacityMgr.checkIfHostReachMaxGuestLimit(host)) {
+            s_logger.debug(String.format("Cannot deploy VM [%s] in the last 
host [%s] because this host already has the max number of running VMs (users 
and system VMs). Skipping this and trying other available hosts.",
+                    vm.getUuid(), host.getUuid()));
+            return false;
+        }
+
+        ServiceOfferingDetailsVO offeringDetails = 
_serviceOfferingDetailsDao.findDetail(offering.getId(), 
GPU.Keys.vgpuType.toString());
+        ServiceOfferingDetailsVO groupName = 
_serviceOfferingDetailsDao.findDetail(offering.getId(), 
GPU.Keys.pciDevice.toString());
+        if (offeringDetails != null && 
!_resourceMgr.isGPUDeviceAvailable(host.getId(), groupName.getValue(), 
offeringDetails.getValue())) {
+            s_logger.debug(String.format("Cannot deploy VM [%s] in the last 
host [%s] because this host does not have the required GPU devices available. 
Skipping this and trying other available hosts.",
+                    vm.getUuid(), host.getUuid()));
+            return false;
+        }
+
+        if (volumesRequireEncryption && 
!Boolean.parseBoolean(host.getDetail(Host.HOST_VOLUME_ENCRYPTION))) {
+            s_logger.warn(String.format("The last host of this VM %s does not 
support volume encryption, which is required by this VM.", host));
+            return false;
+        }
+        return true;
+    }
+
+    private DeployDestination 
deployInSpecifiedHostWithoutHA(VirtualMachineProfile vmProfile, DeploymentPlan 
plan, ExcludeList avoids,
+            DeploymentPlanner planner, VirtualMachine vm, DataCenter dc, 
String uefiFlag)
+            throws InsufficientServerCapacityException {
+        Long hostIdSpecified = plan.getHostId();
+        s_logger.debug(String.format("DeploymentPlan [%s] has specified host 
[%s] without HA flag. Choosing this host to deploy VM [%s].", 
plan.getClass().getSimpleName(), hostIdSpecified, vm.getUuid()));
+
+        HostVO host = _hostDao.findById(hostIdSpecified);
+        if (host != null && StringUtils.isNotBlank(uefiFlag) && 
"yes".equalsIgnoreCase(uefiFlag)) {
+            _hostDao.loadDetails(host);
+            if (MapUtils.isNotEmpty(host.getDetails()) && 
host.getDetails().containsKey(Host.HOST_UEFI_ENABLE) && 
"false".equalsIgnoreCase(host.getDetails().get(Host.HOST_UEFI_ENABLE))) {
+                s_logger.debug(String.format("Cannot deploy VM [%s] to 
specified host [%s] because this host does not support UEFI VM deployment, 
returning.", vm.getUuid(), host.getUuid()));
+                return null;
+
+            }
+        }
+        if (host == null) {
+            s_logger.debug(String.format("Cannot deploy VM [%s] to host [%s] 
because this host cannot be found.", vm.getUuid(), hostIdSpecified));
+            return null;
+        }
+        if (avoids.shouldAvoid(host)) {
+            s_logger.debug(String.format("Cannot deploy VM [%s] to host [%s] 
because this host is in the avoid set.", vm.getUuid(), host.getUuid()));
+            return null;
+        }
+
+        s_logger.debug(String.format("Trying to find suitable pools for host 
[%s] under pod [%s], cluster [%s] and zone [%s], to deploy VM [%s].",
+                host.getUuid(), host.getDataCenterId(), host.getPodId(), 
host.getClusterId(), vm.getUuid()));
+
+        Pod pod = _podDao.findById(host.getPodId());
+        Cluster cluster = _clusterDao.findById(host.getClusterId());
+
+        boolean displayStorage = getDisplayStorageFromVmProfile(vmProfile);
+        if (vm.getHypervisorType() == HypervisorType.BareMetal) {
+            DeployDestination dest = new DeployDestination(dc, pod, cluster, 
host, new HashMap<Volume, StoragePool>(),
+                    displayStorage);
+            s_logger.debug("Returning Deployment Destination: " + dest);
+            return dest;
+        }
+
+        DataCenterDeployment lastPlan = new 
DataCenterDeployment(host.getDataCenterId(), host.getPodId(),
+                host.getClusterId(), hostIdSpecified, plan.getPoolId(), null, 
plan.getReservationContext());
+
+        Pair<Map<Volume, List<StoragePool>>, List<Volume>> result = 
findSuitablePoolsForVolumes(vmProfile, lastPlan,
+                avoids, HostAllocator.RETURN_UPTO_ALL);
+        Map<Volume, List<StoragePool>> suitableVolumeStoragePools = 
result.first();
+        List<Volume> readyAndReusedVolumes = result.second();
+
+        if (!suitableVolumeStoragePools.isEmpty()) {
+            List<Host> suitableHosts = new ArrayList<Host>();
+            suitableHosts.add(host);
+            Pair<Host, Map<Volume, StoragePool>> potentialResources = 
findPotentialDeploymentResources(suitableHosts,
+                    suitableVolumeStoragePools, avoids, 
getPlannerUsage(planner, vmProfile, plan, avoids),
+                    readyAndReusedVolumes, plan.getPreferredHosts(), vm);
+            if (potentialResources != null) {
+                pod = _podDao.findById(host.getPodId());
+                cluster = _clusterDao.findById(host.getClusterId());
+                Map<Volume, StoragePool> storageVolMap = 
potentialResources.second();
+                for (Volume vol : readyAndReusedVolumes) {
+                    storageVolMap.remove(vol);
+                }
+                DeployDestination dest = new DeployDestination(dc, pod, 
cluster, host, storageVolMap, displayStorage);
+                s_logger.debug("Returning Deployment Destination: " + dest);
+                return dest;
+            }
+        }
+        s_logger.debug(String.format("Cannot deploy VM [%s] under host [%s], 
because there are no suitable pools found.", vmProfile.getUuid(), 
host.getUuid()));

Review Comment:
   ```suggestion
           s_logger.debug(String.format("Cannot deploy VM [%s] under host [%s], 
because no suitable pools were found.", vmProfile.getUuid(), host.getUuid()));
   ```



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to