Skip to content

Commit 592038a

Browse files
authored
api,server,ui: granular resource limit management (#8362)
Feature spec: https://cwiki.apache.org/confluence/display/CLOUDSTACK/Granular+Resource+Limit+Management Introduces the concept of tagged resource limits for granular resource limit management. Limits can be enforced on accounts and domains for the deployment of entities for a tagged resource. Current tagged resource limits can be used for the following resource types, Host limits - user_vm - cpu - memory Storage limits - volume - primary_storage Following global settings can used to specify tags for which limit needs to be enforced, Host: `resource.limit.host.tags` Storage: `resource.limit.storage.tags` Option for specifying tagged resource limits and viewing tagged resource usage are made available in the UI. Enhances the use of templatetag for VM deployment and template creation Adds option to list service/compute offerings that can be used with a given template. A new parameter named templateid has been added. Adds option to list disk offering with suitability flag for a virtual machine. A new parameter named virtualmachineid has been added to the listDiskOfferings API which when passed returns suitableforvirtualmachine param in the response.
1 parent 6af1c25 commit 592038a

File tree

116 files changed

+6448
-1100
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

116 files changed

+6448
-1100
lines changed

.github/workflows/ci.yml

+2-1
Original file line numberDiff line numberDiff line change
@@ -179,7 +179,8 @@ jobs:
179179
"component/test_project_usage
180180
component/test_protocol_number_security_group
181181
component/test_public_ip
182-
component/test_resource_limits",
182+
component/test_resource_limits
183+
component/test_resource_limit_tags",
183184
"component/test_regions_accounts
184185
component/test_routers
185186
component/test_snapshots

api/src/main/java/com/cloud/capacity/Capacity.java

+9
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616
// under the License.
1717
package com.cloud.capacity;
1818

19+
import java.util.List;
20+
1921
import org.apache.cloudstack.api.Identity;
2022
import org.apache.cloudstack.api.InternalIdentity;
2123

@@ -35,6 +37,11 @@ public interface Capacity extends InternalIdentity, Identity {
3537

3638
public static final short CAPACITY_TYPE_CPU_CORE = 90;
3739

40+
public static final List<Short> STORAGE_CAPACITY_TYPES = List.of(CAPACITY_TYPE_STORAGE,
41+
CAPACITY_TYPE_STORAGE_ALLOCATED,
42+
CAPACITY_TYPE_SECONDARY_STORAGE,
43+
CAPACITY_TYPE_LOCAL_STORAGE);
44+
3845
public Long getHostOrPoolId();
3946

4047
public Long getDataCenterId();
@@ -54,4 +61,6 @@ public interface Capacity extends InternalIdentity, Identity {
5461
public Float getUsedPercentage();
5562

5663
public Long getAllocatedCapacity();
64+
65+
public String getTag();
5766
}

api/src/main/java/com/cloud/configuration/Resource.java

+1
Original file line numberDiff line numberDiff line change
@@ -85,5 +85,6 @@ public String getName() {
8585
long getOwnerId();
8686

8787
ResourceOwnerType getResourceOwnerType();
88+
String getTag();
8889

8990
}

api/src/main/java/com/cloud/storage/Volume.java

+2
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@
3030

3131
public interface Volume extends ControlledEntity, Identity, InternalIdentity, BasedOn, StateObject<Volume.State>, Displayable {
3232

33+
static final long DISK_OFFERING_SUITABILITY_CHECK_VOLUME_ID = -1;
34+
3335
// Managed storage volume parameters (specified in the compute/disk offering for PowerFlex)
3436
String BANDWIDTH_LIMIT_IN_MBPS = "bandwidthLimitInMbps";
3537
String IOPS_LIMIT = "iopsLimit";

api/src/main/java/com/cloud/user/ResourceLimitService.java

+55-21
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,18 @@
1818

1919
import java.util.List;
2020

21+
import org.apache.cloudstack.api.response.AccountResponse;
22+
import org.apache.cloudstack.api.response.DomainResponse;
23+
import org.apache.cloudstack.framework.config.ConfigKey;
24+
2125
import com.cloud.configuration.Resource.ResourceType;
2226
import com.cloud.configuration.ResourceCount;
2327
import com.cloud.configuration.ResourceLimit;
2428
import com.cloud.domain.Domain;
2529
import com.cloud.exception.ResourceAllocationException;
26-
import org.apache.cloudstack.framework.config.ConfigKey;
27-
import org.apache.cloudstack.user.ResourceReservation;
30+
import com.cloud.offering.DiskOffering;
31+
import com.cloud.offering.ServiceOffering;
32+
import com.cloud.template.VirtualMachineTemplate;
2833

2934
public interface ResourceLimitService {
3035

@@ -34,6 +39,13 @@ public interface ResourceLimitService {
3439
"The default maximum secondary storage space (in GiB) that can be used for a project", false);
3540
static final ConfigKey<Long> ResourceCountCheckInterval = new ConfigKey<>("Advanced", Long.class, "resourcecount.check.interval", "300",
3641
"Time (in seconds) to wait before running resource recalculation and fixing task. Default is 300 seconds, Setting this to 0 disables execution of the task", false);
42+
static final ConfigKey<String> ResourceLimitHostTags = new ConfigKey<>("Advanced", String.class, "resource.limit.host.tags", "",
43+
"A comma-separated list of tags for host resource limits", true);
44+
static final ConfigKey<String> ResourceLimitStorageTags = new ConfigKey<>("Advanced", String.class, "resource.limit.storage.tags", "",
45+
"A comma-separated list of tags for storage resource limits", true);
46+
47+
static final List<ResourceType> HostTagsSupportingTypes = List.of(ResourceType.user_vm, ResourceType.cpu, ResourceType.memory);
48+
static final List<ResourceType> StorageTagsSupportingTypes = List.of(ResourceType.volume, ResourceType.primary_storage);
3749

3850
/**
3951
* Updates an existing resource limit with the specified details. If a limit doesn't exist, will create one.
@@ -46,22 +58,27 @@ public interface ResourceLimitService {
4658
* TODO
4759
* @param max
4860
* TODO
61+
* @param tag
62+
* tag for the resource type
4963
*
5064
* @return the updated/created resource limit
5165
*/
52-
ResourceLimit updateResourceLimit(Long accountId, Long domainId, Integer resourceType, Long max);
66+
ResourceLimit updateResourceLimit(Long accountId, Long domainId, Integer resourceType, Long max, String tag);
5367

5468
/**
5569
* Updates an existing resource count details for the account/domain
5670
*
5771
* @param accountId
58-
* TODO
72+
* Id of the account for which resource recalculation to be done
5973
* @param domainId
60-
* TODO
74+
* Id of the domain for which resource recalculation to be doneDO
6175
* @param typeId
62-
* TODO
76+
* type of the resource for which recalculation to be done
77+
* @param tag
78+
* tag for the resource type for which recalculation to be done
6379
* @return the updated/created resource counts
6480
*/
81+
List<? extends ResourceCount> recalculateResourceCount(Long accountId, Long domainId, Integer typeId, String tag);
6582
List<? extends ResourceCount> recalculateResourceCount(Long accountId, Long domainId, Integer typeId);
6683

6784
/**
@@ -77,17 +94,18 @@ public interface ResourceLimitService {
7794
* TODO
7895
* @return a list of limits that match the criteria
7996
*/
80-
public List<? extends ResourceLimit> searchForLimits(Long id, Long accountId, Long domainId, ResourceType resourceType, Long startIndex, Long pageSizeVal);
97+
public List<? extends ResourceLimit> searchForLimits(Long id, Long accountId, Long domainId, ResourceType resourceType, String tag, Long startIndex, Long pageSizeVal);
8198

8299
/**
83100
* Finds the resource limit for a specified account and type. If the account has an infinite limit, will check
84101
* the account's parent domain, and if that limit is also infinite, will return the ROOT domain's limit.
85102
*
86103
* @param account
87104
* @param type
105+
* @param tag
88106
* @return resource limit
89107
*/
90-
public long findCorrectResourceLimitForAccount(Account account, ResourceType type);
108+
public long findCorrectResourceLimitForAccount(Account account, ResourceType type, String tag);
91109

92110
/**
93111
* This call should be used when we have already queried resource limit for an account. This is to handle
@@ -105,9 +123,10 @@ public interface ResourceLimitService {
105123
*
106124
* @param domain
107125
* @param type
126+
* @param tag
108127
* @return resource limit
109128
*/
110-
public long findCorrectResourceLimitForDomain(Domain domain, ResourceType type);
129+
public long findCorrectResourceLimitForDomain(Domain domain, ResourceType type, String tag);
111130

112131
/**
113132
* Finds the default resource limit for a specified type.
@@ -122,9 +141,10 @@ public interface ResourceLimitService {
122141
*
123142
* @param domain
124143
* @param type
144+
* @param tag
125145
* @return resource limit
126146
*/
127-
public long findCorrectResourceLimitForAccountAndDomain(Account account, Domain domain, ResourceType type);
147+
public long findCorrectResourceLimitForAccountAndDomain(Account account, Domain domain, ResourceType type, String tag);
128148

129149
/**
130150
* Increments the resource count
@@ -134,6 +154,7 @@ public interface ResourceLimitService {
134154
* @param delta
135155
*/
136156
public void incrementResourceCount(long accountId, ResourceType type, Long... delta);
157+
public void incrementResourceCountWithTag(long accountId, ResourceType type, String tag, Long... delta);
137158

138159
/**
139160
* Decrements the resource count
@@ -143,6 +164,7 @@ public interface ResourceLimitService {
143164
* @param delta
144165
*/
145166
public void decrementResourceCount(long accountId, ResourceType type, Long... delta);
167+
public void decrementResourceCountWithTag(long accountId, ResourceType type, String tag, Long... delta);
146168

147169
/**
148170
* Checks if a limit has been exceeded for an account
@@ -155,15 +177,17 @@ public interface ResourceLimitService {
155177
* @throws ResourceAllocationException
156178
*/
157179
public void checkResourceLimit(Account account, ResourceCount.ResourceType type, long... count) throws ResourceAllocationException;
180+
public void checkResourceLimitWithTag(Account account, ResourceCount.ResourceType type, String tag, long... count) throws ResourceAllocationException;
158181

159182
/**
160183
* Gets the count of resources for a resource type and account
161184
*
162185
* @param account
163186
* @param type
187+
* @param tag
164188
* @return count of resources
165189
*/
166-
public long getResourceCount(Account account, ResourceType type);
190+
public long getResourceCount(Account account, ResourceType type, String tag);
167191

168192
/**
169193
* Checks if a limit has been exceeded for an account if displayResource flag is on
@@ -208,15 +232,25 @@ public interface ResourceLimitService {
208232
*/
209233
void decrementResourceCount(long accountId, ResourceType type, Boolean displayResource, Long... delta);
210234

211-
/**
212-
* Adds a reservation that will be counted in subsequent calls to {count}getResourceCount{code} until {code}this[code}
213-
* is closed. It will create a reservation record that will be counted when resource limits are checked.
214-
* @param account The account for which the reservation is.
215-
* @param displayResource whether this resource is shown to users at all (if not it is not counted to limits)
216-
* @param type resource type
217-
* @param delta amount to reserve (will not be <+ 0)
218-
* @return a {code}AutoClosable{Code} object representing the resource the user needs
219-
*/
220-
ResourceReservation getReservation(Account account, Boolean displayResource, ResourceType type, Long delta) throws ResourceAllocationException;
235+
List<String> getResourceLimitHostTags();
236+
List<String> getResourceLimitHostTags(ServiceOffering serviceOffering, VirtualMachineTemplate template);
237+
List<String> getResourceLimitStorageTags();
238+
List<String> getResourceLimitStorageTags(DiskOffering diskOffering);
239+
void updateTaggedResourceLimitsAndCountsForAccounts(List<AccountResponse> responses, String tag);
240+
void updateTaggedResourceLimitsAndCountsForDomains(List<DomainResponse> responses, String tag);
241+
void checkVolumeResourceLimit(Account owner, Boolean display, Long size, DiskOffering diskOffering) throws ResourceAllocationException;
242+
void incrementVolumeResourceCount(long accountId, Boolean display, Long size, DiskOffering diskOffering);
243+
void decrementVolumeResourceCount(long accountId, Boolean display, Long size, DiskOffering diskOffering);
244+
void incrementVolumePrimaryStorageResourceCount(long accountId, Boolean display, Long size, DiskOffering diskOffering);
245+
void decrementVolumePrimaryStorageResourceCount(long accountId, Boolean display, Long size, DiskOffering diskOffering);
246+
void checkVmResourceLimit(Account owner, Boolean display, ServiceOffering serviceOffering, VirtualMachineTemplate template) throws ResourceAllocationException;
247+
void incrementVmResourceCount(long accountId, Boolean display, ServiceOffering serviceOffering, VirtualMachineTemplate template);
248+
void decrementVmResourceCount(long accountId, Boolean display, ServiceOffering serviceOffering, VirtualMachineTemplate template);
249+
void checkVmCpuResourceLimit(Account owner, Boolean display, ServiceOffering serviceOffering, VirtualMachineTemplate template, Long cpu) throws ResourceAllocationException;
250+
void incrementVmCpuResourceCount(long accountId, Boolean display, ServiceOffering serviceOffering, VirtualMachineTemplate template, Long cpu);
251+
void decrementVmCpuResourceCount(long accountId, Boolean display, ServiceOffering serviceOffering, VirtualMachineTemplate template, Long cpu);
252+
void checkVmMemoryResourceLimit(Account owner, Boolean display, ServiceOffering serviceOffering, VirtualMachineTemplate template, Long memory) throws ResourceAllocationException;
253+
void incrementVmMemoryResourceCount(long accountId, Boolean display, ServiceOffering serviceOffering, VirtualMachineTemplate template, Long memory);
254+
void decrementVmMemoryResourceCount(long accountId, Boolean display, ServiceOffering serviceOffering, VirtualMachineTemplate template, Long memory);
221255

222256
}

api/src/main/java/org/apache/cloudstack/api/ApiConstants.java

+6-1
Original file line numberDiff line numberDiff line change
@@ -285,6 +285,7 @@ public class ApiConstants {
285285
public static final String LAST_SERVER_STOP = "lastserverstop";
286286
public static final String LEVEL = "level";
287287
public static final String LENGTH = "length";
288+
public static final String LIMIT = "limit";
288289
public static final String LIMIT_CPU_USE = "limitcpuuse";
289290
public static final String LIST_HOSTS = "listhosts";
290291
public static final String LOCK = "lock";
@@ -380,6 +381,7 @@ public class ApiConstants {
380381
public static final String RECONNECT = "reconnect";
381382
public static final String RECOVER = "recover";
382383
public static final String REQUIRES_HVM = "requireshvm";
384+
public static final String RESOURCE_COUNT = "resourcecount";
383385
public static final String RESOURCE_NAME = "resourcename";
384386
public static final String RESOURCE_TYPE = "resourcetype";
385387
public static final String RESOURCE_TYPE_NAME = "resourcetypename";
@@ -420,8 +422,9 @@ public class ApiConstants {
420422
public static final String SNAPSHOT_POLICY_ID = "snapshotpolicyid";
421423
public static final String SNAPSHOT_TYPE = "snapshottype";
422424
public static final String SNAPSHOT_QUIESCEVM = "quiescevm";
423-
public static final String SUPPORTS_STORAGE_SNAPSHOT = "supportsstoragesnapshot";
424425
public static final String SOURCE_ZONE_ID = "sourcezoneid";
426+
public static final String SUITABLE_FOR_VM = "suitableforvirtualmachine";
427+
public static final String SUPPORTS_STORAGE_SNAPSHOT = "supportsstoragesnapshot";
425428
public static final String START_DATE = "startdate";
426429
public static final String START_ID = "startid";
427430
public static final String START_IP = "startip";
@@ -449,6 +452,7 @@ public class ApiConstants {
449452
public static final String TIMEOUT = "timeout";
450453
public static final String TIMEZONE = "timezone";
451454
public static final String TIMEZONEOFFSET = "timezoneoffset";
455+
public static final String TOTAL = "total";
452456
public static final String TOTAL_SUBNETS = "totalsubnets";
453457
public static final String TYPE = "type";
454458
public static final String TRUST_STORE = "truststore";
@@ -719,6 +723,7 @@ public class ApiConstants {
719723
public static final String POLICY_UUID = "policyuuid";
720724
public static final String RULE_UUID = "ruleuuid";
721725
public static final String DIRECTION = "direction";
726+
public static final String TAGGED_RESOURCES = "taggedresources";
722727
public static final String TAG_UUID = "taguuid";
723728
public static final String TAG_TYPE = "tagtype";
724729
public static final String TAG_VALUE = "tagvalue";

api/src/main/java/org/apache/cloudstack/api/command/admin/domain/ListDomainsCmd.java

+21-9
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,6 @@
2020
import java.util.EnumSet;
2121
import java.util.List;
2222

23-
import com.cloud.server.ResourceIcon;
24-
import com.cloud.server.ResourceTag;
25-
import org.apache.cloudstack.api.response.ResourceIconResponse;
26-
2723
import org.apache.cloudstack.api.APICommand;
2824
import org.apache.cloudstack.api.ApiConstants;
2925
import org.apache.cloudstack.api.ApiConstants.DomainDetails;
@@ -33,9 +29,13 @@
3329
import org.apache.cloudstack.api.command.user.UserCmd;
3430
import org.apache.cloudstack.api.response.DomainResponse;
3531
import org.apache.cloudstack.api.response.ListResponse;
32+
import org.apache.cloudstack.api.response.ResourceIconResponse;
33+
import org.apache.commons.collections.CollectionUtils;
3634

3735
import com.cloud.domain.Domain;
3836
import com.cloud.exception.InvalidParameterValueException;
37+
import com.cloud.server.ResourceIcon;
38+
import com.cloud.server.ResourceTag;
3939

4040
@APICommand(name = "listDomains", description = "Lists domains and provides detailed information for listed domains", responseObject = DomainResponse.class, responseView = ResponseView.Restricted, entityType = {Domain.class},
4141
requestHasSensitiveInfo = false, responseHasSensitiveInfo = false)
@@ -71,6 +71,9 @@ public class ListDomainsCmd extends BaseListCmd implements UserCmd {
7171
description = "flag to display the resource icon for domains")
7272
private Boolean showIcon;
7373

74+
@Parameter(name = ApiConstants.TAG, type = CommandType.STRING, description = "Tag for resource type to return usage", since = "4.20.0")
75+
private String tag;
76+
7477
/////////////////////////////////////////////////////
7578
/////////////////// Accessors ///////////////////////
7679
/////////////////////////////////////////////////////
@@ -110,10 +113,14 @@ public EnumSet<DomainDetails> getDetails() throws InvalidParameterValueException
110113
return dv;
111114
}
112115

113-
public Boolean getShowIcon() {
116+
public boolean getShowIcon() {
114117
return showIcon != null ? showIcon : false;
115118
}
116119

120+
public String getTag() {
121+
return tag;
122+
}
123+
117124
/////////////////////////////////////////////////////
118125
/////////////// API Implementation///////////////////
119126
/////////////////////////////////////////////////////
@@ -128,12 +135,17 @@ public void execute() {
128135
ListResponse<DomainResponse> response = _queryService.searchForDomains(this);
129136
response.setResponseName(getCommandName());
130137
this.setResponseObject(response);
131-
if (response != null && response.getCount() > 0 && getShowIcon()) {
132-
updateDomainResponse(response.getResponses());
133-
}
138+
updateDomainResponse(response.getResponses());
134139
}
135140

136-
private void updateDomainResponse(List<DomainResponse> response) {
141+
protected void updateDomainResponse(List<DomainResponse> response) {
142+
if (CollectionUtils.isEmpty(response)) {
143+
return;
144+
}
145+
_resourceLimitService.updateTaggedResourceLimitsAndCountsForDomains(response, getTag());
146+
if (!getShowIcon()) {
147+
return;
148+
}
137149
for (DomainResponse domainResponse : response) {
138150
ResourceIcon resourceIcon = resourceIconManager.getByResourceTypeAndUuid(ResourceTag.ResourceObjectType.Domain, domainResponse.getId());
139151
if (resourceIcon == null) {

api/src/main/java/org/apache/cloudstack/api/command/admin/resource/ListCapacityCmd.java

+7
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,9 @@ public class ListCapacityCmd extends BaseListCmd {
7171
@Parameter(name = ApiConstants.SORT_BY, type = CommandType.STRING, since = "3.0.0", description = "Sort the results. Available values: Usage")
7272
private String sortBy;
7373

74+
@Parameter(name = ApiConstants.TAG, type = CommandType.STRING, description = "Tag for the resource type", since = "4.20.0")
75+
private String tag;
76+
7477
/////////////////////////////////////////////////////
7578
/////////////////// Accessors ///////////////////////
7679
/////////////////////////////////////////////////////
@@ -107,6 +110,10 @@ public String getSortBy() {
107110
return null;
108111
}
109112

113+
public String getTag() {
114+
return tag;
115+
}
116+
110117
/////////////////////////////////////////////////////
111118
/////////////// API Implementation///////////////////
112119
/////////////////////////////////////////////////////

0 commit comments

Comments
 (0)