This is an automated email from the ASF dual-hosted git repository.

pearl11594 pushed a commit to branch fr06-cks-template-register
in repository https://gitbox.apache.org/repos/asf/cloudstack.git

commit d639bbec2c7d3d54e15bbb1f96dd1b03179e06c6
Author: nvazquez <nicovazque...@gmail.com>
AuthorDate: Mon Feb 5 00:51:59 2024 -0300

    Deploy VMs according to the node type offering
---
 .../org/apache/cloudstack/api/ApiConstants.java    |  6 ++
 .../kubernetes/cluster/KubernetesCluster.java      |  4 +
 .../cluster/KubernetesClusterManagerImpl.java      | 91 +++++++++++++++-------
 .../KubernetesClusterActionWorker.java             | 25 ++++++
 ...ernetesClusterResourceModifierActionWorker.java |  3 +-
 .../KubernetesClusterStartWorker.java              |  6 +-
 .../cluster/CreateKubernetesClusterCmd.java        | 30 -------
 .../api/response/KubernetesClusterResponse.java    | 84 ++++++++++++++++++++
 .../cluster/KubernetesClusterManagerImplTest.java  |  4 +-
 .../cluster/CreateKubernetesClusterCmdTest.java    | 15 +---
 10 files changed, 195 insertions(+), 73 deletions(-)

diff --git a/api/src/main/java/org/apache/cloudstack/api/ApiConstants.java 
b/api/src/main/java/org/apache/cloudstack/api/ApiConstants.java
index 350d8742fb2..365992258c3 100644
--- a/api/src/main/java/org/apache/cloudstack/api/ApiConstants.java
+++ b/api/src/main/java/org/apache/cloudstack/api/ApiConstants.java
@@ -488,6 +488,12 @@ public class ApiConstants {
 
     public static final String VLAN = "vlan";
     public static final String VLAN_RANGE = "vlanrange";
+    public static final String WORKER_SERVICE_OFFERING_ID = "workerofferingid";
+    public static final String WORKER_SERVICE_OFFERING_NAME = 
"workerofferingname";
+    public static final String CONTROL_SERVICE_OFFERING_ID = 
"controlofferingid";
+    public static final String CONTROL_SERVICE_OFFERING_NAME = 
"controlofferingname";
+    public static final String ETCD_SERVICE_OFFERING_ID = "etcdofferingid";
+    public static final String ETCD_SERVICE_OFFERING_NAME = "etcdofferingname";
     public static final String REMOVE_VLAN = "removevlan";
     public static final String VLAN_ID = "vlanid";
     public static final String ISOLATED_PVLAN = "isolatedpvlan";
diff --git 
a/plugins/integrations/kubernetes-service/src/main/java/com/cloud/kubernetes/cluster/KubernetesCluster.java
 
b/plugins/integrations/kubernetes-service/src/main/java/com/cloud/kubernetes/cluster/KubernetesCluster.java
index 591da077aec..b83a3b73706 100644
--- 
a/plugins/integrations/kubernetes-service/src/main/java/com/cloud/kubernetes/cluster/KubernetesCluster.java
+++ 
b/plugins/integrations/kubernetes-service/src/main/java/com/cloud/kubernetes/cluster/KubernetesCluster.java
@@ -142,4 +142,8 @@ public interface KubernetesCluster extends 
ControlledEntity, com.cloud.utils.fsm
     Long getMaxSize();
     Long getSecurityGroupId();
     ClusterType getClusterType();
+    Long getControlServiceOfferingId();
+    Long getWorkerServiceOfferingId();
+    Long getEtcdServiceOfferingId();
+    Long getEtcdNodeCount();
 }
diff --git 
a/plugins/integrations/kubernetes-service/src/main/java/com/cloud/kubernetes/cluster/KubernetesClusterManagerImpl.java
 
b/plugins/integrations/kubernetes-service/src/main/java/com/cloud/kubernetes/cluster/KubernetesClusterManagerImpl.java
index c7de5dbcd2e..93dd48b34ae 100644
--- 
a/plugins/integrations/kubernetes-service/src/main/java/com/cloud/kubernetes/cluster/KubernetesClusterManagerImpl.java
+++ 
b/plugins/integrations/kubernetes-service/src/main/java/com/cloud/kubernetes/cluster/KubernetesClusterManagerImpl.java
@@ -43,6 +43,7 @@ import java.util.concurrent.TimeUnit;
 import javax.inject.Inject;
 import javax.naming.ConfigurationException;
 
+import 
com.cloud.kubernetes.cluster.KubernetesClusterHelper.KubernetesClusterNodeType;
 import com.cloud.uservm.UserVm;
 import com.cloud.vm.UserVmService;
 import org.apache.cloudstack.acl.ControlledEntity;
@@ -75,7 +76,6 @@ import org.apache.cloudstack.framework.config.ConfigKey;
 import org.apache.cloudstack.managed.context.ManagedContextRunnable;
 import org.apache.commons.codec.binary.Base64;
 import org.apache.commons.collections.CollectionUtils;
-import org.apache.commons.collections.MapUtils;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.log4j.Level;
 import org.apache.log4j.Logger;
@@ -550,6 +550,33 @@ public class KubernetesClusterManagerImpl extends 
ManagerBase implements Kuberne
         throw new InsufficientServerCapacityException(msg, DataCenter.class, 
zone.getId());
     }
 
+    protected void 
setNodeTypeServiceOfferingResponse(KubernetesClusterResponse response,
+                                                      
KubernetesClusterNodeType nodeType,
+                                                      Long offeringId) {
+        if (offeringId == null) {
+            return;
+        }
+        ServiceOfferingVO offering = serviceOfferingDao.findById(offeringId);
+        if (offering != null) {
+            setServiceOfferingResponseForNodeType(response, offering, 
nodeType);
+        }
+    }
+
+    protected void 
setServiceOfferingResponseForNodeType(KubernetesClusterResponse response,
+                                                         ServiceOfferingVO 
offering,
+                                                         
KubernetesClusterNodeType nodeType) {
+        if (CONTROL == nodeType) {
+            response.setControlOfferingId(offering.getUuid());
+            response.setControlOfferingName(offering.getName());
+        } else if (WORKER == nodeType) {
+            response.setWorkerOfferingId(offering.getUuid());
+            response.setWorkerOfferingName(offering.getName());
+        } else if (ETCD == nodeType) {
+            response.setEtcdOfferingId(offering.getUuid());
+            response.setEtcdOfferingName(offering.getName());
+        }
+    }
+
     @Override
     public KubernetesClusterResponse createKubernetesClusterResponse(long 
kubernetesClusterId) {
         KubernetesClusterVO kubernetesCluster = 
kubernetesClusterDao.findById(kubernetesClusterId);
@@ -573,6 +600,14 @@ public class KubernetesClusterManagerImpl extends 
ManagerBase implements Kuberne
             response.setServiceOfferingId(offering.getUuid());
             response.setServiceOfferingName(offering.getName());
         }
+
+        setNodeTypeServiceOfferingResponse(response, WORKER, 
kubernetesCluster.getWorkerServiceOfferingId());
+        setNodeTypeServiceOfferingResponse(response, CONTROL, 
kubernetesCluster.getControlServiceOfferingId());
+        setNodeTypeServiceOfferingResponse(response, ETCD, 
kubernetesCluster.getEtcdServiceOfferingId());
+
+        if (kubernetesCluster.getEtcdNodeCount() != null) {
+            response.setEtcdNodes(kubernetesCluster.getEtcdNodeCount());
+        }
         KubernetesSupportedVersionVO version = 
kubernetesSupportedVersionDao.findById(kubernetesCluster.getKubernetesVersionId());
         if (version != null) {
             response.setKubernetesVersionId(version.getUuid());
@@ -752,6 +787,7 @@ public class KubernetesClusterManagerImpl extends 
ManagerBase implements Kuberne
         final Long nodeRootDiskSize = cmd.getNodeRootDiskSize();
         final String externalLoadBalancerIpAddress = 
cmd.getExternalLoadBalancerIpAddress();
         final Map<String, Long> serviceOfferingNodeTypeMap = 
cmd.getServiceOfferingNodeTypeMap();
+        final Long defaultServiceOfferingId = cmd.getServiceOfferingId();
 
         if (name == null || name.isEmpty()) {
             throw new InvalidParameterValueException("Invalid name for the 
Kubernetes cluster name: " + name);
@@ -809,7 +845,7 @@ public class KubernetesClusterManagerImpl extends 
ManagerBase implements Kuberne
             throw new InvalidParameterValueException(String.format("ISO 
associated with version ID: %s is not in Ready state for datacenter ID: %s",  
clusterKubernetesVersion.getUuid(), zone.getUuid()));
         }
 
-        validateServiceOfferingsForNodeTypes(serviceOfferingNodeTypeMap, 
cmd.getEtcdNodes(), clusterKubernetesVersion);
+        validateServiceOfferingsForNodeTypes(serviceOfferingNodeTypeMap, 
defaultServiceOfferingId, cmd.getEtcdNodes(), clusterKubernetesVersion);
 
         validateSshKeyPairForKubernetesCreateParameters(sshKeyPair, owner);
 
@@ -838,26 +874,23 @@ public class KubernetesClusterManagerImpl extends 
ManagerBase implements Kuberne
         }
     }
 
-    protected void validateServiceOfferingsForNodeTypes(Map<String, Long> map, 
Long etcdNodes, KubernetesSupportedVersion clusterKubernetesVersion) {
-        if (MapUtils.isEmpty(map)) {
-            throw new InvalidParameterValueException("Please specify at least 
one service offering for the cluster");
-        }
-        if (!map.containsKey(WORKER.name()) || 
!map.containsKey(CONTROL.name())) {
-            throw new InvalidParameterValueException("Please specify a service 
offering for worker and control nodes");
-        }
-        if (etcdNodes != null && etcdNodes > 0 && 
!map.containsKey(ETCD.name())) {
-            throw new InvalidParameterValueException("Please specify a service 
offering for the etcd nodes");
-        }
+    protected void validateServiceOfferingsForNodeTypes(Map<String, Long> map,
+                                                        Long 
defaultServiceOfferingId,
+                                                        Long etcdNodes,
+                                                        
KubernetesSupportedVersion clusterKubernetesVersion) {
         for (String key : CLUSTER_NODES_TYPES_LIST) {
-            validateServiceOfferingForNode(map, key, etcdNodes, 
clusterKubernetesVersion);
+            validateServiceOfferingForNode(map, defaultServiceOfferingId, key, 
etcdNodes, clusterKubernetesVersion);
         }
     }
 
-    protected void validateServiceOfferingForNode(Map<String, Long> map, 
String key, Long etcdNodes, KubernetesSupportedVersion 
clusterKubernetesVersion) {
+    protected void validateServiceOfferingForNode(Map<String, Long> map,
+                                                  Long 
defaultServiceOfferingId,
+                                                  String key, Long etcdNodes,
+                                                  KubernetesSupportedVersion 
clusterKubernetesVersion) {
         if (ETCD.name().equalsIgnoreCase(key) && (etcdNodes == null || 
etcdNodes == 0)) {
             return;
         }
-        Long serviceOfferingId = map.getOrDefault(key, null);
+        Long serviceOfferingId = map.getOrDefault(key, 
defaultServiceOfferingId);
         ServiceOffering serviceOffering = serviceOfferingId != null ? 
serviceOfferingDao.findById(serviceOfferingId) : null;
         if (serviceOffering == null) {
             throw new InvalidParameterValueException("No service offering 
found with ID: " + serviceOfferingId);
@@ -1243,7 +1276,8 @@ public class KubernetesClusterManagerImpl extends 
ManagerBase implements Kuberne
         final KubernetesSupportedVersion clusterKubernetesVersion = 
kubernetesSupportedVersionDao.findById(cmd.getKubernetesVersionId());
 
         Map<String, Long> serviceOfferingNodeTypeMap = 
cmd.getServiceOfferingNodeTypeMap();
-        Hypervisor.HypervisorType hypervisorType = 
validateDeploymentAndSelectDestinationHypervisor(serviceOfferingNodeTypeMap, 
nodeTypeCount, zone);
+        Long defaultServiceOfferingId = cmd.getServiceOfferingId();
+        Hypervisor.HypervisorType hypervisorType = 
getHypervisorTypeAndValidateNodeDeployments(serviceOfferingNodeTypeMap, 
defaultServiceOfferingId, nodeTypeCount, zone);
 
         SecurityGroup securityGroup = null;
         if (zone.isSecurityGroupEnabled()) {
@@ -1253,7 +1287,7 @@ public class KubernetesClusterManagerImpl extends 
ManagerBase implements Kuberne
         final Network defaultNetwork = 
getKubernetesClusterNetworkIfMissing(cmd.getName(), zone, owner, 
(int)controlNodeCount, (int)clusterSize, 
cmd.getExternalLoadBalancerIpAddress(), cmd.getNetworkId());
         final VMTemplateVO finalTemplate = getKubernetesServiceTemplate(zone, 
hypervisorType);
         // Set the service_offering_id as the ID of the worker nodes offering 
for backwards compatibility
-        final ServiceOffering serviceOffering = 
serviceOfferingDao.findById(serviceOfferingNodeTypeMap.get(WORKER.name()));
+        final ServiceOffering serviceOffering = 
serviceOfferingDao.findById(serviceOfferingNodeTypeMap.getOrDefault(WORKER.name(),
 defaultServiceOfferingId));
         Pair<Long, Long> capacityPair = 
calculateClusterCapacity(serviceOfferingNodeTypeMap, nodeTypeCount);
         final long cores = capacityPair.first();
         final long memory = capacityPair.second();
@@ -1266,11 +1300,15 @@ public class KubernetesClusterManagerImpl extends 
ManagerBase implements Kuberne
                         serviceOffering.getId(), finalTemplate.getId(), 
defaultNetwork.getId(), owner.getDomainId(),
                         owner.getAccountId(), controlNodeCount, clusterSize, 
KubernetesCluster.State.Created, cmd.getSSHKeyPairName(), cores, memory,
                         cmd.getNodeRootDiskSize(), "", 
KubernetesCluster.ClusterType.CloudManaged);
-                
newCluster.setWorkerServiceOfferingId(serviceOfferingNodeTypeMap.getOrDefault(WORKER.name(),
 null));
-                
newCluster.setControlServiceOfferingId(serviceOfferingNodeTypeMap.getOrDefault(CONTROL.name(),
 null));
-                if (etcdNodes > 0) {
+                if (serviceOfferingNodeTypeMap.containsKey(WORKER.name())) {
+                    
newCluster.setWorkerServiceOfferingId(serviceOfferingNodeTypeMap.get(WORKER.name()));
+                }
+                if (serviceOfferingNodeTypeMap.containsKey(CONTROL.name())) {
+                    
newCluster.setControlServiceOfferingId(serviceOfferingNodeTypeMap.get(CONTROL.name()));
+                }
+                if (etcdNodes > 0 && 
serviceOfferingNodeTypeMap.containsKey(ETCD.name())) {
                     newCluster.setEtcdNodeCount(etcdNodes);
-                    
newCluster.setEtcdServiceOfferingId(serviceOfferingNodeTypeMap.getOrDefault(ETCD.name(),
 null));
+                    
newCluster.setEtcdServiceOfferingId(serviceOfferingNodeTypeMap.get(ETCD.name()));
                 }
                 if (zone.isSecurityGroupEnabled()) {
                     newCluster.setSecurityGroupId(finalSecurityGroup.getId());
@@ -1303,13 +1341,13 @@ public class KubernetesClusterManagerImpl extends 
ManagerBase implements Kuberne
         return new Pair<>(cores, memory);
     }
 
-    protected Hypervisor.HypervisorType 
validateDeploymentAndSelectDestinationHypervisor(Map<String, Long> 
serviceOfferingNodeTypeMap,
-                                                                               
          Map<String, Long> nodeTypeCount, DataCenter zone) {
+    protected Hypervisor.HypervisorType 
getHypervisorTypeAndValidateNodeDeployments(Map<String, Long> 
serviceOfferingNodeTypeMap,
+                                                                               
     Long defaultServiceOfferingId,
+                                                                               
     Map<String, Long> nodeTypeCount, DataCenter zone) {
         Hypervisor.HypervisorType hypervisorType = null;
-        List<ServiceOffering> serviceOfferingList = new ArrayList<>();
         for (String nodeType : CLUSTER_NODES_TYPES_LIST) {
             ServiceOffering serviceOffering = null;
-            Long nodes = nodeTypeCount.get(nodeType);
+            Long nodes = nodeTypeCount.getOrDefault(nodeType, 
defaultServiceOfferingId);
             try {
                 if (nodeType.equalsIgnoreCase(ETCD.name()) &&
                         (!serviceOfferingNodeTypeMap.containsKey(ETCD.name()) 
|| nodes == 0)) {
@@ -1317,13 +1355,12 @@ public class KubernetesClusterManagerImpl extends 
ManagerBase implements Kuberne
                 }
                 serviceOffering = 
serviceOfferingDao.findById(serviceOfferingNodeTypeMap.get(nodeType));
                 DeployDestination deployDestination = plan(nodes, zone, 
serviceOffering);
-                if (deployDestination == null || 
deployDestination.getCluster() == null) {
+                if (deployDestination.getCluster() == null) {
                     logAndThrow(Level.ERROR, String.format("Creating 
Kubernetes cluster failed due to error while finding suitable deployment plan 
for cluster in zone : %s", zone.getName()));
                 }
                 if (hypervisorType == null) {
                     hypervisorType = 
deployDestination.getCluster().getHypervisorType();
                 }
-                serviceOfferingList.add(serviceOffering);
             } catch (InsufficientCapacityException e) {
                 logAndThrow(Level.ERROR, String.format("Creating Kubernetes 
cluster failed due to insufficient capacity for %d nodes cluster in zone : %s 
with service offering : %s", nodes, zone.getName(), serviceOffering.getName()));
             }
diff --git 
a/plugins/integrations/kubernetes-service/src/main/java/com/cloud/kubernetes/cluster/actionworkers/KubernetesClusterActionWorker.java
 
b/plugins/integrations/kubernetes-service/src/main/java/com/cloud/kubernetes/cluster/actionworkers/KubernetesClusterActionWorker.java
index a84320e4d7f..5b6fa94a2c3 100644
--- 
a/plugins/integrations/kubernetes-service/src/main/java/com/cloud/kubernetes/cluster/actionworkers/KubernetesClusterActionWorker.java
+++ 
b/plugins/integrations/kubernetes-service/src/main/java/com/cloud/kubernetes/cluster/actionworkers/KubernetesClusterActionWorker.java
@@ -31,6 +31,8 @@ import java.util.stream.Collectors;
 
 import javax.inject.Inject;
 
+import 
com.cloud.kubernetes.cluster.KubernetesClusterHelper.KubernetesClusterNodeType;
+import com.cloud.offering.ServiceOffering;
 import org.apache.cloudstack.api.ApiConstants;
 import org.apache.cloudstack.ca.CAManager;
 import org.apache.cloudstack.config.ApiServiceConfiguration;
@@ -689,4 +691,27 @@ public class KubernetesClusterActionWorker {
     public void setKeys(String[] keys) {
         this.keys = keys;
     }
+
+    protected ServiceOffering 
getServiceOfferingForNodeTypeOnCluster(KubernetesClusterNodeType nodeType,
+                                                                     
KubernetesCluster cluster) {
+        Long offeringId = null;
+        Long defaultOfferingId = cluster.getServiceOfferingId();
+        Long controlOfferingId = cluster.getControlServiceOfferingId();
+        Long workerOfferingId = cluster.getWorkerServiceOfferingId();
+        Long etcdOfferingId = cluster.getEtcdServiceOfferingId();
+        if (KubernetesClusterNodeType.CONTROL == nodeType) {
+            offeringId = controlOfferingId != null ? controlOfferingId : 
defaultOfferingId;
+        } else if (KubernetesClusterNodeType.WORKER == nodeType) {
+            offeringId = workerOfferingId != null ? workerOfferingId : 
defaultOfferingId;
+        } else if (KubernetesClusterNodeType.ETCD == nodeType && 
cluster.getEtcdNodeCount() != null && cluster.getEtcdNodeCount() > 0) {
+            offeringId = etcdOfferingId != null ? etcdOfferingId : 
defaultOfferingId;
+        }
+
+        if (offeringId == null) {
+            String msg = String.format("Cannot find a service offering for the 
%s nodes on the Kubernetes cluster %s", nodeType.name(), cluster.getName());
+            LOGGER.error(msg);
+            throw new CloudRuntimeException(msg);
+        }
+        return serviceOfferingDao.findById(offeringId);
+    }
 }
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 08a1ad3452d..c0e38287639 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
@@ -17,6 +17,7 @@
 
 package com.cloud.kubernetes.cluster.actionworkers;
 
+import static 
com.cloud.kubernetes.cluster.KubernetesClusterHelper.KubernetesClusterNodeType.WORKER;
 import static com.cloud.utils.NumbersUtil.toHumanReadableSize;
 
 import java.io.File;
@@ -376,7 +377,7 @@ public class KubernetesClusterResourceModifierActionWorker 
extends KubernetesClu
             ResourceUnavailableException, InsufficientCapacityException {
         UserVm nodeVm = null;
         DataCenter zone = 
dataCenterDao.findById(kubernetesCluster.getZoneId());
-        ServiceOffering serviceOffering = 
serviceOfferingDao.findById(kubernetesCluster.getServiceOfferingId());
+        ServiceOffering serviceOffering = 
getServiceOfferingForNodeTypeOnCluster(WORKER, kubernetesCluster);
         List<Long> networkIds = new ArrayList<Long>();
         networkIds.add(kubernetesCluster.getNetworkId());
         Account owner = accountDao.findById(kubernetesCluster.getAccountId());
diff --git 
a/plugins/integrations/kubernetes-service/src/main/java/com/cloud/kubernetes/cluster/actionworkers/KubernetesClusterStartWorker.java
 
b/plugins/integrations/kubernetes-service/src/main/java/com/cloud/kubernetes/cluster/actionworkers/KubernetesClusterStartWorker.java
index 84ad9bdc0a6..f0989d9d1e9 100644
--- 
a/plugins/integrations/kubernetes-service/src/main/java/com/cloud/kubernetes/cluster/actionworkers/KubernetesClusterStartWorker.java
+++ 
b/plugins/integrations/kubernetes-service/src/main/java/com/cloud/kubernetes/cluster/actionworkers/KubernetesClusterStartWorker.java
@@ -75,6 +75,8 @@ import com.cloud.vm.UserVmManager;
 import com.cloud.vm.VirtualMachine;
 import com.cloud.vm.VmDetailConstants;
 
+import static 
com.cloud.kubernetes.cluster.KubernetesClusterHelper.KubernetesClusterNodeType.CONTROL;
+
 public class KubernetesClusterStartWorker extends 
KubernetesClusterResourceModifierActionWorker {
 
     private KubernetesSupportedVersion kubernetesClusterVersion;
@@ -183,7 +185,7 @@ public class KubernetesClusterStartWorker extends 
KubernetesClusterResourceModif
             ResourceUnavailableException, InsufficientCapacityException {
         UserVm controlVm = null;
         DataCenter zone = 
dataCenterDao.findById(kubernetesCluster.getZoneId());
-        ServiceOffering serviceOffering = 
serviceOfferingDao.findById(kubernetesCluster.getServiceOfferingId());
+        ServiceOffering serviceOffering = 
getServiceOfferingForNodeTypeOnCluster(CONTROL, kubernetesCluster);
         List<Long> networkIds = new ArrayList<Long>();
         networkIds.add(kubernetesCluster.getNetworkId());
         Pair<String, Map<Long, Network.IpAddresses>> ipAddresses = 
getKubernetesControlNodeIpAddresses(zone, network, owner);
@@ -263,7 +265,7 @@ public class KubernetesClusterStartWorker extends 
KubernetesClusterResourceModif
             ResourceUnavailableException, InsufficientCapacityException {
         UserVm additionalControlVm = null;
         DataCenter zone = 
dataCenterDao.findById(kubernetesCluster.getZoneId());
-        ServiceOffering serviceOffering = 
serviceOfferingDao.findById(kubernetesCluster.getServiceOfferingId());
+        ServiceOffering serviceOffering = 
getServiceOfferingForNodeTypeOnCluster(CONTROL, kubernetesCluster);
         List<Long> networkIds = new ArrayList<Long>();
         networkIds.add(kubernetesCluster.getNetworkId());
         Network.IpAddresses addrs = new Network.IpAddresses(null, null);
diff --git 
a/plugins/integrations/kubernetes-service/src/main/java/org/apache/cloudstack/api/command/user/kubernetes/cluster/CreateKubernetesClusterCmd.java
 
b/plugins/integrations/kubernetes-service/src/main/java/org/apache/cloudstack/api/command/user/kubernetes/cluster/CreateKubernetesClusterCmd.java
index b950f071bce..08ed1b1b280 100644
--- 
a/plugins/integrations/kubernetes-service/src/main/java/org/apache/cloudstack/api/command/user/kubernetes/cluster/CreateKubernetesClusterCmd.java
+++ 
b/plugins/integrations/kubernetes-service/src/main/java/org/apache/cloudstack/api/command/user/kubernetes/cluster/CreateKubernetesClusterCmd.java
@@ -17,9 +17,7 @@
 package org.apache.cloudstack.api.command.user.kubernetes.cluster;
 
 import java.security.InvalidParameterException;
-import java.util.Arrays;
 import java.util.HashMap;
-import java.util.List;
 import java.util.Map;
 
 import javax.inject.Inject;
@@ -319,38 +317,10 @@ public class CreateKubernetesClusterCmd extends 
BaseAsyncCreateCmd {
             for (Map<String, String> entry : 
serviceOfferingNodeTypeMap.values()) {
                 processNodeTypeOfferingEntryAndAddToMappingIfValid(entry, 
mapping);
             }
-            addMissingNodeTypeDefaultOffering(mapping, serviceOfferingId, 
etcdNodes);
-        } else {
-            addDefaultNodeTypeOfferingEntries(serviceOfferingId, etcdNodes, 
mapping);
         }
         return mapping;
     }
 
-    private void addMissingNodeTypeDefaultOffering(Map<String, Long> mapping, 
Long serviceOfferingId, Long etcdNodes) {
-        if (MapUtils.isEmpty(mapping)) {
-            return;
-        }
-        boolean addEtcdOffering = etcdNodes != null && etcdNodes > 0;
-        List<String> keys = 
Arrays.asList(KubernetesClusterNodeType.CONTROL.name(), 
KubernetesClusterNodeType.WORKER.name(), KubernetesClusterNodeType.ETCD.name());
-        for (String key : keys) {
-            if (mapping.containsKey(key)) {
-                continue;
-            }
-            if (!key.equalsIgnoreCase(KubernetesClusterNodeType.ETCD.name()) ||
-                    (addEtcdOffering && 
key.equalsIgnoreCase(KubernetesClusterNodeType.ETCD.name()))) {
-                mapping.put(key, serviceOfferingId);
-            }
-        }
-    }
-
-    protected void addDefaultNodeTypeOfferingEntries(Long serviceOfferingId, 
Long etcdNodes, Map<String, Long> mapping) {
-        mapping.put(KubernetesClusterNodeType.CONTROL.name(), 
serviceOfferingId);
-        mapping.put(KubernetesClusterNodeType.WORKER.name(), 
serviceOfferingId);
-        if (etcdNodes != null && etcdNodes > 0) {
-            mapping.put(KubernetesClusterNodeType.ETCD.name(), 
serviceOfferingId);
-        }
-    }
-
     /////////////////////////////////////////////////////
     /////////////// API Implementation///////////////////
     /////////////////////////////////////////////////////
diff --git 
a/plugins/integrations/kubernetes-service/src/main/java/org/apache/cloudstack/api/response/KubernetesClusterResponse.java
 
b/plugins/integrations/kubernetes-service/src/main/java/org/apache/cloudstack/api/response/KubernetesClusterResponse.java
index 168dfaf6091..c14fd9812f5 100644
--- 
a/plugins/integrations/kubernetes-service/src/main/java/org/apache/cloudstack/api/response/KubernetesClusterResponse.java
+++ 
b/plugins/integrations/kubernetes-service/src/main/java/org/apache/cloudstack/api/response/KubernetesClusterResponse.java
@@ -58,6 +58,34 @@ public class KubernetesClusterResponse extends 
BaseResponseWithAnnotations imple
     @Param(description = "the name of the service offering of the Kubernetes 
cluster")
     private String serviceOfferingName;
 
+    @SerializedName(ApiConstants.WORKER_SERVICE_OFFERING_ID)
+    @Param(description = "the ID of the service offering of the worker nodes 
on the Kubernetes cluster")
+    private String workerOfferingId;
+
+    @SerializedName(ApiConstants.WORKER_SERVICE_OFFERING_NAME)
+    @Param(description = "the name of the service offering of the worker nodes 
on the Kubernetes cluster")
+    private String workerOfferingName;
+
+    @SerializedName(ApiConstants.CONTROL_SERVICE_OFFERING_ID)
+    @Param(description = "the ID of the service offering of the control nodes 
on the Kubernetes cluster")
+    private String controlOfferingId;
+
+    @SerializedName(ApiConstants.CONTROL_SERVICE_OFFERING_NAME)
+    @Param(description = "the name of the service offering of the control 
nodes on the Kubernetes cluster")
+    private String controlOfferingName;
+
+    @SerializedName(ApiConstants.ETCD_SERVICE_OFFERING_ID)
+    @Param(description = "the ID of the service offering of the etcd nodes on 
the Kubernetes cluster")
+    private String etcdOfferingId;
+
+    @SerializedName(ApiConstants.ETCD_SERVICE_OFFERING_NAME)
+    @Param(description = "the name of the service offering of the etcd nodes 
on the Kubernetes cluster")
+    private String etcdOfferingName;
+
+    @SerializedName(ApiConstants.ETCD_NODES)
+    @Param(description = "the number of the etcd nodes on the Kubernetes 
cluster")
+    private Long etcdNodes;
+
     @SerializedName(ApiConstants.TEMPLATE_ID)
     @Param(description = "the ID of the template of the Kubernetes cluster")
     private String templateId;
@@ -359,6 +387,62 @@ public class KubernetesClusterResponse extends 
BaseResponseWithAnnotations imple
         this.serviceOfferingName = serviceOfferingName;
     }
 
+    public String getWorkerOfferingId() {
+        return workerOfferingId;
+    }
+
+    public void setWorkerOfferingId(String workerOfferingId) {
+        this.workerOfferingId = workerOfferingId;
+    }
+
+    public String getWorkerOfferingName() {
+        return workerOfferingName;
+    }
+
+    public void setWorkerOfferingName(String workerOfferingName) {
+        this.workerOfferingName = workerOfferingName;
+    }
+
+    public String getControlOfferingId() {
+        return controlOfferingId;
+    }
+
+    public void setControlOfferingId(String controlOfferingId) {
+        this.controlOfferingId = controlOfferingId;
+    }
+
+    public String getControlOfferingName() {
+        return controlOfferingName;
+    }
+
+    public void setControlOfferingName(String controlOfferingName) {
+        this.controlOfferingName = controlOfferingName;
+    }
+
+    public String getEtcdOfferingId() {
+        return etcdOfferingId;
+    }
+
+    public void setEtcdOfferingId(String etcdOfferingId) {
+        this.etcdOfferingId = etcdOfferingId;
+    }
+
+    public String getEtcdOfferingName() {
+        return etcdOfferingName;
+    }
+
+    public void setEtcdOfferingName(String etcdOfferingName) {
+        this.etcdOfferingName = etcdOfferingName;
+    }
+
+    public Long getEtcdNodes() {
+        return etcdNodes;
+    }
+
+    public void setEtcdNodes(Long etcdNodes) {
+        this.etcdNodes = etcdNodes;
+    }
+
     public void setVirtualMachines(List<UserVmResponse> virtualMachines) {
         this.virtualMachines = virtualMachines;
     }
diff --git 
a/plugins/integrations/kubernetes-service/src/test/java/com/cloud/kubernetes/cluster/KubernetesClusterManagerImplTest.java
 
b/plugins/integrations/kubernetes-service/src/test/java/com/cloud/kubernetes/cluster/KubernetesClusterManagerImplTest.java
index e5eafc03512..8ba91269244 100644
--- 
a/plugins/integrations/kubernetes-service/src/test/java/com/cloud/kubernetes/cluster/KubernetesClusterManagerImplTest.java
+++ 
b/plugins/integrations/kubernetes-service/src/test/java/com/cloud/kubernetes/cluster/KubernetesClusterManagerImplTest.java
@@ -318,7 +318,7 @@ public class KubernetesClusterManagerImplTest {
         KubernetesSupportedVersion version = 
Mockito.mock(KubernetesSupportedVersion.class);
         Mockito.when(version.getMinimumCpu()).thenReturn(2);
         Mockito.when(version.getMinimumRamSize()).thenReturn(2048);
-        kubernetesClusterManager.validateServiceOfferingForNode(map, 
WORKER.name(), null, version);
+        kubernetesClusterManager.validateServiceOfferingForNode(map, 1L, 
WORKER.name(), null, version);
         
Mockito.verify(kubernetesClusterManager).validateServiceOffering(serviceOffering,
 version);
     }
 
@@ -330,7 +330,7 @@ public class KubernetesClusterManagerImplTest {
         ServiceOfferingVO serviceOffering = 
Mockito.mock(ServiceOfferingVO.class);
         
Mockito.when(serviceOfferingDao.findById(1L)).thenReturn(serviceOffering);
         Mockito.when(serviceOffering.isDynamic()).thenReturn(true);
-        kubernetesClusterManager.validateServiceOfferingForNode(map, 
WORKER.name(), null, null);
+        kubernetesClusterManager.validateServiceOfferingForNode(map, 1L, 
WORKER.name(), null, null);
     }
 
     @Test
diff --git 
a/plugins/integrations/kubernetes-service/src/test/java/org/apache/cloudstack/api/command/user/kubernetes/cluster/CreateKubernetesClusterCmdTest.java
 
b/plugins/integrations/kubernetes-service/src/test/java/org/apache/cloudstack/api/command/user/kubernetes/cluster/CreateKubernetesClusterCmdTest.java
index 6dbbc53ec22..b5c6cf257a4 100644
--- 
a/plugins/integrations/kubernetes-service/src/test/java/org/apache/cloudstack/api/command/user/kubernetes/cluster/CreateKubernetesClusterCmdTest.java
+++ 
b/plugins/integrations/kubernetes-service/src/test/java/org/apache/cloudstack/api/command/user/kubernetes/cluster/CreateKubernetesClusterCmdTest.java
@@ -82,7 +82,7 @@ public class CreateKubernetesClusterCmdTest {
     }
 
     @Test
-    public void testNodeOfferingMapMissingEtcd() {
+    public void testNodeOfferingMap() {
         cmd.serviceOfferingNodeTypeMap = new HashMap<>();
         Map<String, String> firstMap = createMapEntry(WORKER, 
workerNodesOfferingId);
         Map<String, String> secondMap = createMapEntry(CONTROL, 
controlNodesOfferingId);
@@ -101,11 +101,7 @@ public class CreateKubernetesClusterCmdTest {
         cmd.serviceOfferingNodeTypeMap = null;
         cmd.serviceOfferingId = controlOfferingId;
         Map<String, Long> map = cmd.getServiceOfferingNodeTypeMap();
-        Assert.assertNotNull(map);
-        Assert.assertEquals(2, map.size());
-        Assert.assertTrue(map.containsKey(WORKER.name()) && 
map.containsKey(CONTROL.name()));
-        Assert.assertEquals(controlOfferingId, map.get(WORKER.name()));
-        Assert.assertEquals(controlOfferingId, map.get(CONTROL.name()));
+        Assert.assertTrue(map.isEmpty());
     }
 
     @Test
@@ -114,13 +110,10 @@ public class CreateKubernetesClusterCmdTest {
         Map<String, String> firstMap = createMapEntry(ETCD, 
etcdNodesOfferingId);
         cmd.serviceOfferingNodeTypeMap.put("map1", firstMap);
         cmd.etcdNodes = 2L;
-        cmd.serviceOfferingId = controlOfferingId;
         Map<String, Long> map = cmd.getServiceOfferingNodeTypeMap();
         Assert.assertNotNull(map);
-        Assert.assertEquals(3, map.size());
-        Assert.assertTrue(map.containsKey(WORKER.name()) && 
map.containsKey(CONTROL.name()) && map.containsKey(ETCD.name()));
-        Assert.assertEquals(controlOfferingId, map.get(WORKER.name()));
-        Assert.assertEquals(controlOfferingId, map.get(CONTROL.name()));
+        Assert.assertEquals(1, map.size());
+        Assert.assertTrue(map.containsKey(ETCD.name()));
         Assert.assertEquals(etcdOfferingId, map.get(ETCD.name()));
     }
 

Reply via email to