From cd3851946b1e173f6134741d0b50dc27c7890760 Mon Sep 17 00:00:00 2001 From: Pearl Dsilva Date: Fri, 9 Apr 2021 12:34:10 +0530 Subject: [PATCH 1/3] tests: Fix k8s test failures on VMware (#4896) This PR fixes the k8s test failures noticed on vmware. Co-authored-by: Pearl Dsilva Co-authored-by: Abhishek Kumar --- ...esClusterResourceModifierActionWorker.java | 1 - .../smoke/test_kubernetes_clusters.py | 106 +++++++++++------- 2 files changed, 63 insertions(+), 44 deletions(-) diff --git a/plugins/integrations/kubernetes-service/src/main/java/com/cloud/kubernetes/cluster/actionworkers/KubernetesClusterResourceModifierActionWorker.java b/plugins/integrations/kubernetes-service/src/main/java/com/cloud/kubernetes/cluster/actionworkers/KubernetesClusterResourceModifierActionWorker.java index c771cf34561..324143cffcf 100644 --- a/plugins/integrations/kubernetes-service/src/main/java/com/cloud/kubernetes/cluster/actionworkers/KubernetesClusterResourceModifierActionWorker.java +++ b/plugins/integrations/kubernetes-service/src/main/java/com/cloud/kubernetes/cluster/actionworkers/KubernetesClusterResourceModifierActionWorker.java @@ -307,7 +307,6 @@ public class KubernetesClusterResourceModifierActionWorker extends KubernetesClu Field f = startVm.getClass().getDeclaredField("id"); f.setAccessible(true); f.set(startVm, vm.getId()); - resizeNodeVolume(vm); userVmService.startVirtualMachine(startVm); if (LOGGER.isInfoEnabled()) { LOGGER.info(String.format("Started VM : %s in the Kubernetes cluster : %s", vm.getDisplayName(), kubernetesCluster.getName())); diff --git a/test/integration/smoke/test_kubernetes_clusters.py b/test/integration/smoke/test_kubernetes_clusters.py index f2f0471cfbf..5ea5d772de0 100644 --- a/test/integration/smoke/test_kubernetes_clusters.py +++ b/test/integration/smoke/test_kubernetes_clusters.py @@ -37,6 +37,7 @@ from marvin.codes import PASS, FAILED from marvin.lib.base import (Template, ServiceOffering, Account, + StoragePool, Configurations) from marvin.lib.utils import (cleanup_resources, validateList, @@ -81,7 +82,7 @@ class TestKubernetesCluster(cloudstackTestCase): "cloud.kubernetes.service.enabled", "true") cls.restartServer() - + cls.updateVmwareSettings(False) cls.cks_template = None cls.initial_configuration_cks_template_name = None cls.cks_service_offering = None @@ -120,12 +121,13 @@ class TestKubernetesCluster(cloudstackTestCase): (cls.services["cks_kubernetes_versions"]["1.16.3"]["semanticversion"], cls.services["cks_kubernetes_versions"]["1.16.3"]["url"], e)) if cls.setup_failed == False: - cls.cks_template = cls.getKubernetesTemplate() + cls.cks_template, existAlready = cls.getKubernetesTemplate() if cls.cks_template == FAILED: assert False, "getKubernetesTemplate() failed to return template for hypervisor %s" % cls.hypervisor cls.setup_failed = True else: - cls._cleanup.append(cls.cks_template) + if not existAlready: + cls._cleanup.append(cls.cks_template) if cls.setup_failed == False: cls.initial_configuration_cks_template_name = Configurations.list(cls.apiclient, @@ -162,8 +164,6 @@ class TestKubernetesCluster(cloudstackTestCase): cls.debug("Error: Exception during cleanup for added Kubernetes supported versions: %s" % e) try: # Restore original CKS template - if cls.cks_template != None: - cls.cks_template.delete(cls.apiclient) if cls.hypervisorNotSupported == False and cls.initial_configuration_cks_template_name != None: Configurations.update(cls.apiclient, cls.cks_template_name_key, @@ -176,6 +176,8 @@ class TestKubernetesCluster(cloudstackTestCase): "false") cls.restartServer() + cls.updateVmwareSettings(True) + cleanup_resources(cls.apiclient, cls._cleanup) except Exception as e: raise Exception("Warning: Exception during cleanup : %s" % e) @@ -183,6 +185,24 @@ class TestKubernetesCluster(cloudstackTestCase): raise Exception("Warning: Exception during cleanup, unable to delete Kubernetes supported versions") return + @classmethod + def updateVmwareSettings(cls, tearDown): + value = "false" + if not tearDown: + value = "true" + if cls.hypervisor.lower() == 'vmware': + Configurations.update(cls.apiclient, + "vmware.create.full.clone", + value) + allStoragePools = StoragePool.list( + cls.apiclient + ) + for pool in allStoragePools: + Configurations.update(cls.apiclient, + storageid=pool.id, + name="vmware.create.full.clone", + value=value) + @classmethod def restartServer(cls): """Restart management server""" @@ -227,7 +247,7 @@ class TestKubernetesCluster(cloudstackTestCase): if hypervisor not in cks_templates.keys(): cls.debug("Provided hypervisor has no CKS template") - return FAILED + return FAILED, False cks_template = cks_templates[hypervisor] @@ -244,13 +264,13 @@ class TestKubernetesCluster(cloudstackTestCase): details = [{"keyboard": "us"}] template = Template.register(cls.apiclient, cks_template, zoneid=cls.zone.id, hypervisor=hypervisor.lower(), randomize_name=False, details=details) template.download(cls.apiclient) - return template + return template, False for template in templates: if template.isready and template.ispublic: - return Template(template.__dict__) + return Template(template.__dict__), True - return FAILED + return FAILED, False @classmethod def waitForKubernetesSupportedVersionIsoReadyState(cls, version_id, retries=30, interval=60): @@ -313,38 +333,7 @@ class TestKubernetesCluster(cloudstackTestCase): @attr(tags=["advanced", "smoke"], required_hardware="true") @skipTestIf("hypervisorNotSupported") - def test_01_deploy_kubernetes_cluster(self): - """Test to deploy a new Kubernetes cluster - - # Validate the following: - # 1. createKubernetesCluster should return valid info for new cluster - # 2. The Cloud Database contains the valid information - # 3. stopKubernetesCluster should stop the cluster - """ - if self.setup_failed == True: - self.fail("Setup incomplete") - global k8s_cluster - k8s_cluster = self.getValidKubernetesCluster() - - self.debug("Kubernetes cluster with ID: %s successfully deployed, now stopping it" % k8s_cluster.id) - - self.stopAndVerifyKubernetesCluster(k8s_cluster.id) - - self.debug("Kubernetes cluster with ID: %s successfully stopped, now starting it again" % k8s_cluster.id) - - try: - k8s_cluster = self.startKubernetesCluster(k8s_cluster.id) - except Exception as e: - self.deleteKubernetesClusterAndVerify(k8s_cluster.id, False, True) - self.fail("Failed to start Kubernetes cluster due to: %s" % e) - - self.verifyKubernetesClusterState(k8s_cluster, 'Running') - - return - - @attr(tags=["advanced", "smoke"], required_hardware="true") - @skipTestIf("hypervisorNotSupported") - def test_02_invalid_upgrade_kubernetes_cluster(self): + def test_01_invalid_upgrade_kubernetes_cluster(self): """Test to check for failure while tying to upgrade a Kubernetes cluster to a lower version # Validate the following: @@ -364,12 +353,13 @@ class TestKubernetesCluster(cloudstackTestCase): self.fail("Kubernetes cluster upgraded to a lower Kubernetes supported version. Must be an error.") except Exception as e: self.debug("Upgrading Kubernetes cluster with invalid Kubernetes supported version check successful, API failure: %s" % e) + self.deleteKubernetesClusterAndVerify(k8s_cluster.id, False, True) return @attr(tags=["advanced", "smoke"], required_hardware="true") @skipTestIf("hypervisorNotSupported") - def test_03_deploy_and_upgrade_kubernetes_cluster(self): + def test_02_deploy_and_upgrade_kubernetes_cluster(self): """Test to deploy a new Kubernetes cluster and upgrade it to newer version # Validate the following: @@ -395,7 +385,7 @@ class TestKubernetesCluster(cloudstackTestCase): @attr(tags=["advanced", "smoke"], required_hardware="true") @skipTestIf("hypervisorNotSupported") - def test_04_deploy_and_scale_kubernetes_cluster(self): + def test_03_deploy_and_scale_kubernetes_cluster(self): """Test to deploy a new Kubernetes cluster and check for failure while tying to scale it # Validate the following: @@ -431,6 +421,36 @@ class TestKubernetesCluster(cloudstackTestCase): return + @attr(tags=["advanced", "smoke"], required_hardware="true") + @skipTestIf("hypervisorNotSupported") + def test_04_basic_lifecycle_kubernetes_cluster(self): + """Test to deploy a new Kubernetes cluster + + # Validate the following: + # 1. createKubernetesCluster should return valid info for new cluster + # 2. The Cloud Database contains the valid information + # 3. stopKubernetesCluster should stop the cluster + """ + if self.setup_failed == True: + self.fail("Setup incomplete") + global k8s_cluster + k8s_cluster = self.getValidKubernetesCluster() + + self.debug("Kubernetes cluster with ID: %s successfully deployed, now stopping it" % k8s_cluster.id) + + self.stopAndVerifyKubernetesCluster(k8s_cluster.id) + + self.debug("Kubernetes cluster with ID: %s successfully stopped, now starting it again" % k8s_cluster.id) + + try: + k8s_cluster = self.startKubernetesCluster(k8s_cluster.id) + except Exception as e: + self.deleteKubernetesClusterAndVerify(k8s_cluster.id, False, True) + self.fail("Failed to start Kubernetes cluster due to: %s" % e) + + self.verifyKubernetesClusterState(k8s_cluster, 'Running') + return + @attr(tags=["advanced", "smoke"], required_hardware="true") @skipTestIf("hypervisorNotSupported") def test_05_delete_kubernetes_cluster(self): From cd60b8d97df0a5a31f41b4d810ff949e2d73beb1 Mon Sep 17 00:00:00 2001 From: Abhishek Kumar Date: Fri, 9 Apr 2021 12:35:58 +0530 Subject: [PATCH 2/3] host-allocator: check capacity for suitable hosts (#4884) Fixes #4517 Adds capacity checks for RandomAllocator (host allocator) Factors out host cpu capability and capacity check wrt serviceoffering code into CapacityManager. Signed-off-by: Abhishek Kumar --- .../com/cloud/capacity/CapacityManager.java | 4 + .../allocator/impl/RandomAllocator.java | 193 +++++++++--------- .../allocator/impl/FirstFitAllocator.java | 25 +-- .../cloud/capacity/CapacityManagerImpl.java | 18 ++ 4 files changed, 119 insertions(+), 121 deletions(-) diff --git a/engine/components-api/src/main/java/com/cloud/capacity/CapacityManager.java b/engine/components-api/src/main/java/com/cloud/capacity/CapacityManager.java index 8827ca41d3c..251f2e27277 100644 --- a/engine/components-api/src/main/java/com/cloud/capacity/CapacityManager.java +++ b/engine/components-api/src/main/java/com/cloud/capacity/CapacityManager.java @@ -22,8 +22,10 @@ import org.apache.cloudstack.framework.config.ConfigKey; import org.apache.cloudstack.storage.datastore.db.StoragePoolVO; import com.cloud.host.Host; +import com.cloud.offering.ServiceOffering; import com.cloud.service.ServiceOfferingVO; import com.cloud.storage.VMTemplateVO; +import com.cloud.utils.Pair; import com.cloud.vm.VirtualMachine; /** @@ -141,4 +143,6 @@ public interface CapacityManager { long getUsedBytes(StoragePoolVO pool); long getUsedIops(StoragePoolVO pool); + + Pair checkIfHostHasCpuCapabilityAndCapacity(Host host, ServiceOffering offering, boolean considerReservedCapacity); } diff --git a/plugins/host-allocators/random/src/main/java/com/cloud/agent/manager/allocator/impl/RandomAllocator.java b/plugins/host-allocators/random/src/main/java/com/cloud/agent/manager/allocator/impl/RandomAllocator.java index 1b373f7e73d..8a46d10a7b5 100644 --- a/plugins/host-allocators/random/src/main/java/com/cloud/agent/manager/allocator/impl/RandomAllocator.java +++ b/plugins/host-allocators/random/src/main/java/com/cloud/agent/manager/allocator/impl/RandomAllocator.java @@ -22,10 +22,14 @@ import java.util.List; import javax.inject.Inject; +import org.apache.commons.collections.CollectionUtils; import org.apache.log4j.Logger; import org.springframework.stereotype.Component; import com.cloud.agent.manager.allocator.HostAllocator; +import com.cloud.capacity.CapacityManager; +import com.cloud.dc.ClusterDetailsDao; +import com.cloud.dc.dao.ClusterDao; import com.cloud.deploy.DeploymentPlan; import com.cloud.deploy.DeploymentPlanner.ExcludeList; import com.cloud.host.Host; @@ -34,6 +38,7 @@ import com.cloud.host.HostVO; import com.cloud.host.dao.HostDao; import com.cloud.offering.ServiceOffering; import com.cloud.resource.ResourceManager; +import com.cloud.utils.Pair; import com.cloud.utils.component.AdapterBase; import com.cloud.vm.VirtualMachine; import com.cloud.vm.VirtualMachineProfile; @@ -45,6 +50,81 @@ public class RandomAllocator extends AdapterBase implements HostAllocator { private HostDao _hostDao; @Inject private ResourceManager _resourceMgr; + @Inject + private ClusterDao clusterDao; + @Inject + private ClusterDetailsDao clusterDetailsDao; + @Inject + private CapacityManager capacityManager; + + private List findSuitableHosts(VirtualMachineProfile vmProfile, DeploymentPlan plan, Type type, + ExcludeList avoid, List hosts, int returnUpTo, + boolean considerReservedCapacity) { + long dcId = plan.getDataCenterId(); + Long podId = plan.getPodId(); + Long clusterId = plan.getClusterId(); + ServiceOffering offering = vmProfile.getServiceOffering(); + List hostsCopy = null; + List suitableHosts = new ArrayList(); + + if (type == Host.Type.Storage) { + return suitableHosts; + } + String hostTag = offering.getHostTag(); + if (hostTag != null) { + s_logger.debug("Looking for hosts in dc: " + dcId + " pod:" + podId + " cluster:" + clusterId + " having host tag:" + hostTag); + } else { + s_logger.debug("Looking for hosts in dc: " + dcId + " pod:" + podId + " cluster:" + clusterId); + } + if (hosts != null) { + // retain all computing hosts, regardless of whether they support routing...it's random after all + hostsCopy = new ArrayList(hosts); + if (hostTag != null) { + hostsCopy.retainAll(_hostDao.listByHostTag(type, clusterId, podId, dcId, hostTag)); + } else { + hostsCopy.retainAll(_resourceMgr.listAllUpAndEnabledHosts(type, clusterId, podId, dcId)); + } + } else { + // list all computing hosts, regardless of whether they support routing...it's random after all + hostsCopy = new ArrayList(); + if (hostTag != null) { + hostsCopy = _hostDao.listByHostTag(type, clusterId, podId, dcId, hostTag); + } else { + hostsCopy = _resourceMgr.listAllUpAndEnabledHosts(type, clusterId, podId, dcId); + } + } + s_logger.debug("Random Allocator found " + hostsCopy.size() + " hosts"); + if (hostsCopy.size() == 0) { + return suitableHosts; + } + Collections.shuffle(hostsCopy); + for (Host host : hostsCopy) { + if (suitableHosts.size() == returnUpTo) { + break; + } + if (avoid.shouldAvoid(host)) { + if (s_logger.isDebugEnabled()) { + s_logger.debug("Host name: " + host.getName() + ", hostId: " + host.getId() + " is in avoid set, skipping this and trying other available hosts"); + } + continue; + } + Pair cpuCapabilityAndCapacity = capacityManager.checkIfHostHasCpuCapabilityAndCapacity(host, offering, considerReservedCapacity); + if (!cpuCapabilityAndCapacity.first() || !cpuCapabilityAndCapacity.second()) { + if (s_logger.isDebugEnabled()) { + s_logger.debug("Not using host " + host.getId() + "; host has cpu capability? " + cpuCapabilityAndCapacity.first() + ", host has capacity?" + cpuCapabilityAndCapacity.second()); + } + continue; + } + if (s_logger.isDebugEnabled()) { + s_logger.debug("Found a suitable host, adding to list: " + host.getId()); + } + suitableHosts.add(host); + } + if (s_logger.isDebugEnabled()) { + s_logger.debug("Random Host Allocator returning " + suitableHosts.size() + " suitable hosts"); + } + return suitableHosts; + } @Override public List allocateTo(VirtualMachineProfile vmProfile, DeploymentPlan plan, Type type, ExcludeList avoid, int returnUpTo) { @@ -52,113 +132,22 @@ public class RandomAllocator extends AdapterBase implements HostAllocator { } @Override - public List allocateTo(VirtualMachineProfile vmProfile, DeploymentPlan plan, Type type, ExcludeList avoid, List hosts, int returnUpTo, - boolean considerReservedCapacity) { - long dcId = plan.getDataCenterId(); - Long podId = plan.getPodId(); - Long clusterId = plan.getClusterId(); - ServiceOffering offering = vmProfile.getServiceOffering(); - List suitableHosts = new ArrayList(); - List hostsCopy = new ArrayList(hosts); - - if (type == Host.Type.Storage) { - return suitableHosts; - } - - String hostTag = offering.getHostTag(); - if (hostTag != null) { - s_logger.debug("Looking for hosts in dc: " + dcId + " pod:" + podId + " cluster:" + clusterId + " having host tag:" + hostTag); - } else { - s_logger.debug("Looking for hosts in dc: " + dcId + " pod:" + podId + " cluster:" + clusterId); - } - - // list all computing hosts, regardless of whether they support routing...it's random after all - if (hostTag != null) { - hostsCopy.retainAll(_hostDao.listByHostTag(type, clusterId, podId, dcId, hostTag)); - } else { - hostsCopy.retainAll(_resourceMgr.listAllUpAndEnabledHosts(type, clusterId, podId, dcId)); - } - - s_logger.debug("Random Allocator found " + hostsCopy.size() + " hosts"); - if (hostsCopy.size() == 0) { - return suitableHosts; - } - - Collections.shuffle(hostsCopy); - for (Host host : hostsCopy) { - if (suitableHosts.size() == returnUpTo) { - break; - } - - if (!avoid.shouldAvoid(host)) { - suitableHosts.add(host); - } else { - if (s_logger.isDebugEnabled()) { - s_logger.debug("Host name: " + host.getName() + ", hostId: " + host.getId() + " is in avoid set, " + "skipping this and trying other available hosts"); - } + public List allocateTo(VirtualMachineProfile vmProfile, DeploymentPlan plan, Type type, + ExcludeList avoid, List hosts, int returnUpTo, + boolean considerReservedCapacity) { + if (CollectionUtils.isEmpty(hosts)) { + if (s_logger.isDebugEnabled()) { + s_logger.debug("Random Allocator found 0 hosts as given host list is empty"); } + return new ArrayList(); } - - if (s_logger.isDebugEnabled()) { - s_logger.debug("Random Host Allocator returning " + suitableHosts.size() + " suitable hosts"); - } - - return suitableHosts; + return findSuitableHosts(vmProfile, plan, type, avoid, hosts, returnUpTo, considerReservedCapacity); } @Override - public List allocateTo(VirtualMachineProfile vmProfile, DeploymentPlan plan, Type type, ExcludeList avoid, int returnUpTo, boolean considerReservedCapacity) { - - long dcId = plan.getDataCenterId(); - Long podId = plan.getPodId(); - Long clusterId = plan.getClusterId(); - ServiceOffering offering = vmProfile.getServiceOffering(); - - List suitableHosts = new ArrayList(); - - if (type == Host.Type.Storage) { - return suitableHosts; - } - - String hostTag = offering.getHostTag(); - if (hostTag != null) { - s_logger.debug("Looking for hosts in dc: " + dcId + " pod:" + podId + " cluster:" + clusterId + " having host tag:" + hostTag); - } else { - s_logger.debug("Looking for hosts in dc: " + dcId + " pod:" + podId + " cluster:" + clusterId); - } - - // list all computing hosts, regardless of whether they support routing...it's random after all - List hosts = new ArrayList(); - if (hostTag != null) { - hosts = _hostDao.listByHostTag(type, clusterId, podId, dcId, hostTag); - } else { - hosts = _resourceMgr.listAllUpAndEnabledHosts(type, clusterId, podId, dcId); - } - - s_logger.debug("Random Allocator found " + hosts.size() + " hosts"); - - if (hosts.size() == 0) { - return suitableHosts; - } - - Collections.shuffle(hosts); - for (Host host : hosts) { - if (suitableHosts.size() == returnUpTo) { - break; - } - - if (!avoid.shouldAvoid(host)) { - suitableHosts.add(host); - } else { - if (s_logger.isDebugEnabled()) { - s_logger.debug("Host name: " + host.getName() + ", hostId: " + host.getId() + " is in avoid set, skipping this and trying other available hosts"); - } - } - } - if (s_logger.isDebugEnabled()) { - s_logger.debug("Random Host Allocator returning " + suitableHosts.size() + " suitable hosts"); - } - return suitableHosts; + public List allocateTo(VirtualMachineProfile vmProfile, DeploymentPlan plan, + Type type, ExcludeList avoid, int returnUpTo, boolean considerReservedCapacity) { + return findSuitableHosts(vmProfile, plan, type, avoid, null, returnUpTo, considerReservedCapacity); } @Override diff --git a/server/src/main/java/com/cloud/agent/manager/allocator/impl/FirstFitAllocator.java b/server/src/main/java/com/cloud/agent/manager/allocator/impl/FirstFitAllocator.java index 698d6d73904..01101d4b8ec 100644 --- a/server/src/main/java/com/cloud/agent/manager/allocator/impl/FirstFitAllocator.java +++ b/server/src/main/java/com/cloud/agent/manager/allocator/impl/FirstFitAllocator.java @@ -35,7 +35,6 @@ import com.cloud.capacity.CapacityVO; import com.cloud.capacity.dao.CapacityDao; import com.cloud.configuration.Config; import com.cloud.dc.ClusterDetailsDao; -import com.cloud.dc.ClusterDetailsVO; import com.cloud.dc.dao.ClusterDao; import com.cloud.deploy.DeploymentPlan; import com.cloud.deploy.DeploymentPlanner.ExcludeList; @@ -47,7 +46,6 @@ import com.cloud.host.HostVO; import com.cloud.host.dao.HostDao; import com.cloud.host.dao.HostDetailsDao; import com.cloud.offering.ServiceOffering; -import com.cloud.org.Cluster; import com.cloud.resource.ResourceManager; import com.cloud.service.ServiceOfferingDetailsVO; import com.cloud.service.dao.ServiceOfferingDetailsDao; @@ -57,12 +55,13 @@ import com.cloud.storage.VMTemplateVO; import com.cloud.storage.dao.GuestOSCategoryDao; import com.cloud.storage.dao.GuestOSDao; import com.cloud.user.Account; +import com.cloud.utils.Pair; import com.cloud.utils.component.AdapterBase; +import com.cloud.vm.UserVmDetailVO; import com.cloud.vm.VirtualMachine; import com.cloud.vm.VirtualMachineProfile; -import com.cloud.vm.dao.VMInstanceDao; -import com.cloud.vm.UserVmDetailVO; import com.cloud.vm.dao.UserVmDetailsDao; +import com.cloud.vm.dao.VMInstanceDao; /** @@ -336,27 +335,15 @@ public class FirstFitAllocator extends AdapterBase implements HostAllocator { continue; } } - - int cpu_requested = offering.getCpu() * offering.getSpeed(); - long ram_requested = offering.getRamSize() * 1024L * 1024L; - Cluster cluster = _clusterDao.findById(host.getClusterId()); - ClusterDetailsVO clusterDetailsCpuOvercommit = _clusterDetailsDao.findDetail(cluster.getId(), "cpuOvercommitRatio"); - ClusterDetailsVO clusterDetailsRamOvercommmt = _clusterDetailsDao.findDetail(cluster.getId(), "memoryOvercommitRatio"); - Float cpuOvercommitRatio = Float.parseFloat(clusterDetailsCpuOvercommit.getValue()); - Float memoryOvercommitRatio = Float.parseFloat(clusterDetailsRamOvercommmt.getValue()); - - boolean hostHasCpuCapability = _capacityMgr.checkIfHostHasCpuCapability(host.getId(), offering.getCpu(), offering.getSpeed()); - boolean hostHasCapacity = _capacityMgr.checkIfHostHasCapacity(host.getId(), cpu_requested, ram_requested, false, cpuOvercommitRatio, memoryOvercommitRatio, - considerReservedCapacity); - - if (hostHasCpuCapability && hostHasCapacity) { + Pair cpuCapabilityAndCapacity = _capacityMgr.checkIfHostHasCpuCapabilityAndCapacity(host, offering, considerReservedCapacity); + if (cpuCapabilityAndCapacity.first() && cpuCapabilityAndCapacity.second()) { if (s_logger.isDebugEnabled()) { s_logger.debug("Found a suitable host, adding to list: " + host.getId()); } suitableHosts.add(host); } else { if (s_logger.isDebugEnabled()) { - s_logger.debug("Not using host " + host.getId() + "; host has cpu capability? " + hostHasCpuCapability + ", host has capacity?" + hostHasCapacity); + s_logger.debug("Not using host " + host.getId() + "; host has cpu capability? " + cpuCapabilityAndCapacity.first() + ", host has capacity?" + cpuCapabilityAndCapacity.second()); } avoid.addHost(host.getId()); } diff --git a/server/src/main/java/com/cloud/capacity/CapacityManagerImpl.java b/server/src/main/java/com/cloud/capacity/CapacityManagerImpl.java index f851471b0e0..f78031d6754 100644 --- a/server/src/main/java/com/cloud/capacity/CapacityManagerImpl.java +++ b/server/src/main/java/com/cloud/capacity/CapacityManagerImpl.java @@ -60,6 +60,7 @@ import com.cloud.host.dao.HostDao; import com.cloud.hypervisor.Hypervisor.HypervisorType; import com.cloud.hypervisor.dao.HypervisorCapabilitiesDao; import com.cloud.offering.ServiceOffering; +import com.cloud.org.Cluster; import com.cloud.resource.ResourceListener; import com.cloud.resource.ResourceManager; import com.cloud.resource.ResourceState; @@ -1091,6 +1092,23 @@ public class CapacityManagerImpl extends ManagerBase implements CapacityManager, } + @Override + public Pair checkIfHostHasCpuCapabilityAndCapacity(Host host, ServiceOffering offering, boolean considerReservedCapacity) { + int cpu_requested = offering.getCpu() * offering.getSpeed(); + long ram_requested = offering.getRamSize() * 1024L * 1024L; + Cluster cluster = _clusterDao.findById(host.getClusterId()); + ClusterDetailsVO clusterDetailsCpuOvercommit = _clusterDetailsDao.findDetail(cluster.getId(), "cpuOvercommitRatio"); + ClusterDetailsVO clusterDetailsRamOvercommmt = _clusterDetailsDao.findDetail(cluster.getId(), "memoryOvercommitRatio"); + Float cpuOvercommitRatio = Float.parseFloat(clusterDetailsCpuOvercommit.getValue()); + Float memoryOvercommitRatio = Float.parseFloat(clusterDetailsRamOvercommmt.getValue()); + + boolean hostHasCpuCapability = checkIfHostHasCpuCapability(host.getId(), offering.getCpu(), offering.getSpeed()); + boolean hostHasCapacity = checkIfHostHasCapacity(host.getId(), cpu_requested, ram_requested, false, cpuOvercommitRatio, memoryOvercommitRatio, + considerReservedCapacity); + + return new Pair<>(hostHasCpuCapability, hostHasCapacity); + } + @Override public boolean processAnswers(long agentId, long seq, Answer[] answers) { // TODO Auto-generated method stub From d8c6e00498c34c2ead3bb288f7aa58ceb73347c7 Mon Sep 17 00:00:00 2001 From: Abhishek Kumar Date: Fri, 9 Apr 2021 13:12:06 +0530 Subject: [PATCH 3/3] hypervisor: XCP-ng 8.2 support (#4672) Adds new/missing guest os mappings for XCP-ng/Xenserver 8.1 Copy guest OS mappings from XCP-ng/Xenserver 8.1 for XCP-ng/Xenserver 8.2 Adds Ubuntu 20.04 guest os mapping for XCP-ng/Xenserver 8.2 Signed-off-by: Abhishek Kumar --- .../META-INF/db/schema-41500to41510.sql | 33 +++++++++++++++++++ .../com/cloud/hypervisor/XenServerGuru.java | 10 +++++- 2 files changed, 42 insertions(+), 1 deletion(-) diff --git a/engine/schema/src/main/resources/META-INF/db/schema-41500to41510.sql b/engine/schema/src/main/resources/META-INF/db/schema-41500to41510.sql index 5c25c0b745e..21d9dcba03b 100644 --- a/engine/schema/src/main/resources/META-INF/db/schema-41500to41510.sql +++ b/engine/schema/src/main/resources/META-INF/db/schema-41500to41510.sql @@ -23,3 +23,36 @@ UPDATE `cloud`.`guest_os` SET display_name='Fedora Linux (32 bit)' WHERE id=320; UPDATE `cloud`.`guest_os` SET display_name='Mandriva Linux (32 bit)' WHERE id=323; UPDATE `cloud`.`guest_os` SET display_name='OpenSUSE Linux (32 bit)' WHERE id=327; + +-- Add support for SUSE Linux Enterprise Desktop 12 SP3 (64-bit) for Xenserver 8.1.0 +INSERT INTO `cloud`.`guest_os` (id, uuid, category_id, display_name, created) VALUES (330, UUID(), 5, 'SUSE Linux Enterprise Desktop 12 SP3 (64-bit)', now()); +INSERT INTO `cloud`.`guest_os_hypervisor` (uuid,hypervisor_type, hypervisor_version, guest_os_name, guest_os_id, created, is_user_defined) VALUES (UUID(),'Xenserver', '8.1.0', 'SUSE Linux Enterprise Desktop 12 SP3 (64-bit)', 330, now(), 0); +-- Add support for SUSE Linux Enterprise Desktop 12 SP4 (64-bit) for Xenserver 8.1.0 +INSERT INTO `cloud`.`guest_os` (id, uuid, category_id, display_name, created) VALUES (331, UUID(), 5, 'SUSE Linux Enterprise Desktop 12 SP4 (64-bit)', now()); +INSERT INTO `cloud`.`guest_os_hypervisor` (uuid,hypervisor_type, hypervisor_version, guest_os_name, guest_os_id, created, is_user_defined) VALUES (UUID(),'Xenserver', '8.1.0', 'SUSE Linux Enterprise Desktop 12 SP4 (64-bit)', 331, now(), 0); +-- Add support for SUSE Linux Enterprise Server 12 SP4 (64-bit) for Xenserver 8.1.0 +INSERT INTO `cloud`.`guest_os` (id, uuid, category_id, display_name, created) VALUES (332, UUID(), 5, 'SUSE Linux Enterprise Server 12 SP4 (64-bit)', now()); +INSERT INTO `cloud`.`guest_os_hypervisor` (uuid,hypervisor_type, hypervisor_version, guest_os_name, guest_os_id, created, is_user_defined) VALUES (UUID(),'Xenserver', '8.1.0', 'SUSE Linux Enterprise Server 12 SP4 (64-bit)', 332, now(), 0); +-- Add support for Scientific Linux 7 for Xenserver 8.1.0 +INSERT INTO `cloud`.`guest_os` (id, uuid, category_id, display_name, created) VALUES (333, UUID(), 9, 'Scientific Linux 7', now()); +INSERT INTO `cloud`.`guest_os_hypervisor` (uuid,hypervisor_type, hypervisor_version, guest_os_name, guest_os_id, created, is_user_defined) VALUES (UUID(),'Xenserver', '8.1.0', 'Scientific Linux 7', 333, now(), 0); +-- Add support for NeoKylin Linux Server 7 for Xenserver 8.1.0 +INSERT INTO `cloud`.`guest_os` (id, uuid, category_id, display_name, created) VALUES (334, UUID(), 9, 'NeoKylin Linux Server 7', now()); +INSERT INTO `cloud`.`guest_os_hypervisor` (uuid,hypervisor_type, hypervisor_version, guest_os_name, guest_os_id, created, is_user_defined) VALUES (UUID(),'Xenserver', '8.1.0', 'NeoKylin Linux Server 7', 332, now(), 0); +-- Add support CentOS 8 for Xenserver 8.1.0 +INSERT INTO `cloud`.`guest_os_hypervisor` (uuid,hypervisor_type, hypervisor_version, guest_os_name, guest_os_id, created, is_user_defined) VALUES (UUID(),'Xenserver', '8.1.0', 'CentOS 8', 297, now(), 0); +-- Add support for Debian Buster 10 for Xenserver 8.1.0 +INSERT INTO `cloud`.`guest_os_hypervisor` (uuid,hypervisor_type, hypervisor_version, guest_os_name, guest_os_id, created, is_user_defined) VALUES (UUID(),'Xenserver', '8.1.0', 'Debian Buster 10', 292, now(), 0); +INSERT INTO `cloud`.`guest_os_hypervisor` (uuid,hypervisor_type, hypervisor_version, guest_os_name, guest_os_id, created, is_user_defined) VALUES (UUID(),'Xenserver', '8.1.0', 'Debian Buster 10', 293, now(), 0); +-- Add support for SUSE Linux Enterprise 15 (64-bit) for Xenserver 8.1.0 +INSERT INTO `cloud`.`guest_os_hypervisor` (uuid,hypervisor_type, hypervisor_version, guest_os_name, guest_os_id, created, is_user_defined) VALUES (UUID(),'Xenserver', '8.1.0', 'SUSE Linux Enterprise 15 (64-bit)', 291, now(), 0); + +-- Add XenServer 8.2.0 hypervisor capabilities +INSERT IGNORE INTO `cloud`.`hypervisor_capabilities`(uuid, hypervisor_type, hypervisor_version, max_guests_limit, max_data_volumes_limit, max_hosts_per_cluster, storage_motion_supported) values (UUID(), 'XenServer', '8.2.0', 1000, 253, 64, 1); + +-- Copy XenServer 8.1.0 hypervisor guest OS mappings to XenServer 8.2.0 +INSERT IGNORE INTO `cloud`.`guest_os_hypervisor` (uuid,hypervisor_type, hypervisor_version, guest_os_name, guest_os_id, created, is_user_defined) SELECT UUID(),'Xenserver', '8.2.0', guest_os_name, guest_os_id, utc_timestamp(), 0 FROM `cloud`.`guest_os_hypervisor` WHERE hypervisor_type='Xenserver' AND hypervisor_version='8.1.0'; + +-- Add support for Ubuntu Focal Fossa 20.04 for Xenserver 8.2.0 +INSERT INTO `cloud`.`guest_os` (id, uuid, category_id, display_name, created) VALUES (335, UUID(), 10, 'Ubuntu 20.04 LTS', now()); +INSERT INTO `cloud`.`guest_os_hypervisor` (uuid,hypervisor_type, hypervisor_version, guest_os_name, guest_os_id, created, is_user_defined) VALUES (UUID(),'Xenserver', '8.2.0', 'Ubuntu Focal Fossa 20.04', 330, now(), 0); diff --git a/plugins/hypervisors/xenserver/src/main/java/com/cloud/hypervisor/XenServerGuru.java b/plugins/hypervisors/xenserver/src/main/java/com/cloud/hypervisor/XenServerGuru.java index 2ef942cd53a..c77ac44cdaf 100644 --- a/plugins/hypervisors/xenserver/src/main/java/com/cloud/hypervisor/XenServerGuru.java +++ b/plugins/hypervisors/xenserver/src/main/java/com/cloud/hypervisor/XenServerGuru.java @@ -17,6 +17,7 @@ package com.cloud.hypervisor; import java.util.ArrayList; +import java.util.Comparator; import java.util.List; import java.util.Map; @@ -98,7 +99,14 @@ public class XenServerGuru extends HypervisorGuruBase implements HypervisorGuru, if (userVmVO != null) { HostVO host = hostDao.findById(userVmVO.getHostId()); if (host != null) { - to.setVcpuMaxLimit(MaxNumberOfVCPUSPerVM.valueIn(host.getClusterId())); + List clusterHosts = hostDao.listByClusterAndHypervisorType(host.getClusterId(), host.getHypervisorType()); + HostVO hostWithMinSocket = clusterHosts.stream().min(Comparator.comparing(HostVO::getCpuSockets)).orElse(null); + Integer vCpus = MaxNumberOfVCPUSPerVM.valueIn(host.getClusterId()); + if (hostWithMinSocket != null && hostWithMinSocket.getCpuSockets() != null && + hostWithMinSocket.getCpuSockets() < vCpus) { + vCpus = hostWithMinSocket.getCpuSockets(); + } + to.setVcpuMaxLimit(vCpus); } }