From c6237c48acac8b405e1f12492835c86ea33b9829 Mon Sep 17 00:00:00 2001 From: Daniel Augusto Veronezi Salvador <38945620+GutoVeronezi@users.noreply.github.com> Date: Fri, 30 Jun 2023 11:09:55 -0300 Subject: [PATCH] Retrieve only resource count on user dashboard (#7617) * Allow retrieving only the count of resources on APIs listPublicIpAddresses, listNetworks, listVirtualMachines and listVolumes * Use parameter to retrieve only the count of resources in the dashboard * Create abstract class --- .../apache/cloudstack/api/ApiConstants.java | 1 + .../BaseListRetrieveOnlyResourceCountCmd.java | 28 ++++++++++++++++++ .../address/ListPublicIpAddressesCmd.java | 19 ++++++------ .../command/user/network/ListNetworksCmd.java | 29 ++++++++++--------- .../api/command/user/vm/ListVMsCmd.java | 13 ++++----- .../command/user/volume/ListVolumesCmd.java | 11 ++++--- .../com/cloud/api/query/QueryManagerImpl.java | 15 ++++++++-- ui/src/views/dashboard/UsageDashboard.vue | 12 ++++---- 8 files changed, 83 insertions(+), 45 deletions(-) create mode 100644 api/src/main/java/org/apache/cloudstack/api/BaseListRetrieveOnlyResourceCountCmd.java diff --git a/api/src/main/java/org/apache/cloudstack/api/ApiConstants.java b/api/src/main/java/org/apache/cloudstack/api/ApiConstants.java index 509c2a35d20..d3ce4d3c7c7 100644 --- a/api/src/main/java/org/apache/cloudstack/api/ApiConstants.java +++ b/api/src/main/java/org/apache/cloudstack/api/ApiConstants.java @@ -372,6 +372,7 @@ public class ApiConstants { public static final String RESOURCE_TYPE = "resourcetype"; public static final String RESOURCE_TYPE_NAME = "resourcetypename"; public static final String RESPONSE = "response"; + public static final String RETRIEVE_ONLY_RESOURCE_COUNT = "retrieveonlyresourcecount"; public static final String REVERTABLE = "revertable"; public static final String REVOKED = "revoked"; public static final String REGISTERED = "registered"; diff --git a/api/src/main/java/org/apache/cloudstack/api/BaseListRetrieveOnlyResourceCountCmd.java b/api/src/main/java/org/apache/cloudstack/api/BaseListRetrieveOnlyResourceCountCmd.java new file mode 100644 index 00000000000..0e8e136a6c1 --- /dev/null +++ b/api/src/main/java/org/apache/cloudstack/api/BaseListRetrieveOnlyResourceCountCmd.java @@ -0,0 +1,28 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +package org.apache.cloudstack.api; + +import org.apache.commons.lang3.BooleanUtils; + +public abstract class BaseListRetrieveOnlyResourceCountCmd extends BaseListTaggedResourcesCmd { + @Parameter(name = ApiConstants.RETRIEVE_ONLY_RESOURCE_COUNT, type = CommandType.BOOLEAN, description = "makes the API's response contains only the resource count") + private Boolean retrieveOnlyResourceCount; + + public Boolean getRetrieveOnlyResourceCount() { + return BooleanUtils.toBooleanDefaultIfNull(retrieveOnlyResourceCount, false); + } +} diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/address/ListPublicIpAddressesCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/address/ListPublicIpAddressesCmd.java index 505de6829a0..22eb70cc0c2 100644 --- a/api/src/main/java/org/apache/cloudstack/api/command/user/address/ListPublicIpAddressesCmd.java +++ b/api/src/main/java/org/apache/cloudstack/api/command/user/address/ListPublicIpAddressesCmd.java @@ -25,7 +25,7 @@ import org.apache.cloudstack.acl.RoleType; import org.apache.cloudstack.api.APICommand; import org.apache.cloudstack.api.ApiCommandResourceType; import org.apache.cloudstack.api.ApiConstants; -import org.apache.cloudstack.api.BaseListTaggedResourcesCmd; +import org.apache.cloudstack.api.BaseListRetrieveOnlyResourceCountCmd; import org.apache.cloudstack.api.Parameter; import org.apache.cloudstack.api.ResponseObject.ResponseView; import org.apache.cloudstack.api.command.user.UserCmd; @@ -42,7 +42,7 @@ import com.cloud.utils.Pair; @APICommand(name = "listPublicIpAddresses", description = "Lists all public IP addresses", responseObject = IPAddressResponse.class, responseView = ResponseView.Restricted, requestHasSensitiveInfo = false, responseHasSensitiveInfo = false, entityType = { IpAddress.class }) -public class ListPublicIpAddressesCmd extends BaseListTaggedResourcesCmd implements UserCmd { +public class ListPublicIpAddressesCmd extends BaseListRetrieveOnlyResourceCountCmd implements UserCmd { public static final Logger s_logger = Logger.getLogger(ListPublicIpAddressesCmd.class.getName()); private static final String s_name = "listpublicipaddressesresponse"; @@ -173,10 +173,6 @@ public class ListPublicIpAddressesCmd extends BaseListTaggedResourcesCmd impleme return forVirtualNetwork; } - public Boolean getForLoadBalancing() { - return forLoadBalancing; - } - public String getState() { return state; } @@ -194,10 +190,13 @@ public class ListPublicIpAddressesCmd extends BaseListTaggedResourcesCmd impleme Pair, Integer> result = _mgr.searchForIPAddresses(this); ListResponse response = new ListResponse<>(); List ipAddrResponses = new ArrayList<>(); - for (IpAddress ipAddress : result.first()) { - IPAddressResponse ipResponse = _responseGenerator.createIPAddressResponse(getResponseView(), ipAddress); - ipResponse.setObjectName("publicipaddress"); - ipAddrResponses.add(ipResponse); + + if (!getRetrieveOnlyResourceCount()) { + for (IpAddress ipAddress : result.first()) { + IPAddressResponse ipResponse = _responseGenerator.createIPAddressResponse(getResponseView(), ipAddress); + ipResponse.setObjectName("publicipaddress"); + ipAddrResponses.add(ipResponse); + } } response.setResponses(ipAddrResponses, result.second()); diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/network/ListNetworksCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/network/ListNetworksCmd.java index df82d9fd625..f370c037814 100644 --- a/api/src/main/java/org/apache/cloudstack/api/command/user/network/ListNetworksCmd.java +++ b/api/src/main/java/org/apache/cloudstack/api/command/user/network/ListNetworksCmd.java @@ -23,12 +23,13 @@ import com.cloud.server.ResourceIcon; import com.cloud.server.ResourceTag; import org.apache.cloudstack.api.response.NetworkOfferingResponse; import org.apache.cloudstack.api.response.ResourceIconResponse; +import org.apache.commons.lang3.BooleanUtils; import org.apache.log4j.Logger; import org.apache.cloudstack.acl.RoleType; import org.apache.cloudstack.api.APICommand; import org.apache.cloudstack.api.ApiConstants; -import org.apache.cloudstack.api.BaseListTaggedResourcesCmd; +import org.apache.cloudstack.api.BaseListRetrieveOnlyResourceCountCmd; import org.apache.cloudstack.api.Parameter; import org.apache.cloudstack.api.ResponseObject.ResponseView; import org.apache.cloudstack.api.command.user.UserCmd; @@ -44,7 +45,7 @@ import org.apache.commons.lang3.StringUtils; @APICommand(name = "listNetworks", description = "Lists all available networks.", responseObject = NetworkResponse.class, responseView = ResponseView.Restricted, entityType = {Network.class}, requestHasSensitiveInfo = false, responseHasSensitiveInfo = false) -public class ListNetworksCmd extends BaseListTaggedResourcesCmd implements UserCmd { +public class ListNetworksCmd extends BaseListRetrieveOnlyResourceCountCmd implements UserCmd { public static final Logger s_logger = Logger.getLogger(ListNetworksCmd.class.getName()); private static final String s_name = "listnetworksresponse"; @@ -190,14 +191,11 @@ public class ListNetworksCmd extends BaseListTaggedResourcesCmd implements UserC @Override public Boolean getDisplay() { - if (display != null) { - return display; - } - return super.getDisplay(); + return BooleanUtils.toBooleanDefaultIfNull(display, super.getDisplay()); } public Boolean getShowIcon() { - return showIcon != null ? showIcon : false; + return BooleanUtils.toBooleanDefaultIfNull(showIcon, false); } public String getNetworkFilter() { @@ -215,16 +213,21 @@ public class ListNetworksCmd extends BaseListTaggedResourcesCmd implements UserC @Override public void execute() { Pair, Integer> networks = _networkService.searchForNetworks(this); - ListResponse response = new ListResponse(); - List networkResponses = new ArrayList(); - for (Network network : networks.first()) { - NetworkResponse networkResponse = _responseGenerator.createNetworkResponse(getResponseView(), network); - networkResponses.add(networkResponse); + ListResponse response = new ListResponse<>(); + List networkResponses = new ArrayList<>(); + + if (!getRetrieveOnlyResourceCount()) { + for (Network network : networks.first()) { + NetworkResponse networkResponse = _responseGenerator.createNetworkResponse(getResponseView(), network); + networkResponses.add(networkResponse); + } } + response.setResponses(networkResponses, networks.second()); response.setResponseName(getCommandName()); setResponseObject(response); - if (response != null && response.getCount() > 0 && getShowIcon()) { + + if (!getRetrieveOnlyResourceCount() && response.getCount() > 0 && getShowIcon()) { updateNetworkResponse(response.getResponses()); } } diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/vm/ListVMsCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/vm/ListVMsCmd.java index e609655c580..07d83b47d3c 100644 --- a/api/src/main/java/org/apache/cloudstack/api/command/user/vm/ListVMsCmd.java +++ b/api/src/main/java/org/apache/cloudstack/api/command/user/vm/ListVMsCmd.java @@ -26,7 +26,7 @@ import org.apache.cloudstack.api.APICommand; import org.apache.cloudstack.api.ApiCommandResourceType; import org.apache.cloudstack.api.ApiConstants; import org.apache.cloudstack.api.ApiConstants.VMDetails; -import org.apache.cloudstack.api.BaseListTaggedResourcesCmd; +import org.apache.cloudstack.api.BaseListRetrieveOnlyResourceCountCmd; import org.apache.cloudstack.api.Parameter; import org.apache.cloudstack.api.ResponseObject.ResponseView; import org.apache.cloudstack.api.command.user.UserCmd; @@ -44,6 +44,7 @@ import org.apache.cloudstack.api.response.UserResponse; import org.apache.cloudstack.api.response.UserVmResponse; import org.apache.cloudstack.api.response.VpcResponse; import org.apache.cloudstack.api.response.ZoneResponse; +import org.apache.commons.lang3.BooleanUtils; import org.apache.log4j.Logger; import com.cloud.exception.InvalidParameterValueException; @@ -54,7 +55,7 @@ import com.cloud.vm.VirtualMachine; @APICommand(name = "listVirtualMachines", description = "List the virtual machines owned by the account.", responseObject = UserVmResponse.class, responseView = ResponseView.Restricted, entityType = {VirtualMachine.class}, requestHasSensitiveInfo = false, responseHasSensitiveInfo = true) -public class ListVMsCmd extends BaseListTaggedResourcesCmd implements UserCmd { +public class ListVMsCmd extends BaseListRetrieveOnlyResourceCountCmd implements UserCmd { public static final Logger s_logger = Logger.getLogger(ListVMsCmd.class.getName()); private static final String s_name = "listvirtualmachinesresponse"; @@ -148,7 +149,6 @@ public class ListVMsCmd extends BaseListTaggedResourcesCmd implements UserCmd { @Parameter(name = ApiConstants.USER_DATA, type = CommandType.BOOLEAN, description = "Whether to return the VMs' user data or not. By default, user data will not be returned.", since = "4.18.0.0") private Boolean showUserData; - ///////////////////////////////////////////////////// /////////////////// Accessors /////////////////////// ///////////////////////////////////////////////////// @@ -255,14 +255,11 @@ public class ListVMsCmd extends BaseListTaggedResourcesCmd implements UserCmd { @Override public Boolean getDisplay() { - if (display != null) { - return display; - } - return super.getDisplay(); + return BooleanUtils.toBooleanDefaultIfNull(display, super.getDisplay()); } public Boolean getShowIcon() { - return showIcon != null ? showIcon : false; + return BooleanUtils.toBooleanDefaultIfNull(showIcon, false); } public Boolean getAccumulate() { diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/volume/ListVolumesCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/volume/ListVolumesCmd.java index fdac3ff2937..b62a909d71f 100644 --- a/api/src/main/java/org/apache/cloudstack/api/command/user/volume/ListVolumesCmd.java +++ b/api/src/main/java/org/apache/cloudstack/api/command/user/volume/ListVolumesCmd.java @@ -22,7 +22,7 @@ import org.apache.cloudstack.acl.RoleType; import org.apache.cloudstack.api.APICommand; import org.apache.cloudstack.api.ApiCommandResourceType; import org.apache.cloudstack.api.ApiConstants; -import org.apache.cloudstack.api.BaseListTaggedResourcesCmd; +import org.apache.cloudstack.api.BaseListRetrieveOnlyResourceCountCmd; import org.apache.cloudstack.api.Parameter; import org.apache.cloudstack.api.ResponseObject.ResponseView; import org.apache.cloudstack.api.command.user.UserCmd; @@ -35,13 +35,14 @@ import org.apache.cloudstack.api.response.StoragePoolResponse; import org.apache.cloudstack.api.response.UserVmResponse; import org.apache.cloudstack.api.response.VolumeResponse; import org.apache.cloudstack.api.response.ZoneResponse; +import org.apache.commons.lang3.BooleanUtils; import org.apache.log4j.Logger; import com.cloud.storage.Volume; @APICommand(name = "listVolumes", description = "Lists all volumes.", responseObject = VolumeResponse.class, responseView = ResponseView.Restricted, entityType = { Volume.class}, requestHasSensitiveInfo = false, responseHasSensitiveInfo = false) -public class ListVolumesCmd extends BaseListTaggedResourcesCmd implements UserCmd { +public class ListVolumesCmd extends BaseListRetrieveOnlyResourceCountCmd implements UserCmd { public static final Logger s_logger = Logger.getLogger(ListVolumesCmd.class.getName()); private static final String s_name = "listvolumesresponse"; @@ -145,15 +146,13 @@ public class ListVolumesCmd extends BaseListTaggedResourcesCmd implements UserCm @Override public Boolean getDisplay() { - if (display != null) { - return display; - } - return super.getDisplay(); + return BooleanUtils.toBooleanDefaultIfNull(display, super.getDisplay()); } public String getState() { return state; } + ///////////////////////////////////////////////////// /////////////// API Implementation/////////////////// ///////////////////////////////////////////////////// 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 e78f6958e1a..63927f2f9ef 100644 --- a/server/src/main/java/com/cloud/api/query/QueryManagerImpl.java +++ b/server/src/main/java/com/cloud/api/query/QueryManagerImpl.java @@ -973,7 +973,13 @@ public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements Q @Override public ListResponse searchForUserVMs(ListVMsCmd cmd) { Pair, Integer> result = searchForUserVMsInternal(cmd); - ListResponse response = new ListResponse(); + ListResponse response = new ListResponse<>(); + + if (cmd.getRetrieveOnlyResourceCount()) { + response.setResponses(new ArrayList<>(), result.second()); + return response; + } + ResponseView respView = ResponseView.Restricted; Account caller = CallContext.current().getCallingAccount(); if (_accountMgr.isRootAdmin(caller.getId())) { @@ -2062,7 +2068,12 @@ public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements Q @Override public ListResponse searchForVolumes(ListVolumesCmd cmd) { Pair, Integer> result = searchForVolumesInternal(cmd); - ListResponse response = new ListResponse(); + ListResponse response = new ListResponse<>(); + + if (cmd.getRetrieveOnlyResourceCount()) { + response.setResponses(new ArrayList<>(), result.second()); + return response; + } ResponseView respView = cmd.getResponseView(); Account account = CallContext.current().getCallingAccount(); diff --git a/ui/src/views/dashboard/UsageDashboard.vue b/ui/src/views/dashboard/UsageDashboard.vue index 4264a90f925..28a892ac71e 100644 --- a/ui/src/views/dashboard/UsageDashboard.vue +++ b/ui/src/views/dashboard/UsageDashboard.vue @@ -169,7 +169,7 @@ export default { methods: { fetchData () { this.stats = [{}, {}, {}, {}, {}, {}] - api('listVirtualMachines', { state: 'Running', listall: true }).then(json => { + api('listVirtualMachines', { state: 'Running', listall: true, retrieveonlyresourcecount: true }).then(json => { var count = 0 if (json && json.listvirtualmachinesresponse) { count = json.listvirtualmachinesresponse.count @@ -177,7 +177,7 @@ export default { var tileColor = this.$config.theme['@dashboard-tile-runningvms-bg'] || '#dfe9cc' this.stats.splice(0, 1, { name: this.$t('label.running.vms'), count: count, icon: 'desktop-outlined', bgcolor: tileColor, path: '/vm', query: { state: 'running', filter: 'running' } }) }) - api('listVirtualMachines', { state: 'Stopped', listall: true }).then(json => { + api('listVirtualMachines', { state: 'Stopped', listall: true, retrieveonlyresourcecount: true }).then(json => { var count = 0 if (json && json.listvirtualmachinesresponse) { count = json.listvirtualmachinesresponse.count @@ -185,7 +185,7 @@ export default { var tileColor = this.$config.theme['@dashboard-tile-stoppedvms-bg'] || '#edcbce' this.stats.splice(1, 1, { name: this.$t('label.stopped.vms'), count: count, icon: 'poweroff-outlined', bgcolor: tileColor, path: '/vm', query: { state: 'stopped', filter: 'stopped' } }) }) - api('listVirtualMachines', { listall: true }).then(json => { + api('listVirtualMachines', { listall: true, retrieveonlyresourcecount: true }).then(json => { var count = 0 if (json && json.listvirtualmachinesresponse) { count = json.listvirtualmachinesresponse.count @@ -193,7 +193,7 @@ export default { var tileColor = this.$config.theme['@dashboard-tile-totalvms-bg'] || '#ffffff' this.stats.splice(2, 1, { name: this.$t('label.total.vms'), count: count, icon: 'number-outlined', bgcolor: tileColor, path: '/vm' }) }) - api('listVolumes', { listall: true }).then(json => { + api('listVolumes', { listall: true, retrieveonlyresourcecount: true }).then(json => { var count = 0 if (json && json.listvolumesresponse) { count = json.listvolumesresponse.count @@ -201,7 +201,7 @@ export default { var tileColor = this.$config.theme['@dashboard-tile-totalvolumes-bg'] || '#ffffff' this.stats.splice(3, 1, { name: this.$t('label.total.volume'), count: count, icon: 'database-outlined', bgcolor: tileColor, path: '/volume' }) }) - api('listNetworks', { listall: true }).then(json => { + api('listNetworks', { listall: true, retrieveonlyresourcecount: true }).then(json => { var count = 0 if (json && json.listnetworksresponse) { count = json.listnetworksresponse.count @@ -209,7 +209,7 @@ export default { var tileColor = this.$config.theme['@dashboard-tile-totalnetworks-bg'] || '#ffffff' this.stats.splice(4, 1, { name: this.$t('label.total.network'), count: count, icon: 'apartment-outlined', bgcolor: tileColor, path: '/guestnetwork' }) }) - api('listPublicIpAddresses', { listall: true }).then(json => { + api('listPublicIpAddresses', { listall: true, retrieveonlyresourcecount: true }).then(json => { var count = 0 if (json && json.listpublicipaddressesresponse) { count = json.listpublicipaddressesresponse.count