Skip to content

Commit 78dcccc

Browse files
committed
handle resourceallocationexception
Signed-off-by: Abhishek Kumar <abhishek.mrt22@gmail.com>
1 parent 94bd8d1 commit 78dcccc

File tree

6 files changed

+78
-24
lines changed

6 files changed

+78
-24
lines changed

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

Lines changed: 24 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -22,39 +22,45 @@ public interface Resource {
2222
String UNLIMITED = "Unlimited";
2323

2424
enum ResourceType { // All storage type resources are allocated_storage and not the physical storage.
25-
user_vm("user_vm", 0),
26-
public_ip("public_ip", 1),
27-
volume("volume", 2),
28-
snapshot("snapshot", 3),
29-
template("template", 4),
30-
project("project", 5),
31-
network("network", 6),
32-
vpc("vpc", 7),
33-
cpu("cpu", 8),
34-
memory("memory", 9),
35-
primary_storage("primary_storage", 10),
36-
secondary_storage("secondary_storage", 11),
37-
backup("backup", 12),
38-
backup_storage("backup_storage", 13),
39-
bucket("bucket", 14),
40-
object_storage("object_storage", 15),
41-
gpu("gpu", 16);
25+
user_vm("user_vm", "Instance", 0),
26+
public_ip("public_ip", "Public IP", 1),
27+
volume("volume", "Volume", 2),
28+
snapshot("snapshot", "Snapshot", 3),
29+
template("template", "Template", 4),
30+
project("project", "Project", 5),
31+
network("network", "Network", 6),
32+
vpc("vpc", "VPC", 7),
33+
cpu("cpu", "CPU", 8),
34+
memory("memory", "Memory", 9),
35+
primary_storage("primary_storage", "Primary Storage", 10),
36+
secondary_storage("secondary_storage", "Secondary Storage", 11),
37+
backup("backup", "Backup", 12),
38+
backup_storage("backup_storage", "Backup Storage", 13),
39+
bucket("bucket", "Bucket", 14),
40+
object_storage("object_storage", "Object Storage", 15),
41+
gpu("gpu", "GPU", 16);
4242

4343
private String name;
44+
private String displayName;
4445
private int ordinal;
4546
public static final long bytesToKiB = 1024;
4647
public static final long bytesToMiB = bytesToKiB * 1024;
4748
public static final long bytesToGiB = bytesToMiB * 1024;
4849

49-
ResourceType(String name, int ordinal) {
50+
ResourceType(String name, String displayName, int ordinal) {
5051
this.name = name;
52+
this.displayName = displayName;
5153
this.ordinal = ordinal;
5254
}
5355

5456
public String getName() {
5557
return name;
5658
}
5759

60+
public String getDisplayName() {
61+
return displayName;
62+
}
63+
5864
public int getOrdinal() {
5965
return ordinal;
6066
}

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

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,9 @@
1717
package org.apache.cloudstack.api;
1818

1919
import java.util.ArrayList;
20+
import java.util.Map;
21+
22+
import org.apache.cloudstack.context.ErrorMessageResolver;
2023

2124
import com.cloud.exception.CloudException;
2225
import com.cloud.utils.exception.CSExceptionErrorCode;
@@ -34,6 +37,14 @@ public ServerApiException() {
3437
setCSErrorCode(CSExceptionErrorCode.getCSErrCode(ServerApiException.class.getName()));
3538
}
3639

40+
public ServerApiException(ApiErrorCode errorCode, String messageKey, Map<String, Object> errorMetadata) {
41+
_errorCode = errorCode;
42+
this.messageKey = messageKey;
43+
this.metadata = errorMetadata;
44+
_description = ErrorMessageResolver.getMessage(messageKey, errorMetadata);
45+
setCSErrorCode(CSExceptionErrorCode.getCSErrCode(ServerApiException.class.getName()));
46+
}
47+
3748
public ServerApiException(ApiErrorCode errorCode, String description) {
3849
_errorCode = errorCode;
3950
_description = description;

api/src/main/java/org/apache/cloudstack/api/command/user/vm/DeployVMCmd.java

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
// under the License.
1717
package org.apache.cloudstack.api.command.user.vm;
1818

19+
import java.util.Collections;
1920
import java.util.Objects;
2021
import java.util.stream.Stream;
2122

@@ -156,7 +157,18 @@ public void create() throws ResourceAllocationException {
156157
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, ex.getMessage());
157158
} catch (ResourceAllocationException ex) {
158159
logger.warn("Exception: ", ex);
159-
throw new ServerApiException(ApiErrorCode.RESOURCE_ALLOCATION_ERROR, ex.getMessage());
160+
handleCreateResourceAllocationException(ex);
160161
}
161162
}
163+
164+
protected void handleCreateResourceAllocationException(ResourceAllocationException ex) {
165+
if (ex.getMessage() != null && ex.getMessage().startsWith("Maximum amount")) {
166+
throw new ServerApiException(ApiErrorCode.RESOURCE_ALLOCATION_ERROR,
167+
"vm.deploy.resourcelimit.exceeded.account", Collections.emptyMap());
168+
} else if (ex.getMessage() != null && ex.getMessage().startsWith("Maximum domain resource limits")) {
169+
throw new ServerApiException(ApiErrorCode.RESOURCE_ALLOCATION_ERROR,
170+
"vm.deploy.resourcelimit.exceeded.domain", Collections.emptyMap());
171+
}
172+
throw new ServerApiException(ApiErrorCode.RESOURCE_ALLOCATION_ERROR, ex.getMessage());
173+
}
162174
}

api/src/main/java/org/apache/cloudstack/context/ErrorMessageResolver.java

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,6 @@
3939
import org.apache.logging.log4j.LogManager;
4040
import org.apache.logging.log4j.Logger;
4141

42-
import com.cloud.exception.InvalidParameterValueException;
4342
import com.cloud.utils.PropertiesUtil;
4443
import com.cloud.utils.exception.CloudRuntimeException;
4544
import com.fasterxml.jackson.core.type.TypeReference;
@@ -287,12 +286,15 @@ public static void updateExceptionResponse(ExceptionResponse response, CloudRunt
287286

288287
if (key == null) {
289288
Throwable cause = cre.getCause();
290-
if (!(cause instanceof InvalidParameterValueException)) {
289+
if (!(cause instanceof CloudRuntimeException)) {
291290
return;
292291
}
293-
InvalidParameterValueException ipve = (InvalidParameterValueException) cause;
294-
key = ipve.getMessageKey();
295-
map = ipve.getMetadata();
292+
CloudRuntimeException causeEx = (CloudRuntimeException) cause;
293+
key = causeEx.getMessageKey();
294+
if (key == null) {
295+
return;
296+
}
297+
map = causeEx.getMetadata();
296298
}
297299
response.setErrorTextKey(key);
298300
String template = getTemplateForKey(key);

client/conf/error-messages.json.in

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,10 @@
55
"vm.deploy.diskoffering.with.diskoffering.details": "Unable to deploy Instance as both a disk offering ID and data disk offering details were provided. Specify only one.",
66
"vm.deploy.hypervisor.volume.snapshot.not.supported": "Unable to deploy Instance because deployment from an existing volume or snapshot is supported only on the KVM hypervisor.",
77
"vm.deploy.network.not.found.ip.map": "The network selected {{networkId}} in IP to network map could not be found. It may have been removed or is no longer accessible.",
8+
"vm.deploy.resourcelimit.exceeded.account": "Unable to deploy Instance because allocating {{resourceRequested}} more {{resourceTypeDisplay}} would exceed the {{resourceOwnerType}} limits. Current: {{resourceAmount}}, Reserved: {{resourceReserved}}, Limit: {{resourceLimit}}. Release unused resources, then retry.",
9+
"vm.deploy.resourcelimit.exceeded.account.admin": "Unable to deploy Instance because allocating {{resourceRequested}} more {{resourceTypeDisplay}} would exceed the {{resourceOwnerType}} limits for {{resourceOwner}}. Current: {{resourceAmount}}, Reserved: {{resourceReserved}}, Limit: {{resourceLimit}}. Release unused resources or increase the limit, then retry.",
10+
"vm.deploy.resourcelimit.exceeded.domain": "Unable to deploy Instance because allocating {{resourceRequested}} more {{resourceTypeDisplay}} would exceed the domain limits. Current: {{resourceAmount}}, Reserved: {{resourceReserved}}, Limit: {{resourceLimit}}. Release unused resources, then retry.",
11+
"vm.deploy.resourcelimit.exceeded.domain.admin": "Unable to deploy Instance because allocating {{resourceRequested}} more {{resourceTypeDisplay}} would exceed the limits for domain {{resourceOwnerDomain}}. Current: {{resourceAmount}}, Reserved: {{resourceReserved}}, Limit: {{resourceLimit}}. Release unused resources or increase the limit, then retry.",
812
"vm.deploy.serviceoffering.fixed.parameters.not.allowed": "Unable to deploy the instance because the selected service offering {{serviceOffering}} does not allow specifying {{cpuNumberKey}}, {{cpuSpeedKey}}, or {{memory}}.",
913
"vm.deploy.serviceoffering.fixed.parameters.not.allowed.admin": "Unable to deploy the instance because the selected service offering {{serviceOffering}} is not a dynamic offering and it does not allow specifying {{cpuNumberKey}}, {{cpuSpeedKey}}, or {{memory}}.",
1014
"vm.deploy.serviceoffering.inactive": "Unable to deploy Instance as the given service offering {{serviceOffering}} is inactive. Specify an active service offering.",

server/src/main/java/com/cloud/resourcelimit/ResourceLimitManagerImpl.java

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -559,6 +559,16 @@ protected void checkDomainResourceLimit(final Account account, final Project pro
559559

560560
if (domainResourceLimit != Resource.RESOURCE_UNLIMITED && requestedDomainResourceCount > domainResourceLimit) {
561561
String message = "Maximum" + messageSuffix;
562+
Map<Object, Object> details = new HashMap<>();
563+
details.put("resourceTypeDisplay", StringUtils.isBlank(tag) ? type.getDisplayName() : type.getDisplayName() + " (tag: " + tag + ")");
564+
details.put("resourceOwner", ObjectUtils.firstNonNull(project, account));
565+
details.put("resourceOwnerDomain", domain);
566+
details.put("resourceOwnerType", project == null ? "Account" : "Project");
567+
details.put("resourceLimit", convDomainResourceLimit);
568+
details.put("resourceAmount", convCurrentDomainResourceCount);
569+
details.put("resourceReserved", convCurrentResourceReservation);
570+
details.put("resourceRequested", convNumResources);
571+
CallContext.current().putContextParameters(details);
562572
ResourceAllocationException e = new ResourceAllocationException(message, type);
563573
logger.error(message, e);
564574
throw e;
@@ -598,6 +608,15 @@ protected void checkAccountResourceLimit(final Account account, final Project pr
598608

599609
if (accountResourceLimit != Resource.RESOURCE_UNLIMITED && requestedResourceCount > accountResourceLimit) {
600610
String message = "Maximum" + messageSuffix;
611+
Map<Object, Object> details = new HashMap<>();
612+
details.put("resourceTypeDisplay", StringUtils.isBlank(tag) ? type.getDisplayName() : type.getDisplayName() + " (tag: " + tag + ")");
613+
details.put("resourceOwner", ObjectUtils.firstNonNull(project, account));
614+
details.put("resourceOwnerType", project == null ? "Account" : "Project");
615+
details.put("resourceLimit", convertedAccountResourceLimit);
616+
details.put("resourceAmount", convertedCurrentResourceCount);
617+
details.put("resourceReserved", convertedCurrentResourceReservation);
618+
details.put("resourceRequested", convertedNumResources);
619+
CallContext.current().putContextParameters(details);
601620
ResourceAllocationException e = new ResourceAllocationException(message, type);
602621
logger.error(message, e);
603622
throw e;

0 commit comments

Comments
 (0)