diff --git a/api/src/main/java/com/cloud/dc/DataCenter.java b/api/src/main/java/com/cloud/dc/DataCenter.java index 7d434c5f2315..4a8f6d9d0a0b 100644 --- a/api/src/main/java/com/cloud/dc/DataCenter.java +++ b/api/src/main/java/com/cloud/dc/DataCenter.java @@ -16,11 +16,12 @@ // under the License. package com.cloud.dc; -import com.cloud.org.Grouping; +import java.util.Map; + import org.apache.cloudstack.acl.InfrastructureEntity; import org.apache.cloudstack.kernel.Partition; -import java.util.Map; +import com.cloud.org.Grouping; /** * @@ -80,4 +81,6 @@ public enum NetworkType { String getZoneToken(); boolean isLocalStorageEnabled(); + + int getSortKey(); } diff --git a/api/src/main/java/org/apache/cloudstack/api/command/admin/zone/UpdateZoneCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/admin/zone/UpdateZoneCmd.java index 9ad8972ecfdd..2f5feed803d3 100644 --- a/api/src/main/java/org/apache/cloudstack/api/command/admin/zone/UpdateZoneCmd.java +++ b/api/src/main/java/org/apache/cloudstack/api/command/admin/zone/UpdateZoneCmd.java @@ -95,6 +95,9 @@ public class UpdateZoneCmd extends BaseCmd { @Parameter(name = ApiConstants.LOCAL_STORAGE_ENABLED, type = CommandType.BOOLEAN, description = "true if local storage offering enabled, false otherwise") private Boolean localStorageEnabled; + @Parameter(name = ApiConstants.SORT_KEY, type = CommandType.INTEGER, description = "sort key of the zone, integer") + private Integer sortKey; + ///////////////////////////////////////////////////// /////////////////// Accessors /////////////////////// ///////////////////////////////////////////////////// @@ -163,6 +166,10 @@ public Boolean getLocalStorageEnabled() { return localStorageEnabled; } + public Integer getSortKey() { + return sortKey; + } + ///////////////////////////////////////////////////// /////////////// API Implementation/////////////////// ///////////////////////////////////////////////////// diff --git a/api/src/main/java/org/apache/cloudstack/query/QueryService.java b/api/src/main/java/org/apache/cloudstack/query/QueryService.java index 6a7c200cc28a..1f0f933d7d21 100644 --- a/api/src/main/java/org/apache/cloudstack/query/QueryService.java +++ b/api/src/main/java/org/apache/cloudstack/query/QueryService.java @@ -85,7 +85,7 @@ public interface QueryService { // Config keys - static final ConfigKey AllowUserViewDestroyedVM = new ConfigKey("Advanced", Boolean.class, "allow.user.view.destroyed.vm", "false", + ConfigKey AllowUserViewDestroyedVM = new ConfigKey<>("Advanced", Boolean.class, "allow.user.view.destroyed.vm", "false", "Determines whether users can view their destroyed or expunging vm ", true, ConfigKey.Scope.Account); static final ConfigKey UserVMBlacklistedDetails = new ConfigKey("Advanced", String.class, @@ -96,6 +96,11 @@ public interface QueryService { "user.vm.readonly.ui.details", "dataDiskController, rootDiskController", "List of UI read-only VM settings/details as comma separated string", true); + ConfigKey SortKeyAscending = new ConfigKey<>("Advanced", Boolean.class, "sortkey.algorithm", "true", + "Sort algorithm - ascending or descending - to use. For entities that use sort key(template, disk offering, service offering, " + + "network offering, zones), we use the flag to determine if the entities should be sorted ascending (when flag is true) " + + "or descending (when flag is false). Within the scope of the config all users see the same result.", true, ConfigKey.Scope.Global); + ListResponse searchForUsers(ListUsersCmd cmd) throws PermissionDeniedException; ListResponse searchForEvents(ListEventsCmd cmd); diff --git a/engine/orchestration/src/main/java/org/apache/cloudstack/engine/datacenter/entity/api/db/EngineDataCenterVO.java b/engine/orchestration/src/main/java/org/apache/cloudstack/engine/datacenter/entity/api/db/EngineDataCenterVO.java index ba967be6210c..26e982013c2e 100644 --- a/engine/orchestration/src/main/java/org/apache/cloudstack/engine/datacenter/entity/api/db/EngineDataCenterVO.java +++ b/engine/orchestration/src/main/java/org/apache/cloudstack/engine/datacenter/entity/api/db/EngineDataCenterVO.java @@ -16,14 +16,9 @@ // under the License. package org.apache.cloudstack.engine.datacenter.entity.api.db; -import com.cloud.network.Network.Provider; -import com.cloud.org.Grouping; -import com.cloud.utils.NumbersUtil; -import com.cloud.utils.db.GenericDao; -import com.cloud.utils.db.StateMachine; -import org.apache.cloudstack.api.Identity; -import org.apache.cloudstack.engine.datacenter.entity.api.DataCenterResourceEntity.State; -import org.apache.cloudstack.engine.datacenter.entity.api.DataCenterResourceEntity.State.Event; +import java.util.Date; +import java.util.Map; +import java.util.UUID; import javax.persistence.Column; import javax.persistence.Entity; @@ -37,9 +32,16 @@ import javax.persistence.Temporal; import javax.persistence.TemporalType; import javax.persistence.Transient; -import java.util.Date; -import java.util.Map; -import java.util.UUID; + +import org.apache.cloudstack.api.Identity; +import org.apache.cloudstack.engine.datacenter.entity.api.DataCenterResourceEntity.State; +import org.apache.cloudstack.engine.datacenter.entity.api.DataCenterResourceEntity.State.Event; + +import com.cloud.network.Network.Provider; +import com.cloud.org.Grouping; +import com.cloud.utils.NumbersUtil; +import com.cloud.utils.db.GenericDao; +import com.cloud.utils.db.StateMachine; @Entity @Table(name = "data_center") @@ -140,6 +142,9 @@ public class EngineDataCenterVO implements EngineDataCenter, Identity { @Column(name = "is_local_storage_enabled") boolean localStorageEnabled; + @Column(name = "sort_key") + int sortKey; + //orchestration @Column(name = "owner") private String owner = null; @@ -389,6 +394,10 @@ public void setLocalStorageEnabled(boolean enabled) { this.localStorageEnabled = enabled; } + public int getSortKey() { + return sortKey; + } + @Override public Map getDetails() { return details; diff --git a/engine/schema/src/main/java/com/cloud/dc/DataCenterVO.java b/engine/schema/src/main/java/com/cloud/dc/DataCenterVO.java index 4ab0eada1e11..d71f34cdc7e7 100644 --- a/engine/schema/src/main/java/com/cloud/dc/DataCenterVO.java +++ b/engine/schema/src/main/java/com/cloud/dc/DataCenterVO.java @@ -16,10 +16,9 @@ // under the License. package com.cloud.dc; -import com.cloud.network.Network.Provider; -import com.cloud.org.Grouping; -import com.cloud.utils.NumbersUtil; -import com.cloud.utils.db.GenericDao; +import java.util.Date; +import java.util.Map; +import java.util.UUID; import javax.persistence.Column; import javax.persistence.Entity; @@ -31,9 +30,11 @@ import javax.persistence.Table; import javax.persistence.TableGenerator; import javax.persistence.Transient; -import java.util.Date; -import java.util.Map; -import java.util.UUID; + +import com.cloud.network.Network.Provider; +import com.cloud.org.Grouping; +import com.cloud.utils.NumbersUtil; +import com.cloud.utils.db.GenericDao; @Entity @Table(name = "data_center") @@ -134,6 +135,9 @@ public class DataCenterVO implements DataCenter { @Column(name = "is_local_storage_enabled") boolean localStorageEnabled; + @Column(name = "sort_key") + int sortKey; + @Override public String getDnsProvider() { return dnsProvider; @@ -363,6 +367,15 @@ public void setLocalStorageEnabled(boolean enabled) { this.localStorageEnabled = enabled; } + @Override + public int getSortKey() { + return sortKey; + } + + public void setSortKey(int newSortKey) { + sortKey = newSortKey; + } + @Override public Map getDetails() { return details; diff --git a/engine/schema/src/main/resources/META-INF/db/schema-41200to41300.sql b/engine/schema/src/main/resources/META-INF/db/schema-41200to41300.sql index e2221f23f824..ee599f65229e 100644 --- a/engine/schema/src/main/resources/META-INF/db/schema-41200to41300.sql +++ b/engine/schema/src/main/resources/META-INF/db/schema-41200to41300.sql @@ -21,3 +21,46 @@ -- DPDK client and server mode support ALTER TABLE `cloud`.`service_offering_details` CHANGE COLUMN `value` `value` TEXT NOT NULL; + +-- Add `sort_key` column to data_center +ALTER TABLE `cloud`.`data_center` ADD COLUMN `sort_key` INT(32) NOT NULL DEFAULT 0; + +-- Recreate data_center_view +DROP VIEW IF EXISTS `cloud`.`data_center_view`; +CREATE VIEW `cloud`.`data_center_view` AS + select + data_center.id, + data_center.uuid, + data_center.name, + data_center.is_security_group_enabled, + data_center.is_local_storage_enabled, + data_center.description, + data_center.dns1, + data_center.dns2, + data_center.ip6_dns1, + data_center.ip6_dns2, + data_center.internal_dns1, + data_center.internal_dns2, + data_center.guest_network_cidr, + data_center.domain, + data_center.networktype, + data_center.allocation_state, + data_center.zone_token, + data_center.dhcp_provider, + data_center.removed, + data_center.sort_key, + domain.id domain_id, + domain.uuid domain_uuid, + domain.name domain_name, + domain.path domain_path, + dedicated_resources.affinity_group_id, + dedicated_resources.account_id, + affinity_group.uuid affinity_group_uuid + from + `cloud`.`data_center` + left join + `cloud`.`domain` ON data_center.domain_id = domain.id + left join + `cloud`.`dedicated_resources` ON data_center.id = dedicated_resources.data_center_id + left join + `cloud`.`affinity_group` ON dedicated_resources.affinity_group_id = affinity_group.id; diff --git a/server/src/main/java/com/cloud/api/query/QueryManagerImpl.java b/server/src/main/java/com/cloud/api/query/QueryManagerImpl.java index 2cf72e26ae64..50ba4b4a9b99 100644 --- a/server/src/main/java/com/cloud/api/query/QueryManagerImpl.java +++ b/server/src/main/java/com/cloud/api/query/QueryManagerImpl.java @@ -2508,9 +2508,7 @@ private Pair, Integer> searchForDiskOfferingsInternal(L // till // root - Boolean isAscending = Boolean.parseBoolean(_configDao.getValue("sortkey.algorithm")); - isAscending = (isAscending == null ? true : isAscending); - Filter searchFilter = new Filter(DiskOfferingJoinVO.class, "sortKey", isAscending, cmd.getStartIndex(), cmd.getPageSizeVal()); + Filter searchFilter = new Filter(DiskOfferingJoinVO.class, "sortKey", SortKeyAscending.value(), cmd.getStartIndex(), cmd.getPageSizeVal()); SearchCriteria sc = _diskOfferingJoinDao.createSearchCriteria(); sc.addAnd("type", Op.EQ, DiskOfferingVO.Type.Disk); @@ -2650,9 +2648,7 @@ private Pair, Integer> searchForServiceOfferingsInte // their domains+parent domains ... all the way // till // root - Boolean isAscending = Boolean.parseBoolean(_configDao.getValue("sortkey.algorithm")); - isAscending = (isAscending == null ? true : isAscending); - Filter searchFilter = new Filter(ServiceOfferingJoinVO.class, "sortKey", isAscending, cmd.getStartIndex(), cmd.getPageSizeVal()); + Filter searchFilter = new Filter(ServiceOfferingJoinVO.class, "sortKey", SortKeyAscending.value(), cmd.getStartIndex(), cmd.getPageSizeVal()); Account caller = CallContext.current().getCallingAccount(); Object name = cmd.getServiceOfferingName(); @@ -2826,7 +2822,7 @@ private Pair, Integer> listDataCentersInternal(ListZonesC sb.join("tagSearch", tagSearch, sb.entity().getId(), tagSearch.entity().getResourceId(), JoinBuilder.JoinType.INNER); } - Filter searchFilter = new Filter(DataCenterJoinVO.class, null, false, cmd.getStartIndex(), cmd.getPageSizeVal()); + Filter searchFilter = new Filter(DataCenterJoinVO.class, "sortKey", SortKeyAscending.value(), cmd.getStartIndex(), cmd.getPageSizeVal()); SearchCriteria sc = sb.create(); if (networkType != null) { @@ -3086,10 +3082,8 @@ private Pair, Integer> searchForTemplatesInternal(Long temp VMTemplateVO template = null; - Boolean isAscending = Boolean.parseBoolean(_configDao.getValue("sortkey.algorithm")); - isAscending = (isAscending == null ? Boolean.TRUE : isAscending); - Filter searchFilter = new Filter(TemplateJoinVO.class, "sortKey", isAscending, startIndex, pageSize); - searchFilter.addOrderBy(TemplateJoinVO.class, "tempZonePair", isAscending); + Filter searchFilter = new Filter(TemplateJoinVO.class, "sortKey", SortKeyAscending.value(), startIndex, pageSize); + searchFilter.addOrderBy(TemplateJoinVO.class, "tempZonePair", SortKeyAscending.value()); SearchBuilder sb = _templateJoinDao.createSearchBuilder(); sb.select(null, Func.DISTINCT, sb.entity().getTempZonePair()); // select distinct (templateId, zoneId) pair @@ -3714,6 +3708,6 @@ public String getConfigComponentName() { @Override public ConfigKey[] getConfigKeys() { - return new ConfigKey[] {AllowUserViewDestroyedVM, UserVMBlacklistedDetails, UserVMReadOnlyUIDetails}; + return new ConfigKey[] {AllowUserViewDestroyedVM, UserVMBlacklistedDetails, UserVMReadOnlyUIDetails, SortKeyAscending}; } } diff --git a/server/src/main/java/com/cloud/api/query/vo/DataCenterJoinVO.java b/server/src/main/java/com/cloud/api/query/vo/DataCenterJoinVO.java index 2c4832012975..14273f00bf8a 100644 --- a/server/src/main/java/com/cloud/api/query/vo/DataCenterJoinVO.java +++ b/server/src/main/java/com/cloud/api/query/vo/DataCenterJoinVO.java @@ -117,6 +117,9 @@ public class DataCenterJoinVO extends BaseViewVO implements InternalIdentity, Id @Column(name = "account_id") private long accountId; + @Column(name = "sort_key") + private int sortKey; + public DataCenterJoinVO() { } @@ -221,4 +224,8 @@ public String getAffinityGroupUuid() { public long getAccountId() { return accountId; } + + public int getSortKey() { + return sortKey; + } } diff --git a/server/src/main/java/com/cloud/configuration/Config.java b/server/src/main/java/com/cloud/configuration/Config.java index 87cf779ef0ba..f3901f13e170 100644 --- a/server/src/main/java/com/cloud/configuration/Config.java +++ b/server/src/main/java/com/cloud/configuration/Config.java @@ -995,14 +995,6 @@ public enum Config { "30", "Garbage collection interval to destroy unused ELB vms in minutes. Minimum of 5", null), - SortKeyAlgorithm( - "Advanced", - ManagementServer.class, - Boolean.class, - "sortkey.algorithm", - "false", - "Sort algorithm for those who use sort key(template, disk offering, service offering, network offering), true means ascending sort while false means descending sort", - null), EnableEC2API("Advanced", ManagementServer.class, Boolean.class, "enable.ec2.api", "false", "enable EC2 API on CloudStack", null), EnableS3API("Advanced", ManagementServer.class, Boolean.class, "enable.s3.api", "false", "enable Amazon S3 API on CloudStack", null), RecreateSystemVmEnabled( diff --git a/server/src/main/java/com/cloud/configuration/ConfigurationManagerImpl.java b/server/src/main/java/com/cloud/configuration/ConfigurationManagerImpl.java index 8df175092ae5..cda28449ce26 100755 --- a/server/src/main/java/com/cloud/configuration/ConfigurationManagerImpl.java +++ b/server/src/main/java/com/cloud/configuration/ConfigurationManagerImpl.java @@ -1922,6 +1922,8 @@ public DataCenter editZone(final UpdateZoneCmd cmd) { guestCidr = zone.getGuestNetworkCidr(); } + int sortKey = cmd.getSortKey() != null ? cmd.getSortKey() : zone.getSortKey(); + // validate network domain if (networkDomain != null && !networkDomain.isEmpty()) { if (!NetUtils.verifyDomainName(networkDomain)) { @@ -1944,6 +1946,7 @@ public DataCenter editZone(final UpdateZoneCmd cmd) { zone.setInternalDns1(internalDns1); zone.setInternalDns2(internalDns2); zone.setGuestNetworkCidr(guestCidr); + zone.setSortKey(sortKey); if (localStorageEnabled != null) { zone.setLocalStorageEnabled(localStorageEnabled.booleanValue()); } diff --git a/ui/scripts/cloudStack.js b/ui/scripts/cloudStack.js index 7faa8c590ca0..e57f79a3c1e2 100644 --- a/ui/scripts/cloudStack.js +++ b/ui/scripts/cloudStack.js @@ -187,6 +187,24 @@ } }); + // Update global pagesize for sort key in UI + $.ajax({ + type: 'GET', + url: createURL('listConfigurations'), + data: {name: 'sortkey.algorithm'}, + dataType: 'json', + async: false, + success: function(data, textStatus, xhr) { + if (data && data.listconfigurationsresponse && data.listconfigurationsresponse.configuration) { + var config = data.listconfigurationsresponse.configuration[0]; + if (config && config.name == 'sortkey.algorithm') { + g_sortKeyIsAscending = config.value == 'true'; + } + } + }, + error: function(xhr) { // ignore any errors, fallback to the default + } + }); // Populate IDP list $.ajax({ diff --git a/ui/scripts/sharedFunctions.js b/ui/scripts/sharedFunctions.js index 995b8415ebca..3b0e30837d70 100644 --- a/ui/scripts/sharedFunctions.js +++ b/ui/scripts/sharedFunctions.js @@ -35,6 +35,7 @@ var g_cloudstackversion = null; var g_queryAsyncJobResultInterval = 3000; var g_idpList = null; var g_appendIdpDomain = false; +var g_sortKeyIsAscending = false; //keyboard keycode var keycode_Enter = 13; @@ -2405,7 +2406,7 @@ cloudStack.api = { url: createURL(updateCommand), data: { id: args.context[objType].id, - sortKey: args.index + sortKey: g_sortKeyIsAscending ? (-1 * args.index) : args.index }, success: function(json) { args.response.success(); diff --git a/ui/scripts/system.js b/ui/scripts/system.js index d87636d953a3..bce94fc1e206 100755 --- a/ui/scripts/system.js +++ b/ui/scripts/system.js @@ -7641,6 +7641,8 @@ } }, + reorder: cloudStack.api.actions.sort('updateZone', 'physicalResources'), + dataProvider: function (args) { var array1 =[]; if (args.filterBy != null) {