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 573e752ce125..0dbb8b03e1d5 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 @@ -217,6 +217,7 @@ protected DeployDestination plan(final long nodesCount, final DataCenter zone, f } boolean suitable_host_found = false; HostVO suitableHost = null; + ClusterVO suitableCluster = null; for (int i = 1; i <= nodesCount; i++) { suitable_host_found = false; for (Map.Entry> hostEntry : hosts_with_resevered_capacity.entrySet()) { @@ -244,6 +245,7 @@ protected DeployDestination plan(final long nodesCount, final DataCenter zone, f hostEntry.setValue(new Pair(h, reserved)); suitable_host_found = true; suitableHost = h; + suitableCluster = cluster; break; } } @@ -259,10 +261,12 @@ protected DeployDestination plan(final long nodesCount, final DataCenter zone, f if (logger.isInfoEnabled()) { logger.info("Suitable hosts found in datacenter: {}, creating deployment destination", zone); } + // Include the cluster so that the network's virtual router is deployed on the same + // hypervisor type as the Kubernetes nodes in zones with mixed hypervisor clusters if (useDedicatedHosts) { - return new DeployDestination(zone, null, null, suitableHost); + return new DeployDestination(zone, null, suitableCluster, suitableHost); } - return new DeployDestination(zone, null, null, null); + return new DeployDestination(zone, null, suitableCluster, null); } String msg = String.format("Cannot find enough capacity for Kubernetes cluster(requested cpu=%d memory=%s) with offering: %s hypervisor: %s and arch: %s", cpu_requested * nodesCount, toHumanReadableSize(ram_requested * nodesCount), offering.getName(), clusterTemplate.getHypervisorType().toString(), arch.getType()); diff --git a/plugins/integrations/kubernetes-service/src/test/java/com/cloud/kubernetes/cluster/actionworkers/KubernetesClusterResourceModifierActionWorkerTest.java b/plugins/integrations/kubernetes-service/src/test/java/com/cloud/kubernetes/cluster/actionworkers/KubernetesClusterResourceModifierActionWorkerTest.java index c220a3468afb..e4c961d98834 100644 --- a/plugins/integrations/kubernetes-service/src/test/java/com/cloud/kubernetes/cluster/actionworkers/KubernetesClusterResourceModifierActionWorkerTest.java +++ b/plugins/integrations/kubernetes-service/src/test/java/com/cloud/kubernetes/cluster/actionworkers/KubernetesClusterResourceModifierActionWorkerTest.java @@ -17,12 +17,31 @@ package com.cloud.kubernetes.cluster.actionworkers; +import java.util.List; + +import com.cloud.capacity.CapacityManager; +import com.cloud.cpu.CPU; +import com.cloud.dc.ClusterDetailsDao; +import com.cloud.dc.ClusterDetailsVO; +import com.cloud.dc.ClusterVO; +import com.cloud.dc.DataCenter; +import com.cloud.dc.dao.ClusterDao; +import com.cloud.deploy.DeployDestination; +import com.cloud.exception.InsufficientServerCapacityException; +import com.cloud.host.Host; +import com.cloud.host.HostVO; +import com.cloud.host.dao.HostDao; +import com.cloud.hypervisor.Hypervisor; import com.cloud.kubernetes.cluster.KubernetesCluster; import com.cloud.kubernetes.cluster.KubernetesClusterManagerImpl; import com.cloud.kubernetes.cluster.dao.KubernetesClusterDao; import com.cloud.kubernetes.cluster.dao.KubernetesClusterDetailsDao; import com.cloud.kubernetes.cluster.dao.KubernetesClusterVmMapDao; import com.cloud.kubernetes.version.dao.KubernetesSupportedVersionDao; +import com.cloud.offering.ServiceOffering; +import com.cloud.resource.ResourceManager; +import com.cloud.template.VirtualMachineTemplate; +import org.apache.cloudstack.affinity.dao.AffinityGroupDao; import org.junit.Assert; import org.junit.Before; import org.junit.Test; @@ -135,4 +154,58 @@ public void getKubernetesClusterNodeNamePrefixTestNormalizedPrefixShouldNotStart Mockito.when(kubernetesClusterMock.getName()).thenReturn(originalPrefix); Assert.assertEquals(expectedPrefix, kubernetesClusterResourceModifierActionWorker.getKubernetesClusterNodeNamePrefix()); } + + @Test + public void planTestDeployDestinationShouldContainClusterOfSuitableHost() throws InsufficientServerCapacityException { + long zoneId = 1L; + long clusterId = 2L; + DataCenter zone = Mockito.mock(DataCenter.class); + Mockito.when(zone.getId()).thenReturn(zoneId); + ServiceOffering offering = Mockito.mock(ServiceOffering.class); + Mockito.when(offering.getCpu()).thenReturn(2); + Mockito.when(offering.getSpeed()).thenReturn(1000); + Mockito.when(offering.getRamSize()).thenReturn(2048); + + VirtualMachineTemplate template = Mockito.mock(VirtualMachineTemplate.class); + Mockito.when(template.getHypervisorType()).thenReturn(Hypervisor.HypervisorType.KVM); + Mockito.when(template.getArch()).thenReturn(CPU.CPUArch.amd64); + kubernetesClusterResourceModifierActionWorker.clusterTemplate = template; + + HostVO kvmHost = Mockito.mock(HostVO.class); + Mockito.when(kvmHost.getUuid()).thenReturn("kvm-host"); + Mockito.when(kvmHost.getHypervisorType()).thenReturn(Hypervisor.HypervisorType.KVM); + Mockito.when(kvmHost.getArch()).thenReturn(CPU.CPUArch.amd64); + Mockito.when(kvmHost.getClusterId()).thenReturn(clusterId); + HostVO vmwareHost = Mockito.mock(HostVO.class); + Mockito.when(vmwareHost.getHypervisorType()).thenReturn(Hypervisor.HypervisorType.VMware); + + ClusterVO kvmCluster = Mockito.mock(ClusterVO.class); + Mockito.when(kvmCluster.getId()).thenReturn(clusterId); + ClusterDetailsVO overcommitDetail = Mockito.mock(ClusterDetailsVO.class); + Mockito.when(overcommitDetail.getValue()).thenReturn("1.0"); + + AffinityGroupDao affinityGroupDao = Mockito.mock(AffinityGroupDao.class); + ResourceManager resourceManager = Mockito.mock(ResourceManager.class); + Mockito.when(resourceManager.listAllHostsInOneZoneByType(Host.Type.Routing, zoneId)).thenReturn(List.of(vmwareHost, kvmHost)); + ClusterDao clusterDao = Mockito.mock(ClusterDao.class); + Mockito.when(clusterDao.findById(clusterId)).thenReturn(kvmCluster); + ClusterDetailsDao clusterDetailsDao = Mockito.mock(ClusterDetailsDao.class); + Mockito.when(clusterDetailsDao.findDetail(Mockito.eq(clusterId), Mockito.anyString())).thenReturn(overcommitDetail); + CapacityManager capacityManager = Mockito.mock(CapacityManager.class); + Mockito.when(capacityManager.checkIfHostHasCapacity(Mockito.eq(kvmHost), Mockito.anyInt(), Mockito.anyLong(), + Mockito.anyBoolean(), Mockito.anyFloat(), Mockito.anyFloat(), Mockito.anyBoolean())).thenReturn(true); + + kubernetesClusterResourceModifierActionWorker.affinityGroupDao = affinityGroupDao; + kubernetesClusterResourceModifierActionWorker.resourceManager = resourceManager; + kubernetesClusterResourceModifierActionWorker.clusterDao = clusterDao; + kubernetesClusterResourceModifierActionWorker.clusterDetailsDao = clusterDetailsDao; + kubernetesClusterResourceModifierActionWorker.capacityManager = capacityManager; + kubernetesClusterResourceModifierActionWorker.hostDao = Mockito.mock(HostDao.class); + + DeployDestination dest = kubernetesClusterResourceModifierActionWorker.plan(1, zone, offering, null, null, + Hypervisor.HypervisorType.KVM, CPU.CPUArch.amd64); + + Assert.assertEquals(kvmCluster, dest.getCluster()); + Assert.assertNull(dest.getHost()); + } }