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:10 UTC

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

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'