diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-api/src/main/java/org/apache/hadoop/yarn/exceptions/InvalidResourceRequestException.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-api/src/main/java/org/apache/hadoop/yarn/exceptions/InvalidResourceRequestException.java index f4fd2fa38a1..1ea9eefd87f 100644 --- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-api/src/main/java/org/apache/hadoop/yarn/exceptions/InvalidResourceRequestException.java +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-api/src/main/java/org/apache/hadoop/yarn/exceptions/InvalidResourceRequestException.java @@ -30,19 +30,55 @@ * */ public class InvalidResourceRequestException extends YarnException { + public static final String LESS_THAN_ZERO_RESOURCE_MESSAGE_TEMPLATE = + "Invalid resource request! Cannot allocate containers as " + + "requested resource is less than 0! " + + "Requested resource type=[%s], " + "Requested resource=%s"; + + public static final String GREATER_THAN_MAX_RESOURCE_MESSAGE_TEMPLATE = + "Invalid resource request! Cannot allocate containers as " + + "requested resource is greater than " + + "maximum allowed allocation. " + + "Requested resource type=[%s], " + + "Requested resource=%s, maximum allowed allocation=%s, " + + "please note that maximum allowed allocation is calculated " + + "by scheduler based on maximum resource of registered " + + "NodeManagers, which might be less than configured " + + "maximum allocation=%s"; + + public static final String UNKNOWN_REASON_MESSAGE_TEMPLATE = + "Invalid resource request! " + + "Cannot allocate containers for an unknown reason! " + + "Requested resource type=[%s], Requested resource=%s"; + + public enum InvalidResourceType { + LESS_THAN_ZERO, GREATER_THEN_MAX_ALLOCATION, UNKNOWN; + } private static final long serialVersionUID = 13498237L; + private final InvalidResourceType invalidResourceType; public InvalidResourceRequestException(Throwable cause) { super(cause); + this.invalidResourceType = InvalidResourceType.UNKNOWN; } public InvalidResourceRequestException(String message) { + this(message, InvalidResourceType.UNKNOWN); + } + + public InvalidResourceRequestException(String message, + InvalidResourceType invalidResourceType) { super(message); + this.invalidResourceType = invalidResourceType; } public InvalidResourceRequestException(String message, Throwable cause) { super(message, cause); + this.invalidResourceType = InvalidResourceType.UNKNOWN; } + public InvalidResourceType getInvalidResourceType() { + return invalidResourceType; + } } diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/DefaultAMSProcessor.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/DefaultAMSProcessor.java index 71558a76be9..43f73e48a40 100644 --- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/DefaultAMSProcessor.java +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/DefaultAMSProcessor.java @@ -53,6 +53,8 @@ import org.apache.hadoop.yarn.exceptions.InvalidContainerReleaseException; import org.apache.hadoop.yarn.exceptions.InvalidResourceBlacklistRequestException; import org.apache.hadoop.yarn.exceptions.InvalidResourceRequestException; +import org.apache.hadoop.yarn.exceptions.InvalidResourceRequestException + .InvalidResourceType; import org.apache.hadoop.yarn.exceptions.SchedulerInvalidResoureRequestException; import org.apache.hadoop.yarn.exceptions.YarnException; import org.apache.hadoop.yarn.factories.RecordFactory; @@ -89,6 +91,12 @@ import java.util.Map; import java.util.Set; +import static org.apache.hadoop.yarn.exceptions + .InvalidResourceRequestException.InvalidResourceType + .GREATER_THEN_MAX_ALLOCATION; +import static org.apache.hadoop.yarn.exceptions + .InvalidResourceRequestException.InvalidResourceType.LESS_THAN_ZERO; + /** * This is the default Application Master Service processor. It has be the * last processor in the @{@link AMSProcessingChain}. @@ -231,8 +239,8 @@ public void allocate(ApplicationAttemptId appAttemptId, maximumCapacity, app.getQueue(), getScheduler(), getRmContext()); } catch (InvalidResourceRequestException e) { - LOG.warn("Invalid resource ask by application " + appAttemptId, e); - throw e; + RMAppAttempt rmAppAttempt = app.getRMAppAttempt(appAttemptId); + handleInvalidResourceException(e, rmAppAttempt); } try { @@ -336,6 +344,17 @@ public void allocate(ApplicationAttemptId appAttemptId, allocation.getPreviousAttemptContainers()); } + private void handleInvalidResourceException(InvalidResourceRequestException e, + RMAppAttempt rmAppAttempt) throws InvalidResourceRequestException { + if (e.getInvalidResourceType() == LESS_THAN_ZERO || + e.getInvalidResourceType() == GREATER_THEN_MAX_ALLOCATION) { + rmAppAttempt.updateAMLaunchDiagnostics(e.getMessage()); + } + LOG.warn("Invalid resource ask by application " + + rmAppAttempt.getAppAttemptId(), e); + throw e; + } + private void handleNodeUpdates(RMApp app, AllocateResponse allocateResponse) { Map updatedNodes = new HashMap<>(); if(app.pullRMNodeUpdates(updatedNodes) > 0) { diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/scheduler/SchedulerUtils.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/scheduler/SchedulerUtils.java index 844057ea142..32dc9d6a05b 100644 --- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/scheduler/SchedulerUtils.java +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/scheduler/SchedulerUtils.java @@ -45,6 +45,8 @@ import org.apache.hadoop.yarn.conf.YarnConfiguration; import org.apache.hadoop.yarn.exceptions.InvalidLabelResourceRequestException; import org.apache.hadoop.yarn.exceptions.InvalidResourceRequestException; +import org.apache.hadoop.yarn.exceptions.InvalidResourceRequestException + .InvalidResourceType; import org.apache.hadoop.yarn.exceptions .SchedulerInvalidResoureRequestException; import org.apache.hadoop.yarn.factories.RecordFactory; @@ -61,6 +63,15 @@ import org.apache.hadoop.yarn.util.resource.ResourceUtils; import org.apache.hadoop.yarn.util.resource.Resources; +import static org.apache.hadoop.yarn.exceptions + .InvalidResourceRequestException + .GREATER_THAN_MAX_RESOURCE_MESSAGE_TEMPLATE; +import static org.apache.hadoop.yarn.exceptions + .InvalidResourceRequestException + .LESS_THAN_ZERO_RESOURCE_MESSAGE_TEMPLATE; +import static org.apache.hadoop.yarn.exceptions + .InvalidResourceRequestException.UNKNOWN_REASON_MESSAGE_TEMPLATE; + /** * Utilities shared by schedulers. */ @@ -257,9 +268,9 @@ public static void normalizeAndValidateRequest(ResourceRequest resReq, } - public static void normalizeAndValidateRequest(ResourceRequest resReq, - Resource maximumResource, String queueName, YarnScheduler scheduler, - boolean isRecovery, RMContext rmContext, QueueInfo queueInfo) + private static void normalizeAndValidateRequest(ResourceRequest resReq, + Resource maximumResource, String queueName, YarnScheduler scheduler, + boolean isRecovery, RMContext rmContext, QueueInfo queueInfo) throws InvalidResourceRequestException { Configuration conf = rmContext.getYarnConfiguration(); // If Node label is not enabled throw exception @@ -384,13 +395,13 @@ static void checkResourceRequestAgainstAvailableResource(Resource reqResource, if (requestedRI.getValue() < 0) { throwInvalidResourceException(reqResource, availableResource, - reqResourceName); + reqResourceName, InvalidResourceType.LESS_THAN_ZERO); } boolean valid = checkResource(requestedRI, availableResource); if (!valid) { throwInvalidResourceException(reqResource, availableResource, - reqResourceName); + reqResourceName, InvalidResourceType.GREATER_THEN_MAX_ALLOCATION); } } } @@ -470,18 +481,30 @@ private static boolean checkResource( } private static void throwInvalidResourceException(Resource reqResource, - Resource availableResource, String reqResourceName) + Resource maxAllowedAllocation, String reqResourceName, + InvalidResourceType invalidResourceType) throws InvalidResourceRequestException { - throw new InvalidResourceRequestException( - "Invalid resource request, requested resource type=[" + reqResourceName - + "] < 0 or greater than maximum allowed allocation. Requested " - + "resource=" + reqResource + ", maximum allowed allocation=" - + availableResource - + ", please note that maximum allowed allocation is calculated " - + "by scheduler based on maximum resource of registered " - + "NodeManagers, which might be less than configured " - + "maximum allocation=" - + ResourceUtils.getResourceTypesMaximumAllocation()); + final String message; + + if (invalidResourceType == InvalidResourceType.LESS_THAN_ZERO) { + message = String.format(LESS_THAN_ZERO_RESOURCE_MESSAGE_TEMPLATE, + reqResourceName, reqResource); + } else if (invalidResourceType == + InvalidResourceType.GREATER_THEN_MAX_ALLOCATION) { + message = String.format(GREATER_THAN_MAX_RESOURCE_MESSAGE_TEMPLATE, + reqResourceName, reqResource, maxAllowedAllocation, + ResourceUtils.getResourceTypesMaximumAllocation()); + } else if (invalidResourceType == InvalidResourceType.UNKNOWN) { + message = String.format(UNKNOWN_REASON_MESSAGE_TEMPLATE, reqResourceName, + reqResource); + } else { + throw new IllegalArgumentException(String.format( + "InvalidResourceType argument should be either " + "%s, %s or %s", + InvalidResourceType.LESS_THAN_ZERO, + InvalidResourceType.GREATER_THEN_MAX_ALLOCATION, + InvalidResourceType.UNKNOWN)); + } + throw new InvalidResourceRequestException(message); } private static void checkQueueLabelInLabelManager(String labelExpression, diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/test/java/org/apache/hadoop/yarn/server/resourcemanager/scheduler/TestSchedulerUtils.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/test/java/org/apache/hadoop/yarn/server/resourcemanager/scheduler/TestSchedulerUtils.java index 15cfdb01e7b..36838832a4d 100644 --- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/test/java/org/apache/hadoop/yarn/server/resourcemanager/scheduler/TestSchedulerUtils.java +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/test/java/org/apache/hadoop/yarn/server/resourcemanager/scheduler/TestSchedulerUtils.java @@ -67,6 +67,8 @@ import org.apache.hadoop.yarn.exceptions.InvalidLabelResourceRequestException; import org.apache.hadoop.yarn.exceptions.InvalidResourceBlacklistRequestException; import org.apache.hadoop.yarn.exceptions.InvalidResourceRequestException; +import org.apache.hadoop.yarn.exceptions.InvalidResourceRequestException + .InvalidResourceType; import org.apache.hadoop.yarn.exceptions.YarnException; import org.apache.hadoop.yarn.ipc.YarnRPC; import org.apache.hadoop.yarn.nodelabels.CommonNodeLabelsManager; @@ -642,7 +644,8 @@ public void testValidateResourceRequest() { mockScheduler, rmContext); fail("Negative memory should not be accepted"); } catch (InvalidResourceRequestException e) { - // expected + assertEquals(InvalidResourceType.LESS_THAN_ZERO, + e.getInvalidResourceType()); } // negative vcores @@ -657,7 +660,8 @@ public void testValidateResourceRequest() { mockScheduler, rmContext); fail("Negative vcores should not be accepted"); } catch (InvalidResourceRequestException e) { - // expected + assertEquals(InvalidResourceType.LESS_THAN_ZERO, + e.getInvalidResourceType()); } // more than max memory @@ -673,7 +677,8 @@ public void testValidateResourceRequest() { mockScheduler, rmContext); fail("More than max memory should not be accepted"); } catch (InvalidResourceRequestException e) { - // expected + assertEquals(InvalidResourceType.GREATER_THEN_MAX_ALLOCATION, + e.getInvalidResourceType()); } // more than max vcores @@ -688,7 +693,8 @@ public void testValidateResourceRequest() { mockScheduler, rmContext); fail("More than max vcores should not be accepted"); } catch (InvalidResourceRequestException e) { - // expected + assertEquals(InvalidResourceType.GREATER_THEN_MAX_ALLOCATION, + e.getInvalidResourceType()); } }