cks,ui: allow changing stopped cluster offering, improvements (#7475)

* cks,ui: allow changing stopped cluster offering, improvements

Fixes #7454

- Allows changing compute offering for a stopped cluster
- Allows compute offering change when the cluster has autoscaling enabled

Signed-off-by: Abhishek Kumar <abhishek.mrt22@gmail.com>
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 150d203..e366216 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
@@ -803,6 +803,34 @@
         }
     }
 
+    protected void validateKubernetesClusterScaleSize(final KubernetesClusterVO kubernetesCluster, final Long clusterSize, final int maxClusterSize, final DataCenter zone) {
+        if (clusterSize == null) {
+            return;
+        }
+        if (clusterSize == kubernetesCluster.getNodeCount()) {
+            return;
+        }
+        if (kubernetesCluster.getState().equals(KubernetesCluster.State.Stopped)) { // Cannot scale stopped cluster currently for cluster size
+            throw new PermissionDeniedException(String.format("Kubernetes cluster : %s is in %s state", kubernetesCluster.getName(), kubernetesCluster.getState().toString()));
+        }
+        if (clusterSize < 1) {
+            throw new InvalidParameterValueException(String.format("Kubernetes cluster : %s cannot be scaled for size, %d", kubernetesCluster.getName(), clusterSize));
+        }
+        if (clusterSize + kubernetesCluster.getControlNodeCount() > maxClusterSize) {
+            throw new InvalidParameterValueException(
+                    String.format("Maximum cluster size can not exceed %d. Please contact your administrator", maxClusterSize));
+        }
+        if (clusterSize > kubernetesCluster.getNodeCount()) { // Upscale
+            VMTemplateVO template = templateDao.findById(kubernetesCluster.getTemplateId());
+            if (template == null) {
+                throw new InvalidParameterValueException(String.format("Invalid template associated with Kubernetes cluster : %s",  kubernetesCluster.getName()));
+            }
+            if (CollectionUtils.isEmpty(templateJoinDao.newTemplateView(template, zone.getId(), true))) {
+                throw new InvalidParameterValueException(String.format("Template : %s associated with Kubernetes cluster : %s is not in Ready state for datacenter : %s", template.getName(), kubernetesCluster.getName(), zone.getName()));
+            }
+        }
+    }
+
     private void validateKubernetesClusterScaleParameters(ScaleKubernetesClusterCmd cmd) {
         final Long kubernetesClusterId = cmd.getId();
         final Long serviceOfferingId = cmd.getServiceOfferingId();
@@ -844,8 +872,8 @@
 
         int maxClusterSize = KubernetesMaxClusterSize.valueIn(kubernetesCluster.getAccountId());
         if (isAutoscalingEnabled != null && isAutoscalingEnabled) {
-            if (clusterSize != null || serviceOfferingId != null || nodeIds != null) {
-                throw new InvalidParameterValueException("Autoscaling can not be passed along with nodeids or clustersize or service offering");
+            if (clusterSize != null || nodeIds != null) {
+                throw new InvalidParameterValueException("Autoscaling can not be passed along with nodeids or clustersize");
             }
 
             if (!KubernetesVersionManagerImpl.versionSupportsAutoscaling(clusterVersion)) {
@@ -914,34 +942,14 @@
                 }
             }
             final ServiceOffering existingServiceOffering = serviceOfferingDao.findById(kubernetesCluster.getServiceOfferingId());
-            if (serviceOffering.getRamSize() < existingServiceOffering.getRamSize() ||
-                    serviceOffering.getCpu() * serviceOffering.getSpeed() < existingServiceOffering.getCpu() * existingServiceOffering.getSpeed()) {
+            if (KubernetesCluster.State.Running.equals(kubernetesCluster.getState()) && (serviceOffering.getRamSize() < existingServiceOffering.getRamSize() ||
+                    serviceOffering.getCpu() * serviceOffering.getSpeed() < existingServiceOffering.getCpu() * existingServiceOffering.getSpeed())) {
                 logAndThrow(Level.WARN, String.format("Kubernetes cluster cannot be scaled down for service offering. Service offering : %s offers lesser resources as compared to service offering : %s of Kubernetes cluster : %s",
                         serviceOffering.getName(), existingServiceOffering.getName(), kubernetesCluster.getName()));
             }
         }
 
-        if (clusterSize != null) {
-            if (kubernetesCluster.getState().equals(KubernetesCluster.State.Stopped)) { // Cannot scale stopped cluster currently for cluster size
-                throw new PermissionDeniedException(String.format("Kubernetes cluster : %s is in %s state", kubernetesCluster.getName(), kubernetesCluster.getState().toString()));
-            }
-            if (clusterSize < 1) {
-                throw new InvalidParameterValueException(String.format("Kubernetes cluster : %s cannot be scaled for size, %d", kubernetesCluster.getName(), clusterSize));
-            }
-            if (clusterSize + kubernetesCluster.getControlNodeCount() > maxClusterSize) {
-                throw new InvalidParameterValueException(
-                    String.format("Maximum cluster size can not exceed %d. Please contact your administrator", maxClusterSize));
-            }
-            if (clusterSize > kubernetesCluster.getNodeCount()) { // Upscale
-                VMTemplateVO template = templateDao.findById(kubernetesCluster.getTemplateId());
-                if (template == null) {
-                    throw new InvalidParameterValueException(String.format("Invalid template associated with Kubernetes cluster : %s",  kubernetesCluster.getName()));
-                }
-                if (CollectionUtils.isEmpty(templateJoinDao.newTemplateView(template, zone.getId(), true))) {
-                    throw new InvalidParameterValueException(String.format("Template : %s associated with Kubernetes cluster : %s is not in Ready state for datacenter : %s", template.getName(), kubernetesCluster.getName(), zone.getName()));
-                }
-            }
-        }
+        validateKubernetesClusterScaleSize(kubernetesCluster, clusterSize, maxClusterSize, zone);
     }
 
     private void validateKubernetesClusterUpgradeParameters(UpgradeKubernetesClusterCmd cmd) {
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 6949c0c..bc06d16 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,29 @@
 
 package com.cloud.kubernetes.cluster.actionworkers;
 
+import static com.cloud.utils.NumbersUtil.toHumanReadableSize;
+
+import java.io.File;
+import java.io.IOException;
+import java.lang.reflect.Field;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+import javax.inject.Inject;
+
+import org.apache.cloudstack.api.ApiConstants;
+import org.apache.cloudstack.api.BaseCmd;
+import org.apache.cloudstack.api.command.user.firewall.CreateFirewallRuleCmd;
+import org.apache.cloudstack.api.command.user.vm.StartVMCmd;
+import org.apache.cloudstack.api.command.user.volume.ResizeVolumeCmd;
+import org.apache.commons.codec.binary.Base64;
+import org.apache.commons.collections.CollectionUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.log4j.Level;
+
 import com.cloud.capacity.CapacityManager;
 import com.cloud.dc.ClusterDetailsDao;
 import com.cloud.dc.ClusterDetailsVO;
@@ -77,28 +100,6 @@
 import com.cloud.vm.VmDetailConstants;
 import com.cloud.vm.dao.VMInstanceDao;
 
-import org.apache.cloudstack.api.ApiConstants;
-import org.apache.cloudstack.api.BaseCmd;
-import org.apache.cloudstack.api.command.user.firewall.CreateFirewallRuleCmd;
-import org.apache.cloudstack.api.command.user.vm.StartVMCmd;
-import org.apache.cloudstack.api.command.user.volume.ResizeVolumeCmd;
-import org.apache.commons.codec.binary.Base64;
-import org.apache.commons.collections.CollectionUtils;
-import org.apache.commons.lang3.StringUtils;
-import org.apache.log4j.Level;
-
-import javax.inject.Inject;
-import java.io.File;
-import java.io.IOException;
-import java.lang.reflect.Field;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.concurrent.ConcurrentHashMap;
-
-import static com.cloud.utils.NumbersUtil.toHumanReadableSize;
-
 public class KubernetesClusterResourceModifierActionWorker extends KubernetesClusterActionWorker {
 
     @Inject
@@ -669,7 +670,6 @@
         } finally {
             // Deploying the autoscaler might fail but it can be deployed manually too, so no need to go to an alert state
             updateLoginUserDetails(null);
-            stateTransitTo(kubernetesCluster.getId(), KubernetesCluster.Event.OperationSucceeded);
         }
     }
 }
diff --git a/plugins/integrations/kubernetes-service/src/main/java/com/cloud/kubernetes/cluster/actionworkers/KubernetesClusterScaleWorker.java b/plugins/integrations/kubernetes-service/src/main/java/com/cloud/kubernetes/cluster/actionworkers/KubernetesClusterScaleWorker.java
index a335757..b6c9f52 100644
--- a/plugins/integrations/kubernetes-service/src/main/java/com/cloud/kubernetes/cluster/actionworkers/KubernetesClusterScaleWorker.java
+++ b/plugins/integrations/kubernetes-service/src/main/java/com/cloud/kubernetes/cluster/actionworkers/KubernetesClusterScaleWorker.java
@@ -28,6 +28,7 @@
 
 import org.apache.cloudstack.api.InternalIdentity;
 import org.apache.commons.collections.CollectionUtils;
+import org.apache.commons.lang3.StringUtils;
 import org.apache.log4j.Level;
 
 import com.cloud.dc.DataCenter;
@@ -57,7 +58,6 @@
 import com.cloud.vm.VMInstanceVO;
 import com.cloud.vm.VirtualMachine;
 import com.cloud.vm.dao.VMInstanceDao;
-import org.apache.commons.lang3.StringUtils;
 
 public class KubernetesClusterScaleWorker extends KubernetesClusterResourceModifierActionWorker {
 
@@ -406,6 +406,19 @@
         kubernetesCluster = updateKubernetesClusterEntry(clusterSize, null);
     }
 
+    private boolean isAutoscalingChanged() {
+        if (this.isAutoscalingEnabled == null) {
+            return false;
+        }
+        if (this.isAutoscalingEnabled != kubernetesCluster.getAutoscalingEnabled()) {
+            return true;
+        }
+        if (minSize != null && (!minSize.equals(kubernetesCluster.getMinSize()))) {
+            return true;
+        }
+        return maxSize != null && (!maxSize.equals(kubernetesCluster.getMaxSize()));
+    }
+
     public boolean scaleCluster() throws CloudRuntimeException {
         init();
         if (LOGGER.isInfoEnabled()) {
@@ -417,11 +430,17 @@
         if (existingServiceOffering == null) {
             logAndThrow(Level.ERROR, String.format("Scaling Kubernetes cluster : %s failed, service offering for the Kubernetes cluster not found!", kubernetesCluster.getName()));
         }
-
-        if (this.isAutoscalingEnabled != null) {
-            return autoscaleCluster(this.isAutoscalingEnabled, minSize, maxSize);
-        }
+        final boolean autscalingChanged = isAutoscalingChanged();
         final boolean serviceOfferingScalingNeeded = serviceOffering != null && serviceOffering.getId() != existingServiceOffering.getId();
+
+        if (autscalingChanged) {
+            boolean autoScaled = autoscaleCluster(this.isAutoscalingEnabled, minSize, maxSize);
+            if (autoScaled && serviceOfferingScalingNeeded) {
+                scaleKubernetesClusterOffering();
+            }
+            stateTransitTo(kubernetesCluster.getId(), KubernetesCluster.Event.OperationSucceeded);
+            return autoScaled;
+        }
         final boolean clusterSizeScalingNeeded = clusterSize != null && clusterSize != originalClusterSize;
         final long newVMRequired = clusterSize == null ? 0 : clusterSize - originalClusterSize;
         if (serviceOfferingScalingNeeded && clusterSizeScalingNeeded) {
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
new file mode 100644
index 0000000..8475c9e
--- /dev/null
+++ b/plugins/integrations/kubernetes-service/src/test/java/com/cloud/kubernetes/cluster/KubernetesClusterManagerImplTest.java
@@ -0,0 +1,129 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package com.cloud.kubernetes.cluster;
+
+import java.util.List;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.Spy;
+import org.mockito.junit.MockitoJUnitRunner;
+
+import com.cloud.api.query.dao.TemplateJoinDao;
+import com.cloud.api.query.vo.TemplateJoinVO;
+import com.cloud.dc.DataCenter;
+import com.cloud.exception.InvalidParameterValueException;
+import com.cloud.exception.PermissionDeniedException;
+import com.cloud.storage.VMTemplateVO;
+import com.cloud.storage.dao.VMTemplateDao;
+
+@RunWith(MockitoJUnitRunner.class)
+public class KubernetesClusterManagerImplTest {
+
+    @Mock
+    VMTemplateDao templateDao;
+
+    @Mock
+    TemplateJoinDao templateJoinDao;
+
+    @Spy
+    @InjectMocks
+    KubernetesClusterManagerImpl clusterManager;
+
+    @Test
+    public void testValidateKubernetesClusterScaleSizeNullNewSizeNoError() {
+        clusterManager.validateKubernetesClusterScaleSize(Mockito.mock(KubernetesClusterVO.class), null, 100, Mockito.mock(DataCenter.class));
+    }
+
+    @Test
+    public void testValidateKubernetesClusterScaleSizeSameNewSizeNoError() {
+        Long size = 2L;
+        KubernetesClusterVO clusterVO = Mockito.mock(KubernetesClusterVO.class);
+        Mockito.when(clusterVO.getNodeCount()).thenReturn(size);
+        clusterManager.validateKubernetesClusterScaleSize(clusterVO, size, 100, Mockito.mock(DataCenter.class));
+    }
+
+    @Test(expected = PermissionDeniedException.class)
+    public void testValidateKubernetesClusterScaleSizeStoppedCluster() {
+        Long size = 2L;
+        KubernetesClusterVO clusterVO = Mockito.mock(KubernetesClusterVO.class);
+        Mockito.when(clusterVO.getNodeCount()).thenReturn(size);
+        Mockito.when(clusterVO.getState()).thenReturn(KubernetesCluster.State.Stopped);
+        clusterManager.validateKubernetesClusterScaleSize(clusterVO, 3L, 100, Mockito.mock(DataCenter.class));
+    }
+
+    @Test(expected = InvalidParameterValueException.class)
+    public void testValidateKubernetesClusterScaleSizeZeroNewSize() {
+        Long size = 2L;
+        KubernetesClusterVO clusterVO = Mockito.mock(KubernetesClusterVO.class);
+        Mockito.when(clusterVO.getState()).thenReturn(KubernetesCluster.State.Running);
+        Mockito.when(clusterVO.getNodeCount()).thenReturn(size);
+        clusterManager.validateKubernetesClusterScaleSize(clusterVO, 0L, 100, Mockito.mock(DataCenter.class));
+    }
+
+    @Test(expected = InvalidParameterValueException.class)
+    public void testValidateKubernetesClusterScaleSizeOverMaxSize() {
+        KubernetesClusterVO clusterVO = Mockito.mock(KubernetesClusterVO.class);
+        Mockito.when(clusterVO.getState()).thenReturn(KubernetesCluster.State.Running);
+        Mockito.when(clusterVO.getControlNodeCount()).thenReturn(1L);
+        clusterManager.validateKubernetesClusterScaleSize(clusterVO, 4L, 4, Mockito.mock(DataCenter.class));
+    }
+
+    @Test
+    public void testValidateKubernetesClusterScaleSizeDownsacaleNoError() {
+        KubernetesClusterVO clusterVO = Mockito.mock(KubernetesClusterVO.class);
+        Mockito.when(clusterVO.getState()).thenReturn(KubernetesCluster.State.Running);
+        Mockito.when(clusterVO.getControlNodeCount()).thenReturn(1L);
+        Mockito.when(clusterVO.getNodeCount()).thenReturn(4L);
+        clusterManager.validateKubernetesClusterScaleSize(clusterVO, 2L, 10, Mockito.mock(DataCenter.class));
+    }
+
+    @Test(expected = InvalidParameterValueException.class)
+    public void testValidateKubernetesClusterScaleSizeUpscaleDeletedTemplate() {
+        KubernetesClusterVO clusterVO = Mockito.mock(KubernetesClusterVO.class);
+        Mockito.when(clusterVO.getState()).thenReturn(KubernetesCluster.State.Running);
+        Mockito.when(clusterVO.getControlNodeCount()).thenReturn(1L);
+        Mockito.when(clusterVO.getNodeCount()).thenReturn(2L);
+        Mockito.when(templateDao.findById(Mockito.anyLong())).thenReturn(null);
+        clusterManager.validateKubernetesClusterScaleSize(clusterVO, 4L, 10, Mockito.mock(DataCenter.class));
+    }
+
+    @Test(expected = InvalidParameterValueException.class)
+    public void testValidateKubernetesClusterScaleSizeUpscaleNotInZoneTemplate() {
+        KubernetesClusterVO clusterVO = Mockito.mock(KubernetesClusterVO.class);
+        Mockito.when(clusterVO.getState()).thenReturn(KubernetesCluster.State.Running);
+        Mockito.when(clusterVO.getControlNodeCount()).thenReturn(1L);
+        Mockito.when(clusterVO.getNodeCount()).thenReturn(2L);
+        Mockito.when(templateDao.findById(Mockito.anyLong())).thenReturn(Mockito.mock(VMTemplateVO.class));
+        Mockito.when(templateJoinDao.newTemplateView(Mockito.any(VMTemplateVO.class), Mockito.anyLong(), Mockito.anyBoolean())).thenReturn(null);
+        clusterManager.validateKubernetesClusterScaleSize(clusterVO, 4L, 10, Mockito.mock(DataCenter.class));
+    }
+
+    @Test
+    public void testValidateKubernetesClusterScaleSizeUpscaleNoError() {
+        KubernetesClusterVO clusterVO = Mockito.mock(KubernetesClusterVO.class);
+        Mockito.when(clusterVO.getState()).thenReturn(KubernetesCluster.State.Running);
+        Mockito.when(clusterVO.getControlNodeCount()).thenReturn(1L);
+        Mockito.when(clusterVO.getNodeCount()).thenReturn(2L);
+        Mockito.when(templateDao.findById(Mockito.anyLong())).thenReturn(Mockito.mock(VMTemplateVO.class));
+        Mockito.when(templateJoinDao.newTemplateView(Mockito.any(VMTemplateVO.class), Mockito.anyLong(), Mockito.anyBoolean())).thenReturn(List.of(Mockito.mock(TemplateJoinVO.class)));
+        clusterManager.validateKubernetesClusterScaleSize(clusterVO, 4L, 10, Mockito.mock(DataCenter.class));
+    }
+}
\ No newline at end of file
diff --git a/ui/src/config/section/compute.js b/ui/src/config/section/compute.js
index e933baf..5393e8b 100644
--- a/ui/src/config/section/compute.js
+++ b/ui/src/config/section/compute.js
@@ -504,7 +504,7 @@
           message: 'message.kubernetes.cluster.scale',
           docHelp: 'plugins/cloudstack-kubernetes-service.html#scaling-kubernetes-cluster',
           dataView: true,
-          show: (record) => { return ['Created', 'Running'].includes(record.state) },
+          show: (record) => { return ['Created', 'Running', 'Stopped'].includes(record.state) },
           popup: true,
           component: shallowRef(defineAsyncComponent(() => import('@/views/compute/ScaleKubernetesCluster.vue')))
         },
diff --git a/ui/src/views/compute/ScaleKubernetesCluster.vue b/ui/src/views/compute/ScaleKubernetesCluster.vue
index 17f605d..f9af2ef 100644
--- a/ui/src/views/compute/ScaleKubernetesCluster.vue
+++ b/ui/src/views/compute/ScaleKubernetesCluster.vue
@@ -28,6 +28,25 @@
         :rules="rules"
         @finish="handleSubmit"
         layout="vertical">
+        <a-form-item name="serviceofferingid" ref="serviceofferingid">
+          <template #label>
+            <tooltip-label :title="$t('label.serviceofferingid')" :tooltip="apiParams.serviceofferingid.description"/>
+          </template>
+          <a-select
+            id="offering-selection"
+            v-model:value="form.serviceofferingid"
+            showSearch
+            optionFilterProp="label"
+            :filterOption="(input, option) => {
+              return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
+            }"
+            :loading="serviceOfferingLoading"
+            :placeholder="apiParams.serviceofferingid.description">
+            <a-select-option v-for="(opt, optIndex) in serviceOfferings" :key="optIndex">
+              {{ opt.name || opt.description }}
+            </a-select-option>
+          </a-select>
+        </a-form-item>
         <a-form-item name="autoscalingenabled" ref="autoscalingenabled" v-if="apiParams.autoscalingenabled">
           <template #label>
             <tooltip-label :title="$t('label.cks.cluster.autoscalingenabled')" :tooltip="apiParams.autoscalingenabled.description"/>
@@ -53,26 +72,7 @@
           </a-form-item>
         </span>
         <span v-else>
-          <a-form-item name="serviceofferingid" ref="serviceofferingid">
-            <template #label>
-              <tooltip-label :title="$t('label.serviceofferingid')" :tooltip="apiParams.serviceofferingid.description"/>
-            </template>
-            <a-select
-              id="offering-selection"
-              v-model:value="form.serviceofferingid"
-              showSearch
-              optionFilterProp="label"
-              :filterOption="(input, option) => {
-                return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
-              }"
-              :loading="serviceOfferingLoading"
-              :placeholder="apiParams.serviceofferingid.description">
-              <a-select-option v-for="(opt, optIndex) in serviceOfferings" :key="optIndex">
-                {{ opt.name || opt.description }}
-              </a-select-option>
-            </a-select>
-          </a-form-item>
-          <a-form-item name="size" ref="size">
+          <a-form-item name="size" ref="size" v-if="['Created', 'Running'].includes(resource.state)">
             <template #label>
               <tooltip-label :title="$t('label.cks.cluster.size')" :tooltip="apiParams.size.description"/>
             </template>
@@ -152,6 +152,10 @@
       })
     },
     fetchData () {
+      if (this.resource.state === 'Running') {
+        this.fetchKubernetesClusterServiceOfferingData()
+        return
+      }
       this.fetchKubernetesVersionData()
     },
     isValidValueForKey (obj, key) {
@@ -163,13 +167,28 @@
     isObjectEmpty (obj) {
       return !(obj !== null && obj !== undefined && Object.keys(obj).length > 0 && obj.constructor === Object)
     },
+    fetchKubernetesClusterServiceOfferingData () {
+      const params = {}
+      if (!this.isObjectEmpty(this.resource)) {
+        params.id = this.resource.serviceofferingid
+      }
+      api('listServiceOfferings', params).then(json => {
+        var items = json?.listserviceofferingsresponse?.serviceoffering || []
+        if (this.arrayHasItems(items) && !this.isObjectEmpty(items[0])) {
+          this.minCpu = items[0].cpunumber
+          this.minMemory = items[0].memory
+        }
+      }).finally(() => {
+        this.fetchServiceOfferingData()
+      })
+    },
     fetchKubernetesVersionData () {
       const params = {}
       if (!this.isObjectEmpty(this.resource)) {
         params.id = this.resource.kubernetesversionid
       }
       api('listKubernetesSupportedVersions', params).then(json => {
-        const versionObjs = json.listkubernetessupportedversionsresponse.kubernetessupportedversion
+        const versionObjs = json?.listkubernetessupportedversionsresponse?.kubernetessupportedversion || []
         if (this.arrayHasItems(versionObjs) && !this.isObjectEmpty(versionObjs[0])) {
           this.minCpu = versionObjs[0].mincpunumber
           this.minMemory = versionObjs[0].minmemory
@@ -180,14 +199,16 @@
     },
     fetchServiceOfferingData () {
       this.serviceOfferings = []
-      const params = {}
+      const params = {
+        cpunumber: this.minCpu,
+        memory: this.minMemory
+      }
       this.serviceOfferingLoading = true
       api('listServiceOfferings', params).then(json => {
-        var items = json.listserviceofferingsresponse.serviceoffering
-        if (items != null) {
+        var items = json?.listserviceofferingsresponse?.serviceoffering || []
+        if (this.arrayHasItems(items)) {
           for (var i = 0; i < items.length; i++) {
-            if (items[i].iscustomized === false &&
-                items[i].cpunumber >= this.minCpu && items[i].memory >= this.minMemory) {
+            if (items[i].iscustomized === false) {
               this.serviceOfferings.push(items[i])
             }
           }
@@ -220,7 +241,7 @@
         if (this.isValidValueForKey(values, 'size') && values.size > 0) {
           params.size = values.size
         }
-        if (this.isValidValueForKey(values, 'serviceofferingid') && this.arrayHasItems(this.serviceOfferings) && this.autoscalingenabled == null) {
+        if (this.isValidValueForKey(values, 'serviceofferingid') && this.arrayHasItems(this.serviceOfferings)) {
           params.serviceofferingid = this.serviceOfferings[values.serviceofferingid].id
         }
         if (this.isValidValueForKey(values, 'minsize')) {