You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cloudstack.apache.org by we...@apache.org on 2022/11/08 09:45:07 UTC

[cloudstack] branch 4.18-vm-autoscaling updated (3356cc4a24c -> 489cfba3816)

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

weizhou pushed a change to branch 4.18-vm-autoscaling
in repository https://gitbox.apache.org/repos/asf/cloudstack.git


    from 3356cc4a24c AS: rename counter names
     new 242398df178 AS: fix code smell and add unit test AutoScaleVmProfileVOTest
     new 1e4aaa538cd AS: check AS group name (a-zA-Z0-9 and hyphen only)
     new 489cfba3816 AS: add capability VmAutoScaling to Lb Service

The 3 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 api/src/main/java/com/cloud/network/Network.java   |  1 +
 .../java/com/cloud/offering/NetworkOffering.java   |  2 +
 .../org/apache/cloudstack/api/ApiConstants.java    |  1 +
 .../cloudstack/api/response/NetworkResponse.java   | 12 ++++
 .../com/cloud/network/as/AutoScaleVmProfileVO.java |  4 ++
 .../com/cloud/offerings/NetworkOfferingVO.java     | 12 ++++
 .../resources/META-INF/db/schema-41710to41800.sql  | 72 +++++++++++++++++++
 .../cloud/network/as/AutoScaleVmProfileVOTest.java | 65 +++++++++++++++++
 .../as/dao/AutoScaleVmGroupVmMapDaoImplTest.java   | 14 ++++
 .../cloud/network/element/NetscalerElement.java    |  1 +
 .../main/java/com/cloud/api/ApiResponseHelper.java |  6 ++
 .../cloud/api/query/vo/NetworkOfferingJoinVO.java  |  8 +++
 .../configuration/ConfigurationManagerImpl.java    | 28 ++++++--
 .../com/cloud/network/as/AutoScaleManagerImpl.java | 52 +++++++++++---
 .../network/element/VirtualRouterElement.java      |  1 +
 .../cloud/network/as/AutoScaleManagerImplTest.java | 84 +++++++++++++++++++---
 test/integration/smoke/test_vm_autoscaling.py      |  6 ++
 ui/public/locales/en.json                          |  4 ++
 ui/src/views/compute/CreateAutoScaleVmGroup.vue    | 19 +++++
 ui/src/views/compute/wizard/NetworkSelection.vue   | 10 ++-
 ui/src/views/offering/AddNetworkOffering.vue       | 13 ++++
 21 files changed, 389 insertions(+), 26 deletions(-)
 create mode 100755 engine/schema/src/test/java/com/cloud/network/as/AutoScaleVmProfileVOTest.java


[cloudstack] 02/03: AS: check AS group name (a-zA-Z0-9 and hyphen only)

Posted by we...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

weizhou pushed a commit to branch 4.18-vm-autoscaling
in repository https://gitbox.apache.org/repos/asf/cloudstack.git

commit 1e4aaa538cd71ad7ebec2bc8e86828e528bf73f4
Author: Wei Zhou <we...@apache.org>
AuthorDate: Tue Nov 8 10:43:05 2022 +0100

    AS: check AS group name (a-zA-Z0-9 and hyphen only)
---
 .../com/cloud/network/as/AutoScaleManagerImpl.java | 28 ++++++++--
 .../cloud/network/as/AutoScaleManagerImplTest.java | 60 +++++++++++++++++++---
 ui/public/locales/en.json                          |  1 +
 ui/src/views/compute/CreateAutoScaleVmGroup.vue    |  9 ++++
 4 files changed, 87 insertions(+), 11 deletions(-)

diff --git a/server/src/main/java/com/cloud/network/as/AutoScaleManagerImpl.java b/server/src/main/java/com/cloud/network/as/AutoScaleManagerImpl.java
index 477b16e5836..6c6a1fb07d6 100644
--- a/server/src/main/java/com/cloud/network/as/AutoScaleManagerImpl.java
+++ b/server/src/main/java/com/cloud/network/as/AutoScaleManagerImpl.java
@@ -282,7 +282,8 @@ public class AutoScaleManagerImpl extends ManagerBase implements AutoScaleManage
     private static final List<String> supportedDeployParams = Arrays.asList(PARAM_ROOT_DISK_SIZE, PARAM_DISK_OFFERING_ID, PARAM_DISK_SIZE, PARAM_SECURITY_GROUP_IDS,
             PARAM_OVERRIDE_DISK_OFFERING_ID, PARAM_SSH_KEYPAIRS, PARAM_AFFINITY_GROUP_IDS, PARAM_NETWORK_IDS);
 
-    private static final String VM_HOSTNAME_PREFIX = "autoScaleVm";
+    protected static final String VM_HOSTNAME_PREFIX = "autoScaleVm-";
+    protected static final int VM_HOSTNAME_RANDOM_SUFFIX_LENGTH = 6;
 
     private static final Long DEFAULT_HOST_ID = -1L;
 
@@ -1168,6 +1169,9 @@ public class AutoScaleManagerImpl extends ManagerBase implements AutoScaleManage
     @DB
     protected AutoScaleVmGroupVO checkValidityAndPersist(final AutoScaleVmGroupVO vmGroup, final List<Long> passedScaleUpPolicyIds,
         final List<Long> passedScaleDownPolicyIds) {
+
+        checkAutoScaleVmGroupName(vmGroup.getName());
+
         int minMembers = vmGroup.getMinMembers();
         int maxMembers = vmGroup.getMaxMembers();
         int interval = vmGroup.getInterval();
@@ -1882,8 +1886,26 @@ public class AutoScaleManagerImpl extends ManagerBase implements AutoScaleManage
     }
 
     private String getNextVmHostName(AutoScaleVmGroupVO asGroup) {
-        return VM_HOSTNAME_PREFIX + "-" + asGroup.getName() + "-" + asGroup.getNextVmSeq() + "-" +
-                RandomStringUtils.random(6, 0, 0, true, false, (char[])null, new SecureRandom()).toLowerCase();
+        String vmHostNameSuffix = "-" + asGroup.getNextVmSeq() + "-" +
+                RandomStringUtils.random(VM_HOSTNAME_RANDOM_SUFFIX_LENGTH, 0, 0, true, false, (char[])null, new SecureRandom()).toLowerCase();
+        // Truncate vm group name because max length of vm name is 63
+        int subStringLength = Math.min(asGroup.getName().length(), 63 - VM_HOSTNAME_PREFIX.length() - vmHostNameSuffix.length());
+        return VM_HOSTNAME_PREFIX + asGroup.getName().substring(0, subStringLength) + vmHostNameSuffix;
+    }
+
+    private void checkAutoScaleVmGroupName(String groupName) {
+        String errorMessage = "";
+        if (groupName == null || groupName.length() > 255 || groupName.length() < 1) {
+            errorMessage = "AutoScale Vm Group name must be between 1 and 255 characters long";
+        } else if (!groupName.toLowerCase().matches("[a-z0-9-]*")) {
+            errorMessage = "AutoScale Vm Group name may contain only the ASCII letters 'a' through 'z' (in a case-insensitive manner), " +
+                    "the digits '0' through '9' and the hyphen ('-')";
+        }
+        if (StringUtils.isNotBlank(errorMessage)) {
+            s_logger.warn(errorMessage);
+            throw new InvalidParameterValueException("Invalid AutoScale VM group name. It can contain the ASCII letters 'a' through 'z', " +
+                    "'A' through 'Z', the digits '0' through '9' and the hyphen ('-'), must be between 1 and 255 characters long.");
+        }
     }
 
     private boolean startNewVM(long vmId) {
diff --git a/server/src/test/java/com/cloud/network/as/AutoScaleManagerImplTest.java b/server/src/test/java/com/cloud/network/as/AutoScaleManagerImplTest.java
index b494c02fe98..ba58c7b5157 100644
--- a/server/src/test/java/com/cloud/network/as/AutoScaleManagerImplTest.java
+++ b/server/src/test/java/com/cloud/network/as/AutoScaleManagerImplTest.java
@@ -153,8 +153,8 @@ import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyLong;
 import static org.mockito.ArgumentMatchers.anyString;
 import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.ArgumentMatchers.matches;
 import static org.mockito.ArgumentMatchers.nullable;
-
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.when;
@@ -294,6 +294,9 @@ public class AutoScaleManagerImplTest {
 
     private static final Long vmGroupId = 22L;
     private static final String vmGroupName = "test-vmgroup";
+    private static final String vmGroupNameWithMaxLength = "12345678901234567890123456789012345678901234567890" +
+            "1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890" +
+            "123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345";
     private static final String vmGroupUuid = "2222-2222-1111";
     private static final int minMembers = 2;
     private static final int maxMembers = 3;
@@ -952,12 +955,13 @@ public class AutoScaleManagerImplTest {
         UpdateAutoScaleVmGroupCmd cmd = new UpdateAutoScaleVmGroupCmd();
 
         ReflectionTestUtils.setField(cmd, "id", vmGroupId);
-        ReflectionTestUtils.setField(cmd, "name", vmGroupName + "-new");
+        ReflectionTestUtils.setField(cmd, "name", vmGroupNameWithMaxLength);
         ReflectionTestUtils.setField(cmd, "minMembers", minMembers + 1);
         ReflectionTestUtils.setField(cmd, "maxMembers", maxMembers + 1);
         ReflectionTestUtils.setField(cmd, "interval", interval);
 
         when(autoScaleVmGroupDao.findById(vmGroupId)).thenReturn(asVmGroupMock);
+        when(asVmGroupMock.getName()).thenReturn(vmGroupNameWithMaxLength);
         when(asVmGroupMock.getInterval()).thenReturn(interval);
         when(asVmGroupMock.getMaxMembers()).thenReturn(maxMembers);
         when(asVmGroupMock.getMinMembers()).thenReturn(minMembers);
@@ -992,7 +996,7 @@ public class AutoScaleManagerImplTest {
 
         Assert.assertEquals(asVmGroupMock, vmGroup);
 
-        Mockito.verify(asVmGroupMock).setName(vmGroupName + "-new");
+        Mockito.verify(asVmGroupMock).setName(vmGroupNameWithMaxLength);
         Mockito.verify(asVmGroupMock).setMinMembers(minMembers + 1);
         Mockito.verify(asVmGroupMock).setMaxMembers(maxMembers + 1);
         Mockito.verify(asVmGroupMock).setInterval(interval);
@@ -1003,7 +1007,7 @@ public class AutoScaleManagerImplTest {
         UpdateAutoScaleVmGroupCmd cmd = new UpdateAutoScaleVmGroupCmd();
 
         ReflectionTestUtils.setField(cmd, "id", vmGroupId);
-        ReflectionTestUtils.setField(cmd, "name", vmGroupName + "new");
+        ReflectionTestUtils.setField(cmd, "name", vmGroupName + "-new");
         ReflectionTestUtils.setField(cmd, "minMembers", minMembers + 1);
         ReflectionTestUtils.setField(cmd, "maxMembers", maxMembers + 1);
         ReflectionTestUtils.setField(cmd, "interval", interval);
@@ -1018,6 +1022,34 @@ public class AutoScaleManagerImplTest {
         AutoScaleVmGroup vmGroup = autoScaleManagerImplSpy.updateAutoScaleVmGroup(cmd);
     }
 
+    @Test(expected = InvalidParameterValueException.class)
+    public void testUpdateAutoScaleVmGroupFail2() {
+        UpdateAutoScaleVmGroupCmd cmd = new UpdateAutoScaleVmGroupCmd();
+
+        ReflectionTestUtils.setField(cmd, "id", vmGroupId);
+        String newName = vmGroupName + "!";
+        ReflectionTestUtils.setField(cmd, "name", newName);
+        when(asVmGroupMock.getName()).thenReturn(newName);
+
+        when(autoScaleVmGroupDao.findById(vmGroupId)).thenReturn(asVmGroupMock);
+
+        AutoScaleVmGroup vmGroup = autoScaleManagerImplSpy.updateAutoScaleVmGroup(cmd);
+    }
+
+    @Test(expected = InvalidParameterValueException.class)
+    public void testUpdateAutoScaleVmGroupFail3() {
+        UpdateAutoScaleVmGroupCmd cmd = new UpdateAutoScaleVmGroupCmd();
+
+        ReflectionTestUtils.setField(cmd, "id", vmGroupId);
+        String newName = vmGroupNameWithMaxLength + "6";
+        ReflectionTestUtils.setField(cmd, "name", newName);
+        when(asVmGroupMock.getName()).thenReturn(newName);
+
+        when(autoScaleVmGroupDao.findById(vmGroupId)).thenReturn(asVmGroupMock);
+
+        AutoScaleVmGroup vmGroup = autoScaleManagerImplSpy.updateAutoScaleVmGroup(cmd);
+    }
+
     @Test
     public void testEnableAutoScaleVmGroupInEnabledState() {
         when(autoScaleVmGroupDao.findById(vmGroupId)).thenReturn(asVmGroupMock);
@@ -1144,6 +1176,7 @@ public class AutoScaleManagerImplTest {
         when(asVmGroupMock.getProfileId()).thenReturn(vmProfileId);
         when(asVmGroupMock.getLoadBalancerId()).thenReturn(loadBalancerId);
         when(asVmGroupMock.getNextVmSeq()).thenReturn(nextVmSeq);
+        when(asVmGroupMock.getName()).thenReturn(vmGroupName);
 
         when(autoScaleVmProfileDao.findById(vmProfileId)).thenReturn(asVmProfileMock);
         when(asVmProfileMock.getTemplateId()).thenReturn(templateId);
@@ -1174,7 +1207,10 @@ public class AutoScaleManagerImplTest {
 
         Assert.assertEquals((long) virtualMachineId, result);
 
-        Mockito.verify(userVmService).createBasicSecurityGroupVirtualMachine(any(), any(), any(), any(), any(), any(), any(),
+        String vmHostNamePattern = autoScaleManagerImplSpy.VM_HOSTNAME_PREFIX + vmGroupName +
+                "-" + asVmGroupMock.getNextVmSeq() + "-[a-z]{6}";
+        Mockito.verify(userVmService).createBasicSecurityGroupVirtualMachine(any(), any(), any(), any(), any(),
+                matches(vmHostNamePattern), matches(vmHostNamePattern),
                 any(), any(), any(), any(), any(), any(), any(), any(), any(), any(), any(), eq(true), any(), any(), any(),
                 any(), any(), any(), any(), eq(true), any());
         Mockito.verify(asVmGroupMock).setNextVmSeq(nextVmSeq + 1);
@@ -1185,6 +1221,7 @@ public class AutoScaleManagerImplTest {
         when(asVmGroupMock.getProfileId()).thenReturn(vmProfileId);
         when(asVmGroupMock.getLoadBalancerId()).thenReturn(loadBalancerId);
         when(asVmGroupMock.getNextVmSeq()).thenReturn(nextVmSeq + 1);
+        when(asVmGroupMock.getName()).thenReturn(vmGroupName);
 
         when(autoScaleVmProfileDao.findById(vmProfileId)).thenReturn(asVmProfileMock);
         when(asVmProfileMock.getTemplateId()).thenReturn(templateId);
@@ -1216,8 +1253,11 @@ public class AutoScaleManagerImplTest {
 
         Assert.assertEquals((long) virtualMachineId, result);
 
-        Mockito.verify(userVmService).createAdvancedSecurityGroupVirtualMachine(any(), any(), any(), any(), any(), any(), any(),
-                any(), any(), any(), any(), any(), any(), any(), any(), any(), any(), any(), any(), any(), any(), any(),
+        String vmHostNamePattern = autoScaleManagerImplSpy.VM_HOSTNAME_PREFIX + vmGroupName +
+                "-" + asVmGroupMock.getNextVmSeq() + "-[a-z]{6}";
+        Mockito.verify(userVmService).createAdvancedSecurityGroupVirtualMachine(any(), any(), any(), any(), any(), any(),
+                matches(vmHostNamePattern), matches(vmHostNamePattern),
+                any(), any(), any(), any(), any(), any(), any(), any(), any(), any(), any(), any(), any(), any(),
                 any(), any(), any(), any(), any(), eq(true), any(), any());
         Mockito.verify(asVmGroupMock).setNextVmSeq(nextVmSeq + 2);
     }
@@ -1227,6 +1267,7 @@ public class AutoScaleManagerImplTest {
         when(asVmGroupMock.getProfileId()).thenReturn(vmProfileId);
         when(asVmGroupMock.getLoadBalancerId()).thenReturn(loadBalancerId);
         when(asVmGroupMock.getNextVmSeq()).thenReturn(nextVmSeq + 2);
+        when(asVmGroupMock.getName()).thenReturn(vmGroupNameWithMaxLength);
 
         when(autoScaleVmProfileDao.findById(vmProfileId)).thenReturn(asVmProfileMock);
         when(asVmProfileMock.getTemplateId()).thenReturn(templateId);
@@ -1258,7 +1299,10 @@ public class AutoScaleManagerImplTest {
 
         Assert.assertEquals((long) virtualMachineId, result);
 
-        Mockito.verify(userVmService).createAdvancedVirtualMachine(any(), any(), any(), any(), any(), any(), any(),
+        String vmHostNamePattern = autoScaleManagerImplSpy.VM_HOSTNAME_PREFIX + vmGroupNameWithMaxLength.substring(0, 41) +
+                "-" + asVmGroupMock.getNextVmSeq() + "-[a-z]{6}";
+        Mockito.verify(userVmService).createAdvancedVirtualMachine(any(), any(), any(), any(), any(),
+                matches(vmHostNamePattern), matches(vmHostNamePattern),
                 any(), any(), any(), any(), any(), any(), any(), any(), any(), any(), any(), eq(true), any(), any(), any(),
                 any(), any(), any(), any(), eq(true), any(), any());
         Mockito.verify(asVmGroupMock).setNextVmSeq(nextVmSeq + 3);
diff --git a/ui/public/locales/en.json b/ui/public/locales/en.json
index 1742e7c5c40..be87ccb031e 100644
--- a/ui/public/locales/en.json
+++ b/ui/public/locales/en.json
@@ -2314,6 +2314,7 @@
 "message.error.internallb.instance.port": "Please specify a instance port.",
 "message.error.internallb.name": "Please specify a name for the internal LB.",
 "message.error.internallb.source.port": "Please specify a source port.",
+"message.error.invalid.autoscale.vmgroup.name": "Invalid AutoScale VM group name. It can contain the ASCII letters 'a' through 'z', 'A' through 'Z', the digits '0' through '9' and the hyphen ('-'), must be between 1 and 255 characters long.",
 "message.error.ip.range": "Please enter valid range.",
 "message.error.ipv4.address": "Please enter a valid IPv4 address.",
 "message.error.ipv4.dns1": "Please enter IpV4 DNS 1.",
diff --git a/ui/src/views/compute/CreateAutoScaleVmGroup.vue b/ui/src/views/compute/CreateAutoScaleVmGroup.vue
index fc2cb3bca50..432a98e5466 100644
--- a/ui/src/views/compute/CreateAutoScaleVmGroup.vue
+++ b/ui/src/views/compute/CreateAutoScaleVmGroup.vue
@@ -2225,6 +2225,15 @@ export default {
           return
         }
 
+        const regex = /^([a-zA-Z0-9-]){0,255}$/
+        if (!values.name || values.name.length === 0 || !regex.test(values.name)) {
+          this.$notification.error({
+            message: this.$t('message.request.failed'),
+            description: this.$t('message.error.invalid.autoscale.vmgroup.name')
+          })
+          return
+        }
+
         if (this.scaleUpPolicies.length === 0) {
           this.$notification.error({
             message: this.$t('message.request.failed'),


[cloudstack] 01/03: AS: fix code smell and add unit test AutoScaleVmProfileVOTest

Posted by we...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

weizhou pushed a commit to branch 4.18-vm-autoscaling
in repository https://gitbox.apache.org/repos/asf/cloudstack.git

commit 242398df17878a370785e768512202c6ee498533
Author: Wei Zhou <we...@apache.org>
AuthorDate: Tue Nov 8 10:42:58 2022 +0100

    AS: fix code smell and add unit test AutoScaleVmProfileVOTest
---
 .../com/cloud/network/as/AutoScaleVmProfileVO.java |  4 ++
 .../cloud/network/as/AutoScaleVmProfileVOTest.java | 65 ++++++++++++++++++++++
 .../as/dao/AutoScaleVmGroupVmMapDaoImplTest.java   | 14 +++++
 .../com/cloud/network/as/AutoScaleManagerImpl.java |  8 ---
 .../cloud/network/as/AutoScaleManagerImplTest.java |  7 +++
 5 files changed, 90 insertions(+), 8 deletions(-)

diff --git a/engine/schema/src/main/java/com/cloud/network/as/AutoScaleVmProfileVO.java b/engine/schema/src/main/java/com/cloud/network/as/AutoScaleVmProfileVO.java
index 7893e271bf7..0a0ba1e62aa 100644
--- a/engine/schema/src/main/java/com/cloud/network/as/AutoScaleVmProfileVO.java
+++ b/engine/schema/src/main/java/com/cloud/network/as/AutoScaleVmProfileVO.java
@@ -186,6 +186,10 @@ public class AutoScaleVmProfileVO implements AutoScaleVmProfile, Identity, Inter
         return paramsList;
     }
 
+    public String getCounterParamsString() {
+        return this.counterParams;
+    }
+
     public void setCounterParams(String counterParam) {
         this.counterParams = counterParam;
     }
diff --git a/engine/schema/src/test/java/com/cloud/network/as/AutoScaleVmProfileVOTest.java b/engine/schema/src/test/java/com/cloud/network/as/AutoScaleVmProfileVOTest.java
new file mode 100755
index 00000000000..ff922986f88
--- /dev/null
+++ b/engine/schema/src/test/java/com/cloud/network/as/AutoScaleVmProfileVOTest.java
@@ -0,0 +1,65 @@
+// 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.network.as;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import com.cloud.utils.Pair;
+import org.junit.Assert;
+import org.junit.Test;
+
+public class AutoScaleVmProfileVOTest {
+
+    @Test
+    public void testCounterParamsForUpdate() {
+        AutoScaleVmProfileVO profile = new AutoScaleVmProfileVO();
+
+        Map<String, HashMap<String, String>> counterParamList = new HashMap<>();
+        counterParamList.put("0", new HashMap<>() {{ put("name", "snmpcommunity"); put("value", "public"); }});
+        counterParamList.put("1", new HashMap<>() {{ put("name", "snmpport"); put("value", "161"); }});
+
+        profile.setCounterParamsForUpdate(counterParamList);
+        Assert.assertEquals("snmpcommunity=public&snmpport=161", profile.getCounterParamsString());
+
+        List<Pair<String, String>>  counterParams = profile.getCounterParams();
+        Assert.assertEquals(2, counterParams.size());
+        Assert.assertEquals("snmpcommunity", counterParams.get(0).first());
+        Assert.assertEquals("public", counterParams.get(0).second());
+        Assert.assertEquals("snmpport", counterParams.get(1).first());
+        Assert.assertEquals("161", counterParams.get(1).second());
+    }
+
+    @Test
+    public void tstSetOtherDeployParamsForUpdate() {
+        AutoScaleVmProfileVO profile = new AutoScaleVmProfileVO();
+
+        Map<String, HashMap<String, String>> otherDeployParamsMap = new HashMap<>();
+        otherDeployParamsMap.put("0", new HashMap<>() {{ put("name", "serviceofferingid"); put("value", "a7fb50f6-01d9-11ed-8bc1-77f8f0228926"); }});
+        otherDeployParamsMap.put("1", new HashMap<>() {{ put("name", "rootdisksize"); put("value", "10"); }});
+
+        profile.setOtherDeployParamsForUpdate(otherDeployParamsMap);
+
+        List<Pair<String, String>> otherDeployParamsList = profile.getOtherDeployParamsList();
+        Assert.assertEquals(2, otherDeployParamsList.size());
+        Assert.assertEquals("serviceofferingid", otherDeployParamsList.get(0).first());
+        Assert.assertEquals("a7fb50f6-01d9-11ed-8bc1-77f8f0228926", otherDeployParamsList.get(0).second());
+        Assert.assertEquals("rootdisksize", otherDeployParamsList.get(1).first());
+        Assert.assertEquals("10", otherDeployParamsList.get(1).second());
+    }
+}
\ No newline at end of file
diff --git a/engine/schema/src/test/java/com/cloud/network/as/dao/AutoScaleVmGroupVmMapDaoImplTest.java b/engine/schema/src/test/java/com/cloud/network/as/dao/AutoScaleVmGroupVmMapDaoImplTest.java
index add0a40c628..2dde1008e6b 100644
--- a/engine/schema/src/test/java/com/cloud/network/as/dao/AutoScaleVmGroupVmMapDaoImplTest.java
+++ b/engine/schema/src/test/java/com/cloud/network/as/dao/AutoScaleVmGroupVmMapDaoImplTest.java
@@ -83,6 +83,20 @@ public class AutoScaleVmGroupVmMapDaoImplTest {
         Mockito.verify(searchCriteriaCountAvailableVmsByGroup).setJoinParameters("vmSearch", "states", new Object[] {VirtualMachine.State.Starting, VirtualMachine.State.Running, VirtualMachine.State.Stopping, VirtualMachine.State.Migrating});
     }
 
+    @Test
+    public void testCountByGroup() throws Exception {
+        Mockito.doNothing().when(searchCriteriaAutoScaleVmGroupVmMapVOMock).setParameters(Mockito.anyString(), Mockito.any());
+        PowerMockito.doReturn(6).when(AutoScaleVmGroupVmMapDaoImplSpy, "getCountIncludingRemoved", Mockito.any(SearchCriteria.class));
+
+        long groupId = 4L;
+
+        int result = AutoScaleVmGroupVmMapDaoImplSpy.countByGroup(groupId);
+
+        Assert.assertEquals(6, result);
+
+        Mockito.verify(searchCriteriaAutoScaleVmGroupVmMapVOMock).setParameters("vmGroupId", groupId);
+    }
+
     @Test
     public void testListByGroup() throws Exception {
         Mockito.doNothing().when(searchCriteriaAutoScaleVmGroupVmMapVOMock).setParameters(Mockito.anyString(), Mockito.any());
diff --git a/server/src/main/java/com/cloud/network/as/AutoScaleManagerImpl.java b/server/src/main/java/com/cloud/network/as/AutoScaleManagerImpl.java
index 0c2f52c6b45..477b16e5836 100644
--- a/server/src/main/java/com/cloud/network/as/AutoScaleManagerImpl.java
+++ b/server/src/main/java/com/cloud/network/as/AutoScaleManagerImpl.java
@@ -17,7 +17,6 @@
 package com.cloud.network.as;
 
 import java.security.SecureRandom;
-import java.text.SimpleDateFormat;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Date;
@@ -1887,13 +1886,6 @@ public class AutoScaleManagerImpl extends ManagerBase implements AutoScaleManage
                 RandomStringUtils.random(6, 0, 0, true, false, (char[])null, new SecureRandom()).toLowerCase();
     }
 
-    private String getCurrentTimeStampString() {
-        Date current = new Date();
-        SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss");
-
-        return sdf.format(current);
-    }
-
     private boolean startNewVM(long vmId) {
         try {
             CallContext.current().setEventDetails("Vm Id: " + vmId);
diff --git a/server/src/test/java/com/cloud/network/as/AutoScaleManagerImplTest.java b/server/src/test/java/com/cloud/network/as/AutoScaleManagerImplTest.java
index 0761f7fed27..b494c02fe98 100644
--- a/server/src/test/java/com/cloud/network/as/AutoScaleManagerImplTest.java
+++ b/server/src/test/java/com/cloud/network/as/AutoScaleManagerImplTest.java
@@ -324,6 +324,7 @@ public class AutoScaleManagerImplTest {
     private static final Long scaleUpCounterId = 36L;
     private static final Long scaleDownConditionId = 37L;
     private static final Long scaleDownCounterId = 38L;
+    private static final Long nextVmSeq = 39L;
 
     @Mock
     DataCenterVO zoneMock;
@@ -1142,6 +1143,7 @@ public class AutoScaleManagerImplTest {
     public void testCreateNewVM1() throws ResourceUnavailableException, InsufficientCapacityException, ResourceAllocationException {
         when(asVmGroupMock.getProfileId()).thenReturn(vmProfileId);
         when(asVmGroupMock.getLoadBalancerId()).thenReturn(loadBalancerId);
+        when(asVmGroupMock.getNextVmSeq()).thenReturn(nextVmSeq);
 
         when(autoScaleVmProfileDao.findById(vmProfileId)).thenReturn(asVmProfileMock);
         when(asVmProfileMock.getTemplateId()).thenReturn(templateId);
@@ -1175,12 +1177,14 @@ public class AutoScaleManagerImplTest {
         Mockito.verify(userVmService).createBasicSecurityGroupVirtualMachine(any(), any(), any(), any(), any(), any(), any(),
                 any(), any(), any(), any(), any(), any(), any(), any(), any(), any(), any(), eq(true), any(), any(), any(),
                 any(), any(), any(), any(), eq(true), any());
+        Mockito.verify(asVmGroupMock).setNextVmSeq(nextVmSeq + 1);
     }
 
     @Test
     public void testCreateNewVM2() throws ResourceUnavailableException, InsufficientCapacityException, ResourceAllocationException {
         when(asVmGroupMock.getProfileId()).thenReturn(vmProfileId);
         when(asVmGroupMock.getLoadBalancerId()).thenReturn(loadBalancerId);
+        when(asVmGroupMock.getNextVmSeq()).thenReturn(nextVmSeq + 1);
 
         when(autoScaleVmProfileDao.findById(vmProfileId)).thenReturn(asVmProfileMock);
         when(asVmProfileMock.getTemplateId()).thenReturn(templateId);
@@ -1215,12 +1219,14 @@ public class AutoScaleManagerImplTest {
         Mockito.verify(userVmService).createAdvancedSecurityGroupVirtualMachine(any(), any(), any(), any(), any(), any(), any(),
                 any(), any(), any(), any(), any(), any(), any(), any(), any(), any(), any(), any(), any(), any(), any(),
                 any(), any(), any(), any(), any(), eq(true), any(), any());
+        Mockito.verify(asVmGroupMock).setNextVmSeq(nextVmSeq + 2);
     }
 
     @Test
     public void testCreateNewVM3() throws ResourceUnavailableException, InsufficientCapacityException, ResourceAllocationException {
         when(asVmGroupMock.getProfileId()).thenReturn(vmProfileId);
         when(asVmGroupMock.getLoadBalancerId()).thenReturn(loadBalancerId);
+        when(asVmGroupMock.getNextVmSeq()).thenReturn(nextVmSeq + 2);
 
         when(autoScaleVmProfileDao.findById(vmProfileId)).thenReturn(asVmProfileMock);
         when(asVmProfileMock.getTemplateId()).thenReturn(templateId);
@@ -1255,6 +1261,7 @@ public class AutoScaleManagerImplTest {
         Mockito.verify(userVmService).createAdvancedVirtualMachine(any(), any(), any(), any(), any(), any(), any(),
                 any(), any(), any(), any(), any(), any(), any(), any(), any(), any(), any(), eq(true), any(), any(), any(),
                 any(), any(), any(), any(), eq(true), any(), any());
+        Mockito.verify(asVmGroupMock).setNextVmSeq(nextVmSeq + 3);
     }
 
     @Test


[cloudstack] 03/03: AS: add capability VmAutoScaling to Lb Service

Posted by we...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

weizhou pushed a commit to branch 4.18-vm-autoscaling
in repository https://gitbox.apache.org/repos/asf/cloudstack.git

commit 489cfba381603761556873a725631b402ba57829
Author: Wei Zhou <we...@apache.org>
AuthorDate: Tue Nov 8 10:44:45 2022 +0100

    AS: add capability VmAutoScaling to Lb Service
---
 api/src/main/java/com/cloud/network/Network.java   |  1 +
 .../java/com/cloud/offering/NetworkOffering.java   |  2 +
 .../org/apache/cloudstack/api/ApiConstants.java    |  1 +
 .../cloudstack/api/response/NetworkResponse.java   | 12 ++++
 .../com/cloud/offerings/NetworkOfferingVO.java     | 12 ++++
 .../resources/META-INF/db/schema-41710to41800.sql  | 72 ++++++++++++++++++++++
 .../cloud/network/element/NetscalerElement.java    |  1 +
 .../main/java/com/cloud/api/ApiResponseHelper.java |  6 ++
 .../cloud/api/query/vo/NetworkOfferingJoinVO.java  |  8 +++
 .../configuration/ConfigurationManagerImpl.java    | 28 +++++++--
 .../com/cloud/network/as/AutoScaleManagerImpl.java | 16 +++++
 .../network/element/VirtualRouterElement.java      |  1 +
 .../cloud/network/as/AutoScaleManagerImplTest.java | 17 +++++
 test/integration/smoke/test_vm_autoscaling.py      |  6 ++
 ui/public/locales/en.json                          |  3 +
 ui/src/views/compute/CreateAutoScaleVmGroup.vue    | 10 +++
 ui/src/views/compute/wizard/NetworkSelection.vue   | 10 ++-
 ui/src/views/offering/AddNetworkOffering.vue       | 13 ++++
 18 files changed, 212 insertions(+), 7 deletions(-)

diff --git a/api/src/main/java/com/cloud/network/Network.java b/api/src/main/java/com/cloud/network/Network.java
index 0fee5c04d25..8fce2502a60 100644
--- a/api/src/main/java/com/cloud/network/Network.java
+++ b/api/src/main/java/com/cloud/network/Network.java
@@ -285,6 +285,7 @@ public interface Network extends ControlledEntity, StateObject<Network.State>, I
         public static final Capability NoVlan = new Capability("NoVlan");
         public static final Capability PublicAccess = new Capability("PublicAccess");
         public static final Capability ExtraDhcpOptions = new Capability("ExtraDhcpOptions");
+        public static final Capability VmAutoScaling = new Capability("VmAutoScaling");
 
         private final String name;
 
diff --git a/api/src/main/java/com/cloud/offering/NetworkOffering.java b/api/src/main/java/com/cloud/offering/NetworkOffering.java
index bf904419176..5825431c6bd 100644
--- a/api/src/main/java/com/cloud/offering/NetworkOffering.java
+++ b/api/src/main/java/com/cloud/offering/NetworkOffering.java
@@ -143,6 +143,8 @@ public interface NetworkOffering extends InfrastructureEntity, InternalIdentity,
 
     boolean isSupportingPublicAccess();
 
+    boolean isSupportsVmAutoScaling();
+
     String getServicePackage();
 
     Date getCreated();
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 1b6219c7d33..96110dbb57f 100644
--- a/api/src/main/java/org/apache/cloudstack/api/ApiConstants.java
+++ b/api/src/main/java/org/apache/cloudstack/api/ApiConstants.java
@@ -837,6 +837,7 @@ public class ApiConstants {
     public static final String SUPPORTS_REGION_LEVEL_VPC = "supportsregionLevelvpc";
     public static final String SUPPORTS_STRECHED_L2_SUBNET = "supportsstrechedl2subnet";
     public static final String SUPPORTS_PUBLIC_ACCESS = "supportspublicaccess";
+    public static final String SUPPORTS_VM_AUTOSCALING = "supportsvmautoscaling";
     public static final String REGION_LEVEL_VPC = "regionlevelvpc";
     public static final String STRECHED_L2_SUBNET = "strechedl2subnet";
     public static final String NETWORK_NAME = "networkname";
diff --git a/api/src/main/java/org/apache/cloudstack/api/response/NetworkResponse.java b/api/src/main/java/org/apache/cloudstack/api/response/NetworkResponse.java
index 19edc1b3944..51b3ade17ab 100644
--- a/api/src/main/java/org/apache/cloudstack/api/response/NetworkResponse.java
+++ b/api/src/main/java/org/apache/cloudstack/api/response/NetworkResponse.java
@@ -255,6 +255,10 @@ public class NetworkResponse extends BaseResponseWithAssociatedNetwork implement
     @Param(description = "If the network has redundant routers enabled", since = "4.11.1")
     private Boolean redundantRouter;
 
+    @SerializedName(ApiConstants.SUPPORTS_VM_AUTOSCALING)
+    @Param(description = "if network offering supports vm autoscaling feature", since = "4.18.0")
+    private Boolean supportsVmAutoScaling;
+
     @SerializedName(ApiConstants.RESOURCE_ICON)
     @Param(description = "Base64 string representation of the resource icon", since = "4.16.0.0")
     ResourceIconResponse icon;
@@ -534,6 +538,14 @@ public class NetworkResponse extends BaseResponseWithAssociatedNetwork implement
         this.redundantRouter = redundantRouter;
     }
 
+    public Boolean getSupportsVmAutoScaling() {
+        return supportsVmAutoScaling;
+    }
+
+    public void setSupportsVmAutoScaling(Boolean supportsVmAutoScaling) {
+        this.supportsVmAutoScaling = supportsVmAutoScaling;
+    }
+
     public String getVpcName() {
         return vpcName;
     }
diff --git a/engine/schema/src/main/java/com/cloud/offerings/NetworkOfferingVO.java b/engine/schema/src/main/java/com/cloud/offerings/NetworkOfferingVO.java
index ff187687fdf..a3ceb9cce43 100644
--- a/engine/schema/src/main/java/com/cloud/offerings/NetworkOfferingVO.java
+++ b/engine/schema/src/main/java/com/cloud/offerings/NetworkOfferingVO.java
@@ -148,6 +148,9 @@ public class NetworkOfferingVO implements NetworkOffering {
     @Column(name="supports_public_access")
     boolean supportsPublicAccess = false;
 
+    @Column(name = "supports_vm_autoscaling")
+    boolean supportsVmAutoScaling = false;
+
     @Override
     public String getDisplayText() {
         return displayText;
@@ -534,4 +537,13 @@ public class NetworkOfferingVO implements NetworkOffering {
     public String getServicePackage() {
         return servicePackageUuid;
     }
+
+    public void setSupportsVmAutoScaling(boolean supportsVmAutoScaling) {
+        this.supportsVmAutoScaling = supportsVmAutoScaling;
+    }
+
+    @Override
+    public boolean isSupportsVmAutoScaling() {
+        return supportsVmAutoScaling;
+    }
 }
diff --git a/engine/schema/src/main/resources/META-INF/db/schema-41710to41800.sql b/engine/schema/src/main/resources/META-INF/db/schema-41710to41800.sql
index 73862ae1799..f6ee5e207b2 100644
--- a/engine/schema/src/main/resources/META-INF/db/schema-41710to41800.sql
+++ b/engine/schema/src/main/resources/META-INF/db/schema-41710to41800.sql
@@ -294,6 +294,11 @@ CREATE PROCEDURE `cloud`.`IDEMPOTENT_DROP_FOREIGN_KEY` (
 BEGIN
     DECLARE CONTINUE HANDLER FOR 1091, 1025 BEGIN END; SET @ddl = CONCAT('ALTER TABLE ', in_table_name); SET @ddl = CONCAT(@ddl, ' ', ' DROP FOREIGN KEY '); SET @ddl = CONCAT(@ddl, ' ', in_foreign_key_name); PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt; END;
 
+-- Add column 'supports_vm_autoscaling' to 'network_offerings' table
+CALL `cloud`.`IDEMPOTENT_ADD_COLUMN`('cloud.network_offerings', 'supports_vm_autoscaling', 'boolean default false');
+UPDATE `cloud`.`network_offerings` SET supports_vm_autoscaling = 1 WHERE unique_name = 'DefaultIsolatedNetworkOfferingWithSourceNatService';
+UPDATE `cloud`.`network_offerings` SET supports_vm_autoscaling = 1 WHERE unique_name = 'DefaultIsolatedNetworkOfferingForVpcNetworks';
+
 -- Add column 'name' to 'autoscale_vmgroups' table
 CALL `cloud`.`IDEMPOTENT_ADD_COLUMN`('cloud.autoscale_vmgroups', 'name', 'VARCHAR(255) DEFAULT NULL COMMENT "name of the autoscale vm group" AFTER `load_balancer_id`');
 UPDATE `cloud`.`autoscale_vmgroups` SET `name` = CONCAT('AutoScale-VmGroup-',id) WHERE `name` IS NULL;
@@ -366,6 +371,73 @@ CREATE TABLE IF NOT EXISTS `cloud`.`autoscale_vmgroup_statistics` (
   INDEX `i_autoscale_vmgroup_statistics__counter_id`(`counter_id`)
 ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
 
+
+-- Update Network offering view with supports_vm_autoscaling
+DROP VIEW IF EXISTS `cloud`.`network_offering_view`;
+CREATE VIEW `cloud`.`network_offering_view` AS
+    SELECT
+        `network_offerings`.`id` AS `id`,
+        `network_offerings`.`uuid` AS `uuid`,
+        `network_offerings`.`name` AS `name`,
+        `network_offerings`.`unique_name` AS `unique_name`,
+        `network_offerings`.`display_text` AS `display_text`,
+        `network_offerings`.`nw_rate` AS `nw_rate`,
+        `network_offerings`.`mc_rate` AS `mc_rate`,
+        `network_offerings`.`traffic_type` AS `traffic_type`,
+        `network_offerings`.`tags` AS `tags`,
+        `network_offerings`.`system_only` AS `system_only`,
+        `network_offerings`.`specify_vlan` AS `specify_vlan`,
+        `network_offerings`.`service_offering_id` AS `service_offering_id`,
+        `network_offerings`.`conserve_mode` AS `conserve_mode`,
+        `network_offerings`.`created` AS `created`,
+        `network_offerings`.`removed` AS `removed`,
+        `network_offerings`.`default` AS `default`,
+        `network_offerings`.`availability` AS `availability`,
+        `network_offerings`.`dedicated_lb_service` AS `dedicated_lb_service`,
+        `network_offerings`.`shared_source_nat_service` AS `shared_source_nat_service`,
+        `network_offerings`.`sort_key` AS `sort_key`,
+        `network_offerings`.`redundant_router_service` AS `redundant_router_service`,
+        `network_offerings`.`state` AS `state`,
+        `network_offerings`.`guest_type` AS `guest_type`,
+        `network_offerings`.`elastic_ip_service` AS `elastic_ip_service`,
+        `network_offerings`.`eip_associate_public_ip` AS `eip_associate_public_ip`,
+        `network_offerings`.`elastic_lb_service` AS `elastic_lb_service`,
+        `network_offerings`.`specify_ip_ranges` AS `specify_ip_ranges`,
+        `network_offerings`.`inline` AS `inline`,
+        `network_offerings`.`is_persistent` AS `is_persistent`,
+        `network_offerings`.`internal_lb` AS `internal_lb`,
+        `network_offerings`.`public_lb` AS `public_lb`,
+        `network_offerings`.`egress_default_policy` AS `egress_default_policy`,
+        `network_offerings`.`concurrent_connections` AS `concurrent_connections`,
+        `network_offerings`.`keep_alive_enabled` AS `keep_alive_enabled`,
+        `network_offerings`.`supports_streched_l2` AS `supports_streched_l2`,
+        `network_offerings`.`supports_public_access` AS `supports_public_access`,
+        `network_offerings`.`supports_vm_autoscaling` AS `supports_vm_autoscaling`,
+        `network_offerings`.`for_vpc` AS `for_vpc`,
+        `network_offerings`.`service_package_id` AS `service_package_id`,
+        GROUP_CONCAT(DISTINCT(domain.id)) AS domain_id,
+        GROUP_CONCAT(DISTINCT(domain.uuid)) AS domain_uuid,
+        GROUP_CONCAT(DISTINCT(domain.name)) AS domain_name,
+        GROUP_CONCAT(DISTINCT(domain.path)) AS domain_path,
+        GROUP_CONCAT(DISTINCT(zone.id)) AS zone_id,
+        GROUP_CONCAT(DISTINCT(zone.uuid)) AS zone_uuid,
+        GROUP_CONCAT(DISTINCT(zone.name)) AS zone_name,
+        `offering_details`.value AS internet_protocol
+    FROM
+        `cloud`.`network_offerings`
+            LEFT JOIN
+        `cloud`.`network_offering_details` AS `domain_details` ON `domain_details`.`network_offering_id` = `network_offerings`.`id` AND `domain_details`.`name`='domainid'
+            LEFT JOIN
+        `cloud`.`domain` AS `domain` ON FIND_IN_SET(`domain`.`id`, `domain_details`.`value`)
+            LEFT JOIN
+        `cloud`.`network_offering_details` AS `zone_details` ON `zone_details`.`network_offering_id` = `network_offerings`.`id` AND `zone_details`.`name`='zoneid'
+            LEFT JOIN
+        `cloud`.`data_center` AS `zone` ON FIND_IN_SET(`zone`.`id`, `zone_details`.`value`)
+            LEFT JOIN
+        `cloud`.`network_offering_details` AS `offering_details` ON `offering_details`.`network_offering_id` = `network_offerings`.`id` AND `offering_details`.`name`='internetProtocol'
+    GROUP BY
+        `network_offerings`.`id`;
+
 -- UserData as first class resource (PR #6202)
 CREATE TABLE `cloud`.`user_data` (
   `id` bigint unsigned NOT NULL auto_increment COMMENT 'id',
diff --git a/plugins/network-elements/netscaler/src/main/java/com/cloud/network/element/NetscalerElement.java b/plugins/network-elements/netscaler/src/main/java/com/cloud/network/element/NetscalerElement.java
index 35ba873afc2..1339113711e 100644
--- a/plugins/network-elements/netscaler/src/main/java/com/cloud/network/element/NetscalerElement.java
+++ b/plugins/network-elements/netscaler/src/main/java/com/cloud/network/element/NetscalerElement.java
@@ -527,6 +527,7 @@ IpDeployer, StaticNatServiceProvider, GslbServiceProvider {
         Gson gson = new Gson();
         String autoScaleCounterList = gson.toJson(counterList);
         lbCapabilities.put(Capability.AutoScaleCounters, autoScaleCounterList);
+        lbCapabilities.put(Capability.VmAutoScaling, "true");
 
         LbStickinessMethod method;
         List<LbStickinessMethod> methodList = new ArrayList<LbStickinessMethod>();
diff --git a/server/src/main/java/com/cloud/api/ApiResponseHelper.java b/server/src/main/java/com/cloud/api/ApiResponseHelper.java
index fe2acf29348..e08ba5250e9 100644
--- a/server/src/main/java/com/cloud/api/ApiResponseHelper.java
+++ b/server/src/main/java/com/cloud/api/ApiResponseHelper.java
@@ -2180,6 +2180,11 @@ public class ApiResponseHelper implements ResponseGenerator {
                 inline.setValue(offering.isInline() ? "true" : "false");
                 lbCapResponse.add(inline);
 
+                CapabilityResponse vmAutoScaling = new CapabilityResponse();
+                vmAutoScaling.setName(Capability.VmAutoScaling.getName());
+                vmAutoScaling.setValue(offering.isSupportsVmAutoScaling() ? "true" : "false");
+                lbCapResponse.add(vmAutoScaling);
+
                 svcRsp.setCapabilities(lbCapResponse);
             } else if (Service.SourceNat == service) {
                 List<CapabilityResponse> capabilities = new ArrayList<CapabilityResponse>();
@@ -2525,6 +2530,7 @@ public class ApiResponseHelper implements ResponseGenerator {
         response.setExternalId(network.getExternalId());
         response.setRedundantRouter(network.isRedundant());
         response.setCreated(network.getCreated());
+        response.setSupportsVmAutoScaling(networkOfferingDao.findByIdIncludingRemoved(network.getNetworkOfferingId()).isSupportsVmAutoScaling());
 
         Long bytesReceived = 0L;
         Long bytesSent = 0L;
diff --git a/server/src/main/java/com/cloud/api/query/vo/NetworkOfferingJoinVO.java b/server/src/main/java/com/cloud/api/query/vo/NetworkOfferingJoinVO.java
index 981acc8bbff..59bb3691fa0 100644
--- a/server/src/main/java/com/cloud/api/query/vo/NetworkOfferingJoinVO.java
+++ b/server/src/main/java/com/cloud/api/query/vo/NetworkOfferingJoinVO.java
@@ -148,6 +148,9 @@ public class NetworkOfferingJoinVO extends BaseViewVO implements NetworkOffering
     @Column(name = "supports_public_access")
     private boolean supportsPublicAccess = false;
 
+    @Column(name = "supports_vm_autoscaling")
+    boolean supportsVmAutoScaling = false;
+
     @Column(name = "for_vpc")
     private boolean forVpc;
 
@@ -401,4 +404,9 @@ public class NetworkOfferingJoinVO extends BaseViewVO implements NetworkOffering
     public String getInternetProtocol() {
         return internetProtocol;
     }
+
+    @Override
+    public boolean isSupportsVmAutoScaling() {
+        return supportsVmAutoScaling;
+    }
 }
diff --git a/server/src/main/java/com/cloud/configuration/ConfigurationManagerImpl.java b/server/src/main/java/com/cloud/configuration/ConfigurationManagerImpl.java
index ad085830a98..9395206ce12 100755
--- a/server/src/main/java/com/cloud/configuration/ConfigurationManagerImpl.java
+++ b/server/src/main/java/com/cloud/configuration/ConfigurationManagerImpl.java
@@ -6043,9 +6043,10 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati
 
     void validateLoadBalancerServiceCapabilities(final Map<Capability, String> lbServiceCapabilityMap) {
         if (lbServiceCapabilityMap != null && !lbServiceCapabilityMap.isEmpty()) {
-            if (lbServiceCapabilityMap.keySet().size() > 3 || !lbServiceCapabilityMap.containsKey(Capability.SupportedLBIsolation)) {
-                throw new InvalidParameterValueException("Only " + Capability.SupportedLBIsolation.getName() + ", " + Capability.ElasticLb.getName() + ", "
-                        + Capability.InlineMode.getName() + " capabilities can be sepcified for LB service");
+            if (lbServiceCapabilityMap.keySet().size() > 4 || !lbServiceCapabilityMap.containsKey(Capability.SupportedLBIsolation)) {
+                throw new InvalidParameterValueException(String.format("Only %s capabilities can be specified for LB service",
+                        StringUtils.join(Capability.SupportedLBIsolation.getName(), Capability.ElasticLb.getName(),
+                                Capability.InlineMode.getName(), Capability.LbSchemes.getName(), Capability.VmAutoScaling.getName())));
             }
 
             for (final Capability cap : lbServiceCapabilityMap.keySet()) {
@@ -6074,9 +6075,16 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati
                     if (!internalLb && !publicLb) {
                         throw new InvalidParameterValueException("Unknown specified value for " + Capability.LbSchemes.getName());
                     }
+                } else if (cap == Capability.VmAutoScaling) {
+                    final boolean enabled = value.contains("true");
+                    final boolean disabled = value.contains("false");
+                    if (!enabled && !disabled) {
+                        throw new InvalidParameterValueException("Unknown specified value for " + Capability.VmAutoScaling.getName());
+                    }
                 } else {
-                    throw new InvalidParameterValueException("Only " + Capability.SupportedLBIsolation.getName() + ", " + Capability.ElasticLb.getName() + ", "
-                            + Capability.InlineMode.getName() + ", " + Capability.LbSchemes.getName() + " capabilities can be sepcified for LB service");
+                    throw new InvalidParameterValueException(String.format("Only %s capabilities can be specified for LB service",
+                            StringUtils.join(Capability.SupportedLBIsolation.getName(), Capability.ElasticLb.getName(),
+                                    Capability.InlineMode.getName(), Capability.LbSchemes.getName(), Capability.VmAutoScaling.getName())));
                 }
             }
         }
@@ -6236,6 +6244,7 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati
         boolean internalLb = false;
         boolean strechedL2Subnet = false;
         boolean publicAccess = false;
+        boolean vmAutoScaling = false;
 
         if (serviceCapabilityMap != null && !serviceCapabilityMap.isEmpty()) {
             final Map<Capability, String> lbServiceCapabilityMap = serviceCapabilityMap.get(Service.Lb);
@@ -6270,6 +6279,12 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati
                         publicLb = publicLbStr.contains("public");
                     }
                 }
+
+                final String vmAutoScalingStr = lbServiceCapabilityMap.get(Capability.VmAutoScaling);
+                if (vmAutoScalingStr != null) {
+                    _networkModel.checkCapabilityForProvider(serviceProviderMap.get(Service.Lb), Service.Lb, Capability.VmAutoScaling, vmAutoScalingStr);
+                    vmAutoScaling = vmAutoScalingStr.contains("true");
+                }
             }
 
             // in the current version of the code, publicLb and specificLb can't
@@ -6340,6 +6355,9 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati
             offeringFinal.setState(NetworkOffering.State.Enabled);
         }
 
+        // Set VM AutoScaling capability
+        offeringFinal.setSupportsVmAutoScaling(vmAutoScaling);
+
         //Set Service package id
         offeringFinal.setServicePackage(servicePackageUuid);
         // validate the details
diff --git a/server/src/main/java/com/cloud/network/as/AutoScaleManagerImpl.java b/server/src/main/java/com/cloud/network/as/AutoScaleManagerImpl.java
index 6c6a1fb07d6..bd522b23891 100644
--- a/server/src/main/java/com/cloud/network/as/AutoScaleManagerImpl.java
+++ b/server/src/main/java/com/cloud/network/as/AutoScaleManagerImpl.java
@@ -141,7 +141,9 @@ import com.cloud.network.router.VirtualRouterAutoScale.AutoScaleMetricsValue;
 import com.cloud.network.router.VirtualRouterAutoScale.AutoScaleValueType;
 import com.cloud.network.router.VirtualRouterAutoScale.VirtualRouterAutoScaleCounter;
 import com.cloud.offering.DiskOffering;
+import com.cloud.offering.NetworkOffering;
 import com.cloud.offering.ServiceOffering;
+import com.cloud.offerings.dao.NetworkOfferingDao;
 import com.cloud.projects.Project.ListProjectResourcesCriteria;
 import com.cloud.server.ResourceTag;
 import com.cloud.service.ServiceOfferingVO;
@@ -269,6 +271,8 @@ public class AutoScaleManagerImpl extends ManagerBase implements AutoScaleManage
     private SSHKeyPairDao sshKeyPairDao;
     @Inject
     private AffinityGroupDao affinityGroupDao;
+    @Inject
+    private NetworkOfferingDao networkOfferingDao;
 
     private static final String PARAM_ROOT_DISK_SIZE = "rootdisksize";
     private static final String PARAM_DISK_OFFERING_ID = "diskofferingid";
@@ -330,6 +334,17 @@ public class AutoScaleManagerImpl extends ManagerBase implements AutoScaleManage
         return result;
     }
 
+    public void validateNetworkCapability(long networkId) {
+        Network network = networkDao.findById(networkId);
+        if (network == null) {
+            throw new CloudRuntimeException(String.format("Unable to find network with id: %s ", networkId));
+        }
+        NetworkOffering offering = networkOfferingDao.findByIdIncludingRemoved(network.getNetworkOfferingId());
+        if (!offering.isSupportsVmAutoScaling()) {
+            throw new InvalidParameterValueException("Vm AutoScaling is not supported by this network.");
+        }
+    }
+
     public void validateAutoScaleCounters(long networkid, List<Counter> counters, List<Pair<String, String>> counterParamPassed) {
         List<AutoScaleCounter> supportedCounters = getSupportedAutoScaleCounters(networkid);
         if (supportedCounters == null) {
@@ -1228,6 +1243,7 @@ public class AutoScaleManagerImpl extends ManagerBase implements AutoScaleManage
             getEntityInDatabase(CallContext.current().getCallingAccount(), ApiConstants.VMPROFILE_ID, vmGroup.getProfileId(), autoScaleVmProfileDao);
 
         LoadBalancerVO loadBalancer = getEntityInDatabase(CallContext.current().getCallingAccount(), ApiConstants.LBID, vmGroup.getLoadBalancerId(), lbDao);
+        validateNetworkCapability(loadBalancer.getNetworkId());
         validateAutoScaleCounters(loadBalancer.getNetworkId(), counters, profileVO.getCounterParams());
 
         Network.Provider provider = getLoadBalancerServiceProvider(vmGroup.getLoadBalancerId());
diff --git a/server/src/main/java/com/cloud/network/element/VirtualRouterElement.java b/server/src/main/java/com/cloud/network/element/VirtualRouterElement.java
index b8966e65284..839ab9ae0af 100644
--- a/server/src/main/java/com/cloud/network/element/VirtualRouterElement.java
+++ b/server/src/main/java/com/cloud/network/element/VirtualRouterElement.java
@@ -541,6 +541,7 @@ NetworkMigrationResponder, AggregatedCommandExecutor, RedundantResource, DnsServ
         final Gson gson = new Gson();
         final String autoScaleCounterList = gson.toJson(counterList);
         lbCapabilities.put(Capability.AutoScaleCounters, autoScaleCounterList);
+        lbCapabilities.put(Capability.VmAutoScaling, "true");
         capabilities.put(Service.Lb, lbCapabilities);
 
         // Set capabilities for Firewall service
diff --git a/server/src/test/java/com/cloud/network/as/AutoScaleManagerImplTest.java b/server/src/test/java/com/cloud/network/as/AutoScaleManagerImplTest.java
index ba58c7b5157..870f76d2c36 100644
--- a/server/src/test/java/com/cloud/network/as/AutoScaleManagerImplTest.java
+++ b/server/src/test/java/com/cloud/network/as/AutoScaleManagerImplTest.java
@@ -68,6 +68,8 @@ import com.cloud.network.router.VirtualRouterAutoScale.VirtualRouterAutoScaleCou
 import com.cloud.network.rules.LoadBalancer;
 import com.cloud.offering.DiskOffering;
 import com.cloud.offering.ServiceOffering;
+import com.cloud.offerings.NetworkOfferingVO;
+import com.cloud.offerings.dao.NetworkOfferingDao;
 import com.cloud.server.ResourceTag;
 import com.cloud.service.ServiceOfferingVO;
 import com.cloud.service.dao.ServiceOfferingDao;
@@ -221,6 +223,8 @@ public class AutoScaleManagerImplTest {
     @Mock
     NetworkDao networkDao;
     @Mock
+    NetworkOfferingDao networkOfferingDao;
+    @Mock
     ServiceOfferingDao serviceOfferingDao;
     @Mock
     DiskOfferingDao diskOfferingDao;
@@ -328,6 +332,7 @@ public class AutoScaleManagerImplTest {
     private static final Long scaleDownConditionId = 37L;
     private static final Long scaleDownCounterId = 38L;
     private static final Long nextVmSeq = 39L;
+    private static final Long networkOfferingId = 40L;
 
     @Mock
     DataCenterVO zoneMock;
@@ -340,6 +345,8 @@ public class AutoScaleManagerImplTest {
     @Mock
     NetworkVO networkMock;
     @Mock
+    NetworkOfferingVO networkOfferingMock;
+    @Mock
     CounterVO counterMock;
     @Mock
     ConditionVO conditionMock;
@@ -901,6 +908,11 @@ public class AutoScaleManagerImplTest {
         when(autoScaleVmProfileDao.findById(vmProfileId)).thenReturn(asVmProfileMock);
         PowerMockito.doReturn(Network.Provider.VirtualRouter).when(autoScaleManagerImplSpy).getLoadBalancerServiceProvider(loadBalancerId);
         PowerMockito.doNothing().when(autoScaleManagerImplSpy).validateAutoScaleCounters(anyLong(), any(), any());
+        when(loadBalancerMock.getNetworkId()).thenReturn(networkId);
+        when(networkDao.findById(networkId)).thenReturn(networkMock);
+        when(networkMock.getNetworkOfferingId()).thenReturn(networkOfferingId);
+        when(networkOfferingDao.findByIdIncludingRemoved(networkOfferingId)).thenReturn(networkOfferingMock);
+        when(networkOfferingMock.isSupportsVmAutoScaling()).thenReturn(true);
 
         when(autoScaleVmGroupDao.persist(any())).thenReturn(asVmGroupMock);
 
@@ -987,6 +999,11 @@ public class AutoScaleManagerImplTest {
         when(autoScaleVmProfileDao.findById(vmProfileId)).thenReturn(asVmProfileMock);
         PowerMockito.doReturn(Network.Provider.VirtualRouter).when(autoScaleManagerImplSpy).getLoadBalancerServiceProvider(loadBalancerId);
         PowerMockito.doNothing().when(autoScaleManagerImplSpy).validateAutoScaleCounters(anyLong(), any(), any());
+        when(loadBalancerMock.getNetworkId()).thenReturn(networkId);
+        when(networkDao.findById(networkId)).thenReturn(networkMock);
+        when(networkMock.getNetworkOfferingId()).thenReturn(networkOfferingId);
+        when(networkOfferingDao.findByIdIncludingRemoved(networkOfferingId)).thenReturn(networkOfferingMock);
+        when(networkOfferingMock.isSupportsVmAutoScaling()).thenReturn(true);
 
         when(autoScaleVmGroupDao.persist(any())).thenReturn(asVmGroupMock);
 
diff --git a/test/integration/smoke/test_vm_autoscaling.py b/test/integration/smoke/test_vm_autoscaling.py
index 2ac9d2b8c49..6dc7a0755d0 100644
--- a/test/integration/smoke/test_vm_autoscaling.py
+++ b/test/integration/smoke/test_vm_autoscaling.py
@@ -134,6 +134,12 @@ class TestVmAutoScaling(cloudstackTestCase):
         cls._cleanup.append(cls.disk_offering_custom_new)
 
         # 3. Create network offering for isolated networks
+        cls.services["isolated_network_offering"]["serviceCapabilityList"] = {
+            "Lb": {
+                "SupportedLbIsolation": 'dedicated',
+                "VmAutoScaling": 'true'
+            },
+        }
         cls.network_offering_isolated = NetworkOffering.create(
             cls.apiclient,
             cls.services["isolated_network_offering"]
diff --git a/ui/public/locales/en.json b/ui/public/locales/en.json
index be87ccb031e..efa91bf4054 100644
--- a/ui/public/locales/en.json
+++ b/ui/public/locales/en.json
@@ -1715,6 +1715,7 @@
 "label.supportsha": "Supports HA",
 "label.supportspublicaccess": "Supports public access",
 "label.supportsstrechedl2subnet": "Supports stretched L2 subnet",
+"label.supportsvmautoscaling": "Supports VM auto scaling",
 "label.suspend.project": "Suspend project",
 "label.switch.type": "Switch type",
 "label.sync.storage": "Sync storage pool",
@@ -2113,6 +2114,7 @@
 "message.authorization.failed": "Session expired, authorization verification failed.",
 "message.autoscale.loadbalancer.update": "The load balancer rule can be updated only when autoscale VM group is DISABLED.",
 "message.autoscale.policies.update": "The scale up/down policies can be updated only when autoscale VM group is DISABLED.",
+"message.autoscale.vm.networks": "Please choose at least one network for VMs in the autoscale VM group. The default network must be an Isolated network or VPC tier which supports VM AutoScaling and has load balancing rules.",
 "message.autoscale.vmprofile.update": "The autoscale vm profile can be updated only when autoscale VM group is DISABLED.",
 "message.backup.attach.restore": "Please confirm that you want to restore and attach the volume from the backup?",
 "message.backup.create": "Are you sure you want create a VM backup?",
@@ -2352,6 +2354,7 @@
 "message.error.s3nfs.server": "Please enter S3 NFS Server",
 "message.error.select.load.balancer": "Please select a load balancer",
 "message.error.select.network": "Please select a network",
+"message.error.select.network.supports.vm.autoscaling": "The default network you selected does not support VM AutoScaling, please select a default network which supports VM AutoScaling.",
 "message.error.select.user": "Please select a user",
 "message.error.swift.account": "Please enter account",
 "message.error.swift.key": "Please enter key",
diff --git a/ui/src/views/compute/CreateAutoScaleVmGroup.vue b/ui/src/views/compute/CreateAutoScaleVmGroup.vue
index 432a98e5466..fd76cd410c0 100644
--- a/ui/src/views/compute/CreateAutoScaleVmGroup.vue
+++ b/ui/src/views/compute/CreateAutoScaleVmGroup.vue
@@ -329,6 +329,7 @@
                 :status="zoneSelected ? 'process' : 'wait'"
                 v-if="zone && zone.networktype !== 'Basic'">
                 <template #description>
+                  <label>{{ $t('message.autoscale.vm.networks') }}</label>
                   <div v-if="zoneSelected">
                     <div v-if="vm.templateid && templateNics && templateNics.length > 0">
                       <instance-nics-network-select-list-view
@@ -2209,6 +2210,15 @@ export default {
           return
         }
 
+        const defaultNetwork = this.networks.filter(network => network.id === this.defaultNetworkId)[0]
+        if (defaultNetwork.supportsvmautoscaling !== true) {
+          this.$notification.error({
+            message: this.$t('message.request.failed'),
+            description: this.$t('message.error.select.network.supports.vm.autoscaling')
+          })
+          return
+        }
+
         if (!values.loadbalancerid) {
           this.$notification.error({
             message: this.$t('message.request.failed'),
diff --git a/ui/src/views/compute/wizard/NetworkSelection.vue b/ui/src/views/compute/wizard/NetworkSelection.vue
index b8d18448b8a..68c914eb6ba 100644
--- a/ui/src/views/compute/wizard/NetworkSelection.vue
+++ b/ui/src/views/compute/wizard/NetworkSelection.vue
@@ -181,17 +181,22 @@ export default {
         {
           dataIndex: 'type',
           title: this.$t('label.guestiptype'),
-          width: '30%'
+          width: '15%'
         },
         {
           dataIndex: 'vpcName',
           title: this.$t('label.vpc'),
-          width: '30%',
+          width: '20%',
           filters: vpcFilter,
           filteredValue: _.get(this.filteredInfo, 'id'),
           onFilter: (value, record) => {
             return record.vpcid === value
           }
+        },
+        {
+          dataIndex: 'supportsvmautoscaling',
+          title: this.$t('label.supportsvmautoscaling'),
+          width: '25%'
         }
       ]
     },
@@ -218,6 +223,7 @@ export default {
         return {
           ...network,
           ...{
+            supportsvmautoscaling: network.supportsvmautoscaling ? 'Yes' : 'No',
             vpcName: _.get(vpc, 'displaytext')
           }
         }
diff --git a/ui/src/views/offering/AddNetworkOffering.vue b/ui/src/views/offering/AddNetworkOffering.vue
index 73e7ebade35..a2bc9ad6ecd 100644
--- a/ui/src/views/offering/AddNetworkOffering.vue
+++ b/ui/src/views/offering/AddNetworkOffering.vue
@@ -280,6 +280,13 @@
             </a-radio-button>
           </a-radio-group>
         </a-form-item>
+        <a-form-item
+          name="vmautoscalingcapability"
+          ref="vmautoscalingcapability"
+          :label="$t('label.supportsvmautoscaling')"
+          v-if="lbServiceChecked && ['Netscaler', 'VirtualRouter', 'VpcVirtualRouter'].includes(lbServiceProvider)">
+          <a-switch v-model:checked="form.vmautoscalingcapability" />
+        </a-form-item>
         <a-form-item
           name="elasticlb"
           ref="elasticlb"
@@ -948,6 +955,12 @@ export default {
             delete params.associatepublicip
           }
           if (supportedServices.includes('Lb')) {
+            if ('vmautoscalingcapability' in values) {
+              params['servicecapabilitylist[' + serviceCapabilityIndex + '].service'] = 'lb'
+              params['servicecapabilitylist[' + serviceCapabilityIndex + '].capabilitytype'] = 'VmAutoScaling'
+              params['servicecapabilitylist[' + serviceCapabilityIndex + '].capabilityvalue'] = values.vmautoscalingcapability
+              serviceCapabilityIndex++
+            }
             if (values.elasticlb === true) {
               params['servicecapabilitylist[' + serviceCapabilityIndex + '].service'] = 'lb'
               params['servicecapabilitylist[' + serviceCapabilityIndex + '].capabilitytype'] = 'ElasticLb'