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

dahn pushed a commit to branch 4.20-main-merge-try
in repository https://gitbox.apache.org/repos/asf/cloudstack.git

commit bcafbd16495ef9d0f50b9d23def24462d090ea6c
Merge: 0d4147f3f63 609efcc231a
Author: Daan Hoogland <d...@apache.org>
AuthorDate: Fri Jul 25 23:38:12 2025 +0200

    Merge branch '4.20'

 .../main/java/com/cloud/user/AccountService.java   |   2 +
 .../api/command/admin/cluster/ListClustersCmd.java |   6 +-
 .../api/command/admin/pod/ListPodsByCmd.java       |   4 +-
 .../command/user/config/ListCapabilitiesCmd.java   |   1 +
 .../command/user/userdata/RegisterUserDataCmd.java |  52 +-
 .../api/command/user/zone/ListZonesCmd.java        |   7 -
 .../api/response/CapabilitiesResponse.java         |   8 +
 .../cloudstack/api/response/UserDataResponse.java  |  22 +-
 .../org/apache/cloudstack/query/QueryService.java  |  12 +-
 .../com/cloud/agent/api/CheckVolumeAnswer.java     |  15 +-
 .../cloud/agent/api/CopyRemoteVolumeAnswer.java    |  15 +-
 .../main/java/com/cloud/vm/VirtualMachineGuru.java |   4 +
 .../cloudstack/backup/NASBackupProvider.java       |  13 +-
 .../kvm/resource/LibvirtComputingResource.java     |  11 +-
 .../LibvirtCheckConvertInstanceCommandWrapper.java |   2 +-
 .../wrapper/LibvirtCheckVolumeCommandWrapper.java  |  80 ++-
 .../LibvirtConvertInstanceCommandWrapper.java      |   2 +-
 .../LibvirtCopyRemoteVolumeCommandWrapper.java     |  76 +-
 .../LibvirtGetVolumesOnStorageCommandWrapper.java  |  66 +-
 .../wrapper/LibvirtReadyCommandWrapper.java        |   6 +-
 .../wrapper/LibvirtResizeVolumeCommandWrapper.java |  19 +-
 .../LibvirtRestoreBackupCommandWrapper.java        |  60 +-
 .../hypervisor/kvm/storage/KVMPhysicalDisk.java    |  32 +
 .../contrail/management/MockAccountManager.java    |   6 +
 .../lifecycle/StorageVmSharedFSLifeCycle.java      |  25 +-
 .../lifecycle/StorageVmSharedFSLifeCycleTest.java  |  11 +-
 plugins/storage/volume/linstor/CHANGELOG.md        |   6 +
 .../kvm/storage/LinstorStorageAdaptor.java         |   2 +-
 .../driver/LinstorPrimaryDataStoreDriverImpl.java  |  12 +-
 .../driver/ScaleIOPrimaryDataStoreDriver.java      |  16 +-
 .../driver/ScaleIOPrimaryDataStoreDriverTest.java  |  12 +
 .../kvm/storage/StorPoolStorageAdaptor.java        |   3 +
 .../cloudstack/api/command/LdapListUsersCmd.java   |   5 +-
 .../apache/cloudstack/ldap/LdapAuthenticator.java  |  58 +-
 .../apache/cloudstack/ldap/LdapManagerImpl.java    |  22 +-
 .../java/com/cloud/api/query/QueryManagerImpl.java | 482 +++++++------
 .../cloud/api/query/dao/TemplateJoinDaoImpl.java   |   7 +-
 .../consoleproxy/ConsoleProxyManagerImpl.java      |   6 +-
 .../resourcelimit/ResourceLimitManagerImpl.java    | 113 ++-
 .../com/cloud/server/ManagementServerImpl.java     |   8 +-
 .../com/cloud/storage/VolumeApiServiceImpl.java    |  16 +-
 .../java/com/cloud/user/AccountManagerImpl.java    |   1 +
 .../cloudstack/backup/BackupManagerImpl.java       |   2 +
 .../cloudstack/vm/UnmanagedVMsManagerImpl.java     |  45 +-
 .../cloud/storage/VolumeApiServiceImplTest.java    |   7 +-
 .../com/cloud/user/MockAccountManagerImpl.java     |   5 +
 .../java/com/cloud/consoleproxy/ConsoleProxy.java  |   7 +
 .../consoleproxy/ConsoleProxyNoVncClient.java      |  84 ++-
 .../com/cloud/consoleproxy/vnc/NoVncClient.java    |   8 +-
 .../cloud/consoleproxy/vnc/network/NioSocket.java  |   3 +-
 .../consoleproxy/vnc/network/NioSocketHandler.java |   3 +-
 .../vnc/network/NioSocketHandlerImpl.java          |  16 +-
 .../vnc/network/NioSocketInputStream.java          |  46 +-
 .../vnc/network/NioSocketSSLEngineManager.java     |  40 +-
 .../vnc/network/NioSocketTLSInputStream.java       |   3 +-
 .../vnc/network/NioSocketTLSOutputStream.java      |   5 +-
 .../SecondaryStorageManagerImpl.java               |   5 +-
 .../storage/resource/HttpUploadServerHandler.java  |  12 +-
 systemvm/agent/conf/consoleproxy.properties        |   1 +
 systemvm/debian/opt/cloud/bin/setup/common.sh      |   6 +-
 .../debian/opt/cloud/bin/setup/consoleproxy.sh     |   4 +
 systemvm/debian/opt/cloud/bin/setup/secstorage.sh  |   1 +
 .../plugins/linstor/test_linstor_volumes.py        |  73 +-
 ui/public/locales/ar.json                          |  24 +-
 ui/public/locales/ca.json                          |  22 +-
 ui/public/locales/de_DE.json                       |  26 +-
 ui/public/locales/el_GR.json                       |  51 +-
 ui/public/locales/en.json                          | 788 ++++++++++-----------
 ui/public/locales/es.json                          |  24 +-
 ui/public/locales/fr_FR.json                       |  24 +-
 ui/public/locales/hi.json                          |   4 +-
 ui/public/locales/hu.json                          |  26 +-
 ui/public/locales/it_IT.json                       |  24 +-
 ui/public/locales/ja_JP.json                       |  24 +-
 ui/public/locales/ko_KR.json                       |  24 +-
 ui/public/locales/nb_NO.json                       |  24 +-
 ui/public/locales/nl_NL.json                       |  24 +-
 ui/public/locales/pl.json                          |  24 +-
 ui/public/locales/pt_BR.json                       |  24 +-
 ui/public/locales/ru_RU.json                       |  24 +-
 ui/public/locales/zh_CN.json                       |  24 +-
 ui/src/components/view/InfoCard.vue                |  22 +-
 ui/src/components/view/ListView.vue                |   7 +-
 ui/src/config/section/account.js                   |   2 +-
 ui/src/config/section/compute.js                   |   6 +-
 ui/src/config/section/domain.js                    |   5 +
 ui/src/config/section/network.js                   |  21 +-
 ui/src/views/compute/AutoScaleVmProfile.vue        |  14 +-
 ui/src/views/compute/CreateAutoScaleVmGroup.vue    |  14 +-
 ui/src/views/compute/DeployVM.vue                  |  56 +-
 ui/src/views/compute/DeployVnfAppliance.vue        |  73 +-
 ui/src/views/compute/EditVM.vue                    |   7 +-
 ui/src/views/compute/RegisterUserData.vue          |  39 +-
 ui/src/views/compute/ResetUserData.vue             |  14 +-
 ui/src/views/compute/wizard/UserDataSelection.vue  |   4 +-
 ui/src/views/image/RegisterOrUploadIso.vue         |   4 +-
 ui/src/views/image/RegisterOrUploadTemplate.vue    |   4 +-
 ui/src/views/image/UpdateISO.vue                   |   4 +-
 ui/src/views/image/UpdateTemplate.vue              |   4 +-
 ui/src/views/infra/network/ServiceProvidersTab.vue |   2 +-
 .../{AclListRulesTab.vue => AclRulesTab.vue}       |   2 +-
 ui/src/views/network/VpcTab.vue                    |   8 +-
 ui/src/views/offering/AddNetworkOffering.vue       |   2 +-
 .../com/cloud/hypervisor/vmware/mo/HostMO.java     | 152 +---
 104 files changed, 1882 insertions(+), 1491 deletions(-)

diff --cc 
api/src/main/java/org/apache/cloudstack/api/command/user/config/ListCapabilitiesCmd.java
index 77a7a7fd8ea,bd3f39a09aa..318bed11ad9
--- 
a/api/src/main/java/org/apache/cloudstack/api/command/user/config/ListCapabilitiesCmd.java
+++ 
b/api/src/main/java/org/apache/cloudstack/api/command/user/config/ListCapabilitiesCmd.java
@@@ -72,7 -72,7 +72,8 @@@ public class ListCapabilitiesCmd extend
          response.setInstancesDisksStatsRetentionTime((Integer) 
capabilities.get(ApiConstants.INSTANCES_DISKS_STATS_RETENTION_TIME));
          
response.setSharedFsVmMinCpuCount((Integer)capabilities.get(ApiConstants.SHAREDFSVM_MIN_CPU_COUNT));
          
response.setSharedFsVmMinRamSize((Integer)capabilities.get(ApiConstants.SHAREDFSVM_MIN_RAM_SIZE));
 +        response.setInstanceLeaseEnabled((Boolean) 
capabilities.get(ApiConstants.INSTANCE_LEASE_ENABLED));
+         response.setDynamicScalingEnabled((Boolean) 
capabilities.get(ApiConstants.DYNAMIC_SCALING_ENABLED));
          response.setObjectName("capability");
          response.setResponseName(getCommandName());
          this.setResponseObject(response);
diff --cc 
api/src/main/java/org/apache/cloudstack/api/response/CapabilitiesResponse.java
index 74dbfa15a43,ff2e33b1389..910dc5fa38d
--- 
a/api/src/main/java/org/apache/cloudstack/api/response/CapabilitiesResponse.java
+++ 
b/api/src/main/java/org/apache/cloudstack/api/response/CapabilitiesResponse.java
@@@ -136,10 -136,10 +136,14 @@@ public class CapabilitiesResponse exten
      @Param(description = "the min Ram size for the service offering used by 
the shared filesystem instance", since = "4.20.0")
      private Integer sharedFsVmMinRamSize;
  
 +    @SerializedName(ApiConstants.INSTANCE_LEASE_ENABLED)
 +    @Param(description = "true if instance lease feature is enabled", since = 
"4.21.0")
 +    private Boolean instanceLeaseEnabled;
 +
+     @SerializedName(ApiConstants.DYNAMIC_SCALING_ENABLED)
+     @Param(description = "true if dynamically scaling for instances is 
enabled", since = "4.21.0")
+     private Boolean dynamicScalingEnabled;
+ 
      public void setSecurityGroupsEnabled(boolean securityGroupsEnabled) {
          this.securityGroupsEnabled = securityGroupsEnabled;
      }
@@@ -252,7 -252,7 +256,11 @@@
          this.sharedFsVmMinRamSize = sharedFsVmMinRamSize;
      }
  
 +    public void setInstanceLeaseEnabled(Boolean instanceLeaseEnabled) {
 +        this.instanceLeaseEnabled = instanceLeaseEnabled;
 +    }
++
+     public void setDynamicScalingEnabled(Boolean dynamicScalingEnabled) {
+         this.dynamicScalingEnabled = dynamicScalingEnabled;
+     }
  }
diff --cc 
plugins/storage/sharedfs/storagevm/src/test/java/org/apache/cloudstack/storage/sharedfs/lifecycle/StorageVmSharedFSLifeCycleTest.java
index 813d8978697,2cc909ce0d7..21753257f75
--- 
a/plugins/storage/sharedfs/storagevm/src/test/java/org/apache/cloudstack/storage/sharedfs/lifecycle/StorageVmSharedFSLifeCycleTest.java
+++ 
b/plugins/storage/sharedfs/storagevm/src/test/java/org/apache/cloudstack/storage/sharedfs/lifecycle/StorageVmSharedFSLifeCycleTest.java
@@@ -257,11 -258,16 +257,16 @@@ public class StorageVmSharedFSLifeCycle
                  anyString(), anyLong(), anyLong(), isNull(), 
any(Hypervisor.HypervisorType.class), any(BaseCmd.HTTPMethod.class), 
anyString(),
                  isNull(), isNull(), anyList(), isNull(), 
any(Network.IpAddresses.class), isNull(), isNull(), isNull(),
                  anyMap(), isNull(), isNull(), isNull(), isNull(),
 -                anyBoolean(), anyString(), isNull())).thenReturn(vm);
 +                anyBoolean(), anyString(), isNull(), isNull(), 
isNull())).thenReturn(vm);
  
-         VolumeVO volume = mock(VolumeVO.class);
-         when(volume.getId()).thenReturn(s_volumeId);
-         when(volumeDao.findByInstanceAndType(s_vmId, 
Volume.Type.DATADISK)).thenReturn(List.of(volume));
+         VolumeVO rootVol = mock(VolumeVO.class);
+         when(rootVol.getVolumeType()).thenReturn(Volume.Type.ROOT);
+         when(rootVol.getName()).thenReturn("ROOT-1");
+         VolumeVO dataVol = mock(VolumeVO.class);
+         when(dataVol.getId()).thenReturn(s_volumeId);
+         when(dataVol.getName()).thenReturn("DATA-1");
+         when(dataVol.getVolumeType()).thenReturn(Volume.Type.DATADISK);
+         when(volumeDao.findByInstance(s_vmId)).thenReturn(List.of(rootVol, 
dataVol));
  
           Pair<Long, Long> result = lifeCycle.deploySharedFS(sharedFS, 
s_networkId, s_diskOfferingId, s_size, s_minIops, s_maxIops);
           Assert.assertEquals(Optional.ofNullable(result.first()), 
Optional.ofNullable(s_volumeId));
diff --cc server/src/main/java/com/cloud/api/query/QueryManagerImpl.java
index cdedd830c0a,6fb9ab515cb..0f8adf1a666
--- a/server/src/main/java/com/cloud/api/query/QueryManagerImpl.java
+++ b/server/src/main/java/com/cloud/api/query/QueryManagerImpl.java
@@@ -167,13 -161,11 +168,13 @@@ import org.apache.cloudstack.storage.da
  import org.apache.cloudstack.storage.datastore.db.StoragePoolDetailVO;
  import org.apache.cloudstack.storage.datastore.db.StoragePoolDetailsDao;
  import org.apache.cloudstack.storage.datastore.db.StoragePoolVO;
- import org.apache.cloudstack.storage.datastore.db.TemplateDataStoreDao;
 +import org.apache.cloudstack.vm.lease.VMLeaseManager;
  import org.apache.commons.collections.CollectionUtils;
  import org.apache.commons.collections.MapUtils;
  import org.apache.commons.lang3.EnumUtils;
 +import org.apache.commons.lang3.ObjectUtils;
  import org.apache.commons.lang3.StringUtils;
+ import org.jetbrains.annotations.NotNull;
  import org.springframework.stereotype.Component;
  
  import com.cloud.api.query.dao.AccountJoinDao;
@@@ -728,10 -643,10 +716,10 @@@ public class QueryManagerImpl extends M
          String keyword = null;
  
          Pair<List<UserAccountJoinVO>, Integer> result =  
getUserListInternal(caller, permittedAccounts, listAll, id,
 -                username, type, accountName, state, keyword, null, domainId, 
recursive, null);
 +                username, type, accountName, state, keyword, null, domainId, 
recursive, null, null);
-         ListResponse<UserResponse> response = new 
ListResponse<UserResponse>();
+         ListResponse<UserResponse> response = new ListResponse<>();
          List<UserResponse> userResponses = 
ViewResponseHelper.createUserResponse(ResponseView.Restricted, 
CallContext.current().getCallingAccount().getDomainId(),
-                 result.first().toArray(new 
UserAccountJoinVO[result.first().size()]));
+                 result.first().toArray(new UserAccountJoinVO[0]));
          response.setResponses(userResponses, result.second());
          return response;
      }
@@@ -769,8 -683,8 +757,8 @@@
      }
  
      private Pair<List<UserAccountJoinVO>, Integer> 
getUserListInternal(Account caller, List<Long> permittedAccounts, boolean 
listAll, Long id, Object username, Object type,
 -            String accountName, Object state, String keyword, String 
apiKeyAccess, Long domainId, boolean recursive, Filter searchFilter) {
 +            String accountName, Object state, String keyword, String 
apiKeyAccess, Long domainId, boolean recursive, Filter searchFilter, 
User.Source userSource) {
-         Ternary<Long, Boolean, ListProjectResourcesCriteria> 
domainIdRecursiveListProject = new Ternary<Long, Boolean, 
ListProjectResourcesCriteria>(domainId, recursive, null);
+         Ternary<Long, Boolean, ListProjectResourcesCriteria> 
domainIdRecursiveListProject = new Ternary<>(domainId, recursive, null);
          accountMgr.buildACLSearchParameters(caller, id, accountName, null, 
permittedAccounts, domainIdRecursiveListProject, listAll, false);
          domainId = domainIdRecursiveListProject.first();
          Boolean isRecursive = domainIdRecursiveListProject.second();
@@@ -3235,17 -3096,25 +3222,17 @@@
      private ListResponse<StoragePoolResponse> 
createStoragesPoolResponse(Pair<List<StoragePoolJoinVO>, Integer> storagePools, 
boolean getCustomStats) {
          ListResponse<StoragePoolResponse> response = new ListResponse<>();
  
-         List<StoragePoolResponse> poolResponses = 
ViewResponseHelper.createStoragePoolResponse(getCustomStats, 
storagePools.first().toArray(new 
StoragePoolJoinVO[storagePools.first().size()]));
+         List<StoragePoolResponse> poolResponses = 
ViewResponseHelper.createStoragePoolResponse(getCustomStats, 
storagePools.first().toArray(new StoragePoolJoinVO[0]));
          Map<String, Long> poolUuidToIdMap = 
storagePools.first().stream().collect(Collectors.toMap(StoragePoolJoinVO::getUuid,
 StoragePoolJoinVO::getId, (a, b) -> a));
          for (StoragePoolResponse poolResponse : poolResponses) {
 +            Long poolId = poolUuidToIdMap.get(poolResponse.getId());
              DataStore store = 
dataStoreManager.getPrimaryDataStore(poolResponse.getId());
 +
              if (store != null) {
 -                DataStoreDriver driver = store.getDriver();
 -                if (driver != null && driver.getCapabilities() != null) {
 -                    Map<String, String> caps = driver.getCapabilities();
 -                    if 
(Storage.StoragePoolType.NetworkFilesystem.toString().equals(poolResponse.getType())
 &&
 -                        
HypervisorType.VMware.toString().equals(poolResponse.getHypervisor())) {
 -                        StoragePoolDetailVO detail = 
_storagePoolDetailsDao.findDetail(poolUuidToIdMap.get(poolResponse.getId()), 
Storage.Capability.HARDWARE_ACCELERATION.toString());
 -                        if (detail != null) {
 -                            
caps.put(Storage.Capability.HARDWARE_ACCELERATION.toString(), 
detail.getValue());
 -                        }
 -                    }
 -                    poolResponse.setCaps(caps);
 -                }
 +                addPoolDetailsAndCapabilities(poolResponse, store, poolId);
              }
 -            setPoolResponseNFSMountOptions(poolResponse, 
poolUuidToIdMap.get(poolResponse.getId()));
 +
 +            setPoolResponseNFSMountOptions(poolResponse, poolId);
          }
  
          response.setResponses(poolResponses, storagePools.second());
@@@ -3319,100 -3158,7 +3306,100 @@@
          return response;
      }
  
 +    @Override
 +    public ListResponse<StorageAccessGroupResponse> 
searchForStorageAccessGroups(ListStorageAccessGroupsCmd cmd) {
 +        String name = cmd.getName();
 +        String keyword = cmd.getKeyword();
 +        Set<String> storageAccessGroups = new HashSet<>();
 +
 +        addStorageAccessGroups(storageAccessGroups, 
storagePoolAndAccessGroupMapDao.listDistinctStorageAccessGroups(name, keyword));
 +        addStorageAccessGroups(storageAccessGroups, 
hostDao.listDistinctStorageAccessGroups(name, keyword));
 +        addStorageAccessGroups(storageAccessGroups, 
clusterDao.listDistinctStorageAccessGroups(name, keyword));
 +        addStorageAccessGroups(storageAccessGroups, 
podDao.listDistinctStorageAccessGroups(name, keyword));
 +        addStorageAccessGroups(storageAccessGroups, 
dataCenterDao.listDistinctStorageAccessGroups(name, keyword));
 +
 +        if (StringUtils.isNotEmpty(name) && 
storageAccessGroups.contains(name)) {
 +            storageAccessGroups = Collections.singleton(name);
 +        }
 +
 +        if (StringUtils.isNotEmpty(keyword)) {
 +            storageAccessGroups = storageAccessGroups.stream()
 +                    .filter(group -> group.contains(keyword))
 +                    .collect(Collectors.toSet());
 +        }
 +
 +        List<StorageAccessGroupResponse> responseList = 
buildStorageAccessGroupResponses(storageAccessGroups, name);
 +
 +        ListResponse<StorageAccessGroupResponse> response = new 
ListResponse<>();
 +        response.setResponses(responseList, storageAccessGroups.size());
 +        return response;
 +    }
 +
 +    private void addStorageAccessGroups(Set<String> storageAccessGroups, 
List<String> groups) {
 +        for (String group : groups) {
 +            if (group != null && !group.isEmpty()) {
 +                storageAccessGroups.addAll(Arrays.asList(group.split(",")));
 +            }
 +        }
 +    }
 +
 +    private List<StorageAccessGroupResponse> buildStorageAccessGroupResponses(
 +            Set<String> storageAccessGroups, String name) {
 +        List<StorageAccessGroupResponse> responseList = new ArrayList<>();
 +
 +        for (String sag : storageAccessGroups) {
 +            StorageAccessGroupResponse sagResponse = new 
StorageAccessGroupResponse();
 +            sagResponse.setName(sag);
 +            sagResponse.setObjectName(ApiConstants.STORAGE_ACCESS_GROUP);
 +
 +            if (StringUtils.isNotBlank(name)) {
 +                fetchStorageAccessGroupResponse(sagResponse, name);
 +            }
 +
 +            responseList.add(sagResponse);
 +        }
 +        return responseList;
 +    }
 +
 +    private void fetchStorageAccessGroupResponse(StorageAccessGroupResponse 
sagResponse, String name) {
 +        
sagResponse.setHostResponseList(searchForServersWithMinimalResponse(new 
ListHostsCmd(name)));
 +        
sagResponse.setZoneResponseList(listDataCentersWithMinimalResponse(new 
ListZonesCmd(name)));
 +        sagResponse.setPodResponseList(fetchPodsByStorageAccessGroup(name));
 +        
sagResponse.setClusterResponseList(fetchClustersByStorageAccessGroup(name));
 +        
sagResponse.setStoragePoolResponseList(searchForStoragePoolsWithMinimalResponse(new
 ListStoragePoolsCmd(name)));
 +    }
 +
 +    private ListResponse<PodResponse> fetchPodsByStorageAccessGroup(String 
name) {
 +        ListPodsByCmd listPodsByCmd = new ListPodsByCmd(name);
 +        Pair<List<? extends Pod>, Integer> podResponsePair = 
managementService.searchForPods(listPodsByCmd);
 +        List<PodResponse> podResponses = podResponsePair.first().stream()
 +                .map(pod -> {
 +                    PodResponse podResponse = 
responseGenerator.createMinimalPodResponse(pod);
 +                    podResponse.setObjectName("pod");
 +                    return podResponse;
 +                }).collect(Collectors.toList());
 +
 +        ListResponse<PodResponse> podResponse = new ListResponse<>();
 +        podResponse.setResponses(podResponses, podResponsePair.second());
 +        return podResponse;
 +    }
 +
 +    private ListResponse<ClusterResponse> 
fetchClustersByStorageAccessGroup(String name) {
 +        ListClustersCmd listClustersCmd = new ListClustersCmd(name);
 +        Pair<List<? extends Cluster>, Integer> clusterResponsePair = 
managementService.searchForClusters(listClustersCmd);
 +        List<ClusterResponse> clusterResponses = 
clusterResponsePair.first().stream()
 +                .map(cluster -> {
 +                    ClusterResponse clusterResponse = 
responseGenerator.createMinimalClusterResponse(cluster);
 +                    clusterResponse.setObjectName("cluster");
 +                    return clusterResponse;
 +                }).collect(Collectors.toList());
 +
 +        ListResponse<ClusterResponse> clusterResponse = new ListResponse<>();
 +        clusterResponse.setResponses(clusterResponses, 
clusterResponsePair.second());
 +        return clusterResponse;
 +    }
 +
-     private Pair<List<StoragePoolTagVO>, Integer> 
searchForStorageTagsInternal(ListStorageTagsCmd cmd) {
+     private Pair<List<StoragePoolTagVO>, Integer> 
searchForStorageTagsInternal() {
          Filter searchFilter = new Filter(StoragePoolTagVO.class, "id", 
Boolean.TRUE, null, null);
  
          SearchBuilder<StoragePoolTagVO> sb = 
_storageTagDao.createSearchBuilder();
@@@ -4497,7 -4228,11 +4483,11 @@@
      private Pair<List<DataCenterJoinVO>, Integer> 
listDataCentersInternal(ListZonesCmd cmd) {
          Account account = CallContext.current().getCallingAccount();
          Long domainId = cmd.getDomainId();
-         Long id = cmd.getId();
+         Long zoneId = cmd.getId();
 -        if( ! 
AllowUserViewAllDataCenters.valueInDomain(account.getDomainId())) {
++        if( ! 
AllowUserViewAllDataCenters.valueInScope(ConfigKey.Scope.Domain, 
account.getDomainId())) {
+             zoneId = 
accountMgr.checkAccessAndSpecifyAuthority(CallContext.current().getCallingAccount(),
 zoneId);
+             logger.debug("not allowing users to view all zones ; selected 
zone is = {}", zoneId);
+         }
          List<Long> ids = getIdsListFromCmd(cmd.getId(), cmd.getIds());
          String keyword = cmd.getKeyword();
          String name = cmd.getName();
@@@ -4675,6 -4300,12 +4563,19 @@@
              }
          }
  
+         buildSearchCriteriaForTags(resourceTags, sc);
+ 
++        if (storageAccessGroup != null) {
++            sc.setParameters("storageAccessGroupExact", storageAccessGroup);
++            sc.setParameters("storageAccessGroupPrefix", storageAccessGroup + 
",%");
++            sc.setParameters("storageAccessGroupSuffix", "%," + 
storageAccessGroup);
++            sc.setParameters("storageAccessGroupMiddle", "%," + 
storageAccessGroup + ",%");
++        }
++
+         return _dcJoinDao.searchAndCount(sc, searchFilter);
+     }
+ 
+     private static void buildSearchCriteriaForTags(Map<String, String> 
resourceTags, SearchCriteria<DataCenterJoinVO> sc) {
          if (resourceTags != null && !resourceTags.isEmpty()) {
              int count = 0;
              sc.setJoinParameters("tagSearch", "resourceType", 
ResourceObjectType.Zone.toString());
@@@ -4796,7 -4539,7 +4810,7 @@@
                  null, cmd.getPageSizeVal(), cmd.getStartIndex(), 
cmd.getZoneId(), cmd.getStoragePoolId(),
                  cmd.getImageStoreId(), hypervisorType, showDomr, 
cmd.listInReadyState(), permittedAccounts, caller,
                  listProjectResourcesCriteria, tags, showRemovedTmpl, 
cmd.getIds(), parentTemplateId, cmd.getShowUnique(),
-                 templateType, isVnf, cmd.getArch(), cmd.getOsCategoryId(), 
forCks);
 -                templateType, isVnf, domainId, isRecursive, cmd.getArch());
++                templateType, isVnf, domainId, isRecursive, cmd.getArch(), 
cmd.getOsCategoryId(), forCks);
      }
  
      private Pair<List<TemplateJoinVO>, Integer> 
searchForTemplatesInternal(Long templateId, String name, String keyword,
@@@ -4805,7 -4548,7 +4819,7 @@@
              boolean showDomr, boolean onlyReady, List<Account> 
permittedAccounts, Account caller,
              ListProjectResourcesCriteria listProjectResourcesCriteria, 
Map<String, String> tags,
              boolean showRemovedTmpl, List<Long> ids, Long parentTemplateId, 
Boolean showUnique, String templateType,
-             Boolean isVnf, CPU.CPUArch arch, Long osCategoryId, Boolean 
forCks) {
 -            Boolean isVnf, Long domainId, boolean isRecursive, CPU.CPUArch 
arch) {
++            Boolean isVnf, Long domainId, boolean isRecursive, CPU.CPUArch 
arch, Long osCategoryId, Boolean forCks) {
  
          // check if zone is configured, if not, just return empty list
          List<HypervisorType> hypers = null;
@@@ -5253,7 -4986,7 +5273,7 @@@
                  cmd.getPageSizeVal(), cmd.getStartIndex(), cmd.getZoneId(), 
cmd.getStoragePoolId(), cmd.getImageStoreId(),
                  hypervisorType, true, cmd.listInReadyState(), 
permittedAccounts, caller, listProjectResourcesCriteria,
                  tags, showRemovedISO, null, null, cmd.getShowUnique(), null, 
null,
-                 cmd.getArch(), cmd.getOsCategoryId(), null);
 -                domainId, isRecursive, cmd.getArch());
++                domainId, isRecursive, cmd.getArch(), cmd.getOsCategoryId(), 
null);
      }
  
      @Override
diff --cc 
server/src/main/java/com/cloud/resourcelimit/ResourceLimitManagerImpl.java
index 37d74445776,85cca63546c..47f650da2cc
--- a/server/src/main/java/com/cloud/resourcelimit/ResourceLimitManagerImpl.java
+++ b/server/src/main/java/com/cloud/resourcelimit/ResourceLimitManagerImpl.java
@@@ -615,9 -587,9 +610,9 @@@ public class ResourceLimitManagerImpl e
  
      @Override
      public long findDefaultResourceLimitForDomain(ResourceType resourceType) {
-         Long resourceLimit = null;
+         Long resourceLimit;
          resourceLimit = domainResourceLimitMap.get(resourceType.getName());
 -        if (resourceLimit != null && (resourceType == 
ResourceType.primary_storage || resourceType == 
ResourceType.secondary_storage)) {
 +        if (resourceLimit != null && 
ResourceType.isStorageType(resourceType)) {
              if (! 
Long.valueOf(Resource.RESOURCE_UNLIMITED).equals(resourceLimit)) {
                  resourceLimit = resourceLimit * ResourceType.bytesToGiB;
              }
@@@ -1327,11 -1274,12 +1325,12 @@@
              _resourceCountDao.persist(new ResourceCountVO(type, newCount, 
accountId, ResourceOwnerType.Account, tag));
          }
  
 -        // No need to log message for primary and secondary storage because 
both are recalculating the
 +        // No need to log message for storage type resources because both are 
recalculating the
          // resource count which will not lead to any discrepancy.
-         if (newCount != null && !newCount.equals(oldCount) && 
!ResourceType.isStorageType(type)) {
-             logger.warn("Discrepancy in the resource count " + "(original 
count=" + oldCount + " correct count = " + newCount + ") for type " + type +
-                     " for account ID " + accountId + " is fixed during 
resource count recalculation.");
+         if (newCount != null && !newCount.equals(oldCount) &&
+                 type != Resource.ResourceType.primary_storage && type != 
Resource.ResourceType.secondary_storage) {
+             logger.warn("Discrepancy in the resource count (original count={} 
correct count = {}) for type {} for account ID {} is fixed during resource 
count recalculation.",
+                     oldCount, newCount, type, accountId);
          }
  
          return (newCount == null) ? 0 : newCount;
diff --cc server/src/main/java/com/cloud/server/ManagementServerImpl.java
index 650028e1247,271372bf656..2bbd7e1bf86
--- a/server/src/main/java/com/cloud/server/ManagementServerImpl.java
+++ b/server/src/main/java/com/cloud/server/ManagementServerImpl.java
@@@ -777,7 -751,7 +777,6 @@@ import com.cloud.org.Grouping.Allocatio
  import com.cloud.projects.Project;
  import com.cloud.projects.Project.ListProjectResourcesCriteria;
  import com.cloud.projects.ProjectManager;
--import com.cloud.resource.ResourceManager;
  import com.cloud.server.ResourceTag.ResourceObjectType;
  import com.cloud.service.ServiceOfferingVO;
  import com.cloud.service.dao.ServiceOfferingDao;
@@@ -879,9 -854,6 +878,9 @@@ public class ManagementServerImpl exten
      static final ConfigKey<Integer> sshKeyLength = new 
ConfigKey<>("Advanced", Integer.class, "ssh.key.length", "2048", "Specifies 
custom SSH key length (bit)", true, ConfigKey.Scope.Global);
      static final ConfigKey<Boolean> humanReadableSizes = new 
ConfigKey<>("Advanced", Boolean.class, "display.human.readable.sizes", "true", 
"Enables outputting human readable byte sizes to logs and usage records.", 
false, ConfigKey.Scope.Global);
      public static final ConfigKey<String> customCsIdentifier = new 
ConfigKey<>("Advanced", String.class, "custom.cs.identifier", 
UUID.randomUUID().toString().split("-")[0].substring(4), "Custom identifier for 
the cloudstack installation", true, ConfigKey.Scope.Global);
-     public static final ConfigKey<Boolean> 
exposeCloudStackVersionInApiXmlResponse = new ConfigKey<Boolean>("Advanced", 
Boolean.class, "expose.cloudstack.version.api.xml.response", "true", "Indicates 
whether ACS version should appear in the root element of an API XML response.", 
true, ConfigKey.Scope.Global);
-     public static final ConfigKey<Boolean> 
exposeCloudStackVersionInApiListCapabilities = new 
ConfigKey<Boolean>("Advanced", Boolean.class, 
"expose.cloudstack.version.api.list.capabilities", "true", "Indicates whether 
ACS version should show in the listCapabilities API.", true, 
ConfigKey.Scope.Global);
++    public static final ConfigKey<Boolean> 
exposeCloudStackVersionInApiXmlResponse = new ConfigKey<>("Advanced", 
Boolean.class, "expose.cloudstack.version.api.xml.response", "true", "Indicates 
whether ACS version should appear in the root element of an API XML response.", 
true, ConfigKey.Scope.Global);
++    public static final ConfigKey<Boolean> 
exposeCloudStackVersionInApiListCapabilities = new ConfigKey<>("Advanced", 
Boolean.class, "expose.cloudstack.version.api.list.capabilities", "true", 
"Indicates whether ACS version should show in the listCapabilities API.", true, 
ConfigKey.Scope.Global);
 +
      private static final VirtualMachine.Type []systemVmTypes = { 
VirtualMachine.Type.SecondaryStorageVm, VirtualMachine.Type.ConsoleProxy};
      private static final List<HypervisorType> 
LIVE_MIGRATION_SUPPORTING_HYPERVISORS = List.of(HypervisorType.Hyperv, 
HypervisorType.KVM,
              HypervisorType.LXC, HypervisorType.Ovm, HypervisorType.Ovm3, 
HypervisorType.Simulator, HypervisorType.VMware, HypervisorType.XenServer);
@@@ -985,8 -955,8 +984,6 @@@
      @Inject
      private ProjectManager _projectMgr;
      @Inject
--    private ResourceManager _resourceMgr;
--    @Inject
      private HighAvailabilityManager _haMgr;
      @Inject
      private HostTagsDao _hostTagsDao;
@@@ -4728,7 -4528,7 +4725,8 @@@
          capabilities.put(ApiConstants.INSTANCES_STATS_USER_ONLY, 
StatsCollector.vmStatsCollectUserVMOnly.value());
          
capabilities.put(ApiConstants.INSTANCES_DISKS_STATS_RETENTION_ENABLED, 
StatsCollector.vmDiskStatsRetentionEnabled.value());
          capabilities.put(ApiConstants.INSTANCES_DISKS_STATS_RETENTION_TIME, 
StatsCollector.vmDiskStatsMaxRetentionTime.value());
 +        capabilities.put(ApiConstants.INSTANCE_LEASE_ENABLED, 
VMLeaseManager.InstanceLeaseEnabled.value());
+         capabilities.put(ApiConstants.DYNAMIC_SCALING_ENABLED, 
UserVmManager.EnableDynamicallyScaleVm.value());
          if (apiLimitEnabled) {
              capabilities.put("apiLimitInterval", apiLimitInterval);
              capabilities.put("apiLimitMax", apiLimitMax);
diff --cc ui/public/locales/en.json
index e26cd4d494e,c36b96cc961..6e675d1c061
--- a/ui/public/locales/en.json
+++ b/ui/public/locales/en.json
@@@ -53,9 -53,7 +53,8 @@@
  "label.acquiring.ip": "Acquiring IP",
  "label.associated.resource": "Associated resource",
  "label.action": "Action",
 -"label.action.attach.disk": "Attach Disk",
 +"label.action.add.nodes.to.kubernetes.cluster": "Add nodes to Kubernetes 
cluster",
 +"label.action.remove.nodes.from.kubernetes.cluster": "Remove nodes from 
Kubernetes cluster",
- "label.action.attach.disk": "Attach disk",
  "label.action.attach.iso": "Attach ISO",
  "label.action.attach.to.instance": "Attach to Instance",
  "label.action.bulk.delete.egress.firewall.rules": "Bulk delete egress 
firewall rules",
@@@ -72,9 -70,8 +71,9 @@@
  "label.action.change.password": "Change password",
  "label.action.clear.webhook.deliveries": "Clear deliveries",
  "label.action.delete.webhook.deliveries": "Delete deliveries",
- "label.action.change.primary.storage.scope": "Change primary storage scope",
+ "label.action.change.primary.storage.scope": "Change Primary Storage scope",
  "label.action.configure.stickiness": "Stickiness",
 +"label.action.configure.storage.access.group": "Update storage access group",
  "label.action.copy.iso": "Copy ISO",
  "label.action.copy.snapshot": "Copy Snapshot",
  "label.action.copy.template": "Copy Template",
@@@ -84,13 -81,12 +83,13 @@@
  "label.action.create.volume.add": "Create and Add Volume",
  "label.action.delete.account": "Delete Account",
  "label.action.delete.backup.offering": "Delete backup offering",
- "label.action.delete.cluster": "Delete cluster",
- "label.action.delete.domain": "Delete domain",
- "label.action.delete.egress.firewall": "Delete egress firewall rule",
- "label.action.delete.firewall": "Delete firewall rule",
+ "label.action.delete.cluster": "Delete Cluster",
+ "label.action.delete.domain": "Delete Domain",
+ "label.action.delete.egress.firewall": "Delete Egress Firewall Rule",
+ "label.action.delete.firewall": "Delete Firewall Rule",
  "label.action.delete.interface.static.route": "Remove Tungsten Fabric 
interface static route",
  "label.action.delete.guest.os": "Delete guest OS",
 +"label.action.delete.guest.os.category": "Delete guest OS category",
  "label.action.delete.guest.os.hypervisor.mapping": "Delete guest OS 
hypervisor mapping",
  "label.action.delete.ip.range": "Delete IP range",
  "label.action.delete.iso": "Delete ISO",
@@@ -224,13 -220,9 +223,13 @@@
  "label.action.unmanage.instance": "Unmanage Instance",
  "label.action.unmanage.instances": "Unmanage Instances",
  "label.action.unmanage.virtualmachine": "Unmanage Instance",
 +"label.action.update.cluster": "Update cluster",
 +"label.action.update.pod": "Update pod",
 +"label.action.update.zone": "Update zone",
 +"label.action.update.storage.pool": "Update storage pool",
  "label.action.unmanage.volume": "Unmanage Volume",
  "label.action.unmanage.volumes": "Unmanage Volumes",
- "label.action.update.host": "Update host",
+ "label.action.update.host": "Update Host",
  "label.action.update.security.groups": "Update security groups",
  "label.action.update.offering.access": "Update offering access",
  "label.action.update.resource.count": "Update resource count",
@@@ -256,40 -248,37 +255,39 @@@
  "label.add.by": "Add by",
  "label.add.certificate": "Add certificate",
  "label.add.ciscoasa1000v": "Add CiscoASA1000v resource",
- "label.add.cluster": "Add cluster",
- "label.add.compute.offering": "Add compute offering",
+ "label.add.cluster": "Add Cluster",
+ "label.add.compute.offering": "Add Compute Offering",
  "label.add.condition": "Add condition",
- "label.add.disk.offering": "Add disk offering",
- "label.add.domain": "Add domain",
- "label.add.egress.rule": "Add egress rule",
+ "label.add.disk.offering": "Add Disk Offering",
+ "label.add.domain": "Add Domain",
+ "label.add.egress.rule": "Add Egress Rule",
  "label.add.f5.device": "Add F5 device",
- "label.add.firewall": "Add firewall rule",
+ "label.add.firewall": "Add Firewall Rule",
  "label.add.firewallrule": "Add Firewall Rule",
- "label.add.guest.network": "Add guest Network",
- "label.add.guest.os": "Add guest OS",
+ "label.add.guest.network": "Add Guest Network",
+ "label.add.guest.os": "Add Guest OS",
 +"label.add.guest.os.category": "Add guest OS category",
- "label.add.guest.os.hypervisor.mapping": "Add guest OS hypervisor mapping",
- "label.add.host": "Add host",
- "label.add.ingress.rule": "Add ingress rule",
+ "label.add.guest.os.hypervisor.mapping": "Add guest os hypervisor mapping",
+ "label.add.host": "Add Host",
+ "label.add.ingress.rule": "Add Ingress Rule",
  "label.add.intermediate.certificate": "Add intermediate certificate",
  "label.add.internal.lb": "Add internal LB",
- "label.add.ip.range": "Add IP range",
- "label.add.ipv4.subnet": "Add IPv4 subnet for Routed networks",
+ "label.add.ip.range": "Add IP Range",
+ "label.add.ipv4.subnet": "Add IPv4 Subnet for Routed Networks",
  "label.add.ip.v6.prefix": "Add IPv6 prefix",
- "label.add.isolated.network": "Add isolated Network",
- "label.add.kubernetes.cluster": "Add Kubernetes cluster",
+ "label.add.isolated.network": "Add Isolated Network",
+ "label.add.kubernetes.cluster": "Add Kubernetes Cluster",
+ "label.add.acl.name": "ACL name",
  "label.add.ldap.account": "Add LDAP Account",
- "label.add.list.name": "ACL List name",
  "label.add.logical.router": "Add Logical Router to this Network",
  "label.add.more": "Add more",
 +"label.add.nodes": "Add Nodes to Kubernetes Cluster",
- "label.add.netscaler.device": "Add Netscaler device",
+ "label.add.netscaler.device": "Add Netscaler Device",
  "label.add.network": "Add Network",
  "label.add.network.acl": "Add Network ACL",
- "label.add.network.acl.list": "Add Network ACL list",
- "label.add.network.offering": "Add Network offering",
+ "label.add.network.offering": "Add Network Offering",
  "label.add.network.permission": "Add Network permission",
- "label.add.new.gateway": "Add new gateway",
+ "label.add.new.gateway": "Add new Gateway",
  "label.add.new.tier": "Add new Network Tier",
  "label.add.niciranvp.device": "Add Nvp controller",
  "label.add.note": "Add comment",
@@@ -439,16 -427,13 +437,16 @@@
  "label.backup.configure.schedule": "Configure Backup Schedule",
  "label.backup.offering.assign": "Assign Instance to backup offering",
  "label.backup.offering.remove": "Remove Instance from backup offering",
- "label.backup.offerings": "Backup offerings",
+ "label.backup.offerings": "Backup Offerings",
  "label.backup.repository": "Backup Repository",
  "label.backup.restore": "Restore Instance backup",
- "label.backupofferingid": "Backup offering",
- "label.backupofferingname": "Backup offering",
- "label.backup.repository.add": "Add backup repository",
- "label.backup.repository.remove": "Remove backup repository",
+ "label.backupofferingid": "Backup Offering",
+ "label.backupofferingname": "Backup Offering",
+ "label.backup.repository.add": "Add Backup Repository",
+ "label.backup.repository.remove": "Remove Backup Repository",
 +"label.backuplimit": "Backup Limits",
 +"label.backup.storage": "Backup Storage",
 +"label.backupstoragelimit": "Backup Storage Limits (GiB)",
  "label.balance": "Balance",
  "label.bandwidth": "Bandwidth",
  "label.baremetal.dhcp.devices": "Bare metal DHCP devices",
@@@ -477,14 -462,13 +475,14 @@@
  "label.brocade.vcs.address": "Vcs switch address",
  "label.browser": "Browser",
  "label.bucket": "Bucket",
 +"label.bucketlimit": "Bucket Limits",
  "label.by.account": "By Account",
- "label.by.domain": "By domain",
+ "label.by.domain": "By Domain",
  "label.by.level": "By level",
- "label.by.pod": "By pod",
+ "label.by.pod": "By Pod",
  "label.by.state": "By state",
  "label.by.type": "By type",
- "label.by.zone": "By zone",
+ "label.by.zone": "By Zone",
  "label.bypassvlanoverlapcheck": "Bypass VLAN id/range overlap",
  "label.cachemode": "Write-cache type",
  "label.cancel": "Cancel",
@@@ -683,10 -653,8 +681,10 @@@
  "label.daily": "Daily",
  "label.dark.mode": "Dark mode",
  "label.dashboard": "Dashboard",
- "label.data.disk": "Data disk",
+ "label.data.disk": "Data Disk",
 +"label.data.pool": "Data pool",
 +"label.data.pool.description": "Data pool is required when using a Ceph pool 
with erasure code",
- "label.data.disk.offering": "Data disk offering",
+ "label.data.disk.offering": "Data Disk Offering",
  "label.date": "Date",
  "label.datetime.filter.period": "From <b>{startDate}</b> to <b>{endDate}</b>",
  "label.datetime.filter.starting": "Starting <b>{startDate}</b>.",
@@@ -1033,9 -1000,8 +1031,9 @@@
  "label.firstname": "First name",
  "label.firstname.lower": "firstname",
  "label.fix.errors": "Fix errors",
- "label.fixed": "Fixed offering",
+ "label.fixed": "Fixed Offering",
  "label.for": "for",
 +"label.forcks": "For CKS",
  "label.forbidden": "Forbidden",
  "label.forced": "Force",
  "label.force.ms.to.import.vm.files": "Enable to force OVF Download via 
Management Server. Disable to use KVM Host ovftool (if installed)",
@@@ -1085,9 -1050,7 +1083,9 @@@
  "label.guest.netmask": "Guest netmask",
  "label.guest.networks": "Guest Networks",
  "label.guest.os": "Guest OS",
 +"label.guest.os.category": "Guest OS Category",
 +"label.guest.os.categories": "Guest OS Categories",
- "label.guest.os.hypervisor.mappings": "Guest OS mappings",
+ "label.guest.os.hypervisor.mappings": "Guest OS Mappings",
  "label.guest.start.ip": "Guest start IP",
  "label.guest.traffic": "Guest traffic",
  "label.guestcidraddress": "Guest CIDR",
@@@ -1163,14 -1126,12 +1161,14 @@@
  "label.ikelifetime": "IKE lifetime (second)",
  "label.ikepolicy": "IKE policy",
  "label.ikeversion": "IKE version",
 +"label.image": "Image",
 +"label.image.type": "Image type",
  "label.images": "Images",
  "label.imagestoreid": "Secondary Storage",
- "label.import.backup.offering": "Import backup offering",
+ "label.import.backup.offering": "Import Backup Offering",
  "label.import.instance": "Import Instance",
- "label.import.offering": "Import offering",
- "label.import.role": "Import role",
+ "label.import.offering": "Import Offering",
+ "label.import.role": "Import Role",
  "label.import.volume": "Import Volume",
  "label.inactive": "Inactive",
  "label.in.progress": "in progress",
@@@ -1312,18 -1272,16 +1310,18 @@@
  "label.keyboardtype": "Keyboard type",
  "label.keypair": "SSH key pair",
  "label.keypairs": "SSH key pair(s)",
- "label.kubeconfig.cluster": "Kubernetes cluster config",
+ "label.kubeconfig.cluster": "Kubernetes Cluster config",
  "label.kubernetes": "Kubernetes",
- "label.kubernetes.access.details": "The kubernetes nodes can be accessed via 
ssh using: <br> <code><b> ssh -i [ssh_key] -p [port_number] 
cloud@[public_ip_address] </b></code> <br><br> where, <br> 
<code><b>ssh_key:</b></code> points to the ssh private key file corresponding 
to the key that was associated while creating the Kubernetes cluster. If no ssh 
key was provided during Kubernetes cluster creation, use the ssh private key of 
the management server. <br> <code><b>port_number:</b></co [...]
- "label.kubernetes.cluster": "Kubernetes cluster",
+ "label.kubernetes.access.details": "The kubernetes nodes can be accessed via 
ssh using: <br> <code><b> ssh -i [ssh_key] -p [port_number] 
cloud@[public_ip_address] </b></code> <br><br> where, <br> 
<code><b>ssh_key:</b></code> points to the ssh private key file corresponding 
to the key that was associated while creating the Kubernetes Cluster. If no ssh 
key was provided during Kubernetes cluster creation, use the ssh private key of 
the management server. <br> <code><b>port_number:</b></co [...]
+ "label.kubernetes.cluster": "Kubernetes Cluster",
 +"label.kubernetes.cluster.add.nodes.to.cluster": "Add nodes to Kubernetes 
cluster",
- "label.kubernetes.cluster.create": "Create Kubernetes cluster",
- "label.kubernetes.cluster.delete": "Delete Kubernetes cluster",
- "label.kubernetes.cluster.scale": "Scale Kubernetes cluster",
- "label.kubernetes.cluster.start": "Start Kubernetes cluster",
- "label.kubernetes.cluster.stop": "Stop Kubernetes cluster",
+ "label.kubernetes.cluster.create": "Create Kubernetes Cluster",
+ "label.kubernetes.cluster.delete": "Delete Kubernetes Cluster",
 +"label.kubernetes.cluster.remove.nodes.from.cluster": "Remove nodes from 
Kubernetes cluster",
- "label.kubernetes.cluster.upgrade": "Upgrade Kubernetes cluster",
+ "label.kubernetes.cluster.scale": "Scale Kubernetes Cluster",
+ "label.kubernetes.cluster.start": "Start Kubernetes Cluster",
+ "label.kubernetes.cluster.stop": "Stop Kubernetes Cluster",
+ "label.kubernetes.cluster.upgrade": "Upgrade Kubernetes Cluster",
  "label.kubernetes.dashboard": "Kubernetes dashboard UI",
  "label.kubernetes.dashboard.create.token": "Create token for Kubernetes 
dashboard",
  "label.kubernetes.dashboard.create.token.desc": "Since Kubernetes v1.24.0, 
there is no auto-generation of secret-based service Account token due to 
security reason. You need to create a service Account and an optional 
long-lived Bearer Token for the service Account.",
@@@ -1368,9 -1326,8 +1366,9 @@@
  "label.lbprovider": "Load balancer provider",
  "label.lbruleid": "Load balancer ID",
  "label.lbtype": "Load balancer type",
 +"label.ldap": "LDAP",
- "label.ldap.configuration": "LDAP configuration",
- "label.ldap.group.name": "LDAP group",
+ "label.ldap.configuration": "LDAP Configuration",
+ "label.ldap.group.name": "LDAP Group",
  "label.level": "Level",
  "label.license.agreements": "License agreements",
  "label.limit": "Limit",
@@@ -1427,13 -1384,12 +1425,12 @@@
  "label.managed.volumes": "Managed Volumes",
  "label.managedstate": "Managed state",
  "label.management": "Management",
--"label.managementserverid": "Management server",
--"label.managementservername": "Management server",
  "label.management.ips": "Management IP addresses",
- "label.management.server": "Management server",
- "label.management.servers": "Management servers",
+ "label.management.server": "Management Server",
+ "label.management.servers": "Management Servers",
  "label.management.server.peers": "Peers",
++"label.managementserverid": "Management server",
 +"label.managementservername": "Management Server",
  "label.managementservers": "Number of management servers",
  "label.matchall": "Match all",
  "label.max": "Max.",
@@@ -1456,9 -1408,8 +1453,9 @@@
  "label.maxmembers": "Max members",
  "label.maxmemory": "Max. memory (MiB)",
  "label.maxnetwork": "Max. Networks",
 +"label.maxobjectstorage": "Max. Object Storage (GiB)",
  "label.maxprimarystorage": "Max. primary storage (GiB)",
- "label.maxproject": "Max. projects",
+ "label.maxproject": "Max. Projects",
  "label.maxpublicip": "Max. public IPs",
  "label.maxsecondarystorage": "Max. secondary storage (GiB)",
  "label.maxsize": "Maximum size",
@@@ -1753,9 -1688,8 +1750,9 @@@
  "label.peerstate": "Peer State",
  "label.peerstate.lastupdated": "Peer State Updated Time",
  "label.pending.jobs": "Pending Jobs",
 +"label.pendingjobscount": "Number Of pending jobs",
  "label.per.account": "Per Account",
- "label.per.zone": "Per zone",
+ "label.per.zone": "Per Zone",
  "label.percentage": "Percentage",
  "label.perfectforwardsecrecy": "Perfect forward secrecy",
  "label.perform.fresh.checks": "Perform fresh checks",
@@@ -1934,7 -1863,7 +1931,8 @@@
  "label.register.oauth": "Register OAuth",
  "label.register.template": "Register Template",
  "label.register.user.data": "Register User Data",
 +"label.register.cni.config": "Register CNI Configuration",
+ "label.register.user.data.details": "Enter the User Data in plain text or in 
Base64 encoding. Up to 32KB of Base64 encoded User Data can be sent by default. 
The setting vm.userdata.max.length can be used to increase the limit to upto 
1MB.",
  "label.reinstall.vm": "Reinstall Instance",
  "label.reject": "Reject",
  "label.related": "Related",
@@@ -1960,9 -1888,8 +1958,9 @@@
  "label.remove.ldap": "Remove LDAP",
  "label.remove.logical.network": "Remove Network from logical router",
  "label.remove.logical.router": "Remove logical router",
- "label.remove.network.offering": "Remove Network offering",
+ "label.remove.network.offering": "Remove Network Offering",
  "label.remove.network.route.table": "Remove Tungsten Fabric Network routing 
table",
 +"label.remove.nodes": "Remove nodes from Kubernetes cluster",
  "label.remove.pf": "Remove port forwarding rule",
  "label.remove.policy": "Remove policy",
  "label.remove.project.account": "Remove Account from project",
@@@ -2130,20 -2054,16 +2127,19 @@@
  "label.sequence": "Sequence",
  "label.server": "Server",
  "label.server.certificate": "Server certificate",
- "label.serviceip": "Service IP",
  "label.service.connectivity.distributedroutercapabilitycheckbox": 
"Distributed router",
  "label.service.connectivity.regionlevelvpccapabilitycheckbox": "Region level 
VPC",
- "label.service.group": "Service group",
- "label.serviceip": "Management IP",
+ "label.service.group": "Service Group",
 -"label.serviceip": "Management IP",
++"label.serviceip": "Management Server IP",
  "label.service.lb.elasticlbcheckbox": "Elastic LB",
  "label.service.lb.inlinemodedropdown": "Mode",
  "label.service.lb.lbisolationdropdown": "LB isolation",
  "label.service.lb.netscaler.servicepackages": "Netscaler service packages",
  "label.service.lb.netscaler.servicepackages.description": "Service package 
description",
- "label.service.offering": "Service offering",
+ "label.service.offering": "Service Offering",
 +"label.service.offering.controlnodes": "Compute offering for Control Nodes",
 +"label.service.offering.etcdnodes": "Compute offering for etcd Nodes",
 +"label.service.offering.workernodes": "Compute offering for Worker Nodes",
  "label.service.staticnat.associatepublicip": "Associate public IP",
  "label.service.staticnat.elasticipcheckbox": "Elastic IP",
  "label.servicegroupuuid": "Service Group",
@@@ -2219,24 -2138,21 +2215,25 @@@
  "label.srctaguuid": "Source Tag",
  "label.srx": "SRX",
  "label.srx.firewall": "Juniper SRX firewall",
- "label.ssh.key.pairs": "SSH key pairs",
+ "label.ssh.key.pairs": "SSH Key Pairs",
 +"label.storageaccessgroups": "Storage Access Groups",
 +"label.clusterstorageaccessgroups": "Cluster Storage Access Groups",
 +"label.podstorageaccessgroups": "Pod Storage Access Groups",
 +"label.zonestorageaccessgroups": "Zone Storage Access Groups",
  "label.uefi.supported": "UEFI supported",
  "label.usediops": "IOPS used",
- "label.userdataid": "Userdata ID",
- "label.userdataname": "Userdata name",
- "label.userdatadetails": "Userdata details",
- "label.userdataparams": "Userdata parameters",
- "label.userdatapolicy": "Userdata link policy",
- "label.userdata.text": "Manual Userdata entry",
- "label.userdata.registered": "Stored Userdata",
- "label.userdata.do.override": "Userdata override",
- "label.userdata.do.append": "Userdata append",
- "label.userdatapolicy.tooltip": "Userdata linked to the Template can be 
overridden by Userdata provided during Instance deploy. Select the override 
policy as required.",
+ "label.user.data.id": "User Data ID",
+ "label.user.data.name": "User Data name",
+ "label.user.data.details": "User Data details",
+ "label.user.data.params": "User Data parameters",
+ "label.user.data.policy": "User Data link policy",
+ "label.user.data.text": "Manual User Data entry",
+ "label.user.data.registered": "Stored User Data",
+ "label.user.data.do.override": "User Data override",
+ "label.user.data.do.append": "User Data append",
+ "label.user.data.policy.tooltip": "User Data linked to the Template can be 
overridden by User Data provided during Instance deploy. Select the override 
policy as required.",
  "label.user.data": "User Data",
+ "label.user.data.library": "User Data Library",
  "label.ssh.port": "SSH port",
  "label.sshkeypair": "New SSH key pair",
  "label.sshkeypairs": "SSH key pairs",
@@@ -2518,14 -2433,12 +2517,12 @@@
  "label.usagetypedescription": "Usage description",
  "label.use.kubectl.access.cluster": "<code><b>kubectl</b></code> and 
<code><b>kubeconfig</b></code> file to access cluster",
  "label.use.local.timezone": "Use local timezone",
 +"label.use.router.ip.resolver": "Use Virtual Router IP as resolver",
  "label.used": "Used",
  "label.usehttps": "Use HTTPS",
- "label.usenewdiskoffering": "Replace disk offering?",
+ "label.usenewdiskoffering": "Replace Disk Offering?",
  "label.user": "User",
  "label.user.conflict": "Conflict",
- "label.userdata": "Userdata",
- "label.userdatal2": "User data",
 -"label.user.data": "User Data",
  "label.username": "Username",
  "label.username.tooltip": "The Username for the Host",
  "label.users": "Users",
@@@ -2629,10 -2542,8 +2626,10 @@@
  "label.vnf.templates": "VNF templates",
  "label.vnf.template.register": "Register VNF template",
  "label.vnmc": "VNMC",
- "label.volgroup": "Volume group",
+ "label.volgroup": "Volume Group",
  "label.volume": "Volume",
 +"label.vms.empty": "No VMs available to be added to the Kubernetes cluster",
 +"label.vms.remove.empty": "No external VMs present in the Kubernetes cluster 
to be removed",
  "label.volume.empty": "No data volumes attached to this Instance",
  "label.volume.encryption.support": "Volume Encryption Supported",
  "label.volume.metrics": "Volume Metrics",
@@@ -2650,10 -2561,9 +2647,10 @@@
  "label.volumetype": "Volume Type",
  "label.vpc": "VPC",
  "label.vpcs": "VPCs",
 +"label.vpc.gateway.ip": "VPC Gateway IP",
  "label.vpc.id": "VPC ID",
- "label.vpc.offerings": "VPC offerings",
- "label.vpc.virtual.router": "VPC virtual router",
+ "label.vpc.offerings": "VPC Offerings",
+ "label.vpc.virtual.router": "VPC Virtual Router",
  "label.vpc.restart.required": "VPC restart required",
  "label.vpcid": "VPC",
  "label.vpclimit": "VPC limits",
@@@ -2721,9 -2631,9 +2718,10 @@@
  "label.oobm.username": "Out-of-band management username",
  "label.bucket.update": "Update Bucket",
  "label.bucket.delete": "Delete Bucket",
 -"label.quotagb": "Quota in GB",
 +"label.quotagib": "Quota in GiB",
+ "label.edgecluster": "Edge Cluster",
  "label.encryption": "Encryption",
 +"label.etcdnodes": "Number of etcd nodes",
  "label.versioning": "Versioning",
  "label.objectlocking": "Object Lock",
  "label.bucket.policy": "Bucket Policy",
@@@ -2875,11 -2772,10 +2873,11 @@@
  "message.remove.ip.v6.firewall.rule.failed": "Failed to remove IPv6 firewall 
rule",
  "message.remove.ip.v6.firewall.rule.processing": "Removing IPv6 firewall 
rule...",
  "message.remove.ip.v6.firewall.rule.success": "Removed IPv6 firewall rule",
 +"message.add.netris.controller": "Add Netris Provider",
  "message.add.nsx.controller": "Add NSX Provider",
- "message.add.network": "Add a new network for zone: <b><span 
id=\"zone_name\"></span></b>",
- "message.add.network.acl.failed": "Adding network ACL list failed.",
- "message.add.network.acl.processing": "Adding network ACL list...",
+ "message.add.network": "Add a new network for Zone: <b><span 
id=\"zone_name\"></span></b>",
+ "message.add.network.acl.failed": "Adding network ACL failed.",
+ "message.add.network.acl.processing": "Adding network ACL...",
  "message.add.network.failed": "Adding network failed.",
  "message.add.network.processing": "Adding network...",
  "message.add.new.gateway.to.vpc": "Please specify the information to add a 
new gateway to this VPC.",
@@@ -3119,17 -3009,15 +3117,17 @@@
  "message.desc.import.shared.kvm.wizard": "Import QCOW2 image from selected 
Primary Storage Pool",
  "message.desc.import.unmanage.volume": "Please choose a storage pool that you 
want to import or unmanage volumes. The storage pool should be in Up status. 
<br>This feature only supports KVM.",
  "message.desc.importexportinstancewizard": "By choosing to manage an 
Instance, CloudStack takes over the orchestration of that Instance. Unmanaging 
an Instance removes CloudStack ability to manage it. In both cases, the 
Instance is left running and no changes are done to the VM on the 
hypervisor.<br><br>For KVM, managing a VM is an experimental feature.",
- "message.desc.importmigratefromvmwarewizard": "By selecting an existing or 
external VMware Datacenter and an instance to import, CloudStack migrates the 
selected instance from VMware to KVM on a conversion host using virt-v2v and 
imports it into a KVM cluster",
- "message.desc.primary.storage": "Each cluster must contain one or more 
primary storage servers. We will add the first one now. Primary storage 
contains the disk volumes for all the Instances running on hosts in the 
cluster. Use any standards-compliant protocol that is supported by the 
underlying hypervisor.",
+ "message.desc.importmigratefromvmwarewizard": "By selecting an existing or 
external VMware Datacenter and an instance to import, CloudStack migrates the 
selected instance from VMware to KVM on a conversion host using virt-v2v and 
imports it into a KVM Cluster",
+ "message.desc.primary.storage": "Each Cluster must contain one or more 
primary storage servers. We will add the first one now. Primary storage 
contains the disk volumes for all the Instances running on hosts in the 
cluster. Use any standards-compliant protocol that is supported by the 
underlying hypervisor.",
 +"message.desc.register.template": "Hosted on download.cloudstack.org, these 
templates can be easily registered directly within CloudStack. Simply click 
<strong>Register Template</strong> for the templates you wish to use.",
  "message.desc.reset.ssh.key.pair": "Please specify a ssh key pair that you 
would like to add to this Instance.",
- "message.desc.secondary.storage": "Each zone must have at least one NFS or 
secondary storage server. We will add the first one now. Secondary storage 
stores Instance Templates, ISO images, and Instance disk volume Snapshots. This 
server must be available to all hosts in the zone.<br/><br/>Provide the IP 
address and exported path.",
- "message.desc.register.user.data": "Please fill in the following data to 
register a User data.",
+ "message.desc.secondary.storage": "Each Zone must have at least one NFS or 
secondary storage server. We will add the first one now. Secondary storage 
stores Instance Templates, ISO images, and Instance disk volume Snapshots. This 
server must be available to all hosts in the zone.<br/><br/>Provide the IP 
address and exported path.",
+ "message.desc.register.user.data": "Please fill in the following to register 
new User Data.",
 +"message.desc.register.cni.config": "Please fill in the following data to 
register CNI Configuration as user data.",
  "message.desc.registered.user.data": "Registered a User Data.",
- "message.desc.zone": "A zone is the largest organizational unit in 
CloudStack, and it typically corresponds to a single datacenter. Zones provide 
physical isolation and redundancy. A zone consists of one or more pods (each of 
which contains hosts and primary storage servers) and a secondary storage 
server which is shared by all pods in the zone.",
- "message.desc.zone.edge": "A zone is the largest organizational unit in 
CloudStack, and it typically corresponds to a single datacenter. Zones provide 
physical isolation and redundancy. An edge zone consists of one or more hosts 
(each of which provides local storage as primary storage servers). Only shared 
and L2 Networks can be deployed in such zones and functionalities that require 
secondary storages are not supported.",
- "message.drs.plan.description": "The maximum number of live migrations 
allowed for DRS. Configure DRS under the settings tab before generating a plan 
or to enable automatic DRS for the cluster.",
+ "message.desc.zone": "A Zone is the largest organizational unit in 
CloudStack, and it typically corresponds to a single datacenter. Zones provide 
physical isolation and redundancy. A zone consists of one or more Pods (each of 
which contains hosts and primary storage servers) and a secondary storage 
server which is shared by all pods in the zone.",
+ "message.desc.zone.edge": "A Zone is the largest organizational unit in 
CloudStack, and it typically corresponds to a single datacenter. Zones provide 
physical isolation and redundancy. An edge zone consists of one or more hosts 
(each of which provides local storage as primary storage servers). Only shared 
and L2 Networks can be deployed in such zones and functionalities that require 
secondary storages are not supported.",
+ "message.drs.plan.description": "The maximum number of live migrations 
allowed for DRS. Configure DRS under the settings tab before generating a plan 
or to enable automatic DRS for the Cluster.",
  "message.drs.plan.executed": "DRS plan executed successfully.",
  "message.zone.edge.local.storage": "Local storage will be used by default for 
User Instances and virtual routers",
  "message.detach.disk": "Are you sure you want to detach this disk?",
@@@ -3344,9 -3232,8 +3342,9 @@@
  "message.import.volume": "Please specify the domain, account or project name. 
<br>If not set, the volume will be imported for the caller.",
  "message.info.cloudian.console": "Cloudian Management Console should open in 
another window.",
  "message.installwizard.cloudstack.helptext.website": " * Project website:\t ",
 +"message.infra.setup.netris.description": "This zone must contain a Netris 
provider because the isolation method is Netris",
- "message.infra.setup.nsx.description": "This zone must contain an NSX 
provider because the isolation method is NSX",
- "message.infra.setup.tungsten.description": "This zone must contain a 
Tungsten-Fabric provider because the isolation method is TF",
+ "message.infra.setup.nsx.description": "This Zone must contain an NSX 
provider because the isolation method is NSX",
+ "message.infra.setup.tungsten.description": "This Zone must contain a 
Tungsten-Fabric provider because the isolation method is TF",
  "message.installwizard.cloudstack.helptext.document": " * Documentation:\t ",
  "message.installwizard.cloudstack.helptext.header": "\nYou can find more 
information about Apache CloudStack™ on the pages listed below.\n",
  "message.installwizard.cloudstack.helptext.issues": " * Report issues:\t ",
@@@ -3354,21 -3241,14 +3352,21 @@@
  "message.installwizard.cloudstack.helptext.releasenotes": " * Release 
notes:\t ",
  "message.installwizard.cloudstack.helptext.survey": " * Take the survey:\t ",
  "message.installwizard.copy.whatiscloudstack": "CloudStack™ is a software 
platform that pools computing resources to build public, private, and hybrid 
Infrastructure as a Service (IaaS) clouds. CloudStack™ manages the Network, 
storage, and compute nodes that make up a cloud infrastructure. Use CloudStack™ 
to deploy, manage, and configure cloud computing environments.\n\nExtending 
beyond individual Instance images running on commodity hardware, CloudStack™ 
provides a turnkey cloud infras [...]
- "message.installwizard.tooltip.addpod.name": "A name for the pod.",
+ "message.installwizard.tooltip.addpod.name": "A name for the Pod.",
  "message.installwizard.tooltip.addpod.reservedsystemendip": "This is the IP 
range in the private Network that the CloudStack uses to manage Secondary 
Storage VMs and Console Proxy VMs. These IP addresses are taken from the same 
subnet as computing servers.",
- "message.installwizard.tooltip.addpod.reservedsystemgateway": "The gateway 
for the hosts in that pod.",
+ "message.installwizard.tooltip.addpod.reservedsystemgateway": "The gateway 
for the hosts in that Pod.",
  "message.installwizard.tooltip.addpod.reservedsystemstartip": "This is the IP 
range in the private Network that the CloudStack uses to manage Secondary 
Storage VMs and Console Proxy VMs. These IP addresses are taken from the same 
subnet as computing servers.",
- "message.installwizard.tooltip.configureguesttraffic.guestendip": "The range 
of IP addresses that will be available for allocation to guests in this zone. 
If one NIC is used, these IPs should be in the same CIDR as the pod CIDR.",
+ "message.installwizard.tooltip.configureguesttraffic.guestendip": "The range 
of IP addresses that will be available for allocation to guests in this Zone. 
If one NIC is used, these IPs should be in the same CIDR as the Pod CIDR.",
  "message.installwizard.tooltip.configureguesttraffic.guestgateway": "The 
gateway that the guests should use.",
  "message.installwizard.tooltip.configureguesttraffic.guestnetmask": "The 
netmask in use on the subnet that the guests should use.",
- "message.installwizard.tooltip.configureguesttraffic.gueststartip": "The 
range of IP addresses that will be available for allocation to guests in this 
zone. If one NIC is used, these IPs should be in the same CIDR as the pod 
CIDR.",
+ "message.installwizard.tooltip.configureguesttraffic.gueststartip": "The 
range of IP addresses that will be available for allocation to guests in this 
Zone. If one NIC is used, these IPs should be in the same CIDR as the Pod 
CIDR.",
 +"message.installwizard.tooltip.netris.provider.name": "Netris Provider name 
is required",
 +"message.installwizard.tooltip.netris.provider.url": "Netris Provider URL not 
provided",
 +"message.installwizard.tooltip.netris.provider.username": "Netris Provider 
username not provided",
 +"message.installwizard.tooltip.netris.provider.password": "Netris Provider 
password not provided",
 +"message.installwizard.tooltip.netris.provider.site": "Netris Provider Site 
name not provided",
 +"message.installwizard.tooltip.netris.provider.tag": "Netris Tag to be 
assigned to vNets",
 +"message.installwizard.tooltip.netris.provider.tenant.name": "Netris Provider 
Admin Tenant name not provided",
  "message.installwizard.tooltip.nsx.provider.hostname": "NSX Provider hostname 
/ IP address not provided",
  "message.installwizard.tooltip.nsx.provider.username": "NSX Provider username 
not provided",
  "message.installwizard.tooltip.nsx.provider.password": "NSX Provider password 
not provided",
@@@ -3391,16 -3270,14 +3389,16 @@@
  "message.ip.v6.prefix.delete": "IPv6 prefix deleted",
  "message.iso.arch": "Please select an ISO architecture",
  "message.iso.desc": "Disc image containing data or bootable media for OS.",
- "message.kubeconfig.cluster.not.available": "Kubernetes cluster kubeconfig 
not available currently.",
+ "message.kubeconfig.cluster.not.available": "Kubernetes Cluster kubeconfig 
not available currently.",
 +"message.kubernetes.cluster.add.nodes": "Please confirm that you want to add 
the following nodes to the cluster",
- "message.kubernetes.cluster.delete": "Please confirm that you want to destroy 
the cluster.",
- "message.kubernetes.cluster.scale": "Please select desired cluster 
configuration.",
- "message.kubernetes.cluster.start": "Please confirm that you want to start 
the cluster.",
- "message.kubernetes.cluster.stop": "Please confirm that you want to stop the 
cluster.",
+ "message.kubernetes.cluster.delete": "Please confirm that you want to destroy 
the Cluster.",
+ "message.kubernetes.cluster.scale": "Please select desired Cluster 
configuration.",
+ "message.kubernetes.cluster.start": "Please confirm that you want to start 
the Cluster.",
+ "message.kubernetes.cluster.stop": "Please confirm that you want to stop the 
Cluster.",
 +"message.kubernetes.cluster.remove.nodes": "Please confirm that you want to 
remove the following nodes from the cluster",
  "message.kubernetes.cluster.upgrade": "Please select new Kubernetes version.",
  "message.kubernetes.version.delete": "Please confirm that you want to delete 
this Kubernetes version.",
- "message.l2.network.unsupported.for.nsx": "L2 networks aren't supported for 
NSX enabled zones",
+ "message.l2.network.unsupported.for.nsx": "L2 networks aren't supported for 
NSX enabled Zones",
  "message.launch.zone": "Zone is ready to launch; please proceed to the next 
step.",
  "message.launch.zone.description": "Zone is ready to launch; please proceed 
to the next step.",
  "message.launch.zone.hint": "Configure Network components and traffic 
including IP addresses.",
@@@ -3475,17 -3352,15 +3473,17 @@@
  "message.password.reset.success": "Password has been reset successfully. 
Please login using your new credentials.",
  "message.path": "Path : ",
  "message.path.description": "NFS: exported path from the server. VMFS: 
/datacenter name/datastore name. SharedMountPoint: path where primary storage 
is mounted, such as /mnt/primary.",
 +"message.please.confirm.remove.cni.configuration": "Please confirm that you 
want to remove this CNI Configuration",
  "message.please.confirm.remove.ssh.key.pair": "Please confirm that you want 
to remove this SSH key pair.",
- "message.please.confirm.remove.user.data": "Please confirm that you want to 
remove this Userdata",
+ "message.please.confirm.remove.user.data": "Please confirm that you want to 
remove this User Data",
  "message.please.enter.valid.value": "Please enter a valid value.",
  "message.please.enter.value": "Please enter values.",
  "message.please.wait.while.autoscale.vmgroup.is.being.created": "Please wait 
while your AutoScaling Group is being created; this may take a while...",
- "message.please.wait.while.zone.is.being.created": "Please wait while your 
zone is being created; this may take a while...",
+ "message.please.wait.while.zone.is.being.created": "Please wait while your 
Zone is being created; this may take a while...",
  "message.pod.dedicated": "Pod dedicated.",
  "message.pod.dedication.released": "Pod dedication released.",
 -"message.prepare.for.shutdown": "Please confirm that you would like to prep 
this Management server for shutdown. It will not accept any new Async Jobs but 
will NOT terminate after there are no pending jobs.",
 +"message.prepare.for.shutdown": "Please confirm that you would like to 
prepare this Management Server for shutdown. It will not accept any new Async 
Jobs but will NOT terminate after there are no pending jobs.",
 +"message.prepare.for.maintenance": "Please confirm that you would like to 
prepare this Management Server for maintenance. It will not accept any new 
Async Jobs.",
  "message.primary.storage.invalid.state": "Primary storage is not in Up state",
  "message.processing.complete": "Processing complete!",
  "message.protocol.description": "For XenServer, choose NFS, iSCSI, or 
PreSetup. For KVM, choose NFS, SharedMountPoint, RDB, CLVM or Gluster. For 
vSphere, choose NFS, PreSetup (VMFS or iSCSI or FiberChannel or vSAN or vVols) 
or DatastoreCluster. For Hyper-V, choose SMB/CIFS. For LXC, choose NFS or 
SharedMountPoint. For OVM, choose NFS or OCFS2.",
@@@ -3571,13 -3446,12 +3569,13 @@@
  "message.set.default.nic.manual": "Please manually update the default NIC on 
the Instance now.",
  "message.setting.updated": "Setting Updated:",
  "message.setting.update.delay": "The new value will take effect within 30 
seconds.",
- "message.setup.physical.network.during.zone.creation": "When adding a zone, 
you need to set up one or more physical networks. Each physical network can 
carry one or more types of traffic, with certain restrictions on how they may 
be combined. Add or remove one or more traffic types onto each physical 
network.",
- "message.setup.physical.network.during.zone.creation.basic": "When adding a 
basic zone, you can set up one physical Network, which corresponds to a NIC on 
the hypervisor. The Network carries several types of traffic.<br/><br/>You may 
also <strong>add</strong> other traffic types onto the physical Network.",
+ "message.setup.physical.network.during.zone.creation": "When adding a Zone, 
you need to set up one or more physical networks. Each physical network can 
carry one or more types of traffic, with certain restrictions on how they may 
be combined. Add or remove one or more traffic types onto each physical 
network.",
+ "message.setup.physical.network.during.zone.creation.basic": "When adding a 
basic Zone, you can set up one physical Network, which corresponds to a NIC on 
the hypervisor. The Network carries several types of traffic.<br/><br/>You may 
also <strong>add</strong> other traffic types onto the physical Network.",
  "message.shared.network.offering.warning": "Domain admins and regular Users 
can only create shared Networks from Network offering with the setting 
specifyvlan=false. Please contact an administrator to create a Network offering 
if this list is empty.",
- "message.shared.network.unsupported.for.nsx": "Shared networks aren't 
supported for NSX enabled zones",
- "message.shutdown.triggered": "Shutdown has been triggered. This Management 
Server will not accept new jobs",
+ "message.shared.network.unsupported.for.nsx": "Shared networks aren't 
supported for NSX enabled Zones",
+ "message.shutdown.triggered": "A shutdown has been triggered. CloudStack will 
not accept new jobs",
 +"message.maintenance.initiated": "Maintenance has been initiated. This 
Management Server will not accept new jobs",
- "message.snapshot.additional.zones": "Snapshots will always be created in its 
native zone - %x, here you can select additional zone(s) where it will be 
copied to at creation time",
+ "message.snapshot.additional.zones": "Snapshots will always be created in its 
native Zone - %x, here you can select additional zone(s) where it will be 
copied to at creation time",
  "message.sourcenatip.change.warning": "WARNING: Changing the sourcenat IP 
address of the network will cause connectivity downtime for the Instances with 
NICs in the Network.",
  "message.sourcenatip.change.inhibited": "Changing the sourcenat to this IP of 
the Network to this address is inhibited as firewall rules are defined for it. 
This can include port forwarding or load balancing rules.\n - If this is an 
Isolated Network, please use updateNetwork/click the edit button.\n - If this 
is a VPC, first clear all other rules for this address.",
  "message.specify.tag.key": "Please specify a tag key.",
@@@ -3599,11 -3473,9 +3597,11 @@@
  "message.success.add.kuberversion": "Successfully added Kubernetes version",
  "message.success.add.logical.router": "Successfully added Logical Router",
  "message.success.add.network": "Successfully added Network",
- "message.success.add.network.acl": "Successfully added Network ACL list",
+ "message.success.add.network.acl": "Successfully added Network ACL",
  "message.success.add.network.static.route": "Successfully added Network 
Static Route",
  "message.success.add.network.permissions": "Successfully added Network 
permissions",
 +"message.success.add.nodes.to.cluster": "Successfully added nodes to 
Kubernetes cluster",
 +"message.success.remove.nodes.from.cluster": "Successfully removed nodes from 
Kubernetes cluster",
  "message.success.add.physical.network": "Successfully added Physical Network",
  "message.success.add.object.storage": "Successfully added Object Storage",
  "message.success.add.policy.rule": "Successfully added Policy rule",
@@@ -3842,12 -3713,11 +3840,12 @@@
  "message.warn.change.primary.storage.scope": "This feature is tested and 
supported for the following configurations:<br>KVM - NFS/Ceph - 
DefaultPrimary<br>VMware - NFS - DefaultPrimary<br>*There might be extra steps 
involved to make it work for other configurations.",
  "message.warn.filetype": "jpg, jpeg, png, bmp and svg are the only supported 
image formats.",
  "message.warn.importing.instance.without.nic": "WARNING: This Instance is 
being imported without NICs and many Network resources will not be available. 
Consider creating a NIC via vCenter before importing or as soon as the Instance 
is imported.",
 +"message.warn.select.template": "Please select a Template for Registration.",
- "message.warn.zone.mtu.update": "Please note that this limit won't affect 
pre-existing Network’s MTU settings",
+ "message.warn.zone.mtu.update": "Please note that this limit won't affect 
pre-existing Network's MTU settings",
  "message.webhook.deliveries.time.filter": "Webhook deliveries list can be 
filtered based on date-time. Select 'Custom' for specifying start and end date 
range.",
  "message.zone.creation.complete": "Zone creation complete.",
- "message.zone.detail.description": "Populate zone details.",
- "message.zone.detail.hint": "A zone is the largest organizational unit in 
CloudStack, and it typically corresponds to a single datacenter. Zones provide 
physical isolation and redundancy. A zone consists of one or more pods (each of 
which contains hosts and primary storage servers) and a secondary storage 
server which is shared by all pods in the zone.",
+ "message.zone.detail.description": "Populate Zone details.",
+ "message.zone.detail.hint": "A Zone is the largest organizational unit in 
CloudStack, and it typically corresponds to a single datacenter. Zones provide 
physical isolation and redundancy. A zone consists of one or more Pods (each of 
which contains hosts and primary storage servers) and a secondary storage 
server which is shared by all pods in the zone.",
  "message.validate.min": "Please enter a value greater than or equal to {0}.",
  "message.action.delete.object.storage": "Please confirm that you want to 
delete this Object Store",
  "message.bgp.peers.null": "Please note, if no BGP peers are selected, the VR 
will connect to <br> (1) dedicated BGP peers the owner can access, if the owner 
has dedicated BGP peers and account setting use.system.bgp.peers is set to 
false; <br> (2) all BGP peers the owner can access, otherwise.<br>",
diff --cc ui/src/components/view/InfoCard.vue
index c5e771de5a6,f1efcaef281..7ec91621a70
--- a/ui/src/components/view/InfoCard.vue
+++ b/ui/src/components/view/InfoCard.vue
@@@ -31,11 -31,14 +31,14 @@@
                      <edit-outlined class="upload-icon"/>
                    </div>
                    <slot name="avatar">
 -                    <span v-if="(resource.icon && resource.icon.base64image 
|| images.template || images.iso || resourceIcon) && !['router', 'systemvm', 
'volume'].includes($route.path.split('/')[1])">
 -                      <resource-icon :image="getImage(resource.icon && 
resource.icon.base64image || images.template || images.iso || resourceIcon)" 
size="4x" style="margin-right: 5px"/>
 +                    <span v-if="resourceIcon && !['router', 'systemvm', 
'volume'].includes($route.path.split('/')[1])">
 +                      <resource-icon :image="resourceIcon" size="4x" 
style="margin-right: 5px"/>
                      </span>
+                     <span v-else-if="resource.vmtype === 'sharedfsvm'">
+                       <file-text-outlined style="font-size: 36px;" />
+                     </span>
                      <span v-else>
 -                      <os-logo v-if="resource.ostypeid || resource.ostypename 
|| ['guestoscategory'].includes($route.path.split('/')[1])" 
:osId="resource.ostypeid" :osName="resource.ostypename || resource.name" 
size="3x" @update-osname="setResourceOsType"/>
 +                      <os-logo v-if="resource.ostypeid || resource.ostypename 
|| ['guestoscategory'].includes($route.path.split('/')[1])" 
:osId="resource.ostypeid" :osName="resource.ostypename || 
resource.osdisplayname || resource.name" size="3x" />
                        <render-icon v-else-if="typeof $route.meta.icon 
==='string'" style="font-size: 36px" :icon="$route.meta.icon" />
                        <font-awesome-icon
                          v-else-if="$route.meta.icon && 
Array.isArray($route.meta.icon)"
@@@ -912,7 -891,7 +927,8 @@@ import UploadResourceIcon from '@/compo
  import eventBus from '@/config/eventBus'
  import ResourceIcon from '@/components/view/ResourceIcon'
  import ResourceLabel from '@/components/widgets/ResourceLabel'
 +import ImageDeployInstanceButton from 
'@/components/view/ImageDeployInstanceButton'
+ import { FileTextOutlined } from '@ant-design/icons-vue'
  
  export default {
    name: 'InfoCard',
@@@ -925,7 -904,7 +941,8 @@@
      UploadResourceIcon,
      ResourceIcon,
      ResourceLabel,
 +    ImageDeployInstanceButton
+     FileTextOutlined
    },
    props: {
      resource: {
diff --cc ui/src/views/compute/DeployVM.vue
index ac98f35d806,a604fe68fe4..7cdb5b52b9e
--- a/ui/src/views/compute/DeployVM.vue
+++ b/ui/src/views/compute/DeployVM.vue
@@@ -583,44 -603,16 +583,44 @@@
                            @change="val => { dynamicscalingenabled = val }"/>
                        </a-form-item>
                      </a-form-item>
 +                    <a-form-item name="showLeaseOptions" 
ref="showLeaseOptions" v-if="isLeaseFeatureEnabled">
 +                      <template #label>
 +                        <tooltip-label :title="$t('label.lease.enable')" 
:tooltip="$t('label.lease.enable.tooltip')"/>
 +                      </template>
 +                      <a-switch v-model:checked="showLeaseOptions" 
@change="onToggleLeaseData"/>
 +                    </a-form-item>
 +                    <a-row :gutter="12" v-if="isLeaseFeatureEnabled && 
showLeaseOptions">
 +                      <a-col :md="12" :lg="12">
 +                        <a-form-item name="leaseduration" ref="leaseduration">
 +                          <template #label>
 +                            <tooltip-label :title="$t('label.leaseduration')" 
/>
 +                          </template>
 +                          <a-input
 +                            v-model:value="form.leaseduration"
 +                            
:placeholder="$t('label.instance.lease.placeholder')"/>
 +                        </a-form-item>
 +                      </a-col>
 +                      <a-col :md="12" :lg="12">
 +                        <a-form-item name="leaseexpiryaction" 
ref="leaseexpiryaction">
 +                          <template #label>
 +                            <tooltip-label 
:title="$t('label.leaseexpiryaction')"  />
 +                          </template>
 +                          <a-select v-model:value="form.leaseexpiryaction" 
:defaultValue="leaseexpiryaction">
 +                            <a-select-option v-for="action in expiryActions" 
:key="action" :label="action" />
 +                          </a-select>
 +                        </a-form-item>
 +                      </a-col>
 +                    </a-row>
-                     <a-form-item :label="$t('label.userdata')">
+                     <a-form-item :label="$t('label.user.data')">
                        <a-card>
                          <div v-if="this.template && this.template.userdataid">
 -                          <a-text type="primary">
 -                              Userdata "{{ $t(this.template.userdataname) }}" 
is linked with template "{{ $t(this.template.name) }}" with override policy "{{ 
$t(this.template.userdatapolicy) }}"
 -                          </a-text><br/><br/>
 +                          <a-typography-text>
 +                            Userdata "{{ $t(this.template.userdataname) }}" 
is linked with template "{{ $t(this.template.name) }}" with override policy "{{ 
$t(this.template.userdatapolicy) }}"
 +                          </a-typography-text><br/><br/>
                            <div v-if="templateUserDataParams.length > 0 && 
!doUserdataOverride">
 -                            <a-text type="primary" v-if="this.template && 
this.template.userdataid && templateUserDataParams.length > 0">
 -                                Enter the values for the variables in userdata
 -                            </a-text>
 +                            <a-typography-text v-if="this.template && 
this.template.userdataid && templateUserDataParams.length > 0">
 +                              Enter the values for the variables in userdata
 +                            </a-typography-text>
                              <a-input-group>
                                <a-table
                                  size="small"
@@@ -2496,68 -2349,66 +2495,77 @@@ export default 
        })
      },
      fetchOptions (param, name, exclude) {
 -      if (exclude && exclude.length > 0) {
 -        if (exclude.includes(name)) {
 -          return
 +      return new Promise((resolve, reject) => {
 +        if (exclude && exclude.length > 0 && exclude.includes(name)) {
 +          return resolve(null)
          }
-         this.loading[name] = true
-         param.loading = true
-         param.opts = []
-         const options = param.options || {}
-         if (!('listall' in options) && !['zones', 'pods', 'clusters', 
'hosts', 'dynamicScalingVmConfig', 'hypervisors'].includes(name)) {
-           options.listall = true
-         }
-         postAPI(param.list, options).then((response) => {
-           param.loading = false
-           _.map(response, (responseItem, responseKey) => {
-             if (Object.keys(responseItem).length === 0) {
-               this.rowCount[name] = 0
-               this.options[name] = []
-               return resolve(null)
+       }
+       this.loading[name] = true
+       param.loading = true
+       param.opts = []
+       const options = param.options || {}
+       if (!('listall' in options) && !['zones', 'pods', 'clusters', 'hosts', 
'hypervisors'].includes(name)) {
+         options.listall = true
+       }
 -      api(param.list, options).then((response) => {
++      postApi(param.list, options).then((response) => {
+         param.loading = false
+         _.map(response, (responseItem, responseKey) => {
+           if (Object.keys(responseItem).length === 0) {
+             this.rowCount[name] = 0
+             this.options[name] = []
+             return
+           }
+           if (!responseKey.includes('response')) {
+             return
+           }
+           _.map(responseItem, (response, key) => {
+             if (key === 'count') {
+               this.rowCount[name] = response
+               return
              }
 -            param.opts = response
 -            this.options[name] = response
 -
 -            if (name === 'hypervisors') {
 -              const hypervisorFromResponse = response[0] && response[0].name 
? response[0].name : null
 -              this.dataPreFill.hypervisor = hypervisorFromResponse
 -              this.form.hypervisor = hypervisorFromResponse
 +            if (!responseKey.includes('response')) {
 +              return resolve(null)
              }
 +            _.map(responseItem, (response, key) => {
 +              if (key === 'count') {
 +                this.rowCount[name] = response
 +                return
 +              }
 +              param.opts = response
 +              this.options[name] = response
  
 -            if (param.field) {
 -              this.fillValue(param.field)
 -            }
 -          })
 +              if (name === 'hypervisors') {
 +                const hypervisorFromResponse = response[0] && 
response[0].name ? response[0].name : null
 +                this.dataPreFill.hypervisor = hypervisorFromResponse
 +                this.form.hypervisor = hypervisorFromResponse
 +              }
  
 -          if (name === 'zones') {
 -            let zoneid = ''
 -            if (this.$route.query.zoneid) {
 -              zoneid = this.$route.query.zoneid
 -            } else if (this.options.zones.length === 1) {
 -              zoneid = this.options.zones[0].id
 -            }
 -            if (zoneid) {
 -              this.form.zoneid = zoneid
 -              this.onSelectZoneId(zoneid)
 +              if (param.field) {
 +                this.fillValue(param.field)
 +              }
 +            })
 +
 +            if (name === 'zones') {
 +              let zoneid = ''
 +              if (this.$route.query.zoneid) {
 +                zoneid = this.$route.query.zoneid
 +              } else if (this.options.zones.length === 1) {
 +                zoneid = this.options.zones[0].id
 +              }
 +              if (zoneid) {
 +                this.form.zoneid = zoneid
 +                this.onSelectZoneId(zoneid)
 +              }
              }
 -          }
 +          })
 +          resolve(response)
 +        }).catch(function (error) {
 +          console.log(error.stack)
 +          param.loading = false
 +          reject(error)
 +        }).finally(() => {
 +          this.loading[name] = false
          })
 -      }).catch(function (error) {
 -        console.log(error.stack)
 -        param.loading = false
 -      }).finally(() => {
 -        this.loading[name] = false
        })
      },
      fetchTemplates (templateFilter, params) {
diff --cc ui/src/views/compute/DeployVnfAppliance.vue
index a5618f5d9d4,1117413d710..19a87ba8664
--- a/ui/src/views/compute/DeployVnfAppliance.vue
+++ b/ui/src/views/compute/DeployVnfAppliance.vue
@@@ -549,16 -564,16 +549,16 @@@
                            @change="val => { dynamicscalingenabled = val }"/>
                        </a-form-item>
                      </a-form-item>
-                     <a-form-item :label="$t('label.userdata')">
+                     <a-form-item :label="$t('label.user.data')">
                        <a-card>
                          <div v-if="this.template && this.template.userdataid">
 -                          <a-text type="primary">
 +                          <a-typography-text>
                                Userdata "{{ $t(this.template.userdataname) }}" 
is linked with template "{{ $t(this.template.name) }}" with override policy "{{ 
$t(this.template.userdatapolicy) }}"
 -                          </a-text><br/><br/>
 +                          </a-typography-text><br/><br/>
                            <div v-if="templateUserDataParams.length > 0 && 
!doUserdataOverride">
 -                            <a-text type="primary" v-if="this.template && 
this.template.userdataid && templateUserDataParams.length > 0">
 +                            <a-typography-text v-if="this.template && 
this.template.userdataid && templateUserDataParams.length > 0">
                                  Enter the values for the variables in userdata
 -                            </a-text>
 +                            </a-typography-text>
                              <a-input-group>
                                <a-table
                                  size="small"
@@@ -1288,18 -1277,20 +1287,19 @@@ export default 
          key: 'templateid',
          tab: this.$t('label.templates')
        }]
 -      return tabList
      },
      userdataTabList () {
-       return [
-         {
-           key: 'userdataregistered',
-           tab: this.$t('label.userdata.registered')
-         },
-         {
-           key: 'userdatatext',
-           tab: this.$t('label.userdata.text')
-         }
-       ]
+       let tabList = []
+       tabList = [{
+         key: 'userdataregistered',
+         tab: this.$t('label.user.data.registered')
+       },
+       {
+         key: 'userdatatext',
+         tab: this.$t('label.user.data.text')
+       }]
+ 
+       return tabList
      },
      showVnfNicsSection () {
        return this.networks && this.networks.length > 0 && this.vm.templateid 
&& this.templateVnfNics && this.templateVnfNics.length > 0
@@@ -2467,68 -2386,66 +2467,77 @@@
        })
      },
      fetchOptions (param, name, exclude) {
 -      if (exclude && exclude.length > 0) {
 -        if (exclude.includes(name)) {
 -          return
 +      return new Promise((resolve, reject) => {
 +        if (exclude && exclude.length > 0 && exclude.includes(name)) {
 +          return resolve(null)
          }
-         this.loading[name] = true
-         param.loading = true
-         param.opts = []
-         const options = param.options || {}
-         if (!('listall' in options) && !['zones', 'pods', 'clusters', 
'hosts', 'dynamicScalingVmConfig', 'hypervisors'].includes(name)) {
-           options.listall = true
-         }
-         postAPI(param.list, options).then((response) => {
-           param.loading = false
-           _.map(response, (responseItem, responseKey) => {
-             if (Object.keys(responseItem).length === 0) {
-               this.rowCount[name] = 0
-               this.options[name] = []
-               return resolve(null)
+       }
+       this.loading[name] = true
+       param.loading = true
+       param.opts = []
+       const options = param.options || {}
+       if (!('listall' in options) && !['zones', 'pods', 'clusters', 'hosts', 
'hypervisors'].includes(name)) {
+         options.listall = true
+       }
 -      api(param.list, options).then((response) => {
++      postApi(param.list, options).then((response) => {
+         param.loading = false
+         _.map(response, (responseItem, responseKey) => {
+           if (Object.keys(responseItem).length === 0) {
+             this.rowCount[name] = 0
+             this.options[name] = []
+             return
+           }
+           if (!responseKey.includes('response')) {
+             return
+           }
+           _.map(responseItem, (response, key) => {
+             if (key === 'count') {
+               this.rowCount[name] = response
+               return
              }
 -            param.opts = response
 -            this.options[name] = response
 -
 -            if (name === 'hypervisors') {
 -              const hypervisorFromResponse = response[0] && response[0].name 
? response[0].name : null
 -              this.dataPreFill.hypervisor = hypervisorFromResponse
 -              this.form.hypervisor = hypervisorFromResponse
 +            if (!responseKey.includes('response')) {
 +              return resolve(null)
              }
 +            _.map(responseItem, (response, key) => {
 +              if (key === 'count') {
 +                this.rowCount[name] = response
 +                return
 +              }
 +              param.opts = response
 +              this.options[name] = response
  
 -            if (param.field) {
 -              this.fillValue(param.field)
 -            }
 -          })
 +              if (name === 'hypervisors') {
 +                const hypervisorFromResponse = response[0] && 
response[0].name ? response[0].name : null
 +                this.dataPreFill.hypervisor = hypervisorFromResponse
 +                this.form.hypervisor = hypervisorFromResponse
 +              }
  
 -          if (name === 'zones') {
 -            let zoneid = ''
 -            if (this.$route.query.zoneid) {
 -              zoneid = this.$route.query.zoneid
 -            } else if (this.options.zones.length === 1) {
 -              zoneid = this.options.zones[0].id
 -            }
 -            if (zoneid) {
 -              this.form.zoneid = zoneid
 -              this.onSelectZoneId(zoneid)
 +              if (param.field) {
 +                this.fillValue(param.field)
 +              }
 +            })
 +
 +            if (name === 'zones') {
 +              let zoneid = ''
 +              if (this.$route.query.zoneid) {
 +                zoneid = this.$route.query.zoneid
 +              } else if (this.options.zones.length === 1) {
 +                zoneid = this.options.zones[0].id
 +              }
 +              if (zoneid) {
 +                this.form.zoneid = zoneid
 +                this.onSelectZoneId(zoneid)
 +              }
              }
 -          }
 +          })
 +          resolve(response)
 +        }).catch(function (error) {
 +          console.log(error.stack)
 +          param.loading = false
 +          reject(error)
 +        }).finally(() => {
 +          this.loading[name] = false
          })
 -      }).catch(function (error) {
 -        console.log(error.stack)
 -        param.loading = false
 -      }).finally(() => {
 -        this.loading[name] = false
        })
      },
      fetchTemplates (templateFilter, params) {
diff --cc ui/src/views/compute/EditVM.vue
index f7b7649b96b,d5e75fcc658..e35ca6dd49d
--- a/ui/src/views/compute/EditVM.vue
+++ b/ui/src/views/compute/EditVM.vue
@@@ -291,19 -247,9 +289,22 @@@ export default 
          this.template = templateResponses[0]
        })
      },
 +    fetchDynamicScalingVmConfig () {
 +      const params = {}
 +      params.name = 'enable.dynamic.scale.vm'
 +      params.zoneid = this.resource.zoneid
 +      var apiName = 'listConfigurations'
 +      getAPI(apiName, params).then(json => {
 +        const configResponse = json.listconfigurationsresponse.configuration
 +        this.dynamicScalingVmConfig = configResponse[0]?.value === 'true'
 +      })
 +    },
 +    canDynamicScalingEnabled () {
 +      return this.template.isdynamicallyscalable && 
this.serviceOffering.dynamicscalingenabled && this.dynamicScalingVmConfig
 +    },
+     isDynamicScalingEnabled () {
+       return this.template.isdynamicallyscalable && 
this.serviceOffering.dynamicscalingenabled && 
this.$store.getters.features.dynamicscalingenabled
+     },
      fetchOsTypes () {
        this.osTypes.loading = true
        this.osTypes.opts = []
diff --cc ui/src/views/compute/RegisterUserData.vue
index 4631ad70e7d,3fb54962f2b..8f7b438576d
--- a/ui/src/views/compute/RegisterUserData.vue
+++ b/ui/src/views/compute/RegisterUserData.vue
@@@ -35,34 -35,20 +35,31 @@@
              :placeholder="apiParams.name.description"
              v-focus="true" />
          </a-form-item>
-         <div v-if="$route.name === 'userdata'">
-           <a-form-item name="userdata" ref="userdata">
-             <template #label>
-               <tooltip-label :title="$t('label.userdata')" 
:tooltip="apiParams.userdata.description"/>
-             </template>
-             <a-textarea
-               v-model:value="form.userdata"
-               :placeholder="apiParams.userdata.description"/>
-           </a-form-item>
-         </div>
-         <div v-else>
-           <a-form-item name="cniconfig" ref="cniconfig">
-             <template #label>
-               <tooltip-label :title="$t('label.cniconfiguration')" 
:tooltip="apiParams.cniconfig.description"/>
-             </template>
-             <a-textarea
-               v-model:value="form.cniconfig"
-               :placeholder="apiParams.cniconfig.description"/>
-           </a-form-item>
-         </div>
+         <a-form-item name="userdata" ref="userdata">
+           <template #label>
+             <tooltip-label :title="$t('label.user.data')" 
:tooltip="$t('label.register.user.data.details')"/>
+           </template>
+           <a-textarea
+             v-model:value="form.userdata"
+             :placeholder="$t('label.register.user.data.details')"/>
+         </a-form-item>
++        <a-form-item name="cniconfig" ref="cniconfig">
++          <template #label>
++            <tooltip-label :title="$t('label.cniconfiguration')" 
:tooltip="apiParams.cniconfig.description"/>
++          </template>
++          <a-textarea
++            v-model:value="form.cniconfig"
++            :placeholder="apiParams.cniconfig.description"/>
++        </a-form-item>
          <a-form-item name="isbase64" ref="isbase64" 
:label="$t('label.is.base64.encoded')">
            <a-checkbox v-model:checked="form.isbase64"></a-checkbox>
          </a-form-item>
          <a-form-item name="params" ref="params">
            <template #label>
 +            <tooltip-label
 +              :title="$route.name === 'userdata' ? $t('label.userdataparams') 
: $t('label.cniconfigparams')"
 +              :tooltip="apiParams.params.description"/>
+             <tooltip-label :title="$t('label.user.data.params')" 
:tooltip="apiParams.params.description"/>
            </template>
            <a-select
              mode="tags"
diff --cc ui/src/views/compute/ResetUserData.vue
index 462a0901b88,8849db5dcca..c05c9452b2d
--- a/ui/src/views/compute/ResetUserData.vue
+++ b/ui/src/views/compute/ResetUserData.vue
@@@ -362,10 -362,13 +362,10 @@@ export default 
        params.id = this.resource.resetUserDataResourceId ? 
this.resource.resetUserDataResourceId : this.resource.id
  
        const resetUserDataApiName = this.resource.resetUserDataApiName ? 
this.resource.resetUserDataApiName : 'resetUserDataForVirtualMachine'
 -      const httpMethod = params.userdata ? 'POST' : 'GET'
 -      const args = httpMethod === 'POST' ? {} : params
 -      const data = httpMethod === 'POST' ? params : {}
  
 -      api(resetUserDataApiName, args, httpMethod, data).then(json => {
 +      postAPI(resetUserDataApiName, params).then(json => {
          this.$message.success({
-           content: `${this.$t('label.action.userdata.reset')} - 
${this.$t('label.success')}`,
+           content: `${this.$t('label.action.user.data.reset')} - 
${this.$t('label.success')}`,
            duration: 2
          })
          this.$emit('refresh-data')
diff --cc ui/src/views/compute/wizard/UserDataSelection.vue
index 06eaefcc060,0b8fdc06952..b8739e81e53
--- a/ui/src/views/compute/wizard/UserDataSelection.vue
+++ b/ui/src/views/compute/wizard/UserDataSelection.vue
@@@ -34,8 -33,7 +34,8 @@@
        :scroll="{ y: 225 }"
      >
        <template #headerCell="{ column }">
-         <template v-if="column.key === 'name'"><solution-outlined /> {{ 
$t('label.userdata') }}</template>
+         <template v-if="column.key === 'name'"><solution-outlined /> {{ 
$t('label.user.data') }}</template>
 +        <template v-if="column.key === 'AS_NUMBER'"><user-outlined /> {{ 
$t('label.account') }}</template>
          <template v-if="column.key === 'account'"><user-outlined /> {{ 
$t('label.account') }}</template>
          <template v-if="column.key === 'domain'"><block-outlined /> {{ 
$t('label.domain') }}</template>
        </template>

Reply via email to