diff --git hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/ApplicationMasterService.java hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/ApplicationMasterService.java index 9dfdea8..d5c0329 100644 --- hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/ApplicationMasterService.java +++ hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/ApplicationMasterService.java @@ -400,6 +400,13 @@ public AllocateResponse allocate(AllocateRequest request) throw e; } + try { + SchedulerUtils.validateContainerReleaseRequest(release, appAttemptId); + } catch (InvalidResourceRequestException e) { + LOG.warn("Invalid container release by application " + appAttemptId, e); + throw e; + } + // Send new requests to appAttempt. Allocation allocation = this.rScheduler.allocate(appAttemptId, ask, release, diff --git hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/scheduler/SchedulerUtils.java 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 b340f33..9a57817 100644 --- hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/scheduler/SchedulerUtils.java +++ hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/scheduler/SchedulerUtils.java @@ -21,6 +21,7 @@ import org.apache.hadoop.classification.InterfaceAudience.Private; import org.apache.hadoop.classification.InterfaceStability.Unstable; +import org.apache.hadoop.yarn.api.records.ApplicationAttemptId; import org.apache.hadoop.yarn.api.records.ContainerExitStatus; import org.apache.hadoop.yarn.api.records.ResourceBlacklistRequest; import org.apache.hadoop.yarn.api.records.ContainerId; @@ -208,4 +209,26 @@ public static void validateBlacklistRequest(ResourceBlacklistRequest blacklistRe } } } + + /** + * It will validate to make sure all the containers belong to correct + * application attempt id. If not then it will throw + * {@link InvalidResourceRequestException} + * @param containerReleaseList containers to be released as requested by + * application master. + * @param appAttemptId Application attempt Id + * @throws InvalidResourceRequestException + */ + public static void + validateContainerReleaseRequest(List containerReleaseList, + ApplicationAttemptId appAttemptId) + throws InvalidResourceRequestException { + for (ContainerId cId : containerReleaseList) { + if (!appAttemptId.equals(cId.getApplicationAttemptId())) { + throw new InvalidResourceRequestException("Cannot release container : " + + cId.toString() + " not belonging to this application attempt : " + + appAttemptId); + } + } + } } diff --git hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/test/java/org/apache/hadoop/yarn/server/resourcemanager/MockAM.java hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/test/java/org/apache/hadoop/yarn/server/resourcemanager/MockAM.java index 88e094d..5bc4554 100644 --- hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/test/java/org/apache/hadoop/yarn/server/resourcemanager/MockAM.java +++ hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/test/java/org/apache/hadoop/yarn/server/resourcemanager/MockAM.java @@ -130,6 +130,9 @@ public AllocateResponse schedule() throws Exception { return response; } + public void addContainerToBeReleased(ContainerId containerId) { + releases.add(containerId); + } public AllocateResponse allocate( String host, int memory, int numContainers, List releases) throws Exception { diff --git hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/test/java/org/apache/hadoop/yarn/server/resourcemanager/applicationmasterservice/TestApplicationMasterService.java hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/test/java/org/apache/hadoop/yarn/server/resourcemanager/applicationmasterservice/TestApplicationMasterService.java index 6e790ba..bca71b8 100644 --- hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/test/java/org/apache/hadoop/yarn/server/resourcemanager/applicationmasterservice/TestApplicationMasterService.java +++ hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/test/java/org/apache/hadoop/yarn/server/resourcemanager/applicationmasterservice/TestApplicationMasterService.java @@ -24,7 +24,9 @@ import org.apache.commons.logging.LogFactory; import org.apache.hadoop.yarn.api.protocolrecords.AllocateResponse; import org.apache.hadoop.yarn.api.records.Container; +import org.apache.hadoop.yarn.api.records.ContainerId; import org.apache.hadoop.yarn.conf.YarnConfiguration; +import org.apache.hadoop.yarn.exceptions.InvalidResourceRequestException; import org.apache.hadoop.yarn.security.ContainerTokenIdentifier; import org.apache.hadoop.yarn.server.resourcemanager.MockAM; import org.apache.hadoop.yarn.server.resourcemanager.MockNM; @@ -88,4 +90,65 @@ public void testRMIdentifierOnContainerAllocation() throws Exception { Assert.assertEquals(MockRM.clusterTimeStamp, tokenId.getRMIdentifer()); rm.stop(); } + + @Test(timeout=600000) + public void testInvalidContainerReleaseRequest() throws Exception { + MockRM rm = new MockRM(conf); + + try { + rm.start(); + + // Register node1 + MockNM nm1 = rm.registerNode("127.0.0.1:1234", 6 * GB); + + // Submit an application + RMApp app1 = rm.submitApp(1024); + + // kick the scheduling + nm1.nodeHeartbeat(true); + RMAppAttempt attempt1 = app1.getCurrentAppAttempt(); + MockAM am1 = rm.sendAMLaunched(attempt1.getAppAttemptId()); + am1.registerAppAttempt(); + + am1.addRequests(new String[] { "127.0.0.1" }, GB, 1, 1); + AllocateResponse alloc1Response = am1.schedule(); // send the request + + // kick the scheduler + nm1.nodeHeartbeat(true); + while (alloc1Response.getAllocatedContainers().size() < 1) { + LOG.info("Waiting for containers to be created for app 1..."); + Thread.sleep(1000); + alloc1Response = am1.schedule(); + } + + Assert.assertTrue(alloc1Response.getAllocatedContainers().size() > 0); + + RMApp app2 = rm.submitApp(1024); + + nm1.nodeHeartbeat(true); + RMAppAttempt attempt2 = app2.getCurrentAppAttempt(); + MockAM am2 = rm.sendAMLaunched(attempt2.getAppAttemptId()); + am2.registerAppAttempt(); + + // Now trying to release container allocated for app1 -> appAttempt1. + ContainerId cId = alloc1Response.getAllocatedContainers().get(0).getId(); + am2.addContainerToBeReleased(cId); + try { + am2.schedule(); + Assert.fail("Exception was expected!!"); + } catch (InvalidResourceRequestException e) { + StringBuilder sb = new StringBuilder("Cannot release container : "); + sb.append(cId.toString()); + sb.append(" not belonging to this application attempt : "); + sb.append(attempt2.getAppAttemptId().toString()); + System.out.println("Error : " + e.getMessage()); + System.out.println("expected : " + sb.toString()); + Assert.assertTrue(e.getMessage().contains(sb.toString())); + } + } finally { + if (rm != null) { + rm.stop(); + } + } + } }