Fix CKS cluster creation not honoring the CKS ISO arch (#11902)

* Fix CKS cluster creation not honouring the CKS ISO arch

* Fix arch type reference to choose right template

* Include template name on the CKS clusters response

---------

Co-authored-by: Harikrishna Patnala <harikrishna.patnala@gmail.com>
This commit is contained in:
Nicolas Vazquez 2025-10-27 02:28:46 -03:00 committed by GitHub
parent f52a27cce6
commit 2dbc86abfa
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 35 additions and 12 deletions

View File

@ -556,7 +556,7 @@ public class KubernetesClusterManagerImpl extends ManagerBase implements Kuberne
if (cksIso == null) { if (cksIso == null) {
return systemVMPreferredArchitecture; return systemVMPreferredArchitecture;
} }
String cksIsoArchName = cksIso.getArch().name(); String cksIsoArchName = cksIso.getArch().getType();
return cksIsoArchName.equals(systemVMPreferredArchitecture) ? systemVMPreferredArchitecture : cksIsoArchName; return cksIsoArchName.equals(systemVMPreferredArchitecture) ? systemVMPreferredArchitecture : cksIsoArchName;
} }
@ -807,6 +807,7 @@ public class KubernetesClusterManagerImpl extends ManagerBase implements Kuberne
VMTemplateVO template = ApiDBUtils.findTemplateById(kubernetesCluster.getTemplateId()); VMTemplateVO template = ApiDBUtils.findTemplateById(kubernetesCluster.getTemplateId());
if (template != null) { if (template != null) {
response.setTemplateId(template.getUuid()); response.setTemplateId(template.getUuid());
response.setTemplateName(template.getName());
} }
ServiceOfferingVO offering = serviceOfferingDao.findByIdIncludingRemoved(kubernetesCluster.getServiceOfferingId()); ServiceOfferingVO offering = serviceOfferingDao.findByIdIncludingRemoved(kubernetesCluster.getServiceOfferingId());
if (offering != null) { if (offering != null) {

View File

@ -36,6 +36,7 @@ import java.util.stream.Collectors;
import javax.inject.Inject; import javax.inject.Inject;
import com.cloud.cpu.CPU;
import com.cloud.deploy.DataCenterDeployment; import com.cloud.deploy.DataCenterDeployment;
import com.cloud.deploy.DeploymentPlan; import com.cloud.deploy.DeploymentPlan;
import com.cloud.dc.DedicatedResourceVO; import com.cloud.dc.DedicatedResourceVO;
@ -177,7 +178,7 @@ public class KubernetesClusterResourceModifierActionWorker extends KubernetesClu
} }
protected DeployDestination plan(final long nodesCount, final DataCenter zone, final ServiceOffering offering, protected DeployDestination plan(final long nodesCount, final DataCenter zone, final ServiceOffering offering,
final Long domainId, final Long accountId, final Hypervisor.HypervisorType hypervisorType) throws InsufficientServerCapacityException { final Long domainId, final Long accountId, final Hypervisor.HypervisorType hypervisorType, CPU.CPUArch arch) throws InsufficientServerCapacityException {
final int cpu_requested = offering.getCpu() * offering.getSpeed(); final int cpu_requested = offering.getCpu() * offering.getSpeed();
final long ram_requested = offering.getRamSize() * 1024L * 1024L; final long ram_requested = offering.getRamSize() * 1024L * 1024L;
boolean useDedicatedHosts = false; boolean useDedicatedHosts = false;
@ -201,6 +202,15 @@ public class KubernetesClusterResourceModifierActionWorker extends KubernetesClu
if (hypervisorType != null) { if (hypervisorType != null) {
hosts = hosts.stream().filter(x -> x.getHypervisorType() == hypervisorType).collect(Collectors.toList()); hosts = hosts.stream().filter(x -> x.getHypervisorType() == hypervisorType).collect(Collectors.toList());
} }
if (arch != null) {
hosts = hosts.stream().filter(x -> x.getArch().equals(arch)).collect(Collectors.toList());
}
if (CollectionUtils.isEmpty(hosts)) {
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());
logAndThrow(Level.WARN, msg, new InsufficientServerCapacityException(msg, DataCenter.class, zone.getId()));
}
final Map<String, Pair<HostVO, Integer>> hosts_with_resevered_capacity = new ConcurrentHashMap<String, Pair<HostVO, Integer>>(); final Map<String, Pair<HostVO, Integer>> hosts_with_resevered_capacity = new ConcurrentHashMap<String, Pair<HostVO, Integer>>();
for (HostVO h : hosts) { for (HostVO h : hosts) {
hosts_with_resevered_capacity.put(h.getUuid(), new Pair<HostVO, Integer>(h, 0)); hosts_with_resevered_capacity.put(h.getUuid(), new Pair<HostVO, Integer>(h, 0));
@ -254,8 +264,8 @@ public class KubernetesClusterResourceModifierActionWorker extends KubernetesClu
} }
return new DeployDestination(zone, null, null, null); return new DeployDestination(zone, null, null, null);
} }
String msg = String.format("Cannot find enough capacity for Kubernetes cluster(requested cpu=%d memory=%s) with offering: %s and hypervisor: %s", 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()); cpu_requested * nodesCount, toHumanReadableSize(ram_requested * nodesCount), offering.getName(), clusterTemplate.getHypervisorType().toString(), arch.getType());
logger.warn(msg); logger.warn(msg);
throw new InsufficientServerCapacityException(msg, DataCenter.class, zone.getId()); throw new InsufficientServerCapacityException(msg, DataCenter.class, zone.getId());
@ -265,7 +275,7 @@ public class KubernetesClusterResourceModifierActionWorker extends KubernetesClu
* Plan Kubernetes Cluster Deployment * Plan Kubernetes Cluster Deployment
* @return a map of DeployDestination per node type * @return a map of DeployDestination per node type
*/ */
protected Map<String, DeployDestination> planKubernetesCluster(Long domainId, Long accountId, Hypervisor.HypervisorType hypervisorType) throws InsufficientServerCapacityException { protected Map<String, DeployDestination> planKubernetesCluster(Long domainId, Long accountId, Hypervisor.HypervisorType hypervisorType, CPU.CPUArch arch) throws InsufficientServerCapacityException {
Map<String, DeployDestination> destinationMap = new HashMap<>(); Map<String, DeployDestination> destinationMap = new HashMap<>();
DataCenter zone = dataCenterDao.findById(kubernetesCluster.getZoneId()); DataCenter zone = dataCenterDao.findById(kubernetesCluster.getZoneId());
if (logger.isDebugEnabled()) { if (logger.isDebugEnabled()) {
@ -286,7 +296,7 @@ public class KubernetesClusterResourceModifierActionWorker extends KubernetesClu
if (logger.isDebugEnabled()) { if (logger.isDebugEnabled()) {
logger.debug("Checking deployment destination for {} nodes on Kubernetes cluster : {} in zone : {}", nodeType.name(), kubernetesCluster.getName(), zone.getName()); logger.debug("Checking deployment destination for {} nodes on Kubernetes cluster : {} in zone : {}", nodeType.name(), kubernetesCluster.getName(), zone.getName());
} }
DeployDestination planForNodeType = plan(nodes, zone, nodeOffering, domainId, accountId, hypervisorType); DeployDestination planForNodeType = plan(nodes, zone, nodeOffering, domainId, accountId, hypervisorType, arch);
destinationMap.put(nodeType.name(), planForNodeType); destinationMap.put(nodeType.name(), planForNodeType);
} }
return destinationMap; return destinationMap;
@ -322,7 +332,7 @@ public class KubernetesClusterResourceModifierActionWorker extends KubernetesClu
if (Objects.nonNull(domainId) && !listDedicatedHostsInDomain(domainId).isEmpty()) { if (Objects.nonNull(domainId) && !listDedicatedHostsInDomain(domainId).isEmpty()) {
DeployDestination dest = null; DeployDestination dest = null;
try { try {
Map<String, DeployDestination> destinationMap = planKubernetesCluster(domainId, accountId, vm.getHypervisorType()); Map<String, DeployDestination> destinationMap = planKubernetesCluster(domainId, accountId, vm.getHypervisorType(), clusterTemplate.getArch());
dest = destinationMap.get(nodeType.name()); dest = destinationMap.get(nodeType.name());
} catch (InsufficientCapacityException e) { } catch (InsufficientCapacityException e) {
logTransitStateAndThrow(Level.ERROR, String.format("Provisioning the cluster failed due to insufficient capacity in the Kubernetes cluster: %s", kubernetesCluster.getUuid()), kubernetesCluster.getId(), KubernetesCluster.Event.CreateFailed, e); logTransitStateAndThrow(Level.ERROR, String.format("Provisioning the cluster failed due to insufficient capacity in the Kubernetes cluster: %s", kubernetesCluster.getUuid()), kubernetesCluster.getId(), KubernetesCluster.Event.CreateFailed, e);

View File

@ -341,9 +341,9 @@ public class KubernetesClusterScaleWorker extends KubernetesClusterResourceModif
VMTemplateVO clusterTemplate = templateDao.findById(kubernetesCluster.getTemplateId()); VMTemplateVO clusterTemplate = templateDao.findById(kubernetesCluster.getTemplateId());
try { try {
if (originalState.equals(KubernetesCluster.State.Running)) { if (originalState.equals(KubernetesCluster.State.Running)) {
plan(newVmRequiredCount, zone, clusterServiceOffering, kubernetesCluster.getDomainId(), kubernetesCluster.getAccountId(), clusterTemplate.getHypervisorType()); plan(newVmRequiredCount, zone, clusterServiceOffering, kubernetesCluster.getDomainId(), kubernetesCluster.getAccountId(), clusterTemplate.getHypervisorType(), clusterTemplate.getArch());
} else { } else {
plan(kubernetesCluster.getTotalNodeCount() + newVmRequiredCount, zone, clusterServiceOffering, kubernetesCluster.getDomainId(), kubernetesCluster.getAccountId(), clusterTemplate.getHypervisorType()); plan(kubernetesCluster.getTotalNodeCount() + newVmRequiredCount, zone, clusterServiceOffering, kubernetesCluster.getDomainId(), kubernetesCluster.getAccountId(), clusterTemplate.getHypervisorType(), clusterTemplate.getArch());
} }
} catch (InsufficientCapacityException e) { } catch (InsufficientCapacityException e) {
logTransitStateToFailedIfNeededAndThrow(Level.WARN, String.format("Scaling failed for Kubernetes cluster : %s in zone : %s, insufficient capacity", kubernetesCluster.getName(), zone.getName())); logTransitStateToFailedIfNeededAndThrow(Level.WARN, String.format("Scaling failed for Kubernetes cluster : %s in zone : %s, insufficient capacity", kubernetesCluster.getName(), zone.getName()));

View File

@ -749,7 +749,7 @@ public class KubernetesClusterStartWorker extends KubernetesClusterResourceModif
DeployDestination dest = null; DeployDestination dest = null;
try { try {
VMTemplateVO clusterTemplate = templateDao.findById(kubernetesCluster.getTemplateId()); VMTemplateVO clusterTemplate = templateDao.findById(kubernetesCluster.getTemplateId());
Map<String, DeployDestination> destinationMap = planKubernetesCluster(domainId, accountId, clusterTemplate.getHypervisorType()); Map<String, DeployDestination> destinationMap = planKubernetesCluster(domainId, accountId, clusterTemplate.getHypervisorType(), clusterTemplate.getArch());
dest = destinationMap.get(WORKER.name()); dest = destinationMap.get(WORKER.name());
} catch (InsufficientCapacityException e) { } catch (InsufficientCapacityException e) {
logTransitStateAndThrow(Level.ERROR, String.format("Provisioning the cluster failed due to insufficient capacity in the Kubernetes cluster: %s", kubernetesCluster.getUuid()), kubernetesCluster.getId(), KubernetesCluster.Event.CreateFailed, e); logTransitStateAndThrow(Level.ERROR, String.format("Provisioning the cluster failed due to insufficient capacity in the Kubernetes cluster: %s", kubernetesCluster.getUuid()), kubernetesCluster.getId(), KubernetesCluster.Event.CreateFailed, e);

View File

@ -91,6 +91,10 @@ public class KubernetesClusterResponse extends BaseResponseWithAnnotations imple
@Param(description = "the ID of the template of the Kubernetes cluster") @Param(description = "the ID of the template of the Kubernetes cluster")
private String templateId; private String templateId;
@SerializedName(ApiConstants.TEMPLATE_NAME)
@Param(description = "the name of the template of the Kubernetes cluster")
private String templateName;
@SerializedName(ApiConstants.NETWORK_ID) @SerializedName(ApiConstants.NETWORK_ID)
@Param(description = "the ID of the network of the Kubernetes cluster") @Param(description = "the ID of the network of the Kubernetes cluster")
private String networkId; private String networkId;
@ -267,6 +271,14 @@ public class KubernetesClusterResponse extends BaseResponseWithAnnotations imple
this.templateId = templateId; this.templateId = templateId;
} }
public String getTemplateName() {
return templateName;
}
public void setTemplateName(String templateName) {
this.templateName = templateName;
}
public String getNetworkId() { public String getNetworkId() {
return networkId; return networkId;
} }

View File

@ -430,7 +430,7 @@ public class KubernetesClusterManagerImplTest {
VMTemplateVO cksIso = Mockito.mock(VMTemplateVO.class); VMTemplateVO cksIso = Mockito.mock(VMTemplateVO.class);
Mockito.when(cksIso.getArch()).thenReturn(CPU.CPUArch.arm64); Mockito.when(cksIso.getArch()).thenReturn(CPU.CPUArch.arm64);
String cksClusterPreferredArch = kubernetesClusterManager.getCksClusterPreferredArch(systemVMArch, cksIso); String cksClusterPreferredArch = kubernetesClusterManager.getCksClusterPreferredArch(systemVMArch, cksIso);
Assert.assertEquals(CPU.CPUArch.arm64.name(), cksClusterPreferredArch); Assert.assertEquals(CPU.CPUArch.arm64.getType(), cksClusterPreferredArch);
} }
@Test @Test
@ -439,6 +439,6 @@ public class KubernetesClusterManagerImplTest {
VMTemplateVO cksIso = Mockito.mock(VMTemplateVO.class); VMTemplateVO cksIso = Mockito.mock(VMTemplateVO.class);
Mockito.when(cksIso.getArch()).thenReturn(CPU.CPUArch.amd64); Mockito.when(cksIso.getArch()).thenReturn(CPU.CPUArch.amd64);
String cksClusterPreferredArch = kubernetesClusterManager.getCksClusterPreferredArch(systemVMArch, cksIso); String cksClusterPreferredArch = kubernetesClusterManager.getCksClusterPreferredArch(systemVMArch, cksIso);
Assert.assertEquals(CPU.CPUArch.amd64.name(), cksClusterPreferredArch); Assert.assertEquals(CPU.CPUArch.amd64.getType(), cksClusterPreferredArch);
} }
} }