server: add support for sorting zones in UI/API (#3242)

Problem: Not able to configure a sort order for the zones that are listed in various views in the UI.

Root Cause: There is no mechanism to accept sort key for existing zones or UI widget, that would allow to listing zones in the UI in a certain order.

Solution: The order of zones in listed in various views in the UI can now be configured through the newly added “sort_key” field added for the zone. It can be set using updateZone API by providing “sort_key” parameter for a zone, or by reordering the items in the zones list in the UI. UI has been updated to show ordering controls in zones list view. Database changes include updating table “data_center” by adding “sort_key” column (containing integer values and defaults to zero).

Signed-off-by: Rohit Yadav <rohit.yadav@shapeblue.com>
This commit is contained in:
Rohit Yadav 2019-06-19 18:03:56 +05:30 committed by GitHub
parent 0d6cae6339
commit 90cd8aa73d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 139 additions and 42 deletions

View File

@ -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 interface DataCenter extends InfrastructureEntity, Grouping, Partition {
String getZoneToken();
boolean isLocalStorageEnabled();
int getSortKey();
}

View File

@ -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 class UpdateZoneCmd extends BaseCmd {
return localStorageEnabled;
}
public Integer getSortKey() {
return sortKey;
}
/////////////////////////////////////////////////////
/////////////// API Implementation///////////////////
/////////////////////////////////////////////////////

View File

@ -85,7 +85,7 @@ import com.cloud.exception.PermissionDeniedException;
public interface QueryService {
// Config keys
static final ConfigKey<Boolean> AllowUserViewDestroyedVM = new ConfigKey<Boolean>("Advanced", Boolean.class, "allow.user.view.destroyed.vm", "false",
ConfigKey<Boolean> 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<String> UserVMBlacklistedDetails = new ConfigKey<String>("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<Boolean> 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<UserResponse> searchForUsers(ListUsersCmd cmd) throws PermissionDeniedException;
ListResponse<EventResponse> searchForEvents(ListEventsCmd cmd);

View File

@ -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.TableGenerator;
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 class EngineDataCenterVO implements EngineDataCenter, Identity {
this.localStorageEnabled = enabled;
}
public int getSortKey() {
return sortKey;
}
@Override
public Map<String, String> getDetails() {
return details;

View File

@ -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.Id;
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 class DataCenterVO implements DataCenter {
this.localStorageEnabled = enabled;
}
@Override
public int getSortKey() {
return sortKey;
}
public void setSortKey(int newSortKey) {
sortKey = newSortKey;
}
@Override
public Map<String, String> getDetails() {
return details;

View File

@ -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;

View File

@ -2496,9 +2496,7 @@ public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements Q
// 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<DiskOfferingJoinVO> sc = _diskOfferingJoinDao.createSearchCriteria();
sc.addAnd("type", Op.EQ, DiskOfferingVO.Type.Disk);
@ -2638,9 +2636,7 @@ public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements Q
// 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();
@ -2814,7 +2810,7 @@ public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements Q
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<DataCenterJoinVO> sc = sb.create();
if (networkType != null) {
@ -3074,10 +3070,8 @@ public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements Q
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<TemplateJoinVO> sb = _templateJoinDao.createSearchBuilder();
sb.select(null, Func.DISTINCT, sb.entity().getTempZonePair()); // select distinct (templateId, zoneId) pair
@ -3702,6 +3696,6 @@ public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements Q
@Override
public ConfigKey<?>[] getConfigKeys() {
return new ConfigKey<?>[] {AllowUserViewDestroyedVM, UserVMBlacklistedDetails, UserVMReadOnlyUIDetails};
return new ConfigKey<?>[] {AllowUserViewDestroyedVM, UserVMBlacklistedDetails, UserVMReadOnlyUIDetails, SortKeyAscending};
}
}

View File

@ -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 class DataCenterJoinVO extends BaseViewVO implements InternalIdentity, Id
public long getAccountId() {
return accountId;
}
public int getSortKey() {
return sortKey;
}
}

View File

@ -987,14 +987,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(

View File

@ -1922,6 +1922,8 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati
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 class ConfigurationManagerImpl extends ManagerBase implements Configurati
zone.setInternalDns1(internalDns1);
zone.setInternalDns2(internalDns2);
zone.setGuestNetworkCidr(guestCidr);
zone.setSortKey(sortKey);
if (localStorageEnabled != null) {
zone.setLocalStorageEnabled(localStorageEnabled.booleanValue());
}

View File

@ -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({

View File

@ -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;
@ -2418,7 +2419,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();

View File

@ -7641,6 +7641,8 @@
}
},
reorder: cloudStack.api.actions.sort('updateZone', 'physicalResources'),
dataProvider: function (args) {
var array1 =[];
if (args.filterBy != null) {